1c896fe29Sbellard /* 2c896fe29Sbellard * Tiny Code Generator for QEMU 3c896fe29Sbellard * 4c896fe29Sbellard * Copyright (c) 2008 Fabrice Bellard 5c896fe29Sbellard * 6c896fe29Sbellard * Permission is hereby granted, free of charge, to any person obtaining a copy 7c896fe29Sbellard * of this software and associated documentation files (the "Software"), to deal 8c896fe29Sbellard * in the Software without restriction, including without limitation the rights 9c896fe29Sbellard * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10c896fe29Sbellard * copies of the Software, and to permit persons to whom the Software is 11c896fe29Sbellard * furnished to do so, subject to the following conditions: 12c896fe29Sbellard * 13c896fe29Sbellard * The above copyright notice and this permission notice shall be included in 14c896fe29Sbellard * all copies or substantial portions of the Software. 15c896fe29Sbellard * 16c896fe29Sbellard * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17c896fe29Sbellard * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18c896fe29Sbellard * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19c896fe29Sbellard * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20c896fe29Sbellard * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21c896fe29Sbellard * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22c896fe29Sbellard * THE SOFTWARE. 23c896fe29Sbellard */ 24c896fe29Sbellard 25c896fe29Sbellard /* define it to use liveness analysis (better code) */ 268f2e8c07SKirill Batuzov #define USE_TCG_OPTIMIZATIONS 27c896fe29Sbellard 28757e725bSPeter Maydell #include "qemu/osdep.h" 29cca82982Saurel32 30813da627SRichard Henderson /* Define to jump the ELF file used to communicate with GDB. */ 31813da627SRichard Henderson #undef DEBUG_JIT 32813da627SRichard Henderson 3372fd2efbSEmilio G. Cota #include "qemu/error-report.h" 34f348b6d1SVeronia Bahaa #include "qemu/cutils.h" 351de7afc9SPaolo Bonzini #include "qemu/host-utils.h" 36d4c51a0aSMarkus Armbruster #include "qemu/qemu-print.h" 371de7afc9SPaolo Bonzini #include "qemu/timer.h" 38084cfca1SRichard Henderson #include "qemu/cacheflush.h" 39c896fe29Sbellard 40c5d3c498SStefan Weil /* Note: the long term plan is to reduce the dependencies on the QEMU 41c896fe29Sbellard CPU definitions. Currently they are used for qemu_ld/st 42c896fe29Sbellard instructions */ 43c896fe29Sbellard #define NO_CPU_IO_DEFS 44c896fe29Sbellard #include "cpu.h" 45c896fe29Sbellard 4663c91552SPaolo Bonzini #include "exec/exec-all.h" 4763c91552SPaolo Bonzini 485cc8767dSLike Xu #if !defined(CONFIG_USER_ONLY) 495cc8767dSLike Xu #include "hw/boards.h" 505cc8767dSLike Xu #endif 515cc8767dSLike Xu 52dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h" 53813da627SRichard Henderson 54edee2579SRichard Henderson #if UINTPTR_MAX == UINT32_MAX 55813da627SRichard Henderson # define ELF_CLASS ELFCLASS32 56edee2579SRichard Henderson #else 57edee2579SRichard Henderson # define ELF_CLASS ELFCLASS64 58813da627SRichard Henderson #endif 59813da627SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 60813da627SRichard Henderson # define ELF_DATA ELFDATA2MSB 61813da627SRichard Henderson #else 62813da627SRichard Henderson # define ELF_DATA ELFDATA2LSB 63813da627SRichard Henderson #endif 64813da627SRichard Henderson 65c896fe29Sbellard #include "elf.h" 66508127e2SPaolo Bonzini #include "exec/log.h" 673468b59eSEmilio G. Cota #include "sysemu/sysemu.h" 68c896fe29Sbellard 69139c1837SPaolo Bonzini /* Forward declarations for functions declared in tcg-target.c.inc and 70ce151109SPeter Maydell used here. */ 71e4d58b41SRichard Henderson static void tcg_target_init(TCGContext *s); 72f69d277eSRichard Henderson static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode); 73e4d58b41SRichard Henderson static void tcg_target_qemu_prologue(TCGContext *s); 746ac17786SRichard Henderson static bool patch_reloc(tcg_insn_unit *code_ptr, int type, 752ba7fae2SRichard Henderson intptr_t value, intptr_t addend); 76c896fe29Sbellard 77497a22ebSRichard Henderson /* The CIE and FDE header definitions will be common to all hosts. */ 78497a22ebSRichard Henderson typedef struct { 79497a22ebSRichard Henderson uint32_t len __attribute__((aligned((sizeof(void *))))); 80497a22ebSRichard Henderson uint32_t id; 81497a22ebSRichard Henderson uint8_t version; 82497a22ebSRichard Henderson char augmentation[1]; 83497a22ebSRichard Henderson uint8_t code_align; 84497a22ebSRichard Henderson uint8_t data_align; 85497a22ebSRichard Henderson uint8_t return_column; 86497a22ebSRichard Henderson } DebugFrameCIE; 87497a22ebSRichard Henderson 88497a22ebSRichard Henderson typedef struct QEMU_PACKED { 89497a22ebSRichard Henderson uint32_t len __attribute__((aligned((sizeof(void *))))); 90497a22ebSRichard Henderson uint32_t cie_offset; 91edee2579SRichard Henderson uintptr_t func_start; 92edee2579SRichard Henderson uintptr_t func_len; 93497a22ebSRichard Henderson } DebugFrameFDEHeader; 94497a22ebSRichard Henderson 952c90784aSRichard Henderson typedef struct QEMU_PACKED { 962c90784aSRichard Henderson DebugFrameCIE cie; 972c90784aSRichard Henderson DebugFrameFDEHeader fde; 982c90784aSRichard Henderson } DebugFrameHeader; 992c90784aSRichard Henderson 100813da627SRichard Henderson static void tcg_register_jit_int(void *buf, size_t size, 1012c90784aSRichard Henderson const void *debug_frame, 1022c90784aSRichard Henderson size_t debug_frame_size) 103813da627SRichard Henderson __attribute__((unused)); 104813da627SRichard Henderson 105139c1837SPaolo Bonzini /* Forward declarations for functions declared and used in tcg-target.c.inc. */ 106069ea736SRichard Henderson static const char *target_parse_constraint(TCGArgConstraint *ct, 107069ea736SRichard Henderson const char *ct_str, TCGType type); 1082a534affSRichard Henderson static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1, 109a05b5b9bSRichard Henderson intptr_t arg2); 11078113e83SRichard Henderson static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg); 111c0ad3001SStefan Weil static void tcg_out_movi(TCGContext *s, TCGType type, 1122a534affSRichard Henderson TCGReg ret, tcg_target_long arg); 113c0ad3001SStefan Weil static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, 114c0ad3001SStefan Weil const int *const_args); 115d2fd745fSRichard Henderson #if TCG_TARGET_MAYBE_vec 116e7632cfaSRichard Henderson static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece, 117e7632cfaSRichard Henderson TCGReg dst, TCGReg src); 118d6ecb4a9SRichard Henderson static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece, 119d6ecb4a9SRichard Henderson TCGReg dst, TCGReg base, intptr_t offset); 120e7632cfaSRichard Henderson static void tcg_out_dupi_vec(TCGContext *s, TCGType type, 121e7632cfaSRichard Henderson TCGReg dst, tcg_target_long arg); 122d2fd745fSRichard Henderson static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, unsigned vecl, 123d2fd745fSRichard Henderson unsigned vece, const TCGArg *args, 124d2fd745fSRichard Henderson const int *const_args); 125d2fd745fSRichard Henderson #else 126e7632cfaSRichard Henderson static inline bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece, 127e7632cfaSRichard Henderson TCGReg dst, TCGReg src) 128e7632cfaSRichard Henderson { 129e7632cfaSRichard Henderson g_assert_not_reached(); 130e7632cfaSRichard Henderson } 131d6ecb4a9SRichard Henderson static inline bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece, 132d6ecb4a9SRichard Henderson TCGReg dst, TCGReg base, intptr_t offset) 133d6ecb4a9SRichard Henderson { 134d6ecb4a9SRichard Henderson g_assert_not_reached(); 135d6ecb4a9SRichard Henderson } 136e7632cfaSRichard Henderson static inline void tcg_out_dupi_vec(TCGContext *s, TCGType type, 137e7632cfaSRichard Henderson TCGReg dst, tcg_target_long arg) 138e7632cfaSRichard Henderson { 139e7632cfaSRichard Henderson g_assert_not_reached(); 140e7632cfaSRichard Henderson } 141d2fd745fSRichard Henderson static inline void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, unsigned vecl, 142d2fd745fSRichard Henderson unsigned vece, const TCGArg *args, 143d2fd745fSRichard Henderson const int *const_args) 144d2fd745fSRichard Henderson { 145d2fd745fSRichard Henderson g_assert_not_reached(); 146d2fd745fSRichard Henderson } 147d2fd745fSRichard Henderson #endif 1482a534affSRichard Henderson static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1, 149a05b5b9bSRichard Henderson intptr_t arg2); 15059d7c14eSRichard Henderson static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val, 15159d7c14eSRichard Henderson TCGReg base, intptr_t ofs); 152cf066674SRichard Henderson static void tcg_out_call(TCGContext *s, tcg_insn_unit *target); 153f6c6afc1SRichard Henderson static int tcg_target_const_match(tcg_target_long val, TCGType type, 154c0ad3001SStefan Weil const TCGArgConstraint *arg_ct); 155659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS 156aeee05f5SRichard Henderson static int tcg_out_ldst_finalize(TCGContext *s); 157659ef5cbSRichard Henderson #endif 158c896fe29Sbellard 159a505785cSEmilio G. Cota #define TCG_HIGHWATER 1024 160a505785cSEmilio G. Cota 161df2cce29SEmilio G. Cota static TCGContext **tcg_ctxs; 162df2cce29SEmilio G. Cota static unsigned int n_tcg_ctxs; 1631c2adb95SRichard Henderson TCGv_env cpu_env = 0; 164df2cce29SEmilio G. Cota 165be2cdc5eSEmilio G. Cota struct tcg_region_tree { 166be2cdc5eSEmilio G. Cota QemuMutex lock; 167be2cdc5eSEmilio G. Cota GTree *tree; 168be2cdc5eSEmilio G. Cota /* padding to avoid false sharing is computed at run-time */ 169be2cdc5eSEmilio G. Cota }; 170be2cdc5eSEmilio G. Cota 171e8feb96fSEmilio G. Cota /* 172e8feb96fSEmilio G. Cota * We divide code_gen_buffer into equally-sized "regions" that TCG threads 173e8feb96fSEmilio G. Cota * dynamically allocate from as demand dictates. Given appropriate region 174e8feb96fSEmilio G. Cota * sizing, this minimizes flushes even when some TCG threads generate a lot 175e8feb96fSEmilio G. Cota * more code than others. 176e8feb96fSEmilio G. Cota */ 177e8feb96fSEmilio G. Cota struct tcg_region_state { 178e8feb96fSEmilio G. Cota QemuMutex lock; 179e8feb96fSEmilio G. Cota 180e8feb96fSEmilio G. Cota /* fields set at init time */ 181e8feb96fSEmilio G. Cota void *start; 182e8feb96fSEmilio G. Cota void *start_aligned; 183e8feb96fSEmilio G. Cota void *end; 184e8feb96fSEmilio G. Cota size_t n; 185e8feb96fSEmilio G. Cota size_t size; /* size of one region */ 186e8feb96fSEmilio G. Cota size_t stride; /* .size + guard size */ 187e8feb96fSEmilio G. Cota 188e8feb96fSEmilio G. Cota /* fields protected by the lock */ 189e8feb96fSEmilio G. Cota size_t current; /* current region index */ 190e8feb96fSEmilio G. Cota size_t agg_size_full; /* aggregate size of full regions */ 191e8feb96fSEmilio G. Cota }; 192e8feb96fSEmilio G. Cota 193e8feb96fSEmilio G. Cota static struct tcg_region_state region; 194be2cdc5eSEmilio G. Cota /* 195be2cdc5eSEmilio G. Cota * This is an array of struct tcg_region_tree's, with padding. 196be2cdc5eSEmilio G. Cota * We use void * to simplify the computation of region_trees[i]; each 197be2cdc5eSEmilio G. Cota * struct is found every tree_size bytes. 198be2cdc5eSEmilio G. Cota */ 199be2cdc5eSEmilio G. Cota static void *region_trees; 200be2cdc5eSEmilio G. Cota static size_t tree_size; 201d2fd745fSRichard Henderson static TCGRegSet tcg_target_available_regs[TCG_TYPE_COUNT]; 202b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs; 203c896fe29Sbellard 2041813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1 2054196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v) 206c896fe29Sbellard { 207c896fe29Sbellard *s->code_ptr++ = v; 208c896fe29Sbellard } 209c896fe29Sbellard 2104196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p, 2114196dca6SPeter Maydell uint8_t v) 2125c53bb81SPeter Maydell { 2131813e175SRichard Henderson *p = v; 2145c53bb81SPeter Maydell } 2151813e175SRichard Henderson #endif 2165c53bb81SPeter Maydell 2171813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2 2184196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v) 219c896fe29Sbellard { 2201813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 2) { 2211813e175SRichard Henderson *s->code_ptr++ = v; 2221813e175SRichard Henderson } else { 2231813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 2244387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 2251813e175SRichard Henderson s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE); 2261813e175SRichard Henderson } 227c896fe29Sbellard } 228c896fe29Sbellard 2294196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p, 2304196dca6SPeter Maydell uint16_t v) 2315c53bb81SPeter Maydell { 2321813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 2) { 2331813e175SRichard Henderson *p = v; 2341813e175SRichard Henderson } else { 2355c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 2365c53bb81SPeter Maydell } 2371813e175SRichard Henderson } 2381813e175SRichard Henderson #endif 2395c53bb81SPeter Maydell 2401813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4 2414196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v) 242c896fe29Sbellard { 2431813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 4) { 2441813e175SRichard Henderson *s->code_ptr++ = v; 2451813e175SRichard Henderson } else { 2461813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 2474387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 2481813e175SRichard Henderson s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE); 2491813e175SRichard Henderson } 250c896fe29Sbellard } 251c896fe29Sbellard 2524196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p, 2534196dca6SPeter Maydell uint32_t v) 2545c53bb81SPeter Maydell { 2551813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 4) { 2561813e175SRichard Henderson *p = v; 2571813e175SRichard Henderson } else { 2585c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 2595c53bb81SPeter Maydell } 2601813e175SRichard Henderson } 2611813e175SRichard Henderson #endif 2625c53bb81SPeter Maydell 2631813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 8 2644196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v) 265ac26eb69SRichard Henderson { 2661813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 8) { 2671813e175SRichard Henderson *s->code_ptr++ = v; 2681813e175SRichard Henderson } else { 2691813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 2704387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 2711813e175SRichard Henderson s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE); 2721813e175SRichard Henderson } 273ac26eb69SRichard Henderson } 274ac26eb69SRichard Henderson 2754196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p, 2764196dca6SPeter Maydell uint64_t v) 2775c53bb81SPeter Maydell { 2781813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 8) { 2791813e175SRichard Henderson *p = v; 2801813e175SRichard Henderson } else { 2815c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 2825c53bb81SPeter Maydell } 2831813e175SRichard Henderson } 2841813e175SRichard Henderson #endif 2855c53bb81SPeter Maydell 286c896fe29Sbellard /* label relocation processing */ 287c896fe29Sbellard 2881813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type, 289bec16311SRichard Henderson TCGLabel *l, intptr_t addend) 290c896fe29Sbellard { 2917ecd02a0SRichard Henderson TCGRelocation *r = tcg_malloc(sizeof(TCGRelocation)); 292c896fe29Sbellard 293c896fe29Sbellard r->type = type; 294c896fe29Sbellard r->ptr = code_ptr; 295c896fe29Sbellard r->addend = addend; 2967ecd02a0SRichard Henderson QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next); 297c896fe29Sbellard } 298c896fe29Sbellard 299bec16311SRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l, tcg_insn_unit *ptr) 300c896fe29Sbellard { 301eabb7b91SAurelien Jarno tcg_debug_assert(!l->has_value); 302c896fe29Sbellard l->has_value = 1; 3031813e175SRichard Henderson l->u.value_ptr = ptr; 304c896fe29Sbellard } 305c896fe29Sbellard 30642a268c2SRichard Henderson TCGLabel *gen_new_label(void) 307c896fe29Sbellard { 308b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 30951e3972cSRichard Henderson TCGLabel *l = tcg_malloc(sizeof(TCGLabel)); 310c896fe29Sbellard 3117ecd02a0SRichard Henderson memset(l, 0, sizeof(TCGLabel)); 3127ecd02a0SRichard Henderson l->id = s->nb_labels++; 3137ecd02a0SRichard Henderson QSIMPLEQ_INIT(&l->relocs); 3147ecd02a0SRichard Henderson 315bef16ab4SRichard Henderson QSIMPLEQ_INSERT_TAIL(&s->labels, l, next); 31642a268c2SRichard Henderson 31742a268c2SRichard Henderson return l; 318c896fe29Sbellard } 319c896fe29Sbellard 3207ecd02a0SRichard Henderson static bool tcg_resolve_relocs(TCGContext *s) 3217ecd02a0SRichard Henderson { 3227ecd02a0SRichard Henderson TCGLabel *l; 3237ecd02a0SRichard Henderson 3247ecd02a0SRichard Henderson QSIMPLEQ_FOREACH(l, &s->labels, next) { 3257ecd02a0SRichard Henderson TCGRelocation *r; 3267ecd02a0SRichard Henderson uintptr_t value = l->u.value; 3277ecd02a0SRichard Henderson 3287ecd02a0SRichard Henderson QSIMPLEQ_FOREACH(r, &l->relocs, next) { 3297ecd02a0SRichard Henderson if (!patch_reloc(r->ptr, r->type, value, r->addend)) { 3307ecd02a0SRichard Henderson return false; 3317ecd02a0SRichard Henderson } 3327ecd02a0SRichard Henderson } 3337ecd02a0SRichard Henderson } 3347ecd02a0SRichard Henderson return true; 3357ecd02a0SRichard Henderson } 3367ecd02a0SRichard Henderson 3379f754620SRichard Henderson static void set_jmp_reset_offset(TCGContext *s, int which) 3389f754620SRichard Henderson { 339f14bed3fSRichard Henderson /* 340f14bed3fSRichard Henderson * We will check for overflow at the end of the opcode loop in 341f14bed3fSRichard Henderson * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX. 342f14bed3fSRichard Henderson */ 343f14bed3fSRichard Henderson s->tb_jmp_reset_offset[which] = tcg_current_code_size(s); 3449f754620SRichard Henderson } 3459f754620SRichard Henderson 346139c1837SPaolo Bonzini #include "tcg-target.c.inc" 347c896fe29Sbellard 348be2cdc5eSEmilio G. Cota /* compare a pointer @ptr and a tb_tc @s */ 349be2cdc5eSEmilio G. Cota static int ptr_cmp_tb_tc(const void *ptr, const struct tb_tc *s) 350be2cdc5eSEmilio G. Cota { 351be2cdc5eSEmilio G. Cota if (ptr >= s->ptr + s->size) { 352be2cdc5eSEmilio G. Cota return 1; 353be2cdc5eSEmilio G. Cota } else if (ptr < s->ptr) { 354be2cdc5eSEmilio G. Cota return -1; 355be2cdc5eSEmilio G. Cota } 356be2cdc5eSEmilio G. Cota return 0; 357be2cdc5eSEmilio G. Cota } 358be2cdc5eSEmilio G. Cota 359be2cdc5eSEmilio G. Cota static gint tb_tc_cmp(gconstpointer ap, gconstpointer bp) 360be2cdc5eSEmilio G. Cota { 361be2cdc5eSEmilio G. Cota const struct tb_tc *a = ap; 362be2cdc5eSEmilio G. Cota const struct tb_tc *b = bp; 363be2cdc5eSEmilio G. Cota 364be2cdc5eSEmilio G. Cota /* 365be2cdc5eSEmilio G. Cota * When both sizes are set, we know this isn't a lookup. 366be2cdc5eSEmilio G. Cota * This is the most likely case: every TB must be inserted; lookups 367be2cdc5eSEmilio G. Cota * are a lot less frequent. 368be2cdc5eSEmilio G. Cota */ 369be2cdc5eSEmilio G. Cota if (likely(a->size && b->size)) { 370be2cdc5eSEmilio G. Cota if (a->ptr > b->ptr) { 371be2cdc5eSEmilio G. Cota return 1; 372be2cdc5eSEmilio G. Cota } else if (a->ptr < b->ptr) { 373be2cdc5eSEmilio G. Cota return -1; 374be2cdc5eSEmilio G. Cota } 375be2cdc5eSEmilio G. Cota /* a->ptr == b->ptr should happen only on deletions */ 376be2cdc5eSEmilio G. Cota g_assert(a->size == b->size); 377be2cdc5eSEmilio G. Cota return 0; 378be2cdc5eSEmilio G. Cota } 379be2cdc5eSEmilio G. Cota /* 380be2cdc5eSEmilio G. Cota * All lookups have either .size field set to 0. 381be2cdc5eSEmilio G. Cota * From the glib sources we see that @ap is always the lookup key. However 382be2cdc5eSEmilio G. Cota * the docs provide no guarantee, so we just mark this case as likely. 383be2cdc5eSEmilio G. Cota */ 384be2cdc5eSEmilio G. Cota if (likely(a->size == 0)) { 385be2cdc5eSEmilio G. Cota return ptr_cmp_tb_tc(a->ptr, b); 386be2cdc5eSEmilio G. Cota } 387be2cdc5eSEmilio G. Cota return ptr_cmp_tb_tc(b->ptr, a); 388be2cdc5eSEmilio G. Cota } 389be2cdc5eSEmilio G. Cota 390be2cdc5eSEmilio G. Cota static void tcg_region_trees_init(void) 391be2cdc5eSEmilio G. Cota { 392be2cdc5eSEmilio G. Cota size_t i; 393be2cdc5eSEmilio G. Cota 394be2cdc5eSEmilio G. Cota tree_size = ROUND_UP(sizeof(struct tcg_region_tree), qemu_dcache_linesize); 395be2cdc5eSEmilio G. Cota region_trees = qemu_memalign(qemu_dcache_linesize, region.n * tree_size); 396be2cdc5eSEmilio G. Cota for (i = 0; i < region.n; i++) { 397be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = region_trees + i * tree_size; 398be2cdc5eSEmilio G. Cota 399be2cdc5eSEmilio G. Cota qemu_mutex_init(&rt->lock); 400be2cdc5eSEmilio G. Cota rt->tree = g_tree_new(tb_tc_cmp); 401be2cdc5eSEmilio G. Cota } 402be2cdc5eSEmilio G. Cota } 403be2cdc5eSEmilio G. Cota 404be2cdc5eSEmilio G. Cota static struct tcg_region_tree *tc_ptr_to_region_tree(void *p) 405be2cdc5eSEmilio G. Cota { 406be2cdc5eSEmilio G. Cota size_t region_idx; 407be2cdc5eSEmilio G. Cota 408be2cdc5eSEmilio G. Cota if (p < region.start_aligned) { 409be2cdc5eSEmilio G. Cota region_idx = 0; 410be2cdc5eSEmilio G. Cota } else { 411be2cdc5eSEmilio G. Cota ptrdiff_t offset = p - region.start_aligned; 412be2cdc5eSEmilio G. Cota 413be2cdc5eSEmilio G. Cota if (offset > region.stride * (region.n - 1)) { 414be2cdc5eSEmilio G. Cota region_idx = region.n - 1; 415be2cdc5eSEmilio G. Cota } else { 416be2cdc5eSEmilio G. Cota region_idx = offset / region.stride; 417be2cdc5eSEmilio G. Cota } 418be2cdc5eSEmilio G. Cota } 419be2cdc5eSEmilio G. Cota return region_trees + region_idx * tree_size; 420be2cdc5eSEmilio G. Cota } 421be2cdc5eSEmilio G. Cota 422be2cdc5eSEmilio G. Cota void tcg_tb_insert(TranslationBlock *tb) 423be2cdc5eSEmilio G. Cota { 424be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr); 425be2cdc5eSEmilio G. Cota 426be2cdc5eSEmilio G. Cota qemu_mutex_lock(&rt->lock); 427be2cdc5eSEmilio G. Cota g_tree_insert(rt->tree, &tb->tc, tb); 428be2cdc5eSEmilio G. Cota qemu_mutex_unlock(&rt->lock); 429be2cdc5eSEmilio G. Cota } 430be2cdc5eSEmilio G. Cota 431be2cdc5eSEmilio G. Cota void tcg_tb_remove(TranslationBlock *tb) 432be2cdc5eSEmilio G. Cota { 433be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr); 434be2cdc5eSEmilio G. Cota 435be2cdc5eSEmilio G. Cota qemu_mutex_lock(&rt->lock); 436be2cdc5eSEmilio G. Cota g_tree_remove(rt->tree, &tb->tc); 437be2cdc5eSEmilio G. Cota qemu_mutex_unlock(&rt->lock); 438be2cdc5eSEmilio G. Cota } 439be2cdc5eSEmilio G. Cota 440be2cdc5eSEmilio G. Cota /* 441be2cdc5eSEmilio G. Cota * Find the TB 'tb' such that 442be2cdc5eSEmilio G. Cota * tb->tc.ptr <= tc_ptr < tb->tc.ptr + tb->tc.size 443be2cdc5eSEmilio G. Cota * Return NULL if not found. 444be2cdc5eSEmilio G. Cota */ 445be2cdc5eSEmilio G. Cota TranslationBlock *tcg_tb_lookup(uintptr_t tc_ptr) 446be2cdc5eSEmilio G. Cota { 447be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = tc_ptr_to_region_tree((void *)tc_ptr); 448be2cdc5eSEmilio G. Cota TranslationBlock *tb; 449be2cdc5eSEmilio G. Cota struct tb_tc s = { .ptr = (void *)tc_ptr }; 450be2cdc5eSEmilio G. Cota 451be2cdc5eSEmilio G. Cota qemu_mutex_lock(&rt->lock); 452be2cdc5eSEmilio G. Cota tb = g_tree_lookup(rt->tree, &s); 453be2cdc5eSEmilio G. Cota qemu_mutex_unlock(&rt->lock); 454be2cdc5eSEmilio G. Cota return tb; 455be2cdc5eSEmilio G. Cota } 456be2cdc5eSEmilio G. Cota 457be2cdc5eSEmilio G. Cota static void tcg_region_tree_lock_all(void) 458be2cdc5eSEmilio G. Cota { 459be2cdc5eSEmilio G. Cota size_t i; 460be2cdc5eSEmilio G. Cota 461be2cdc5eSEmilio G. Cota for (i = 0; i < region.n; i++) { 462be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = region_trees + i * tree_size; 463be2cdc5eSEmilio G. Cota 464be2cdc5eSEmilio G. Cota qemu_mutex_lock(&rt->lock); 465be2cdc5eSEmilio G. Cota } 466be2cdc5eSEmilio G. Cota } 467be2cdc5eSEmilio G. Cota 468be2cdc5eSEmilio G. Cota static void tcg_region_tree_unlock_all(void) 469be2cdc5eSEmilio G. Cota { 470be2cdc5eSEmilio G. Cota size_t i; 471be2cdc5eSEmilio G. Cota 472be2cdc5eSEmilio G. Cota for (i = 0; i < region.n; i++) { 473be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = region_trees + i * tree_size; 474be2cdc5eSEmilio G. Cota 475be2cdc5eSEmilio G. Cota qemu_mutex_unlock(&rt->lock); 476be2cdc5eSEmilio G. Cota } 477be2cdc5eSEmilio G. Cota } 478be2cdc5eSEmilio G. Cota 479be2cdc5eSEmilio G. Cota void tcg_tb_foreach(GTraverseFunc func, gpointer user_data) 480be2cdc5eSEmilio G. Cota { 481be2cdc5eSEmilio G. Cota size_t i; 482be2cdc5eSEmilio G. Cota 483be2cdc5eSEmilio G. Cota tcg_region_tree_lock_all(); 484be2cdc5eSEmilio G. Cota for (i = 0; i < region.n; i++) { 485be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = region_trees + i * tree_size; 486be2cdc5eSEmilio G. Cota 487be2cdc5eSEmilio G. Cota g_tree_foreach(rt->tree, func, user_data); 488be2cdc5eSEmilio G. Cota } 489be2cdc5eSEmilio G. Cota tcg_region_tree_unlock_all(); 490be2cdc5eSEmilio G. Cota } 491be2cdc5eSEmilio G. Cota 492be2cdc5eSEmilio G. Cota size_t tcg_nb_tbs(void) 493be2cdc5eSEmilio G. Cota { 494be2cdc5eSEmilio G. Cota size_t nb_tbs = 0; 495be2cdc5eSEmilio G. Cota size_t i; 496be2cdc5eSEmilio G. Cota 497be2cdc5eSEmilio G. Cota tcg_region_tree_lock_all(); 498be2cdc5eSEmilio G. Cota for (i = 0; i < region.n; i++) { 499be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = region_trees + i * tree_size; 500be2cdc5eSEmilio G. Cota 501be2cdc5eSEmilio G. Cota nb_tbs += g_tree_nnodes(rt->tree); 502be2cdc5eSEmilio G. Cota } 503be2cdc5eSEmilio G. Cota tcg_region_tree_unlock_all(); 504be2cdc5eSEmilio G. Cota return nb_tbs; 505be2cdc5eSEmilio G. Cota } 506be2cdc5eSEmilio G. Cota 507938e897aSEmilio G. Cota static gboolean tcg_region_tree_traverse(gpointer k, gpointer v, gpointer data) 508938e897aSEmilio G. Cota { 509938e897aSEmilio G. Cota TranslationBlock *tb = v; 510938e897aSEmilio G. Cota 511938e897aSEmilio G. Cota tb_destroy(tb); 512938e897aSEmilio G. Cota return FALSE; 513938e897aSEmilio G. Cota } 514938e897aSEmilio G. Cota 515be2cdc5eSEmilio G. Cota static void tcg_region_tree_reset_all(void) 516be2cdc5eSEmilio G. Cota { 517be2cdc5eSEmilio G. Cota size_t i; 518be2cdc5eSEmilio G. Cota 519be2cdc5eSEmilio G. Cota tcg_region_tree_lock_all(); 520be2cdc5eSEmilio G. Cota for (i = 0; i < region.n; i++) { 521be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = region_trees + i * tree_size; 522be2cdc5eSEmilio G. Cota 523938e897aSEmilio G. Cota g_tree_foreach(rt->tree, tcg_region_tree_traverse, NULL); 524be2cdc5eSEmilio G. Cota /* Increment the refcount first so that destroy acts as a reset */ 525be2cdc5eSEmilio G. Cota g_tree_ref(rt->tree); 526be2cdc5eSEmilio G. Cota g_tree_destroy(rt->tree); 527be2cdc5eSEmilio G. Cota } 528be2cdc5eSEmilio G. Cota tcg_region_tree_unlock_all(); 529be2cdc5eSEmilio G. Cota } 530be2cdc5eSEmilio G. Cota 531e8feb96fSEmilio G. Cota static void tcg_region_bounds(size_t curr_region, void **pstart, void **pend) 532e8feb96fSEmilio G. Cota { 533e8feb96fSEmilio G. Cota void *start, *end; 534e8feb96fSEmilio G. Cota 535e8feb96fSEmilio G. Cota start = region.start_aligned + curr_region * region.stride; 536e8feb96fSEmilio G. Cota end = start + region.size; 537e8feb96fSEmilio G. Cota 538e8feb96fSEmilio G. Cota if (curr_region == 0) { 539e8feb96fSEmilio G. Cota start = region.start; 540e8feb96fSEmilio G. Cota } 541e8feb96fSEmilio G. Cota if (curr_region == region.n - 1) { 542e8feb96fSEmilio G. Cota end = region.end; 543e8feb96fSEmilio G. Cota } 544e8feb96fSEmilio G. Cota 545e8feb96fSEmilio G. Cota *pstart = start; 546e8feb96fSEmilio G. Cota *pend = end; 547e8feb96fSEmilio G. Cota } 548e8feb96fSEmilio G. Cota 549e8feb96fSEmilio G. Cota static void tcg_region_assign(TCGContext *s, size_t curr_region) 550e8feb96fSEmilio G. Cota { 551e8feb96fSEmilio G. Cota void *start, *end; 552e8feb96fSEmilio G. Cota 553e8feb96fSEmilio G. Cota tcg_region_bounds(curr_region, &start, &end); 554e8feb96fSEmilio G. Cota 555e8feb96fSEmilio G. Cota s->code_gen_buffer = start; 556e8feb96fSEmilio G. Cota s->code_gen_ptr = start; 557e8feb96fSEmilio G. Cota s->code_gen_buffer_size = end - start; 558e8feb96fSEmilio G. Cota s->code_gen_highwater = end - TCG_HIGHWATER; 559e8feb96fSEmilio G. Cota } 560e8feb96fSEmilio G. Cota 561e8feb96fSEmilio G. Cota static bool tcg_region_alloc__locked(TCGContext *s) 562e8feb96fSEmilio G. Cota { 563e8feb96fSEmilio G. Cota if (region.current == region.n) { 564e8feb96fSEmilio G. Cota return true; 565e8feb96fSEmilio G. Cota } 566e8feb96fSEmilio G. Cota tcg_region_assign(s, region.current); 567e8feb96fSEmilio G. Cota region.current++; 568e8feb96fSEmilio G. Cota return false; 569e8feb96fSEmilio G. Cota } 570e8feb96fSEmilio G. Cota 571e8feb96fSEmilio G. Cota /* 572e8feb96fSEmilio G. Cota * Request a new region once the one in use has filled up. 573e8feb96fSEmilio G. Cota * Returns true on error. 574e8feb96fSEmilio G. Cota */ 575e8feb96fSEmilio G. Cota static bool tcg_region_alloc(TCGContext *s) 576e8feb96fSEmilio G. Cota { 577e8feb96fSEmilio G. Cota bool err; 578e8feb96fSEmilio G. Cota /* read the region size now; alloc__locked will overwrite it on success */ 579e8feb96fSEmilio G. Cota size_t size_full = s->code_gen_buffer_size; 580e8feb96fSEmilio G. Cota 581e8feb96fSEmilio G. Cota qemu_mutex_lock(®ion.lock); 582e8feb96fSEmilio G. Cota err = tcg_region_alloc__locked(s); 583e8feb96fSEmilio G. Cota if (!err) { 584e8feb96fSEmilio G. Cota region.agg_size_full += size_full - TCG_HIGHWATER; 585e8feb96fSEmilio G. Cota } 586e8feb96fSEmilio G. Cota qemu_mutex_unlock(®ion.lock); 587e8feb96fSEmilio G. Cota return err; 588e8feb96fSEmilio G. Cota } 589e8feb96fSEmilio G. Cota 590e8feb96fSEmilio G. Cota /* 591e8feb96fSEmilio G. Cota * Perform a context's first region allocation. 592e8feb96fSEmilio G. Cota * This function does _not_ increment region.agg_size_full. 593e8feb96fSEmilio G. Cota */ 594e8feb96fSEmilio G. Cota static inline bool tcg_region_initial_alloc__locked(TCGContext *s) 595e8feb96fSEmilio G. Cota { 596e8feb96fSEmilio G. Cota return tcg_region_alloc__locked(s); 597e8feb96fSEmilio G. Cota } 598e8feb96fSEmilio G. Cota 599e8feb96fSEmilio G. Cota /* Call from a safe-work context */ 600e8feb96fSEmilio G. Cota void tcg_region_reset_all(void) 601e8feb96fSEmilio G. Cota { 602d73415a3SStefan Hajnoczi unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs); 603e8feb96fSEmilio G. Cota unsigned int i; 604e8feb96fSEmilio G. Cota 605e8feb96fSEmilio G. Cota qemu_mutex_lock(®ion.lock); 606e8feb96fSEmilio G. Cota region.current = 0; 607e8feb96fSEmilio G. Cota region.agg_size_full = 0; 608e8feb96fSEmilio G. Cota 6093468b59eSEmilio G. Cota for (i = 0; i < n_ctxs; i++) { 610d73415a3SStefan Hajnoczi TCGContext *s = qatomic_read(&tcg_ctxs[i]); 6113468b59eSEmilio G. Cota bool err = tcg_region_initial_alloc__locked(s); 612e8feb96fSEmilio G. Cota 613e8feb96fSEmilio G. Cota g_assert(!err); 614e8feb96fSEmilio G. Cota } 615e8feb96fSEmilio G. Cota qemu_mutex_unlock(®ion.lock); 616be2cdc5eSEmilio G. Cota 617be2cdc5eSEmilio G. Cota tcg_region_tree_reset_all(); 618e8feb96fSEmilio G. Cota } 619e8feb96fSEmilio G. Cota 6203468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY 6213468b59eSEmilio G. Cota static size_t tcg_n_regions(void) 6223468b59eSEmilio G. Cota { 6233468b59eSEmilio G. Cota return 1; 6243468b59eSEmilio G. Cota } 6253468b59eSEmilio G. Cota #else 6263468b59eSEmilio G. Cota /* 6273468b59eSEmilio G. Cota * It is likely that some vCPUs will translate more code than others, so we 6283468b59eSEmilio G. Cota * first try to set more regions than max_cpus, with those regions being of 6293468b59eSEmilio G. Cota * reasonable size. If that's not possible we make do by evenly dividing 6303468b59eSEmilio G. Cota * the code_gen_buffer among the vCPUs. 6313468b59eSEmilio G. Cota */ 6323468b59eSEmilio G. Cota static size_t tcg_n_regions(void) 6333468b59eSEmilio G. Cota { 6343468b59eSEmilio G. Cota size_t i; 6353468b59eSEmilio G. Cota 6363468b59eSEmilio G. Cota /* Use a single region if all we have is one vCPU thread */ 6375cc8767dSLike Xu #if !defined(CONFIG_USER_ONLY) 6385cc8767dSLike Xu MachineState *ms = MACHINE(qdev_get_machine()); 6395cc8767dSLike Xu unsigned int max_cpus = ms->smp.max_cpus; 6405cc8767dSLike Xu #endif 6413468b59eSEmilio G. Cota if (max_cpus == 1 || !qemu_tcg_mttcg_enabled()) { 6423468b59eSEmilio G. Cota return 1; 6433468b59eSEmilio G. Cota } 6443468b59eSEmilio G. Cota 6453468b59eSEmilio G. Cota /* Try to have more regions than max_cpus, with each region being >= 2 MB */ 6463468b59eSEmilio G. Cota for (i = 8; i > 0; i--) { 6473468b59eSEmilio G. Cota size_t regions_per_thread = i; 6483468b59eSEmilio G. Cota size_t region_size; 6493468b59eSEmilio G. Cota 6503468b59eSEmilio G. Cota region_size = tcg_init_ctx.code_gen_buffer_size; 6513468b59eSEmilio G. Cota region_size /= max_cpus * regions_per_thread; 6523468b59eSEmilio G. Cota 6533468b59eSEmilio G. Cota if (region_size >= 2 * 1024u * 1024) { 6543468b59eSEmilio G. Cota return max_cpus * regions_per_thread; 6553468b59eSEmilio G. Cota } 6563468b59eSEmilio G. Cota } 6573468b59eSEmilio G. Cota /* If we can't, then just allocate one region per vCPU thread */ 6583468b59eSEmilio G. Cota return max_cpus; 6593468b59eSEmilio G. Cota } 6603468b59eSEmilio G. Cota #endif 6613468b59eSEmilio G. Cota 662e8feb96fSEmilio G. Cota /* 663e8feb96fSEmilio G. Cota * Initializes region partitioning. 664e8feb96fSEmilio G. Cota * 665e8feb96fSEmilio G. Cota * Called at init time from the parent thread (i.e. the one calling 666e8feb96fSEmilio G. Cota * tcg_context_init), after the target's TCG globals have been set. 6673468b59eSEmilio G. Cota * 6683468b59eSEmilio G. Cota * Region partitioning works by splitting code_gen_buffer into separate regions, 6693468b59eSEmilio G. Cota * and then assigning regions to TCG threads so that the threads can translate 6703468b59eSEmilio G. Cota * code in parallel without synchronization. 6713468b59eSEmilio G. Cota * 6723468b59eSEmilio G. Cota * In softmmu the number of TCG threads is bounded by max_cpus, so we use at 6733468b59eSEmilio G. Cota * least max_cpus regions in MTTCG. In !MTTCG we use a single region. 6743468b59eSEmilio G. Cota * Note that the TCG options from the command-line (i.e. -accel accel=tcg,[...]) 6753468b59eSEmilio G. Cota * must have been parsed before calling this function, since it calls 6763468b59eSEmilio G. Cota * qemu_tcg_mttcg_enabled(). 6773468b59eSEmilio G. Cota * 6783468b59eSEmilio G. Cota * In user-mode we use a single region. Having multiple regions in user-mode 6793468b59eSEmilio G. Cota * is not supported, because the number of vCPU threads (recall that each thread 6803468b59eSEmilio G. Cota * spawned by the guest corresponds to a vCPU thread) is only bounded by the 6813468b59eSEmilio G. Cota * OS, and usually this number is huge (tens of thousands is not uncommon). 6823468b59eSEmilio G. Cota * Thus, given this large bound on the number of vCPU threads and the fact 6833468b59eSEmilio G. Cota * that code_gen_buffer is allocated at compile-time, we cannot guarantee 6843468b59eSEmilio G. Cota * that the availability of at least one region per vCPU thread. 6853468b59eSEmilio G. Cota * 6863468b59eSEmilio G. Cota * However, this user-mode limitation is unlikely to be a significant problem 6873468b59eSEmilio G. Cota * in practice. Multi-threaded guests share most if not all of their translated 6883468b59eSEmilio G. Cota * code, which makes parallel code generation less appealing than in softmmu. 689e8feb96fSEmilio G. Cota */ 690e8feb96fSEmilio G. Cota void tcg_region_init(void) 691e8feb96fSEmilio G. Cota { 692e8feb96fSEmilio G. Cota void *buf = tcg_init_ctx.code_gen_buffer; 693e8feb96fSEmilio G. Cota void *aligned; 694e8feb96fSEmilio G. Cota size_t size = tcg_init_ctx.code_gen_buffer_size; 695e8feb96fSEmilio G. Cota size_t page_size = qemu_real_host_page_size; 696e8feb96fSEmilio G. Cota size_t region_size; 697e8feb96fSEmilio G. Cota size_t n_regions; 698e8feb96fSEmilio G. Cota size_t i; 699e8feb96fSEmilio G. Cota 7003468b59eSEmilio G. Cota n_regions = tcg_n_regions(); 701e8feb96fSEmilio G. Cota 702e8feb96fSEmilio G. Cota /* The first region will be 'aligned - buf' bytes larger than the others */ 703e8feb96fSEmilio G. Cota aligned = QEMU_ALIGN_PTR_UP(buf, page_size); 704e8feb96fSEmilio G. Cota g_assert(aligned < tcg_init_ctx.code_gen_buffer + size); 705e8feb96fSEmilio G. Cota /* 706e8feb96fSEmilio G. Cota * Make region_size a multiple of page_size, using aligned as the start. 707e8feb96fSEmilio G. Cota * As a result of this we might end up with a few extra pages at the end of 708e8feb96fSEmilio G. Cota * the buffer; we will assign those to the last region. 709e8feb96fSEmilio G. Cota */ 710e8feb96fSEmilio G. Cota region_size = (size - (aligned - buf)) / n_regions; 711e8feb96fSEmilio G. Cota region_size = QEMU_ALIGN_DOWN(region_size, page_size); 712e8feb96fSEmilio G. Cota 713e8feb96fSEmilio G. Cota /* A region must have at least 2 pages; one code, one guard */ 714e8feb96fSEmilio G. Cota g_assert(region_size >= 2 * page_size); 715e8feb96fSEmilio G. Cota 716e8feb96fSEmilio G. Cota /* init the region struct */ 717e8feb96fSEmilio G. Cota qemu_mutex_init(®ion.lock); 718e8feb96fSEmilio G. Cota region.n = n_regions; 719e8feb96fSEmilio G. Cota region.size = region_size - page_size; 720e8feb96fSEmilio G. Cota region.stride = region_size; 721e8feb96fSEmilio G. Cota region.start = buf; 722e8feb96fSEmilio G. Cota region.start_aligned = aligned; 723e8feb96fSEmilio G. Cota /* page-align the end, since its last page will be a guard page */ 724e8feb96fSEmilio G. Cota region.end = QEMU_ALIGN_PTR_DOWN(buf + size, page_size); 725e8feb96fSEmilio G. Cota /* account for that last guard page */ 726e8feb96fSEmilio G. Cota region.end -= page_size; 727e8feb96fSEmilio G. Cota 728e8feb96fSEmilio G. Cota /* set guard pages */ 729e8feb96fSEmilio G. Cota for (i = 0; i < region.n; i++) { 730e8feb96fSEmilio G. Cota void *start, *end; 731e8feb96fSEmilio G. Cota int rc; 732e8feb96fSEmilio G. Cota 733e8feb96fSEmilio G. Cota tcg_region_bounds(i, &start, &end); 734e8feb96fSEmilio G. Cota rc = qemu_mprotect_none(end, page_size); 735e8feb96fSEmilio G. Cota g_assert(!rc); 736e8feb96fSEmilio G. Cota } 737e8feb96fSEmilio G. Cota 738be2cdc5eSEmilio G. Cota tcg_region_trees_init(); 739be2cdc5eSEmilio G. Cota 7403468b59eSEmilio G. Cota /* In user-mode we support only one ctx, so do the initial allocation now */ 7413468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY 742e8feb96fSEmilio G. Cota { 743e8feb96fSEmilio G. Cota bool err = tcg_region_initial_alloc__locked(tcg_ctx); 744e8feb96fSEmilio G. Cota 745e8feb96fSEmilio G. Cota g_assert(!err); 746e8feb96fSEmilio G. Cota } 7473468b59eSEmilio G. Cota #endif 748e8feb96fSEmilio G. Cota } 749e8feb96fSEmilio G. Cota 75038b47b19SEmilio G. Cota static void alloc_tcg_plugin_context(TCGContext *s) 75138b47b19SEmilio G. Cota { 75238b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN 75338b47b19SEmilio G. Cota s->plugin_tb = g_new0(struct qemu_plugin_tb, 1); 75438b47b19SEmilio G. Cota s->plugin_tb->insns = 75538b47b19SEmilio G. Cota g_ptr_array_new_with_free_func(qemu_plugin_insn_cleanup_fn); 75638b47b19SEmilio G. Cota #endif 75738b47b19SEmilio G. Cota } 75838b47b19SEmilio G. Cota 759e8feb96fSEmilio G. Cota /* 7603468b59eSEmilio G. Cota * All TCG threads except the parent (i.e. the one that called tcg_context_init 7613468b59eSEmilio G. Cota * and registered the target's TCG globals) must register with this function 7623468b59eSEmilio G. Cota * before initiating translation. 7633468b59eSEmilio G. Cota * 7643468b59eSEmilio G. Cota * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation 7653468b59eSEmilio G. Cota * of tcg_region_init() for the reasoning behind this. 7663468b59eSEmilio G. Cota * 7673468b59eSEmilio G. Cota * In softmmu each caller registers its context in tcg_ctxs[]. Note that in 7683468b59eSEmilio G. Cota * softmmu tcg_ctxs[] does not track tcg_ctx_init, since the initial context 7693468b59eSEmilio G. Cota * is not used anymore for translation once this function is called. 7703468b59eSEmilio G. Cota * 7713468b59eSEmilio G. Cota * Not tracking tcg_init_ctx in tcg_ctxs[] in softmmu keeps code that iterates 7723468b59eSEmilio G. Cota * over the array (e.g. tcg_code_size() the same for both softmmu and user-mode. 7733468b59eSEmilio G. Cota */ 7743468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY 7753468b59eSEmilio G. Cota void tcg_register_thread(void) 7763468b59eSEmilio G. Cota { 7773468b59eSEmilio G. Cota tcg_ctx = &tcg_init_ctx; 7783468b59eSEmilio G. Cota } 7793468b59eSEmilio G. Cota #else 7803468b59eSEmilio G. Cota void tcg_register_thread(void) 7813468b59eSEmilio G. Cota { 7825cc8767dSLike Xu MachineState *ms = MACHINE(qdev_get_machine()); 7833468b59eSEmilio G. Cota TCGContext *s = g_malloc(sizeof(*s)); 7843468b59eSEmilio G. Cota unsigned int i, n; 7853468b59eSEmilio G. Cota bool err; 7863468b59eSEmilio G. Cota 7873468b59eSEmilio G. Cota *s = tcg_init_ctx; 7883468b59eSEmilio G. Cota 7893468b59eSEmilio G. Cota /* Relink mem_base. */ 7903468b59eSEmilio G. Cota for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) { 7913468b59eSEmilio G. Cota if (tcg_init_ctx.temps[i].mem_base) { 7923468b59eSEmilio G. Cota ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps; 7933468b59eSEmilio G. Cota tcg_debug_assert(b >= 0 && b < n); 7943468b59eSEmilio G. Cota s->temps[i].mem_base = &s->temps[b]; 7953468b59eSEmilio G. Cota } 7963468b59eSEmilio G. Cota } 7973468b59eSEmilio G. Cota 7983468b59eSEmilio G. Cota /* Claim an entry in tcg_ctxs */ 799d73415a3SStefan Hajnoczi n = qatomic_fetch_inc(&n_tcg_ctxs); 8005cc8767dSLike Xu g_assert(n < ms->smp.max_cpus); 801d73415a3SStefan Hajnoczi qatomic_set(&tcg_ctxs[n], s); 8023468b59eSEmilio G. Cota 80338b47b19SEmilio G. Cota if (n > 0) { 80438b47b19SEmilio G. Cota alloc_tcg_plugin_context(s); 80538b47b19SEmilio G. Cota } 80638b47b19SEmilio G. Cota 8073468b59eSEmilio G. Cota tcg_ctx = s; 8083468b59eSEmilio G. Cota qemu_mutex_lock(®ion.lock); 8093468b59eSEmilio G. Cota err = tcg_region_initial_alloc__locked(tcg_ctx); 8103468b59eSEmilio G. Cota g_assert(!err); 8113468b59eSEmilio G. Cota qemu_mutex_unlock(®ion.lock); 8123468b59eSEmilio G. Cota } 8133468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */ 8143468b59eSEmilio G. Cota 8153468b59eSEmilio G. Cota /* 816e8feb96fSEmilio G. Cota * Returns the size (in bytes) of all translated code (i.e. from all regions) 817e8feb96fSEmilio G. Cota * currently in the cache. 818e8feb96fSEmilio G. Cota * See also: tcg_code_capacity() 819e8feb96fSEmilio G. Cota * Do not confuse with tcg_current_code_size(); that one applies to a single 820e8feb96fSEmilio G. Cota * TCG context. 821e8feb96fSEmilio G. Cota */ 822e8feb96fSEmilio G. Cota size_t tcg_code_size(void) 823e8feb96fSEmilio G. Cota { 824d73415a3SStefan Hajnoczi unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs); 825e8feb96fSEmilio G. Cota unsigned int i; 826e8feb96fSEmilio G. Cota size_t total; 827e8feb96fSEmilio G. Cota 828e8feb96fSEmilio G. Cota qemu_mutex_lock(®ion.lock); 829e8feb96fSEmilio G. Cota total = region.agg_size_full; 8303468b59eSEmilio G. Cota for (i = 0; i < n_ctxs; i++) { 831d73415a3SStefan Hajnoczi const TCGContext *s = qatomic_read(&tcg_ctxs[i]); 832e8feb96fSEmilio G. Cota size_t size; 833e8feb96fSEmilio G. Cota 834d73415a3SStefan Hajnoczi size = qatomic_read(&s->code_gen_ptr) - s->code_gen_buffer; 835e8feb96fSEmilio G. Cota g_assert(size <= s->code_gen_buffer_size); 836e8feb96fSEmilio G. Cota total += size; 837e8feb96fSEmilio G. Cota } 838e8feb96fSEmilio G. Cota qemu_mutex_unlock(®ion.lock); 839e8feb96fSEmilio G. Cota return total; 840e8feb96fSEmilio G. Cota } 841e8feb96fSEmilio G. Cota 842e8feb96fSEmilio G. Cota /* 843e8feb96fSEmilio G. Cota * Returns the code capacity (in bytes) of the entire cache, i.e. including all 844e8feb96fSEmilio G. Cota * regions. 845e8feb96fSEmilio G. Cota * See also: tcg_code_size() 846e8feb96fSEmilio G. Cota */ 847e8feb96fSEmilio G. Cota size_t tcg_code_capacity(void) 848e8feb96fSEmilio G. Cota { 849e8feb96fSEmilio G. Cota size_t guard_size, capacity; 850e8feb96fSEmilio G. Cota 851e8feb96fSEmilio G. Cota /* no need for synchronization; these variables are set at init time */ 852e8feb96fSEmilio G. Cota guard_size = region.stride - region.size; 853e8feb96fSEmilio G. Cota capacity = region.end + guard_size - region.start; 854e8feb96fSEmilio G. Cota capacity -= region.n * (guard_size + TCG_HIGHWATER); 855e8feb96fSEmilio G. Cota return capacity; 856e8feb96fSEmilio G. Cota } 857e8feb96fSEmilio G. Cota 858128ed227SEmilio G. Cota size_t tcg_tb_phys_invalidate_count(void) 859128ed227SEmilio G. Cota { 860d73415a3SStefan Hajnoczi unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs); 861128ed227SEmilio G. Cota unsigned int i; 862128ed227SEmilio G. Cota size_t total = 0; 863128ed227SEmilio G. Cota 864128ed227SEmilio G. Cota for (i = 0; i < n_ctxs; i++) { 865d73415a3SStefan Hajnoczi const TCGContext *s = qatomic_read(&tcg_ctxs[i]); 866128ed227SEmilio G. Cota 867d73415a3SStefan Hajnoczi total += qatomic_read(&s->tb_phys_invalidate_count); 868128ed227SEmilio G. Cota } 869128ed227SEmilio G. Cota return total; 870128ed227SEmilio G. Cota } 871128ed227SEmilio G. Cota 872c896fe29Sbellard /* pool based memory allocation */ 873c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size) 874c896fe29Sbellard { 875c896fe29Sbellard TCGPool *p; 876c896fe29Sbellard int pool_size; 877c896fe29Sbellard 878c896fe29Sbellard if (size > TCG_POOL_CHUNK_SIZE) { 879c896fe29Sbellard /* big malloc: insert a new pool (XXX: could optimize) */ 8807267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + size); 881c896fe29Sbellard p->size = size; 8824055299eSKirill Batuzov p->next = s->pool_first_large; 8834055299eSKirill Batuzov s->pool_first_large = p; 8844055299eSKirill Batuzov return p->data; 885c896fe29Sbellard } else { 886c896fe29Sbellard p = s->pool_current; 887c896fe29Sbellard if (!p) { 888c896fe29Sbellard p = s->pool_first; 889c896fe29Sbellard if (!p) 890c896fe29Sbellard goto new_pool; 891c896fe29Sbellard } else { 892c896fe29Sbellard if (!p->next) { 893c896fe29Sbellard new_pool: 894c896fe29Sbellard pool_size = TCG_POOL_CHUNK_SIZE; 8957267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + pool_size); 896c896fe29Sbellard p->size = pool_size; 897c896fe29Sbellard p->next = NULL; 898c896fe29Sbellard if (s->pool_current) 899c896fe29Sbellard s->pool_current->next = p; 900c896fe29Sbellard else 901c896fe29Sbellard s->pool_first = p; 902c896fe29Sbellard } else { 903c896fe29Sbellard p = p->next; 904c896fe29Sbellard } 905c896fe29Sbellard } 906c896fe29Sbellard } 907c896fe29Sbellard s->pool_current = p; 908c896fe29Sbellard s->pool_cur = p->data + size; 909c896fe29Sbellard s->pool_end = p->data + p->size; 910c896fe29Sbellard return p->data; 911c896fe29Sbellard } 912c896fe29Sbellard 913c896fe29Sbellard void tcg_pool_reset(TCGContext *s) 914c896fe29Sbellard { 9154055299eSKirill Batuzov TCGPool *p, *t; 9164055299eSKirill Batuzov for (p = s->pool_first_large; p; p = t) { 9174055299eSKirill Batuzov t = p->next; 9184055299eSKirill Batuzov g_free(p); 9194055299eSKirill Batuzov } 9204055299eSKirill Batuzov s->pool_first_large = NULL; 921c896fe29Sbellard s->pool_cur = s->pool_end = NULL; 922c896fe29Sbellard s->pool_current = NULL; 923c896fe29Sbellard } 924c896fe29Sbellard 925100b5e01SRichard Henderson typedef struct TCGHelperInfo { 926100b5e01SRichard Henderson void *func; 927100b5e01SRichard Henderson const char *name; 928afb49896SRichard Henderson unsigned flags; 929afb49896SRichard Henderson unsigned sizemask; 930100b5e01SRichard Henderson } TCGHelperInfo; 931100b5e01SRichard Henderson 9322ef6175aSRichard Henderson #include "exec/helper-proto.h" 9332ef6175aSRichard Henderson 934100b5e01SRichard Henderson static const TCGHelperInfo all_helpers[] = { 9352ef6175aSRichard Henderson #include "exec/helper-tcg.h" 936100b5e01SRichard Henderson }; 937619205fdSEmilio G. Cota static GHashTable *helper_table; 938100b5e01SRichard Henderson 93991478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)]; 940f69d277eSRichard Henderson static void process_op_defs(TCGContext *s); 9411c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type, 9421c2adb95SRichard Henderson TCGReg reg, const char *name); 94391478cefSRichard Henderson 944c896fe29Sbellard void tcg_context_init(TCGContext *s) 945c896fe29Sbellard { 946100b5e01SRichard Henderson int op, total_args, n, i; 947c896fe29Sbellard TCGOpDef *def; 948c896fe29Sbellard TCGArgConstraint *args_ct; 9491c2adb95SRichard Henderson TCGTemp *ts; 950c896fe29Sbellard 951c896fe29Sbellard memset(s, 0, sizeof(*s)); 952c896fe29Sbellard s->nb_globals = 0; 953c896fe29Sbellard 954c896fe29Sbellard /* Count total number of arguments and allocate the corresponding 955c896fe29Sbellard space */ 956c896fe29Sbellard total_args = 0; 957c896fe29Sbellard for(op = 0; op < NB_OPS; op++) { 958c896fe29Sbellard def = &tcg_op_defs[op]; 959c896fe29Sbellard n = def->nb_iargs + def->nb_oargs; 960c896fe29Sbellard total_args += n; 961c896fe29Sbellard } 962c896fe29Sbellard 963bc2b17e6SRichard Henderson args_ct = g_new0(TCGArgConstraint, total_args); 964c896fe29Sbellard 965c896fe29Sbellard for(op = 0; op < NB_OPS; op++) { 966c896fe29Sbellard def = &tcg_op_defs[op]; 967c896fe29Sbellard def->args_ct = args_ct; 968c896fe29Sbellard n = def->nb_iargs + def->nb_oargs; 969c896fe29Sbellard args_ct += n; 970c896fe29Sbellard } 971c896fe29Sbellard 9725cd8f621SRichard Henderson /* Register helpers. */ 97384fd9dd3SRichard Henderson /* Use g_direct_hash/equal for direct pointer comparisons on func. */ 974619205fdSEmilio G. Cota helper_table = g_hash_table_new(NULL, NULL); 97584fd9dd3SRichard Henderson 976100b5e01SRichard Henderson for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) { 97784fd9dd3SRichard Henderson g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func, 97872866e82SRichard Henderson (gpointer)&all_helpers[i]); 979100b5e01SRichard Henderson } 9805cd8f621SRichard Henderson 981c896fe29Sbellard tcg_target_init(s); 982f69d277eSRichard Henderson process_op_defs(s); 98391478cefSRichard Henderson 98491478cefSRichard Henderson /* Reverse the order of the saved registers, assuming they're all at 98591478cefSRichard Henderson the start of tcg_target_reg_alloc_order. */ 98691478cefSRichard Henderson for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) { 98791478cefSRichard Henderson int r = tcg_target_reg_alloc_order[n]; 98891478cefSRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) { 98991478cefSRichard Henderson break; 99091478cefSRichard Henderson } 99191478cefSRichard Henderson } 99291478cefSRichard Henderson for (i = 0; i < n; ++i) { 99391478cefSRichard Henderson indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i]; 99491478cefSRichard Henderson } 99591478cefSRichard Henderson for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) { 99691478cefSRichard Henderson indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i]; 99791478cefSRichard Henderson } 998b1311c4aSEmilio G. Cota 99938b47b19SEmilio G. Cota alloc_tcg_plugin_context(s); 100038b47b19SEmilio G. Cota 1001b1311c4aSEmilio G. Cota tcg_ctx = s; 10023468b59eSEmilio G. Cota /* 10033468b59eSEmilio G. Cota * In user-mode we simply share the init context among threads, since we 10043468b59eSEmilio G. Cota * use a single region. See the documentation tcg_region_init() for the 10053468b59eSEmilio G. Cota * reasoning behind this. 10063468b59eSEmilio G. Cota * In softmmu we will have at most max_cpus TCG threads. 10073468b59eSEmilio G. Cota */ 10083468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY 1009df2cce29SEmilio G. Cota tcg_ctxs = &tcg_ctx; 1010df2cce29SEmilio G. Cota n_tcg_ctxs = 1; 10113468b59eSEmilio G. Cota #else 10125cc8767dSLike Xu MachineState *ms = MACHINE(qdev_get_machine()); 10135cc8767dSLike Xu unsigned int max_cpus = ms->smp.max_cpus; 10143468b59eSEmilio G. Cota tcg_ctxs = g_new(TCGContext *, max_cpus); 10153468b59eSEmilio G. Cota #endif 10161c2adb95SRichard Henderson 10171c2adb95SRichard Henderson tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0)); 10181c2adb95SRichard Henderson ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env"); 10191c2adb95SRichard Henderson cpu_env = temp_tcgv_ptr(ts); 10209002ec79SRichard Henderson } 1021b03cce8eSbellard 10226e3b2bfdSEmilio G. Cota /* 10236e3b2bfdSEmilio G. Cota * Allocate TBs right before their corresponding translated code, making 10246e3b2bfdSEmilio G. Cota * sure that TBs and code are on different cache lines. 10256e3b2bfdSEmilio G. Cota */ 10266e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s) 10276e3b2bfdSEmilio G. Cota { 10286e3b2bfdSEmilio G. Cota uintptr_t align = qemu_icache_linesize; 10296e3b2bfdSEmilio G. Cota TranslationBlock *tb; 10306e3b2bfdSEmilio G. Cota void *next; 10316e3b2bfdSEmilio G. Cota 1032e8feb96fSEmilio G. Cota retry: 10336e3b2bfdSEmilio G. Cota tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align); 10346e3b2bfdSEmilio G. Cota next = (void *)ROUND_UP((uintptr_t)(tb + 1), align); 10356e3b2bfdSEmilio G. Cota 10366e3b2bfdSEmilio G. Cota if (unlikely(next > s->code_gen_highwater)) { 1037e8feb96fSEmilio G. Cota if (tcg_region_alloc(s)) { 10386e3b2bfdSEmilio G. Cota return NULL; 10396e3b2bfdSEmilio G. Cota } 1040e8feb96fSEmilio G. Cota goto retry; 1041e8feb96fSEmilio G. Cota } 1042d73415a3SStefan Hajnoczi qatomic_set(&s->code_gen_ptr, next); 104357a26946SRichard Henderson s->data_gen_ptr = NULL; 10446e3b2bfdSEmilio G. Cota return tb; 10456e3b2bfdSEmilio G. Cota } 10466e3b2bfdSEmilio G. Cota 10479002ec79SRichard Henderson void tcg_prologue_init(TCGContext *s) 10489002ec79SRichard Henderson { 10498163b749SRichard Henderson size_t prologue_size, total_size; 10508163b749SRichard Henderson void *buf0, *buf1; 10518163b749SRichard Henderson 10528163b749SRichard Henderson /* Put the prologue at the beginning of code_gen_buffer. */ 10538163b749SRichard Henderson buf0 = s->code_gen_buffer; 10545b38ee31SRichard Henderson total_size = s->code_gen_buffer_size; 10558163b749SRichard Henderson s->code_ptr = buf0; 10568163b749SRichard Henderson s->code_buf = buf0; 10575b38ee31SRichard Henderson s->data_gen_ptr = NULL; 10588163b749SRichard Henderson s->code_gen_prologue = buf0; 10598163b749SRichard Henderson 10605b38ee31SRichard Henderson /* Compute a high-water mark, at which we voluntarily flush the buffer 10615b38ee31SRichard Henderson and start over. The size here is arbitrary, significantly larger 10625b38ee31SRichard Henderson than we expect the code generation for any one opcode to require. */ 10635b38ee31SRichard Henderson s->code_gen_highwater = s->code_gen_buffer + (total_size - TCG_HIGHWATER); 10645b38ee31SRichard Henderson 10655b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 10665b38ee31SRichard Henderson s->pool_labels = NULL; 10675b38ee31SRichard Henderson #endif 10685b38ee31SRichard Henderson 10698163b749SRichard Henderson /* Generate the prologue. */ 1070b03cce8eSbellard tcg_target_qemu_prologue(s); 10715b38ee31SRichard Henderson 10725b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 10735b38ee31SRichard Henderson /* Allow the prologue to put e.g. guest_base into a pool entry. */ 10745b38ee31SRichard Henderson { 10751768987bSRichard Henderson int result = tcg_out_pool_finalize(s); 10761768987bSRichard Henderson tcg_debug_assert(result == 0); 10775b38ee31SRichard Henderson } 10785b38ee31SRichard Henderson #endif 10795b38ee31SRichard Henderson 10808163b749SRichard Henderson buf1 = s->code_ptr; 1081*df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 10828163b749SRichard Henderson flush_icache_range((uintptr_t)buf0, (uintptr_t)buf1); 1083*df5d2b16SRichard Henderson #endif 10848163b749SRichard Henderson 10858163b749SRichard Henderson /* Deduct the prologue from the buffer. */ 10868163b749SRichard Henderson prologue_size = tcg_current_code_size(s); 10878163b749SRichard Henderson s->code_gen_ptr = buf1; 10888163b749SRichard Henderson s->code_gen_buffer = buf1; 10898163b749SRichard Henderson s->code_buf = buf1; 10905b38ee31SRichard Henderson total_size -= prologue_size; 10918163b749SRichard Henderson s->code_gen_buffer_size = total_size; 10928163b749SRichard Henderson 10938163b749SRichard Henderson tcg_register_jit(s->code_gen_buffer, total_size); 1094d6b64b2bSRichard Henderson 1095d6b64b2bSRichard Henderson #ifdef DEBUG_DISAS 1096d6b64b2bSRichard Henderson if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) { 1097fc59d2d8SRobert Foley FILE *logfile = qemu_log_lock(); 10988163b749SRichard Henderson qemu_log("PROLOGUE: [size=%zu]\n", prologue_size); 10995b38ee31SRichard Henderson if (s->data_gen_ptr) { 11005b38ee31SRichard Henderson size_t code_size = s->data_gen_ptr - buf0; 11015b38ee31SRichard Henderson size_t data_size = prologue_size - code_size; 11025b38ee31SRichard Henderson size_t i; 11035b38ee31SRichard Henderson 11044c389f6eSRichard Henderson log_disas(buf0, code_size); 11055b38ee31SRichard Henderson 11065b38ee31SRichard Henderson for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) { 11075b38ee31SRichard Henderson if (sizeof(tcg_target_ulong) == 8) { 11085b38ee31SRichard Henderson qemu_log("0x%08" PRIxPTR ": .quad 0x%016" PRIx64 "\n", 11095b38ee31SRichard Henderson (uintptr_t)s->data_gen_ptr + i, 11105b38ee31SRichard Henderson *(uint64_t *)(s->data_gen_ptr + i)); 11115b38ee31SRichard Henderson } else { 11125b38ee31SRichard Henderson qemu_log("0x%08" PRIxPTR ": .long 0x%08x\n", 11135b38ee31SRichard Henderson (uintptr_t)s->data_gen_ptr + i, 11145b38ee31SRichard Henderson *(uint32_t *)(s->data_gen_ptr + i)); 11155b38ee31SRichard Henderson } 11165b38ee31SRichard Henderson } 11175b38ee31SRichard Henderson } else { 11184c389f6eSRichard Henderson log_disas(buf0, prologue_size); 11195b38ee31SRichard Henderson } 1120d6b64b2bSRichard Henderson qemu_log("\n"); 1121d6b64b2bSRichard Henderson qemu_log_flush(); 1122fc59d2d8SRobert Foley qemu_log_unlock(logfile); 1123d6b64b2bSRichard Henderson } 1124d6b64b2bSRichard Henderson #endif 1125cedbcb01SEmilio G. Cota 1126cedbcb01SEmilio G. Cota /* Assert that goto_ptr is implemented completely. */ 1127cedbcb01SEmilio G. Cota if (TCG_TARGET_HAS_goto_ptr) { 1128cedbcb01SEmilio G. Cota tcg_debug_assert(s->code_gen_epilogue != NULL); 1129cedbcb01SEmilio G. Cota } 1130c896fe29Sbellard } 1131c896fe29Sbellard 1132c896fe29Sbellard void tcg_func_start(TCGContext *s) 1133c896fe29Sbellard { 1134c896fe29Sbellard tcg_pool_reset(s); 1135c896fe29Sbellard s->nb_temps = s->nb_globals; 11360ec9eabcSRichard Henderson 11370ec9eabcSRichard Henderson /* No temps have been previously allocated for size or locality. */ 11380ec9eabcSRichard Henderson memset(s->free_temps, 0, sizeof(s->free_temps)); 11390ec9eabcSRichard Henderson 1140abebf925SRichard Henderson s->nb_ops = 0; 1141c896fe29Sbellard s->nb_labels = 0; 1142c896fe29Sbellard s->current_frame_offset = s->frame_start; 1143c896fe29Sbellard 11440a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG 11450a209d4bSRichard Henderson s->goto_tb_issue_mask = 0; 11460a209d4bSRichard Henderson #endif 11470a209d4bSRichard Henderson 114815fa08f8SRichard Henderson QTAILQ_INIT(&s->ops); 114915fa08f8SRichard Henderson QTAILQ_INIT(&s->free_ops); 1150bef16ab4SRichard Henderson QSIMPLEQ_INIT(&s->labels); 1151c896fe29Sbellard } 1152c896fe29Sbellard 11537ca4b752SRichard Henderson static inline TCGTemp *tcg_temp_alloc(TCGContext *s) 11547ca4b752SRichard Henderson { 11557ca4b752SRichard Henderson int n = s->nb_temps++; 11567ca4b752SRichard Henderson tcg_debug_assert(n < TCG_MAX_TEMPS); 11577ca4b752SRichard Henderson return memset(&s->temps[n], 0, sizeof(TCGTemp)); 11587ca4b752SRichard Henderson } 11597ca4b752SRichard Henderson 11607ca4b752SRichard Henderson static inline TCGTemp *tcg_global_alloc(TCGContext *s) 11617ca4b752SRichard Henderson { 1162fa477d25SRichard Henderson TCGTemp *ts; 1163fa477d25SRichard Henderson 11647ca4b752SRichard Henderson tcg_debug_assert(s->nb_globals == s->nb_temps); 11657ca4b752SRichard Henderson s->nb_globals++; 1166fa477d25SRichard Henderson ts = tcg_temp_alloc(s); 1167fa477d25SRichard Henderson ts->temp_global = 1; 1168fa477d25SRichard Henderson 1169fa477d25SRichard Henderson return ts; 1170c896fe29Sbellard } 1171c896fe29Sbellard 1172085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type, 1173b6638662SRichard Henderson TCGReg reg, const char *name) 1174c896fe29Sbellard { 1175c896fe29Sbellard TCGTemp *ts; 1176c896fe29Sbellard 1177b3a62939SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type != TCG_TYPE_I32) { 1178c896fe29Sbellard tcg_abort(); 1179b3a62939SRichard Henderson } 11807ca4b752SRichard Henderson 11817ca4b752SRichard Henderson ts = tcg_global_alloc(s); 1182c896fe29Sbellard ts->base_type = type; 1183c896fe29Sbellard ts->type = type; 1184c896fe29Sbellard ts->fixed_reg = 1; 1185c896fe29Sbellard ts->reg = reg; 1186c896fe29Sbellard ts->name = name; 1187c896fe29Sbellard tcg_regset_set_reg(s->reserved_regs, reg); 11887ca4b752SRichard Henderson 1189085272b3SRichard Henderson return ts; 1190a7812ae4Spbrook } 1191a7812ae4Spbrook 1192b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size) 1193a7812ae4Spbrook { 1194b3a62939SRichard Henderson s->frame_start = start; 1195b3a62939SRichard Henderson s->frame_end = start + size; 1196085272b3SRichard Henderson s->frame_temp 1197085272b3SRichard Henderson = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame"); 1198b3a62939SRichard Henderson } 1199a7812ae4Spbrook 1200085272b3SRichard Henderson TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base, 1201e1ccc054SRichard Henderson intptr_t offset, const char *name) 1202c896fe29Sbellard { 1203b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1204dc41aa7dSRichard Henderson TCGTemp *base_ts = tcgv_ptr_temp(base); 12057ca4b752SRichard Henderson TCGTemp *ts = tcg_global_alloc(s); 1206b3915dbbSRichard Henderson int indirect_reg = 0, bigendian = 0; 12077ca4b752SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 12087ca4b752SRichard Henderson bigendian = 1; 12097ca4b752SRichard Henderson #endif 1210c896fe29Sbellard 1211b3915dbbSRichard Henderson if (!base_ts->fixed_reg) { 12125a18407fSRichard Henderson /* We do not support double-indirect registers. */ 12135a18407fSRichard Henderson tcg_debug_assert(!base_ts->indirect_reg); 1214b3915dbbSRichard Henderson base_ts->indirect_base = 1; 12155a18407fSRichard Henderson s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64 12165a18407fSRichard Henderson ? 2 : 1); 12175a18407fSRichard Henderson indirect_reg = 1; 1218b3915dbbSRichard Henderson } 1219b3915dbbSRichard Henderson 12207ca4b752SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { 12217ca4b752SRichard Henderson TCGTemp *ts2 = tcg_global_alloc(s); 1222c896fe29Sbellard char buf[64]; 12237ca4b752SRichard Henderson 12247ca4b752SRichard Henderson ts->base_type = TCG_TYPE_I64; 1225c896fe29Sbellard ts->type = TCG_TYPE_I32; 1226b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg; 1227c896fe29Sbellard ts->mem_allocated = 1; 1228b3a62939SRichard Henderson ts->mem_base = base_ts; 12297ca4b752SRichard Henderson ts->mem_offset = offset + bigendian * 4; 1230c896fe29Sbellard pstrcpy(buf, sizeof(buf), name); 1231c896fe29Sbellard pstrcat(buf, sizeof(buf), "_0"); 1232c896fe29Sbellard ts->name = strdup(buf); 1233c896fe29Sbellard 12347ca4b752SRichard Henderson tcg_debug_assert(ts2 == ts + 1); 12357ca4b752SRichard Henderson ts2->base_type = TCG_TYPE_I64; 12367ca4b752SRichard Henderson ts2->type = TCG_TYPE_I32; 1237b3915dbbSRichard Henderson ts2->indirect_reg = indirect_reg; 12387ca4b752SRichard Henderson ts2->mem_allocated = 1; 12397ca4b752SRichard Henderson ts2->mem_base = base_ts; 12407ca4b752SRichard Henderson ts2->mem_offset = offset + (1 - bigendian) * 4; 1241c896fe29Sbellard pstrcpy(buf, sizeof(buf), name); 1242c896fe29Sbellard pstrcat(buf, sizeof(buf), "_1"); 1243120c1084SRichard Henderson ts2->name = strdup(buf); 12447ca4b752SRichard Henderson } else { 1245c896fe29Sbellard ts->base_type = type; 1246c896fe29Sbellard ts->type = type; 1247b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg; 1248c896fe29Sbellard ts->mem_allocated = 1; 1249b3a62939SRichard Henderson ts->mem_base = base_ts; 1250c896fe29Sbellard ts->mem_offset = offset; 1251c896fe29Sbellard ts->name = name; 1252c896fe29Sbellard } 1253085272b3SRichard Henderson return ts; 1254c896fe29Sbellard } 1255c896fe29Sbellard 12565bfa8034SRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, bool temp_local) 1257c896fe29Sbellard { 1258b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1259c896fe29Sbellard TCGTemp *ts; 1260641d5fbeSbellard int idx, k; 1261c896fe29Sbellard 12620ec9eabcSRichard Henderson k = type + (temp_local ? TCG_TYPE_COUNT : 0); 12630ec9eabcSRichard Henderson idx = find_first_bit(s->free_temps[k].l, TCG_MAX_TEMPS); 12640ec9eabcSRichard Henderson if (idx < TCG_MAX_TEMPS) { 12650ec9eabcSRichard Henderson /* There is already an available temp with the right type. */ 12660ec9eabcSRichard Henderson clear_bit(idx, s->free_temps[k].l); 12670ec9eabcSRichard Henderson 1268e8996ee0Sbellard ts = &s->temps[idx]; 1269e8996ee0Sbellard ts->temp_allocated = 1; 12707ca4b752SRichard Henderson tcg_debug_assert(ts->base_type == type); 12717ca4b752SRichard Henderson tcg_debug_assert(ts->temp_local == temp_local); 1272e8996ee0Sbellard } else { 12737ca4b752SRichard Henderson ts = tcg_temp_alloc(s); 12747ca4b752SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { 12757ca4b752SRichard Henderson TCGTemp *ts2 = tcg_temp_alloc(s); 12767ca4b752SRichard Henderson 1277c896fe29Sbellard ts->base_type = type; 1278c896fe29Sbellard ts->type = TCG_TYPE_I32; 1279e8996ee0Sbellard ts->temp_allocated = 1; 1280641d5fbeSbellard ts->temp_local = temp_local; 12817ca4b752SRichard Henderson 12827ca4b752SRichard Henderson tcg_debug_assert(ts2 == ts + 1); 12837ca4b752SRichard Henderson ts2->base_type = TCG_TYPE_I64; 12847ca4b752SRichard Henderson ts2->type = TCG_TYPE_I32; 12857ca4b752SRichard Henderson ts2->temp_allocated = 1; 12867ca4b752SRichard Henderson ts2->temp_local = temp_local; 12877ca4b752SRichard Henderson } else { 1288c896fe29Sbellard ts->base_type = type; 1289c896fe29Sbellard ts->type = type; 1290e8996ee0Sbellard ts->temp_allocated = 1; 1291641d5fbeSbellard ts->temp_local = temp_local; 1292c896fe29Sbellard } 1293e8996ee0Sbellard } 129427bfd83cSPeter Maydell 129527bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG) 129627bfd83cSPeter Maydell s->temps_in_use++; 129727bfd83cSPeter Maydell #endif 1298085272b3SRichard Henderson return ts; 1299c896fe29Sbellard } 1300c896fe29Sbellard 1301d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type) 1302d2fd745fSRichard Henderson { 1303d2fd745fSRichard Henderson TCGTemp *t; 1304d2fd745fSRichard Henderson 1305d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG 1306d2fd745fSRichard Henderson switch (type) { 1307d2fd745fSRichard Henderson case TCG_TYPE_V64: 1308d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v64); 1309d2fd745fSRichard Henderson break; 1310d2fd745fSRichard Henderson case TCG_TYPE_V128: 1311d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v128); 1312d2fd745fSRichard Henderson break; 1313d2fd745fSRichard Henderson case TCG_TYPE_V256: 1314d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v256); 1315d2fd745fSRichard Henderson break; 1316d2fd745fSRichard Henderson default: 1317d2fd745fSRichard Henderson g_assert_not_reached(); 1318d2fd745fSRichard Henderson } 1319d2fd745fSRichard Henderson #endif 1320d2fd745fSRichard Henderson 1321d2fd745fSRichard Henderson t = tcg_temp_new_internal(type, 0); 1322d2fd745fSRichard Henderson return temp_tcgv_vec(t); 1323d2fd745fSRichard Henderson } 1324d2fd745fSRichard Henderson 1325d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp. */ 1326d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match) 1327d2fd745fSRichard Henderson { 1328d2fd745fSRichard Henderson TCGTemp *t = tcgv_vec_temp(match); 1329d2fd745fSRichard Henderson 1330d2fd745fSRichard Henderson tcg_debug_assert(t->temp_allocated != 0); 1331d2fd745fSRichard Henderson 1332d2fd745fSRichard Henderson t = tcg_temp_new_internal(t->base_type, 0); 1333d2fd745fSRichard Henderson return temp_tcgv_vec(t); 1334d2fd745fSRichard Henderson } 1335d2fd745fSRichard Henderson 13365bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts) 1337c896fe29Sbellard { 1338b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1339085272b3SRichard Henderson int k, idx; 1340c896fe29Sbellard 134127bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG) 134227bfd83cSPeter Maydell s->temps_in_use--; 134327bfd83cSPeter Maydell if (s->temps_in_use < 0) { 134427bfd83cSPeter Maydell fprintf(stderr, "More temporaries freed than allocated!\n"); 134527bfd83cSPeter Maydell } 134627bfd83cSPeter Maydell #endif 134727bfd83cSPeter Maydell 1348085272b3SRichard Henderson tcg_debug_assert(ts->temp_global == 0); 1349eabb7b91SAurelien Jarno tcg_debug_assert(ts->temp_allocated != 0); 1350e8996ee0Sbellard ts->temp_allocated = 0; 13510ec9eabcSRichard Henderson 1352085272b3SRichard Henderson idx = temp_idx(ts); 135318d13fa2SAlexander Graf k = ts->base_type + (ts->temp_local ? TCG_TYPE_COUNT : 0); 13540ec9eabcSRichard Henderson set_bit(idx, s->free_temps[k].l); 1355e8996ee0Sbellard } 1356e8996ee0Sbellard 1357a7812ae4Spbrook TCGv_i32 tcg_const_i32(int32_t val) 1358a7812ae4Spbrook { 1359a7812ae4Spbrook TCGv_i32 t0; 1360a7812ae4Spbrook t0 = tcg_temp_new_i32(); 1361e8996ee0Sbellard tcg_gen_movi_i32(t0, val); 1362e8996ee0Sbellard return t0; 1363c896fe29Sbellard } 1364c896fe29Sbellard 1365a7812ae4Spbrook TCGv_i64 tcg_const_i64(int64_t val) 1366c896fe29Sbellard { 1367a7812ae4Spbrook TCGv_i64 t0; 1368a7812ae4Spbrook t0 = tcg_temp_new_i64(); 1369e8996ee0Sbellard tcg_gen_movi_i64(t0, val); 1370e8996ee0Sbellard return t0; 1371c896fe29Sbellard } 1372c896fe29Sbellard 1373a7812ae4Spbrook TCGv_i32 tcg_const_local_i32(int32_t val) 1374bdffd4a9Saurel32 { 1375a7812ae4Spbrook TCGv_i32 t0; 1376a7812ae4Spbrook t0 = tcg_temp_local_new_i32(); 1377bdffd4a9Saurel32 tcg_gen_movi_i32(t0, val); 1378bdffd4a9Saurel32 return t0; 1379bdffd4a9Saurel32 } 1380bdffd4a9Saurel32 1381a7812ae4Spbrook TCGv_i64 tcg_const_local_i64(int64_t val) 1382bdffd4a9Saurel32 { 1383a7812ae4Spbrook TCGv_i64 t0; 1384a7812ae4Spbrook t0 = tcg_temp_local_new_i64(); 1385bdffd4a9Saurel32 tcg_gen_movi_i64(t0, val); 1386bdffd4a9Saurel32 return t0; 1387bdffd4a9Saurel32 } 1388bdffd4a9Saurel32 138927bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG) 139027bfd83cSPeter Maydell void tcg_clear_temp_count(void) 139127bfd83cSPeter Maydell { 1392b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 139327bfd83cSPeter Maydell s->temps_in_use = 0; 139427bfd83cSPeter Maydell } 139527bfd83cSPeter Maydell 139627bfd83cSPeter Maydell int tcg_check_temp_count(void) 139727bfd83cSPeter Maydell { 1398b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 139927bfd83cSPeter Maydell if (s->temps_in_use) { 140027bfd83cSPeter Maydell /* Clear the count so that we don't give another 140127bfd83cSPeter Maydell * warning immediately next time around. 140227bfd83cSPeter Maydell */ 140327bfd83cSPeter Maydell s->temps_in_use = 0; 140427bfd83cSPeter Maydell return 1; 140527bfd83cSPeter Maydell } 140627bfd83cSPeter Maydell return 0; 140727bfd83cSPeter Maydell } 140827bfd83cSPeter Maydell #endif 140927bfd83cSPeter Maydell 1410be0f34b5SRichard Henderson /* Return true if OP may appear in the opcode stream. 1411be0f34b5SRichard Henderson Test the runtime variable that controls each opcode. */ 1412be0f34b5SRichard Henderson bool tcg_op_supported(TCGOpcode op) 1413be0f34b5SRichard Henderson { 1414d2fd745fSRichard Henderson const bool have_vec 1415d2fd745fSRichard Henderson = TCG_TARGET_HAS_v64 | TCG_TARGET_HAS_v128 | TCG_TARGET_HAS_v256; 1416d2fd745fSRichard Henderson 1417be0f34b5SRichard Henderson switch (op) { 1418be0f34b5SRichard Henderson case INDEX_op_discard: 1419be0f34b5SRichard Henderson case INDEX_op_set_label: 1420be0f34b5SRichard Henderson case INDEX_op_call: 1421be0f34b5SRichard Henderson case INDEX_op_br: 1422be0f34b5SRichard Henderson case INDEX_op_mb: 1423be0f34b5SRichard Henderson case INDEX_op_insn_start: 1424be0f34b5SRichard Henderson case INDEX_op_exit_tb: 1425be0f34b5SRichard Henderson case INDEX_op_goto_tb: 1426be0f34b5SRichard Henderson case INDEX_op_qemu_ld_i32: 1427be0f34b5SRichard Henderson case INDEX_op_qemu_st_i32: 1428be0f34b5SRichard Henderson case INDEX_op_qemu_ld_i64: 1429be0f34b5SRichard Henderson case INDEX_op_qemu_st_i64: 1430be0f34b5SRichard Henderson return true; 1431be0f34b5SRichard Henderson 143207ce0b05SRichard Henderson case INDEX_op_qemu_st8_i32: 143307ce0b05SRichard Henderson return TCG_TARGET_HAS_qemu_st8_i32; 143407ce0b05SRichard Henderson 1435be0f34b5SRichard Henderson case INDEX_op_goto_ptr: 1436be0f34b5SRichard Henderson return TCG_TARGET_HAS_goto_ptr; 1437be0f34b5SRichard Henderson 1438be0f34b5SRichard Henderson case INDEX_op_mov_i32: 1439be0f34b5SRichard Henderson case INDEX_op_movi_i32: 1440be0f34b5SRichard Henderson case INDEX_op_setcond_i32: 1441be0f34b5SRichard Henderson case INDEX_op_brcond_i32: 1442be0f34b5SRichard Henderson case INDEX_op_ld8u_i32: 1443be0f34b5SRichard Henderson case INDEX_op_ld8s_i32: 1444be0f34b5SRichard Henderson case INDEX_op_ld16u_i32: 1445be0f34b5SRichard Henderson case INDEX_op_ld16s_i32: 1446be0f34b5SRichard Henderson case INDEX_op_ld_i32: 1447be0f34b5SRichard Henderson case INDEX_op_st8_i32: 1448be0f34b5SRichard Henderson case INDEX_op_st16_i32: 1449be0f34b5SRichard Henderson case INDEX_op_st_i32: 1450be0f34b5SRichard Henderson case INDEX_op_add_i32: 1451be0f34b5SRichard Henderson case INDEX_op_sub_i32: 1452be0f34b5SRichard Henderson case INDEX_op_mul_i32: 1453be0f34b5SRichard Henderson case INDEX_op_and_i32: 1454be0f34b5SRichard Henderson case INDEX_op_or_i32: 1455be0f34b5SRichard Henderson case INDEX_op_xor_i32: 1456be0f34b5SRichard Henderson case INDEX_op_shl_i32: 1457be0f34b5SRichard Henderson case INDEX_op_shr_i32: 1458be0f34b5SRichard Henderson case INDEX_op_sar_i32: 1459be0f34b5SRichard Henderson return true; 1460be0f34b5SRichard Henderson 1461be0f34b5SRichard Henderson case INDEX_op_movcond_i32: 1462be0f34b5SRichard Henderson return TCG_TARGET_HAS_movcond_i32; 1463be0f34b5SRichard Henderson case INDEX_op_div_i32: 1464be0f34b5SRichard Henderson case INDEX_op_divu_i32: 1465be0f34b5SRichard Henderson return TCG_TARGET_HAS_div_i32; 1466be0f34b5SRichard Henderson case INDEX_op_rem_i32: 1467be0f34b5SRichard Henderson case INDEX_op_remu_i32: 1468be0f34b5SRichard Henderson return TCG_TARGET_HAS_rem_i32; 1469be0f34b5SRichard Henderson case INDEX_op_div2_i32: 1470be0f34b5SRichard Henderson case INDEX_op_divu2_i32: 1471be0f34b5SRichard Henderson return TCG_TARGET_HAS_div2_i32; 1472be0f34b5SRichard Henderson case INDEX_op_rotl_i32: 1473be0f34b5SRichard Henderson case INDEX_op_rotr_i32: 1474be0f34b5SRichard Henderson return TCG_TARGET_HAS_rot_i32; 1475be0f34b5SRichard Henderson case INDEX_op_deposit_i32: 1476be0f34b5SRichard Henderson return TCG_TARGET_HAS_deposit_i32; 1477be0f34b5SRichard Henderson case INDEX_op_extract_i32: 1478be0f34b5SRichard Henderson return TCG_TARGET_HAS_extract_i32; 1479be0f34b5SRichard Henderson case INDEX_op_sextract_i32: 1480be0f34b5SRichard Henderson return TCG_TARGET_HAS_sextract_i32; 1481fce1296fSRichard Henderson case INDEX_op_extract2_i32: 1482fce1296fSRichard Henderson return TCG_TARGET_HAS_extract2_i32; 1483be0f34b5SRichard Henderson case INDEX_op_add2_i32: 1484be0f34b5SRichard Henderson return TCG_TARGET_HAS_add2_i32; 1485be0f34b5SRichard Henderson case INDEX_op_sub2_i32: 1486be0f34b5SRichard Henderson return TCG_TARGET_HAS_sub2_i32; 1487be0f34b5SRichard Henderson case INDEX_op_mulu2_i32: 1488be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulu2_i32; 1489be0f34b5SRichard Henderson case INDEX_op_muls2_i32: 1490be0f34b5SRichard Henderson return TCG_TARGET_HAS_muls2_i32; 1491be0f34b5SRichard Henderson case INDEX_op_muluh_i32: 1492be0f34b5SRichard Henderson return TCG_TARGET_HAS_muluh_i32; 1493be0f34b5SRichard Henderson case INDEX_op_mulsh_i32: 1494be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulsh_i32; 1495be0f34b5SRichard Henderson case INDEX_op_ext8s_i32: 1496be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8s_i32; 1497be0f34b5SRichard Henderson case INDEX_op_ext16s_i32: 1498be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16s_i32; 1499be0f34b5SRichard Henderson case INDEX_op_ext8u_i32: 1500be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8u_i32; 1501be0f34b5SRichard Henderson case INDEX_op_ext16u_i32: 1502be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16u_i32; 1503be0f34b5SRichard Henderson case INDEX_op_bswap16_i32: 1504be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap16_i32; 1505be0f34b5SRichard Henderson case INDEX_op_bswap32_i32: 1506be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap32_i32; 1507be0f34b5SRichard Henderson case INDEX_op_not_i32: 1508be0f34b5SRichard Henderson return TCG_TARGET_HAS_not_i32; 1509be0f34b5SRichard Henderson case INDEX_op_neg_i32: 1510be0f34b5SRichard Henderson return TCG_TARGET_HAS_neg_i32; 1511be0f34b5SRichard Henderson case INDEX_op_andc_i32: 1512be0f34b5SRichard Henderson return TCG_TARGET_HAS_andc_i32; 1513be0f34b5SRichard Henderson case INDEX_op_orc_i32: 1514be0f34b5SRichard Henderson return TCG_TARGET_HAS_orc_i32; 1515be0f34b5SRichard Henderson case INDEX_op_eqv_i32: 1516be0f34b5SRichard Henderson return TCG_TARGET_HAS_eqv_i32; 1517be0f34b5SRichard Henderson case INDEX_op_nand_i32: 1518be0f34b5SRichard Henderson return TCG_TARGET_HAS_nand_i32; 1519be0f34b5SRichard Henderson case INDEX_op_nor_i32: 1520be0f34b5SRichard Henderson return TCG_TARGET_HAS_nor_i32; 1521be0f34b5SRichard Henderson case INDEX_op_clz_i32: 1522be0f34b5SRichard Henderson return TCG_TARGET_HAS_clz_i32; 1523be0f34b5SRichard Henderson case INDEX_op_ctz_i32: 1524be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctz_i32; 1525be0f34b5SRichard Henderson case INDEX_op_ctpop_i32: 1526be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctpop_i32; 1527be0f34b5SRichard Henderson 1528be0f34b5SRichard Henderson case INDEX_op_brcond2_i32: 1529be0f34b5SRichard Henderson case INDEX_op_setcond2_i32: 1530be0f34b5SRichard Henderson return TCG_TARGET_REG_BITS == 32; 1531be0f34b5SRichard Henderson 1532be0f34b5SRichard Henderson case INDEX_op_mov_i64: 1533be0f34b5SRichard Henderson case INDEX_op_movi_i64: 1534be0f34b5SRichard Henderson case INDEX_op_setcond_i64: 1535be0f34b5SRichard Henderson case INDEX_op_brcond_i64: 1536be0f34b5SRichard Henderson case INDEX_op_ld8u_i64: 1537be0f34b5SRichard Henderson case INDEX_op_ld8s_i64: 1538be0f34b5SRichard Henderson case INDEX_op_ld16u_i64: 1539be0f34b5SRichard Henderson case INDEX_op_ld16s_i64: 1540be0f34b5SRichard Henderson case INDEX_op_ld32u_i64: 1541be0f34b5SRichard Henderson case INDEX_op_ld32s_i64: 1542be0f34b5SRichard Henderson case INDEX_op_ld_i64: 1543be0f34b5SRichard Henderson case INDEX_op_st8_i64: 1544be0f34b5SRichard Henderson case INDEX_op_st16_i64: 1545be0f34b5SRichard Henderson case INDEX_op_st32_i64: 1546be0f34b5SRichard Henderson case INDEX_op_st_i64: 1547be0f34b5SRichard Henderson case INDEX_op_add_i64: 1548be0f34b5SRichard Henderson case INDEX_op_sub_i64: 1549be0f34b5SRichard Henderson case INDEX_op_mul_i64: 1550be0f34b5SRichard Henderson case INDEX_op_and_i64: 1551be0f34b5SRichard Henderson case INDEX_op_or_i64: 1552be0f34b5SRichard Henderson case INDEX_op_xor_i64: 1553be0f34b5SRichard Henderson case INDEX_op_shl_i64: 1554be0f34b5SRichard Henderson case INDEX_op_shr_i64: 1555be0f34b5SRichard Henderson case INDEX_op_sar_i64: 1556be0f34b5SRichard Henderson case INDEX_op_ext_i32_i64: 1557be0f34b5SRichard Henderson case INDEX_op_extu_i32_i64: 1558be0f34b5SRichard Henderson return TCG_TARGET_REG_BITS == 64; 1559be0f34b5SRichard Henderson 1560be0f34b5SRichard Henderson case INDEX_op_movcond_i64: 1561be0f34b5SRichard Henderson return TCG_TARGET_HAS_movcond_i64; 1562be0f34b5SRichard Henderson case INDEX_op_div_i64: 1563be0f34b5SRichard Henderson case INDEX_op_divu_i64: 1564be0f34b5SRichard Henderson return TCG_TARGET_HAS_div_i64; 1565be0f34b5SRichard Henderson case INDEX_op_rem_i64: 1566be0f34b5SRichard Henderson case INDEX_op_remu_i64: 1567be0f34b5SRichard Henderson return TCG_TARGET_HAS_rem_i64; 1568be0f34b5SRichard Henderson case INDEX_op_div2_i64: 1569be0f34b5SRichard Henderson case INDEX_op_divu2_i64: 1570be0f34b5SRichard Henderson return TCG_TARGET_HAS_div2_i64; 1571be0f34b5SRichard Henderson case INDEX_op_rotl_i64: 1572be0f34b5SRichard Henderson case INDEX_op_rotr_i64: 1573be0f34b5SRichard Henderson return TCG_TARGET_HAS_rot_i64; 1574be0f34b5SRichard Henderson case INDEX_op_deposit_i64: 1575be0f34b5SRichard Henderson return TCG_TARGET_HAS_deposit_i64; 1576be0f34b5SRichard Henderson case INDEX_op_extract_i64: 1577be0f34b5SRichard Henderson return TCG_TARGET_HAS_extract_i64; 1578be0f34b5SRichard Henderson case INDEX_op_sextract_i64: 1579be0f34b5SRichard Henderson return TCG_TARGET_HAS_sextract_i64; 1580fce1296fSRichard Henderson case INDEX_op_extract2_i64: 1581fce1296fSRichard Henderson return TCG_TARGET_HAS_extract2_i64; 1582be0f34b5SRichard Henderson case INDEX_op_extrl_i64_i32: 1583be0f34b5SRichard Henderson return TCG_TARGET_HAS_extrl_i64_i32; 1584be0f34b5SRichard Henderson case INDEX_op_extrh_i64_i32: 1585be0f34b5SRichard Henderson return TCG_TARGET_HAS_extrh_i64_i32; 1586be0f34b5SRichard Henderson case INDEX_op_ext8s_i64: 1587be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8s_i64; 1588be0f34b5SRichard Henderson case INDEX_op_ext16s_i64: 1589be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16s_i64; 1590be0f34b5SRichard Henderson case INDEX_op_ext32s_i64: 1591be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext32s_i64; 1592be0f34b5SRichard Henderson case INDEX_op_ext8u_i64: 1593be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8u_i64; 1594be0f34b5SRichard Henderson case INDEX_op_ext16u_i64: 1595be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16u_i64; 1596be0f34b5SRichard Henderson case INDEX_op_ext32u_i64: 1597be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext32u_i64; 1598be0f34b5SRichard Henderson case INDEX_op_bswap16_i64: 1599be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap16_i64; 1600be0f34b5SRichard Henderson case INDEX_op_bswap32_i64: 1601be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap32_i64; 1602be0f34b5SRichard Henderson case INDEX_op_bswap64_i64: 1603be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap64_i64; 1604be0f34b5SRichard Henderson case INDEX_op_not_i64: 1605be0f34b5SRichard Henderson return TCG_TARGET_HAS_not_i64; 1606be0f34b5SRichard Henderson case INDEX_op_neg_i64: 1607be0f34b5SRichard Henderson return TCG_TARGET_HAS_neg_i64; 1608be0f34b5SRichard Henderson case INDEX_op_andc_i64: 1609be0f34b5SRichard Henderson return TCG_TARGET_HAS_andc_i64; 1610be0f34b5SRichard Henderson case INDEX_op_orc_i64: 1611be0f34b5SRichard Henderson return TCG_TARGET_HAS_orc_i64; 1612be0f34b5SRichard Henderson case INDEX_op_eqv_i64: 1613be0f34b5SRichard Henderson return TCG_TARGET_HAS_eqv_i64; 1614be0f34b5SRichard Henderson case INDEX_op_nand_i64: 1615be0f34b5SRichard Henderson return TCG_TARGET_HAS_nand_i64; 1616be0f34b5SRichard Henderson case INDEX_op_nor_i64: 1617be0f34b5SRichard Henderson return TCG_TARGET_HAS_nor_i64; 1618be0f34b5SRichard Henderson case INDEX_op_clz_i64: 1619be0f34b5SRichard Henderson return TCG_TARGET_HAS_clz_i64; 1620be0f34b5SRichard Henderson case INDEX_op_ctz_i64: 1621be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctz_i64; 1622be0f34b5SRichard Henderson case INDEX_op_ctpop_i64: 1623be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctpop_i64; 1624be0f34b5SRichard Henderson case INDEX_op_add2_i64: 1625be0f34b5SRichard Henderson return TCG_TARGET_HAS_add2_i64; 1626be0f34b5SRichard Henderson case INDEX_op_sub2_i64: 1627be0f34b5SRichard Henderson return TCG_TARGET_HAS_sub2_i64; 1628be0f34b5SRichard Henderson case INDEX_op_mulu2_i64: 1629be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulu2_i64; 1630be0f34b5SRichard Henderson case INDEX_op_muls2_i64: 1631be0f34b5SRichard Henderson return TCG_TARGET_HAS_muls2_i64; 1632be0f34b5SRichard Henderson case INDEX_op_muluh_i64: 1633be0f34b5SRichard Henderson return TCG_TARGET_HAS_muluh_i64; 1634be0f34b5SRichard Henderson case INDEX_op_mulsh_i64: 1635be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulsh_i64; 1636be0f34b5SRichard Henderson 1637d2fd745fSRichard Henderson case INDEX_op_mov_vec: 1638d2fd745fSRichard Henderson case INDEX_op_dup_vec: 1639d2fd745fSRichard Henderson case INDEX_op_dupi_vec: 164037ee55a0SRichard Henderson case INDEX_op_dupm_vec: 1641d2fd745fSRichard Henderson case INDEX_op_ld_vec: 1642d2fd745fSRichard Henderson case INDEX_op_st_vec: 1643d2fd745fSRichard Henderson case INDEX_op_add_vec: 1644d2fd745fSRichard Henderson case INDEX_op_sub_vec: 1645d2fd745fSRichard Henderson case INDEX_op_and_vec: 1646d2fd745fSRichard Henderson case INDEX_op_or_vec: 1647d2fd745fSRichard Henderson case INDEX_op_xor_vec: 1648212be173SRichard Henderson case INDEX_op_cmp_vec: 1649d2fd745fSRichard Henderson return have_vec; 1650d2fd745fSRichard Henderson case INDEX_op_dup2_vec: 1651d2fd745fSRichard Henderson return have_vec && TCG_TARGET_REG_BITS == 32; 1652d2fd745fSRichard Henderson case INDEX_op_not_vec: 1653d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_not_vec; 1654d2fd745fSRichard Henderson case INDEX_op_neg_vec: 1655d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_neg_vec; 1656bcefc902SRichard Henderson case INDEX_op_abs_vec: 1657bcefc902SRichard Henderson return have_vec && TCG_TARGET_HAS_abs_vec; 1658d2fd745fSRichard Henderson case INDEX_op_andc_vec: 1659d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_andc_vec; 1660d2fd745fSRichard Henderson case INDEX_op_orc_vec: 1661d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_orc_vec; 16623774030aSRichard Henderson case INDEX_op_mul_vec: 16633774030aSRichard Henderson return have_vec && TCG_TARGET_HAS_mul_vec; 1664d0ec9796SRichard Henderson case INDEX_op_shli_vec: 1665d0ec9796SRichard Henderson case INDEX_op_shri_vec: 1666d0ec9796SRichard Henderson case INDEX_op_sari_vec: 1667d0ec9796SRichard Henderson return have_vec && TCG_TARGET_HAS_shi_vec; 1668d0ec9796SRichard Henderson case INDEX_op_shls_vec: 1669d0ec9796SRichard Henderson case INDEX_op_shrs_vec: 1670d0ec9796SRichard Henderson case INDEX_op_sars_vec: 1671d0ec9796SRichard Henderson return have_vec && TCG_TARGET_HAS_shs_vec; 1672d0ec9796SRichard Henderson case INDEX_op_shlv_vec: 1673d0ec9796SRichard Henderson case INDEX_op_shrv_vec: 1674d0ec9796SRichard Henderson case INDEX_op_sarv_vec: 1675d0ec9796SRichard Henderson return have_vec && TCG_TARGET_HAS_shv_vec; 1676b0f7e744SRichard Henderson case INDEX_op_rotli_vec: 1677b0f7e744SRichard Henderson return have_vec && TCG_TARGET_HAS_roti_vec; 167823850a74SRichard Henderson case INDEX_op_rotls_vec: 167923850a74SRichard Henderson return have_vec && TCG_TARGET_HAS_rots_vec; 16805d0ceda9SRichard Henderson case INDEX_op_rotlv_vec: 16815d0ceda9SRichard Henderson case INDEX_op_rotrv_vec: 16825d0ceda9SRichard Henderson return have_vec && TCG_TARGET_HAS_rotv_vec; 16838afaf050SRichard Henderson case INDEX_op_ssadd_vec: 16848afaf050SRichard Henderson case INDEX_op_usadd_vec: 16858afaf050SRichard Henderson case INDEX_op_sssub_vec: 16868afaf050SRichard Henderson case INDEX_op_ussub_vec: 16878afaf050SRichard Henderson return have_vec && TCG_TARGET_HAS_sat_vec; 1688dd0a0fcdSRichard Henderson case INDEX_op_smin_vec: 1689dd0a0fcdSRichard Henderson case INDEX_op_umin_vec: 1690dd0a0fcdSRichard Henderson case INDEX_op_smax_vec: 1691dd0a0fcdSRichard Henderson case INDEX_op_umax_vec: 1692dd0a0fcdSRichard Henderson return have_vec && TCG_TARGET_HAS_minmax_vec; 169338dc1294SRichard Henderson case INDEX_op_bitsel_vec: 169438dc1294SRichard Henderson return have_vec && TCG_TARGET_HAS_bitsel_vec; 1695f75da298SRichard Henderson case INDEX_op_cmpsel_vec: 1696f75da298SRichard Henderson return have_vec && TCG_TARGET_HAS_cmpsel_vec; 1697d2fd745fSRichard Henderson 1698db432672SRichard Henderson default: 1699db432672SRichard Henderson tcg_debug_assert(op > INDEX_op_last_generic && op < NB_OPS); 1700db432672SRichard Henderson return true; 1701be0f34b5SRichard Henderson } 1702be0f34b5SRichard Henderson } 1703be0f34b5SRichard Henderson 170439cf05d3Sbellard /* Note: we convert the 64 bit args to 32 bit and do some alignment 170539cf05d3Sbellard and endian swap. Maybe it would be better to do the alignment 170639cf05d3Sbellard and endian swap in tcg_reg_alloc_call(). */ 1707ae8b75dcSRichard Henderson void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args) 1708c896fe29Sbellard { 170975e8b9b7SRichard Henderson int i, real_args, nb_rets, pi; 1710bbb8a1b4SRichard Henderson unsigned sizemask, flags; 1711afb49896SRichard Henderson TCGHelperInfo *info; 171275e8b9b7SRichard Henderson TCGOp *op; 1713afb49896SRichard Henderson 1714619205fdSEmilio G. Cota info = g_hash_table_lookup(helper_table, (gpointer)func); 1715bbb8a1b4SRichard Henderson flags = info->flags; 1716bbb8a1b4SRichard Henderson sizemask = info->sizemask; 17172bece2c8SRichard Henderson 171838b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN 171938b47b19SEmilio G. Cota /* detect non-plugin helpers */ 172038b47b19SEmilio G. Cota if (tcg_ctx->plugin_insn && unlikely(strncmp(info->name, "plugin_", 7))) { 172138b47b19SEmilio G. Cota tcg_ctx->plugin_insn->calls_helpers = true; 172238b47b19SEmilio G. Cota } 172338b47b19SEmilio G. Cota #endif 172438b47b19SEmilio G. Cota 172534b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \ 172634b1a49cSRichard Henderson && !defined(CONFIG_TCG_INTERPRETER) 172734b1a49cSRichard Henderson /* We have 64-bit values in one register, but need to pass as two 172834b1a49cSRichard Henderson separate parameters. Split them. */ 172934b1a49cSRichard Henderson int orig_sizemask = sizemask; 173034b1a49cSRichard Henderson int orig_nargs = nargs; 173134b1a49cSRichard Henderson TCGv_i64 retl, reth; 1732ae8b75dcSRichard Henderson TCGTemp *split_args[MAX_OPC_PARAM]; 173334b1a49cSRichard Henderson 1734f764718dSRichard Henderson retl = NULL; 1735f764718dSRichard Henderson reth = NULL; 173634b1a49cSRichard Henderson if (sizemask != 0) { 173734b1a49cSRichard Henderson for (i = real_args = 0; i < nargs; ++i) { 173834b1a49cSRichard Henderson int is_64bit = sizemask & (1 << (i+1)*2); 173934b1a49cSRichard Henderson if (is_64bit) { 1740085272b3SRichard Henderson TCGv_i64 orig = temp_tcgv_i64(args[i]); 174134b1a49cSRichard Henderson TCGv_i32 h = tcg_temp_new_i32(); 174234b1a49cSRichard Henderson TCGv_i32 l = tcg_temp_new_i32(); 174334b1a49cSRichard Henderson tcg_gen_extr_i64_i32(l, h, orig); 1744ae8b75dcSRichard Henderson split_args[real_args++] = tcgv_i32_temp(h); 1745ae8b75dcSRichard Henderson split_args[real_args++] = tcgv_i32_temp(l); 174634b1a49cSRichard Henderson } else { 174734b1a49cSRichard Henderson split_args[real_args++] = args[i]; 174834b1a49cSRichard Henderson } 174934b1a49cSRichard Henderson } 175034b1a49cSRichard Henderson nargs = real_args; 175134b1a49cSRichard Henderson args = split_args; 175234b1a49cSRichard Henderson sizemask = 0; 175334b1a49cSRichard Henderson } 175434b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64 17552bece2c8SRichard Henderson for (i = 0; i < nargs; ++i) { 17562bece2c8SRichard Henderson int is_64bit = sizemask & (1 << (i+1)*2); 17572bece2c8SRichard Henderson int is_signed = sizemask & (2 << (i+1)*2); 17582bece2c8SRichard Henderson if (!is_64bit) { 17592bece2c8SRichard Henderson TCGv_i64 temp = tcg_temp_new_i64(); 1760085272b3SRichard Henderson TCGv_i64 orig = temp_tcgv_i64(args[i]); 17612bece2c8SRichard Henderson if (is_signed) { 17622bece2c8SRichard Henderson tcg_gen_ext32s_i64(temp, orig); 17632bece2c8SRichard Henderson } else { 17642bece2c8SRichard Henderson tcg_gen_ext32u_i64(temp, orig); 17652bece2c8SRichard Henderson } 1766ae8b75dcSRichard Henderson args[i] = tcgv_i64_temp(temp); 17672bece2c8SRichard Henderson } 17682bece2c8SRichard Henderson } 17692bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */ 17702bece2c8SRichard Henderson 177115fa08f8SRichard Henderson op = tcg_emit_op(INDEX_op_call); 177275e8b9b7SRichard Henderson 177375e8b9b7SRichard Henderson pi = 0; 1774ae8b75dcSRichard Henderson if (ret != NULL) { 177534b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \ 177634b1a49cSRichard Henderson && !defined(CONFIG_TCG_INTERPRETER) 177734b1a49cSRichard Henderson if (orig_sizemask & 1) { 177834b1a49cSRichard Henderson /* The 32-bit ABI is going to return the 64-bit value in 177934b1a49cSRichard Henderson the %o0/%o1 register pair. Prepare for this by using 178034b1a49cSRichard Henderson two return temporaries, and reassemble below. */ 178134b1a49cSRichard Henderson retl = tcg_temp_new_i64(); 178234b1a49cSRichard Henderson reth = tcg_temp_new_i64(); 1783ae8b75dcSRichard Henderson op->args[pi++] = tcgv_i64_arg(reth); 1784ae8b75dcSRichard Henderson op->args[pi++] = tcgv_i64_arg(retl); 178534b1a49cSRichard Henderson nb_rets = 2; 178634b1a49cSRichard Henderson } else { 1787ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(ret); 178834b1a49cSRichard Henderson nb_rets = 1; 178934b1a49cSRichard Henderson } 179034b1a49cSRichard Henderson #else 179134b1a49cSRichard Henderson if (TCG_TARGET_REG_BITS < 64 && (sizemask & 1)) { 179202eb19d0SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 1793ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(ret + 1); 1794ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(ret); 1795a7812ae4Spbrook #else 1796ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(ret); 1797ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(ret + 1); 1798a7812ae4Spbrook #endif 1799a7812ae4Spbrook nb_rets = 2; 180034b1a49cSRichard Henderson } else { 1801ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(ret); 1802a7812ae4Spbrook nb_rets = 1; 1803a7812ae4Spbrook } 180434b1a49cSRichard Henderson #endif 1805a7812ae4Spbrook } else { 1806a7812ae4Spbrook nb_rets = 0; 1807a7812ae4Spbrook } 1808cd9090aaSRichard Henderson TCGOP_CALLO(op) = nb_rets; 180975e8b9b7SRichard Henderson 1810a7812ae4Spbrook real_args = 0; 1811a7812ae4Spbrook for (i = 0; i < nargs; i++) { 18122bece2c8SRichard Henderson int is_64bit = sizemask & (1 << (i+1)*2); 1813bbb8a1b4SRichard Henderson if (TCG_TARGET_REG_BITS < 64 && is_64bit) { 181439cf05d3Sbellard #ifdef TCG_TARGET_CALL_ALIGN_ARGS 181539cf05d3Sbellard /* some targets want aligned 64 bit args */ 1816ebd486d5Smalc if (real_args & 1) { 181775e8b9b7SRichard Henderson op->args[pi++] = TCG_CALL_DUMMY_ARG; 1818ebd486d5Smalc real_args++; 181939cf05d3Sbellard } 182039cf05d3Sbellard #endif 18213f90f252SRichard Henderson /* If stack grows up, then we will be placing successive 18223f90f252SRichard Henderson arguments at lower addresses, which means we need to 18233f90f252SRichard Henderson reverse the order compared to how we would normally 18243f90f252SRichard Henderson treat either big or little-endian. For those arguments 18253f90f252SRichard Henderson that will wind up in registers, this still works for 18263f90f252SRichard Henderson HPPA (the only current STACK_GROWSUP target) since the 18273f90f252SRichard Henderson argument registers are *also* allocated in decreasing 18283f90f252SRichard Henderson order. If another such target is added, this logic may 18293f90f252SRichard Henderson have to get more complicated to differentiate between 18303f90f252SRichard Henderson stack arguments and register arguments. */ 183102eb19d0SRichard Henderson #if defined(HOST_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP) 1832ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(args[i] + 1); 1833ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(args[i]); 1834c896fe29Sbellard #else 1835ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(args[i]); 1836ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(args[i] + 1); 1837c896fe29Sbellard #endif 1838a7812ae4Spbrook real_args += 2; 18392bece2c8SRichard Henderson continue; 18402bece2c8SRichard Henderson } 18412bece2c8SRichard Henderson 1842ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(args[i]); 1843a7812ae4Spbrook real_args++; 1844c896fe29Sbellard } 184575e8b9b7SRichard Henderson op->args[pi++] = (uintptr_t)func; 184675e8b9b7SRichard Henderson op->args[pi++] = flags; 1847cd9090aaSRichard Henderson TCGOP_CALLI(op) = real_args; 1848a7812ae4Spbrook 184975e8b9b7SRichard Henderson /* Make sure the fields didn't overflow. */ 1850cd9090aaSRichard Henderson tcg_debug_assert(TCGOP_CALLI(op) == real_args); 185175e8b9b7SRichard Henderson tcg_debug_assert(pi <= ARRAY_SIZE(op->args)); 18522bece2c8SRichard Henderson 185334b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \ 185434b1a49cSRichard Henderson && !defined(CONFIG_TCG_INTERPRETER) 185534b1a49cSRichard Henderson /* Free all of the parts we allocated above. */ 185634b1a49cSRichard Henderson for (i = real_args = 0; i < orig_nargs; ++i) { 185734b1a49cSRichard Henderson int is_64bit = orig_sizemask & (1 << (i+1)*2); 185834b1a49cSRichard Henderson if (is_64bit) { 1859085272b3SRichard Henderson tcg_temp_free_internal(args[real_args++]); 1860085272b3SRichard Henderson tcg_temp_free_internal(args[real_args++]); 186134b1a49cSRichard Henderson } else { 186234b1a49cSRichard Henderson real_args++; 186334b1a49cSRichard Henderson } 186434b1a49cSRichard Henderson } 186534b1a49cSRichard Henderson if (orig_sizemask & 1) { 186634b1a49cSRichard Henderson /* The 32-bit ABI returned two 32-bit pieces. Re-assemble them. 186734b1a49cSRichard Henderson Note that describing these as TCGv_i64 eliminates an unnecessary 186834b1a49cSRichard Henderson zero-extension that tcg_gen_concat_i32_i64 would create. */ 1869085272b3SRichard Henderson tcg_gen_concat32_i64(temp_tcgv_i64(ret), retl, reth); 187034b1a49cSRichard Henderson tcg_temp_free_i64(retl); 187134b1a49cSRichard Henderson tcg_temp_free_i64(reth); 187234b1a49cSRichard Henderson } 187334b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64 18742bece2c8SRichard Henderson for (i = 0; i < nargs; ++i) { 18752bece2c8SRichard Henderson int is_64bit = sizemask & (1 << (i+1)*2); 18762bece2c8SRichard Henderson if (!is_64bit) { 1877085272b3SRichard Henderson tcg_temp_free_internal(args[i]); 18782bece2c8SRichard Henderson } 18792bece2c8SRichard Henderson } 18802bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */ 1881a7812ae4Spbrook } 1882c896fe29Sbellard 18838fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s) 1884c896fe29Sbellard { 1885ac3b8891SRichard Henderson int i, n; 1886c896fe29Sbellard TCGTemp *ts; 1887ac3b8891SRichard Henderson 1888ac3b8891SRichard Henderson for (i = 0, n = s->nb_globals; i < n; i++) { 1889c896fe29Sbellard ts = &s->temps[i]; 1890ac3b8891SRichard Henderson ts->val_type = (ts->fixed_reg ? TEMP_VAL_REG : TEMP_VAL_MEM); 1891c896fe29Sbellard } 1892ac3b8891SRichard Henderson for (n = s->nb_temps; i < n; i++) { 1893e8996ee0Sbellard ts = &s->temps[i]; 1894ac3b8891SRichard Henderson ts->val_type = (ts->temp_local ? TEMP_VAL_MEM : TEMP_VAL_DEAD); 1895e8996ee0Sbellard ts->mem_allocated = 0; 1896e8996ee0Sbellard ts->fixed_reg = 0; 1897e8996ee0Sbellard } 1898f8b2f202SRichard Henderson 1899f8b2f202SRichard Henderson memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp)); 1900c896fe29Sbellard } 1901c896fe29Sbellard 1902f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size, 1903f8b2f202SRichard Henderson TCGTemp *ts) 1904c896fe29Sbellard { 19051807f4c4SRichard Henderson int idx = temp_idx(ts); 1906ac56dd48Spbrook 1907fa477d25SRichard Henderson if (ts->temp_global) { 1908ac56dd48Spbrook pstrcpy(buf, buf_size, ts->name); 1909f8b2f202SRichard Henderson } else if (ts->temp_local) { 1910641d5fbeSbellard snprintf(buf, buf_size, "loc%d", idx - s->nb_globals); 1911f8b2f202SRichard Henderson } else { 1912ac56dd48Spbrook snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals); 1913c896fe29Sbellard } 1914c896fe29Sbellard return buf; 1915c896fe29Sbellard } 1916c896fe29Sbellard 191743439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf, 191843439139SRichard Henderson int buf_size, TCGArg arg) 1919f8b2f202SRichard Henderson { 192043439139SRichard Henderson return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg)); 1921f8b2f202SRichard Henderson } 1922f8b2f202SRichard Henderson 19236e085f72SRichard Henderson /* Find helper name. */ 19246e085f72SRichard Henderson static inline const char *tcg_find_helper(TCGContext *s, uintptr_t val) 1925e8996ee0Sbellard { 19266e085f72SRichard Henderson const char *ret = NULL; 1927619205fdSEmilio G. Cota if (helper_table) { 1928619205fdSEmilio G. Cota TCGHelperInfo *info = g_hash_table_lookup(helper_table, (gpointer)val); 192972866e82SRichard Henderson if (info) { 193072866e82SRichard Henderson ret = info->name; 193172866e82SRichard Henderson } 1932e8996ee0Sbellard } 19336e085f72SRichard Henderson return ret; 19344dc81f28Sbellard } 19354dc81f28Sbellard 1936f48f3edeSblueswir1 static const char * const cond_name[] = 1937f48f3edeSblueswir1 { 19380aed257fSRichard Henderson [TCG_COND_NEVER] = "never", 19390aed257fSRichard Henderson [TCG_COND_ALWAYS] = "always", 1940f48f3edeSblueswir1 [TCG_COND_EQ] = "eq", 1941f48f3edeSblueswir1 [TCG_COND_NE] = "ne", 1942f48f3edeSblueswir1 [TCG_COND_LT] = "lt", 1943f48f3edeSblueswir1 [TCG_COND_GE] = "ge", 1944f48f3edeSblueswir1 [TCG_COND_LE] = "le", 1945f48f3edeSblueswir1 [TCG_COND_GT] = "gt", 1946f48f3edeSblueswir1 [TCG_COND_LTU] = "ltu", 1947f48f3edeSblueswir1 [TCG_COND_GEU] = "geu", 1948f48f3edeSblueswir1 [TCG_COND_LEU] = "leu", 1949f48f3edeSblueswir1 [TCG_COND_GTU] = "gtu" 1950f48f3edeSblueswir1 }; 1951f48f3edeSblueswir1 1952f713d6adSRichard Henderson static const char * const ldst_name[] = 1953f713d6adSRichard Henderson { 1954f713d6adSRichard Henderson [MO_UB] = "ub", 1955f713d6adSRichard Henderson [MO_SB] = "sb", 1956f713d6adSRichard Henderson [MO_LEUW] = "leuw", 1957f713d6adSRichard Henderson [MO_LESW] = "lesw", 1958f713d6adSRichard Henderson [MO_LEUL] = "leul", 1959f713d6adSRichard Henderson [MO_LESL] = "lesl", 1960f713d6adSRichard Henderson [MO_LEQ] = "leq", 1961f713d6adSRichard Henderson [MO_BEUW] = "beuw", 1962f713d6adSRichard Henderson [MO_BESW] = "besw", 1963f713d6adSRichard Henderson [MO_BEUL] = "beul", 1964f713d6adSRichard Henderson [MO_BESL] = "besl", 1965f713d6adSRichard Henderson [MO_BEQ] = "beq", 1966f713d6adSRichard Henderson }; 1967f713d6adSRichard Henderson 19681f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = { 196952bf9771Stony.nguyen@bt.com #ifdef TARGET_ALIGNED_ONLY 19701f00b27fSSergey Sorokin [MO_UNALN >> MO_ASHIFT] = "un+", 19711f00b27fSSergey Sorokin [MO_ALIGN >> MO_ASHIFT] = "", 19721f00b27fSSergey Sorokin #else 19731f00b27fSSergey Sorokin [MO_UNALN >> MO_ASHIFT] = "", 19741f00b27fSSergey Sorokin [MO_ALIGN >> MO_ASHIFT] = "al+", 19751f00b27fSSergey Sorokin #endif 19761f00b27fSSergey Sorokin [MO_ALIGN_2 >> MO_ASHIFT] = "al2+", 19771f00b27fSSergey Sorokin [MO_ALIGN_4 >> MO_ASHIFT] = "al4+", 19781f00b27fSSergey Sorokin [MO_ALIGN_8 >> MO_ASHIFT] = "al8+", 19791f00b27fSSergey Sorokin [MO_ALIGN_16 >> MO_ASHIFT] = "al16+", 19801f00b27fSSergey Sorokin [MO_ALIGN_32 >> MO_ASHIFT] = "al32+", 19811f00b27fSSergey Sorokin [MO_ALIGN_64 >> MO_ASHIFT] = "al64+", 19821f00b27fSSergey Sorokin }; 19831f00b27fSSergey Sorokin 1984b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d) 1985b016486eSRichard Henderson { 1986b016486eSRichard Henderson return (d & (d - 1)) == 0; 1987b016486eSRichard Henderson } 1988b016486eSRichard Henderson 1989b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d) 1990b016486eSRichard Henderson { 1991b016486eSRichard Henderson if (TCG_TARGET_NB_REGS <= 32) { 1992b016486eSRichard Henderson return ctz32(d); 1993b016486eSRichard Henderson } else { 1994b016486eSRichard Henderson return ctz64(d); 1995b016486eSRichard Henderson } 1996b016486eSRichard Henderson } 1997b016486eSRichard Henderson 19981894f69aSRichard Henderson static void tcg_dump_ops(TCGContext *s, bool have_prefs) 1999c896fe29Sbellard { 2000c896fe29Sbellard char buf[128]; 2001c45cb8bbSRichard Henderson TCGOp *op; 2002c896fe29Sbellard 200315fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 2004c45cb8bbSRichard Henderson int i, k, nb_oargs, nb_iargs, nb_cargs; 2005c45cb8bbSRichard Henderson const TCGOpDef *def; 2006c45cb8bbSRichard Henderson TCGOpcode c; 2007bdfb460eSRichard Henderson int col = 0; 2008c45cb8bbSRichard Henderson 2009c45cb8bbSRichard Henderson c = op->opc; 2010c896fe29Sbellard def = &tcg_op_defs[c]; 2011c45cb8bbSRichard Henderson 2012765b842aSRichard Henderson if (c == INDEX_op_insn_start) { 2013b016486eSRichard Henderson nb_oargs = 0; 201415fa08f8SRichard Henderson col += qemu_log("\n ----"); 20159aef40edSRichard Henderson 20169aef40edSRichard Henderson for (i = 0; i < TARGET_INSN_START_WORDS; ++i) { 20179aef40edSRichard Henderson target_ulong a; 20187e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS 2019efee3746SRichard Henderson a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]); 20207e4597d7Sbellard #else 2021efee3746SRichard Henderson a = op->args[i]; 20227e4597d7Sbellard #endif 2023bdfb460eSRichard Henderson col += qemu_log(" " TARGET_FMT_lx, a); 2024eeacee4dSBlue Swirl } 20257e4597d7Sbellard } else if (c == INDEX_op_call) { 2026c896fe29Sbellard /* variable number of arguments */ 2027cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 2028cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 2029c896fe29Sbellard nb_cargs = def->nb_cargs; 2030b03cce8eSbellard 2031cf066674SRichard Henderson /* function name, flags, out args */ 2032bdfb460eSRichard Henderson col += qemu_log(" %s %s,$0x%" TCG_PRIlx ",$%d", def->name, 2033efee3746SRichard Henderson tcg_find_helper(s, op->args[nb_oargs + nb_iargs]), 2034efee3746SRichard Henderson op->args[nb_oargs + nb_iargs + 1], nb_oargs); 2035b03cce8eSbellard for (i = 0; i < nb_oargs; i++) { 203643439139SRichard Henderson col += qemu_log(",%s", tcg_get_arg_str(s, buf, sizeof(buf), 2037efee3746SRichard Henderson op->args[i])); 2038b03cce8eSbellard } 2039cf066674SRichard Henderson for (i = 0; i < nb_iargs; i++) { 2040efee3746SRichard Henderson TCGArg arg = op->args[nb_oargs + i]; 2041cf066674SRichard Henderson const char *t = "<dummy>"; 2042cf066674SRichard Henderson if (arg != TCG_CALL_DUMMY_ARG) { 204343439139SRichard Henderson t = tcg_get_arg_str(s, buf, sizeof(buf), arg); 2044b03cce8eSbellard } 2045bdfb460eSRichard Henderson col += qemu_log(",%s", t); 2046e8996ee0Sbellard } 2047b03cce8eSbellard } else { 2048bdfb460eSRichard Henderson col += qemu_log(" %s ", def->name); 2049c45cb8bbSRichard Henderson 2050c896fe29Sbellard nb_oargs = def->nb_oargs; 2051c896fe29Sbellard nb_iargs = def->nb_iargs; 2052c896fe29Sbellard nb_cargs = def->nb_cargs; 2053c896fe29Sbellard 2054d2fd745fSRichard Henderson if (def->flags & TCG_OPF_VECTOR) { 2055d2fd745fSRichard Henderson col += qemu_log("v%d,e%d,", 64 << TCGOP_VECL(op), 2056d2fd745fSRichard Henderson 8 << TCGOP_VECE(op)); 2057d2fd745fSRichard Henderson } 2058d2fd745fSRichard Henderson 2059c896fe29Sbellard k = 0; 2060c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 2061eeacee4dSBlue Swirl if (k != 0) { 2062bdfb460eSRichard Henderson col += qemu_log(","); 2063eeacee4dSBlue Swirl } 206443439139SRichard Henderson col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf), 2065efee3746SRichard Henderson op->args[k++])); 2066c896fe29Sbellard } 2067c896fe29Sbellard for (i = 0; i < nb_iargs; i++) { 2068eeacee4dSBlue Swirl if (k != 0) { 2069bdfb460eSRichard Henderson col += qemu_log(","); 2070eeacee4dSBlue Swirl } 207143439139SRichard Henderson col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf), 2072efee3746SRichard Henderson op->args[k++])); 2073c896fe29Sbellard } 2074be210acbSRichard Henderson switch (c) { 2075be210acbSRichard Henderson case INDEX_op_brcond_i32: 2076ffc5ea09SRichard Henderson case INDEX_op_setcond_i32: 2077ffc5ea09SRichard Henderson case INDEX_op_movcond_i32: 2078be210acbSRichard Henderson case INDEX_op_brcond2_i32: 2079be210acbSRichard Henderson case INDEX_op_setcond2_i32: 2080ffc5ea09SRichard Henderson case INDEX_op_brcond_i64: 2081be210acbSRichard Henderson case INDEX_op_setcond_i64: 2082ffc5ea09SRichard Henderson case INDEX_op_movcond_i64: 2083212be173SRichard Henderson case INDEX_op_cmp_vec: 2084f75da298SRichard Henderson case INDEX_op_cmpsel_vec: 2085efee3746SRichard Henderson if (op->args[k] < ARRAY_SIZE(cond_name) 2086efee3746SRichard Henderson && cond_name[op->args[k]]) { 2087efee3746SRichard Henderson col += qemu_log(",%s", cond_name[op->args[k++]]); 2088eeacee4dSBlue Swirl } else { 2089efee3746SRichard Henderson col += qemu_log(",$0x%" TCG_PRIlx, op->args[k++]); 2090eeacee4dSBlue Swirl } 2091f48f3edeSblueswir1 i = 1; 2092be210acbSRichard Henderson break; 2093f713d6adSRichard Henderson case INDEX_op_qemu_ld_i32: 2094f713d6adSRichard Henderson case INDEX_op_qemu_st_i32: 209507ce0b05SRichard Henderson case INDEX_op_qemu_st8_i32: 2096f713d6adSRichard Henderson case INDEX_op_qemu_ld_i64: 2097f713d6adSRichard Henderson case INDEX_op_qemu_st_i64: 209859227d5dSRichard Henderson { 2099efee3746SRichard Henderson TCGMemOpIdx oi = op->args[k++]; 210014776ab5STony Nguyen MemOp op = get_memop(oi); 210159227d5dSRichard Henderson unsigned ix = get_mmuidx(oi); 210259227d5dSRichard Henderson 210359c4b7e8SRichard Henderson if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) { 2104bdfb460eSRichard Henderson col += qemu_log(",$0x%x,%u", op, ix); 210559c4b7e8SRichard Henderson } else { 21061f00b27fSSergey Sorokin const char *s_al, *s_op; 21071f00b27fSSergey Sorokin s_al = alignment_name[(op & MO_AMASK) >> MO_ASHIFT]; 210859c4b7e8SRichard Henderson s_op = ldst_name[op & (MO_BSWAP | MO_SSIZE)]; 2109bdfb460eSRichard Henderson col += qemu_log(",%s%s,%u", s_al, s_op, ix); 2110f713d6adSRichard Henderson } 2111f713d6adSRichard Henderson i = 1; 211259227d5dSRichard Henderson } 2113f713d6adSRichard Henderson break; 2114be210acbSRichard Henderson default: 2115f48f3edeSblueswir1 i = 0; 2116be210acbSRichard Henderson break; 2117be210acbSRichard Henderson } 211851e3972cSRichard Henderson switch (c) { 211951e3972cSRichard Henderson case INDEX_op_set_label: 212051e3972cSRichard Henderson case INDEX_op_br: 212151e3972cSRichard Henderson case INDEX_op_brcond_i32: 212251e3972cSRichard Henderson case INDEX_op_brcond_i64: 212351e3972cSRichard Henderson case INDEX_op_brcond2_i32: 2124efee3746SRichard Henderson col += qemu_log("%s$L%d", k ? "," : "", 2125efee3746SRichard Henderson arg_label(op->args[k])->id); 212651e3972cSRichard Henderson i++, k++; 212751e3972cSRichard Henderson break; 212851e3972cSRichard Henderson default: 212951e3972cSRichard Henderson break; 2130eeacee4dSBlue Swirl } 213151e3972cSRichard Henderson for (; i < nb_cargs; i++, k++) { 2132efee3746SRichard Henderson col += qemu_log("%s$0x%" TCG_PRIlx, k ? "," : "", op->args[k]); 2133bdfb460eSRichard Henderson } 2134bdfb460eSRichard Henderson } 2135bdfb460eSRichard Henderson 21361894f69aSRichard Henderson if (have_prefs || op->life) { 21377606488cSRobert Foley 21387606488cSRobert Foley QemuLogFile *logfile; 21397606488cSRobert Foley 21407606488cSRobert Foley rcu_read_lock(); 2141d73415a3SStefan Hajnoczi logfile = qatomic_rcu_read(&qemu_logfile); 21427606488cSRobert Foley if (logfile) { 21431894f69aSRichard Henderson for (; col < 40; ++col) { 21447606488cSRobert Foley putc(' ', logfile->fd); 2145bdfb460eSRichard Henderson } 21461894f69aSRichard Henderson } 21477606488cSRobert Foley rcu_read_unlock(); 21487606488cSRobert Foley } 21491894f69aSRichard Henderson 21501894f69aSRichard Henderson if (op->life) { 21511894f69aSRichard Henderson unsigned life = op->life; 2152bdfb460eSRichard Henderson 2153bdfb460eSRichard Henderson if (life & (SYNC_ARG * 3)) { 2154bdfb460eSRichard Henderson qemu_log(" sync:"); 2155bdfb460eSRichard Henderson for (i = 0; i < 2; ++i) { 2156bdfb460eSRichard Henderson if (life & (SYNC_ARG << i)) { 2157bdfb460eSRichard Henderson qemu_log(" %d", i); 2158bdfb460eSRichard Henderson } 2159bdfb460eSRichard Henderson } 2160bdfb460eSRichard Henderson } 2161bdfb460eSRichard Henderson life /= DEAD_ARG; 2162bdfb460eSRichard Henderson if (life) { 2163bdfb460eSRichard Henderson qemu_log(" dead:"); 2164bdfb460eSRichard Henderson for (i = 0; life; ++i, life >>= 1) { 2165bdfb460eSRichard Henderson if (life & 1) { 2166bdfb460eSRichard Henderson qemu_log(" %d", i); 2167bdfb460eSRichard Henderson } 2168bdfb460eSRichard Henderson } 2169c896fe29Sbellard } 2170b03cce8eSbellard } 21711894f69aSRichard Henderson 21721894f69aSRichard Henderson if (have_prefs) { 21731894f69aSRichard Henderson for (i = 0; i < nb_oargs; ++i) { 21741894f69aSRichard Henderson TCGRegSet set = op->output_pref[i]; 21751894f69aSRichard Henderson 21761894f69aSRichard Henderson if (i == 0) { 21771894f69aSRichard Henderson qemu_log(" pref="); 21781894f69aSRichard Henderson } else { 21791894f69aSRichard Henderson qemu_log(","); 21801894f69aSRichard Henderson } 21811894f69aSRichard Henderson if (set == 0) { 21821894f69aSRichard Henderson qemu_log("none"); 21831894f69aSRichard Henderson } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) { 21841894f69aSRichard Henderson qemu_log("all"); 21851894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG 21861894f69aSRichard Henderson } else if (tcg_regset_single(set)) { 21871894f69aSRichard Henderson TCGReg reg = tcg_regset_first(set); 21881894f69aSRichard Henderson qemu_log("%s", tcg_target_reg_names[reg]); 21891894f69aSRichard Henderson #endif 21901894f69aSRichard Henderson } else if (TCG_TARGET_NB_REGS <= 32) { 21911894f69aSRichard Henderson qemu_log("%#x", (uint32_t)set); 21921894f69aSRichard Henderson } else { 21931894f69aSRichard Henderson qemu_log("%#" PRIx64, (uint64_t)set); 21941894f69aSRichard Henderson } 21951894f69aSRichard Henderson } 21961894f69aSRichard Henderson } 21971894f69aSRichard Henderson 2198eeacee4dSBlue Swirl qemu_log("\n"); 2199c896fe29Sbellard } 2200c896fe29Sbellard } 2201c896fe29Sbellard 2202c896fe29Sbellard /* we give more priority to constraints with less registers */ 2203c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k) 2204c896fe29Sbellard { 220574a11790SRichard Henderson const TCGArgConstraint *arg_ct = &def->args_ct[k]; 220674a11790SRichard Henderson int n; 2207c896fe29Sbellard 2208bc2b17e6SRichard Henderson if (arg_ct->oalias) { 2209c896fe29Sbellard /* an alias is equivalent to a single register */ 2210c896fe29Sbellard n = 1; 2211c896fe29Sbellard } else { 221274a11790SRichard Henderson n = ctpop64(arg_ct->regs); 2213c896fe29Sbellard } 2214c896fe29Sbellard return TCG_TARGET_NB_REGS - n + 1; 2215c896fe29Sbellard } 2216c896fe29Sbellard 2217c896fe29Sbellard /* sort from highest priority to lowest */ 2218c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n) 2219c896fe29Sbellard { 222066792f90SRichard Henderson int i, j; 222166792f90SRichard Henderson TCGArgConstraint *a = def->args_ct; 2222c896fe29Sbellard 222366792f90SRichard Henderson for (i = 0; i < n; i++) { 222466792f90SRichard Henderson a[start + i].sort_index = start + i; 222566792f90SRichard Henderson } 222666792f90SRichard Henderson if (n <= 1) { 2227c896fe29Sbellard return; 222866792f90SRichard Henderson } 2229c896fe29Sbellard for (i = 0; i < n - 1; i++) { 2230c896fe29Sbellard for (j = i + 1; j < n; j++) { 223166792f90SRichard Henderson int p1 = get_constraint_priority(def, a[start + i].sort_index); 223266792f90SRichard Henderson int p2 = get_constraint_priority(def, a[start + j].sort_index); 2233c896fe29Sbellard if (p1 < p2) { 223466792f90SRichard Henderson int tmp = a[start + i].sort_index; 223566792f90SRichard Henderson a[start + i].sort_index = a[start + j].sort_index; 223666792f90SRichard Henderson a[start + j].sort_index = tmp; 2237c896fe29Sbellard } 2238c896fe29Sbellard } 2239c896fe29Sbellard } 2240c896fe29Sbellard } 2241c896fe29Sbellard 2242f69d277eSRichard Henderson static void process_op_defs(TCGContext *s) 2243c896fe29Sbellard { 2244a9751609SRichard Henderson TCGOpcode op; 2245c896fe29Sbellard 2246f69d277eSRichard Henderson for (op = 0; op < NB_OPS; op++) { 2247f69d277eSRichard Henderson TCGOpDef *def = &tcg_op_defs[op]; 2248f69d277eSRichard Henderson const TCGTargetOpDef *tdefs; 2249069ea736SRichard Henderson TCGType type; 2250069ea736SRichard Henderson int i, nb_args; 2251f69d277eSRichard Henderson 2252f69d277eSRichard Henderson if (def->flags & TCG_OPF_NOT_PRESENT) { 2253f69d277eSRichard Henderson continue; 2254f69d277eSRichard Henderson } 2255f69d277eSRichard Henderson 2256c896fe29Sbellard nb_args = def->nb_iargs + def->nb_oargs; 2257f69d277eSRichard Henderson if (nb_args == 0) { 2258f69d277eSRichard Henderson continue; 2259f69d277eSRichard Henderson } 2260f69d277eSRichard Henderson 2261f69d277eSRichard Henderson tdefs = tcg_target_op_def(op); 2262f69d277eSRichard Henderson /* Missing TCGTargetOpDef entry. */ 2263f69d277eSRichard Henderson tcg_debug_assert(tdefs != NULL); 2264f69d277eSRichard Henderson 2265069ea736SRichard Henderson type = (def->flags & TCG_OPF_64BIT ? TCG_TYPE_I64 : TCG_TYPE_I32); 2266c896fe29Sbellard for (i = 0; i < nb_args; i++) { 2267f69d277eSRichard Henderson const char *ct_str = tdefs->args_ct_str[i]; 2268f69d277eSRichard Henderson /* Incomplete TCGTargetOpDef entry. */ 2269eabb7b91SAurelien Jarno tcg_debug_assert(ct_str != NULL); 2270f69d277eSRichard Henderson 227117280ff4SRichard Henderson while (*ct_str != '\0') { 227217280ff4SRichard Henderson switch(*ct_str) { 227317280ff4SRichard Henderson case '0' ... '9': 227417280ff4SRichard Henderson { 227517280ff4SRichard Henderson int oarg = *ct_str - '0'; 227617280ff4SRichard Henderson tcg_debug_assert(ct_str == tdefs->args_ct_str[i]); 2277eabb7b91SAurelien Jarno tcg_debug_assert(oarg < def->nb_oargs); 227874a11790SRichard Henderson tcg_debug_assert(def->args_ct[oarg].regs != 0); 2279c896fe29Sbellard def->args_ct[i] = def->args_ct[oarg]; 2280bc2b17e6SRichard Henderson /* The output sets oalias. */ 2281bc2b17e6SRichard Henderson def->args_ct[oarg].oalias = true; 22825ff9d6a4Sbellard def->args_ct[oarg].alias_index = i; 2283bc2b17e6SRichard Henderson /* The input sets ialias. */ 2284bc2b17e6SRichard Henderson def->args_ct[i].ialias = true; 22855ff9d6a4Sbellard def->args_ct[i].alias_index = oarg; 228617280ff4SRichard Henderson } 228717280ff4SRichard Henderson ct_str++; 2288c896fe29Sbellard break; 228982790a87SRichard Henderson case '&': 2290bc2b17e6SRichard Henderson def->args_ct[i].newreg = true; 229182790a87SRichard Henderson ct_str++; 229282790a87SRichard Henderson break; 2293c896fe29Sbellard case 'i': 2294c896fe29Sbellard def->args_ct[i].ct |= TCG_CT_CONST; 2295c896fe29Sbellard ct_str++; 2296c896fe29Sbellard break; 2297c896fe29Sbellard default: 2298069ea736SRichard Henderson ct_str = target_parse_constraint(&def->args_ct[i], 2299069ea736SRichard Henderson ct_str, type); 2300f69d277eSRichard Henderson /* Typo in TCGTargetOpDef constraint. */ 2301069ea736SRichard Henderson tcg_debug_assert(ct_str != NULL); 2302c896fe29Sbellard } 2303c896fe29Sbellard } 2304c896fe29Sbellard } 2305c896fe29Sbellard 2306c68aaa18SStefan Weil /* TCGTargetOpDef entry with too much information? */ 2307eabb7b91SAurelien Jarno tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL); 2308c68aaa18SStefan Weil 2309c896fe29Sbellard /* sort the constraints (XXX: this is just an heuristic) */ 2310c896fe29Sbellard sort_constraints(def, 0, def->nb_oargs); 2311c896fe29Sbellard sort_constraints(def, def->nb_oargs, def->nb_iargs); 2312c896fe29Sbellard } 2313c896fe29Sbellard } 2314c896fe29Sbellard 23150c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op) 23160c627cdcSRichard Henderson { 2317d88a117eSRichard Henderson TCGLabel *label; 2318d88a117eSRichard Henderson 2319d88a117eSRichard Henderson switch (op->opc) { 2320d88a117eSRichard Henderson case INDEX_op_br: 2321d88a117eSRichard Henderson label = arg_label(op->args[0]); 2322d88a117eSRichard Henderson label->refs--; 2323d88a117eSRichard Henderson break; 2324d88a117eSRichard Henderson case INDEX_op_brcond_i32: 2325d88a117eSRichard Henderson case INDEX_op_brcond_i64: 2326d88a117eSRichard Henderson label = arg_label(op->args[3]); 2327d88a117eSRichard Henderson label->refs--; 2328d88a117eSRichard Henderson break; 2329d88a117eSRichard Henderson case INDEX_op_brcond2_i32: 2330d88a117eSRichard Henderson label = arg_label(op->args[5]); 2331d88a117eSRichard Henderson label->refs--; 2332d88a117eSRichard Henderson break; 2333d88a117eSRichard Henderson default: 2334d88a117eSRichard Henderson break; 2335d88a117eSRichard Henderson } 2336d88a117eSRichard Henderson 233715fa08f8SRichard Henderson QTAILQ_REMOVE(&s->ops, op, link); 233815fa08f8SRichard Henderson QTAILQ_INSERT_TAIL(&s->free_ops, op, link); 2339abebf925SRichard Henderson s->nb_ops--; 23400c627cdcSRichard Henderson 23410c627cdcSRichard Henderson #ifdef CONFIG_PROFILER 2342d73415a3SStefan Hajnoczi qatomic_set(&s->prof.del_op_count, s->prof.del_op_count + 1); 23430c627cdcSRichard Henderson #endif 23440c627cdcSRichard Henderson } 23450c627cdcSRichard Henderson 234615fa08f8SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc) 234715fa08f8SRichard Henderson { 234815fa08f8SRichard Henderson TCGContext *s = tcg_ctx; 234915fa08f8SRichard Henderson TCGOp *op; 235015fa08f8SRichard Henderson 235115fa08f8SRichard Henderson if (likely(QTAILQ_EMPTY(&s->free_ops))) { 235215fa08f8SRichard Henderson op = tcg_malloc(sizeof(TCGOp)); 235315fa08f8SRichard Henderson } else { 235415fa08f8SRichard Henderson op = QTAILQ_FIRST(&s->free_ops); 235515fa08f8SRichard Henderson QTAILQ_REMOVE(&s->free_ops, op, link); 235615fa08f8SRichard Henderson } 235715fa08f8SRichard Henderson memset(op, 0, offsetof(TCGOp, link)); 235815fa08f8SRichard Henderson op->opc = opc; 2359abebf925SRichard Henderson s->nb_ops++; 236015fa08f8SRichard Henderson 236115fa08f8SRichard Henderson return op; 236215fa08f8SRichard Henderson } 236315fa08f8SRichard Henderson 236415fa08f8SRichard Henderson TCGOp *tcg_emit_op(TCGOpcode opc) 236515fa08f8SRichard Henderson { 236615fa08f8SRichard Henderson TCGOp *op = tcg_op_alloc(opc); 236715fa08f8SRichard Henderson QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link); 236815fa08f8SRichard Henderson return op; 236915fa08f8SRichard Henderson } 237015fa08f8SRichard Henderson 2371ac1043f6SEmilio G. Cota TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op, TCGOpcode opc) 23725a18407fSRichard Henderson { 237315fa08f8SRichard Henderson TCGOp *new_op = tcg_op_alloc(opc); 237415fa08f8SRichard Henderson QTAILQ_INSERT_BEFORE(old_op, new_op, link); 23755a18407fSRichard Henderson return new_op; 23765a18407fSRichard Henderson } 23775a18407fSRichard Henderson 2378ac1043f6SEmilio G. Cota TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, TCGOpcode opc) 23795a18407fSRichard Henderson { 238015fa08f8SRichard Henderson TCGOp *new_op = tcg_op_alloc(opc); 238115fa08f8SRichard Henderson QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link); 23825a18407fSRichard Henderson return new_op; 23835a18407fSRichard Henderson } 23845a18407fSRichard Henderson 2385b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code. */ 2386b4fc67c7SRichard Henderson static void reachable_code_pass(TCGContext *s) 2387b4fc67c7SRichard Henderson { 2388b4fc67c7SRichard Henderson TCGOp *op, *op_next; 2389b4fc67c7SRichard Henderson bool dead = false; 2390b4fc67c7SRichard Henderson 2391b4fc67c7SRichard Henderson QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) { 2392b4fc67c7SRichard Henderson bool remove = dead; 2393b4fc67c7SRichard Henderson TCGLabel *label; 2394b4fc67c7SRichard Henderson int call_flags; 2395b4fc67c7SRichard Henderson 2396b4fc67c7SRichard Henderson switch (op->opc) { 2397b4fc67c7SRichard Henderson case INDEX_op_set_label: 2398b4fc67c7SRichard Henderson label = arg_label(op->args[0]); 2399b4fc67c7SRichard Henderson if (label->refs == 0) { 2400b4fc67c7SRichard Henderson /* 2401b4fc67c7SRichard Henderson * While there is an occasional backward branch, virtually 2402b4fc67c7SRichard Henderson * all branches generated by the translators are forward. 2403b4fc67c7SRichard Henderson * Which means that generally we will have already removed 2404b4fc67c7SRichard Henderson * all references to the label that will be, and there is 2405b4fc67c7SRichard Henderson * little to be gained by iterating. 2406b4fc67c7SRichard Henderson */ 2407b4fc67c7SRichard Henderson remove = true; 2408b4fc67c7SRichard Henderson } else { 2409b4fc67c7SRichard Henderson /* Once we see a label, insns become live again. */ 2410b4fc67c7SRichard Henderson dead = false; 2411b4fc67c7SRichard Henderson remove = false; 2412b4fc67c7SRichard Henderson 2413b4fc67c7SRichard Henderson /* 2414b4fc67c7SRichard Henderson * Optimization can fold conditional branches to unconditional. 2415b4fc67c7SRichard Henderson * If we find a label with one reference which is preceded by 2416b4fc67c7SRichard Henderson * an unconditional branch to it, remove both. This needed to 2417b4fc67c7SRichard Henderson * wait until the dead code in between them was removed. 2418b4fc67c7SRichard Henderson */ 2419b4fc67c7SRichard Henderson if (label->refs == 1) { 2420eae3eb3eSPaolo Bonzini TCGOp *op_prev = QTAILQ_PREV(op, link); 2421b4fc67c7SRichard Henderson if (op_prev->opc == INDEX_op_br && 2422b4fc67c7SRichard Henderson label == arg_label(op_prev->args[0])) { 2423b4fc67c7SRichard Henderson tcg_op_remove(s, op_prev); 2424b4fc67c7SRichard Henderson remove = true; 2425b4fc67c7SRichard Henderson } 2426b4fc67c7SRichard Henderson } 2427b4fc67c7SRichard Henderson } 2428b4fc67c7SRichard Henderson break; 2429b4fc67c7SRichard Henderson 2430b4fc67c7SRichard Henderson case INDEX_op_br: 2431b4fc67c7SRichard Henderson case INDEX_op_exit_tb: 2432b4fc67c7SRichard Henderson case INDEX_op_goto_ptr: 2433b4fc67c7SRichard Henderson /* Unconditional branches; everything following is dead. */ 2434b4fc67c7SRichard Henderson dead = true; 2435b4fc67c7SRichard Henderson break; 2436b4fc67c7SRichard Henderson 2437b4fc67c7SRichard Henderson case INDEX_op_call: 2438b4fc67c7SRichard Henderson /* Notice noreturn helper calls, raising exceptions. */ 2439b4fc67c7SRichard Henderson call_flags = op->args[TCGOP_CALLO(op) + TCGOP_CALLI(op) + 1]; 2440b4fc67c7SRichard Henderson if (call_flags & TCG_CALL_NO_RETURN) { 2441b4fc67c7SRichard Henderson dead = true; 2442b4fc67c7SRichard Henderson } 2443b4fc67c7SRichard Henderson break; 2444b4fc67c7SRichard Henderson 2445b4fc67c7SRichard Henderson case INDEX_op_insn_start: 2446b4fc67c7SRichard Henderson /* Never remove -- we need to keep these for unwind. */ 2447b4fc67c7SRichard Henderson remove = false; 2448b4fc67c7SRichard Henderson break; 2449b4fc67c7SRichard Henderson 2450b4fc67c7SRichard Henderson default: 2451b4fc67c7SRichard Henderson break; 2452b4fc67c7SRichard Henderson } 2453b4fc67c7SRichard Henderson 2454b4fc67c7SRichard Henderson if (remove) { 2455b4fc67c7SRichard Henderson tcg_op_remove(s, op); 2456b4fc67c7SRichard Henderson } 2457b4fc67c7SRichard Henderson } 2458b4fc67c7SRichard Henderson } 2459b4fc67c7SRichard Henderson 2460c70fbf0aSRichard Henderson #define TS_DEAD 1 2461c70fbf0aSRichard Henderson #define TS_MEM 2 2462c70fbf0aSRichard Henderson 24635a18407fSRichard Henderson #define IS_DEAD_ARG(n) (arg_life & (DEAD_ARG << (n))) 24645a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n))) 24655a18407fSRichard Henderson 246625f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp. */ 246725f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts) 246825f49c5fSRichard Henderson { 246925f49c5fSRichard Henderson return ts->state_ptr; 247025f49c5fSRichard Henderson } 247125f49c5fSRichard Henderson 247225f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the 247325f49c5fSRichard Henderson * maximal regset for its type. 247425f49c5fSRichard Henderson */ 247525f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts) 247625f49c5fSRichard Henderson { 247725f49c5fSRichard Henderson *la_temp_pref(ts) 247825f49c5fSRichard Henderson = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]); 247925f49c5fSRichard Henderson } 248025f49c5fSRichard Henderson 24819c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals 24829c43b68dSAurelien Jarno should be in memory. */ 24832616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt) 2484c896fe29Sbellard { 2485b83eabeaSRichard Henderson int i; 2486b83eabeaSRichard Henderson 2487b83eabeaSRichard Henderson for (i = 0; i < ng; ++i) { 2488b83eabeaSRichard Henderson s->temps[i].state = TS_DEAD | TS_MEM; 248925f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 2490b83eabeaSRichard Henderson } 2491b83eabeaSRichard Henderson for (i = ng; i < nt; ++i) { 2492b83eabeaSRichard Henderson s->temps[i].state = TS_DEAD; 249325f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 2494b83eabeaSRichard Henderson } 2495c896fe29Sbellard } 2496c896fe29Sbellard 24979c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals 24989c43b68dSAurelien Jarno and local temps should be in memory. */ 24992616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt) 2500641d5fbeSbellard { 2501b83eabeaSRichard Henderson int i; 2502641d5fbeSbellard 2503b83eabeaSRichard Henderson for (i = 0; i < ng; ++i) { 2504b83eabeaSRichard Henderson s->temps[i].state = TS_DEAD | TS_MEM; 250525f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 2506c70fbf0aSRichard Henderson } 2507b83eabeaSRichard Henderson for (i = ng; i < nt; ++i) { 2508b83eabeaSRichard Henderson s->temps[i].state = (s->temps[i].temp_local 2509b83eabeaSRichard Henderson ? TS_DEAD | TS_MEM 2510b83eabeaSRichard Henderson : TS_DEAD); 251125f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 2512641d5fbeSbellard } 2513641d5fbeSbellard } 2514641d5fbeSbellard 2515f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory. */ 2516f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng) 2517f65a061cSRichard Henderson { 2518f65a061cSRichard Henderson int i; 2519f65a061cSRichard Henderson 2520f65a061cSRichard Henderson for (i = 0; i < ng; ++i) { 252125f49c5fSRichard Henderson int state = s->temps[i].state; 252225f49c5fSRichard Henderson s->temps[i].state = state | TS_MEM; 252325f49c5fSRichard Henderson if (state == TS_DEAD) { 252425f49c5fSRichard Henderson /* If the global was previously dead, reset prefs. */ 252525f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 252625f49c5fSRichard Henderson } 2527f65a061cSRichard Henderson } 2528f65a061cSRichard Henderson } 2529f65a061cSRichard Henderson 2530b4cb76e6SRichard Henderson /* 2531b4cb76e6SRichard Henderson * liveness analysis: conditional branch: all temps are dead, 2532b4cb76e6SRichard Henderson * globals and local temps should be synced. 2533b4cb76e6SRichard Henderson */ 2534b4cb76e6SRichard Henderson static void la_bb_sync(TCGContext *s, int ng, int nt) 2535b4cb76e6SRichard Henderson { 2536b4cb76e6SRichard Henderson la_global_sync(s, ng); 2537b4cb76e6SRichard Henderson 2538b4cb76e6SRichard Henderson for (int i = ng; i < nt; ++i) { 2539b4cb76e6SRichard Henderson if (s->temps[i].temp_local) { 2540b4cb76e6SRichard Henderson int state = s->temps[i].state; 2541b4cb76e6SRichard Henderson s->temps[i].state = state | TS_MEM; 2542b4cb76e6SRichard Henderson if (state != TS_DEAD) { 2543b4cb76e6SRichard Henderson continue; 2544b4cb76e6SRichard Henderson } 2545b4cb76e6SRichard Henderson } else { 2546b4cb76e6SRichard Henderson s->temps[i].state = TS_DEAD; 2547b4cb76e6SRichard Henderson } 2548b4cb76e6SRichard Henderson la_reset_pref(&s->temps[i]); 2549b4cb76e6SRichard Henderson } 2550b4cb76e6SRichard Henderson } 2551b4cb76e6SRichard Henderson 2552f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill. */ 2553f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng) 2554f65a061cSRichard Henderson { 2555f65a061cSRichard Henderson int i; 2556f65a061cSRichard Henderson 2557f65a061cSRichard Henderson for (i = 0; i < ng; i++) { 2558f65a061cSRichard Henderson s->temps[i].state = TS_DEAD | TS_MEM; 255925f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 256025f49c5fSRichard Henderson } 256125f49c5fSRichard Henderson } 256225f49c5fSRichard Henderson 256325f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls. */ 256425f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt) 256525f49c5fSRichard Henderson { 256625f49c5fSRichard Henderson TCGRegSet mask = ~tcg_target_call_clobber_regs; 256725f49c5fSRichard Henderson int i; 256825f49c5fSRichard Henderson 256925f49c5fSRichard Henderson for (i = 0; i < nt; i++) { 257025f49c5fSRichard Henderson TCGTemp *ts = &s->temps[i]; 257125f49c5fSRichard Henderson if (!(ts->state & TS_DEAD)) { 257225f49c5fSRichard Henderson TCGRegSet *pset = la_temp_pref(ts); 257325f49c5fSRichard Henderson TCGRegSet set = *pset; 257425f49c5fSRichard Henderson 257525f49c5fSRichard Henderson set &= mask; 257625f49c5fSRichard Henderson /* If the combination is not possible, restart. */ 257725f49c5fSRichard Henderson if (set == 0) { 257825f49c5fSRichard Henderson set = tcg_target_available_regs[ts->type] & mask; 257925f49c5fSRichard Henderson } 258025f49c5fSRichard Henderson *pset = set; 258125f49c5fSRichard Henderson } 2582f65a061cSRichard Henderson } 2583f65a061cSRichard Henderson } 2584f65a061cSRichard Henderson 2585a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a 2586c896fe29Sbellard given input arguments is dead. Instructions updating dead 2587c896fe29Sbellard temporaries are removed. */ 2588b83eabeaSRichard Henderson static void liveness_pass_1(TCGContext *s) 2589c896fe29Sbellard { 2590c70fbf0aSRichard Henderson int nb_globals = s->nb_globals; 25912616c808SRichard Henderson int nb_temps = s->nb_temps; 259215fa08f8SRichard Henderson TCGOp *op, *op_prev; 259325f49c5fSRichard Henderson TCGRegSet *prefs; 259425f49c5fSRichard Henderson int i; 259525f49c5fSRichard Henderson 259625f49c5fSRichard Henderson prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps); 259725f49c5fSRichard Henderson for (i = 0; i < nb_temps; ++i) { 259825f49c5fSRichard Henderson s->temps[i].state_ptr = prefs + i; 259925f49c5fSRichard Henderson } 2600c896fe29Sbellard 2601ae36a246SRichard Henderson /* ??? Should be redundant with the exit_tb that ends the TB. */ 26022616c808SRichard Henderson la_func_end(s, nb_globals, nb_temps); 2603c896fe29Sbellard 2604eae3eb3eSPaolo Bonzini QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) { 260525f49c5fSRichard Henderson int nb_iargs, nb_oargs; 2606c45cb8bbSRichard Henderson TCGOpcode opc_new, opc_new2; 2607c45cb8bbSRichard Henderson bool have_opc_new2; 2608a1b3c48dSRichard Henderson TCGLifeData arg_life = 0; 260925f49c5fSRichard Henderson TCGTemp *ts; 2610c45cb8bbSRichard Henderson TCGOpcode opc = op->opc; 2611c45cb8bbSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 2612c45cb8bbSRichard Henderson 2613c45cb8bbSRichard Henderson switch (opc) { 2614c896fe29Sbellard case INDEX_op_call: 2615c6e113f5Sbellard { 2616c6e113f5Sbellard int call_flags; 261725f49c5fSRichard Henderson int nb_call_regs; 2618c6e113f5Sbellard 2619cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 2620cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 2621efee3746SRichard Henderson call_flags = op->args[nb_oargs + nb_iargs + 1]; 2622c6e113f5Sbellard 2623c45cb8bbSRichard Henderson /* pure functions can be removed if their result is unused */ 262478505279SAurelien Jarno if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) { 2625c6e113f5Sbellard for (i = 0; i < nb_oargs; i++) { 262625f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 262725f49c5fSRichard Henderson if (ts->state != TS_DEAD) { 2628c6e113f5Sbellard goto do_not_remove_call; 2629c6e113f5Sbellard } 26309c43b68dSAurelien Jarno } 2631c45cb8bbSRichard Henderson goto do_remove; 2632152c35aaSRichard Henderson } 2633c6e113f5Sbellard do_not_remove_call: 2634c896fe29Sbellard 263525f49c5fSRichard Henderson /* Output args are dead. */ 2636c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 263725f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 263825f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 2639a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 26406b64b624SAurelien Jarno } 264125f49c5fSRichard Henderson if (ts->state & TS_MEM) { 2642a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i; 26439c43b68dSAurelien Jarno } 264425f49c5fSRichard Henderson ts->state = TS_DEAD; 264525f49c5fSRichard Henderson la_reset_pref(ts); 264625f49c5fSRichard Henderson 264725f49c5fSRichard Henderson /* Not used -- it will be tcg_target_call_oarg_regs[i]. */ 264825f49c5fSRichard Henderson op->output_pref[i] = 0; 2649c896fe29Sbellard } 2650c896fe29Sbellard 265178505279SAurelien Jarno if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS | 265278505279SAurelien Jarno TCG_CALL_NO_READ_GLOBALS))) { 2653f65a061cSRichard Henderson la_global_kill(s, nb_globals); 2654c70fbf0aSRichard Henderson } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) { 2655f65a061cSRichard Henderson la_global_sync(s, nb_globals); 2656b9c18f56Saurel32 } 2657c896fe29Sbellard 265825f49c5fSRichard Henderson /* Record arguments that die in this helper. */ 2659866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 266025f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 266125f49c5fSRichard Henderson if (ts && ts->state & TS_DEAD) { 2662a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 2663c896fe29Sbellard } 2664c896fe29Sbellard } 266525f49c5fSRichard Henderson 266625f49c5fSRichard Henderson /* For all live registers, remove call-clobbered prefs. */ 266725f49c5fSRichard Henderson la_cross_call(s, nb_temps); 266825f49c5fSRichard Henderson 266925f49c5fSRichard Henderson nb_call_regs = ARRAY_SIZE(tcg_target_call_iarg_regs); 267025f49c5fSRichard Henderson 267125f49c5fSRichard Henderson /* Input arguments are live for preceding opcodes. */ 267225f49c5fSRichard Henderson for (i = 0; i < nb_iargs; i++) { 267325f49c5fSRichard Henderson ts = arg_temp(op->args[i + nb_oargs]); 267425f49c5fSRichard Henderson if (ts && ts->state & TS_DEAD) { 267525f49c5fSRichard Henderson /* For those arguments that die, and will be allocated 267625f49c5fSRichard Henderson * in registers, clear the register set for that arg, 267725f49c5fSRichard Henderson * to be filled in below. For args that will be on 267825f49c5fSRichard Henderson * the stack, reset to any available reg. 267925f49c5fSRichard Henderson */ 268025f49c5fSRichard Henderson *la_temp_pref(ts) 268125f49c5fSRichard Henderson = (i < nb_call_regs ? 0 : 268225f49c5fSRichard Henderson tcg_target_available_regs[ts->type]); 268325f49c5fSRichard Henderson ts->state &= ~TS_DEAD; 268425f49c5fSRichard Henderson } 268525f49c5fSRichard Henderson } 268625f49c5fSRichard Henderson 268725f49c5fSRichard Henderson /* For each input argument, add its input register to prefs. 268825f49c5fSRichard Henderson If a temp is used once, this produces a single set bit. */ 268925f49c5fSRichard Henderson for (i = 0; i < MIN(nb_call_regs, nb_iargs); i++) { 269025f49c5fSRichard Henderson ts = arg_temp(op->args[i + nb_oargs]); 269125f49c5fSRichard Henderson if (ts) { 269225f49c5fSRichard Henderson tcg_regset_set_reg(*la_temp_pref(ts), 269325f49c5fSRichard Henderson tcg_target_call_iarg_regs[i]); 2694c70fbf0aSRichard Henderson } 2695c19f47bfSAurelien Jarno } 2696c6e113f5Sbellard } 2697c896fe29Sbellard break; 2698765b842aSRichard Henderson case INDEX_op_insn_start: 2699c896fe29Sbellard break; 27005ff9d6a4Sbellard case INDEX_op_discard: 27015ff9d6a4Sbellard /* mark the temporary as dead */ 270225f49c5fSRichard Henderson ts = arg_temp(op->args[0]); 270325f49c5fSRichard Henderson ts->state = TS_DEAD; 270425f49c5fSRichard Henderson la_reset_pref(ts); 27055ff9d6a4Sbellard break; 27061305c451SRichard Henderson 27071305c451SRichard Henderson case INDEX_op_add2_i32: 2708c45cb8bbSRichard Henderson opc_new = INDEX_op_add_i32; 2709f1fae40cSRichard Henderson goto do_addsub2; 27101305c451SRichard Henderson case INDEX_op_sub2_i32: 2711c45cb8bbSRichard Henderson opc_new = INDEX_op_sub_i32; 2712f1fae40cSRichard Henderson goto do_addsub2; 2713f1fae40cSRichard Henderson case INDEX_op_add2_i64: 2714c45cb8bbSRichard Henderson opc_new = INDEX_op_add_i64; 2715f1fae40cSRichard Henderson goto do_addsub2; 2716f1fae40cSRichard Henderson case INDEX_op_sub2_i64: 2717c45cb8bbSRichard Henderson opc_new = INDEX_op_sub_i64; 2718f1fae40cSRichard Henderson do_addsub2: 27191305c451SRichard Henderson nb_iargs = 4; 27201305c451SRichard Henderson nb_oargs = 2; 27211305c451SRichard Henderson /* Test if the high part of the operation is dead, but not 27221305c451SRichard Henderson the low part. The result can be optimized to a simple 27231305c451SRichard Henderson add or sub. This happens often for x86_64 guest when the 27241305c451SRichard Henderson cpu mode is set to 32 bit. */ 2725b83eabeaSRichard Henderson if (arg_temp(op->args[1])->state == TS_DEAD) { 2726b83eabeaSRichard Henderson if (arg_temp(op->args[0])->state == TS_DEAD) { 27271305c451SRichard Henderson goto do_remove; 27281305c451SRichard Henderson } 2729c45cb8bbSRichard Henderson /* Replace the opcode and adjust the args in place, 2730c45cb8bbSRichard Henderson leaving 3 unused args at the end. */ 2731c45cb8bbSRichard Henderson op->opc = opc = opc_new; 2732efee3746SRichard Henderson op->args[1] = op->args[2]; 2733efee3746SRichard Henderson op->args[2] = op->args[4]; 27341305c451SRichard Henderson /* Fall through and mark the single-word operation live. */ 27351305c451SRichard Henderson nb_iargs = 2; 27361305c451SRichard Henderson nb_oargs = 1; 27371305c451SRichard Henderson } 27381305c451SRichard Henderson goto do_not_remove; 27391305c451SRichard Henderson 27401414968aSRichard Henderson case INDEX_op_mulu2_i32: 2741c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i32; 2742c45cb8bbSRichard Henderson opc_new2 = INDEX_op_muluh_i32; 2743c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_muluh_i32; 274403271524SRichard Henderson goto do_mul2; 2745f1fae40cSRichard Henderson case INDEX_op_muls2_i32: 2746c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i32; 2747c45cb8bbSRichard Henderson opc_new2 = INDEX_op_mulsh_i32; 2748c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_mulsh_i32; 2749f1fae40cSRichard Henderson goto do_mul2; 2750f1fae40cSRichard Henderson case INDEX_op_mulu2_i64: 2751c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i64; 2752c45cb8bbSRichard Henderson opc_new2 = INDEX_op_muluh_i64; 2753c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_muluh_i64; 275403271524SRichard Henderson goto do_mul2; 2755f1fae40cSRichard Henderson case INDEX_op_muls2_i64: 2756c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i64; 2757c45cb8bbSRichard Henderson opc_new2 = INDEX_op_mulsh_i64; 2758c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_mulsh_i64; 275903271524SRichard Henderson goto do_mul2; 2760f1fae40cSRichard Henderson do_mul2: 27611414968aSRichard Henderson nb_iargs = 2; 27621414968aSRichard Henderson nb_oargs = 2; 2763b83eabeaSRichard Henderson if (arg_temp(op->args[1])->state == TS_DEAD) { 2764b83eabeaSRichard Henderson if (arg_temp(op->args[0])->state == TS_DEAD) { 276503271524SRichard Henderson /* Both parts of the operation are dead. */ 27661414968aSRichard Henderson goto do_remove; 27671414968aSRichard Henderson } 276803271524SRichard Henderson /* The high part of the operation is dead; generate the low. */ 2769c45cb8bbSRichard Henderson op->opc = opc = opc_new; 2770efee3746SRichard Henderson op->args[1] = op->args[2]; 2771efee3746SRichard Henderson op->args[2] = op->args[3]; 2772b83eabeaSRichard Henderson } else if (arg_temp(op->args[0])->state == TS_DEAD && have_opc_new2) { 277303271524SRichard Henderson /* The low part of the operation is dead; generate the high. */ 2774c45cb8bbSRichard Henderson op->opc = opc = opc_new2; 2775efee3746SRichard Henderson op->args[0] = op->args[1]; 2776efee3746SRichard Henderson op->args[1] = op->args[2]; 2777efee3746SRichard Henderson op->args[2] = op->args[3]; 277803271524SRichard Henderson } else { 277903271524SRichard Henderson goto do_not_remove; 278003271524SRichard Henderson } 278103271524SRichard Henderson /* Mark the single-word operation live. */ 27821414968aSRichard Henderson nb_oargs = 1; 27831414968aSRichard Henderson goto do_not_remove; 27841414968aSRichard Henderson 2785c896fe29Sbellard default: 27861305c451SRichard Henderson /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */ 2787c896fe29Sbellard nb_iargs = def->nb_iargs; 2788c896fe29Sbellard nb_oargs = def->nb_oargs; 2789c896fe29Sbellard 2790c896fe29Sbellard /* Test if the operation can be removed because all 27915ff9d6a4Sbellard its outputs are dead. We assume that nb_oargs == 0 27925ff9d6a4Sbellard implies side effects */ 27935ff9d6a4Sbellard if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) { 2794c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 2795b83eabeaSRichard Henderson if (arg_temp(op->args[i])->state != TS_DEAD) { 2796c896fe29Sbellard goto do_not_remove; 2797c896fe29Sbellard } 27989c43b68dSAurelien Jarno } 2799152c35aaSRichard Henderson goto do_remove; 2800152c35aaSRichard Henderson } 2801152c35aaSRichard Henderson goto do_not_remove; 2802152c35aaSRichard Henderson 28031305c451SRichard Henderson do_remove: 28040c627cdcSRichard Henderson tcg_op_remove(s, op); 2805152c35aaSRichard Henderson break; 2806152c35aaSRichard Henderson 2807c896fe29Sbellard do_not_remove: 2808c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 280925f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 281025f49c5fSRichard Henderson 281125f49c5fSRichard Henderson /* Remember the preference of the uses that followed. */ 281225f49c5fSRichard Henderson op->output_pref[i] = *la_temp_pref(ts); 281325f49c5fSRichard Henderson 281425f49c5fSRichard Henderson /* Output args are dead. */ 281525f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 2816a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 28176b64b624SAurelien Jarno } 281825f49c5fSRichard Henderson if (ts->state & TS_MEM) { 2819a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i; 28209c43b68dSAurelien Jarno } 282125f49c5fSRichard Henderson ts->state = TS_DEAD; 282225f49c5fSRichard Henderson la_reset_pref(ts); 2823c896fe29Sbellard } 2824c896fe29Sbellard 282525f49c5fSRichard Henderson /* If end of basic block, update. */ 2826ae36a246SRichard Henderson if (def->flags & TCG_OPF_BB_EXIT) { 2827ae36a246SRichard Henderson la_func_end(s, nb_globals, nb_temps); 2828b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_COND_BRANCH) { 2829b4cb76e6SRichard Henderson la_bb_sync(s, nb_globals, nb_temps); 2830ae36a246SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 28312616c808SRichard Henderson la_bb_end(s, nb_globals, nb_temps); 28323d5c5f87SAurelien Jarno } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { 2833f65a061cSRichard Henderson la_global_sync(s, nb_globals); 283425f49c5fSRichard Henderson if (def->flags & TCG_OPF_CALL_CLOBBER) { 283525f49c5fSRichard Henderson la_cross_call(s, nb_temps); 283625f49c5fSRichard Henderson } 2837c896fe29Sbellard } 2838c896fe29Sbellard 283925f49c5fSRichard Henderson /* Record arguments that die in this opcode. */ 2840866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 284125f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 284225f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 2843a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 2844c896fe29Sbellard } 2845c19f47bfSAurelien Jarno } 284625f49c5fSRichard Henderson 284725f49c5fSRichard Henderson /* Input arguments are live for preceding opcodes. */ 2848c19f47bfSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 284925f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 285025f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 285125f49c5fSRichard Henderson /* For operands that were dead, initially allow 285225f49c5fSRichard Henderson all regs for the type. */ 285325f49c5fSRichard Henderson *la_temp_pref(ts) = tcg_target_available_regs[ts->type]; 285425f49c5fSRichard Henderson ts->state &= ~TS_DEAD; 285525f49c5fSRichard Henderson } 285625f49c5fSRichard Henderson } 285725f49c5fSRichard Henderson 285825f49c5fSRichard Henderson /* Incorporate constraints for this operand. */ 285925f49c5fSRichard Henderson switch (opc) { 286025f49c5fSRichard Henderson case INDEX_op_mov_i32: 286125f49c5fSRichard Henderson case INDEX_op_mov_i64: 286225f49c5fSRichard Henderson /* Note that these are TCG_OPF_NOT_PRESENT and do not 286325f49c5fSRichard Henderson have proper constraints. That said, special case 286425f49c5fSRichard Henderson moves to propagate preferences backward. */ 286525f49c5fSRichard Henderson if (IS_DEAD_ARG(1)) { 286625f49c5fSRichard Henderson *la_temp_pref(arg_temp(op->args[0])) 286725f49c5fSRichard Henderson = *la_temp_pref(arg_temp(op->args[1])); 286825f49c5fSRichard Henderson } 286925f49c5fSRichard Henderson break; 287025f49c5fSRichard Henderson 287125f49c5fSRichard Henderson default: 287225f49c5fSRichard Henderson for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 287325f49c5fSRichard Henderson const TCGArgConstraint *ct = &def->args_ct[i]; 287425f49c5fSRichard Henderson TCGRegSet set, *pset; 287525f49c5fSRichard Henderson 287625f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 287725f49c5fSRichard Henderson pset = la_temp_pref(ts); 287825f49c5fSRichard Henderson set = *pset; 287925f49c5fSRichard Henderson 28809be0d080SRichard Henderson set &= ct->regs; 2881bc2b17e6SRichard Henderson if (ct->ialias) { 288225f49c5fSRichard Henderson set &= op->output_pref[ct->alias_index]; 288325f49c5fSRichard Henderson } 288425f49c5fSRichard Henderson /* If the combination is not possible, restart. */ 288525f49c5fSRichard Henderson if (set == 0) { 28869be0d080SRichard Henderson set = ct->regs; 288725f49c5fSRichard Henderson } 288825f49c5fSRichard Henderson *pset = set; 288925f49c5fSRichard Henderson } 289025f49c5fSRichard Henderson break; 2891c896fe29Sbellard } 2892c896fe29Sbellard break; 2893c896fe29Sbellard } 2894bee158cbSRichard Henderson op->life = arg_life; 2895c896fe29Sbellard } 28961ff0a2c5SEvgeny Voevodin } 2897c896fe29Sbellard 28985a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries. */ 2899b83eabeaSRichard Henderson static bool liveness_pass_2(TCGContext *s) 29005a18407fSRichard Henderson { 29015a18407fSRichard Henderson int nb_globals = s->nb_globals; 290215fa08f8SRichard Henderson int nb_temps, i; 29035a18407fSRichard Henderson bool changes = false; 290415fa08f8SRichard Henderson TCGOp *op, *op_next; 29055a18407fSRichard Henderson 29065a18407fSRichard Henderson /* Create a temporary for each indirect global. */ 29075a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 29085a18407fSRichard Henderson TCGTemp *its = &s->temps[i]; 29095a18407fSRichard Henderson if (its->indirect_reg) { 29105a18407fSRichard Henderson TCGTemp *dts = tcg_temp_alloc(s); 29115a18407fSRichard Henderson dts->type = its->type; 29125a18407fSRichard Henderson dts->base_type = its->base_type; 2913b83eabeaSRichard Henderson its->state_ptr = dts; 2914b83eabeaSRichard Henderson } else { 2915b83eabeaSRichard Henderson its->state_ptr = NULL; 29165a18407fSRichard Henderson } 2917b83eabeaSRichard Henderson /* All globals begin dead. */ 2918b83eabeaSRichard Henderson its->state = TS_DEAD; 29195a18407fSRichard Henderson } 2920b83eabeaSRichard Henderson for (nb_temps = s->nb_temps; i < nb_temps; ++i) { 2921b83eabeaSRichard Henderson TCGTemp *its = &s->temps[i]; 2922b83eabeaSRichard Henderson its->state_ptr = NULL; 2923b83eabeaSRichard Henderson its->state = TS_DEAD; 2924b83eabeaSRichard Henderson } 29255a18407fSRichard Henderson 292615fa08f8SRichard Henderson QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) { 29275a18407fSRichard Henderson TCGOpcode opc = op->opc; 29285a18407fSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 29295a18407fSRichard Henderson TCGLifeData arg_life = op->life; 29305a18407fSRichard Henderson int nb_iargs, nb_oargs, call_flags; 2931b83eabeaSRichard Henderson TCGTemp *arg_ts, *dir_ts; 29325a18407fSRichard Henderson 29335a18407fSRichard Henderson if (opc == INDEX_op_call) { 2934cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 2935cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 2936efee3746SRichard Henderson call_flags = op->args[nb_oargs + nb_iargs + 1]; 29375a18407fSRichard Henderson } else { 29385a18407fSRichard Henderson nb_iargs = def->nb_iargs; 29395a18407fSRichard Henderson nb_oargs = def->nb_oargs; 29405a18407fSRichard Henderson 29415a18407fSRichard Henderson /* Set flags similar to how calls require. */ 2942b4cb76e6SRichard Henderson if (def->flags & TCG_OPF_COND_BRANCH) { 2943b4cb76e6SRichard Henderson /* Like reading globals: sync_globals */ 2944b4cb76e6SRichard Henderson call_flags = TCG_CALL_NO_WRITE_GLOBALS; 2945b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 29465a18407fSRichard Henderson /* Like writing globals: save_globals */ 29475a18407fSRichard Henderson call_flags = 0; 29485a18407fSRichard Henderson } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { 29495a18407fSRichard Henderson /* Like reading globals: sync_globals */ 29505a18407fSRichard Henderson call_flags = TCG_CALL_NO_WRITE_GLOBALS; 29515a18407fSRichard Henderson } else { 29525a18407fSRichard Henderson /* No effect on globals. */ 29535a18407fSRichard Henderson call_flags = (TCG_CALL_NO_READ_GLOBALS | 29545a18407fSRichard Henderson TCG_CALL_NO_WRITE_GLOBALS); 29555a18407fSRichard Henderson } 29565a18407fSRichard Henderson } 29575a18407fSRichard Henderson 29585a18407fSRichard Henderson /* Make sure that input arguments are available. */ 29595a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 2960b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 2961b83eabeaSRichard Henderson if (arg_ts) { 2962b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 2963b83eabeaSRichard Henderson if (dir_ts && arg_ts->state == TS_DEAD) { 2964b83eabeaSRichard Henderson TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32 29655a18407fSRichard Henderson ? INDEX_op_ld_i32 29665a18407fSRichard Henderson : INDEX_op_ld_i64); 2967ac1043f6SEmilio G. Cota TCGOp *lop = tcg_op_insert_before(s, op, lopc); 29685a18407fSRichard Henderson 2969b83eabeaSRichard Henderson lop->args[0] = temp_arg(dir_ts); 2970b83eabeaSRichard Henderson lop->args[1] = temp_arg(arg_ts->mem_base); 2971b83eabeaSRichard Henderson lop->args[2] = arg_ts->mem_offset; 29725a18407fSRichard Henderson 29735a18407fSRichard Henderson /* Loaded, but synced with memory. */ 2974b83eabeaSRichard Henderson arg_ts->state = TS_MEM; 29755a18407fSRichard Henderson } 29765a18407fSRichard Henderson } 29775a18407fSRichard Henderson } 29785a18407fSRichard Henderson 29795a18407fSRichard Henderson /* Perform input replacement, and mark inputs that became dead. 29805a18407fSRichard Henderson No action is required except keeping temp_state up to date 29815a18407fSRichard Henderson so that we reload when needed. */ 29825a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 2983b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 2984b83eabeaSRichard Henderson if (arg_ts) { 2985b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 2986b83eabeaSRichard Henderson if (dir_ts) { 2987b83eabeaSRichard Henderson op->args[i] = temp_arg(dir_ts); 29885a18407fSRichard Henderson changes = true; 29895a18407fSRichard Henderson if (IS_DEAD_ARG(i)) { 2990b83eabeaSRichard Henderson arg_ts->state = TS_DEAD; 29915a18407fSRichard Henderson } 29925a18407fSRichard Henderson } 29935a18407fSRichard Henderson } 29945a18407fSRichard Henderson } 29955a18407fSRichard Henderson 29965a18407fSRichard Henderson /* Liveness analysis should ensure that the following are 29975a18407fSRichard Henderson all correct, for call sites and basic block end points. */ 29985a18407fSRichard Henderson if (call_flags & TCG_CALL_NO_READ_GLOBALS) { 29995a18407fSRichard Henderson /* Nothing to do */ 30005a18407fSRichard Henderson } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) { 30015a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 30025a18407fSRichard Henderson /* Liveness should see that globals are synced back, 30035a18407fSRichard Henderson that is, either TS_DEAD or TS_MEM. */ 3004b83eabeaSRichard Henderson arg_ts = &s->temps[i]; 3005b83eabeaSRichard Henderson tcg_debug_assert(arg_ts->state_ptr == 0 3006b83eabeaSRichard Henderson || arg_ts->state != 0); 30075a18407fSRichard Henderson } 30085a18407fSRichard Henderson } else { 30095a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 30105a18407fSRichard Henderson /* Liveness should see that globals are saved back, 30115a18407fSRichard Henderson that is, TS_DEAD, waiting to be reloaded. */ 3012b83eabeaSRichard Henderson arg_ts = &s->temps[i]; 3013b83eabeaSRichard Henderson tcg_debug_assert(arg_ts->state_ptr == 0 3014b83eabeaSRichard Henderson || arg_ts->state == TS_DEAD); 30155a18407fSRichard Henderson } 30165a18407fSRichard Henderson } 30175a18407fSRichard Henderson 30185a18407fSRichard Henderson /* Outputs become available. */ 301961f15c48SRichard Henderson if (opc == INDEX_op_mov_i32 || opc == INDEX_op_mov_i64) { 302061f15c48SRichard Henderson arg_ts = arg_temp(op->args[0]); 302161f15c48SRichard Henderson dir_ts = arg_ts->state_ptr; 302261f15c48SRichard Henderson if (dir_ts) { 302361f15c48SRichard Henderson op->args[0] = temp_arg(dir_ts); 302461f15c48SRichard Henderson changes = true; 302561f15c48SRichard Henderson 302661f15c48SRichard Henderson /* The output is now live and modified. */ 302761f15c48SRichard Henderson arg_ts->state = 0; 302861f15c48SRichard Henderson 302961f15c48SRichard Henderson if (NEED_SYNC_ARG(0)) { 303061f15c48SRichard Henderson TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 303161f15c48SRichard Henderson ? INDEX_op_st_i32 303261f15c48SRichard Henderson : INDEX_op_st_i64); 303361f15c48SRichard Henderson TCGOp *sop = tcg_op_insert_after(s, op, sopc); 303461f15c48SRichard Henderson TCGTemp *out_ts = dir_ts; 303561f15c48SRichard Henderson 303661f15c48SRichard Henderson if (IS_DEAD_ARG(0)) { 303761f15c48SRichard Henderson out_ts = arg_temp(op->args[1]); 303861f15c48SRichard Henderson arg_ts->state = TS_DEAD; 303961f15c48SRichard Henderson tcg_op_remove(s, op); 304061f15c48SRichard Henderson } else { 304161f15c48SRichard Henderson arg_ts->state = TS_MEM; 304261f15c48SRichard Henderson } 304361f15c48SRichard Henderson 304461f15c48SRichard Henderson sop->args[0] = temp_arg(out_ts); 304561f15c48SRichard Henderson sop->args[1] = temp_arg(arg_ts->mem_base); 304661f15c48SRichard Henderson sop->args[2] = arg_ts->mem_offset; 304761f15c48SRichard Henderson } else { 304861f15c48SRichard Henderson tcg_debug_assert(!IS_DEAD_ARG(0)); 304961f15c48SRichard Henderson } 305061f15c48SRichard Henderson } 305161f15c48SRichard Henderson } else { 30525a18407fSRichard Henderson for (i = 0; i < nb_oargs; i++) { 3053b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 3054b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 3055b83eabeaSRichard Henderson if (!dir_ts) { 30565a18407fSRichard Henderson continue; 30575a18407fSRichard Henderson } 3058b83eabeaSRichard Henderson op->args[i] = temp_arg(dir_ts); 30595a18407fSRichard Henderson changes = true; 30605a18407fSRichard Henderson 30615a18407fSRichard Henderson /* The output is now live and modified. */ 3062b83eabeaSRichard Henderson arg_ts->state = 0; 30635a18407fSRichard Henderson 30645a18407fSRichard Henderson /* Sync outputs upon their last write. */ 30655a18407fSRichard Henderson if (NEED_SYNC_ARG(i)) { 3066b83eabeaSRichard Henderson TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 30675a18407fSRichard Henderson ? INDEX_op_st_i32 30685a18407fSRichard Henderson : INDEX_op_st_i64); 3069ac1043f6SEmilio G. Cota TCGOp *sop = tcg_op_insert_after(s, op, sopc); 30705a18407fSRichard Henderson 3071b83eabeaSRichard Henderson sop->args[0] = temp_arg(dir_ts); 3072b83eabeaSRichard Henderson sop->args[1] = temp_arg(arg_ts->mem_base); 3073b83eabeaSRichard Henderson sop->args[2] = arg_ts->mem_offset; 30745a18407fSRichard Henderson 3075b83eabeaSRichard Henderson arg_ts->state = TS_MEM; 30765a18407fSRichard Henderson } 30775a18407fSRichard Henderson /* Drop outputs that are dead. */ 30785a18407fSRichard Henderson if (IS_DEAD_ARG(i)) { 3079b83eabeaSRichard Henderson arg_ts->state = TS_DEAD; 30805a18407fSRichard Henderson } 30815a18407fSRichard Henderson } 30825a18407fSRichard Henderson } 308361f15c48SRichard Henderson } 30845a18407fSRichard Henderson 30855a18407fSRichard Henderson return changes; 30865a18407fSRichard Henderson } 30875a18407fSRichard Henderson 30888d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG 3089c896fe29Sbellard static void dump_regs(TCGContext *s) 3090c896fe29Sbellard { 3091c896fe29Sbellard TCGTemp *ts; 3092c896fe29Sbellard int i; 3093c896fe29Sbellard char buf[64]; 3094c896fe29Sbellard 3095c896fe29Sbellard for(i = 0; i < s->nb_temps; i++) { 3096c896fe29Sbellard ts = &s->temps[i]; 309743439139SRichard Henderson printf(" %10s: ", tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts)); 3098c896fe29Sbellard switch(ts->val_type) { 3099c896fe29Sbellard case TEMP_VAL_REG: 3100c896fe29Sbellard printf("%s", tcg_target_reg_names[ts->reg]); 3101c896fe29Sbellard break; 3102c896fe29Sbellard case TEMP_VAL_MEM: 3103b3a62939SRichard Henderson printf("%d(%s)", (int)ts->mem_offset, 3104b3a62939SRichard Henderson tcg_target_reg_names[ts->mem_base->reg]); 3105c896fe29Sbellard break; 3106c896fe29Sbellard case TEMP_VAL_CONST: 3107c896fe29Sbellard printf("$0x%" TCG_PRIlx, ts->val); 3108c896fe29Sbellard break; 3109c896fe29Sbellard case TEMP_VAL_DEAD: 3110c896fe29Sbellard printf("D"); 3111c896fe29Sbellard break; 3112c896fe29Sbellard default: 3113c896fe29Sbellard printf("???"); 3114c896fe29Sbellard break; 3115c896fe29Sbellard } 3116c896fe29Sbellard printf("\n"); 3117c896fe29Sbellard } 3118c896fe29Sbellard 3119c896fe29Sbellard for(i = 0; i < TCG_TARGET_NB_REGS; i++) { 3120f8b2f202SRichard Henderson if (s->reg_to_temp[i] != NULL) { 3121c896fe29Sbellard printf("%s: %s\n", 3122c896fe29Sbellard tcg_target_reg_names[i], 3123f8b2f202SRichard Henderson tcg_get_arg_str_ptr(s, buf, sizeof(buf), s->reg_to_temp[i])); 3124c896fe29Sbellard } 3125c896fe29Sbellard } 3126c896fe29Sbellard } 3127c896fe29Sbellard 3128c896fe29Sbellard static void check_regs(TCGContext *s) 3129c896fe29Sbellard { 3130869938aeSRichard Henderson int reg; 3131b6638662SRichard Henderson int k; 3132c896fe29Sbellard TCGTemp *ts; 3133c896fe29Sbellard char buf[64]; 3134c896fe29Sbellard 3135c896fe29Sbellard for (reg = 0; reg < TCG_TARGET_NB_REGS; reg++) { 3136f8b2f202SRichard Henderson ts = s->reg_to_temp[reg]; 3137f8b2f202SRichard Henderson if (ts != NULL) { 3138f8b2f202SRichard Henderson if (ts->val_type != TEMP_VAL_REG || ts->reg != reg) { 3139c896fe29Sbellard printf("Inconsistency for register %s:\n", 3140c896fe29Sbellard tcg_target_reg_names[reg]); 3141b03cce8eSbellard goto fail; 3142c896fe29Sbellard } 3143c896fe29Sbellard } 3144c896fe29Sbellard } 3145c896fe29Sbellard for (k = 0; k < s->nb_temps; k++) { 3146c896fe29Sbellard ts = &s->temps[k]; 3147f8b2f202SRichard Henderson if (ts->val_type == TEMP_VAL_REG && !ts->fixed_reg 3148f8b2f202SRichard Henderson && s->reg_to_temp[ts->reg] != ts) { 3149c896fe29Sbellard printf("Inconsistency for temp %s:\n", 3150f8b2f202SRichard Henderson tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts)); 3151b03cce8eSbellard fail: 3152c896fe29Sbellard printf("reg state:\n"); 3153c896fe29Sbellard dump_regs(s); 3154c896fe29Sbellard tcg_abort(); 3155c896fe29Sbellard } 3156c896fe29Sbellard } 3157c896fe29Sbellard } 3158c896fe29Sbellard #endif 3159c896fe29Sbellard 31602272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts) 3161c896fe29Sbellard { 31629b9c37c3SRichard Henderson #if !(defined(__sparc__) && TCG_TARGET_REG_BITS == 64) 31639b9c37c3SRichard Henderson /* Sparc64 stack is accessed with offset of 2047 */ 3164b591dc59SBlue Swirl s->current_frame_offset = (s->current_frame_offset + 3165b591dc59SBlue Swirl (tcg_target_long)sizeof(tcg_target_long) - 1) & 3166b591dc59SBlue Swirl ~(sizeof(tcg_target_long) - 1); 3167f44c9960SBlue Swirl #endif 3168b591dc59SBlue Swirl if (s->current_frame_offset + (tcg_target_long)sizeof(tcg_target_long) > 3169b591dc59SBlue Swirl s->frame_end) { 31705ff9d6a4Sbellard tcg_abort(); 3171b591dc59SBlue Swirl } 3172c896fe29Sbellard ts->mem_offset = s->current_frame_offset; 3173b3a62939SRichard Henderson ts->mem_base = s->frame_temp; 3174c896fe29Sbellard ts->mem_allocated = 1; 3175e2c6d1b4SRichard Henderson s->current_frame_offset += sizeof(tcg_target_long); 3176c896fe29Sbellard } 3177c896fe29Sbellard 3178b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet); 3179b3915dbbSRichard Henderson 318059d7c14eSRichard Henderson /* Mark a temporary as free or dead. If 'free_or_dead' is negative, 318159d7c14eSRichard Henderson mark it free; otherwise mark it dead. */ 318259d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead) 3183c896fe29Sbellard { 318459d7c14eSRichard Henderson if (ts->fixed_reg) { 318559d7c14eSRichard Henderson return; 318659d7c14eSRichard Henderson } 318759d7c14eSRichard Henderson if (ts->val_type == TEMP_VAL_REG) { 318859d7c14eSRichard Henderson s->reg_to_temp[ts->reg] = NULL; 318959d7c14eSRichard Henderson } 319059d7c14eSRichard Henderson ts->val_type = (free_or_dead < 0 319159d7c14eSRichard Henderson || ts->temp_local 3192fa477d25SRichard Henderson || ts->temp_global 319359d7c14eSRichard Henderson ? TEMP_VAL_MEM : TEMP_VAL_DEAD); 319459d7c14eSRichard Henderson } 3195c896fe29Sbellard 319659d7c14eSRichard Henderson /* Mark a temporary as dead. */ 319759d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts) 319859d7c14eSRichard Henderson { 319959d7c14eSRichard Henderson temp_free_or_dead(s, ts, 1); 320059d7c14eSRichard Henderson } 320159d7c14eSRichard Henderson 320259d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary 320359d7c14eSRichard Henderson registers needs to be allocated to store a constant. If 'free_or_dead' 320459d7c14eSRichard Henderson is non-zero, subsequently release the temporary; if it is positive, the 320559d7c14eSRichard Henderson temp is dead; if it is negative, the temp is free. */ 320698b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs, 320798b4e186SRichard Henderson TCGRegSet preferred_regs, int free_or_dead) 320859d7c14eSRichard Henderson { 320959d7c14eSRichard Henderson if (ts->fixed_reg) { 321059d7c14eSRichard Henderson return; 321159d7c14eSRichard Henderson } 321259d7c14eSRichard Henderson if (!ts->mem_coherent) { 32137f6ceedfSAurelien Jarno if (!ts->mem_allocated) { 32142272e4a7SRichard Henderson temp_allocate_frame(s, ts); 321559d7c14eSRichard Henderson } 321659d7c14eSRichard Henderson switch (ts->val_type) { 321759d7c14eSRichard Henderson case TEMP_VAL_CONST: 321859d7c14eSRichard Henderson /* If we're going to free the temp immediately, then we won't 321959d7c14eSRichard Henderson require it later in a register, so attempt to store the 322059d7c14eSRichard Henderson constant to memory directly. */ 322159d7c14eSRichard Henderson if (free_or_dead 322259d7c14eSRichard Henderson && tcg_out_sti(s, ts->type, ts->val, 322359d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset)) { 322459d7c14eSRichard Henderson break; 322559d7c14eSRichard Henderson } 322659d7c14eSRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 322798b4e186SRichard Henderson allocated_regs, preferred_regs); 322859d7c14eSRichard Henderson /* fallthrough */ 322959d7c14eSRichard Henderson 323059d7c14eSRichard Henderson case TEMP_VAL_REG: 323159d7c14eSRichard Henderson tcg_out_st(s, ts->type, ts->reg, 323259d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset); 323359d7c14eSRichard Henderson break; 323459d7c14eSRichard Henderson 323559d7c14eSRichard Henderson case TEMP_VAL_MEM: 323659d7c14eSRichard Henderson break; 323759d7c14eSRichard Henderson 323859d7c14eSRichard Henderson case TEMP_VAL_DEAD: 323959d7c14eSRichard Henderson default: 324059d7c14eSRichard Henderson tcg_abort(); 3241c896fe29Sbellard } 32427f6ceedfSAurelien Jarno ts->mem_coherent = 1; 32437f6ceedfSAurelien Jarno } 324459d7c14eSRichard Henderson if (free_or_dead) { 324559d7c14eSRichard Henderson temp_free_or_dead(s, ts, free_or_dead); 324659d7c14eSRichard Henderson } 324759d7c14eSRichard Henderson } 32487f6ceedfSAurelien Jarno 32497f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */ 3250b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs) 32517f6ceedfSAurelien Jarno { 3252f8b2f202SRichard Henderson TCGTemp *ts = s->reg_to_temp[reg]; 3253f8b2f202SRichard Henderson if (ts != NULL) { 325498b4e186SRichard Henderson temp_sync(s, ts, allocated_regs, 0, -1); 3255c896fe29Sbellard } 3256c896fe29Sbellard } 3257c896fe29Sbellard 3258b016486eSRichard Henderson /** 3259b016486eSRichard Henderson * tcg_reg_alloc: 3260b016486eSRichard Henderson * @required_regs: Set of registers in which we must allocate. 3261b016486eSRichard Henderson * @allocated_regs: Set of registers which must be avoided. 3262b016486eSRichard Henderson * @preferred_regs: Set of registers we should prefer. 3263b016486eSRichard Henderson * @rev: True if we search the registers in "indirect" order. 3264b016486eSRichard Henderson * 3265b016486eSRichard Henderson * The allocated register must be in @required_regs & ~@allocated_regs, 3266b016486eSRichard Henderson * but if we can put it in @preferred_regs we may save a move later. 3267b016486eSRichard Henderson */ 3268b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs, 3269b016486eSRichard Henderson TCGRegSet allocated_regs, 3270b016486eSRichard Henderson TCGRegSet preferred_regs, bool rev) 3271c896fe29Sbellard { 3272b016486eSRichard Henderson int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order); 3273b016486eSRichard Henderson TCGRegSet reg_ct[2]; 327491478cefSRichard Henderson const int *order; 3275c896fe29Sbellard 3276b016486eSRichard Henderson reg_ct[1] = required_regs & ~allocated_regs; 3277b016486eSRichard Henderson tcg_debug_assert(reg_ct[1] != 0); 3278b016486eSRichard Henderson reg_ct[0] = reg_ct[1] & preferred_regs; 3279b016486eSRichard Henderson 3280b016486eSRichard Henderson /* Skip the preferred_regs option if it cannot be satisfied, 3281b016486eSRichard Henderson or if the preference made no difference. */ 3282b016486eSRichard Henderson f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1]; 3283b016486eSRichard Henderson 328491478cefSRichard Henderson order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order; 3285c896fe29Sbellard 3286b016486eSRichard Henderson /* Try free registers, preferences first. */ 3287b016486eSRichard Henderson for (j = f; j < 2; j++) { 3288b016486eSRichard Henderson TCGRegSet set = reg_ct[j]; 3289b016486eSRichard Henderson 3290b016486eSRichard Henderson if (tcg_regset_single(set)) { 3291b016486eSRichard Henderson /* One register in the set. */ 3292b016486eSRichard Henderson TCGReg reg = tcg_regset_first(set); 3293b016486eSRichard Henderson if (s->reg_to_temp[reg] == NULL) { 3294c896fe29Sbellard return reg; 3295c896fe29Sbellard } 3296b016486eSRichard Henderson } else { 329791478cefSRichard Henderson for (i = 0; i < n; i++) { 3298b016486eSRichard Henderson TCGReg reg = order[i]; 3299b016486eSRichard Henderson if (s->reg_to_temp[reg] == NULL && 3300b016486eSRichard Henderson tcg_regset_test_reg(set, reg)) { 3301b016486eSRichard Henderson return reg; 3302b016486eSRichard Henderson } 3303b016486eSRichard Henderson } 3304b016486eSRichard Henderson } 3305b016486eSRichard Henderson } 3306b016486eSRichard Henderson 3307b016486eSRichard Henderson /* We must spill something. */ 3308b016486eSRichard Henderson for (j = f; j < 2; j++) { 3309b016486eSRichard Henderson TCGRegSet set = reg_ct[j]; 3310b016486eSRichard Henderson 3311b016486eSRichard Henderson if (tcg_regset_single(set)) { 3312b016486eSRichard Henderson /* One register in the set. */ 3313b016486eSRichard Henderson TCGReg reg = tcg_regset_first(set); 3314b3915dbbSRichard Henderson tcg_reg_free(s, reg, allocated_regs); 3315c896fe29Sbellard return reg; 3316b016486eSRichard Henderson } else { 3317b016486eSRichard Henderson for (i = 0; i < n; i++) { 3318b016486eSRichard Henderson TCGReg reg = order[i]; 3319b016486eSRichard Henderson if (tcg_regset_test_reg(set, reg)) { 3320b016486eSRichard Henderson tcg_reg_free(s, reg, allocated_regs); 3321b016486eSRichard Henderson return reg; 3322b016486eSRichard Henderson } 3323b016486eSRichard Henderson } 3324c896fe29Sbellard } 3325c896fe29Sbellard } 3326c896fe29Sbellard 3327c896fe29Sbellard tcg_abort(); 3328c896fe29Sbellard } 3329c896fe29Sbellard 333040ae5c62SRichard Henderson /* Make sure the temporary is in a register. If needed, allocate the register 333140ae5c62SRichard Henderson from DESIRED while avoiding ALLOCATED. */ 333240ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs, 3333b722452aSRichard Henderson TCGRegSet allocated_regs, TCGRegSet preferred_regs) 333440ae5c62SRichard Henderson { 333540ae5c62SRichard Henderson TCGReg reg; 333640ae5c62SRichard Henderson 333740ae5c62SRichard Henderson switch (ts->val_type) { 333840ae5c62SRichard Henderson case TEMP_VAL_REG: 333940ae5c62SRichard Henderson return; 334040ae5c62SRichard Henderson case TEMP_VAL_CONST: 3341b016486eSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs, 3342b722452aSRichard Henderson preferred_regs, ts->indirect_base); 334340ae5c62SRichard Henderson tcg_out_movi(s, ts->type, reg, ts->val); 334440ae5c62SRichard Henderson ts->mem_coherent = 0; 334540ae5c62SRichard Henderson break; 334640ae5c62SRichard Henderson case TEMP_VAL_MEM: 3347b016486eSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs, 3348b722452aSRichard Henderson preferred_regs, ts->indirect_base); 334940ae5c62SRichard Henderson tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset); 335040ae5c62SRichard Henderson ts->mem_coherent = 1; 335140ae5c62SRichard Henderson break; 335240ae5c62SRichard Henderson case TEMP_VAL_DEAD: 335340ae5c62SRichard Henderson default: 335440ae5c62SRichard Henderson tcg_abort(); 335540ae5c62SRichard Henderson } 335640ae5c62SRichard Henderson ts->reg = reg; 335740ae5c62SRichard Henderson ts->val_type = TEMP_VAL_REG; 335840ae5c62SRichard Henderson s->reg_to_temp[reg] = ts; 335940ae5c62SRichard Henderson } 336040ae5c62SRichard Henderson 336159d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a 3362e8996ee0Sbellard temporary registers needs to be allocated to store a constant. */ 336359d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs) 33641ad80729SAurelien Jarno { 33652c0366f0SAurelien Jarno /* The liveness analysis already ensures that globals are back 3366eabb7b91SAurelien Jarno in memory. Keep an tcg_debug_assert for safety. */ 3367f8bf00f1SRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || ts->fixed_reg); 33681ad80729SAurelien Jarno } 33691ad80729SAurelien Jarno 33709814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be 3371641d5fbeSbellard modified be the following code. 'allocated_regs' is used in case a 3372641d5fbeSbellard temporary registers needs to be allocated to store a constant. */ 3373641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs) 3374641d5fbeSbellard { 3375ac3b8891SRichard Henderson int i, n; 3376641d5fbeSbellard 3377ac3b8891SRichard Henderson for (i = 0, n = s->nb_globals; i < n; i++) { 3378b13eb728SRichard Henderson temp_save(s, &s->temps[i], allocated_regs); 3379641d5fbeSbellard } 3380e5097dc8Sbellard } 3381e5097dc8Sbellard 33823d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be 33833d5c5f87SAurelien Jarno read by the following code. 'allocated_regs' is used in case a 33843d5c5f87SAurelien Jarno temporary registers needs to be allocated to store a constant. */ 33853d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs) 33863d5c5f87SAurelien Jarno { 3387ac3b8891SRichard Henderson int i, n; 33883d5c5f87SAurelien Jarno 3389ac3b8891SRichard Henderson for (i = 0, n = s->nb_globals; i < n; i++) { 339012b9b11aSRichard Henderson TCGTemp *ts = &s->temps[i]; 339112b9b11aSRichard Henderson tcg_debug_assert(ts->val_type != TEMP_VAL_REG 339212b9b11aSRichard Henderson || ts->fixed_reg 339312b9b11aSRichard Henderson || ts->mem_coherent); 33943d5c5f87SAurelien Jarno } 33953d5c5f87SAurelien Jarno } 33963d5c5f87SAurelien Jarno 3397e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and 3398e8996ee0Sbellard all globals are stored at their canonical location. */ 3399e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs) 3400e5097dc8Sbellard { 3401e5097dc8Sbellard int i; 3402e5097dc8Sbellard 3403c896fe29Sbellard for (i = s->nb_globals; i < s->nb_temps; i++) { 3404b13eb728SRichard Henderson TCGTemp *ts = &s->temps[i]; 3405641d5fbeSbellard if (ts->temp_local) { 3406b13eb728SRichard Henderson temp_save(s, ts, allocated_regs); 3407641d5fbeSbellard } else { 34082c0366f0SAurelien Jarno /* The liveness analysis already ensures that temps are dead. 3409eabb7b91SAurelien Jarno Keep an tcg_debug_assert for safety. */ 3410eabb7b91SAurelien Jarno tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD); 3411c896fe29Sbellard } 3412641d5fbeSbellard } 3413e8996ee0Sbellard 3414e8996ee0Sbellard save_globals(s, allocated_regs); 3415c896fe29Sbellard } 3416c896fe29Sbellard 3417bab1671fSRichard Henderson /* 3418b4cb76e6SRichard Henderson * At a conditional branch, we assume all temporaries are dead and 3419b4cb76e6SRichard Henderson * all globals and local temps are synced to their location. 3420b4cb76e6SRichard Henderson */ 3421b4cb76e6SRichard Henderson static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs) 3422b4cb76e6SRichard Henderson { 3423b4cb76e6SRichard Henderson sync_globals(s, allocated_regs); 3424b4cb76e6SRichard Henderson 3425b4cb76e6SRichard Henderson for (int i = s->nb_globals; i < s->nb_temps; i++) { 3426b4cb76e6SRichard Henderson TCGTemp *ts = &s->temps[i]; 3427b4cb76e6SRichard Henderson /* 3428b4cb76e6SRichard Henderson * The liveness analysis already ensures that temps are dead. 3429b4cb76e6SRichard Henderson * Keep tcg_debug_asserts for safety. 3430b4cb76e6SRichard Henderson */ 3431b4cb76e6SRichard Henderson if (ts->temp_local) { 3432b4cb76e6SRichard Henderson tcg_debug_assert(ts->val_type != TEMP_VAL_REG || ts->mem_coherent); 3433b4cb76e6SRichard Henderson } else { 3434b4cb76e6SRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD); 3435b4cb76e6SRichard Henderson } 3436b4cb76e6SRichard Henderson } 3437b4cb76e6SRichard Henderson } 3438b4cb76e6SRichard Henderson 3439b4cb76e6SRichard Henderson /* 3440bab1671fSRichard Henderson * Specialized code generation for INDEX_op_movi_*. 3441bab1671fSRichard Henderson */ 34420fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots, 3443ba87719cSRichard Henderson tcg_target_ulong val, TCGLifeData arg_life, 3444ba87719cSRichard Henderson TCGRegSet preferred_regs) 3445e8996ee0Sbellard { 3446d63e3b6eSRichard Henderson /* ENV should not be modified. */ 3447d63e3b6eSRichard Henderson tcg_debug_assert(!ots->fixed_reg); 344859d7c14eSRichard Henderson 344959d7c14eSRichard Henderson /* The movi is not explicitly generated here. */ 3450f8b2f202SRichard Henderson if (ots->val_type == TEMP_VAL_REG) { 3451f8b2f202SRichard Henderson s->reg_to_temp[ots->reg] = NULL; 3452f8b2f202SRichard Henderson } 3453e8996ee0Sbellard ots->val_type = TEMP_VAL_CONST; 3454e8996ee0Sbellard ots->val = val; 345559d7c14eSRichard Henderson ots->mem_coherent = 0; 3456ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) { 3457ba87719cSRichard Henderson temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0)); 345859d7c14eSRichard Henderson } else if (IS_DEAD_ARG(0)) { 3459f8bf00f1SRichard Henderson temp_dead(s, ots); 34604c4e1ab2SAurelien Jarno } 3461e8996ee0Sbellard } 3462e8996ee0Sbellard 3463dd186292SRichard Henderson static void tcg_reg_alloc_movi(TCGContext *s, const TCGOp *op) 34640fe4fca4SPaolo Bonzini { 346543439139SRichard Henderson TCGTemp *ots = arg_temp(op->args[0]); 3466dd186292SRichard Henderson tcg_target_ulong val = op->args[1]; 34670fe4fca4SPaolo Bonzini 346869e3706dSRichard Henderson tcg_reg_alloc_do_movi(s, ots, val, op->life, op->output_pref[0]); 34690fe4fca4SPaolo Bonzini } 34700fe4fca4SPaolo Bonzini 3471bab1671fSRichard Henderson /* 3472bab1671fSRichard Henderson * Specialized code generation for INDEX_op_mov_*. 3473bab1671fSRichard Henderson */ 3474dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op) 3475c896fe29Sbellard { 3476dd186292SRichard Henderson const TCGLifeData arg_life = op->life; 347769e3706dSRichard Henderson TCGRegSet allocated_regs, preferred_regs; 3478c896fe29Sbellard TCGTemp *ts, *ots; 3479450445d5SRichard Henderson TCGType otype, itype; 3480c896fe29Sbellard 3481d21369f5SRichard Henderson allocated_regs = s->reserved_regs; 348269e3706dSRichard Henderson preferred_regs = op->output_pref[0]; 348343439139SRichard Henderson ots = arg_temp(op->args[0]); 348443439139SRichard Henderson ts = arg_temp(op->args[1]); 3485450445d5SRichard Henderson 3486d63e3b6eSRichard Henderson /* ENV should not be modified. */ 3487d63e3b6eSRichard Henderson tcg_debug_assert(!ots->fixed_reg); 3488d63e3b6eSRichard Henderson 3489450445d5SRichard Henderson /* Note that otype != itype for no-op truncation. */ 3490450445d5SRichard Henderson otype = ots->type; 3491450445d5SRichard Henderson itype = ts->type; 3492c896fe29Sbellard 34930fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_CONST) { 34940fe4fca4SPaolo Bonzini /* propagate constant or generate sti */ 34950fe4fca4SPaolo Bonzini tcg_target_ulong val = ts->val; 34960fe4fca4SPaolo Bonzini if (IS_DEAD_ARG(1)) { 34970fe4fca4SPaolo Bonzini temp_dead(s, ts); 34980fe4fca4SPaolo Bonzini } 349969e3706dSRichard Henderson tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs); 35000fe4fca4SPaolo Bonzini return; 35010fe4fca4SPaolo Bonzini } 35020fe4fca4SPaolo Bonzini 35030fe4fca4SPaolo Bonzini /* If the source value is in memory we're going to be forced 35040fe4fca4SPaolo Bonzini to have it in a register in order to perform the copy. Copy 35050fe4fca4SPaolo Bonzini the SOURCE value into its own register first, that way we 35060fe4fca4SPaolo Bonzini don't have to reload SOURCE the next time it is used. */ 35070fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_MEM) { 350869e3706dSRichard Henderson temp_load(s, ts, tcg_target_available_regs[itype], 350969e3706dSRichard Henderson allocated_regs, preferred_regs); 3510c29c1d7eSAurelien Jarno } 3511c29c1d7eSAurelien Jarno 35120fe4fca4SPaolo Bonzini tcg_debug_assert(ts->val_type == TEMP_VAL_REG); 3513d63e3b6eSRichard Henderson if (IS_DEAD_ARG(0)) { 3514c29c1d7eSAurelien Jarno /* mov to a non-saved dead register makes no sense (even with 3515c29c1d7eSAurelien Jarno liveness analysis disabled). */ 3516eabb7b91SAurelien Jarno tcg_debug_assert(NEED_SYNC_ARG(0)); 3517c29c1d7eSAurelien Jarno if (!ots->mem_allocated) { 35182272e4a7SRichard Henderson temp_allocate_frame(s, ots); 3519c29c1d7eSAurelien Jarno } 3520b3a62939SRichard Henderson tcg_out_st(s, otype, ts->reg, ots->mem_base->reg, ots->mem_offset); 3521c29c1d7eSAurelien Jarno if (IS_DEAD_ARG(1)) { 3522f8bf00f1SRichard Henderson temp_dead(s, ts); 3523c29c1d7eSAurelien Jarno } 3524f8bf00f1SRichard Henderson temp_dead(s, ots); 3525e8996ee0Sbellard } else { 3526d63e3b6eSRichard Henderson if (IS_DEAD_ARG(1) && !ts->fixed_reg) { 3527c29c1d7eSAurelien Jarno /* the mov can be suppressed */ 3528c29c1d7eSAurelien Jarno if (ots->val_type == TEMP_VAL_REG) { 3529f8b2f202SRichard Henderson s->reg_to_temp[ots->reg] = NULL; 3530c896fe29Sbellard } 3531c29c1d7eSAurelien Jarno ots->reg = ts->reg; 3532f8bf00f1SRichard Henderson temp_dead(s, ts); 3533c29c1d7eSAurelien Jarno } else { 3534c29c1d7eSAurelien Jarno if (ots->val_type != TEMP_VAL_REG) { 3535c29c1d7eSAurelien Jarno /* When allocating a new register, make sure to not spill the 3536c29c1d7eSAurelien Jarno input one. */ 3537c29c1d7eSAurelien Jarno tcg_regset_set_reg(allocated_regs, ts->reg); 3538450445d5SRichard Henderson ots->reg = tcg_reg_alloc(s, tcg_target_available_regs[otype], 353969e3706dSRichard Henderson allocated_regs, preferred_regs, 3540b016486eSRichard Henderson ots->indirect_base); 3541c29c1d7eSAurelien Jarno } 354278113e83SRichard Henderson if (!tcg_out_mov(s, otype, ots->reg, ts->reg)) { 3543240c08d0SRichard Henderson /* 3544240c08d0SRichard Henderson * Cross register class move not supported. 3545240c08d0SRichard Henderson * Store the source register into the destination slot 3546240c08d0SRichard Henderson * and leave the destination temp as TEMP_VAL_MEM. 3547240c08d0SRichard Henderson */ 3548240c08d0SRichard Henderson assert(!ots->fixed_reg); 3549240c08d0SRichard Henderson if (!ts->mem_allocated) { 3550240c08d0SRichard Henderson temp_allocate_frame(s, ots); 3551240c08d0SRichard Henderson } 3552240c08d0SRichard Henderson tcg_out_st(s, ts->type, ts->reg, 3553240c08d0SRichard Henderson ots->mem_base->reg, ots->mem_offset); 3554240c08d0SRichard Henderson ots->mem_coherent = 1; 3555240c08d0SRichard Henderson temp_free_or_dead(s, ots, -1); 3556240c08d0SRichard Henderson return; 355778113e83SRichard Henderson } 3558c29c1d7eSAurelien Jarno } 3559c896fe29Sbellard ots->val_type = TEMP_VAL_REG; 3560c896fe29Sbellard ots->mem_coherent = 0; 3561f8b2f202SRichard Henderson s->reg_to_temp[ots->reg] = ots; 3562ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) { 356398b4e186SRichard Henderson temp_sync(s, ots, allocated_regs, 0, 0); 3564c29c1d7eSAurelien Jarno } 3565ec7a869dSAurelien Jarno } 3566c896fe29Sbellard } 3567c896fe29Sbellard 3568bab1671fSRichard Henderson /* 3569bab1671fSRichard Henderson * Specialized code generation for INDEX_op_dup_vec. 3570bab1671fSRichard Henderson */ 3571bab1671fSRichard Henderson static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op) 3572bab1671fSRichard Henderson { 3573bab1671fSRichard Henderson const TCGLifeData arg_life = op->life; 3574bab1671fSRichard Henderson TCGRegSet dup_out_regs, dup_in_regs; 3575bab1671fSRichard Henderson TCGTemp *its, *ots; 3576bab1671fSRichard Henderson TCGType itype, vtype; 3577d6ecb4a9SRichard Henderson intptr_t endian_fixup; 3578bab1671fSRichard Henderson unsigned vece; 3579bab1671fSRichard Henderson bool ok; 3580bab1671fSRichard Henderson 3581bab1671fSRichard Henderson ots = arg_temp(op->args[0]); 3582bab1671fSRichard Henderson its = arg_temp(op->args[1]); 3583bab1671fSRichard Henderson 3584bab1671fSRichard Henderson /* ENV should not be modified. */ 3585bab1671fSRichard Henderson tcg_debug_assert(!ots->fixed_reg); 3586bab1671fSRichard Henderson 3587bab1671fSRichard Henderson itype = its->type; 3588bab1671fSRichard Henderson vece = TCGOP_VECE(op); 3589bab1671fSRichard Henderson vtype = TCGOP_VECL(op) + TCG_TYPE_V64; 3590bab1671fSRichard Henderson 3591bab1671fSRichard Henderson if (its->val_type == TEMP_VAL_CONST) { 3592bab1671fSRichard Henderson /* Propagate constant via movi -> dupi. */ 3593bab1671fSRichard Henderson tcg_target_ulong val = its->val; 3594bab1671fSRichard Henderson if (IS_DEAD_ARG(1)) { 3595bab1671fSRichard Henderson temp_dead(s, its); 3596bab1671fSRichard Henderson } 3597bab1671fSRichard Henderson tcg_reg_alloc_do_movi(s, ots, val, arg_life, op->output_pref[0]); 3598bab1671fSRichard Henderson return; 3599bab1671fSRichard Henderson } 3600bab1671fSRichard Henderson 36019be0d080SRichard Henderson dup_out_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs; 36029be0d080SRichard Henderson dup_in_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[1].regs; 3603bab1671fSRichard Henderson 3604bab1671fSRichard Henderson /* Allocate the output register now. */ 3605bab1671fSRichard Henderson if (ots->val_type != TEMP_VAL_REG) { 3606bab1671fSRichard Henderson TCGRegSet allocated_regs = s->reserved_regs; 3607bab1671fSRichard Henderson 3608bab1671fSRichard Henderson if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) { 3609bab1671fSRichard Henderson /* Make sure to not spill the input register. */ 3610bab1671fSRichard Henderson tcg_regset_set_reg(allocated_regs, its->reg); 3611bab1671fSRichard Henderson } 3612bab1671fSRichard Henderson ots->reg = tcg_reg_alloc(s, dup_out_regs, allocated_regs, 3613bab1671fSRichard Henderson op->output_pref[0], ots->indirect_base); 3614bab1671fSRichard Henderson ots->val_type = TEMP_VAL_REG; 3615bab1671fSRichard Henderson ots->mem_coherent = 0; 3616bab1671fSRichard Henderson s->reg_to_temp[ots->reg] = ots; 3617bab1671fSRichard Henderson } 3618bab1671fSRichard Henderson 3619bab1671fSRichard Henderson switch (its->val_type) { 3620bab1671fSRichard Henderson case TEMP_VAL_REG: 3621bab1671fSRichard Henderson /* 3622bab1671fSRichard Henderson * The dup constriaints must be broad, covering all possible VECE. 3623bab1671fSRichard Henderson * However, tcg_op_dup_vec() gets to see the VECE and we allow it 3624bab1671fSRichard Henderson * to fail, indicating that extra moves are required for that case. 3625bab1671fSRichard Henderson */ 3626bab1671fSRichard Henderson if (tcg_regset_test_reg(dup_in_regs, its->reg)) { 3627bab1671fSRichard Henderson if (tcg_out_dup_vec(s, vtype, vece, ots->reg, its->reg)) { 3628bab1671fSRichard Henderson goto done; 3629bab1671fSRichard Henderson } 3630bab1671fSRichard Henderson /* Try again from memory or a vector input register. */ 3631bab1671fSRichard Henderson } 3632bab1671fSRichard Henderson if (!its->mem_coherent) { 3633bab1671fSRichard Henderson /* 3634bab1671fSRichard Henderson * The input register is not synced, and so an extra store 3635bab1671fSRichard Henderson * would be required to use memory. Attempt an integer-vector 3636bab1671fSRichard Henderson * register move first. We do not have a TCGRegSet for this. 3637bab1671fSRichard Henderson */ 3638bab1671fSRichard Henderson if (tcg_out_mov(s, itype, ots->reg, its->reg)) { 3639bab1671fSRichard Henderson break; 3640bab1671fSRichard Henderson } 3641bab1671fSRichard Henderson /* Sync the temp back to its slot and load from there. */ 3642bab1671fSRichard Henderson temp_sync(s, its, s->reserved_regs, 0, 0); 3643bab1671fSRichard Henderson } 3644bab1671fSRichard Henderson /* fall through */ 3645bab1671fSRichard Henderson 3646bab1671fSRichard Henderson case TEMP_VAL_MEM: 3647d6ecb4a9SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 3648d6ecb4a9SRichard Henderson endian_fixup = itype == TCG_TYPE_I32 ? 4 : 8; 3649d6ecb4a9SRichard Henderson endian_fixup -= 1 << vece; 3650d6ecb4a9SRichard Henderson #else 3651d6ecb4a9SRichard Henderson endian_fixup = 0; 3652d6ecb4a9SRichard Henderson #endif 3653d6ecb4a9SRichard Henderson if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg, 3654d6ecb4a9SRichard Henderson its->mem_offset + endian_fixup)) { 3655d6ecb4a9SRichard Henderson goto done; 3656d6ecb4a9SRichard Henderson } 3657bab1671fSRichard Henderson tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset); 3658bab1671fSRichard Henderson break; 3659bab1671fSRichard Henderson 3660bab1671fSRichard Henderson default: 3661bab1671fSRichard Henderson g_assert_not_reached(); 3662bab1671fSRichard Henderson } 3663bab1671fSRichard Henderson 3664bab1671fSRichard Henderson /* We now have a vector input register, so dup must succeed. */ 3665bab1671fSRichard Henderson ok = tcg_out_dup_vec(s, vtype, vece, ots->reg, ots->reg); 3666bab1671fSRichard Henderson tcg_debug_assert(ok); 3667bab1671fSRichard Henderson 3668bab1671fSRichard Henderson done: 3669bab1671fSRichard Henderson if (IS_DEAD_ARG(1)) { 3670bab1671fSRichard Henderson temp_dead(s, its); 3671bab1671fSRichard Henderson } 3672bab1671fSRichard Henderson if (NEED_SYNC_ARG(0)) { 3673bab1671fSRichard Henderson temp_sync(s, ots, s->reserved_regs, 0, 0); 3674bab1671fSRichard Henderson } 3675bab1671fSRichard Henderson if (IS_DEAD_ARG(0)) { 3676bab1671fSRichard Henderson temp_dead(s, ots); 3677bab1671fSRichard Henderson } 3678bab1671fSRichard Henderson } 3679bab1671fSRichard Henderson 3680dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) 3681c896fe29Sbellard { 3682dd186292SRichard Henderson const TCGLifeData arg_life = op->life; 3683dd186292SRichard Henderson const TCGOpDef * const def = &tcg_op_defs[op->opc]; 368482790a87SRichard Henderson TCGRegSet i_allocated_regs; 368582790a87SRichard Henderson TCGRegSet o_allocated_regs; 3686b6638662SRichard Henderson int i, k, nb_iargs, nb_oargs; 3687b6638662SRichard Henderson TCGReg reg; 3688c896fe29Sbellard TCGArg arg; 3689c896fe29Sbellard const TCGArgConstraint *arg_ct; 3690c896fe29Sbellard TCGTemp *ts; 3691c896fe29Sbellard TCGArg new_args[TCG_MAX_OP_ARGS]; 3692c896fe29Sbellard int const_args[TCG_MAX_OP_ARGS]; 3693c896fe29Sbellard 3694c896fe29Sbellard nb_oargs = def->nb_oargs; 3695c896fe29Sbellard nb_iargs = def->nb_iargs; 3696c896fe29Sbellard 3697c896fe29Sbellard /* copy constants */ 3698c896fe29Sbellard memcpy(new_args + nb_oargs + nb_iargs, 3699dd186292SRichard Henderson op->args + nb_oargs + nb_iargs, 3700c896fe29Sbellard sizeof(TCGArg) * def->nb_cargs); 3701c896fe29Sbellard 3702d21369f5SRichard Henderson i_allocated_regs = s->reserved_regs; 3703d21369f5SRichard Henderson o_allocated_regs = s->reserved_regs; 370482790a87SRichard Henderson 3705c896fe29Sbellard /* satisfy input constraints */ 3706c896fe29Sbellard for (k = 0; k < nb_iargs; k++) { 3707d62816f2SRichard Henderson TCGRegSet i_preferred_regs, o_preferred_regs; 3708d62816f2SRichard Henderson 370966792f90SRichard Henderson i = def->args_ct[nb_oargs + k].sort_index; 3710dd186292SRichard Henderson arg = op->args[i]; 3711c896fe29Sbellard arg_ct = &def->args_ct[i]; 371243439139SRichard Henderson ts = arg_temp(arg); 371340ae5c62SRichard Henderson 371440ae5c62SRichard Henderson if (ts->val_type == TEMP_VAL_CONST 371540ae5c62SRichard Henderson && tcg_target_const_match(ts->val, ts->type, arg_ct)) { 3716c896fe29Sbellard /* constant is OK for instruction */ 3717c896fe29Sbellard const_args[i] = 1; 3718c896fe29Sbellard new_args[i] = ts->val; 3719d62816f2SRichard Henderson continue; 3720c896fe29Sbellard } 372140ae5c62SRichard Henderson 3722d62816f2SRichard Henderson i_preferred_regs = o_preferred_regs = 0; 3723bc2b17e6SRichard Henderson if (arg_ct->ialias) { 3724d62816f2SRichard Henderson o_preferred_regs = op->output_pref[arg_ct->alias_index]; 37255ff9d6a4Sbellard if (ts->fixed_reg) { 37265ff9d6a4Sbellard /* if fixed register, we must allocate a new register 37275ff9d6a4Sbellard if the alias is not the same register */ 3728d62816f2SRichard Henderson if (arg != op->args[arg_ct->alias_index]) { 37295ff9d6a4Sbellard goto allocate_in_reg; 3730d62816f2SRichard Henderson } 37315ff9d6a4Sbellard } else { 3732c896fe29Sbellard /* if the input is aliased to an output and if it is 3733c896fe29Sbellard not dead after the instruction, we must allocate 3734c896fe29Sbellard a new register and move it */ 3735866cb6cbSAurelien Jarno if (!IS_DEAD_ARG(i)) { 3736c896fe29Sbellard goto allocate_in_reg; 3737c896fe29Sbellard } 3738d62816f2SRichard Henderson 37397e1df267SAurelien Jarno /* check if the current register has already been allocated 37407e1df267SAurelien Jarno for another input aliased to an output */ 3741d62816f2SRichard Henderson if (ts->val_type == TEMP_VAL_REG) { 37427e1df267SAurelien Jarno int k2, i2; 3743d62816f2SRichard Henderson reg = ts->reg; 37447e1df267SAurelien Jarno for (k2 = 0 ; k2 < k ; k2++) { 374566792f90SRichard Henderson i2 = def->args_ct[nb_oargs + k2].sort_index; 3746bc2b17e6SRichard Henderson if (def->args_ct[i2].ialias && reg == new_args[i2]) { 37477e1df267SAurelien Jarno goto allocate_in_reg; 37487e1df267SAurelien Jarno } 37497e1df267SAurelien Jarno } 37505ff9d6a4Sbellard } 3751d62816f2SRichard Henderson i_preferred_regs = o_preferred_regs; 3752866cb6cbSAurelien Jarno } 3753d62816f2SRichard Henderson } 3754d62816f2SRichard Henderson 37559be0d080SRichard Henderson temp_load(s, ts, arg_ct->regs, i_allocated_regs, i_preferred_regs); 3756c896fe29Sbellard reg = ts->reg; 3757d62816f2SRichard Henderson 37589be0d080SRichard Henderson if (tcg_regset_test_reg(arg_ct->regs, reg)) { 3759c896fe29Sbellard /* nothing to do : the constraint is satisfied */ 3760c896fe29Sbellard } else { 3761c896fe29Sbellard allocate_in_reg: 3762c896fe29Sbellard /* allocate a new register matching the constraint 3763c896fe29Sbellard and move the temporary register into it */ 3764d62816f2SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 3765d62816f2SRichard Henderson i_allocated_regs, 0); 37669be0d080SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->regs, i_allocated_regs, 3767d62816f2SRichard Henderson o_preferred_regs, ts->indirect_base); 376878113e83SRichard Henderson if (!tcg_out_mov(s, ts->type, reg, ts->reg)) { 3769240c08d0SRichard Henderson /* 3770240c08d0SRichard Henderson * Cross register class move not supported. Sync the 3771240c08d0SRichard Henderson * temp back to its slot and load from there. 3772240c08d0SRichard Henderson */ 3773240c08d0SRichard Henderson temp_sync(s, ts, i_allocated_regs, 0, 0); 3774240c08d0SRichard Henderson tcg_out_ld(s, ts->type, reg, 3775240c08d0SRichard Henderson ts->mem_base->reg, ts->mem_offset); 377678113e83SRichard Henderson } 3777c896fe29Sbellard } 3778c896fe29Sbellard new_args[i] = reg; 3779c896fe29Sbellard const_args[i] = 0; 378082790a87SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg); 3781c896fe29Sbellard } 3782c896fe29Sbellard 3783c896fe29Sbellard /* mark dead temporaries and free the associated registers */ 3784866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 3785866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) { 378643439139SRichard Henderson temp_dead(s, arg_temp(op->args[i])); 3787c896fe29Sbellard } 3788c896fe29Sbellard } 3789c896fe29Sbellard 3790b4cb76e6SRichard Henderson if (def->flags & TCG_OPF_COND_BRANCH) { 3791b4cb76e6SRichard Henderson tcg_reg_alloc_cbranch(s, i_allocated_regs); 3792b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 379382790a87SRichard Henderson tcg_reg_alloc_bb_end(s, i_allocated_regs); 3794a52ad07eSAurelien Jarno } else { 3795c896fe29Sbellard if (def->flags & TCG_OPF_CALL_CLOBBER) { 3796b03cce8eSbellard /* XXX: permit generic clobber register list ? */ 3797c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) { 3798c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { 379982790a87SRichard Henderson tcg_reg_free(s, i, i_allocated_regs); 3800c896fe29Sbellard } 3801c896fe29Sbellard } 38023d5c5f87SAurelien Jarno } 38033d5c5f87SAurelien Jarno if (def->flags & TCG_OPF_SIDE_EFFECTS) { 38043d5c5f87SAurelien Jarno /* sync globals if the op has side effects and might trigger 38053d5c5f87SAurelien Jarno an exception. */ 380682790a87SRichard Henderson sync_globals(s, i_allocated_regs); 3807c896fe29Sbellard } 3808c896fe29Sbellard 3809c896fe29Sbellard /* satisfy the output constraints */ 3810c896fe29Sbellard for(k = 0; k < nb_oargs; k++) { 381166792f90SRichard Henderson i = def->args_ct[k].sort_index; 3812dd186292SRichard Henderson arg = op->args[i]; 3813c896fe29Sbellard arg_ct = &def->args_ct[i]; 381443439139SRichard Henderson ts = arg_temp(arg); 3815d63e3b6eSRichard Henderson 3816d63e3b6eSRichard Henderson /* ENV should not be modified. */ 3817d63e3b6eSRichard Henderson tcg_debug_assert(!ts->fixed_reg); 3818d63e3b6eSRichard Henderson 3819bc2b17e6SRichard Henderson if (arg_ct->oalias && !const_args[arg_ct->alias_index]) { 38205ff9d6a4Sbellard reg = new_args[arg_ct->alias_index]; 3821bc2b17e6SRichard Henderson } else if (arg_ct->newreg) { 38229be0d080SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->regs, 382382790a87SRichard Henderson i_allocated_regs | o_allocated_regs, 382469e3706dSRichard Henderson op->output_pref[k], ts->indirect_base); 3825c896fe29Sbellard } else { 38269be0d080SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs, 382769e3706dSRichard Henderson op->output_pref[k], ts->indirect_base); 3828c896fe29Sbellard } 382982790a87SRichard Henderson tcg_regset_set_reg(o_allocated_regs, reg); 3830639368ddSAurelien Jarno if (ts->val_type == TEMP_VAL_REG) { 3831f8b2f202SRichard Henderson s->reg_to_temp[ts->reg] = NULL; 3832639368ddSAurelien Jarno } 3833c896fe29Sbellard ts->val_type = TEMP_VAL_REG; 3834c896fe29Sbellard ts->reg = reg; 3835d63e3b6eSRichard Henderson /* 3836d63e3b6eSRichard Henderson * Temp value is modified, so the value kept in memory is 3837d63e3b6eSRichard Henderson * potentially not the same. 3838d63e3b6eSRichard Henderson */ 3839c896fe29Sbellard ts->mem_coherent = 0; 3840f8b2f202SRichard Henderson s->reg_to_temp[reg] = ts; 3841c896fe29Sbellard new_args[i] = reg; 3842c896fe29Sbellard } 3843e8996ee0Sbellard } 3844c896fe29Sbellard 3845c896fe29Sbellard /* emit instruction */ 3846d2fd745fSRichard Henderson if (def->flags & TCG_OPF_VECTOR) { 3847d2fd745fSRichard Henderson tcg_out_vec_op(s, op->opc, TCGOP_VECL(op), TCGOP_VECE(op), 3848d2fd745fSRichard Henderson new_args, const_args); 3849d2fd745fSRichard Henderson } else { 3850dd186292SRichard Henderson tcg_out_op(s, op->opc, new_args, const_args); 3851d2fd745fSRichard Henderson } 3852c896fe29Sbellard 3853c896fe29Sbellard /* move the outputs in the correct register if needed */ 3854c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 385543439139SRichard Henderson ts = arg_temp(op->args[i]); 3856d63e3b6eSRichard Henderson 3857d63e3b6eSRichard Henderson /* ENV should not be modified. */ 3858d63e3b6eSRichard Henderson tcg_debug_assert(!ts->fixed_reg); 3859d63e3b6eSRichard Henderson 3860ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) { 386198b4e186SRichard Henderson temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i)); 386259d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) { 3863f8bf00f1SRichard Henderson temp_dead(s, ts); 3864ec7a869dSAurelien Jarno } 3865c896fe29Sbellard } 3866c896fe29Sbellard } 3867c896fe29Sbellard 3868b03cce8eSbellard #ifdef TCG_TARGET_STACK_GROWSUP 3869b03cce8eSbellard #define STACK_DIR(x) (-(x)) 3870b03cce8eSbellard #else 3871b03cce8eSbellard #define STACK_DIR(x) (x) 3872b03cce8eSbellard #endif 3873b03cce8eSbellard 3874dd186292SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op) 3875c896fe29Sbellard { 3876cd9090aaSRichard Henderson const int nb_oargs = TCGOP_CALLO(op); 3877cd9090aaSRichard Henderson const int nb_iargs = TCGOP_CALLI(op); 3878dd186292SRichard Henderson const TCGLifeData arg_life = op->life; 3879b6638662SRichard Henderson int flags, nb_regs, i; 3880b6638662SRichard Henderson TCGReg reg; 3881cf066674SRichard Henderson TCGArg arg; 3882c896fe29Sbellard TCGTemp *ts; 3883d3452f1fSRichard Henderson intptr_t stack_offset; 3884d3452f1fSRichard Henderson size_t call_stack_size; 3885cf066674SRichard Henderson tcg_insn_unit *func_addr; 3886cf066674SRichard Henderson int allocate_args; 3887c896fe29Sbellard TCGRegSet allocated_regs; 3888c896fe29Sbellard 3889dd186292SRichard Henderson func_addr = (tcg_insn_unit *)(intptr_t)op->args[nb_oargs + nb_iargs]; 3890dd186292SRichard Henderson flags = op->args[nb_oargs + nb_iargs + 1]; 3891c896fe29Sbellard 38926e17d0c5SStefan Weil nb_regs = ARRAY_SIZE(tcg_target_call_iarg_regs); 3893c45cb8bbSRichard Henderson if (nb_regs > nb_iargs) { 3894c45cb8bbSRichard Henderson nb_regs = nb_iargs; 3895cf066674SRichard Henderson } 3896c896fe29Sbellard 3897c896fe29Sbellard /* assign stack slots first */ 3898c45cb8bbSRichard Henderson call_stack_size = (nb_iargs - nb_regs) * sizeof(tcg_target_long); 3899c896fe29Sbellard call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) & 3900c896fe29Sbellard ~(TCG_TARGET_STACK_ALIGN - 1); 3901b03cce8eSbellard allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE); 3902b03cce8eSbellard if (allocate_args) { 3903345649c0SBlue Swirl /* XXX: if more than TCG_STATIC_CALL_ARGS_SIZE is needed, 3904345649c0SBlue Swirl preallocate call stack */ 3905345649c0SBlue Swirl tcg_abort(); 3906b03cce8eSbellard } 390739cf05d3Sbellard 390839cf05d3Sbellard stack_offset = TCG_TARGET_CALL_STACK_OFFSET; 3909c45cb8bbSRichard Henderson for (i = nb_regs; i < nb_iargs; i++) { 3910dd186292SRichard Henderson arg = op->args[nb_oargs + i]; 391139cf05d3Sbellard #ifdef TCG_TARGET_STACK_GROWSUP 391239cf05d3Sbellard stack_offset -= sizeof(tcg_target_long); 391339cf05d3Sbellard #endif 391439cf05d3Sbellard if (arg != TCG_CALL_DUMMY_ARG) { 391543439139SRichard Henderson ts = arg_temp(arg); 391640ae5c62SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 3917b722452aSRichard Henderson s->reserved_regs, 0); 3918e4d5434cSblueswir1 tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset); 391939cf05d3Sbellard } 392039cf05d3Sbellard #ifndef TCG_TARGET_STACK_GROWSUP 392139cf05d3Sbellard stack_offset += sizeof(tcg_target_long); 392239cf05d3Sbellard #endif 3923c896fe29Sbellard } 3924c896fe29Sbellard 3925c896fe29Sbellard /* assign input registers */ 3926d21369f5SRichard Henderson allocated_regs = s->reserved_regs; 3927c896fe29Sbellard for (i = 0; i < nb_regs; i++) { 3928dd186292SRichard Henderson arg = op->args[nb_oargs + i]; 392939cf05d3Sbellard if (arg != TCG_CALL_DUMMY_ARG) { 393043439139SRichard Henderson ts = arg_temp(arg); 3931c896fe29Sbellard reg = tcg_target_call_iarg_regs[i]; 393240ae5c62SRichard Henderson 3933c896fe29Sbellard if (ts->val_type == TEMP_VAL_REG) { 3934c896fe29Sbellard if (ts->reg != reg) { 39354250da10SRichard Henderson tcg_reg_free(s, reg, allocated_regs); 393678113e83SRichard Henderson if (!tcg_out_mov(s, ts->type, reg, ts->reg)) { 3937240c08d0SRichard Henderson /* 3938240c08d0SRichard Henderson * Cross register class move not supported. Sync the 3939240c08d0SRichard Henderson * temp back to its slot and load from there. 3940240c08d0SRichard Henderson */ 3941240c08d0SRichard Henderson temp_sync(s, ts, allocated_regs, 0, 0); 3942240c08d0SRichard Henderson tcg_out_ld(s, ts->type, reg, 3943240c08d0SRichard Henderson ts->mem_base->reg, ts->mem_offset); 394478113e83SRichard Henderson } 3945c896fe29Sbellard } 3946c896fe29Sbellard } else { 3947ccb1bb66SRichard Henderson TCGRegSet arg_set = 0; 394840ae5c62SRichard Henderson 39494250da10SRichard Henderson tcg_reg_free(s, reg, allocated_regs); 395040ae5c62SRichard Henderson tcg_regset_set_reg(arg_set, reg); 3951b722452aSRichard Henderson temp_load(s, ts, arg_set, allocated_regs, 0); 3952c896fe29Sbellard } 395340ae5c62SRichard Henderson 3954c896fe29Sbellard tcg_regset_set_reg(allocated_regs, reg); 3955c896fe29Sbellard } 395639cf05d3Sbellard } 3957c896fe29Sbellard 3958c896fe29Sbellard /* mark dead temporaries and free the associated registers */ 3959866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 3960866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) { 396143439139SRichard Henderson temp_dead(s, arg_temp(op->args[i])); 3962c896fe29Sbellard } 3963c896fe29Sbellard } 3964c896fe29Sbellard 3965c896fe29Sbellard /* clobber call registers */ 3966c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) { 3967c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { 3968b3915dbbSRichard Henderson tcg_reg_free(s, i, allocated_regs); 3969c896fe29Sbellard } 3970c896fe29Sbellard } 3971c896fe29Sbellard 397278505279SAurelien Jarno /* Save globals if they might be written by the helper, sync them if 397378505279SAurelien Jarno they might be read. */ 397478505279SAurelien Jarno if (flags & TCG_CALL_NO_READ_GLOBALS) { 397578505279SAurelien Jarno /* Nothing to do */ 397678505279SAurelien Jarno } else if (flags & TCG_CALL_NO_WRITE_GLOBALS) { 397778505279SAurelien Jarno sync_globals(s, allocated_regs); 397878505279SAurelien Jarno } else { 3979e8996ee0Sbellard save_globals(s, allocated_regs); 3980b9c18f56Saurel32 } 3981c896fe29Sbellard 3982cf066674SRichard Henderson tcg_out_call(s, func_addr); 3983c896fe29Sbellard 3984c896fe29Sbellard /* assign output registers and emit moves if needed */ 3985c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 3986dd186292SRichard Henderson arg = op->args[i]; 398743439139SRichard Henderson ts = arg_temp(arg); 3988d63e3b6eSRichard Henderson 3989d63e3b6eSRichard Henderson /* ENV should not be modified. */ 3990d63e3b6eSRichard Henderson tcg_debug_assert(!ts->fixed_reg); 3991d63e3b6eSRichard Henderson 3992c896fe29Sbellard reg = tcg_target_call_oarg_regs[i]; 3993eabb7b91SAurelien Jarno tcg_debug_assert(s->reg_to_temp[reg] == NULL); 3994639368ddSAurelien Jarno if (ts->val_type == TEMP_VAL_REG) { 3995f8b2f202SRichard Henderson s->reg_to_temp[ts->reg] = NULL; 3996639368ddSAurelien Jarno } 3997c896fe29Sbellard ts->val_type = TEMP_VAL_REG; 3998c896fe29Sbellard ts->reg = reg; 3999c896fe29Sbellard ts->mem_coherent = 0; 4000f8b2f202SRichard Henderson s->reg_to_temp[reg] = ts; 4001ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) { 400298b4e186SRichard Henderson temp_sync(s, ts, allocated_regs, 0, IS_DEAD_ARG(i)); 400359d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) { 4004f8bf00f1SRichard Henderson temp_dead(s, ts); 4005c896fe29Sbellard } 4006c896fe29Sbellard } 40078c11ad25SAurelien Jarno } 4008c896fe29Sbellard 4009c896fe29Sbellard #ifdef CONFIG_PROFILER 4010c896fe29Sbellard 4011c3fac113SEmilio G. Cota /* avoid copy/paste errors */ 4012c3fac113SEmilio G. Cota #define PROF_ADD(to, from, field) \ 4013c3fac113SEmilio G. Cota do { \ 4014d73415a3SStefan Hajnoczi (to)->field += qatomic_read(&((from)->field)); \ 4015c3fac113SEmilio G. Cota } while (0) 4016c896fe29Sbellard 4017c3fac113SEmilio G. Cota #define PROF_MAX(to, from, field) \ 4018c3fac113SEmilio G. Cota do { \ 4019d73415a3SStefan Hajnoczi typeof((from)->field) val__ = qatomic_read(&((from)->field)); \ 4020c3fac113SEmilio G. Cota if (val__ > (to)->field) { \ 4021c3fac113SEmilio G. Cota (to)->field = val__; \ 4022c3fac113SEmilio G. Cota } \ 4023c3fac113SEmilio G. Cota } while (0) 4024c3fac113SEmilio G. Cota 4025c3fac113SEmilio G. Cota /* Pass in a zero'ed @prof */ 4026c3fac113SEmilio G. Cota static inline 4027c3fac113SEmilio G. Cota void tcg_profile_snapshot(TCGProfile *prof, bool counters, bool table) 4028c896fe29Sbellard { 4029d73415a3SStefan Hajnoczi unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs); 4030c3fac113SEmilio G. Cota unsigned int i; 4031c3fac113SEmilio G. Cota 40323468b59eSEmilio G. Cota for (i = 0; i < n_ctxs; i++) { 4033d73415a3SStefan Hajnoczi TCGContext *s = qatomic_read(&tcg_ctxs[i]); 40343468b59eSEmilio G. Cota const TCGProfile *orig = &s->prof; 4035c3fac113SEmilio G. Cota 4036c3fac113SEmilio G. Cota if (counters) { 403772fd2efbSEmilio G. Cota PROF_ADD(prof, orig, cpu_exec_time); 4038c3fac113SEmilio G. Cota PROF_ADD(prof, orig, tb_count1); 4039c3fac113SEmilio G. Cota PROF_ADD(prof, orig, tb_count); 4040c3fac113SEmilio G. Cota PROF_ADD(prof, orig, op_count); 4041c3fac113SEmilio G. Cota PROF_MAX(prof, orig, op_count_max); 4042c3fac113SEmilio G. Cota PROF_ADD(prof, orig, temp_count); 4043c3fac113SEmilio G. Cota PROF_MAX(prof, orig, temp_count_max); 4044c3fac113SEmilio G. Cota PROF_ADD(prof, orig, del_op_count); 4045c3fac113SEmilio G. Cota PROF_ADD(prof, orig, code_in_len); 4046c3fac113SEmilio G. Cota PROF_ADD(prof, orig, code_out_len); 4047c3fac113SEmilio G. Cota PROF_ADD(prof, orig, search_out_len); 4048c3fac113SEmilio G. Cota PROF_ADD(prof, orig, interm_time); 4049c3fac113SEmilio G. Cota PROF_ADD(prof, orig, code_time); 4050c3fac113SEmilio G. Cota PROF_ADD(prof, orig, la_time); 4051c3fac113SEmilio G. Cota PROF_ADD(prof, orig, opt_time); 4052c3fac113SEmilio G. Cota PROF_ADD(prof, orig, restore_count); 4053c3fac113SEmilio G. Cota PROF_ADD(prof, orig, restore_time); 4054c3fac113SEmilio G. Cota } 4055c3fac113SEmilio G. Cota if (table) { 4056c896fe29Sbellard int i; 4057d70724ceSzhanghailiang 405815fc7daaSRichard Henderson for (i = 0; i < NB_OPS; i++) { 4059c3fac113SEmilio G. Cota PROF_ADD(prof, orig, table_op_count[i]); 4060c3fac113SEmilio G. Cota } 4061c3fac113SEmilio G. Cota } 4062c3fac113SEmilio G. Cota } 4063c3fac113SEmilio G. Cota } 4064c3fac113SEmilio G. Cota 4065c3fac113SEmilio G. Cota #undef PROF_ADD 4066c3fac113SEmilio G. Cota #undef PROF_MAX 4067c3fac113SEmilio G. Cota 4068c3fac113SEmilio G. Cota static void tcg_profile_snapshot_counters(TCGProfile *prof) 4069c3fac113SEmilio G. Cota { 4070c3fac113SEmilio G. Cota tcg_profile_snapshot(prof, true, false); 4071c3fac113SEmilio G. Cota } 4072c3fac113SEmilio G. Cota 4073c3fac113SEmilio G. Cota static void tcg_profile_snapshot_table(TCGProfile *prof) 4074c3fac113SEmilio G. Cota { 4075c3fac113SEmilio G. Cota tcg_profile_snapshot(prof, false, true); 4076c3fac113SEmilio G. Cota } 4077c3fac113SEmilio G. Cota 4078d4c51a0aSMarkus Armbruster void tcg_dump_op_count(void) 4079c3fac113SEmilio G. Cota { 4080c3fac113SEmilio G. Cota TCGProfile prof = {}; 4081c3fac113SEmilio G. Cota int i; 4082c3fac113SEmilio G. Cota 4083c3fac113SEmilio G. Cota tcg_profile_snapshot_table(&prof); 4084c3fac113SEmilio G. Cota for (i = 0; i < NB_OPS; i++) { 4085d4c51a0aSMarkus Armbruster qemu_printf("%s %" PRId64 "\n", tcg_op_defs[i].name, 4086c3fac113SEmilio G. Cota prof.table_op_count[i]); 4087c896fe29Sbellard } 4088c896fe29Sbellard } 408972fd2efbSEmilio G. Cota 409072fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void) 409172fd2efbSEmilio G. Cota { 4092d73415a3SStefan Hajnoczi unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs); 409372fd2efbSEmilio G. Cota unsigned int i; 409472fd2efbSEmilio G. Cota int64_t ret = 0; 409572fd2efbSEmilio G. Cota 409672fd2efbSEmilio G. Cota for (i = 0; i < n_ctxs; i++) { 4097d73415a3SStefan Hajnoczi const TCGContext *s = qatomic_read(&tcg_ctxs[i]); 409872fd2efbSEmilio G. Cota const TCGProfile *prof = &s->prof; 409972fd2efbSEmilio G. Cota 4100d73415a3SStefan Hajnoczi ret += qatomic_read(&prof->cpu_exec_time); 410172fd2efbSEmilio G. Cota } 410272fd2efbSEmilio G. Cota return ret; 410372fd2efbSEmilio G. Cota } 4104246ae24dSMax Filippov #else 4105d4c51a0aSMarkus Armbruster void tcg_dump_op_count(void) 4106246ae24dSMax Filippov { 4107d4c51a0aSMarkus Armbruster qemu_printf("[TCG profiler not compiled]\n"); 4108246ae24dSMax Filippov } 410972fd2efbSEmilio G. Cota 411072fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void) 411172fd2efbSEmilio G. Cota { 411272fd2efbSEmilio G. Cota error_report("%s: TCG profiler not compiled", __func__); 411372fd2efbSEmilio G. Cota exit(EXIT_FAILURE); 411472fd2efbSEmilio G. Cota } 4115c896fe29Sbellard #endif 4116c896fe29Sbellard 4117c896fe29Sbellard 41185bd2ec3dSAlex Bennée int tcg_gen_code(TCGContext *s, TranslationBlock *tb) 4119c896fe29Sbellard { 4120c3fac113SEmilio G. Cota #ifdef CONFIG_PROFILER 4121c3fac113SEmilio G. Cota TCGProfile *prof = &s->prof; 4122c3fac113SEmilio G. Cota #endif 412315fa08f8SRichard Henderson int i, num_insns; 412415fa08f8SRichard Henderson TCGOp *op; 4125c896fe29Sbellard 412604fe6400SRichard Henderson #ifdef CONFIG_PROFILER 412704fe6400SRichard Henderson { 4128c1f543b7SEmilio G. Cota int n = 0; 412904fe6400SRichard Henderson 413015fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 413115fa08f8SRichard Henderson n++; 413215fa08f8SRichard Henderson } 4133d73415a3SStefan Hajnoczi qatomic_set(&prof->op_count, prof->op_count + n); 4134c3fac113SEmilio G. Cota if (n > prof->op_count_max) { 4135d73415a3SStefan Hajnoczi qatomic_set(&prof->op_count_max, n); 413604fe6400SRichard Henderson } 413704fe6400SRichard Henderson 413804fe6400SRichard Henderson n = s->nb_temps; 4139d73415a3SStefan Hajnoczi qatomic_set(&prof->temp_count, prof->temp_count + n); 4140c3fac113SEmilio G. Cota if (n > prof->temp_count_max) { 4141d73415a3SStefan Hajnoczi qatomic_set(&prof->temp_count_max, n); 414204fe6400SRichard Henderson } 414304fe6400SRichard Henderson } 414404fe6400SRichard Henderson #endif 414504fe6400SRichard Henderson 4146c896fe29Sbellard #ifdef DEBUG_DISAS 4147d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP) 4148d977e1c2SAlex Bennée && qemu_log_in_addr_range(tb->pc))) { 4149fc59d2d8SRobert Foley FILE *logfile = qemu_log_lock(); 415093fcfe39Saliguori qemu_log("OP:\n"); 41511894f69aSRichard Henderson tcg_dump_ops(s, false); 415293fcfe39Saliguori qemu_log("\n"); 4153fc59d2d8SRobert Foley qemu_log_unlock(logfile); 4154c896fe29Sbellard } 4155c896fe29Sbellard #endif 4156c896fe29Sbellard 4157bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG 4158bef16ab4SRichard Henderson /* Ensure all labels referenced have been emitted. */ 4159bef16ab4SRichard Henderson { 4160bef16ab4SRichard Henderson TCGLabel *l; 4161bef16ab4SRichard Henderson bool error = false; 4162bef16ab4SRichard Henderson 4163bef16ab4SRichard Henderson QSIMPLEQ_FOREACH(l, &s->labels, next) { 4164bef16ab4SRichard Henderson if (unlikely(!l->present) && l->refs) { 4165bef16ab4SRichard Henderson qemu_log_mask(CPU_LOG_TB_OP, 4166bef16ab4SRichard Henderson "$L%d referenced but not present.\n", l->id); 4167bef16ab4SRichard Henderson error = true; 4168bef16ab4SRichard Henderson } 4169bef16ab4SRichard Henderson } 4170bef16ab4SRichard Henderson assert(!error); 4171bef16ab4SRichard Henderson } 4172bef16ab4SRichard Henderson #endif 4173bef16ab4SRichard Henderson 4174c5cc28ffSAurelien Jarno #ifdef CONFIG_PROFILER 4175d73415a3SStefan Hajnoczi qatomic_set(&prof->opt_time, prof->opt_time - profile_getclock()); 4176c5cc28ffSAurelien Jarno #endif 4177c5cc28ffSAurelien Jarno 41788f2e8c07SKirill Batuzov #ifdef USE_TCG_OPTIMIZATIONS 4179c45cb8bbSRichard Henderson tcg_optimize(s); 41808f2e8c07SKirill Batuzov #endif 41818f2e8c07SKirill Batuzov 4182a23a9ec6Sbellard #ifdef CONFIG_PROFILER 4183d73415a3SStefan Hajnoczi qatomic_set(&prof->opt_time, prof->opt_time + profile_getclock()); 4184d73415a3SStefan Hajnoczi qatomic_set(&prof->la_time, prof->la_time - profile_getclock()); 4185a23a9ec6Sbellard #endif 4186c5cc28ffSAurelien Jarno 4187b4fc67c7SRichard Henderson reachable_code_pass(s); 4188b83eabeaSRichard Henderson liveness_pass_1(s); 41895a18407fSRichard Henderson 41905a18407fSRichard Henderson if (s->nb_indirects > 0) { 41915a18407fSRichard Henderson #ifdef DEBUG_DISAS 41925a18407fSRichard Henderson if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND) 41935a18407fSRichard Henderson && qemu_log_in_addr_range(tb->pc))) { 4194fc59d2d8SRobert Foley FILE *logfile = qemu_log_lock(); 41955a18407fSRichard Henderson qemu_log("OP before indirect lowering:\n"); 41961894f69aSRichard Henderson tcg_dump_ops(s, false); 41975a18407fSRichard Henderson qemu_log("\n"); 4198fc59d2d8SRobert Foley qemu_log_unlock(logfile); 41995a18407fSRichard Henderson } 42005a18407fSRichard Henderson #endif 42015a18407fSRichard Henderson /* Replace indirect temps with direct temps. */ 4202b83eabeaSRichard Henderson if (liveness_pass_2(s)) { 42035a18407fSRichard Henderson /* If changes were made, re-run liveness. */ 4204b83eabeaSRichard Henderson liveness_pass_1(s); 42055a18407fSRichard Henderson } 42065a18407fSRichard Henderson } 4207c5cc28ffSAurelien Jarno 4208a23a9ec6Sbellard #ifdef CONFIG_PROFILER 4209d73415a3SStefan Hajnoczi qatomic_set(&prof->la_time, prof->la_time + profile_getclock()); 4210a23a9ec6Sbellard #endif 4211c896fe29Sbellard 4212c896fe29Sbellard #ifdef DEBUG_DISAS 4213d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT) 4214d977e1c2SAlex Bennée && qemu_log_in_addr_range(tb->pc))) { 4215fc59d2d8SRobert Foley FILE *logfile = qemu_log_lock(); 4216c5cc28ffSAurelien Jarno qemu_log("OP after optimization and liveness analysis:\n"); 42171894f69aSRichard Henderson tcg_dump_ops(s, true); 421893fcfe39Saliguori qemu_log("\n"); 4219fc59d2d8SRobert Foley qemu_log_unlock(logfile); 4220c896fe29Sbellard } 4221c896fe29Sbellard #endif 4222c896fe29Sbellard 4223c896fe29Sbellard tcg_reg_alloc_start(s); 4224c896fe29Sbellard 4225e7e168f4SEmilio G. Cota s->code_buf = tb->tc.ptr; 4226e7e168f4SEmilio G. Cota s->code_ptr = tb->tc.ptr; 4227c896fe29Sbellard 4228659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS 42296001f772SLaurent Vivier QSIMPLEQ_INIT(&s->ldst_labels); 4230659ef5cbSRichard Henderson #endif 423157a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 423257a26946SRichard Henderson s->pool_labels = NULL; 423357a26946SRichard Henderson #endif 42349ecefc84SRichard Henderson 4235fca8a500SRichard Henderson num_insns = -1; 423615fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 4237c45cb8bbSRichard Henderson TCGOpcode opc = op->opc; 4238b3db8758Sblueswir1 4239c896fe29Sbellard #ifdef CONFIG_PROFILER 4240d73415a3SStefan Hajnoczi qatomic_set(&prof->table_op_count[opc], prof->table_op_count[opc] + 1); 4241c896fe29Sbellard #endif 4242c45cb8bbSRichard Henderson 4243c896fe29Sbellard switch (opc) { 4244c896fe29Sbellard case INDEX_op_mov_i32: 4245c896fe29Sbellard case INDEX_op_mov_i64: 4246d2fd745fSRichard Henderson case INDEX_op_mov_vec: 4247dd186292SRichard Henderson tcg_reg_alloc_mov(s, op); 4248c896fe29Sbellard break; 4249e8996ee0Sbellard case INDEX_op_movi_i32: 4250e8996ee0Sbellard case INDEX_op_movi_i64: 4251d2fd745fSRichard Henderson case INDEX_op_dupi_vec: 4252dd186292SRichard Henderson tcg_reg_alloc_movi(s, op); 4253e8996ee0Sbellard break; 4254bab1671fSRichard Henderson case INDEX_op_dup_vec: 4255bab1671fSRichard Henderson tcg_reg_alloc_dup(s, op); 4256bab1671fSRichard Henderson break; 4257765b842aSRichard Henderson case INDEX_op_insn_start: 4258fca8a500SRichard Henderson if (num_insns >= 0) { 42599f754620SRichard Henderson size_t off = tcg_current_code_size(s); 42609f754620SRichard Henderson s->gen_insn_end_off[num_insns] = off; 42619f754620SRichard Henderson /* Assert that we do not overflow our stored offset. */ 42629f754620SRichard Henderson assert(s->gen_insn_end_off[num_insns] == off); 4263fca8a500SRichard Henderson } 4264fca8a500SRichard Henderson num_insns++; 4265bad729e2SRichard Henderson for (i = 0; i < TARGET_INSN_START_WORDS; ++i) { 4266bad729e2SRichard Henderson target_ulong a; 4267bad729e2SRichard Henderson #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS 4268efee3746SRichard Henderson a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]); 4269bad729e2SRichard Henderson #else 4270efee3746SRichard Henderson a = op->args[i]; 4271bad729e2SRichard Henderson #endif 4272fca8a500SRichard Henderson s->gen_insn_data[num_insns][i] = a; 4273bad729e2SRichard Henderson } 4274c896fe29Sbellard break; 42755ff9d6a4Sbellard case INDEX_op_discard: 427643439139SRichard Henderson temp_dead(s, arg_temp(op->args[0])); 42775ff9d6a4Sbellard break; 4278c896fe29Sbellard case INDEX_op_set_label: 4279e8996ee0Sbellard tcg_reg_alloc_bb_end(s, s->reserved_regs); 4280efee3746SRichard Henderson tcg_out_label(s, arg_label(op->args[0]), s->code_ptr); 4281c896fe29Sbellard break; 4282c896fe29Sbellard case INDEX_op_call: 4283dd186292SRichard Henderson tcg_reg_alloc_call(s, op); 4284c45cb8bbSRichard Henderson break; 4285c896fe29Sbellard default: 428625c4d9ccSRichard Henderson /* Sanity check that we've not introduced any unhandled opcodes. */ 4287be0f34b5SRichard Henderson tcg_debug_assert(tcg_op_supported(opc)); 4288c896fe29Sbellard /* Note: in order to speed up the code, it would be much 4289c896fe29Sbellard faster to have specialized register allocator functions for 4290c896fe29Sbellard some common argument patterns */ 4291dd186292SRichard Henderson tcg_reg_alloc_op(s, op); 4292c896fe29Sbellard break; 4293c896fe29Sbellard } 42948d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG 4295c896fe29Sbellard check_regs(s); 4296c896fe29Sbellard #endif 4297b125f9dcSRichard Henderson /* Test for (pending) buffer overflow. The assumption is that any 4298b125f9dcSRichard Henderson one operation beginning below the high water mark cannot overrun 4299b125f9dcSRichard Henderson the buffer completely. Thus we can test for overflow after 4300b125f9dcSRichard Henderson generating code without having to check during generation. */ 4301644da9b3SJohn Clarke if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) { 4302b125f9dcSRichard Henderson return -1; 4303b125f9dcSRichard Henderson } 43046e6c4efeSRichard Henderson /* Test for TB overflow, as seen by gen_insn_end_off. */ 43056e6c4efeSRichard Henderson if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) { 43066e6c4efeSRichard Henderson return -2; 43076e6c4efeSRichard Henderson } 4308c896fe29Sbellard } 4309fca8a500SRichard Henderson tcg_debug_assert(num_insns >= 0); 4310fca8a500SRichard Henderson s->gen_insn_end_off[num_insns] = tcg_current_code_size(s); 4311c45cb8bbSRichard Henderson 4312b76f0d8cSYeongkyoon Lee /* Generate TB finalization at the end of block */ 4313659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS 4314aeee05f5SRichard Henderson i = tcg_out_ldst_finalize(s); 4315aeee05f5SRichard Henderson if (i < 0) { 4316aeee05f5SRichard Henderson return i; 431723dceda6SRichard Henderson } 4318659ef5cbSRichard Henderson #endif 431957a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 43201768987bSRichard Henderson i = tcg_out_pool_finalize(s); 43211768987bSRichard Henderson if (i < 0) { 43221768987bSRichard Henderson return i; 432357a26946SRichard Henderson } 432457a26946SRichard Henderson #endif 43257ecd02a0SRichard Henderson if (!tcg_resolve_relocs(s)) { 43267ecd02a0SRichard Henderson return -2; 43277ecd02a0SRichard Henderson } 4328c896fe29Sbellard 4329*df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 4330c896fe29Sbellard /* flush instruction cache */ 43311813e175SRichard Henderson flush_icache_range((uintptr_t)s->code_buf, (uintptr_t)s->code_ptr); 4332*df5d2b16SRichard Henderson #endif 43332aeabc08SStefan Weil 43341813e175SRichard Henderson return tcg_current_code_size(s); 4335c896fe29Sbellard } 4336c896fe29Sbellard 4337a23a9ec6Sbellard #ifdef CONFIG_PROFILER 43383de2faa9SMarkus Armbruster void tcg_dump_info(void) 4339a23a9ec6Sbellard { 4340c3fac113SEmilio G. Cota TCGProfile prof = {}; 4341c3fac113SEmilio G. Cota const TCGProfile *s; 4342c3fac113SEmilio G. Cota int64_t tb_count; 4343c3fac113SEmilio G. Cota int64_t tb_div_count; 4344c3fac113SEmilio G. Cota int64_t tot; 4345c3fac113SEmilio G. Cota 4346c3fac113SEmilio G. Cota tcg_profile_snapshot_counters(&prof); 4347c3fac113SEmilio G. Cota s = &prof; 4348c3fac113SEmilio G. Cota tb_count = s->tb_count; 4349c3fac113SEmilio G. Cota tb_div_count = tb_count ? tb_count : 1; 4350c3fac113SEmilio G. Cota tot = s->interm_time + s->code_time; 4351a23a9ec6Sbellard 43523de2faa9SMarkus Armbruster qemu_printf("JIT cycles %" PRId64 " (%0.3f s at 2.4 GHz)\n", 4353a23a9ec6Sbellard tot, tot / 2.4e9); 43543de2faa9SMarkus Armbruster qemu_printf("translated TBs %" PRId64 " (aborted=%" PRId64 43553de2faa9SMarkus Armbruster " %0.1f%%)\n", 4356fca8a500SRichard Henderson tb_count, s->tb_count1 - tb_count, 4357fca8a500SRichard Henderson (double)(s->tb_count1 - s->tb_count) 4358fca8a500SRichard Henderson / (s->tb_count1 ? s->tb_count1 : 1) * 100.0); 43593de2faa9SMarkus Armbruster qemu_printf("avg ops/TB %0.1f max=%d\n", 4360fca8a500SRichard Henderson (double)s->op_count / tb_div_count, s->op_count_max); 43613de2faa9SMarkus Armbruster qemu_printf("deleted ops/TB %0.2f\n", 4362fca8a500SRichard Henderson (double)s->del_op_count / tb_div_count); 43633de2faa9SMarkus Armbruster qemu_printf("avg temps/TB %0.2f max=%d\n", 4364fca8a500SRichard Henderson (double)s->temp_count / tb_div_count, s->temp_count_max); 43653de2faa9SMarkus Armbruster qemu_printf("avg host code/TB %0.1f\n", 4366fca8a500SRichard Henderson (double)s->code_out_len / tb_div_count); 43673de2faa9SMarkus Armbruster qemu_printf("avg search data/TB %0.1f\n", 4368fca8a500SRichard Henderson (double)s->search_out_len / tb_div_count); 4369a23a9ec6Sbellard 43703de2faa9SMarkus Armbruster qemu_printf("cycles/op %0.1f\n", 4371a23a9ec6Sbellard s->op_count ? (double)tot / s->op_count : 0); 43723de2faa9SMarkus Armbruster qemu_printf("cycles/in byte %0.1f\n", 4373a23a9ec6Sbellard s->code_in_len ? (double)tot / s->code_in_len : 0); 43743de2faa9SMarkus Armbruster qemu_printf("cycles/out byte %0.1f\n", 4375a23a9ec6Sbellard s->code_out_len ? (double)tot / s->code_out_len : 0); 43763de2faa9SMarkus Armbruster qemu_printf("cycles/search byte %0.1f\n", 4377fca8a500SRichard Henderson s->search_out_len ? (double)tot / s->search_out_len : 0); 4378fca8a500SRichard Henderson if (tot == 0) { 4379a23a9ec6Sbellard tot = 1; 4380fca8a500SRichard Henderson } 43813de2faa9SMarkus Armbruster qemu_printf(" gen_interm time %0.1f%%\n", 4382a23a9ec6Sbellard (double)s->interm_time / tot * 100.0); 43833de2faa9SMarkus Armbruster qemu_printf(" gen_code time %0.1f%%\n", 4384a23a9ec6Sbellard (double)s->code_time / tot * 100.0); 43853de2faa9SMarkus Armbruster qemu_printf("optim./code time %0.1f%%\n", 4386c5cc28ffSAurelien Jarno (double)s->opt_time / (s->code_time ? s->code_time : 1) 4387c5cc28ffSAurelien Jarno * 100.0); 43883de2faa9SMarkus Armbruster qemu_printf("liveness/code time %0.1f%%\n", 4389a23a9ec6Sbellard (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0); 43903de2faa9SMarkus Armbruster qemu_printf("cpu_restore count %" PRId64 "\n", 4391a23a9ec6Sbellard s->restore_count); 43923de2faa9SMarkus Armbruster qemu_printf(" avg cycles %0.1f\n", 4393a23a9ec6Sbellard s->restore_count ? (double)s->restore_time / s->restore_count : 0); 4394a23a9ec6Sbellard } 4395a23a9ec6Sbellard #else 43963de2faa9SMarkus Armbruster void tcg_dump_info(void) 4397a23a9ec6Sbellard { 43983de2faa9SMarkus Armbruster qemu_printf("[TCG profiler not compiled]\n"); 4399a23a9ec6Sbellard } 4400a23a9ec6Sbellard #endif 4401813da627SRichard Henderson 4402813da627SRichard Henderson #ifdef ELF_HOST_MACHINE 44035872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things: 44045872bbf2SRichard Henderson 44055872bbf2SRichard Henderson (1) Define ELF_HOST_MACHINE to indicate both what value to 44065872bbf2SRichard Henderson put into the ELF image and to indicate support for the feature. 44075872bbf2SRichard Henderson 44085872bbf2SRichard Henderson (2) Define tcg_register_jit. This should create a buffer containing 44095872bbf2SRichard Henderson the contents of a .debug_frame section that describes the post- 44105872bbf2SRichard Henderson prologue unwind info for the tcg machine. 44115872bbf2SRichard Henderson 44125872bbf2SRichard Henderson (3) Call tcg_register_jit_int, with the constructed .debug_frame. 44135872bbf2SRichard Henderson */ 4414813da627SRichard Henderson 4415813da627SRichard Henderson /* Begin GDB interface. THE FOLLOWING MUST MATCH GDB DOCS. */ 4416813da627SRichard Henderson typedef enum { 4417813da627SRichard Henderson JIT_NOACTION = 0, 4418813da627SRichard Henderson JIT_REGISTER_FN, 4419813da627SRichard Henderson JIT_UNREGISTER_FN 4420813da627SRichard Henderson } jit_actions_t; 4421813da627SRichard Henderson 4422813da627SRichard Henderson struct jit_code_entry { 4423813da627SRichard Henderson struct jit_code_entry *next_entry; 4424813da627SRichard Henderson struct jit_code_entry *prev_entry; 4425813da627SRichard Henderson const void *symfile_addr; 4426813da627SRichard Henderson uint64_t symfile_size; 4427813da627SRichard Henderson }; 4428813da627SRichard Henderson 4429813da627SRichard Henderson struct jit_descriptor { 4430813da627SRichard Henderson uint32_t version; 4431813da627SRichard Henderson uint32_t action_flag; 4432813da627SRichard Henderson struct jit_code_entry *relevant_entry; 4433813da627SRichard Henderson struct jit_code_entry *first_entry; 4434813da627SRichard Henderson }; 4435813da627SRichard Henderson 4436813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline)); 4437813da627SRichard Henderson void __jit_debug_register_code(void) 4438813da627SRichard Henderson { 4439813da627SRichard Henderson asm(""); 4440813da627SRichard Henderson } 4441813da627SRichard Henderson 4442813da627SRichard Henderson /* Must statically initialize the version, because GDB may check 4443813da627SRichard Henderson the version before we can set it. */ 4444813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 }; 4445813da627SRichard Henderson 4446813da627SRichard Henderson /* End GDB interface. */ 4447813da627SRichard Henderson 4448813da627SRichard Henderson static int find_string(const char *strtab, const char *str) 4449813da627SRichard Henderson { 4450813da627SRichard Henderson const char *p = strtab + 1; 4451813da627SRichard Henderson 4452813da627SRichard Henderson while (1) { 4453813da627SRichard Henderson if (strcmp(p, str) == 0) { 4454813da627SRichard Henderson return p - strtab; 4455813da627SRichard Henderson } 4456813da627SRichard Henderson p += strlen(p) + 1; 4457813da627SRichard Henderson } 4458813da627SRichard Henderson } 4459813da627SRichard Henderson 44605872bbf2SRichard Henderson static void tcg_register_jit_int(void *buf_ptr, size_t buf_size, 44612c90784aSRichard Henderson const void *debug_frame, 44622c90784aSRichard Henderson size_t debug_frame_size) 4463813da627SRichard Henderson { 44645872bbf2SRichard Henderson struct __attribute__((packed)) DebugInfo { 44655872bbf2SRichard Henderson uint32_t len; 44665872bbf2SRichard Henderson uint16_t version; 44675872bbf2SRichard Henderson uint32_t abbrev; 44685872bbf2SRichard Henderson uint8_t ptr_size; 44695872bbf2SRichard Henderson uint8_t cu_die; 44705872bbf2SRichard Henderson uint16_t cu_lang; 44715872bbf2SRichard Henderson uintptr_t cu_low_pc; 44725872bbf2SRichard Henderson uintptr_t cu_high_pc; 44735872bbf2SRichard Henderson uint8_t fn_die; 44745872bbf2SRichard Henderson char fn_name[16]; 44755872bbf2SRichard Henderson uintptr_t fn_low_pc; 44765872bbf2SRichard Henderson uintptr_t fn_high_pc; 44775872bbf2SRichard Henderson uint8_t cu_eoc; 44785872bbf2SRichard Henderson }; 4479813da627SRichard Henderson 4480813da627SRichard Henderson struct ElfImage { 4481813da627SRichard Henderson ElfW(Ehdr) ehdr; 4482813da627SRichard Henderson ElfW(Phdr) phdr; 44835872bbf2SRichard Henderson ElfW(Shdr) shdr[7]; 44845872bbf2SRichard Henderson ElfW(Sym) sym[2]; 44855872bbf2SRichard Henderson struct DebugInfo di; 44865872bbf2SRichard Henderson uint8_t da[24]; 44875872bbf2SRichard Henderson char str[80]; 44885872bbf2SRichard Henderson }; 44895872bbf2SRichard Henderson 44905872bbf2SRichard Henderson struct ElfImage *img; 44915872bbf2SRichard Henderson 44925872bbf2SRichard Henderson static const struct ElfImage img_template = { 44935872bbf2SRichard Henderson .ehdr = { 44945872bbf2SRichard Henderson .e_ident[EI_MAG0] = ELFMAG0, 44955872bbf2SRichard Henderson .e_ident[EI_MAG1] = ELFMAG1, 44965872bbf2SRichard Henderson .e_ident[EI_MAG2] = ELFMAG2, 44975872bbf2SRichard Henderson .e_ident[EI_MAG3] = ELFMAG3, 44985872bbf2SRichard Henderson .e_ident[EI_CLASS] = ELF_CLASS, 44995872bbf2SRichard Henderson .e_ident[EI_DATA] = ELF_DATA, 45005872bbf2SRichard Henderson .e_ident[EI_VERSION] = EV_CURRENT, 45015872bbf2SRichard Henderson .e_type = ET_EXEC, 45025872bbf2SRichard Henderson .e_machine = ELF_HOST_MACHINE, 45035872bbf2SRichard Henderson .e_version = EV_CURRENT, 45045872bbf2SRichard Henderson .e_phoff = offsetof(struct ElfImage, phdr), 45055872bbf2SRichard Henderson .e_shoff = offsetof(struct ElfImage, shdr), 45065872bbf2SRichard Henderson .e_ehsize = sizeof(ElfW(Shdr)), 45075872bbf2SRichard Henderson .e_phentsize = sizeof(ElfW(Phdr)), 45085872bbf2SRichard Henderson .e_phnum = 1, 45095872bbf2SRichard Henderson .e_shentsize = sizeof(ElfW(Shdr)), 45105872bbf2SRichard Henderson .e_shnum = ARRAY_SIZE(img->shdr), 45115872bbf2SRichard Henderson .e_shstrndx = ARRAY_SIZE(img->shdr) - 1, 4512abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS 4513abbb3eaeSRichard Henderson .e_flags = ELF_HOST_FLAGS, 4514abbb3eaeSRichard Henderson #endif 4515abbb3eaeSRichard Henderson #ifdef ELF_OSABI 4516abbb3eaeSRichard Henderson .e_ident[EI_OSABI] = ELF_OSABI, 4517abbb3eaeSRichard Henderson #endif 45185872bbf2SRichard Henderson }, 45195872bbf2SRichard Henderson .phdr = { 45205872bbf2SRichard Henderson .p_type = PT_LOAD, 45215872bbf2SRichard Henderson .p_flags = PF_X, 45225872bbf2SRichard Henderson }, 45235872bbf2SRichard Henderson .shdr = { 45245872bbf2SRichard Henderson [0] = { .sh_type = SHT_NULL }, 45255872bbf2SRichard Henderson /* Trick: The contents of code_gen_buffer are not present in 45265872bbf2SRichard Henderson this fake ELF file; that got allocated elsewhere. Therefore 45275872bbf2SRichard Henderson we mark .text as SHT_NOBITS (similar to .bss) so that readers 45285872bbf2SRichard Henderson will not look for contents. We can record any address. */ 45295872bbf2SRichard Henderson [1] = { /* .text */ 45305872bbf2SRichard Henderson .sh_type = SHT_NOBITS, 45315872bbf2SRichard Henderson .sh_flags = SHF_EXECINSTR | SHF_ALLOC, 45325872bbf2SRichard Henderson }, 45335872bbf2SRichard Henderson [2] = { /* .debug_info */ 45345872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 45355872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, di), 45365872bbf2SRichard Henderson .sh_size = sizeof(struct DebugInfo), 45375872bbf2SRichard Henderson }, 45385872bbf2SRichard Henderson [3] = { /* .debug_abbrev */ 45395872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 45405872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, da), 45415872bbf2SRichard Henderson .sh_size = sizeof(img->da), 45425872bbf2SRichard Henderson }, 45435872bbf2SRichard Henderson [4] = { /* .debug_frame */ 45445872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 45455872bbf2SRichard Henderson .sh_offset = sizeof(struct ElfImage), 45465872bbf2SRichard Henderson }, 45475872bbf2SRichard Henderson [5] = { /* .symtab */ 45485872bbf2SRichard Henderson .sh_type = SHT_SYMTAB, 45495872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, sym), 45505872bbf2SRichard Henderson .sh_size = sizeof(img->sym), 45515872bbf2SRichard Henderson .sh_info = 1, 45525872bbf2SRichard Henderson .sh_link = ARRAY_SIZE(img->shdr) - 1, 45535872bbf2SRichard Henderson .sh_entsize = sizeof(ElfW(Sym)), 45545872bbf2SRichard Henderson }, 45555872bbf2SRichard Henderson [6] = { /* .strtab */ 45565872bbf2SRichard Henderson .sh_type = SHT_STRTAB, 45575872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, str), 45585872bbf2SRichard Henderson .sh_size = sizeof(img->str), 45595872bbf2SRichard Henderson } 45605872bbf2SRichard Henderson }, 45615872bbf2SRichard Henderson .sym = { 45625872bbf2SRichard Henderson [1] = { /* code_gen_buffer */ 45635872bbf2SRichard Henderson .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC), 45645872bbf2SRichard Henderson .st_shndx = 1, 45655872bbf2SRichard Henderson } 45665872bbf2SRichard Henderson }, 45675872bbf2SRichard Henderson .di = { 45685872bbf2SRichard Henderson .len = sizeof(struct DebugInfo) - 4, 45695872bbf2SRichard Henderson .version = 2, 45705872bbf2SRichard Henderson .ptr_size = sizeof(void *), 45715872bbf2SRichard Henderson .cu_die = 1, 45725872bbf2SRichard Henderson .cu_lang = 0x8001, /* DW_LANG_Mips_Assembler */ 45735872bbf2SRichard Henderson .fn_die = 2, 45745872bbf2SRichard Henderson .fn_name = "code_gen_buffer" 45755872bbf2SRichard Henderson }, 45765872bbf2SRichard Henderson .da = { 45775872bbf2SRichard Henderson 1, /* abbrev number (the cu) */ 45785872bbf2SRichard Henderson 0x11, 1, /* DW_TAG_compile_unit, has children */ 45795872bbf2SRichard Henderson 0x13, 0x5, /* DW_AT_language, DW_FORM_data2 */ 45805872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */ 45815872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */ 45825872bbf2SRichard Henderson 0, 0, /* end of abbrev */ 45835872bbf2SRichard Henderson 2, /* abbrev number (the fn) */ 45845872bbf2SRichard Henderson 0x2e, 0, /* DW_TAG_subprogram, no children */ 45855872bbf2SRichard Henderson 0x3, 0x8, /* DW_AT_name, DW_FORM_string */ 45865872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */ 45875872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */ 45885872bbf2SRichard Henderson 0, 0, /* end of abbrev */ 45895872bbf2SRichard Henderson 0 /* no more abbrev */ 45905872bbf2SRichard Henderson }, 45915872bbf2SRichard Henderson .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0" 45925872bbf2SRichard Henderson ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer", 4593813da627SRichard Henderson }; 4594813da627SRichard Henderson 4595813da627SRichard Henderson /* We only need a single jit entry; statically allocate it. */ 4596813da627SRichard Henderson static struct jit_code_entry one_entry; 4597813da627SRichard Henderson 45985872bbf2SRichard Henderson uintptr_t buf = (uintptr_t)buf_ptr; 4599813da627SRichard Henderson size_t img_size = sizeof(struct ElfImage) + debug_frame_size; 46002c90784aSRichard Henderson DebugFrameHeader *dfh; 4601813da627SRichard Henderson 46025872bbf2SRichard Henderson img = g_malloc(img_size); 46035872bbf2SRichard Henderson *img = img_template; 4604813da627SRichard Henderson 46055872bbf2SRichard Henderson img->phdr.p_vaddr = buf; 46065872bbf2SRichard Henderson img->phdr.p_paddr = buf; 46075872bbf2SRichard Henderson img->phdr.p_memsz = buf_size; 4608813da627SRichard Henderson 46095872bbf2SRichard Henderson img->shdr[1].sh_name = find_string(img->str, ".text"); 46105872bbf2SRichard Henderson img->shdr[1].sh_addr = buf; 46115872bbf2SRichard Henderson img->shdr[1].sh_size = buf_size; 4612813da627SRichard Henderson 46135872bbf2SRichard Henderson img->shdr[2].sh_name = find_string(img->str, ".debug_info"); 46145872bbf2SRichard Henderson img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev"); 46155872bbf2SRichard Henderson 46165872bbf2SRichard Henderson img->shdr[4].sh_name = find_string(img->str, ".debug_frame"); 46175872bbf2SRichard Henderson img->shdr[4].sh_size = debug_frame_size; 46185872bbf2SRichard Henderson 46195872bbf2SRichard Henderson img->shdr[5].sh_name = find_string(img->str, ".symtab"); 46205872bbf2SRichard Henderson img->shdr[6].sh_name = find_string(img->str, ".strtab"); 46215872bbf2SRichard Henderson 46225872bbf2SRichard Henderson img->sym[1].st_name = find_string(img->str, "code_gen_buffer"); 46235872bbf2SRichard Henderson img->sym[1].st_value = buf; 46245872bbf2SRichard Henderson img->sym[1].st_size = buf_size; 46255872bbf2SRichard Henderson 46265872bbf2SRichard Henderson img->di.cu_low_pc = buf; 462745aba097SRichard Henderson img->di.cu_high_pc = buf + buf_size; 46285872bbf2SRichard Henderson img->di.fn_low_pc = buf; 462945aba097SRichard Henderson img->di.fn_high_pc = buf + buf_size; 4630813da627SRichard Henderson 46312c90784aSRichard Henderson dfh = (DebugFrameHeader *)(img + 1); 46322c90784aSRichard Henderson memcpy(dfh, debug_frame, debug_frame_size); 46332c90784aSRichard Henderson dfh->fde.func_start = buf; 46342c90784aSRichard Henderson dfh->fde.func_len = buf_size; 46352c90784aSRichard Henderson 4636813da627SRichard Henderson #ifdef DEBUG_JIT 4637813da627SRichard Henderson /* Enable this block to be able to debug the ELF image file creation. 4638813da627SRichard Henderson One can use readelf, objdump, or other inspection utilities. */ 4639813da627SRichard Henderson { 4640813da627SRichard Henderson FILE *f = fopen("/tmp/qemu.jit", "w+b"); 4641813da627SRichard Henderson if (f) { 46425872bbf2SRichard Henderson if (fwrite(img, img_size, 1, f) != img_size) { 4643813da627SRichard Henderson /* Avoid stupid unused return value warning for fwrite. */ 4644813da627SRichard Henderson } 4645813da627SRichard Henderson fclose(f); 4646813da627SRichard Henderson } 4647813da627SRichard Henderson } 4648813da627SRichard Henderson #endif 4649813da627SRichard Henderson 4650813da627SRichard Henderson one_entry.symfile_addr = img; 4651813da627SRichard Henderson one_entry.symfile_size = img_size; 4652813da627SRichard Henderson 4653813da627SRichard Henderson __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; 4654813da627SRichard Henderson __jit_debug_descriptor.relevant_entry = &one_entry; 4655813da627SRichard Henderson __jit_debug_descriptor.first_entry = &one_entry; 4656813da627SRichard Henderson __jit_debug_register_code(); 4657813da627SRichard Henderson } 4658813da627SRichard Henderson #else 46595872bbf2SRichard Henderson /* No support for the feature. Provide the entry point expected by exec.c, 46605872bbf2SRichard Henderson and implement the internal function we declared earlier. */ 4661813da627SRichard Henderson 4662813da627SRichard Henderson static void tcg_register_jit_int(void *buf, size_t size, 46632c90784aSRichard Henderson const void *debug_frame, 46642c90784aSRichard Henderson size_t debug_frame_size) 4665813da627SRichard Henderson { 4666813da627SRichard Henderson } 4667813da627SRichard Henderson 4668813da627SRichard Henderson void tcg_register_jit(void *buf, size_t buf_size) 4669813da627SRichard Henderson { 4670813da627SRichard Henderson } 4671813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */ 4672db432672SRichard Henderson 4673db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec 4674db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...) 4675db432672SRichard Henderson { 4676db432672SRichard Henderson g_assert_not_reached(); 4677db432672SRichard Henderson } 4678db432672SRichard Henderson #endif 4679