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 100755bf9e5SRichard Henderson static void tcg_register_jit_int(const 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); 1522be7d76bSRichard Henderson static void tcg_out_call(TCGContext *s, const 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; 164*c8bc1168SRichard Henderson const void *tcg_code_gen_epilogue; 165db0c51a3SRichard Henderson uintptr_t tcg_splitwx_diff; 166df2cce29SEmilio G. Cota 167b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 168b91ccb31SRichard Henderson tcg_prologue_fn *tcg_qemu_tb_exec; 169b91ccb31SRichard Henderson #endif 170b91ccb31SRichard Henderson 171be2cdc5eSEmilio G. Cota struct tcg_region_tree { 172be2cdc5eSEmilio G. Cota QemuMutex lock; 173be2cdc5eSEmilio G. Cota GTree *tree; 174be2cdc5eSEmilio G. Cota /* padding to avoid false sharing is computed at run-time */ 175be2cdc5eSEmilio G. Cota }; 176be2cdc5eSEmilio G. Cota 177e8feb96fSEmilio G. Cota /* 178e8feb96fSEmilio G. Cota * We divide code_gen_buffer into equally-sized "regions" that TCG threads 179e8feb96fSEmilio G. Cota * dynamically allocate from as demand dictates. Given appropriate region 180e8feb96fSEmilio G. Cota * sizing, this minimizes flushes even when some TCG threads generate a lot 181e8feb96fSEmilio G. Cota * more code than others. 182e8feb96fSEmilio G. Cota */ 183e8feb96fSEmilio G. Cota struct tcg_region_state { 184e8feb96fSEmilio G. Cota QemuMutex lock; 185e8feb96fSEmilio G. Cota 186e8feb96fSEmilio G. Cota /* fields set at init time */ 187e8feb96fSEmilio G. Cota void *start; 188e8feb96fSEmilio G. Cota void *start_aligned; 189e8feb96fSEmilio G. Cota void *end; 190e8feb96fSEmilio G. Cota size_t n; 191e8feb96fSEmilio G. Cota size_t size; /* size of one region */ 192e8feb96fSEmilio G. Cota size_t stride; /* .size + guard size */ 193e8feb96fSEmilio G. Cota 194e8feb96fSEmilio G. Cota /* fields protected by the lock */ 195e8feb96fSEmilio G. Cota size_t current; /* current region index */ 196e8feb96fSEmilio G. Cota size_t agg_size_full; /* aggregate size of full regions */ 197e8feb96fSEmilio G. Cota }; 198e8feb96fSEmilio G. Cota 199e8feb96fSEmilio G. Cota static struct tcg_region_state region; 200be2cdc5eSEmilio G. Cota /* 201be2cdc5eSEmilio G. Cota * This is an array of struct tcg_region_tree's, with padding. 202be2cdc5eSEmilio G. Cota * We use void * to simplify the computation of region_trees[i]; each 203be2cdc5eSEmilio G. Cota * struct is found every tree_size bytes. 204be2cdc5eSEmilio G. Cota */ 205be2cdc5eSEmilio G. Cota static void *region_trees; 206be2cdc5eSEmilio G. Cota static size_t tree_size; 207d2fd745fSRichard Henderson static TCGRegSet tcg_target_available_regs[TCG_TYPE_COUNT]; 208b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs; 209c896fe29Sbellard 2101813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1 2114196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v) 212c896fe29Sbellard { 213c896fe29Sbellard *s->code_ptr++ = v; 214c896fe29Sbellard } 215c896fe29Sbellard 2164196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p, 2174196dca6SPeter Maydell uint8_t v) 2185c53bb81SPeter Maydell { 2191813e175SRichard Henderson *p = v; 2205c53bb81SPeter Maydell } 2211813e175SRichard Henderson #endif 2225c53bb81SPeter Maydell 2231813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2 2244196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v) 225c896fe29Sbellard { 2261813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 2) { 2271813e175SRichard Henderson *s->code_ptr++ = v; 2281813e175SRichard Henderson } else { 2291813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 2304387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 2311813e175SRichard Henderson s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE); 2321813e175SRichard Henderson } 233c896fe29Sbellard } 234c896fe29Sbellard 2354196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p, 2364196dca6SPeter Maydell uint16_t v) 2375c53bb81SPeter Maydell { 2381813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 2) { 2391813e175SRichard Henderson *p = v; 2401813e175SRichard Henderson } else { 2415c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 2425c53bb81SPeter Maydell } 2431813e175SRichard Henderson } 2441813e175SRichard Henderson #endif 2455c53bb81SPeter Maydell 2461813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4 2474196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v) 248c896fe29Sbellard { 2491813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 4) { 2501813e175SRichard Henderson *s->code_ptr++ = v; 2511813e175SRichard Henderson } else { 2521813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 2534387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 2541813e175SRichard Henderson s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE); 2551813e175SRichard Henderson } 256c896fe29Sbellard } 257c896fe29Sbellard 2584196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p, 2594196dca6SPeter Maydell uint32_t v) 2605c53bb81SPeter Maydell { 2611813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 4) { 2621813e175SRichard Henderson *p = v; 2631813e175SRichard Henderson } else { 2645c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 2655c53bb81SPeter Maydell } 2661813e175SRichard Henderson } 2671813e175SRichard Henderson #endif 2685c53bb81SPeter Maydell 2691813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 8 2704196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v) 271ac26eb69SRichard Henderson { 2721813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 8) { 2731813e175SRichard Henderson *s->code_ptr++ = v; 2741813e175SRichard Henderson } else { 2751813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 2764387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 2771813e175SRichard Henderson s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE); 2781813e175SRichard Henderson } 279ac26eb69SRichard Henderson } 280ac26eb69SRichard Henderson 2814196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p, 2824196dca6SPeter Maydell uint64_t v) 2835c53bb81SPeter Maydell { 2841813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 8) { 2851813e175SRichard Henderson *p = v; 2861813e175SRichard Henderson } else { 2875c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 2885c53bb81SPeter Maydell } 2891813e175SRichard Henderson } 2901813e175SRichard Henderson #endif 2915c53bb81SPeter Maydell 292c896fe29Sbellard /* label relocation processing */ 293c896fe29Sbellard 2941813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type, 295bec16311SRichard Henderson TCGLabel *l, intptr_t addend) 296c896fe29Sbellard { 2977ecd02a0SRichard Henderson TCGRelocation *r = tcg_malloc(sizeof(TCGRelocation)); 298c896fe29Sbellard 299c896fe29Sbellard r->type = type; 300c896fe29Sbellard r->ptr = code_ptr; 301c896fe29Sbellard r->addend = addend; 3027ecd02a0SRichard Henderson QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next); 303c896fe29Sbellard } 304c896fe29Sbellard 30592ab8e7dSRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l) 306c896fe29Sbellard { 307eabb7b91SAurelien Jarno tcg_debug_assert(!l->has_value); 308c896fe29Sbellard l->has_value = 1; 30992ab8e7dSRichard Henderson l->u.value_ptr = tcg_splitwx_to_rx(s->code_ptr); 310c896fe29Sbellard } 311c896fe29Sbellard 31242a268c2SRichard Henderson TCGLabel *gen_new_label(void) 313c896fe29Sbellard { 314b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 31551e3972cSRichard Henderson TCGLabel *l = tcg_malloc(sizeof(TCGLabel)); 316c896fe29Sbellard 3177ecd02a0SRichard Henderson memset(l, 0, sizeof(TCGLabel)); 3187ecd02a0SRichard Henderson l->id = s->nb_labels++; 3197ecd02a0SRichard Henderson QSIMPLEQ_INIT(&l->relocs); 3207ecd02a0SRichard Henderson 321bef16ab4SRichard Henderson QSIMPLEQ_INSERT_TAIL(&s->labels, l, next); 32242a268c2SRichard Henderson 32342a268c2SRichard Henderson return l; 324c896fe29Sbellard } 325c896fe29Sbellard 3267ecd02a0SRichard Henderson static bool tcg_resolve_relocs(TCGContext *s) 3277ecd02a0SRichard Henderson { 3287ecd02a0SRichard Henderson TCGLabel *l; 3297ecd02a0SRichard Henderson 3307ecd02a0SRichard Henderson QSIMPLEQ_FOREACH(l, &s->labels, next) { 3317ecd02a0SRichard Henderson TCGRelocation *r; 3327ecd02a0SRichard Henderson uintptr_t value = l->u.value; 3337ecd02a0SRichard Henderson 3347ecd02a0SRichard Henderson QSIMPLEQ_FOREACH(r, &l->relocs, next) { 3357ecd02a0SRichard Henderson if (!patch_reloc(r->ptr, r->type, value, r->addend)) { 3367ecd02a0SRichard Henderson return false; 3377ecd02a0SRichard Henderson } 3387ecd02a0SRichard Henderson } 3397ecd02a0SRichard Henderson } 3407ecd02a0SRichard Henderson return true; 3417ecd02a0SRichard Henderson } 3427ecd02a0SRichard Henderson 3439f754620SRichard Henderson static void set_jmp_reset_offset(TCGContext *s, int which) 3449f754620SRichard Henderson { 345f14bed3fSRichard Henderson /* 346f14bed3fSRichard Henderson * We will check for overflow at the end of the opcode loop in 347f14bed3fSRichard Henderson * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX. 348f14bed3fSRichard Henderson */ 349f14bed3fSRichard Henderson s->tb_jmp_reset_offset[which] = tcg_current_code_size(s); 3509f754620SRichard Henderson } 3519f754620SRichard Henderson 352139c1837SPaolo Bonzini #include "tcg-target.c.inc" 353c896fe29Sbellard 354be2cdc5eSEmilio G. Cota /* compare a pointer @ptr and a tb_tc @s */ 355be2cdc5eSEmilio G. Cota static int ptr_cmp_tb_tc(const void *ptr, const struct tb_tc *s) 356be2cdc5eSEmilio G. Cota { 357be2cdc5eSEmilio G. Cota if (ptr >= s->ptr + s->size) { 358be2cdc5eSEmilio G. Cota return 1; 359be2cdc5eSEmilio G. Cota } else if (ptr < s->ptr) { 360be2cdc5eSEmilio G. Cota return -1; 361be2cdc5eSEmilio G. Cota } 362be2cdc5eSEmilio G. Cota return 0; 363be2cdc5eSEmilio G. Cota } 364be2cdc5eSEmilio G. Cota 365be2cdc5eSEmilio G. Cota static gint tb_tc_cmp(gconstpointer ap, gconstpointer bp) 366be2cdc5eSEmilio G. Cota { 367be2cdc5eSEmilio G. Cota const struct tb_tc *a = ap; 368be2cdc5eSEmilio G. Cota const struct tb_tc *b = bp; 369be2cdc5eSEmilio G. Cota 370be2cdc5eSEmilio G. Cota /* 371be2cdc5eSEmilio G. Cota * When both sizes are set, we know this isn't a lookup. 372be2cdc5eSEmilio G. Cota * This is the most likely case: every TB must be inserted; lookups 373be2cdc5eSEmilio G. Cota * are a lot less frequent. 374be2cdc5eSEmilio G. Cota */ 375be2cdc5eSEmilio G. Cota if (likely(a->size && b->size)) { 376be2cdc5eSEmilio G. Cota if (a->ptr > b->ptr) { 377be2cdc5eSEmilio G. Cota return 1; 378be2cdc5eSEmilio G. Cota } else if (a->ptr < b->ptr) { 379be2cdc5eSEmilio G. Cota return -1; 380be2cdc5eSEmilio G. Cota } 381be2cdc5eSEmilio G. Cota /* a->ptr == b->ptr should happen only on deletions */ 382be2cdc5eSEmilio G. Cota g_assert(a->size == b->size); 383be2cdc5eSEmilio G. Cota return 0; 384be2cdc5eSEmilio G. Cota } 385be2cdc5eSEmilio G. Cota /* 386be2cdc5eSEmilio G. Cota * All lookups have either .size field set to 0. 387be2cdc5eSEmilio G. Cota * From the glib sources we see that @ap is always the lookup key. However 388be2cdc5eSEmilio G. Cota * the docs provide no guarantee, so we just mark this case as likely. 389be2cdc5eSEmilio G. Cota */ 390be2cdc5eSEmilio G. Cota if (likely(a->size == 0)) { 391be2cdc5eSEmilio G. Cota return ptr_cmp_tb_tc(a->ptr, b); 392be2cdc5eSEmilio G. Cota } 393be2cdc5eSEmilio G. Cota return ptr_cmp_tb_tc(b->ptr, a); 394be2cdc5eSEmilio G. Cota } 395be2cdc5eSEmilio G. Cota 396be2cdc5eSEmilio G. Cota static void tcg_region_trees_init(void) 397be2cdc5eSEmilio G. Cota { 398be2cdc5eSEmilio G. Cota size_t i; 399be2cdc5eSEmilio G. Cota 400be2cdc5eSEmilio G. Cota tree_size = ROUND_UP(sizeof(struct tcg_region_tree), qemu_dcache_linesize); 401be2cdc5eSEmilio G. Cota region_trees = qemu_memalign(qemu_dcache_linesize, region.n * tree_size); 402be2cdc5eSEmilio G. Cota for (i = 0; i < region.n; i++) { 403be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = region_trees + i * tree_size; 404be2cdc5eSEmilio G. Cota 405be2cdc5eSEmilio G. Cota qemu_mutex_init(&rt->lock); 406be2cdc5eSEmilio G. Cota rt->tree = g_tree_new(tb_tc_cmp); 407be2cdc5eSEmilio G. Cota } 408be2cdc5eSEmilio G. Cota } 409be2cdc5eSEmilio G. Cota 410db0c51a3SRichard Henderson static struct tcg_region_tree *tc_ptr_to_region_tree(const void *cp) 411be2cdc5eSEmilio G. Cota { 412db0c51a3SRichard Henderson void *p = tcg_splitwx_to_rw(cp); 413be2cdc5eSEmilio G. Cota size_t region_idx; 414be2cdc5eSEmilio G. Cota 415be2cdc5eSEmilio G. Cota if (p < region.start_aligned) { 416be2cdc5eSEmilio G. Cota region_idx = 0; 417be2cdc5eSEmilio G. Cota } else { 418be2cdc5eSEmilio G. Cota ptrdiff_t offset = p - region.start_aligned; 419be2cdc5eSEmilio G. Cota 420be2cdc5eSEmilio G. Cota if (offset > region.stride * (region.n - 1)) { 421be2cdc5eSEmilio G. Cota region_idx = region.n - 1; 422be2cdc5eSEmilio G. Cota } else { 423be2cdc5eSEmilio G. Cota region_idx = offset / region.stride; 424be2cdc5eSEmilio G. Cota } 425be2cdc5eSEmilio G. Cota } 426be2cdc5eSEmilio G. Cota return region_trees + region_idx * tree_size; 427be2cdc5eSEmilio G. Cota } 428be2cdc5eSEmilio G. Cota 429be2cdc5eSEmilio G. Cota void tcg_tb_insert(TranslationBlock *tb) 430be2cdc5eSEmilio G. Cota { 431be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr); 432be2cdc5eSEmilio G. Cota 433be2cdc5eSEmilio G. Cota qemu_mutex_lock(&rt->lock); 434be2cdc5eSEmilio G. Cota g_tree_insert(rt->tree, &tb->tc, tb); 435be2cdc5eSEmilio G. Cota qemu_mutex_unlock(&rt->lock); 436be2cdc5eSEmilio G. Cota } 437be2cdc5eSEmilio G. Cota 438be2cdc5eSEmilio G. Cota void tcg_tb_remove(TranslationBlock *tb) 439be2cdc5eSEmilio G. Cota { 440be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr); 441be2cdc5eSEmilio G. Cota 442be2cdc5eSEmilio G. Cota qemu_mutex_lock(&rt->lock); 443be2cdc5eSEmilio G. Cota g_tree_remove(rt->tree, &tb->tc); 444be2cdc5eSEmilio G. Cota qemu_mutex_unlock(&rt->lock); 445be2cdc5eSEmilio G. Cota } 446be2cdc5eSEmilio G. Cota 447be2cdc5eSEmilio G. Cota /* 448be2cdc5eSEmilio G. Cota * Find the TB 'tb' such that 449be2cdc5eSEmilio G. Cota * tb->tc.ptr <= tc_ptr < tb->tc.ptr + tb->tc.size 450be2cdc5eSEmilio G. Cota * Return NULL if not found. 451be2cdc5eSEmilio G. Cota */ 452be2cdc5eSEmilio G. Cota TranslationBlock *tcg_tb_lookup(uintptr_t tc_ptr) 453be2cdc5eSEmilio G. Cota { 454be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = tc_ptr_to_region_tree((void *)tc_ptr); 455be2cdc5eSEmilio G. Cota TranslationBlock *tb; 456be2cdc5eSEmilio G. Cota struct tb_tc s = { .ptr = (void *)tc_ptr }; 457be2cdc5eSEmilio G. Cota 458be2cdc5eSEmilio G. Cota qemu_mutex_lock(&rt->lock); 459be2cdc5eSEmilio G. Cota tb = g_tree_lookup(rt->tree, &s); 460be2cdc5eSEmilio G. Cota qemu_mutex_unlock(&rt->lock); 461be2cdc5eSEmilio G. Cota return tb; 462be2cdc5eSEmilio G. Cota } 463be2cdc5eSEmilio G. Cota 464be2cdc5eSEmilio G. Cota static void tcg_region_tree_lock_all(void) 465be2cdc5eSEmilio G. Cota { 466be2cdc5eSEmilio G. Cota size_t i; 467be2cdc5eSEmilio G. Cota 468be2cdc5eSEmilio G. Cota for (i = 0; i < region.n; i++) { 469be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = region_trees + i * tree_size; 470be2cdc5eSEmilio G. Cota 471be2cdc5eSEmilio G. Cota qemu_mutex_lock(&rt->lock); 472be2cdc5eSEmilio G. Cota } 473be2cdc5eSEmilio G. Cota } 474be2cdc5eSEmilio G. Cota 475be2cdc5eSEmilio G. Cota static void tcg_region_tree_unlock_all(void) 476be2cdc5eSEmilio G. Cota { 477be2cdc5eSEmilio G. Cota size_t i; 478be2cdc5eSEmilio G. Cota 479be2cdc5eSEmilio G. Cota for (i = 0; i < region.n; i++) { 480be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = region_trees + i * tree_size; 481be2cdc5eSEmilio G. Cota 482be2cdc5eSEmilio G. Cota qemu_mutex_unlock(&rt->lock); 483be2cdc5eSEmilio G. Cota } 484be2cdc5eSEmilio G. Cota } 485be2cdc5eSEmilio G. Cota 486be2cdc5eSEmilio G. Cota void tcg_tb_foreach(GTraverseFunc func, gpointer user_data) 487be2cdc5eSEmilio G. Cota { 488be2cdc5eSEmilio G. Cota size_t i; 489be2cdc5eSEmilio G. Cota 490be2cdc5eSEmilio G. Cota tcg_region_tree_lock_all(); 491be2cdc5eSEmilio G. Cota for (i = 0; i < region.n; i++) { 492be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = region_trees + i * tree_size; 493be2cdc5eSEmilio G. Cota 494be2cdc5eSEmilio G. Cota g_tree_foreach(rt->tree, func, user_data); 495be2cdc5eSEmilio G. Cota } 496be2cdc5eSEmilio G. Cota tcg_region_tree_unlock_all(); 497be2cdc5eSEmilio G. Cota } 498be2cdc5eSEmilio G. Cota 499be2cdc5eSEmilio G. Cota size_t tcg_nb_tbs(void) 500be2cdc5eSEmilio G. Cota { 501be2cdc5eSEmilio G. Cota size_t nb_tbs = 0; 502be2cdc5eSEmilio G. Cota size_t i; 503be2cdc5eSEmilio G. Cota 504be2cdc5eSEmilio G. Cota tcg_region_tree_lock_all(); 505be2cdc5eSEmilio G. Cota for (i = 0; i < region.n; i++) { 506be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = region_trees + i * tree_size; 507be2cdc5eSEmilio G. Cota 508be2cdc5eSEmilio G. Cota nb_tbs += g_tree_nnodes(rt->tree); 509be2cdc5eSEmilio G. Cota } 510be2cdc5eSEmilio G. Cota tcg_region_tree_unlock_all(); 511be2cdc5eSEmilio G. Cota return nb_tbs; 512be2cdc5eSEmilio G. Cota } 513be2cdc5eSEmilio G. Cota 514938e897aSEmilio G. Cota static gboolean tcg_region_tree_traverse(gpointer k, gpointer v, gpointer data) 515938e897aSEmilio G. Cota { 516938e897aSEmilio G. Cota TranslationBlock *tb = v; 517938e897aSEmilio G. Cota 518938e897aSEmilio G. Cota tb_destroy(tb); 519938e897aSEmilio G. Cota return FALSE; 520938e897aSEmilio G. Cota } 521938e897aSEmilio G. Cota 522be2cdc5eSEmilio G. Cota static void tcg_region_tree_reset_all(void) 523be2cdc5eSEmilio G. Cota { 524be2cdc5eSEmilio G. Cota size_t i; 525be2cdc5eSEmilio G. Cota 526be2cdc5eSEmilio G. Cota tcg_region_tree_lock_all(); 527be2cdc5eSEmilio G. Cota for (i = 0; i < region.n; i++) { 528be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = region_trees + i * tree_size; 529be2cdc5eSEmilio G. Cota 530938e897aSEmilio G. Cota g_tree_foreach(rt->tree, tcg_region_tree_traverse, NULL); 531be2cdc5eSEmilio G. Cota /* Increment the refcount first so that destroy acts as a reset */ 532be2cdc5eSEmilio G. Cota g_tree_ref(rt->tree); 533be2cdc5eSEmilio G. Cota g_tree_destroy(rt->tree); 534be2cdc5eSEmilio G. Cota } 535be2cdc5eSEmilio G. Cota tcg_region_tree_unlock_all(); 536be2cdc5eSEmilio G. Cota } 537be2cdc5eSEmilio G. Cota 538e8feb96fSEmilio G. Cota static void tcg_region_bounds(size_t curr_region, void **pstart, void **pend) 539e8feb96fSEmilio G. Cota { 540e8feb96fSEmilio G. Cota void *start, *end; 541e8feb96fSEmilio G. Cota 542e8feb96fSEmilio G. Cota start = region.start_aligned + curr_region * region.stride; 543e8feb96fSEmilio G. Cota end = start + region.size; 544e8feb96fSEmilio G. Cota 545e8feb96fSEmilio G. Cota if (curr_region == 0) { 546e8feb96fSEmilio G. Cota start = region.start; 547e8feb96fSEmilio G. Cota } 548e8feb96fSEmilio G. Cota if (curr_region == region.n - 1) { 549e8feb96fSEmilio G. Cota end = region.end; 550e8feb96fSEmilio G. Cota } 551e8feb96fSEmilio G. Cota 552e8feb96fSEmilio G. Cota *pstart = start; 553e8feb96fSEmilio G. Cota *pend = end; 554e8feb96fSEmilio G. Cota } 555e8feb96fSEmilio G. Cota 556e8feb96fSEmilio G. Cota static void tcg_region_assign(TCGContext *s, size_t curr_region) 557e8feb96fSEmilio G. Cota { 558e8feb96fSEmilio G. Cota void *start, *end; 559e8feb96fSEmilio G. Cota 560e8feb96fSEmilio G. Cota tcg_region_bounds(curr_region, &start, &end); 561e8feb96fSEmilio G. Cota 562e8feb96fSEmilio G. Cota s->code_gen_buffer = start; 563e8feb96fSEmilio G. Cota s->code_gen_ptr = start; 564e8feb96fSEmilio G. Cota s->code_gen_buffer_size = end - start; 565e8feb96fSEmilio G. Cota s->code_gen_highwater = end - TCG_HIGHWATER; 566e8feb96fSEmilio G. Cota } 567e8feb96fSEmilio G. Cota 568e8feb96fSEmilio G. Cota static bool tcg_region_alloc__locked(TCGContext *s) 569e8feb96fSEmilio G. Cota { 570e8feb96fSEmilio G. Cota if (region.current == region.n) { 571e8feb96fSEmilio G. Cota return true; 572e8feb96fSEmilio G. Cota } 573e8feb96fSEmilio G. Cota tcg_region_assign(s, region.current); 574e8feb96fSEmilio G. Cota region.current++; 575e8feb96fSEmilio G. Cota return false; 576e8feb96fSEmilio G. Cota } 577e8feb96fSEmilio G. Cota 578e8feb96fSEmilio G. Cota /* 579e8feb96fSEmilio G. Cota * Request a new region once the one in use has filled up. 580e8feb96fSEmilio G. Cota * Returns true on error. 581e8feb96fSEmilio G. Cota */ 582e8feb96fSEmilio G. Cota static bool tcg_region_alloc(TCGContext *s) 583e8feb96fSEmilio G. Cota { 584e8feb96fSEmilio G. Cota bool err; 585e8feb96fSEmilio G. Cota /* read the region size now; alloc__locked will overwrite it on success */ 586e8feb96fSEmilio G. Cota size_t size_full = s->code_gen_buffer_size; 587e8feb96fSEmilio G. Cota 588e8feb96fSEmilio G. Cota qemu_mutex_lock(®ion.lock); 589e8feb96fSEmilio G. Cota err = tcg_region_alloc__locked(s); 590e8feb96fSEmilio G. Cota if (!err) { 591e8feb96fSEmilio G. Cota region.agg_size_full += size_full - TCG_HIGHWATER; 592e8feb96fSEmilio G. Cota } 593e8feb96fSEmilio G. Cota qemu_mutex_unlock(®ion.lock); 594e8feb96fSEmilio G. Cota return err; 595e8feb96fSEmilio G. Cota } 596e8feb96fSEmilio G. Cota 597e8feb96fSEmilio G. Cota /* 598e8feb96fSEmilio G. Cota * Perform a context's first region allocation. 599e8feb96fSEmilio G. Cota * This function does _not_ increment region.agg_size_full. 600e8feb96fSEmilio G. Cota */ 601e8feb96fSEmilio G. Cota static inline bool tcg_region_initial_alloc__locked(TCGContext *s) 602e8feb96fSEmilio G. Cota { 603e8feb96fSEmilio G. Cota return tcg_region_alloc__locked(s); 604e8feb96fSEmilio G. Cota } 605e8feb96fSEmilio G. Cota 606e8feb96fSEmilio G. Cota /* Call from a safe-work context */ 607e8feb96fSEmilio G. Cota void tcg_region_reset_all(void) 608e8feb96fSEmilio G. Cota { 609d73415a3SStefan Hajnoczi unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs); 610e8feb96fSEmilio G. Cota unsigned int i; 611e8feb96fSEmilio G. Cota 612e8feb96fSEmilio G. Cota qemu_mutex_lock(®ion.lock); 613e8feb96fSEmilio G. Cota region.current = 0; 614e8feb96fSEmilio G. Cota region.agg_size_full = 0; 615e8feb96fSEmilio G. Cota 6163468b59eSEmilio G. Cota for (i = 0; i < n_ctxs; i++) { 617d73415a3SStefan Hajnoczi TCGContext *s = qatomic_read(&tcg_ctxs[i]); 6183468b59eSEmilio G. Cota bool err = tcg_region_initial_alloc__locked(s); 619e8feb96fSEmilio G. Cota 620e8feb96fSEmilio G. Cota g_assert(!err); 621e8feb96fSEmilio G. Cota } 622e8feb96fSEmilio G. Cota qemu_mutex_unlock(®ion.lock); 623be2cdc5eSEmilio G. Cota 624be2cdc5eSEmilio G. Cota tcg_region_tree_reset_all(); 625e8feb96fSEmilio G. Cota } 626e8feb96fSEmilio G. Cota 6273468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY 6283468b59eSEmilio G. Cota static size_t tcg_n_regions(void) 6293468b59eSEmilio G. Cota { 6303468b59eSEmilio G. Cota return 1; 6313468b59eSEmilio G. Cota } 6323468b59eSEmilio G. Cota #else 6333468b59eSEmilio G. Cota /* 6343468b59eSEmilio G. Cota * It is likely that some vCPUs will translate more code than others, so we 6353468b59eSEmilio G. Cota * first try to set more regions than max_cpus, with those regions being of 6363468b59eSEmilio G. Cota * reasonable size. If that's not possible we make do by evenly dividing 6373468b59eSEmilio G. Cota * the code_gen_buffer among the vCPUs. 6383468b59eSEmilio G. Cota */ 6393468b59eSEmilio G. Cota static size_t tcg_n_regions(void) 6403468b59eSEmilio G. Cota { 6413468b59eSEmilio G. Cota size_t i; 6423468b59eSEmilio G. Cota 6433468b59eSEmilio G. Cota /* Use a single region if all we have is one vCPU thread */ 6445cc8767dSLike Xu #if !defined(CONFIG_USER_ONLY) 6455cc8767dSLike Xu MachineState *ms = MACHINE(qdev_get_machine()); 6465cc8767dSLike Xu unsigned int max_cpus = ms->smp.max_cpus; 6475cc8767dSLike Xu #endif 6483468b59eSEmilio G. Cota if (max_cpus == 1 || !qemu_tcg_mttcg_enabled()) { 6493468b59eSEmilio G. Cota return 1; 6503468b59eSEmilio G. Cota } 6513468b59eSEmilio G. Cota 6523468b59eSEmilio G. Cota /* Try to have more regions than max_cpus, with each region being >= 2 MB */ 6533468b59eSEmilio G. Cota for (i = 8; i > 0; i--) { 6543468b59eSEmilio G. Cota size_t regions_per_thread = i; 6553468b59eSEmilio G. Cota size_t region_size; 6563468b59eSEmilio G. Cota 6573468b59eSEmilio G. Cota region_size = tcg_init_ctx.code_gen_buffer_size; 6583468b59eSEmilio G. Cota region_size /= max_cpus * regions_per_thread; 6593468b59eSEmilio G. Cota 6603468b59eSEmilio G. Cota if (region_size >= 2 * 1024u * 1024) { 6613468b59eSEmilio G. Cota return max_cpus * regions_per_thread; 6623468b59eSEmilio G. Cota } 6633468b59eSEmilio G. Cota } 6643468b59eSEmilio G. Cota /* If we can't, then just allocate one region per vCPU thread */ 6653468b59eSEmilio G. Cota return max_cpus; 6663468b59eSEmilio G. Cota } 6673468b59eSEmilio G. Cota #endif 6683468b59eSEmilio G. Cota 669e8feb96fSEmilio G. Cota /* 670e8feb96fSEmilio G. Cota * Initializes region partitioning. 671e8feb96fSEmilio G. Cota * 672e8feb96fSEmilio G. Cota * Called at init time from the parent thread (i.e. the one calling 673e8feb96fSEmilio G. Cota * tcg_context_init), after the target's TCG globals have been set. 6743468b59eSEmilio G. Cota * 6753468b59eSEmilio G. Cota * Region partitioning works by splitting code_gen_buffer into separate regions, 6763468b59eSEmilio G. Cota * and then assigning regions to TCG threads so that the threads can translate 6773468b59eSEmilio G. Cota * code in parallel without synchronization. 6783468b59eSEmilio G. Cota * 6793468b59eSEmilio G. Cota * In softmmu the number of TCG threads is bounded by max_cpus, so we use at 6803468b59eSEmilio G. Cota * least max_cpus regions in MTTCG. In !MTTCG we use a single region. 6813468b59eSEmilio G. Cota * Note that the TCG options from the command-line (i.e. -accel accel=tcg,[...]) 6823468b59eSEmilio G. Cota * must have been parsed before calling this function, since it calls 6833468b59eSEmilio G. Cota * qemu_tcg_mttcg_enabled(). 6843468b59eSEmilio G. Cota * 6853468b59eSEmilio G. Cota * In user-mode we use a single region. Having multiple regions in user-mode 6863468b59eSEmilio G. Cota * is not supported, because the number of vCPU threads (recall that each thread 6873468b59eSEmilio G. Cota * spawned by the guest corresponds to a vCPU thread) is only bounded by the 6883468b59eSEmilio G. Cota * OS, and usually this number is huge (tens of thousands is not uncommon). 6893468b59eSEmilio G. Cota * Thus, given this large bound on the number of vCPU threads and the fact 6903468b59eSEmilio G. Cota * that code_gen_buffer is allocated at compile-time, we cannot guarantee 6913468b59eSEmilio G. Cota * that the availability of at least one region per vCPU thread. 6923468b59eSEmilio G. Cota * 6933468b59eSEmilio G. Cota * However, this user-mode limitation is unlikely to be a significant problem 6943468b59eSEmilio G. Cota * in practice. Multi-threaded guests share most if not all of their translated 6953468b59eSEmilio G. Cota * code, which makes parallel code generation less appealing than in softmmu. 696e8feb96fSEmilio G. Cota */ 697e8feb96fSEmilio G. Cota void tcg_region_init(void) 698e8feb96fSEmilio G. Cota { 699e8feb96fSEmilio G. Cota void *buf = tcg_init_ctx.code_gen_buffer; 700e8feb96fSEmilio G. Cota void *aligned; 701e8feb96fSEmilio G. Cota size_t size = tcg_init_ctx.code_gen_buffer_size; 702e8feb96fSEmilio G. Cota size_t page_size = qemu_real_host_page_size; 703e8feb96fSEmilio G. Cota size_t region_size; 704e8feb96fSEmilio G. Cota size_t n_regions; 705e8feb96fSEmilio G. Cota size_t i; 706db0c51a3SRichard Henderson uintptr_t splitwx_diff; 707e8feb96fSEmilio G. Cota 7083468b59eSEmilio G. Cota n_regions = tcg_n_regions(); 709e8feb96fSEmilio G. Cota 710e8feb96fSEmilio G. Cota /* The first region will be 'aligned - buf' bytes larger than the others */ 711e8feb96fSEmilio G. Cota aligned = QEMU_ALIGN_PTR_UP(buf, page_size); 712e8feb96fSEmilio G. Cota g_assert(aligned < tcg_init_ctx.code_gen_buffer + size); 713e8feb96fSEmilio G. Cota /* 714e8feb96fSEmilio G. Cota * Make region_size a multiple of page_size, using aligned as the start. 715e8feb96fSEmilio G. Cota * As a result of this we might end up with a few extra pages at the end of 716e8feb96fSEmilio G. Cota * the buffer; we will assign those to the last region. 717e8feb96fSEmilio G. Cota */ 718e8feb96fSEmilio G. Cota region_size = (size - (aligned - buf)) / n_regions; 719e8feb96fSEmilio G. Cota region_size = QEMU_ALIGN_DOWN(region_size, page_size); 720e8feb96fSEmilio G. Cota 721e8feb96fSEmilio G. Cota /* A region must have at least 2 pages; one code, one guard */ 722e8feb96fSEmilio G. Cota g_assert(region_size >= 2 * page_size); 723e8feb96fSEmilio G. Cota 724e8feb96fSEmilio G. Cota /* init the region struct */ 725e8feb96fSEmilio G. Cota qemu_mutex_init(®ion.lock); 726e8feb96fSEmilio G. Cota region.n = n_regions; 727e8feb96fSEmilio G. Cota region.size = region_size - page_size; 728e8feb96fSEmilio G. Cota region.stride = region_size; 729e8feb96fSEmilio G. Cota region.start = buf; 730e8feb96fSEmilio G. Cota region.start_aligned = aligned; 731e8feb96fSEmilio G. Cota /* page-align the end, since its last page will be a guard page */ 732e8feb96fSEmilio G. Cota region.end = QEMU_ALIGN_PTR_DOWN(buf + size, page_size); 733e8feb96fSEmilio G. Cota /* account for that last guard page */ 734e8feb96fSEmilio G. Cota region.end -= page_size; 735e8feb96fSEmilio G. Cota 736e8feb96fSEmilio G. Cota /* set guard pages */ 737db0c51a3SRichard Henderson splitwx_diff = tcg_splitwx_diff; 738e8feb96fSEmilio G. Cota for (i = 0; i < region.n; i++) { 739e8feb96fSEmilio G. Cota void *start, *end; 740e8feb96fSEmilio G. Cota int rc; 741e8feb96fSEmilio G. Cota 742e8feb96fSEmilio G. Cota tcg_region_bounds(i, &start, &end); 743e8feb96fSEmilio G. Cota rc = qemu_mprotect_none(end, page_size); 744e8feb96fSEmilio G. Cota g_assert(!rc); 745db0c51a3SRichard Henderson if (splitwx_diff) { 746db0c51a3SRichard Henderson rc = qemu_mprotect_none(end + splitwx_diff, page_size); 747db0c51a3SRichard Henderson g_assert(!rc); 748db0c51a3SRichard Henderson } 749e8feb96fSEmilio G. Cota } 750e8feb96fSEmilio G. Cota 751be2cdc5eSEmilio G. Cota tcg_region_trees_init(); 752be2cdc5eSEmilio G. Cota 7533468b59eSEmilio G. Cota /* In user-mode we support only one ctx, so do the initial allocation now */ 7543468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY 755e8feb96fSEmilio G. Cota { 756e8feb96fSEmilio G. Cota bool err = tcg_region_initial_alloc__locked(tcg_ctx); 757e8feb96fSEmilio G. Cota 758e8feb96fSEmilio G. Cota g_assert(!err); 759e8feb96fSEmilio G. Cota } 7603468b59eSEmilio G. Cota #endif 761e8feb96fSEmilio G. Cota } 762e8feb96fSEmilio G. Cota 763db0c51a3SRichard Henderson #ifdef CONFIG_DEBUG_TCG 764db0c51a3SRichard Henderson const void *tcg_splitwx_to_rx(void *rw) 765db0c51a3SRichard Henderson { 766db0c51a3SRichard Henderson /* Pass NULL pointers unchanged. */ 767db0c51a3SRichard Henderson if (rw) { 768db0c51a3SRichard Henderson g_assert(in_code_gen_buffer(rw)); 769db0c51a3SRichard Henderson rw += tcg_splitwx_diff; 770db0c51a3SRichard Henderson } 771db0c51a3SRichard Henderson return rw; 772db0c51a3SRichard Henderson } 773db0c51a3SRichard Henderson 774db0c51a3SRichard Henderson void *tcg_splitwx_to_rw(const void *rx) 775db0c51a3SRichard Henderson { 776db0c51a3SRichard Henderson /* Pass NULL pointers unchanged. */ 777db0c51a3SRichard Henderson if (rx) { 778db0c51a3SRichard Henderson rx -= tcg_splitwx_diff; 779db0c51a3SRichard Henderson /* Assert that we end with a pointer in the rw region. */ 780db0c51a3SRichard Henderson g_assert(in_code_gen_buffer(rx)); 781db0c51a3SRichard Henderson } 782db0c51a3SRichard Henderson return (void *)rx; 783db0c51a3SRichard Henderson } 784db0c51a3SRichard Henderson #endif /* CONFIG_DEBUG_TCG */ 785db0c51a3SRichard Henderson 78638b47b19SEmilio G. Cota static void alloc_tcg_plugin_context(TCGContext *s) 78738b47b19SEmilio G. Cota { 78838b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN 78938b47b19SEmilio G. Cota s->plugin_tb = g_new0(struct qemu_plugin_tb, 1); 79038b47b19SEmilio G. Cota s->plugin_tb->insns = 79138b47b19SEmilio G. Cota g_ptr_array_new_with_free_func(qemu_plugin_insn_cleanup_fn); 79238b47b19SEmilio G. Cota #endif 79338b47b19SEmilio G. Cota } 79438b47b19SEmilio G. Cota 795e8feb96fSEmilio G. Cota /* 7963468b59eSEmilio G. Cota * All TCG threads except the parent (i.e. the one that called tcg_context_init 7973468b59eSEmilio G. Cota * and registered the target's TCG globals) must register with this function 7983468b59eSEmilio G. Cota * before initiating translation. 7993468b59eSEmilio G. Cota * 8003468b59eSEmilio G. Cota * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation 8013468b59eSEmilio G. Cota * of tcg_region_init() for the reasoning behind this. 8023468b59eSEmilio G. Cota * 8033468b59eSEmilio G. Cota * In softmmu each caller registers its context in tcg_ctxs[]. Note that in 8043468b59eSEmilio G. Cota * softmmu tcg_ctxs[] does not track tcg_ctx_init, since the initial context 8053468b59eSEmilio G. Cota * is not used anymore for translation once this function is called. 8063468b59eSEmilio G. Cota * 8073468b59eSEmilio G. Cota * Not tracking tcg_init_ctx in tcg_ctxs[] in softmmu keeps code that iterates 8083468b59eSEmilio G. Cota * over the array (e.g. tcg_code_size() the same for both softmmu and user-mode. 8093468b59eSEmilio G. Cota */ 8103468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY 8113468b59eSEmilio G. Cota void tcg_register_thread(void) 8123468b59eSEmilio G. Cota { 8133468b59eSEmilio G. Cota tcg_ctx = &tcg_init_ctx; 8143468b59eSEmilio G. Cota } 8153468b59eSEmilio G. Cota #else 8163468b59eSEmilio G. Cota void tcg_register_thread(void) 8173468b59eSEmilio G. Cota { 8185cc8767dSLike Xu MachineState *ms = MACHINE(qdev_get_machine()); 8193468b59eSEmilio G. Cota TCGContext *s = g_malloc(sizeof(*s)); 8203468b59eSEmilio G. Cota unsigned int i, n; 8213468b59eSEmilio G. Cota bool err; 8223468b59eSEmilio G. Cota 8233468b59eSEmilio G. Cota *s = tcg_init_ctx; 8243468b59eSEmilio G. Cota 8253468b59eSEmilio G. Cota /* Relink mem_base. */ 8263468b59eSEmilio G. Cota for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) { 8273468b59eSEmilio G. Cota if (tcg_init_ctx.temps[i].mem_base) { 8283468b59eSEmilio G. Cota ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps; 8293468b59eSEmilio G. Cota tcg_debug_assert(b >= 0 && b < n); 8303468b59eSEmilio G. Cota s->temps[i].mem_base = &s->temps[b]; 8313468b59eSEmilio G. Cota } 8323468b59eSEmilio G. Cota } 8333468b59eSEmilio G. Cota 8343468b59eSEmilio G. Cota /* Claim an entry in tcg_ctxs */ 835d73415a3SStefan Hajnoczi n = qatomic_fetch_inc(&n_tcg_ctxs); 8365cc8767dSLike Xu g_assert(n < ms->smp.max_cpus); 837d73415a3SStefan Hajnoczi qatomic_set(&tcg_ctxs[n], s); 8383468b59eSEmilio G. Cota 83938b47b19SEmilio G. Cota if (n > 0) { 84038b47b19SEmilio G. Cota alloc_tcg_plugin_context(s); 84138b47b19SEmilio G. Cota } 84238b47b19SEmilio G. Cota 8433468b59eSEmilio G. Cota tcg_ctx = s; 8443468b59eSEmilio G. Cota qemu_mutex_lock(®ion.lock); 8453468b59eSEmilio G. Cota err = tcg_region_initial_alloc__locked(tcg_ctx); 8463468b59eSEmilio G. Cota g_assert(!err); 8473468b59eSEmilio G. Cota qemu_mutex_unlock(®ion.lock); 8483468b59eSEmilio G. Cota } 8493468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */ 8503468b59eSEmilio G. Cota 8513468b59eSEmilio G. Cota /* 852e8feb96fSEmilio G. Cota * Returns the size (in bytes) of all translated code (i.e. from all regions) 853e8feb96fSEmilio G. Cota * currently in the cache. 854e8feb96fSEmilio G. Cota * See also: tcg_code_capacity() 855e8feb96fSEmilio G. Cota * Do not confuse with tcg_current_code_size(); that one applies to a single 856e8feb96fSEmilio G. Cota * TCG context. 857e8feb96fSEmilio G. Cota */ 858e8feb96fSEmilio G. Cota size_t tcg_code_size(void) 859e8feb96fSEmilio G. Cota { 860d73415a3SStefan Hajnoczi unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs); 861e8feb96fSEmilio G. Cota unsigned int i; 862e8feb96fSEmilio G. Cota size_t total; 863e8feb96fSEmilio G. Cota 864e8feb96fSEmilio G. Cota qemu_mutex_lock(®ion.lock); 865e8feb96fSEmilio G. Cota total = region.agg_size_full; 8663468b59eSEmilio G. Cota for (i = 0; i < n_ctxs; i++) { 867d73415a3SStefan Hajnoczi const TCGContext *s = qatomic_read(&tcg_ctxs[i]); 868e8feb96fSEmilio G. Cota size_t size; 869e8feb96fSEmilio G. Cota 870d73415a3SStefan Hajnoczi size = qatomic_read(&s->code_gen_ptr) - s->code_gen_buffer; 871e8feb96fSEmilio G. Cota g_assert(size <= s->code_gen_buffer_size); 872e8feb96fSEmilio G. Cota total += size; 873e8feb96fSEmilio G. Cota } 874e8feb96fSEmilio G. Cota qemu_mutex_unlock(®ion.lock); 875e8feb96fSEmilio G. Cota return total; 876e8feb96fSEmilio G. Cota } 877e8feb96fSEmilio G. Cota 878e8feb96fSEmilio G. Cota /* 879e8feb96fSEmilio G. Cota * Returns the code capacity (in bytes) of the entire cache, i.e. including all 880e8feb96fSEmilio G. Cota * regions. 881e8feb96fSEmilio G. Cota * See also: tcg_code_size() 882e8feb96fSEmilio G. Cota */ 883e8feb96fSEmilio G. Cota size_t tcg_code_capacity(void) 884e8feb96fSEmilio G. Cota { 885e8feb96fSEmilio G. Cota size_t guard_size, capacity; 886e8feb96fSEmilio G. Cota 887e8feb96fSEmilio G. Cota /* no need for synchronization; these variables are set at init time */ 888e8feb96fSEmilio G. Cota guard_size = region.stride - region.size; 889e8feb96fSEmilio G. Cota capacity = region.end + guard_size - region.start; 890e8feb96fSEmilio G. Cota capacity -= region.n * (guard_size + TCG_HIGHWATER); 891e8feb96fSEmilio G. Cota return capacity; 892e8feb96fSEmilio G. Cota } 893e8feb96fSEmilio G. Cota 894128ed227SEmilio G. Cota size_t tcg_tb_phys_invalidate_count(void) 895128ed227SEmilio G. Cota { 896d73415a3SStefan Hajnoczi unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs); 897128ed227SEmilio G. Cota unsigned int i; 898128ed227SEmilio G. Cota size_t total = 0; 899128ed227SEmilio G. Cota 900128ed227SEmilio G. Cota for (i = 0; i < n_ctxs; i++) { 901d73415a3SStefan Hajnoczi const TCGContext *s = qatomic_read(&tcg_ctxs[i]); 902128ed227SEmilio G. Cota 903d73415a3SStefan Hajnoczi total += qatomic_read(&s->tb_phys_invalidate_count); 904128ed227SEmilio G. Cota } 905128ed227SEmilio G. Cota return total; 906128ed227SEmilio G. Cota } 907128ed227SEmilio G. Cota 908c896fe29Sbellard /* pool based memory allocation */ 909c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size) 910c896fe29Sbellard { 911c896fe29Sbellard TCGPool *p; 912c896fe29Sbellard int pool_size; 913c896fe29Sbellard 914c896fe29Sbellard if (size > TCG_POOL_CHUNK_SIZE) { 915c896fe29Sbellard /* big malloc: insert a new pool (XXX: could optimize) */ 9167267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + size); 917c896fe29Sbellard p->size = size; 9184055299eSKirill Batuzov p->next = s->pool_first_large; 9194055299eSKirill Batuzov s->pool_first_large = p; 9204055299eSKirill Batuzov return p->data; 921c896fe29Sbellard } else { 922c896fe29Sbellard p = s->pool_current; 923c896fe29Sbellard if (!p) { 924c896fe29Sbellard p = s->pool_first; 925c896fe29Sbellard if (!p) 926c896fe29Sbellard goto new_pool; 927c896fe29Sbellard } else { 928c896fe29Sbellard if (!p->next) { 929c896fe29Sbellard new_pool: 930c896fe29Sbellard pool_size = TCG_POOL_CHUNK_SIZE; 9317267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + pool_size); 932c896fe29Sbellard p->size = pool_size; 933c896fe29Sbellard p->next = NULL; 934c896fe29Sbellard if (s->pool_current) 935c896fe29Sbellard s->pool_current->next = p; 936c896fe29Sbellard else 937c896fe29Sbellard s->pool_first = p; 938c896fe29Sbellard } else { 939c896fe29Sbellard p = p->next; 940c896fe29Sbellard } 941c896fe29Sbellard } 942c896fe29Sbellard } 943c896fe29Sbellard s->pool_current = p; 944c896fe29Sbellard s->pool_cur = p->data + size; 945c896fe29Sbellard s->pool_end = p->data + p->size; 946c896fe29Sbellard return p->data; 947c896fe29Sbellard } 948c896fe29Sbellard 949c896fe29Sbellard void tcg_pool_reset(TCGContext *s) 950c896fe29Sbellard { 9514055299eSKirill Batuzov TCGPool *p, *t; 9524055299eSKirill Batuzov for (p = s->pool_first_large; p; p = t) { 9534055299eSKirill Batuzov t = p->next; 9544055299eSKirill Batuzov g_free(p); 9554055299eSKirill Batuzov } 9564055299eSKirill Batuzov s->pool_first_large = NULL; 957c896fe29Sbellard s->pool_cur = s->pool_end = NULL; 958c896fe29Sbellard s->pool_current = NULL; 959c896fe29Sbellard } 960c896fe29Sbellard 961100b5e01SRichard Henderson typedef struct TCGHelperInfo { 962100b5e01SRichard Henderson void *func; 963100b5e01SRichard Henderson const char *name; 964afb49896SRichard Henderson unsigned flags; 965afb49896SRichard Henderson unsigned sizemask; 966100b5e01SRichard Henderson } TCGHelperInfo; 967100b5e01SRichard Henderson 9682ef6175aSRichard Henderson #include "exec/helper-proto.h" 9692ef6175aSRichard Henderson 970100b5e01SRichard Henderson static const TCGHelperInfo all_helpers[] = { 9712ef6175aSRichard Henderson #include "exec/helper-tcg.h" 972100b5e01SRichard Henderson }; 973619205fdSEmilio G. Cota static GHashTable *helper_table; 974100b5e01SRichard Henderson 97591478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)]; 976f69d277eSRichard Henderson static void process_op_defs(TCGContext *s); 9771c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type, 9781c2adb95SRichard Henderson TCGReg reg, const char *name); 97991478cefSRichard Henderson 980c896fe29Sbellard void tcg_context_init(TCGContext *s) 981c896fe29Sbellard { 982100b5e01SRichard Henderson int op, total_args, n, i; 983c896fe29Sbellard TCGOpDef *def; 984c896fe29Sbellard TCGArgConstraint *args_ct; 9851c2adb95SRichard Henderson TCGTemp *ts; 986c896fe29Sbellard 987c896fe29Sbellard memset(s, 0, sizeof(*s)); 988c896fe29Sbellard s->nb_globals = 0; 989c896fe29Sbellard 990c896fe29Sbellard /* Count total number of arguments and allocate the corresponding 991c896fe29Sbellard space */ 992c896fe29Sbellard total_args = 0; 993c896fe29Sbellard for(op = 0; op < NB_OPS; op++) { 994c896fe29Sbellard def = &tcg_op_defs[op]; 995c896fe29Sbellard n = def->nb_iargs + def->nb_oargs; 996c896fe29Sbellard total_args += n; 997c896fe29Sbellard } 998c896fe29Sbellard 999bc2b17e6SRichard Henderson args_ct = g_new0(TCGArgConstraint, total_args); 1000c896fe29Sbellard 1001c896fe29Sbellard for(op = 0; op < NB_OPS; op++) { 1002c896fe29Sbellard def = &tcg_op_defs[op]; 1003c896fe29Sbellard def->args_ct = args_ct; 1004c896fe29Sbellard n = def->nb_iargs + def->nb_oargs; 1005c896fe29Sbellard args_ct += n; 1006c896fe29Sbellard } 1007c896fe29Sbellard 10085cd8f621SRichard Henderson /* Register helpers. */ 100984fd9dd3SRichard Henderson /* Use g_direct_hash/equal for direct pointer comparisons on func. */ 1010619205fdSEmilio G. Cota helper_table = g_hash_table_new(NULL, NULL); 101184fd9dd3SRichard Henderson 1012100b5e01SRichard Henderson for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) { 101384fd9dd3SRichard Henderson g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func, 101472866e82SRichard Henderson (gpointer)&all_helpers[i]); 1015100b5e01SRichard Henderson } 10165cd8f621SRichard Henderson 1017c896fe29Sbellard tcg_target_init(s); 1018f69d277eSRichard Henderson process_op_defs(s); 101991478cefSRichard Henderson 102091478cefSRichard Henderson /* Reverse the order of the saved registers, assuming they're all at 102191478cefSRichard Henderson the start of tcg_target_reg_alloc_order. */ 102291478cefSRichard Henderson for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) { 102391478cefSRichard Henderson int r = tcg_target_reg_alloc_order[n]; 102491478cefSRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) { 102591478cefSRichard Henderson break; 102691478cefSRichard Henderson } 102791478cefSRichard Henderson } 102891478cefSRichard Henderson for (i = 0; i < n; ++i) { 102991478cefSRichard Henderson indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i]; 103091478cefSRichard Henderson } 103191478cefSRichard Henderson for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) { 103291478cefSRichard Henderson indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i]; 103391478cefSRichard Henderson } 1034b1311c4aSEmilio G. Cota 103538b47b19SEmilio G. Cota alloc_tcg_plugin_context(s); 103638b47b19SEmilio G. Cota 1037b1311c4aSEmilio G. Cota tcg_ctx = s; 10383468b59eSEmilio G. Cota /* 10393468b59eSEmilio G. Cota * In user-mode we simply share the init context among threads, since we 10403468b59eSEmilio G. Cota * use a single region. See the documentation tcg_region_init() for the 10413468b59eSEmilio G. Cota * reasoning behind this. 10423468b59eSEmilio G. Cota * In softmmu we will have at most max_cpus TCG threads. 10433468b59eSEmilio G. Cota */ 10443468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY 1045df2cce29SEmilio G. Cota tcg_ctxs = &tcg_ctx; 1046df2cce29SEmilio G. Cota n_tcg_ctxs = 1; 10473468b59eSEmilio G. Cota #else 10485cc8767dSLike Xu MachineState *ms = MACHINE(qdev_get_machine()); 10495cc8767dSLike Xu unsigned int max_cpus = ms->smp.max_cpus; 10503468b59eSEmilio G. Cota tcg_ctxs = g_new(TCGContext *, max_cpus); 10513468b59eSEmilio G. Cota #endif 10521c2adb95SRichard Henderson 10531c2adb95SRichard Henderson tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0)); 10541c2adb95SRichard Henderson ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env"); 10551c2adb95SRichard Henderson cpu_env = temp_tcgv_ptr(ts); 10569002ec79SRichard Henderson } 1057b03cce8eSbellard 10586e3b2bfdSEmilio G. Cota /* 10596e3b2bfdSEmilio G. Cota * Allocate TBs right before their corresponding translated code, making 10606e3b2bfdSEmilio G. Cota * sure that TBs and code are on different cache lines. 10616e3b2bfdSEmilio G. Cota */ 10626e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s) 10636e3b2bfdSEmilio G. Cota { 10646e3b2bfdSEmilio G. Cota uintptr_t align = qemu_icache_linesize; 10656e3b2bfdSEmilio G. Cota TranslationBlock *tb; 10666e3b2bfdSEmilio G. Cota void *next; 10676e3b2bfdSEmilio G. Cota 1068e8feb96fSEmilio G. Cota retry: 10696e3b2bfdSEmilio G. Cota tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align); 10706e3b2bfdSEmilio G. Cota next = (void *)ROUND_UP((uintptr_t)(tb + 1), align); 10716e3b2bfdSEmilio G. Cota 10726e3b2bfdSEmilio G. Cota if (unlikely(next > s->code_gen_highwater)) { 1073e8feb96fSEmilio G. Cota if (tcg_region_alloc(s)) { 10746e3b2bfdSEmilio G. Cota return NULL; 10756e3b2bfdSEmilio G. Cota } 1076e8feb96fSEmilio G. Cota goto retry; 1077e8feb96fSEmilio G. Cota } 1078d73415a3SStefan Hajnoczi qatomic_set(&s->code_gen_ptr, next); 107957a26946SRichard Henderson s->data_gen_ptr = NULL; 10806e3b2bfdSEmilio G. Cota return tb; 10816e3b2bfdSEmilio G. Cota } 10826e3b2bfdSEmilio G. Cota 10839002ec79SRichard Henderson void tcg_prologue_init(TCGContext *s) 10849002ec79SRichard Henderson { 10858163b749SRichard Henderson size_t prologue_size, total_size; 10868163b749SRichard Henderson void *buf0, *buf1; 10878163b749SRichard Henderson 10888163b749SRichard Henderson /* Put the prologue at the beginning of code_gen_buffer. */ 10898163b749SRichard Henderson buf0 = s->code_gen_buffer; 10905b38ee31SRichard Henderson total_size = s->code_gen_buffer_size; 10918163b749SRichard Henderson s->code_ptr = buf0; 10928163b749SRichard Henderson s->code_buf = buf0; 10935b38ee31SRichard Henderson s->data_gen_ptr = NULL; 1094b91ccb31SRichard Henderson 1095db0c51a3SRichard Henderson /* 1096db0c51a3SRichard Henderson * The region trees are not yet configured, but tcg_splitwx_to_rx 1097db0c51a3SRichard Henderson * needs the bounds for an assert. 1098db0c51a3SRichard Henderson */ 1099db0c51a3SRichard Henderson region.start = buf0; 1100db0c51a3SRichard Henderson region.end = buf0 + total_size; 1101db0c51a3SRichard Henderson 1102b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 1103db0c51a3SRichard Henderson tcg_qemu_tb_exec = (tcg_prologue_fn *)tcg_splitwx_to_rx(buf0); 1104b91ccb31SRichard Henderson #endif 11058163b749SRichard Henderson 11065b38ee31SRichard Henderson /* Compute a high-water mark, at which we voluntarily flush the buffer 11075b38ee31SRichard Henderson and start over. The size here is arbitrary, significantly larger 11085b38ee31SRichard Henderson than we expect the code generation for any one opcode to require. */ 11095b38ee31SRichard Henderson s->code_gen_highwater = s->code_gen_buffer + (total_size - TCG_HIGHWATER); 11105b38ee31SRichard Henderson 11115b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 11125b38ee31SRichard Henderson s->pool_labels = NULL; 11135b38ee31SRichard Henderson #endif 11145b38ee31SRichard Henderson 11158163b749SRichard Henderson /* Generate the prologue. */ 1116b03cce8eSbellard tcg_target_qemu_prologue(s); 11175b38ee31SRichard Henderson 11185b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 11195b38ee31SRichard Henderson /* Allow the prologue to put e.g. guest_base into a pool entry. */ 11205b38ee31SRichard Henderson { 11211768987bSRichard Henderson int result = tcg_out_pool_finalize(s); 11221768987bSRichard Henderson tcg_debug_assert(result == 0); 11235b38ee31SRichard Henderson } 11245b38ee31SRichard Henderson #endif 11255b38ee31SRichard Henderson 11268163b749SRichard Henderson buf1 = s->code_ptr; 1127df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 1128db0c51a3SRichard Henderson flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(buf0), (uintptr_t)buf0, 11291da8de39SRichard Henderson tcg_ptr_byte_diff(buf1, buf0)); 1130df5d2b16SRichard Henderson #endif 11318163b749SRichard Henderson 11328163b749SRichard Henderson /* Deduct the prologue from the buffer. */ 11338163b749SRichard Henderson prologue_size = tcg_current_code_size(s); 11348163b749SRichard Henderson s->code_gen_ptr = buf1; 11358163b749SRichard Henderson s->code_gen_buffer = buf1; 11368163b749SRichard Henderson s->code_buf = buf1; 11375b38ee31SRichard Henderson total_size -= prologue_size; 11388163b749SRichard Henderson s->code_gen_buffer_size = total_size; 11398163b749SRichard Henderson 1140755bf9e5SRichard Henderson tcg_register_jit(tcg_splitwx_to_rx(s->code_gen_buffer), total_size); 1141d6b64b2bSRichard Henderson 1142d6b64b2bSRichard Henderson #ifdef DEBUG_DISAS 1143d6b64b2bSRichard Henderson if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) { 1144fc59d2d8SRobert Foley FILE *logfile = qemu_log_lock(); 11458163b749SRichard Henderson qemu_log("PROLOGUE: [size=%zu]\n", prologue_size); 11465b38ee31SRichard Henderson if (s->data_gen_ptr) { 11475b38ee31SRichard Henderson size_t code_size = s->data_gen_ptr - buf0; 11485b38ee31SRichard Henderson size_t data_size = prologue_size - code_size; 11495b38ee31SRichard Henderson size_t i; 11505b38ee31SRichard Henderson 11514c389f6eSRichard Henderson log_disas(buf0, code_size); 11525b38ee31SRichard Henderson 11535b38ee31SRichard Henderson for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) { 11545b38ee31SRichard Henderson if (sizeof(tcg_target_ulong) == 8) { 11555b38ee31SRichard Henderson qemu_log("0x%08" PRIxPTR ": .quad 0x%016" PRIx64 "\n", 11565b38ee31SRichard Henderson (uintptr_t)s->data_gen_ptr + i, 11575b38ee31SRichard Henderson *(uint64_t *)(s->data_gen_ptr + i)); 11585b38ee31SRichard Henderson } else { 11595b38ee31SRichard Henderson qemu_log("0x%08" PRIxPTR ": .long 0x%08x\n", 11605b38ee31SRichard Henderson (uintptr_t)s->data_gen_ptr + i, 11615b38ee31SRichard Henderson *(uint32_t *)(s->data_gen_ptr + i)); 11625b38ee31SRichard Henderson } 11635b38ee31SRichard Henderson } 11645b38ee31SRichard Henderson } else { 11654c389f6eSRichard Henderson log_disas(buf0, prologue_size); 11665b38ee31SRichard Henderson } 1167d6b64b2bSRichard Henderson qemu_log("\n"); 1168d6b64b2bSRichard Henderson qemu_log_flush(); 1169fc59d2d8SRobert Foley qemu_log_unlock(logfile); 1170d6b64b2bSRichard Henderson } 1171d6b64b2bSRichard Henderson #endif 1172cedbcb01SEmilio G. Cota 1173cedbcb01SEmilio G. Cota /* Assert that goto_ptr is implemented completely. */ 1174cedbcb01SEmilio G. Cota if (TCG_TARGET_HAS_goto_ptr) { 11758b5c2b62SRichard Henderson tcg_debug_assert(tcg_code_gen_epilogue != NULL); 1176cedbcb01SEmilio G. Cota } 1177c896fe29Sbellard } 1178c896fe29Sbellard 1179c896fe29Sbellard void tcg_func_start(TCGContext *s) 1180c896fe29Sbellard { 1181c896fe29Sbellard tcg_pool_reset(s); 1182c896fe29Sbellard s->nb_temps = s->nb_globals; 11830ec9eabcSRichard Henderson 11840ec9eabcSRichard Henderson /* No temps have been previously allocated for size or locality. */ 11850ec9eabcSRichard Henderson memset(s->free_temps, 0, sizeof(s->free_temps)); 11860ec9eabcSRichard Henderson 1187abebf925SRichard Henderson s->nb_ops = 0; 1188c896fe29Sbellard s->nb_labels = 0; 1189c896fe29Sbellard s->current_frame_offset = s->frame_start; 1190c896fe29Sbellard 11910a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG 11920a209d4bSRichard Henderson s->goto_tb_issue_mask = 0; 11930a209d4bSRichard Henderson #endif 11940a209d4bSRichard Henderson 119515fa08f8SRichard Henderson QTAILQ_INIT(&s->ops); 119615fa08f8SRichard Henderson QTAILQ_INIT(&s->free_ops); 1197bef16ab4SRichard Henderson QSIMPLEQ_INIT(&s->labels); 1198c896fe29Sbellard } 1199c896fe29Sbellard 12007ca4b752SRichard Henderson static inline TCGTemp *tcg_temp_alloc(TCGContext *s) 12017ca4b752SRichard Henderson { 12027ca4b752SRichard Henderson int n = s->nb_temps++; 12037ca4b752SRichard Henderson tcg_debug_assert(n < TCG_MAX_TEMPS); 12047ca4b752SRichard Henderson return memset(&s->temps[n], 0, sizeof(TCGTemp)); 12057ca4b752SRichard Henderson } 12067ca4b752SRichard Henderson 12077ca4b752SRichard Henderson static inline TCGTemp *tcg_global_alloc(TCGContext *s) 12087ca4b752SRichard Henderson { 1209fa477d25SRichard Henderson TCGTemp *ts; 1210fa477d25SRichard Henderson 12117ca4b752SRichard Henderson tcg_debug_assert(s->nb_globals == s->nb_temps); 12127ca4b752SRichard Henderson s->nb_globals++; 1213fa477d25SRichard Henderson ts = tcg_temp_alloc(s); 1214fa477d25SRichard Henderson ts->temp_global = 1; 1215fa477d25SRichard Henderson 1216fa477d25SRichard Henderson return ts; 1217c896fe29Sbellard } 1218c896fe29Sbellard 1219085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type, 1220b6638662SRichard Henderson TCGReg reg, const char *name) 1221c896fe29Sbellard { 1222c896fe29Sbellard TCGTemp *ts; 1223c896fe29Sbellard 1224b3a62939SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type != TCG_TYPE_I32) { 1225c896fe29Sbellard tcg_abort(); 1226b3a62939SRichard Henderson } 12277ca4b752SRichard Henderson 12287ca4b752SRichard Henderson ts = tcg_global_alloc(s); 1229c896fe29Sbellard ts->base_type = type; 1230c896fe29Sbellard ts->type = type; 1231c896fe29Sbellard ts->fixed_reg = 1; 1232c896fe29Sbellard ts->reg = reg; 1233c896fe29Sbellard ts->name = name; 1234c896fe29Sbellard tcg_regset_set_reg(s->reserved_regs, reg); 12357ca4b752SRichard Henderson 1236085272b3SRichard Henderson return ts; 1237a7812ae4Spbrook } 1238a7812ae4Spbrook 1239b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size) 1240a7812ae4Spbrook { 1241b3a62939SRichard Henderson s->frame_start = start; 1242b3a62939SRichard Henderson s->frame_end = start + size; 1243085272b3SRichard Henderson s->frame_temp 1244085272b3SRichard Henderson = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame"); 1245b3a62939SRichard Henderson } 1246a7812ae4Spbrook 1247085272b3SRichard Henderson TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base, 1248e1ccc054SRichard Henderson intptr_t offset, const char *name) 1249c896fe29Sbellard { 1250b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1251dc41aa7dSRichard Henderson TCGTemp *base_ts = tcgv_ptr_temp(base); 12527ca4b752SRichard Henderson TCGTemp *ts = tcg_global_alloc(s); 1253b3915dbbSRichard Henderson int indirect_reg = 0, bigendian = 0; 12547ca4b752SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 12557ca4b752SRichard Henderson bigendian = 1; 12567ca4b752SRichard Henderson #endif 1257c896fe29Sbellard 1258b3915dbbSRichard Henderson if (!base_ts->fixed_reg) { 12595a18407fSRichard Henderson /* We do not support double-indirect registers. */ 12605a18407fSRichard Henderson tcg_debug_assert(!base_ts->indirect_reg); 1261b3915dbbSRichard Henderson base_ts->indirect_base = 1; 12625a18407fSRichard Henderson s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64 12635a18407fSRichard Henderson ? 2 : 1); 12645a18407fSRichard Henderson indirect_reg = 1; 1265b3915dbbSRichard Henderson } 1266b3915dbbSRichard Henderson 12677ca4b752SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { 12687ca4b752SRichard Henderson TCGTemp *ts2 = tcg_global_alloc(s); 1269c896fe29Sbellard char buf[64]; 12707ca4b752SRichard Henderson 12717ca4b752SRichard Henderson ts->base_type = TCG_TYPE_I64; 1272c896fe29Sbellard ts->type = TCG_TYPE_I32; 1273b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg; 1274c896fe29Sbellard ts->mem_allocated = 1; 1275b3a62939SRichard Henderson ts->mem_base = base_ts; 12767ca4b752SRichard Henderson ts->mem_offset = offset + bigendian * 4; 1277c896fe29Sbellard pstrcpy(buf, sizeof(buf), name); 1278c896fe29Sbellard pstrcat(buf, sizeof(buf), "_0"); 1279c896fe29Sbellard ts->name = strdup(buf); 1280c896fe29Sbellard 12817ca4b752SRichard Henderson tcg_debug_assert(ts2 == ts + 1); 12827ca4b752SRichard Henderson ts2->base_type = TCG_TYPE_I64; 12837ca4b752SRichard Henderson ts2->type = TCG_TYPE_I32; 1284b3915dbbSRichard Henderson ts2->indirect_reg = indirect_reg; 12857ca4b752SRichard Henderson ts2->mem_allocated = 1; 12867ca4b752SRichard Henderson ts2->mem_base = base_ts; 12877ca4b752SRichard Henderson ts2->mem_offset = offset + (1 - bigendian) * 4; 1288c896fe29Sbellard pstrcpy(buf, sizeof(buf), name); 1289c896fe29Sbellard pstrcat(buf, sizeof(buf), "_1"); 1290120c1084SRichard Henderson ts2->name = strdup(buf); 12917ca4b752SRichard Henderson } else { 1292c896fe29Sbellard ts->base_type = type; 1293c896fe29Sbellard ts->type = type; 1294b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg; 1295c896fe29Sbellard ts->mem_allocated = 1; 1296b3a62939SRichard Henderson ts->mem_base = base_ts; 1297c896fe29Sbellard ts->mem_offset = offset; 1298c896fe29Sbellard ts->name = name; 1299c896fe29Sbellard } 1300085272b3SRichard Henderson return ts; 1301c896fe29Sbellard } 1302c896fe29Sbellard 13035bfa8034SRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, bool temp_local) 1304c896fe29Sbellard { 1305b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1306c896fe29Sbellard TCGTemp *ts; 1307641d5fbeSbellard int idx, k; 1308c896fe29Sbellard 13090ec9eabcSRichard Henderson k = type + (temp_local ? TCG_TYPE_COUNT : 0); 13100ec9eabcSRichard Henderson idx = find_first_bit(s->free_temps[k].l, TCG_MAX_TEMPS); 13110ec9eabcSRichard Henderson if (idx < TCG_MAX_TEMPS) { 13120ec9eabcSRichard Henderson /* There is already an available temp with the right type. */ 13130ec9eabcSRichard Henderson clear_bit(idx, s->free_temps[k].l); 13140ec9eabcSRichard Henderson 1315e8996ee0Sbellard ts = &s->temps[idx]; 1316e8996ee0Sbellard ts->temp_allocated = 1; 13177ca4b752SRichard Henderson tcg_debug_assert(ts->base_type == type); 13187ca4b752SRichard Henderson tcg_debug_assert(ts->temp_local == temp_local); 1319e8996ee0Sbellard } else { 13207ca4b752SRichard Henderson ts = tcg_temp_alloc(s); 13217ca4b752SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { 13227ca4b752SRichard Henderson TCGTemp *ts2 = tcg_temp_alloc(s); 13237ca4b752SRichard Henderson 1324c896fe29Sbellard ts->base_type = type; 1325c896fe29Sbellard ts->type = TCG_TYPE_I32; 1326e8996ee0Sbellard ts->temp_allocated = 1; 1327641d5fbeSbellard ts->temp_local = temp_local; 13287ca4b752SRichard Henderson 13297ca4b752SRichard Henderson tcg_debug_assert(ts2 == ts + 1); 13307ca4b752SRichard Henderson ts2->base_type = TCG_TYPE_I64; 13317ca4b752SRichard Henderson ts2->type = TCG_TYPE_I32; 13327ca4b752SRichard Henderson ts2->temp_allocated = 1; 13337ca4b752SRichard Henderson ts2->temp_local = temp_local; 13347ca4b752SRichard Henderson } else { 1335c896fe29Sbellard ts->base_type = type; 1336c896fe29Sbellard ts->type = type; 1337e8996ee0Sbellard ts->temp_allocated = 1; 1338641d5fbeSbellard ts->temp_local = temp_local; 1339c896fe29Sbellard } 1340e8996ee0Sbellard } 134127bfd83cSPeter Maydell 134227bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG) 134327bfd83cSPeter Maydell s->temps_in_use++; 134427bfd83cSPeter Maydell #endif 1345085272b3SRichard Henderson return ts; 1346c896fe29Sbellard } 1347c896fe29Sbellard 1348d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type) 1349d2fd745fSRichard Henderson { 1350d2fd745fSRichard Henderson TCGTemp *t; 1351d2fd745fSRichard Henderson 1352d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG 1353d2fd745fSRichard Henderson switch (type) { 1354d2fd745fSRichard Henderson case TCG_TYPE_V64: 1355d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v64); 1356d2fd745fSRichard Henderson break; 1357d2fd745fSRichard Henderson case TCG_TYPE_V128: 1358d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v128); 1359d2fd745fSRichard Henderson break; 1360d2fd745fSRichard Henderson case TCG_TYPE_V256: 1361d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v256); 1362d2fd745fSRichard Henderson break; 1363d2fd745fSRichard Henderson default: 1364d2fd745fSRichard Henderson g_assert_not_reached(); 1365d2fd745fSRichard Henderson } 1366d2fd745fSRichard Henderson #endif 1367d2fd745fSRichard Henderson 1368d2fd745fSRichard Henderson t = tcg_temp_new_internal(type, 0); 1369d2fd745fSRichard Henderson return temp_tcgv_vec(t); 1370d2fd745fSRichard Henderson } 1371d2fd745fSRichard Henderson 1372d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp. */ 1373d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match) 1374d2fd745fSRichard Henderson { 1375d2fd745fSRichard Henderson TCGTemp *t = tcgv_vec_temp(match); 1376d2fd745fSRichard Henderson 1377d2fd745fSRichard Henderson tcg_debug_assert(t->temp_allocated != 0); 1378d2fd745fSRichard Henderson 1379d2fd745fSRichard Henderson t = tcg_temp_new_internal(t->base_type, 0); 1380d2fd745fSRichard Henderson return temp_tcgv_vec(t); 1381d2fd745fSRichard Henderson } 1382d2fd745fSRichard Henderson 13835bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts) 1384c896fe29Sbellard { 1385b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1386085272b3SRichard Henderson int k, idx; 1387c896fe29Sbellard 138827bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG) 138927bfd83cSPeter Maydell s->temps_in_use--; 139027bfd83cSPeter Maydell if (s->temps_in_use < 0) { 139127bfd83cSPeter Maydell fprintf(stderr, "More temporaries freed than allocated!\n"); 139227bfd83cSPeter Maydell } 139327bfd83cSPeter Maydell #endif 139427bfd83cSPeter Maydell 1395085272b3SRichard Henderson tcg_debug_assert(ts->temp_global == 0); 1396eabb7b91SAurelien Jarno tcg_debug_assert(ts->temp_allocated != 0); 1397e8996ee0Sbellard ts->temp_allocated = 0; 13980ec9eabcSRichard Henderson 1399085272b3SRichard Henderson idx = temp_idx(ts); 140018d13fa2SAlexander Graf k = ts->base_type + (ts->temp_local ? TCG_TYPE_COUNT : 0); 14010ec9eabcSRichard Henderson set_bit(idx, s->free_temps[k].l); 1402e8996ee0Sbellard } 1403e8996ee0Sbellard 1404a7812ae4Spbrook TCGv_i32 tcg_const_i32(int32_t val) 1405a7812ae4Spbrook { 1406a7812ae4Spbrook TCGv_i32 t0; 1407a7812ae4Spbrook t0 = tcg_temp_new_i32(); 1408e8996ee0Sbellard tcg_gen_movi_i32(t0, val); 1409e8996ee0Sbellard return t0; 1410c896fe29Sbellard } 1411c896fe29Sbellard 1412a7812ae4Spbrook TCGv_i64 tcg_const_i64(int64_t val) 1413c896fe29Sbellard { 1414a7812ae4Spbrook TCGv_i64 t0; 1415a7812ae4Spbrook t0 = tcg_temp_new_i64(); 1416e8996ee0Sbellard tcg_gen_movi_i64(t0, val); 1417e8996ee0Sbellard return t0; 1418c896fe29Sbellard } 1419c896fe29Sbellard 1420a7812ae4Spbrook TCGv_i32 tcg_const_local_i32(int32_t val) 1421bdffd4a9Saurel32 { 1422a7812ae4Spbrook TCGv_i32 t0; 1423a7812ae4Spbrook t0 = tcg_temp_local_new_i32(); 1424bdffd4a9Saurel32 tcg_gen_movi_i32(t0, val); 1425bdffd4a9Saurel32 return t0; 1426bdffd4a9Saurel32 } 1427bdffd4a9Saurel32 1428a7812ae4Spbrook TCGv_i64 tcg_const_local_i64(int64_t val) 1429bdffd4a9Saurel32 { 1430a7812ae4Spbrook TCGv_i64 t0; 1431a7812ae4Spbrook t0 = tcg_temp_local_new_i64(); 1432bdffd4a9Saurel32 tcg_gen_movi_i64(t0, val); 1433bdffd4a9Saurel32 return t0; 1434bdffd4a9Saurel32 } 1435bdffd4a9Saurel32 143627bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG) 143727bfd83cSPeter Maydell void tcg_clear_temp_count(void) 143827bfd83cSPeter Maydell { 1439b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 144027bfd83cSPeter Maydell s->temps_in_use = 0; 144127bfd83cSPeter Maydell } 144227bfd83cSPeter Maydell 144327bfd83cSPeter Maydell int tcg_check_temp_count(void) 144427bfd83cSPeter Maydell { 1445b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 144627bfd83cSPeter Maydell if (s->temps_in_use) { 144727bfd83cSPeter Maydell /* Clear the count so that we don't give another 144827bfd83cSPeter Maydell * warning immediately next time around. 144927bfd83cSPeter Maydell */ 145027bfd83cSPeter Maydell s->temps_in_use = 0; 145127bfd83cSPeter Maydell return 1; 145227bfd83cSPeter Maydell } 145327bfd83cSPeter Maydell return 0; 145427bfd83cSPeter Maydell } 145527bfd83cSPeter Maydell #endif 145627bfd83cSPeter Maydell 1457be0f34b5SRichard Henderson /* Return true if OP may appear in the opcode stream. 1458be0f34b5SRichard Henderson Test the runtime variable that controls each opcode. */ 1459be0f34b5SRichard Henderson bool tcg_op_supported(TCGOpcode op) 1460be0f34b5SRichard Henderson { 1461d2fd745fSRichard Henderson const bool have_vec 1462d2fd745fSRichard Henderson = TCG_TARGET_HAS_v64 | TCG_TARGET_HAS_v128 | TCG_TARGET_HAS_v256; 1463d2fd745fSRichard Henderson 1464be0f34b5SRichard Henderson switch (op) { 1465be0f34b5SRichard Henderson case INDEX_op_discard: 1466be0f34b5SRichard Henderson case INDEX_op_set_label: 1467be0f34b5SRichard Henderson case INDEX_op_call: 1468be0f34b5SRichard Henderson case INDEX_op_br: 1469be0f34b5SRichard Henderson case INDEX_op_mb: 1470be0f34b5SRichard Henderson case INDEX_op_insn_start: 1471be0f34b5SRichard Henderson case INDEX_op_exit_tb: 1472be0f34b5SRichard Henderson case INDEX_op_goto_tb: 1473be0f34b5SRichard Henderson case INDEX_op_qemu_ld_i32: 1474be0f34b5SRichard Henderson case INDEX_op_qemu_st_i32: 1475be0f34b5SRichard Henderson case INDEX_op_qemu_ld_i64: 1476be0f34b5SRichard Henderson case INDEX_op_qemu_st_i64: 1477be0f34b5SRichard Henderson return true; 1478be0f34b5SRichard Henderson 147907ce0b05SRichard Henderson case INDEX_op_qemu_st8_i32: 148007ce0b05SRichard Henderson return TCG_TARGET_HAS_qemu_st8_i32; 148107ce0b05SRichard Henderson 1482be0f34b5SRichard Henderson case INDEX_op_goto_ptr: 1483be0f34b5SRichard Henderson return TCG_TARGET_HAS_goto_ptr; 1484be0f34b5SRichard Henderson 1485be0f34b5SRichard Henderson case INDEX_op_mov_i32: 1486be0f34b5SRichard Henderson case INDEX_op_movi_i32: 1487be0f34b5SRichard Henderson case INDEX_op_setcond_i32: 1488be0f34b5SRichard Henderson case INDEX_op_brcond_i32: 1489be0f34b5SRichard Henderson case INDEX_op_ld8u_i32: 1490be0f34b5SRichard Henderson case INDEX_op_ld8s_i32: 1491be0f34b5SRichard Henderson case INDEX_op_ld16u_i32: 1492be0f34b5SRichard Henderson case INDEX_op_ld16s_i32: 1493be0f34b5SRichard Henderson case INDEX_op_ld_i32: 1494be0f34b5SRichard Henderson case INDEX_op_st8_i32: 1495be0f34b5SRichard Henderson case INDEX_op_st16_i32: 1496be0f34b5SRichard Henderson case INDEX_op_st_i32: 1497be0f34b5SRichard Henderson case INDEX_op_add_i32: 1498be0f34b5SRichard Henderson case INDEX_op_sub_i32: 1499be0f34b5SRichard Henderson case INDEX_op_mul_i32: 1500be0f34b5SRichard Henderson case INDEX_op_and_i32: 1501be0f34b5SRichard Henderson case INDEX_op_or_i32: 1502be0f34b5SRichard Henderson case INDEX_op_xor_i32: 1503be0f34b5SRichard Henderson case INDEX_op_shl_i32: 1504be0f34b5SRichard Henderson case INDEX_op_shr_i32: 1505be0f34b5SRichard Henderson case INDEX_op_sar_i32: 1506be0f34b5SRichard Henderson return true; 1507be0f34b5SRichard Henderson 1508be0f34b5SRichard Henderson case INDEX_op_movcond_i32: 1509be0f34b5SRichard Henderson return TCG_TARGET_HAS_movcond_i32; 1510be0f34b5SRichard Henderson case INDEX_op_div_i32: 1511be0f34b5SRichard Henderson case INDEX_op_divu_i32: 1512be0f34b5SRichard Henderson return TCG_TARGET_HAS_div_i32; 1513be0f34b5SRichard Henderson case INDEX_op_rem_i32: 1514be0f34b5SRichard Henderson case INDEX_op_remu_i32: 1515be0f34b5SRichard Henderson return TCG_TARGET_HAS_rem_i32; 1516be0f34b5SRichard Henderson case INDEX_op_div2_i32: 1517be0f34b5SRichard Henderson case INDEX_op_divu2_i32: 1518be0f34b5SRichard Henderson return TCG_TARGET_HAS_div2_i32; 1519be0f34b5SRichard Henderson case INDEX_op_rotl_i32: 1520be0f34b5SRichard Henderson case INDEX_op_rotr_i32: 1521be0f34b5SRichard Henderson return TCG_TARGET_HAS_rot_i32; 1522be0f34b5SRichard Henderson case INDEX_op_deposit_i32: 1523be0f34b5SRichard Henderson return TCG_TARGET_HAS_deposit_i32; 1524be0f34b5SRichard Henderson case INDEX_op_extract_i32: 1525be0f34b5SRichard Henderson return TCG_TARGET_HAS_extract_i32; 1526be0f34b5SRichard Henderson case INDEX_op_sextract_i32: 1527be0f34b5SRichard Henderson return TCG_TARGET_HAS_sextract_i32; 1528fce1296fSRichard Henderson case INDEX_op_extract2_i32: 1529fce1296fSRichard Henderson return TCG_TARGET_HAS_extract2_i32; 1530be0f34b5SRichard Henderson case INDEX_op_add2_i32: 1531be0f34b5SRichard Henderson return TCG_TARGET_HAS_add2_i32; 1532be0f34b5SRichard Henderson case INDEX_op_sub2_i32: 1533be0f34b5SRichard Henderson return TCG_TARGET_HAS_sub2_i32; 1534be0f34b5SRichard Henderson case INDEX_op_mulu2_i32: 1535be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulu2_i32; 1536be0f34b5SRichard Henderson case INDEX_op_muls2_i32: 1537be0f34b5SRichard Henderson return TCG_TARGET_HAS_muls2_i32; 1538be0f34b5SRichard Henderson case INDEX_op_muluh_i32: 1539be0f34b5SRichard Henderson return TCG_TARGET_HAS_muluh_i32; 1540be0f34b5SRichard Henderson case INDEX_op_mulsh_i32: 1541be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulsh_i32; 1542be0f34b5SRichard Henderson case INDEX_op_ext8s_i32: 1543be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8s_i32; 1544be0f34b5SRichard Henderson case INDEX_op_ext16s_i32: 1545be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16s_i32; 1546be0f34b5SRichard Henderson case INDEX_op_ext8u_i32: 1547be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8u_i32; 1548be0f34b5SRichard Henderson case INDEX_op_ext16u_i32: 1549be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16u_i32; 1550be0f34b5SRichard Henderson case INDEX_op_bswap16_i32: 1551be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap16_i32; 1552be0f34b5SRichard Henderson case INDEX_op_bswap32_i32: 1553be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap32_i32; 1554be0f34b5SRichard Henderson case INDEX_op_not_i32: 1555be0f34b5SRichard Henderson return TCG_TARGET_HAS_not_i32; 1556be0f34b5SRichard Henderson case INDEX_op_neg_i32: 1557be0f34b5SRichard Henderson return TCG_TARGET_HAS_neg_i32; 1558be0f34b5SRichard Henderson case INDEX_op_andc_i32: 1559be0f34b5SRichard Henderson return TCG_TARGET_HAS_andc_i32; 1560be0f34b5SRichard Henderson case INDEX_op_orc_i32: 1561be0f34b5SRichard Henderson return TCG_TARGET_HAS_orc_i32; 1562be0f34b5SRichard Henderson case INDEX_op_eqv_i32: 1563be0f34b5SRichard Henderson return TCG_TARGET_HAS_eqv_i32; 1564be0f34b5SRichard Henderson case INDEX_op_nand_i32: 1565be0f34b5SRichard Henderson return TCG_TARGET_HAS_nand_i32; 1566be0f34b5SRichard Henderson case INDEX_op_nor_i32: 1567be0f34b5SRichard Henderson return TCG_TARGET_HAS_nor_i32; 1568be0f34b5SRichard Henderson case INDEX_op_clz_i32: 1569be0f34b5SRichard Henderson return TCG_TARGET_HAS_clz_i32; 1570be0f34b5SRichard Henderson case INDEX_op_ctz_i32: 1571be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctz_i32; 1572be0f34b5SRichard Henderson case INDEX_op_ctpop_i32: 1573be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctpop_i32; 1574be0f34b5SRichard Henderson 1575be0f34b5SRichard Henderson case INDEX_op_brcond2_i32: 1576be0f34b5SRichard Henderson case INDEX_op_setcond2_i32: 1577be0f34b5SRichard Henderson return TCG_TARGET_REG_BITS == 32; 1578be0f34b5SRichard Henderson 1579be0f34b5SRichard Henderson case INDEX_op_mov_i64: 1580be0f34b5SRichard Henderson case INDEX_op_movi_i64: 1581be0f34b5SRichard Henderson case INDEX_op_setcond_i64: 1582be0f34b5SRichard Henderson case INDEX_op_brcond_i64: 1583be0f34b5SRichard Henderson case INDEX_op_ld8u_i64: 1584be0f34b5SRichard Henderson case INDEX_op_ld8s_i64: 1585be0f34b5SRichard Henderson case INDEX_op_ld16u_i64: 1586be0f34b5SRichard Henderson case INDEX_op_ld16s_i64: 1587be0f34b5SRichard Henderson case INDEX_op_ld32u_i64: 1588be0f34b5SRichard Henderson case INDEX_op_ld32s_i64: 1589be0f34b5SRichard Henderson case INDEX_op_ld_i64: 1590be0f34b5SRichard Henderson case INDEX_op_st8_i64: 1591be0f34b5SRichard Henderson case INDEX_op_st16_i64: 1592be0f34b5SRichard Henderson case INDEX_op_st32_i64: 1593be0f34b5SRichard Henderson case INDEX_op_st_i64: 1594be0f34b5SRichard Henderson case INDEX_op_add_i64: 1595be0f34b5SRichard Henderson case INDEX_op_sub_i64: 1596be0f34b5SRichard Henderson case INDEX_op_mul_i64: 1597be0f34b5SRichard Henderson case INDEX_op_and_i64: 1598be0f34b5SRichard Henderson case INDEX_op_or_i64: 1599be0f34b5SRichard Henderson case INDEX_op_xor_i64: 1600be0f34b5SRichard Henderson case INDEX_op_shl_i64: 1601be0f34b5SRichard Henderson case INDEX_op_shr_i64: 1602be0f34b5SRichard Henderson case INDEX_op_sar_i64: 1603be0f34b5SRichard Henderson case INDEX_op_ext_i32_i64: 1604be0f34b5SRichard Henderson case INDEX_op_extu_i32_i64: 1605be0f34b5SRichard Henderson return TCG_TARGET_REG_BITS == 64; 1606be0f34b5SRichard Henderson 1607be0f34b5SRichard Henderson case INDEX_op_movcond_i64: 1608be0f34b5SRichard Henderson return TCG_TARGET_HAS_movcond_i64; 1609be0f34b5SRichard Henderson case INDEX_op_div_i64: 1610be0f34b5SRichard Henderson case INDEX_op_divu_i64: 1611be0f34b5SRichard Henderson return TCG_TARGET_HAS_div_i64; 1612be0f34b5SRichard Henderson case INDEX_op_rem_i64: 1613be0f34b5SRichard Henderson case INDEX_op_remu_i64: 1614be0f34b5SRichard Henderson return TCG_TARGET_HAS_rem_i64; 1615be0f34b5SRichard Henderson case INDEX_op_div2_i64: 1616be0f34b5SRichard Henderson case INDEX_op_divu2_i64: 1617be0f34b5SRichard Henderson return TCG_TARGET_HAS_div2_i64; 1618be0f34b5SRichard Henderson case INDEX_op_rotl_i64: 1619be0f34b5SRichard Henderson case INDEX_op_rotr_i64: 1620be0f34b5SRichard Henderson return TCG_TARGET_HAS_rot_i64; 1621be0f34b5SRichard Henderson case INDEX_op_deposit_i64: 1622be0f34b5SRichard Henderson return TCG_TARGET_HAS_deposit_i64; 1623be0f34b5SRichard Henderson case INDEX_op_extract_i64: 1624be0f34b5SRichard Henderson return TCG_TARGET_HAS_extract_i64; 1625be0f34b5SRichard Henderson case INDEX_op_sextract_i64: 1626be0f34b5SRichard Henderson return TCG_TARGET_HAS_sextract_i64; 1627fce1296fSRichard Henderson case INDEX_op_extract2_i64: 1628fce1296fSRichard Henderson return TCG_TARGET_HAS_extract2_i64; 1629be0f34b5SRichard Henderson case INDEX_op_extrl_i64_i32: 1630be0f34b5SRichard Henderson return TCG_TARGET_HAS_extrl_i64_i32; 1631be0f34b5SRichard Henderson case INDEX_op_extrh_i64_i32: 1632be0f34b5SRichard Henderson return TCG_TARGET_HAS_extrh_i64_i32; 1633be0f34b5SRichard Henderson case INDEX_op_ext8s_i64: 1634be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8s_i64; 1635be0f34b5SRichard Henderson case INDEX_op_ext16s_i64: 1636be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16s_i64; 1637be0f34b5SRichard Henderson case INDEX_op_ext32s_i64: 1638be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext32s_i64; 1639be0f34b5SRichard Henderson case INDEX_op_ext8u_i64: 1640be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8u_i64; 1641be0f34b5SRichard Henderson case INDEX_op_ext16u_i64: 1642be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16u_i64; 1643be0f34b5SRichard Henderson case INDEX_op_ext32u_i64: 1644be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext32u_i64; 1645be0f34b5SRichard Henderson case INDEX_op_bswap16_i64: 1646be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap16_i64; 1647be0f34b5SRichard Henderson case INDEX_op_bswap32_i64: 1648be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap32_i64; 1649be0f34b5SRichard Henderson case INDEX_op_bswap64_i64: 1650be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap64_i64; 1651be0f34b5SRichard Henderson case INDEX_op_not_i64: 1652be0f34b5SRichard Henderson return TCG_TARGET_HAS_not_i64; 1653be0f34b5SRichard Henderson case INDEX_op_neg_i64: 1654be0f34b5SRichard Henderson return TCG_TARGET_HAS_neg_i64; 1655be0f34b5SRichard Henderson case INDEX_op_andc_i64: 1656be0f34b5SRichard Henderson return TCG_TARGET_HAS_andc_i64; 1657be0f34b5SRichard Henderson case INDEX_op_orc_i64: 1658be0f34b5SRichard Henderson return TCG_TARGET_HAS_orc_i64; 1659be0f34b5SRichard Henderson case INDEX_op_eqv_i64: 1660be0f34b5SRichard Henderson return TCG_TARGET_HAS_eqv_i64; 1661be0f34b5SRichard Henderson case INDEX_op_nand_i64: 1662be0f34b5SRichard Henderson return TCG_TARGET_HAS_nand_i64; 1663be0f34b5SRichard Henderson case INDEX_op_nor_i64: 1664be0f34b5SRichard Henderson return TCG_TARGET_HAS_nor_i64; 1665be0f34b5SRichard Henderson case INDEX_op_clz_i64: 1666be0f34b5SRichard Henderson return TCG_TARGET_HAS_clz_i64; 1667be0f34b5SRichard Henderson case INDEX_op_ctz_i64: 1668be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctz_i64; 1669be0f34b5SRichard Henderson case INDEX_op_ctpop_i64: 1670be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctpop_i64; 1671be0f34b5SRichard Henderson case INDEX_op_add2_i64: 1672be0f34b5SRichard Henderson return TCG_TARGET_HAS_add2_i64; 1673be0f34b5SRichard Henderson case INDEX_op_sub2_i64: 1674be0f34b5SRichard Henderson return TCG_TARGET_HAS_sub2_i64; 1675be0f34b5SRichard Henderson case INDEX_op_mulu2_i64: 1676be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulu2_i64; 1677be0f34b5SRichard Henderson case INDEX_op_muls2_i64: 1678be0f34b5SRichard Henderson return TCG_TARGET_HAS_muls2_i64; 1679be0f34b5SRichard Henderson case INDEX_op_muluh_i64: 1680be0f34b5SRichard Henderson return TCG_TARGET_HAS_muluh_i64; 1681be0f34b5SRichard Henderson case INDEX_op_mulsh_i64: 1682be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulsh_i64; 1683be0f34b5SRichard Henderson 1684d2fd745fSRichard Henderson case INDEX_op_mov_vec: 1685d2fd745fSRichard Henderson case INDEX_op_dup_vec: 1686d2fd745fSRichard Henderson case INDEX_op_dupi_vec: 168737ee55a0SRichard Henderson case INDEX_op_dupm_vec: 1688d2fd745fSRichard Henderson case INDEX_op_ld_vec: 1689d2fd745fSRichard Henderson case INDEX_op_st_vec: 1690d2fd745fSRichard Henderson case INDEX_op_add_vec: 1691d2fd745fSRichard Henderson case INDEX_op_sub_vec: 1692d2fd745fSRichard Henderson case INDEX_op_and_vec: 1693d2fd745fSRichard Henderson case INDEX_op_or_vec: 1694d2fd745fSRichard Henderson case INDEX_op_xor_vec: 1695212be173SRichard Henderson case INDEX_op_cmp_vec: 1696d2fd745fSRichard Henderson return have_vec; 1697d2fd745fSRichard Henderson case INDEX_op_dup2_vec: 1698d2fd745fSRichard Henderson return have_vec && TCG_TARGET_REG_BITS == 32; 1699d2fd745fSRichard Henderson case INDEX_op_not_vec: 1700d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_not_vec; 1701d2fd745fSRichard Henderson case INDEX_op_neg_vec: 1702d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_neg_vec; 1703bcefc902SRichard Henderson case INDEX_op_abs_vec: 1704bcefc902SRichard Henderson return have_vec && TCG_TARGET_HAS_abs_vec; 1705d2fd745fSRichard Henderson case INDEX_op_andc_vec: 1706d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_andc_vec; 1707d2fd745fSRichard Henderson case INDEX_op_orc_vec: 1708d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_orc_vec; 17093774030aSRichard Henderson case INDEX_op_mul_vec: 17103774030aSRichard Henderson return have_vec && TCG_TARGET_HAS_mul_vec; 1711d0ec9796SRichard Henderson case INDEX_op_shli_vec: 1712d0ec9796SRichard Henderson case INDEX_op_shri_vec: 1713d0ec9796SRichard Henderson case INDEX_op_sari_vec: 1714d0ec9796SRichard Henderson return have_vec && TCG_TARGET_HAS_shi_vec; 1715d0ec9796SRichard Henderson case INDEX_op_shls_vec: 1716d0ec9796SRichard Henderson case INDEX_op_shrs_vec: 1717d0ec9796SRichard Henderson case INDEX_op_sars_vec: 1718d0ec9796SRichard Henderson return have_vec && TCG_TARGET_HAS_shs_vec; 1719d0ec9796SRichard Henderson case INDEX_op_shlv_vec: 1720d0ec9796SRichard Henderson case INDEX_op_shrv_vec: 1721d0ec9796SRichard Henderson case INDEX_op_sarv_vec: 1722d0ec9796SRichard Henderson return have_vec && TCG_TARGET_HAS_shv_vec; 1723b0f7e744SRichard Henderson case INDEX_op_rotli_vec: 1724b0f7e744SRichard Henderson return have_vec && TCG_TARGET_HAS_roti_vec; 172523850a74SRichard Henderson case INDEX_op_rotls_vec: 172623850a74SRichard Henderson return have_vec && TCG_TARGET_HAS_rots_vec; 17275d0ceda9SRichard Henderson case INDEX_op_rotlv_vec: 17285d0ceda9SRichard Henderson case INDEX_op_rotrv_vec: 17295d0ceda9SRichard Henderson return have_vec && TCG_TARGET_HAS_rotv_vec; 17308afaf050SRichard Henderson case INDEX_op_ssadd_vec: 17318afaf050SRichard Henderson case INDEX_op_usadd_vec: 17328afaf050SRichard Henderson case INDEX_op_sssub_vec: 17338afaf050SRichard Henderson case INDEX_op_ussub_vec: 17348afaf050SRichard Henderson return have_vec && TCG_TARGET_HAS_sat_vec; 1735dd0a0fcdSRichard Henderson case INDEX_op_smin_vec: 1736dd0a0fcdSRichard Henderson case INDEX_op_umin_vec: 1737dd0a0fcdSRichard Henderson case INDEX_op_smax_vec: 1738dd0a0fcdSRichard Henderson case INDEX_op_umax_vec: 1739dd0a0fcdSRichard Henderson return have_vec && TCG_TARGET_HAS_minmax_vec; 174038dc1294SRichard Henderson case INDEX_op_bitsel_vec: 174138dc1294SRichard Henderson return have_vec && TCG_TARGET_HAS_bitsel_vec; 1742f75da298SRichard Henderson case INDEX_op_cmpsel_vec: 1743f75da298SRichard Henderson return have_vec && TCG_TARGET_HAS_cmpsel_vec; 1744d2fd745fSRichard Henderson 1745db432672SRichard Henderson default: 1746db432672SRichard Henderson tcg_debug_assert(op > INDEX_op_last_generic && op < NB_OPS); 1747db432672SRichard Henderson return true; 1748be0f34b5SRichard Henderson } 1749be0f34b5SRichard Henderson } 1750be0f34b5SRichard Henderson 175139cf05d3Sbellard /* Note: we convert the 64 bit args to 32 bit and do some alignment 175239cf05d3Sbellard and endian swap. Maybe it would be better to do the alignment 175339cf05d3Sbellard and endian swap in tcg_reg_alloc_call(). */ 1754ae8b75dcSRichard Henderson void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args) 1755c896fe29Sbellard { 175675e8b9b7SRichard Henderson int i, real_args, nb_rets, pi; 1757bbb8a1b4SRichard Henderson unsigned sizemask, flags; 1758afb49896SRichard Henderson TCGHelperInfo *info; 175975e8b9b7SRichard Henderson TCGOp *op; 1760afb49896SRichard Henderson 1761619205fdSEmilio G. Cota info = g_hash_table_lookup(helper_table, (gpointer)func); 1762bbb8a1b4SRichard Henderson flags = info->flags; 1763bbb8a1b4SRichard Henderson sizemask = info->sizemask; 17642bece2c8SRichard Henderson 176538b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN 176638b47b19SEmilio G. Cota /* detect non-plugin helpers */ 176738b47b19SEmilio G. Cota if (tcg_ctx->plugin_insn && unlikely(strncmp(info->name, "plugin_", 7))) { 176838b47b19SEmilio G. Cota tcg_ctx->plugin_insn->calls_helpers = true; 176938b47b19SEmilio G. Cota } 177038b47b19SEmilio G. Cota #endif 177138b47b19SEmilio G. Cota 177234b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \ 177334b1a49cSRichard Henderson && !defined(CONFIG_TCG_INTERPRETER) 177434b1a49cSRichard Henderson /* We have 64-bit values in one register, but need to pass as two 177534b1a49cSRichard Henderson separate parameters. Split them. */ 177634b1a49cSRichard Henderson int orig_sizemask = sizemask; 177734b1a49cSRichard Henderson int orig_nargs = nargs; 177834b1a49cSRichard Henderson TCGv_i64 retl, reth; 1779ae8b75dcSRichard Henderson TCGTemp *split_args[MAX_OPC_PARAM]; 178034b1a49cSRichard Henderson 1781f764718dSRichard Henderson retl = NULL; 1782f764718dSRichard Henderson reth = NULL; 178334b1a49cSRichard Henderson if (sizemask != 0) { 178434b1a49cSRichard Henderson for (i = real_args = 0; i < nargs; ++i) { 178534b1a49cSRichard Henderson int is_64bit = sizemask & (1 << (i+1)*2); 178634b1a49cSRichard Henderson if (is_64bit) { 1787085272b3SRichard Henderson TCGv_i64 orig = temp_tcgv_i64(args[i]); 178834b1a49cSRichard Henderson TCGv_i32 h = tcg_temp_new_i32(); 178934b1a49cSRichard Henderson TCGv_i32 l = tcg_temp_new_i32(); 179034b1a49cSRichard Henderson tcg_gen_extr_i64_i32(l, h, orig); 1791ae8b75dcSRichard Henderson split_args[real_args++] = tcgv_i32_temp(h); 1792ae8b75dcSRichard Henderson split_args[real_args++] = tcgv_i32_temp(l); 179334b1a49cSRichard Henderson } else { 179434b1a49cSRichard Henderson split_args[real_args++] = args[i]; 179534b1a49cSRichard Henderson } 179634b1a49cSRichard Henderson } 179734b1a49cSRichard Henderson nargs = real_args; 179834b1a49cSRichard Henderson args = split_args; 179934b1a49cSRichard Henderson sizemask = 0; 180034b1a49cSRichard Henderson } 180134b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64 18022bece2c8SRichard Henderson for (i = 0; i < nargs; ++i) { 18032bece2c8SRichard Henderson int is_64bit = sizemask & (1 << (i+1)*2); 18042bece2c8SRichard Henderson int is_signed = sizemask & (2 << (i+1)*2); 18052bece2c8SRichard Henderson if (!is_64bit) { 18062bece2c8SRichard Henderson TCGv_i64 temp = tcg_temp_new_i64(); 1807085272b3SRichard Henderson TCGv_i64 orig = temp_tcgv_i64(args[i]); 18082bece2c8SRichard Henderson if (is_signed) { 18092bece2c8SRichard Henderson tcg_gen_ext32s_i64(temp, orig); 18102bece2c8SRichard Henderson } else { 18112bece2c8SRichard Henderson tcg_gen_ext32u_i64(temp, orig); 18122bece2c8SRichard Henderson } 1813ae8b75dcSRichard Henderson args[i] = tcgv_i64_temp(temp); 18142bece2c8SRichard Henderson } 18152bece2c8SRichard Henderson } 18162bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */ 18172bece2c8SRichard Henderson 181815fa08f8SRichard Henderson op = tcg_emit_op(INDEX_op_call); 181975e8b9b7SRichard Henderson 182075e8b9b7SRichard Henderson pi = 0; 1821ae8b75dcSRichard Henderson if (ret != NULL) { 182234b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \ 182334b1a49cSRichard Henderson && !defined(CONFIG_TCG_INTERPRETER) 182434b1a49cSRichard Henderson if (orig_sizemask & 1) { 182534b1a49cSRichard Henderson /* The 32-bit ABI is going to return the 64-bit value in 182634b1a49cSRichard Henderson the %o0/%o1 register pair. Prepare for this by using 182734b1a49cSRichard Henderson two return temporaries, and reassemble below. */ 182834b1a49cSRichard Henderson retl = tcg_temp_new_i64(); 182934b1a49cSRichard Henderson reth = tcg_temp_new_i64(); 1830ae8b75dcSRichard Henderson op->args[pi++] = tcgv_i64_arg(reth); 1831ae8b75dcSRichard Henderson op->args[pi++] = tcgv_i64_arg(retl); 183234b1a49cSRichard Henderson nb_rets = 2; 183334b1a49cSRichard Henderson } else { 1834ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(ret); 183534b1a49cSRichard Henderson nb_rets = 1; 183634b1a49cSRichard Henderson } 183734b1a49cSRichard Henderson #else 183834b1a49cSRichard Henderson if (TCG_TARGET_REG_BITS < 64 && (sizemask & 1)) { 183902eb19d0SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 1840ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(ret + 1); 1841ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(ret); 1842a7812ae4Spbrook #else 1843ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(ret); 1844ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(ret + 1); 1845a7812ae4Spbrook #endif 1846a7812ae4Spbrook nb_rets = 2; 184734b1a49cSRichard Henderson } else { 1848ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(ret); 1849a7812ae4Spbrook nb_rets = 1; 1850a7812ae4Spbrook } 185134b1a49cSRichard Henderson #endif 1852a7812ae4Spbrook } else { 1853a7812ae4Spbrook nb_rets = 0; 1854a7812ae4Spbrook } 1855cd9090aaSRichard Henderson TCGOP_CALLO(op) = nb_rets; 185675e8b9b7SRichard Henderson 1857a7812ae4Spbrook real_args = 0; 1858a7812ae4Spbrook for (i = 0; i < nargs; i++) { 18592bece2c8SRichard Henderson int is_64bit = sizemask & (1 << (i+1)*2); 1860bbb8a1b4SRichard Henderson if (TCG_TARGET_REG_BITS < 64 && is_64bit) { 186139cf05d3Sbellard #ifdef TCG_TARGET_CALL_ALIGN_ARGS 186239cf05d3Sbellard /* some targets want aligned 64 bit args */ 1863ebd486d5Smalc if (real_args & 1) { 186475e8b9b7SRichard Henderson op->args[pi++] = TCG_CALL_DUMMY_ARG; 1865ebd486d5Smalc real_args++; 186639cf05d3Sbellard } 186739cf05d3Sbellard #endif 18683f90f252SRichard Henderson /* If stack grows up, then we will be placing successive 18693f90f252SRichard Henderson arguments at lower addresses, which means we need to 18703f90f252SRichard Henderson reverse the order compared to how we would normally 18713f90f252SRichard Henderson treat either big or little-endian. For those arguments 18723f90f252SRichard Henderson that will wind up in registers, this still works for 18733f90f252SRichard Henderson HPPA (the only current STACK_GROWSUP target) since the 18743f90f252SRichard Henderson argument registers are *also* allocated in decreasing 18753f90f252SRichard Henderson order. If another such target is added, this logic may 18763f90f252SRichard Henderson have to get more complicated to differentiate between 18773f90f252SRichard Henderson stack arguments and register arguments. */ 187802eb19d0SRichard Henderson #if defined(HOST_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP) 1879ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(args[i] + 1); 1880ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(args[i]); 1881c896fe29Sbellard #else 1882ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(args[i]); 1883ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(args[i] + 1); 1884c896fe29Sbellard #endif 1885a7812ae4Spbrook real_args += 2; 18862bece2c8SRichard Henderson continue; 18872bece2c8SRichard Henderson } 18882bece2c8SRichard Henderson 1889ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(args[i]); 1890a7812ae4Spbrook real_args++; 1891c896fe29Sbellard } 189275e8b9b7SRichard Henderson op->args[pi++] = (uintptr_t)func; 189375e8b9b7SRichard Henderson op->args[pi++] = flags; 1894cd9090aaSRichard Henderson TCGOP_CALLI(op) = real_args; 1895a7812ae4Spbrook 189675e8b9b7SRichard Henderson /* Make sure the fields didn't overflow. */ 1897cd9090aaSRichard Henderson tcg_debug_assert(TCGOP_CALLI(op) == real_args); 189875e8b9b7SRichard Henderson tcg_debug_assert(pi <= ARRAY_SIZE(op->args)); 18992bece2c8SRichard Henderson 190034b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \ 190134b1a49cSRichard Henderson && !defined(CONFIG_TCG_INTERPRETER) 190234b1a49cSRichard Henderson /* Free all of the parts we allocated above. */ 190334b1a49cSRichard Henderson for (i = real_args = 0; i < orig_nargs; ++i) { 190434b1a49cSRichard Henderson int is_64bit = orig_sizemask & (1 << (i+1)*2); 190534b1a49cSRichard Henderson if (is_64bit) { 1906085272b3SRichard Henderson tcg_temp_free_internal(args[real_args++]); 1907085272b3SRichard Henderson tcg_temp_free_internal(args[real_args++]); 190834b1a49cSRichard Henderson } else { 190934b1a49cSRichard Henderson real_args++; 191034b1a49cSRichard Henderson } 191134b1a49cSRichard Henderson } 191234b1a49cSRichard Henderson if (orig_sizemask & 1) { 191334b1a49cSRichard Henderson /* The 32-bit ABI returned two 32-bit pieces. Re-assemble them. 191434b1a49cSRichard Henderson Note that describing these as TCGv_i64 eliminates an unnecessary 191534b1a49cSRichard Henderson zero-extension that tcg_gen_concat_i32_i64 would create. */ 1916085272b3SRichard Henderson tcg_gen_concat32_i64(temp_tcgv_i64(ret), retl, reth); 191734b1a49cSRichard Henderson tcg_temp_free_i64(retl); 191834b1a49cSRichard Henderson tcg_temp_free_i64(reth); 191934b1a49cSRichard Henderson } 192034b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64 19212bece2c8SRichard Henderson for (i = 0; i < nargs; ++i) { 19222bece2c8SRichard Henderson int is_64bit = sizemask & (1 << (i+1)*2); 19232bece2c8SRichard Henderson if (!is_64bit) { 1924085272b3SRichard Henderson tcg_temp_free_internal(args[i]); 19252bece2c8SRichard Henderson } 19262bece2c8SRichard Henderson } 19272bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */ 1928a7812ae4Spbrook } 1929c896fe29Sbellard 19308fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s) 1931c896fe29Sbellard { 1932ac3b8891SRichard Henderson int i, n; 1933c896fe29Sbellard TCGTemp *ts; 1934ac3b8891SRichard Henderson 1935ac3b8891SRichard Henderson for (i = 0, n = s->nb_globals; i < n; i++) { 1936c896fe29Sbellard ts = &s->temps[i]; 1937ac3b8891SRichard Henderson ts->val_type = (ts->fixed_reg ? TEMP_VAL_REG : TEMP_VAL_MEM); 1938c896fe29Sbellard } 1939ac3b8891SRichard Henderson for (n = s->nb_temps; i < n; i++) { 1940e8996ee0Sbellard ts = &s->temps[i]; 1941ac3b8891SRichard Henderson ts->val_type = (ts->temp_local ? TEMP_VAL_MEM : TEMP_VAL_DEAD); 1942e8996ee0Sbellard ts->mem_allocated = 0; 1943e8996ee0Sbellard ts->fixed_reg = 0; 1944e8996ee0Sbellard } 1945f8b2f202SRichard Henderson 1946f8b2f202SRichard Henderson memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp)); 1947c896fe29Sbellard } 1948c896fe29Sbellard 1949f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size, 1950f8b2f202SRichard Henderson TCGTemp *ts) 1951c896fe29Sbellard { 19521807f4c4SRichard Henderson int idx = temp_idx(ts); 1953ac56dd48Spbrook 1954fa477d25SRichard Henderson if (ts->temp_global) { 1955ac56dd48Spbrook pstrcpy(buf, buf_size, ts->name); 1956f8b2f202SRichard Henderson } else if (ts->temp_local) { 1957641d5fbeSbellard snprintf(buf, buf_size, "loc%d", idx - s->nb_globals); 1958f8b2f202SRichard Henderson } else { 1959ac56dd48Spbrook snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals); 1960c896fe29Sbellard } 1961c896fe29Sbellard return buf; 1962c896fe29Sbellard } 1963c896fe29Sbellard 196443439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf, 196543439139SRichard Henderson int buf_size, TCGArg arg) 1966f8b2f202SRichard Henderson { 196743439139SRichard Henderson return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg)); 1968f8b2f202SRichard Henderson } 1969f8b2f202SRichard Henderson 19706e085f72SRichard Henderson /* Find helper name. */ 19716e085f72SRichard Henderson static inline const char *tcg_find_helper(TCGContext *s, uintptr_t val) 1972e8996ee0Sbellard { 19736e085f72SRichard Henderson const char *ret = NULL; 1974619205fdSEmilio G. Cota if (helper_table) { 1975619205fdSEmilio G. Cota TCGHelperInfo *info = g_hash_table_lookup(helper_table, (gpointer)val); 197672866e82SRichard Henderson if (info) { 197772866e82SRichard Henderson ret = info->name; 197872866e82SRichard Henderson } 1979e8996ee0Sbellard } 19806e085f72SRichard Henderson return ret; 19814dc81f28Sbellard } 19824dc81f28Sbellard 1983f48f3edeSblueswir1 static const char * const cond_name[] = 1984f48f3edeSblueswir1 { 19850aed257fSRichard Henderson [TCG_COND_NEVER] = "never", 19860aed257fSRichard Henderson [TCG_COND_ALWAYS] = "always", 1987f48f3edeSblueswir1 [TCG_COND_EQ] = "eq", 1988f48f3edeSblueswir1 [TCG_COND_NE] = "ne", 1989f48f3edeSblueswir1 [TCG_COND_LT] = "lt", 1990f48f3edeSblueswir1 [TCG_COND_GE] = "ge", 1991f48f3edeSblueswir1 [TCG_COND_LE] = "le", 1992f48f3edeSblueswir1 [TCG_COND_GT] = "gt", 1993f48f3edeSblueswir1 [TCG_COND_LTU] = "ltu", 1994f48f3edeSblueswir1 [TCG_COND_GEU] = "geu", 1995f48f3edeSblueswir1 [TCG_COND_LEU] = "leu", 1996f48f3edeSblueswir1 [TCG_COND_GTU] = "gtu" 1997f48f3edeSblueswir1 }; 1998f48f3edeSblueswir1 1999f713d6adSRichard Henderson static const char * const ldst_name[] = 2000f713d6adSRichard Henderson { 2001f713d6adSRichard Henderson [MO_UB] = "ub", 2002f713d6adSRichard Henderson [MO_SB] = "sb", 2003f713d6adSRichard Henderson [MO_LEUW] = "leuw", 2004f713d6adSRichard Henderson [MO_LESW] = "lesw", 2005f713d6adSRichard Henderson [MO_LEUL] = "leul", 2006f713d6adSRichard Henderson [MO_LESL] = "lesl", 2007f713d6adSRichard Henderson [MO_LEQ] = "leq", 2008f713d6adSRichard Henderson [MO_BEUW] = "beuw", 2009f713d6adSRichard Henderson [MO_BESW] = "besw", 2010f713d6adSRichard Henderson [MO_BEUL] = "beul", 2011f713d6adSRichard Henderson [MO_BESL] = "besl", 2012f713d6adSRichard Henderson [MO_BEQ] = "beq", 2013f713d6adSRichard Henderson }; 2014f713d6adSRichard Henderson 20151f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = { 201652bf9771Stony.nguyen@bt.com #ifdef TARGET_ALIGNED_ONLY 20171f00b27fSSergey Sorokin [MO_UNALN >> MO_ASHIFT] = "un+", 20181f00b27fSSergey Sorokin [MO_ALIGN >> MO_ASHIFT] = "", 20191f00b27fSSergey Sorokin #else 20201f00b27fSSergey Sorokin [MO_UNALN >> MO_ASHIFT] = "", 20211f00b27fSSergey Sorokin [MO_ALIGN >> MO_ASHIFT] = "al+", 20221f00b27fSSergey Sorokin #endif 20231f00b27fSSergey Sorokin [MO_ALIGN_2 >> MO_ASHIFT] = "al2+", 20241f00b27fSSergey Sorokin [MO_ALIGN_4 >> MO_ASHIFT] = "al4+", 20251f00b27fSSergey Sorokin [MO_ALIGN_8 >> MO_ASHIFT] = "al8+", 20261f00b27fSSergey Sorokin [MO_ALIGN_16 >> MO_ASHIFT] = "al16+", 20271f00b27fSSergey Sorokin [MO_ALIGN_32 >> MO_ASHIFT] = "al32+", 20281f00b27fSSergey Sorokin [MO_ALIGN_64 >> MO_ASHIFT] = "al64+", 20291f00b27fSSergey Sorokin }; 20301f00b27fSSergey Sorokin 2031b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d) 2032b016486eSRichard Henderson { 2033b016486eSRichard Henderson return (d & (d - 1)) == 0; 2034b016486eSRichard Henderson } 2035b016486eSRichard Henderson 2036b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d) 2037b016486eSRichard Henderson { 2038b016486eSRichard Henderson if (TCG_TARGET_NB_REGS <= 32) { 2039b016486eSRichard Henderson return ctz32(d); 2040b016486eSRichard Henderson } else { 2041b016486eSRichard Henderson return ctz64(d); 2042b016486eSRichard Henderson } 2043b016486eSRichard Henderson } 2044b016486eSRichard Henderson 20451894f69aSRichard Henderson static void tcg_dump_ops(TCGContext *s, bool have_prefs) 2046c896fe29Sbellard { 2047c896fe29Sbellard char buf[128]; 2048c45cb8bbSRichard Henderson TCGOp *op; 2049c896fe29Sbellard 205015fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 2051c45cb8bbSRichard Henderson int i, k, nb_oargs, nb_iargs, nb_cargs; 2052c45cb8bbSRichard Henderson const TCGOpDef *def; 2053c45cb8bbSRichard Henderson TCGOpcode c; 2054bdfb460eSRichard Henderson int col = 0; 2055c45cb8bbSRichard Henderson 2056c45cb8bbSRichard Henderson c = op->opc; 2057c896fe29Sbellard def = &tcg_op_defs[c]; 2058c45cb8bbSRichard Henderson 2059765b842aSRichard Henderson if (c == INDEX_op_insn_start) { 2060b016486eSRichard Henderson nb_oargs = 0; 206115fa08f8SRichard Henderson col += qemu_log("\n ----"); 20629aef40edSRichard Henderson 20639aef40edSRichard Henderson for (i = 0; i < TARGET_INSN_START_WORDS; ++i) { 20649aef40edSRichard Henderson target_ulong a; 20657e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS 2066efee3746SRichard Henderson a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]); 20677e4597d7Sbellard #else 2068efee3746SRichard Henderson a = op->args[i]; 20697e4597d7Sbellard #endif 2070bdfb460eSRichard Henderson col += qemu_log(" " TARGET_FMT_lx, a); 2071eeacee4dSBlue Swirl } 20727e4597d7Sbellard } else if (c == INDEX_op_call) { 2073c896fe29Sbellard /* variable number of arguments */ 2074cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 2075cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 2076c896fe29Sbellard nb_cargs = def->nb_cargs; 2077b03cce8eSbellard 2078cf066674SRichard Henderson /* function name, flags, out args */ 2079bdfb460eSRichard Henderson col += qemu_log(" %s %s,$0x%" TCG_PRIlx ",$%d", def->name, 2080efee3746SRichard Henderson tcg_find_helper(s, op->args[nb_oargs + nb_iargs]), 2081efee3746SRichard Henderson op->args[nb_oargs + nb_iargs + 1], nb_oargs); 2082b03cce8eSbellard for (i = 0; i < nb_oargs; i++) { 208343439139SRichard Henderson col += qemu_log(",%s", tcg_get_arg_str(s, buf, sizeof(buf), 2084efee3746SRichard Henderson op->args[i])); 2085b03cce8eSbellard } 2086cf066674SRichard Henderson for (i = 0; i < nb_iargs; i++) { 2087efee3746SRichard Henderson TCGArg arg = op->args[nb_oargs + i]; 2088cf066674SRichard Henderson const char *t = "<dummy>"; 2089cf066674SRichard Henderson if (arg != TCG_CALL_DUMMY_ARG) { 209043439139SRichard Henderson t = tcg_get_arg_str(s, buf, sizeof(buf), arg); 2091b03cce8eSbellard } 2092bdfb460eSRichard Henderson col += qemu_log(",%s", t); 2093e8996ee0Sbellard } 2094b03cce8eSbellard } else { 2095bdfb460eSRichard Henderson col += qemu_log(" %s ", def->name); 2096c45cb8bbSRichard Henderson 2097c896fe29Sbellard nb_oargs = def->nb_oargs; 2098c896fe29Sbellard nb_iargs = def->nb_iargs; 2099c896fe29Sbellard nb_cargs = def->nb_cargs; 2100c896fe29Sbellard 2101d2fd745fSRichard Henderson if (def->flags & TCG_OPF_VECTOR) { 2102d2fd745fSRichard Henderson col += qemu_log("v%d,e%d,", 64 << TCGOP_VECL(op), 2103d2fd745fSRichard Henderson 8 << TCGOP_VECE(op)); 2104d2fd745fSRichard Henderson } 2105d2fd745fSRichard Henderson 2106c896fe29Sbellard k = 0; 2107c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 2108eeacee4dSBlue Swirl if (k != 0) { 2109bdfb460eSRichard Henderson col += qemu_log(","); 2110eeacee4dSBlue Swirl } 211143439139SRichard Henderson col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf), 2112efee3746SRichard Henderson op->args[k++])); 2113c896fe29Sbellard } 2114c896fe29Sbellard for (i = 0; i < nb_iargs; i++) { 2115eeacee4dSBlue Swirl if (k != 0) { 2116bdfb460eSRichard Henderson col += qemu_log(","); 2117eeacee4dSBlue Swirl } 211843439139SRichard Henderson col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf), 2119efee3746SRichard Henderson op->args[k++])); 2120c896fe29Sbellard } 2121be210acbSRichard Henderson switch (c) { 2122be210acbSRichard Henderson case INDEX_op_brcond_i32: 2123ffc5ea09SRichard Henderson case INDEX_op_setcond_i32: 2124ffc5ea09SRichard Henderson case INDEX_op_movcond_i32: 2125be210acbSRichard Henderson case INDEX_op_brcond2_i32: 2126be210acbSRichard Henderson case INDEX_op_setcond2_i32: 2127ffc5ea09SRichard Henderson case INDEX_op_brcond_i64: 2128be210acbSRichard Henderson case INDEX_op_setcond_i64: 2129ffc5ea09SRichard Henderson case INDEX_op_movcond_i64: 2130212be173SRichard Henderson case INDEX_op_cmp_vec: 2131f75da298SRichard Henderson case INDEX_op_cmpsel_vec: 2132efee3746SRichard Henderson if (op->args[k] < ARRAY_SIZE(cond_name) 2133efee3746SRichard Henderson && cond_name[op->args[k]]) { 2134efee3746SRichard Henderson col += qemu_log(",%s", cond_name[op->args[k++]]); 2135eeacee4dSBlue Swirl } else { 2136efee3746SRichard Henderson col += qemu_log(",$0x%" TCG_PRIlx, op->args[k++]); 2137eeacee4dSBlue Swirl } 2138f48f3edeSblueswir1 i = 1; 2139be210acbSRichard Henderson break; 2140f713d6adSRichard Henderson case INDEX_op_qemu_ld_i32: 2141f713d6adSRichard Henderson case INDEX_op_qemu_st_i32: 214207ce0b05SRichard Henderson case INDEX_op_qemu_st8_i32: 2143f713d6adSRichard Henderson case INDEX_op_qemu_ld_i64: 2144f713d6adSRichard Henderson case INDEX_op_qemu_st_i64: 214559227d5dSRichard Henderson { 2146efee3746SRichard Henderson TCGMemOpIdx oi = op->args[k++]; 214714776ab5STony Nguyen MemOp op = get_memop(oi); 214859227d5dSRichard Henderson unsigned ix = get_mmuidx(oi); 214959227d5dSRichard Henderson 215059c4b7e8SRichard Henderson if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) { 2151bdfb460eSRichard Henderson col += qemu_log(",$0x%x,%u", op, ix); 215259c4b7e8SRichard Henderson } else { 21531f00b27fSSergey Sorokin const char *s_al, *s_op; 21541f00b27fSSergey Sorokin s_al = alignment_name[(op & MO_AMASK) >> MO_ASHIFT]; 215559c4b7e8SRichard Henderson s_op = ldst_name[op & (MO_BSWAP | MO_SSIZE)]; 2156bdfb460eSRichard Henderson col += qemu_log(",%s%s,%u", s_al, s_op, ix); 2157f713d6adSRichard Henderson } 2158f713d6adSRichard Henderson i = 1; 215959227d5dSRichard Henderson } 2160f713d6adSRichard Henderson break; 2161be210acbSRichard Henderson default: 2162f48f3edeSblueswir1 i = 0; 2163be210acbSRichard Henderson break; 2164be210acbSRichard Henderson } 216551e3972cSRichard Henderson switch (c) { 216651e3972cSRichard Henderson case INDEX_op_set_label: 216751e3972cSRichard Henderson case INDEX_op_br: 216851e3972cSRichard Henderson case INDEX_op_brcond_i32: 216951e3972cSRichard Henderson case INDEX_op_brcond_i64: 217051e3972cSRichard Henderson case INDEX_op_brcond2_i32: 2171efee3746SRichard Henderson col += qemu_log("%s$L%d", k ? "," : "", 2172efee3746SRichard Henderson arg_label(op->args[k])->id); 217351e3972cSRichard Henderson i++, k++; 217451e3972cSRichard Henderson break; 217551e3972cSRichard Henderson default: 217651e3972cSRichard Henderson break; 2177eeacee4dSBlue Swirl } 217851e3972cSRichard Henderson for (; i < nb_cargs; i++, k++) { 2179efee3746SRichard Henderson col += qemu_log("%s$0x%" TCG_PRIlx, k ? "," : "", op->args[k]); 2180bdfb460eSRichard Henderson } 2181bdfb460eSRichard Henderson } 2182bdfb460eSRichard Henderson 21831894f69aSRichard Henderson if (have_prefs || op->life) { 21847606488cSRobert Foley 21857606488cSRobert Foley QemuLogFile *logfile; 21867606488cSRobert Foley 21877606488cSRobert Foley rcu_read_lock(); 2188d73415a3SStefan Hajnoczi logfile = qatomic_rcu_read(&qemu_logfile); 21897606488cSRobert Foley if (logfile) { 21901894f69aSRichard Henderson for (; col < 40; ++col) { 21917606488cSRobert Foley putc(' ', logfile->fd); 2192bdfb460eSRichard Henderson } 21931894f69aSRichard Henderson } 21947606488cSRobert Foley rcu_read_unlock(); 21957606488cSRobert Foley } 21961894f69aSRichard Henderson 21971894f69aSRichard Henderson if (op->life) { 21981894f69aSRichard Henderson unsigned life = op->life; 2199bdfb460eSRichard Henderson 2200bdfb460eSRichard Henderson if (life & (SYNC_ARG * 3)) { 2201bdfb460eSRichard Henderson qemu_log(" sync:"); 2202bdfb460eSRichard Henderson for (i = 0; i < 2; ++i) { 2203bdfb460eSRichard Henderson if (life & (SYNC_ARG << i)) { 2204bdfb460eSRichard Henderson qemu_log(" %d", i); 2205bdfb460eSRichard Henderson } 2206bdfb460eSRichard Henderson } 2207bdfb460eSRichard Henderson } 2208bdfb460eSRichard Henderson life /= DEAD_ARG; 2209bdfb460eSRichard Henderson if (life) { 2210bdfb460eSRichard Henderson qemu_log(" dead:"); 2211bdfb460eSRichard Henderson for (i = 0; life; ++i, life >>= 1) { 2212bdfb460eSRichard Henderson if (life & 1) { 2213bdfb460eSRichard Henderson qemu_log(" %d", i); 2214bdfb460eSRichard Henderson } 2215bdfb460eSRichard Henderson } 2216c896fe29Sbellard } 2217b03cce8eSbellard } 22181894f69aSRichard Henderson 22191894f69aSRichard Henderson if (have_prefs) { 22201894f69aSRichard Henderson for (i = 0; i < nb_oargs; ++i) { 22211894f69aSRichard Henderson TCGRegSet set = op->output_pref[i]; 22221894f69aSRichard Henderson 22231894f69aSRichard Henderson if (i == 0) { 22241894f69aSRichard Henderson qemu_log(" pref="); 22251894f69aSRichard Henderson } else { 22261894f69aSRichard Henderson qemu_log(","); 22271894f69aSRichard Henderson } 22281894f69aSRichard Henderson if (set == 0) { 22291894f69aSRichard Henderson qemu_log("none"); 22301894f69aSRichard Henderson } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) { 22311894f69aSRichard Henderson qemu_log("all"); 22321894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG 22331894f69aSRichard Henderson } else if (tcg_regset_single(set)) { 22341894f69aSRichard Henderson TCGReg reg = tcg_regset_first(set); 22351894f69aSRichard Henderson qemu_log("%s", tcg_target_reg_names[reg]); 22361894f69aSRichard Henderson #endif 22371894f69aSRichard Henderson } else if (TCG_TARGET_NB_REGS <= 32) { 22381894f69aSRichard Henderson qemu_log("%#x", (uint32_t)set); 22391894f69aSRichard Henderson } else { 22401894f69aSRichard Henderson qemu_log("%#" PRIx64, (uint64_t)set); 22411894f69aSRichard Henderson } 22421894f69aSRichard Henderson } 22431894f69aSRichard Henderson } 22441894f69aSRichard Henderson 2245eeacee4dSBlue Swirl qemu_log("\n"); 2246c896fe29Sbellard } 2247c896fe29Sbellard } 2248c896fe29Sbellard 2249c896fe29Sbellard /* we give more priority to constraints with less registers */ 2250c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k) 2251c896fe29Sbellard { 225274a11790SRichard Henderson const TCGArgConstraint *arg_ct = &def->args_ct[k]; 225374a11790SRichard Henderson int n; 2254c896fe29Sbellard 2255bc2b17e6SRichard Henderson if (arg_ct->oalias) { 2256c896fe29Sbellard /* an alias is equivalent to a single register */ 2257c896fe29Sbellard n = 1; 2258c896fe29Sbellard } else { 225974a11790SRichard Henderson n = ctpop64(arg_ct->regs); 2260c896fe29Sbellard } 2261c896fe29Sbellard return TCG_TARGET_NB_REGS - n + 1; 2262c896fe29Sbellard } 2263c896fe29Sbellard 2264c896fe29Sbellard /* sort from highest priority to lowest */ 2265c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n) 2266c896fe29Sbellard { 226766792f90SRichard Henderson int i, j; 226866792f90SRichard Henderson TCGArgConstraint *a = def->args_ct; 2269c896fe29Sbellard 227066792f90SRichard Henderson for (i = 0; i < n; i++) { 227166792f90SRichard Henderson a[start + i].sort_index = start + i; 227266792f90SRichard Henderson } 227366792f90SRichard Henderson if (n <= 1) { 2274c896fe29Sbellard return; 227566792f90SRichard Henderson } 2276c896fe29Sbellard for (i = 0; i < n - 1; i++) { 2277c896fe29Sbellard for (j = i + 1; j < n; j++) { 227866792f90SRichard Henderson int p1 = get_constraint_priority(def, a[start + i].sort_index); 227966792f90SRichard Henderson int p2 = get_constraint_priority(def, a[start + j].sort_index); 2280c896fe29Sbellard if (p1 < p2) { 228166792f90SRichard Henderson int tmp = a[start + i].sort_index; 228266792f90SRichard Henderson a[start + i].sort_index = a[start + j].sort_index; 228366792f90SRichard Henderson a[start + j].sort_index = tmp; 2284c896fe29Sbellard } 2285c896fe29Sbellard } 2286c896fe29Sbellard } 2287c896fe29Sbellard } 2288c896fe29Sbellard 2289f69d277eSRichard Henderson static void process_op_defs(TCGContext *s) 2290c896fe29Sbellard { 2291a9751609SRichard Henderson TCGOpcode op; 2292c896fe29Sbellard 2293f69d277eSRichard Henderson for (op = 0; op < NB_OPS; op++) { 2294f69d277eSRichard Henderson TCGOpDef *def = &tcg_op_defs[op]; 2295f69d277eSRichard Henderson const TCGTargetOpDef *tdefs; 2296069ea736SRichard Henderson TCGType type; 2297069ea736SRichard Henderson int i, nb_args; 2298f69d277eSRichard Henderson 2299f69d277eSRichard Henderson if (def->flags & TCG_OPF_NOT_PRESENT) { 2300f69d277eSRichard Henderson continue; 2301f69d277eSRichard Henderson } 2302f69d277eSRichard Henderson 2303c896fe29Sbellard nb_args = def->nb_iargs + def->nb_oargs; 2304f69d277eSRichard Henderson if (nb_args == 0) { 2305f69d277eSRichard Henderson continue; 2306f69d277eSRichard Henderson } 2307f69d277eSRichard Henderson 2308f69d277eSRichard Henderson tdefs = tcg_target_op_def(op); 2309f69d277eSRichard Henderson /* Missing TCGTargetOpDef entry. */ 2310f69d277eSRichard Henderson tcg_debug_assert(tdefs != NULL); 2311f69d277eSRichard Henderson 2312069ea736SRichard Henderson type = (def->flags & TCG_OPF_64BIT ? TCG_TYPE_I64 : TCG_TYPE_I32); 2313c896fe29Sbellard for (i = 0; i < nb_args; i++) { 2314f69d277eSRichard Henderson const char *ct_str = tdefs->args_ct_str[i]; 2315f69d277eSRichard Henderson /* Incomplete TCGTargetOpDef entry. */ 2316eabb7b91SAurelien Jarno tcg_debug_assert(ct_str != NULL); 2317f69d277eSRichard Henderson 231817280ff4SRichard Henderson while (*ct_str != '\0') { 231917280ff4SRichard Henderson switch(*ct_str) { 232017280ff4SRichard Henderson case '0' ... '9': 232117280ff4SRichard Henderson { 232217280ff4SRichard Henderson int oarg = *ct_str - '0'; 232317280ff4SRichard Henderson tcg_debug_assert(ct_str == tdefs->args_ct_str[i]); 2324eabb7b91SAurelien Jarno tcg_debug_assert(oarg < def->nb_oargs); 232574a11790SRichard Henderson tcg_debug_assert(def->args_ct[oarg].regs != 0); 2326c896fe29Sbellard def->args_ct[i] = def->args_ct[oarg]; 2327bc2b17e6SRichard Henderson /* The output sets oalias. */ 2328bc2b17e6SRichard Henderson def->args_ct[oarg].oalias = true; 23295ff9d6a4Sbellard def->args_ct[oarg].alias_index = i; 2330bc2b17e6SRichard Henderson /* The input sets ialias. */ 2331bc2b17e6SRichard Henderson def->args_ct[i].ialias = true; 23325ff9d6a4Sbellard def->args_ct[i].alias_index = oarg; 233317280ff4SRichard Henderson } 233417280ff4SRichard Henderson ct_str++; 2335c896fe29Sbellard break; 233682790a87SRichard Henderson case '&': 2337bc2b17e6SRichard Henderson def->args_ct[i].newreg = true; 233882790a87SRichard Henderson ct_str++; 233982790a87SRichard Henderson break; 2340c896fe29Sbellard case 'i': 2341c896fe29Sbellard def->args_ct[i].ct |= TCG_CT_CONST; 2342c896fe29Sbellard ct_str++; 2343c896fe29Sbellard break; 2344c896fe29Sbellard default: 2345069ea736SRichard Henderson ct_str = target_parse_constraint(&def->args_ct[i], 2346069ea736SRichard Henderson ct_str, type); 2347f69d277eSRichard Henderson /* Typo in TCGTargetOpDef constraint. */ 2348069ea736SRichard Henderson tcg_debug_assert(ct_str != NULL); 2349c896fe29Sbellard } 2350c896fe29Sbellard } 2351c896fe29Sbellard } 2352c896fe29Sbellard 2353c68aaa18SStefan Weil /* TCGTargetOpDef entry with too much information? */ 2354eabb7b91SAurelien Jarno tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL); 2355c68aaa18SStefan Weil 2356c896fe29Sbellard /* sort the constraints (XXX: this is just an heuristic) */ 2357c896fe29Sbellard sort_constraints(def, 0, def->nb_oargs); 2358c896fe29Sbellard sort_constraints(def, def->nb_oargs, def->nb_iargs); 2359c896fe29Sbellard } 2360c896fe29Sbellard } 2361c896fe29Sbellard 23620c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op) 23630c627cdcSRichard Henderson { 2364d88a117eSRichard Henderson TCGLabel *label; 2365d88a117eSRichard Henderson 2366d88a117eSRichard Henderson switch (op->opc) { 2367d88a117eSRichard Henderson case INDEX_op_br: 2368d88a117eSRichard Henderson label = arg_label(op->args[0]); 2369d88a117eSRichard Henderson label->refs--; 2370d88a117eSRichard Henderson break; 2371d88a117eSRichard Henderson case INDEX_op_brcond_i32: 2372d88a117eSRichard Henderson case INDEX_op_brcond_i64: 2373d88a117eSRichard Henderson label = arg_label(op->args[3]); 2374d88a117eSRichard Henderson label->refs--; 2375d88a117eSRichard Henderson break; 2376d88a117eSRichard Henderson case INDEX_op_brcond2_i32: 2377d88a117eSRichard Henderson label = arg_label(op->args[5]); 2378d88a117eSRichard Henderson label->refs--; 2379d88a117eSRichard Henderson break; 2380d88a117eSRichard Henderson default: 2381d88a117eSRichard Henderson break; 2382d88a117eSRichard Henderson } 2383d88a117eSRichard Henderson 238415fa08f8SRichard Henderson QTAILQ_REMOVE(&s->ops, op, link); 238515fa08f8SRichard Henderson QTAILQ_INSERT_TAIL(&s->free_ops, op, link); 2386abebf925SRichard Henderson s->nb_ops--; 23870c627cdcSRichard Henderson 23880c627cdcSRichard Henderson #ifdef CONFIG_PROFILER 2389d73415a3SStefan Hajnoczi qatomic_set(&s->prof.del_op_count, s->prof.del_op_count + 1); 23900c627cdcSRichard Henderson #endif 23910c627cdcSRichard Henderson } 23920c627cdcSRichard Henderson 239315fa08f8SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc) 239415fa08f8SRichard Henderson { 239515fa08f8SRichard Henderson TCGContext *s = tcg_ctx; 239615fa08f8SRichard Henderson TCGOp *op; 239715fa08f8SRichard Henderson 239815fa08f8SRichard Henderson if (likely(QTAILQ_EMPTY(&s->free_ops))) { 239915fa08f8SRichard Henderson op = tcg_malloc(sizeof(TCGOp)); 240015fa08f8SRichard Henderson } else { 240115fa08f8SRichard Henderson op = QTAILQ_FIRST(&s->free_ops); 240215fa08f8SRichard Henderson QTAILQ_REMOVE(&s->free_ops, op, link); 240315fa08f8SRichard Henderson } 240415fa08f8SRichard Henderson memset(op, 0, offsetof(TCGOp, link)); 240515fa08f8SRichard Henderson op->opc = opc; 2406abebf925SRichard Henderson s->nb_ops++; 240715fa08f8SRichard Henderson 240815fa08f8SRichard Henderson return op; 240915fa08f8SRichard Henderson } 241015fa08f8SRichard Henderson 241115fa08f8SRichard Henderson TCGOp *tcg_emit_op(TCGOpcode opc) 241215fa08f8SRichard Henderson { 241315fa08f8SRichard Henderson TCGOp *op = tcg_op_alloc(opc); 241415fa08f8SRichard Henderson QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link); 241515fa08f8SRichard Henderson return op; 241615fa08f8SRichard Henderson } 241715fa08f8SRichard Henderson 2418ac1043f6SEmilio G. Cota TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op, TCGOpcode opc) 24195a18407fSRichard Henderson { 242015fa08f8SRichard Henderson TCGOp *new_op = tcg_op_alloc(opc); 242115fa08f8SRichard Henderson QTAILQ_INSERT_BEFORE(old_op, new_op, link); 24225a18407fSRichard Henderson return new_op; 24235a18407fSRichard Henderson } 24245a18407fSRichard Henderson 2425ac1043f6SEmilio G. Cota TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, TCGOpcode opc) 24265a18407fSRichard Henderson { 242715fa08f8SRichard Henderson TCGOp *new_op = tcg_op_alloc(opc); 242815fa08f8SRichard Henderson QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link); 24295a18407fSRichard Henderson return new_op; 24305a18407fSRichard Henderson } 24315a18407fSRichard Henderson 2432b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code. */ 2433b4fc67c7SRichard Henderson static void reachable_code_pass(TCGContext *s) 2434b4fc67c7SRichard Henderson { 2435b4fc67c7SRichard Henderson TCGOp *op, *op_next; 2436b4fc67c7SRichard Henderson bool dead = false; 2437b4fc67c7SRichard Henderson 2438b4fc67c7SRichard Henderson QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) { 2439b4fc67c7SRichard Henderson bool remove = dead; 2440b4fc67c7SRichard Henderson TCGLabel *label; 2441b4fc67c7SRichard Henderson int call_flags; 2442b4fc67c7SRichard Henderson 2443b4fc67c7SRichard Henderson switch (op->opc) { 2444b4fc67c7SRichard Henderson case INDEX_op_set_label: 2445b4fc67c7SRichard Henderson label = arg_label(op->args[0]); 2446b4fc67c7SRichard Henderson if (label->refs == 0) { 2447b4fc67c7SRichard Henderson /* 2448b4fc67c7SRichard Henderson * While there is an occasional backward branch, virtually 2449b4fc67c7SRichard Henderson * all branches generated by the translators are forward. 2450b4fc67c7SRichard Henderson * Which means that generally we will have already removed 2451b4fc67c7SRichard Henderson * all references to the label that will be, and there is 2452b4fc67c7SRichard Henderson * little to be gained by iterating. 2453b4fc67c7SRichard Henderson */ 2454b4fc67c7SRichard Henderson remove = true; 2455b4fc67c7SRichard Henderson } else { 2456b4fc67c7SRichard Henderson /* Once we see a label, insns become live again. */ 2457b4fc67c7SRichard Henderson dead = false; 2458b4fc67c7SRichard Henderson remove = false; 2459b4fc67c7SRichard Henderson 2460b4fc67c7SRichard Henderson /* 2461b4fc67c7SRichard Henderson * Optimization can fold conditional branches to unconditional. 2462b4fc67c7SRichard Henderson * If we find a label with one reference which is preceded by 2463b4fc67c7SRichard Henderson * an unconditional branch to it, remove both. This needed to 2464b4fc67c7SRichard Henderson * wait until the dead code in between them was removed. 2465b4fc67c7SRichard Henderson */ 2466b4fc67c7SRichard Henderson if (label->refs == 1) { 2467eae3eb3eSPaolo Bonzini TCGOp *op_prev = QTAILQ_PREV(op, link); 2468b4fc67c7SRichard Henderson if (op_prev->opc == INDEX_op_br && 2469b4fc67c7SRichard Henderson label == arg_label(op_prev->args[0])) { 2470b4fc67c7SRichard Henderson tcg_op_remove(s, op_prev); 2471b4fc67c7SRichard Henderson remove = true; 2472b4fc67c7SRichard Henderson } 2473b4fc67c7SRichard Henderson } 2474b4fc67c7SRichard Henderson } 2475b4fc67c7SRichard Henderson break; 2476b4fc67c7SRichard Henderson 2477b4fc67c7SRichard Henderson case INDEX_op_br: 2478b4fc67c7SRichard Henderson case INDEX_op_exit_tb: 2479b4fc67c7SRichard Henderson case INDEX_op_goto_ptr: 2480b4fc67c7SRichard Henderson /* Unconditional branches; everything following is dead. */ 2481b4fc67c7SRichard Henderson dead = true; 2482b4fc67c7SRichard Henderson break; 2483b4fc67c7SRichard Henderson 2484b4fc67c7SRichard Henderson case INDEX_op_call: 2485b4fc67c7SRichard Henderson /* Notice noreturn helper calls, raising exceptions. */ 2486b4fc67c7SRichard Henderson call_flags = op->args[TCGOP_CALLO(op) + TCGOP_CALLI(op) + 1]; 2487b4fc67c7SRichard Henderson if (call_flags & TCG_CALL_NO_RETURN) { 2488b4fc67c7SRichard Henderson dead = true; 2489b4fc67c7SRichard Henderson } 2490b4fc67c7SRichard Henderson break; 2491b4fc67c7SRichard Henderson 2492b4fc67c7SRichard Henderson case INDEX_op_insn_start: 2493b4fc67c7SRichard Henderson /* Never remove -- we need to keep these for unwind. */ 2494b4fc67c7SRichard Henderson remove = false; 2495b4fc67c7SRichard Henderson break; 2496b4fc67c7SRichard Henderson 2497b4fc67c7SRichard Henderson default: 2498b4fc67c7SRichard Henderson break; 2499b4fc67c7SRichard Henderson } 2500b4fc67c7SRichard Henderson 2501b4fc67c7SRichard Henderson if (remove) { 2502b4fc67c7SRichard Henderson tcg_op_remove(s, op); 2503b4fc67c7SRichard Henderson } 2504b4fc67c7SRichard Henderson } 2505b4fc67c7SRichard Henderson } 2506b4fc67c7SRichard Henderson 2507c70fbf0aSRichard Henderson #define TS_DEAD 1 2508c70fbf0aSRichard Henderson #define TS_MEM 2 2509c70fbf0aSRichard Henderson 25105a18407fSRichard Henderson #define IS_DEAD_ARG(n) (arg_life & (DEAD_ARG << (n))) 25115a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n))) 25125a18407fSRichard Henderson 251325f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp. */ 251425f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts) 251525f49c5fSRichard Henderson { 251625f49c5fSRichard Henderson return ts->state_ptr; 251725f49c5fSRichard Henderson } 251825f49c5fSRichard Henderson 251925f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the 252025f49c5fSRichard Henderson * maximal regset for its type. 252125f49c5fSRichard Henderson */ 252225f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts) 252325f49c5fSRichard Henderson { 252425f49c5fSRichard Henderson *la_temp_pref(ts) 252525f49c5fSRichard Henderson = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]); 252625f49c5fSRichard Henderson } 252725f49c5fSRichard Henderson 25289c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals 25299c43b68dSAurelien Jarno should be in memory. */ 25302616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt) 2531c896fe29Sbellard { 2532b83eabeaSRichard Henderson int i; 2533b83eabeaSRichard Henderson 2534b83eabeaSRichard Henderson for (i = 0; i < ng; ++i) { 2535b83eabeaSRichard Henderson s->temps[i].state = TS_DEAD | TS_MEM; 253625f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 2537b83eabeaSRichard Henderson } 2538b83eabeaSRichard Henderson for (i = ng; i < nt; ++i) { 2539b83eabeaSRichard Henderson s->temps[i].state = TS_DEAD; 254025f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 2541b83eabeaSRichard Henderson } 2542c896fe29Sbellard } 2543c896fe29Sbellard 25449c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals 25459c43b68dSAurelien Jarno and local temps should be in memory. */ 25462616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt) 2547641d5fbeSbellard { 2548b83eabeaSRichard Henderson int i; 2549641d5fbeSbellard 2550b83eabeaSRichard Henderson for (i = 0; i < ng; ++i) { 2551b83eabeaSRichard Henderson s->temps[i].state = TS_DEAD | TS_MEM; 255225f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 2553c70fbf0aSRichard Henderson } 2554b83eabeaSRichard Henderson for (i = ng; i < nt; ++i) { 2555b83eabeaSRichard Henderson s->temps[i].state = (s->temps[i].temp_local 2556b83eabeaSRichard Henderson ? TS_DEAD | TS_MEM 2557b83eabeaSRichard Henderson : TS_DEAD); 255825f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 2559641d5fbeSbellard } 2560641d5fbeSbellard } 2561641d5fbeSbellard 2562f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory. */ 2563f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng) 2564f65a061cSRichard Henderson { 2565f65a061cSRichard Henderson int i; 2566f65a061cSRichard Henderson 2567f65a061cSRichard Henderson for (i = 0; i < ng; ++i) { 256825f49c5fSRichard Henderson int state = s->temps[i].state; 256925f49c5fSRichard Henderson s->temps[i].state = state | TS_MEM; 257025f49c5fSRichard Henderson if (state == TS_DEAD) { 257125f49c5fSRichard Henderson /* If the global was previously dead, reset prefs. */ 257225f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 257325f49c5fSRichard Henderson } 2574f65a061cSRichard Henderson } 2575f65a061cSRichard Henderson } 2576f65a061cSRichard Henderson 2577b4cb76e6SRichard Henderson /* 2578b4cb76e6SRichard Henderson * liveness analysis: conditional branch: all temps are dead, 2579b4cb76e6SRichard Henderson * globals and local temps should be synced. 2580b4cb76e6SRichard Henderson */ 2581b4cb76e6SRichard Henderson static void la_bb_sync(TCGContext *s, int ng, int nt) 2582b4cb76e6SRichard Henderson { 2583b4cb76e6SRichard Henderson la_global_sync(s, ng); 2584b4cb76e6SRichard Henderson 2585b4cb76e6SRichard Henderson for (int i = ng; i < nt; ++i) { 2586b4cb76e6SRichard Henderson if (s->temps[i].temp_local) { 2587b4cb76e6SRichard Henderson int state = s->temps[i].state; 2588b4cb76e6SRichard Henderson s->temps[i].state = state | TS_MEM; 2589b4cb76e6SRichard Henderson if (state != TS_DEAD) { 2590b4cb76e6SRichard Henderson continue; 2591b4cb76e6SRichard Henderson } 2592b4cb76e6SRichard Henderson } else { 2593b4cb76e6SRichard Henderson s->temps[i].state = TS_DEAD; 2594b4cb76e6SRichard Henderson } 2595b4cb76e6SRichard Henderson la_reset_pref(&s->temps[i]); 2596b4cb76e6SRichard Henderson } 2597b4cb76e6SRichard Henderson } 2598b4cb76e6SRichard Henderson 2599f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill. */ 2600f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng) 2601f65a061cSRichard Henderson { 2602f65a061cSRichard Henderson int i; 2603f65a061cSRichard Henderson 2604f65a061cSRichard Henderson for (i = 0; i < ng; i++) { 2605f65a061cSRichard Henderson s->temps[i].state = TS_DEAD | TS_MEM; 260625f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 260725f49c5fSRichard Henderson } 260825f49c5fSRichard Henderson } 260925f49c5fSRichard Henderson 261025f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls. */ 261125f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt) 261225f49c5fSRichard Henderson { 261325f49c5fSRichard Henderson TCGRegSet mask = ~tcg_target_call_clobber_regs; 261425f49c5fSRichard Henderson int i; 261525f49c5fSRichard Henderson 261625f49c5fSRichard Henderson for (i = 0; i < nt; i++) { 261725f49c5fSRichard Henderson TCGTemp *ts = &s->temps[i]; 261825f49c5fSRichard Henderson if (!(ts->state & TS_DEAD)) { 261925f49c5fSRichard Henderson TCGRegSet *pset = la_temp_pref(ts); 262025f49c5fSRichard Henderson TCGRegSet set = *pset; 262125f49c5fSRichard Henderson 262225f49c5fSRichard Henderson set &= mask; 262325f49c5fSRichard Henderson /* If the combination is not possible, restart. */ 262425f49c5fSRichard Henderson if (set == 0) { 262525f49c5fSRichard Henderson set = tcg_target_available_regs[ts->type] & mask; 262625f49c5fSRichard Henderson } 262725f49c5fSRichard Henderson *pset = set; 262825f49c5fSRichard Henderson } 2629f65a061cSRichard Henderson } 2630f65a061cSRichard Henderson } 2631f65a061cSRichard Henderson 2632a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a 2633c896fe29Sbellard given input arguments is dead. Instructions updating dead 2634c896fe29Sbellard temporaries are removed. */ 2635b83eabeaSRichard Henderson static void liveness_pass_1(TCGContext *s) 2636c896fe29Sbellard { 2637c70fbf0aSRichard Henderson int nb_globals = s->nb_globals; 26382616c808SRichard Henderson int nb_temps = s->nb_temps; 263915fa08f8SRichard Henderson TCGOp *op, *op_prev; 264025f49c5fSRichard Henderson TCGRegSet *prefs; 264125f49c5fSRichard Henderson int i; 264225f49c5fSRichard Henderson 264325f49c5fSRichard Henderson prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps); 264425f49c5fSRichard Henderson for (i = 0; i < nb_temps; ++i) { 264525f49c5fSRichard Henderson s->temps[i].state_ptr = prefs + i; 264625f49c5fSRichard Henderson } 2647c896fe29Sbellard 2648ae36a246SRichard Henderson /* ??? Should be redundant with the exit_tb that ends the TB. */ 26492616c808SRichard Henderson la_func_end(s, nb_globals, nb_temps); 2650c896fe29Sbellard 2651eae3eb3eSPaolo Bonzini QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) { 265225f49c5fSRichard Henderson int nb_iargs, nb_oargs; 2653c45cb8bbSRichard Henderson TCGOpcode opc_new, opc_new2; 2654c45cb8bbSRichard Henderson bool have_opc_new2; 2655a1b3c48dSRichard Henderson TCGLifeData arg_life = 0; 265625f49c5fSRichard Henderson TCGTemp *ts; 2657c45cb8bbSRichard Henderson TCGOpcode opc = op->opc; 2658c45cb8bbSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 2659c45cb8bbSRichard Henderson 2660c45cb8bbSRichard Henderson switch (opc) { 2661c896fe29Sbellard case INDEX_op_call: 2662c6e113f5Sbellard { 2663c6e113f5Sbellard int call_flags; 266425f49c5fSRichard Henderson int nb_call_regs; 2665c6e113f5Sbellard 2666cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 2667cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 2668efee3746SRichard Henderson call_flags = op->args[nb_oargs + nb_iargs + 1]; 2669c6e113f5Sbellard 2670c45cb8bbSRichard Henderson /* pure functions can be removed if their result is unused */ 267178505279SAurelien Jarno if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) { 2672c6e113f5Sbellard for (i = 0; i < nb_oargs; i++) { 267325f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 267425f49c5fSRichard Henderson if (ts->state != TS_DEAD) { 2675c6e113f5Sbellard goto do_not_remove_call; 2676c6e113f5Sbellard } 26779c43b68dSAurelien Jarno } 2678c45cb8bbSRichard Henderson goto do_remove; 2679152c35aaSRichard Henderson } 2680c6e113f5Sbellard do_not_remove_call: 2681c896fe29Sbellard 268225f49c5fSRichard Henderson /* Output args are dead. */ 2683c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 268425f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 268525f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 2686a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 26876b64b624SAurelien Jarno } 268825f49c5fSRichard Henderson if (ts->state & TS_MEM) { 2689a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i; 26909c43b68dSAurelien Jarno } 269125f49c5fSRichard Henderson ts->state = TS_DEAD; 269225f49c5fSRichard Henderson la_reset_pref(ts); 269325f49c5fSRichard Henderson 269425f49c5fSRichard Henderson /* Not used -- it will be tcg_target_call_oarg_regs[i]. */ 269525f49c5fSRichard Henderson op->output_pref[i] = 0; 2696c896fe29Sbellard } 2697c896fe29Sbellard 269878505279SAurelien Jarno if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS | 269978505279SAurelien Jarno TCG_CALL_NO_READ_GLOBALS))) { 2700f65a061cSRichard Henderson la_global_kill(s, nb_globals); 2701c70fbf0aSRichard Henderson } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) { 2702f65a061cSRichard Henderson la_global_sync(s, nb_globals); 2703b9c18f56Saurel32 } 2704c896fe29Sbellard 270525f49c5fSRichard Henderson /* Record arguments that die in this helper. */ 2706866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 270725f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 270825f49c5fSRichard Henderson if (ts && ts->state & TS_DEAD) { 2709a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 2710c896fe29Sbellard } 2711c896fe29Sbellard } 271225f49c5fSRichard Henderson 271325f49c5fSRichard Henderson /* For all live registers, remove call-clobbered prefs. */ 271425f49c5fSRichard Henderson la_cross_call(s, nb_temps); 271525f49c5fSRichard Henderson 271625f49c5fSRichard Henderson nb_call_regs = ARRAY_SIZE(tcg_target_call_iarg_regs); 271725f49c5fSRichard Henderson 271825f49c5fSRichard Henderson /* Input arguments are live for preceding opcodes. */ 271925f49c5fSRichard Henderson for (i = 0; i < nb_iargs; i++) { 272025f49c5fSRichard Henderson ts = arg_temp(op->args[i + nb_oargs]); 272125f49c5fSRichard Henderson if (ts && ts->state & TS_DEAD) { 272225f49c5fSRichard Henderson /* For those arguments that die, and will be allocated 272325f49c5fSRichard Henderson * in registers, clear the register set for that arg, 272425f49c5fSRichard Henderson * to be filled in below. For args that will be on 272525f49c5fSRichard Henderson * the stack, reset to any available reg. 272625f49c5fSRichard Henderson */ 272725f49c5fSRichard Henderson *la_temp_pref(ts) 272825f49c5fSRichard Henderson = (i < nb_call_regs ? 0 : 272925f49c5fSRichard Henderson tcg_target_available_regs[ts->type]); 273025f49c5fSRichard Henderson ts->state &= ~TS_DEAD; 273125f49c5fSRichard Henderson } 273225f49c5fSRichard Henderson } 273325f49c5fSRichard Henderson 273425f49c5fSRichard Henderson /* For each input argument, add its input register to prefs. 273525f49c5fSRichard Henderson If a temp is used once, this produces a single set bit. */ 273625f49c5fSRichard Henderson for (i = 0; i < MIN(nb_call_regs, nb_iargs); i++) { 273725f49c5fSRichard Henderson ts = arg_temp(op->args[i + nb_oargs]); 273825f49c5fSRichard Henderson if (ts) { 273925f49c5fSRichard Henderson tcg_regset_set_reg(*la_temp_pref(ts), 274025f49c5fSRichard Henderson tcg_target_call_iarg_regs[i]); 2741c70fbf0aSRichard Henderson } 2742c19f47bfSAurelien Jarno } 2743c6e113f5Sbellard } 2744c896fe29Sbellard break; 2745765b842aSRichard Henderson case INDEX_op_insn_start: 2746c896fe29Sbellard break; 27475ff9d6a4Sbellard case INDEX_op_discard: 27485ff9d6a4Sbellard /* mark the temporary as dead */ 274925f49c5fSRichard Henderson ts = arg_temp(op->args[0]); 275025f49c5fSRichard Henderson ts->state = TS_DEAD; 275125f49c5fSRichard Henderson la_reset_pref(ts); 27525ff9d6a4Sbellard break; 27531305c451SRichard Henderson 27541305c451SRichard Henderson case INDEX_op_add2_i32: 2755c45cb8bbSRichard Henderson opc_new = INDEX_op_add_i32; 2756f1fae40cSRichard Henderson goto do_addsub2; 27571305c451SRichard Henderson case INDEX_op_sub2_i32: 2758c45cb8bbSRichard Henderson opc_new = INDEX_op_sub_i32; 2759f1fae40cSRichard Henderson goto do_addsub2; 2760f1fae40cSRichard Henderson case INDEX_op_add2_i64: 2761c45cb8bbSRichard Henderson opc_new = INDEX_op_add_i64; 2762f1fae40cSRichard Henderson goto do_addsub2; 2763f1fae40cSRichard Henderson case INDEX_op_sub2_i64: 2764c45cb8bbSRichard Henderson opc_new = INDEX_op_sub_i64; 2765f1fae40cSRichard Henderson do_addsub2: 27661305c451SRichard Henderson nb_iargs = 4; 27671305c451SRichard Henderson nb_oargs = 2; 27681305c451SRichard Henderson /* Test if the high part of the operation is dead, but not 27691305c451SRichard Henderson the low part. The result can be optimized to a simple 27701305c451SRichard Henderson add or sub. This happens often for x86_64 guest when the 27711305c451SRichard Henderson cpu mode is set to 32 bit. */ 2772b83eabeaSRichard Henderson if (arg_temp(op->args[1])->state == TS_DEAD) { 2773b83eabeaSRichard Henderson if (arg_temp(op->args[0])->state == TS_DEAD) { 27741305c451SRichard Henderson goto do_remove; 27751305c451SRichard Henderson } 2776c45cb8bbSRichard Henderson /* Replace the opcode and adjust the args in place, 2777c45cb8bbSRichard Henderson leaving 3 unused args at the end. */ 2778c45cb8bbSRichard Henderson op->opc = opc = opc_new; 2779efee3746SRichard Henderson op->args[1] = op->args[2]; 2780efee3746SRichard Henderson op->args[2] = op->args[4]; 27811305c451SRichard Henderson /* Fall through and mark the single-word operation live. */ 27821305c451SRichard Henderson nb_iargs = 2; 27831305c451SRichard Henderson nb_oargs = 1; 27841305c451SRichard Henderson } 27851305c451SRichard Henderson goto do_not_remove; 27861305c451SRichard Henderson 27871414968aSRichard Henderson case INDEX_op_mulu2_i32: 2788c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i32; 2789c45cb8bbSRichard Henderson opc_new2 = INDEX_op_muluh_i32; 2790c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_muluh_i32; 279103271524SRichard Henderson goto do_mul2; 2792f1fae40cSRichard Henderson case INDEX_op_muls2_i32: 2793c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i32; 2794c45cb8bbSRichard Henderson opc_new2 = INDEX_op_mulsh_i32; 2795c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_mulsh_i32; 2796f1fae40cSRichard Henderson goto do_mul2; 2797f1fae40cSRichard Henderson case INDEX_op_mulu2_i64: 2798c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i64; 2799c45cb8bbSRichard Henderson opc_new2 = INDEX_op_muluh_i64; 2800c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_muluh_i64; 280103271524SRichard Henderson goto do_mul2; 2802f1fae40cSRichard Henderson case INDEX_op_muls2_i64: 2803c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i64; 2804c45cb8bbSRichard Henderson opc_new2 = INDEX_op_mulsh_i64; 2805c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_mulsh_i64; 280603271524SRichard Henderson goto do_mul2; 2807f1fae40cSRichard Henderson do_mul2: 28081414968aSRichard Henderson nb_iargs = 2; 28091414968aSRichard Henderson nb_oargs = 2; 2810b83eabeaSRichard Henderson if (arg_temp(op->args[1])->state == TS_DEAD) { 2811b83eabeaSRichard Henderson if (arg_temp(op->args[0])->state == TS_DEAD) { 281203271524SRichard Henderson /* Both parts of the operation are dead. */ 28131414968aSRichard Henderson goto do_remove; 28141414968aSRichard Henderson } 281503271524SRichard Henderson /* The high part of the operation is dead; generate the low. */ 2816c45cb8bbSRichard Henderson op->opc = opc = opc_new; 2817efee3746SRichard Henderson op->args[1] = op->args[2]; 2818efee3746SRichard Henderson op->args[2] = op->args[3]; 2819b83eabeaSRichard Henderson } else if (arg_temp(op->args[0])->state == TS_DEAD && have_opc_new2) { 282003271524SRichard Henderson /* The low part of the operation is dead; generate the high. */ 2821c45cb8bbSRichard Henderson op->opc = opc = opc_new2; 2822efee3746SRichard Henderson op->args[0] = op->args[1]; 2823efee3746SRichard Henderson op->args[1] = op->args[2]; 2824efee3746SRichard Henderson op->args[2] = op->args[3]; 282503271524SRichard Henderson } else { 282603271524SRichard Henderson goto do_not_remove; 282703271524SRichard Henderson } 282803271524SRichard Henderson /* Mark the single-word operation live. */ 28291414968aSRichard Henderson nb_oargs = 1; 28301414968aSRichard Henderson goto do_not_remove; 28311414968aSRichard Henderson 2832c896fe29Sbellard default: 28331305c451SRichard Henderson /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */ 2834c896fe29Sbellard nb_iargs = def->nb_iargs; 2835c896fe29Sbellard nb_oargs = def->nb_oargs; 2836c896fe29Sbellard 2837c896fe29Sbellard /* Test if the operation can be removed because all 28385ff9d6a4Sbellard its outputs are dead. We assume that nb_oargs == 0 28395ff9d6a4Sbellard implies side effects */ 28405ff9d6a4Sbellard if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) { 2841c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 2842b83eabeaSRichard Henderson if (arg_temp(op->args[i])->state != TS_DEAD) { 2843c896fe29Sbellard goto do_not_remove; 2844c896fe29Sbellard } 28459c43b68dSAurelien Jarno } 2846152c35aaSRichard Henderson goto do_remove; 2847152c35aaSRichard Henderson } 2848152c35aaSRichard Henderson goto do_not_remove; 2849152c35aaSRichard Henderson 28501305c451SRichard Henderson do_remove: 28510c627cdcSRichard Henderson tcg_op_remove(s, op); 2852152c35aaSRichard Henderson break; 2853152c35aaSRichard Henderson 2854c896fe29Sbellard do_not_remove: 2855c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 285625f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 285725f49c5fSRichard Henderson 285825f49c5fSRichard Henderson /* Remember the preference of the uses that followed. */ 285925f49c5fSRichard Henderson op->output_pref[i] = *la_temp_pref(ts); 286025f49c5fSRichard Henderson 286125f49c5fSRichard Henderson /* Output args are dead. */ 286225f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 2863a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 28646b64b624SAurelien Jarno } 286525f49c5fSRichard Henderson if (ts->state & TS_MEM) { 2866a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i; 28679c43b68dSAurelien Jarno } 286825f49c5fSRichard Henderson ts->state = TS_DEAD; 286925f49c5fSRichard Henderson la_reset_pref(ts); 2870c896fe29Sbellard } 2871c896fe29Sbellard 287225f49c5fSRichard Henderson /* If end of basic block, update. */ 2873ae36a246SRichard Henderson if (def->flags & TCG_OPF_BB_EXIT) { 2874ae36a246SRichard Henderson la_func_end(s, nb_globals, nb_temps); 2875b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_COND_BRANCH) { 2876b4cb76e6SRichard Henderson la_bb_sync(s, nb_globals, nb_temps); 2877ae36a246SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 28782616c808SRichard Henderson la_bb_end(s, nb_globals, nb_temps); 28793d5c5f87SAurelien Jarno } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { 2880f65a061cSRichard Henderson la_global_sync(s, nb_globals); 288125f49c5fSRichard Henderson if (def->flags & TCG_OPF_CALL_CLOBBER) { 288225f49c5fSRichard Henderson la_cross_call(s, nb_temps); 288325f49c5fSRichard Henderson } 2884c896fe29Sbellard } 2885c896fe29Sbellard 288625f49c5fSRichard Henderson /* Record arguments that die in this opcode. */ 2887866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 288825f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 288925f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 2890a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 2891c896fe29Sbellard } 2892c19f47bfSAurelien Jarno } 289325f49c5fSRichard Henderson 289425f49c5fSRichard Henderson /* Input arguments are live for preceding opcodes. */ 2895c19f47bfSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 289625f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 289725f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 289825f49c5fSRichard Henderson /* For operands that were dead, initially allow 289925f49c5fSRichard Henderson all regs for the type. */ 290025f49c5fSRichard Henderson *la_temp_pref(ts) = tcg_target_available_regs[ts->type]; 290125f49c5fSRichard Henderson ts->state &= ~TS_DEAD; 290225f49c5fSRichard Henderson } 290325f49c5fSRichard Henderson } 290425f49c5fSRichard Henderson 290525f49c5fSRichard Henderson /* Incorporate constraints for this operand. */ 290625f49c5fSRichard Henderson switch (opc) { 290725f49c5fSRichard Henderson case INDEX_op_mov_i32: 290825f49c5fSRichard Henderson case INDEX_op_mov_i64: 290925f49c5fSRichard Henderson /* Note that these are TCG_OPF_NOT_PRESENT and do not 291025f49c5fSRichard Henderson have proper constraints. That said, special case 291125f49c5fSRichard Henderson moves to propagate preferences backward. */ 291225f49c5fSRichard Henderson if (IS_DEAD_ARG(1)) { 291325f49c5fSRichard Henderson *la_temp_pref(arg_temp(op->args[0])) 291425f49c5fSRichard Henderson = *la_temp_pref(arg_temp(op->args[1])); 291525f49c5fSRichard Henderson } 291625f49c5fSRichard Henderson break; 291725f49c5fSRichard Henderson 291825f49c5fSRichard Henderson default: 291925f49c5fSRichard Henderson for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 292025f49c5fSRichard Henderson const TCGArgConstraint *ct = &def->args_ct[i]; 292125f49c5fSRichard Henderson TCGRegSet set, *pset; 292225f49c5fSRichard Henderson 292325f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 292425f49c5fSRichard Henderson pset = la_temp_pref(ts); 292525f49c5fSRichard Henderson set = *pset; 292625f49c5fSRichard Henderson 29279be0d080SRichard Henderson set &= ct->regs; 2928bc2b17e6SRichard Henderson if (ct->ialias) { 292925f49c5fSRichard Henderson set &= op->output_pref[ct->alias_index]; 293025f49c5fSRichard Henderson } 293125f49c5fSRichard Henderson /* If the combination is not possible, restart. */ 293225f49c5fSRichard Henderson if (set == 0) { 29339be0d080SRichard Henderson set = ct->regs; 293425f49c5fSRichard Henderson } 293525f49c5fSRichard Henderson *pset = set; 293625f49c5fSRichard Henderson } 293725f49c5fSRichard Henderson break; 2938c896fe29Sbellard } 2939c896fe29Sbellard break; 2940c896fe29Sbellard } 2941bee158cbSRichard Henderson op->life = arg_life; 2942c896fe29Sbellard } 29431ff0a2c5SEvgeny Voevodin } 2944c896fe29Sbellard 29455a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries. */ 2946b83eabeaSRichard Henderson static bool liveness_pass_2(TCGContext *s) 29475a18407fSRichard Henderson { 29485a18407fSRichard Henderson int nb_globals = s->nb_globals; 294915fa08f8SRichard Henderson int nb_temps, i; 29505a18407fSRichard Henderson bool changes = false; 295115fa08f8SRichard Henderson TCGOp *op, *op_next; 29525a18407fSRichard Henderson 29535a18407fSRichard Henderson /* Create a temporary for each indirect global. */ 29545a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 29555a18407fSRichard Henderson TCGTemp *its = &s->temps[i]; 29565a18407fSRichard Henderson if (its->indirect_reg) { 29575a18407fSRichard Henderson TCGTemp *dts = tcg_temp_alloc(s); 29585a18407fSRichard Henderson dts->type = its->type; 29595a18407fSRichard Henderson dts->base_type = its->base_type; 2960b83eabeaSRichard Henderson its->state_ptr = dts; 2961b83eabeaSRichard Henderson } else { 2962b83eabeaSRichard Henderson its->state_ptr = NULL; 29635a18407fSRichard Henderson } 2964b83eabeaSRichard Henderson /* All globals begin dead. */ 2965b83eabeaSRichard Henderson its->state = TS_DEAD; 29665a18407fSRichard Henderson } 2967b83eabeaSRichard Henderson for (nb_temps = s->nb_temps; i < nb_temps; ++i) { 2968b83eabeaSRichard Henderson TCGTemp *its = &s->temps[i]; 2969b83eabeaSRichard Henderson its->state_ptr = NULL; 2970b83eabeaSRichard Henderson its->state = TS_DEAD; 2971b83eabeaSRichard Henderson } 29725a18407fSRichard Henderson 297315fa08f8SRichard Henderson QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) { 29745a18407fSRichard Henderson TCGOpcode opc = op->opc; 29755a18407fSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 29765a18407fSRichard Henderson TCGLifeData arg_life = op->life; 29775a18407fSRichard Henderson int nb_iargs, nb_oargs, call_flags; 2978b83eabeaSRichard Henderson TCGTemp *arg_ts, *dir_ts; 29795a18407fSRichard Henderson 29805a18407fSRichard Henderson if (opc == INDEX_op_call) { 2981cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 2982cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 2983efee3746SRichard Henderson call_flags = op->args[nb_oargs + nb_iargs + 1]; 29845a18407fSRichard Henderson } else { 29855a18407fSRichard Henderson nb_iargs = def->nb_iargs; 29865a18407fSRichard Henderson nb_oargs = def->nb_oargs; 29875a18407fSRichard Henderson 29885a18407fSRichard Henderson /* Set flags similar to how calls require. */ 2989b4cb76e6SRichard Henderson if (def->flags & TCG_OPF_COND_BRANCH) { 2990b4cb76e6SRichard Henderson /* Like reading globals: sync_globals */ 2991b4cb76e6SRichard Henderson call_flags = TCG_CALL_NO_WRITE_GLOBALS; 2992b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 29935a18407fSRichard Henderson /* Like writing globals: save_globals */ 29945a18407fSRichard Henderson call_flags = 0; 29955a18407fSRichard Henderson } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { 29965a18407fSRichard Henderson /* Like reading globals: sync_globals */ 29975a18407fSRichard Henderson call_flags = TCG_CALL_NO_WRITE_GLOBALS; 29985a18407fSRichard Henderson } else { 29995a18407fSRichard Henderson /* No effect on globals. */ 30005a18407fSRichard Henderson call_flags = (TCG_CALL_NO_READ_GLOBALS | 30015a18407fSRichard Henderson TCG_CALL_NO_WRITE_GLOBALS); 30025a18407fSRichard Henderson } 30035a18407fSRichard Henderson } 30045a18407fSRichard Henderson 30055a18407fSRichard Henderson /* Make sure that input arguments are available. */ 30065a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 3007b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 3008b83eabeaSRichard Henderson if (arg_ts) { 3009b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 3010b83eabeaSRichard Henderson if (dir_ts && arg_ts->state == TS_DEAD) { 3011b83eabeaSRichard Henderson TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32 30125a18407fSRichard Henderson ? INDEX_op_ld_i32 30135a18407fSRichard Henderson : INDEX_op_ld_i64); 3014ac1043f6SEmilio G. Cota TCGOp *lop = tcg_op_insert_before(s, op, lopc); 30155a18407fSRichard Henderson 3016b83eabeaSRichard Henderson lop->args[0] = temp_arg(dir_ts); 3017b83eabeaSRichard Henderson lop->args[1] = temp_arg(arg_ts->mem_base); 3018b83eabeaSRichard Henderson lop->args[2] = arg_ts->mem_offset; 30195a18407fSRichard Henderson 30205a18407fSRichard Henderson /* Loaded, but synced with memory. */ 3021b83eabeaSRichard Henderson arg_ts->state = TS_MEM; 30225a18407fSRichard Henderson } 30235a18407fSRichard Henderson } 30245a18407fSRichard Henderson } 30255a18407fSRichard Henderson 30265a18407fSRichard Henderson /* Perform input replacement, and mark inputs that became dead. 30275a18407fSRichard Henderson No action is required except keeping temp_state up to date 30285a18407fSRichard Henderson so that we reload when needed. */ 30295a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 3030b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 3031b83eabeaSRichard Henderson if (arg_ts) { 3032b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 3033b83eabeaSRichard Henderson if (dir_ts) { 3034b83eabeaSRichard Henderson op->args[i] = temp_arg(dir_ts); 30355a18407fSRichard Henderson changes = true; 30365a18407fSRichard Henderson if (IS_DEAD_ARG(i)) { 3037b83eabeaSRichard Henderson arg_ts->state = TS_DEAD; 30385a18407fSRichard Henderson } 30395a18407fSRichard Henderson } 30405a18407fSRichard Henderson } 30415a18407fSRichard Henderson } 30425a18407fSRichard Henderson 30435a18407fSRichard Henderson /* Liveness analysis should ensure that the following are 30445a18407fSRichard Henderson all correct, for call sites and basic block end points. */ 30455a18407fSRichard Henderson if (call_flags & TCG_CALL_NO_READ_GLOBALS) { 30465a18407fSRichard Henderson /* Nothing to do */ 30475a18407fSRichard Henderson } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) { 30485a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 30495a18407fSRichard Henderson /* Liveness should see that globals are synced back, 30505a18407fSRichard Henderson that is, either TS_DEAD or TS_MEM. */ 3051b83eabeaSRichard Henderson arg_ts = &s->temps[i]; 3052b83eabeaSRichard Henderson tcg_debug_assert(arg_ts->state_ptr == 0 3053b83eabeaSRichard Henderson || arg_ts->state != 0); 30545a18407fSRichard Henderson } 30555a18407fSRichard Henderson } else { 30565a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 30575a18407fSRichard Henderson /* Liveness should see that globals are saved back, 30585a18407fSRichard Henderson that is, TS_DEAD, waiting to be reloaded. */ 3059b83eabeaSRichard Henderson arg_ts = &s->temps[i]; 3060b83eabeaSRichard Henderson tcg_debug_assert(arg_ts->state_ptr == 0 3061b83eabeaSRichard Henderson || arg_ts->state == TS_DEAD); 30625a18407fSRichard Henderson } 30635a18407fSRichard Henderson } 30645a18407fSRichard Henderson 30655a18407fSRichard Henderson /* Outputs become available. */ 306661f15c48SRichard Henderson if (opc == INDEX_op_mov_i32 || opc == INDEX_op_mov_i64) { 306761f15c48SRichard Henderson arg_ts = arg_temp(op->args[0]); 306861f15c48SRichard Henderson dir_ts = arg_ts->state_ptr; 306961f15c48SRichard Henderson if (dir_ts) { 307061f15c48SRichard Henderson op->args[0] = temp_arg(dir_ts); 307161f15c48SRichard Henderson changes = true; 307261f15c48SRichard Henderson 307361f15c48SRichard Henderson /* The output is now live and modified. */ 307461f15c48SRichard Henderson arg_ts->state = 0; 307561f15c48SRichard Henderson 307661f15c48SRichard Henderson if (NEED_SYNC_ARG(0)) { 307761f15c48SRichard Henderson TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 307861f15c48SRichard Henderson ? INDEX_op_st_i32 307961f15c48SRichard Henderson : INDEX_op_st_i64); 308061f15c48SRichard Henderson TCGOp *sop = tcg_op_insert_after(s, op, sopc); 308161f15c48SRichard Henderson TCGTemp *out_ts = dir_ts; 308261f15c48SRichard Henderson 308361f15c48SRichard Henderson if (IS_DEAD_ARG(0)) { 308461f15c48SRichard Henderson out_ts = arg_temp(op->args[1]); 308561f15c48SRichard Henderson arg_ts->state = TS_DEAD; 308661f15c48SRichard Henderson tcg_op_remove(s, op); 308761f15c48SRichard Henderson } else { 308861f15c48SRichard Henderson arg_ts->state = TS_MEM; 308961f15c48SRichard Henderson } 309061f15c48SRichard Henderson 309161f15c48SRichard Henderson sop->args[0] = temp_arg(out_ts); 309261f15c48SRichard Henderson sop->args[1] = temp_arg(arg_ts->mem_base); 309361f15c48SRichard Henderson sop->args[2] = arg_ts->mem_offset; 309461f15c48SRichard Henderson } else { 309561f15c48SRichard Henderson tcg_debug_assert(!IS_DEAD_ARG(0)); 309661f15c48SRichard Henderson } 309761f15c48SRichard Henderson } 309861f15c48SRichard Henderson } else { 30995a18407fSRichard Henderson for (i = 0; i < nb_oargs; i++) { 3100b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 3101b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 3102b83eabeaSRichard Henderson if (!dir_ts) { 31035a18407fSRichard Henderson continue; 31045a18407fSRichard Henderson } 3105b83eabeaSRichard Henderson op->args[i] = temp_arg(dir_ts); 31065a18407fSRichard Henderson changes = true; 31075a18407fSRichard Henderson 31085a18407fSRichard Henderson /* The output is now live and modified. */ 3109b83eabeaSRichard Henderson arg_ts->state = 0; 31105a18407fSRichard Henderson 31115a18407fSRichard Henderson /* Sync outputs upon their last write. */ 31125a18407fSRichard Henderson if (NEED_SYNC_ARG(i)) { 3113b83eabeaSRichard Henderson TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 31145a18407fSRichard Henderson ? INDEX_op_st_i32 31155a18407fSRichard Henderson : INDEX_op_st_i64); 3116ac1043f6SEmilio G. Cota TCGOp *sop = tcg_op_insert_after(s, op, sopc); 31175a18407fSRichard Henderson 3118b83eabeaSRichard Henderson sop->args[0] = temp_arg(dir_ts); 3119b83eabeaSRichard Henderson sop->args[1] = temp_arg(arg_ts->mem_base); 3120b83eabeaSRichard Henderson sop->args[2] = arg_ts->mem_offset; 31215a18407fSRichard Henderson 3122b83eabeaSRichard Henderson arg_ts->state = TS_MEM; 31235a18407fSRichard Henderson } 31245a18407fSRichard Henderson /* Drop outputs that are dead. */ 31255a18407fSRichard Henderson if (IS_DEAD_ARG(i)) { 3126b83eabeaSRichard Henderson arg_ts->state = TS_DEAD; 31275a18407fSRichard Henderson } 31285a18407fSRichard Henderson } 31295a18407fSRichard Henderson } 313061f15c48SRichard Henderson } 31315a18407fSRichard Henderson 31325a18407fSRichard Henderson return changes; 31335a18407fSRichard Henderson } 31345a18407fSRichard Henderson 31358d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG 3136c896fe29Sbellard static void dump_regs(TCGContext *s) 3137c896fe29Sbellard { 3138c896fe29Sbellard TCGTemp *ts; 3139c896fe29Sbellard int i; 3140c896fe29Sbellard char buf[64]; 3141c896fe29Sbellard 3142c896fe29Sbellard for(i = 0; i < s->nb_temps; i++) { 3143c896fe29Sbellard ts = &s->temps[i]; 314443439139SRichard Henderson printf(" %10s: ", tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts)); 3145c896fe29Sbellard switch(ts->val_type) { 3146c896fe29Sbellard case TEMP_VAL_REG: 3147c896fe29Sbellard printf("%s", tcg_target_reg_names[ts->reg]); 3148c896fe29Sbellard break; 3149c896fe29Sbellard case TEMP_VAL_MEM: 3150b3a62939SRichard Henderson printf("%d(%s)", (int)ts->mem_offset, 3151b3a62939SRichard Henderson tcg_target_reg_names[ts->mem_base->reg]); 3152c896fe29Sbellard break; 3153c896fe29Sbellard case TEMP_VAL_CONST: 3154c896fe29Sbellard printf("$0x%" TCG_PRIlx, ts->val); 3155c896fe29Sbellard break; 3156c896fe29Sbellard case TEMP_VAL_DEAD: 3157c896fe29Sbellard printf("D"); 3158c896fe29Sbellard break; 3159c896fe29Sbellard default: 3160c896fe29Sbellard printf("???"); 3161c896fe29Sbellard break; 3162c896fe29Sbellard } 3163c896fe29Sbellard printf("\n"); 3164c896fe29Sbellard } 3165c896fe29Sbellard 3166c896fe29Sbellard for(i = 0; i < TCG_TARGET_NB_REGS; i++) { 3167f8b2f202SRichard Henderson if (s->reg_to_temp[i] != NULL) { 3168c896fe29Sbellard printf("%s: %s\n", 3169c896fe29Sbellard tcg_target_reg_names[i], 3170f8b2f202SRichard Henderson tcg_get_arg_str_ptr(s, buf, sizeof(buf), s->reg_to_temp[i])); 3171c896fe29Sbellard } 3172c896fe29Sbellard } 3173c896fe29Sbellard } 3174c896fe29Sbellard 3175c896fe29Sbellard static void check_regs(TCGContext *s) 3176c896fe29Sbellard { 3177869938aeSRichard Henderson int reg; 3178b6638662SRichard Henderson int k; 3179c896fe29Sbellard TCGTemp *ts; 3180c896fe29Sbellard char buf[64]; 3181c896fe29Sbellard 3182c896fe29Sbellard for (reg = 0; reg < TCG_TARGET_NB_REGS; reg++) { 3183f8b2f202SRichard Henderson ts = s->reg_to_temp[reg]; 3184f8b2f202SRichard Henderson if (ts != NULL) { 3185f8b2f202SRichard Henderson if (ts->val_type != TEMP_VAL_REG || ts->reg != reg) { 3186c896fe29Sbellard printf("Inconsistency for register %s:\n", 3187c896fe29Sbellard tcg_target_reg_names[reg]); 3188b03cce8eSbellard goto fail; 3189c896fe29Sbellard } 3190c896fe29Sbellard } 3191c896fe29Sbellard } 3192c896fe29Sbellard for (k = 0; k < s->nb_temps; k++) { 3193c896fe29Sbellard ts = &s->temps[k]; 3194f8b2f202SRichard Henderson if (ts->val_type == TEMP_VAL_REG && !ts->fixed_reg 3195f8b2f202SRichard Henderson && s->reg_to_temp[ts->reg] != ts) { 3196c896fe29Sbellard printf("Inconsistency for temp %s:\n", 3197f8b2f202SRichard Henderson tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts)); 3198b03cce8eSbellard fail: 3199c896fe29Sbellard printf("reg state:\n"); 3200c896fe29Sbellard dump_regs(s); 3201c896fe29Sbellard tcg_abort(); 3202c896fe29Sbellard } 3203c896fe29Sbellard } 3204c896fe29Sbellard } 3205c896fe29Sbellard #endif 3206c896fe29Sbellard 32072272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts) 3208c896fe29Sbellard { 32099b9c37c3SRichard Henderson #if !(defined(__sparc__) && TCG_TARGET_REG_BITS == 64) 32109b9c37c3SRichard Henderson /* Sparc64 stack is accessed with offset of 2047 */ 3211b591dc59SBlue Swirl s->current_frame_offset = (s->current_frame_offset + 3212b591dc59SBlue Swirl (tcg_target_long)sizeof(tcg_target_long) - 1) & 3213b591dc59SBlue Swirl ~(sizeof(tcg_target_long) - 1); 3214f44c9960SBlue Swirl #endif 3215b591dc59SBlue Swirl if (s->current_frame_offset + (tcg_target_long)sizeof(tcg_target_long) > 3216b591dc59SBlue Swirl s->frame_end) { 32175ff9d6a4Sbellard tcg_abort(); 3218b591dc59SBlue Swirl } 3219c896fe29Sbellard ts->mem_offset = s->current_frame_offset; 3220b3a62939SRichard Henderson ts->mem_base = s->frame_temp; 3221c896fe29Sbellard ts->mem_allocated = 1; 3222e2c6d1b4SRichard Henderson s->current_frame_offset += sizeof(tcg_target_long); 3223c896fe29Sbellard } 3224c896fe29Sbellard 3225b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet); 3226b3915dbbSRichard Henderson 322759d7c14eSRichard Henderson /* Mark a temporary as free or dead. If 'free_or_dead' is negative, 322859d7c14eSRichard Henderson mark it free; otherwise mark it dead. */ 322959d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead) 3230c896fe29Sbellard { 323159d7c14eSRichard Henderson if (ts->fixed_reg) { 323259d7c14eSRichard Henderson return; 323359d7c14eSRichard Henderson } 323459d7c14eSRichard Henderson if (ts->val_type == TEMP_VAL_REG) { 323559d7c14eSRichard Henderson s->reg_to_temp[ts->reg] = NULL; 323659d7c14eSRichard Henderson } 323759d7c14eSRichard Henderson ts->val_type = (free_or_dead < 0 323859d7c14eSRichard Henderson || ts->temp_local 3239fa477d25SRichard Henderson || ts->temp_global 324059d7c14eSRichard Henderson ? TEMP_VAL_MEM : TEMP_VAL_DEAD); 324159d7c14eSRichard Henderson } 3242c896fe29Sbellard 324359d7c14eSRichard Henderson /* Mark a temporary as dead. */ 324459d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts) 324559d7c14eSRichard Henderson { 324659d7c14eSRichard Henderson temp_free_or_dead(s, ts, 1); 324759d7c14eSRichard Henderson } 324859d7c14eSRichard Henderson 324959d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary 325059d7c14eSRichard Henderson registers needs to be allocated to store a constant. If 'free_or_dead' 325159d7c14eSRichard Henderson is non-zero, subsequently release the temporary; if it is positive, the 325259d7c14eSRichard Henderson temp is dead; if it is negative, the temp is free. */ 325398b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs, 325498b4e186SRichard Henderson TCGRegSet preferred_regs, int free_or_dead) 325559d7c14eSRichard Henderson { 325659d7c14eSRichard Henderson if (ts->fixed_reg) { 325759d7c14eSRichard Henderson return; 325859d7c14eSRichard Henderson } 325959d7c14eSRichard Henderson if (!ts->mem_coherent) { 32607f6ceedfSAurelien Jarno if (!ts->mem_allocated) { 32612272e4a7SRichard Henderson temp_allocate_frame(s, ts); 326259d7c14eSRichard Henderson } 326359d7c14eSRichard Henderson switch (ts->val_type) { 326459d7c14eSRichard Henderson case TEMP_VAL_CONST: 326559d7c14eSRichard Henderson /* If we're going to free the temp immediately, then we won't 326659d7c14eSRichard Henderson require it later in a register, so attempt to store the 326759d7c14eSRichard Henderson constant to memory directly. */ 326859d7c14eSRichard Henderson if (free_or_dead 326959d7c14eSRichard Henderson && tcg_out_sti(s, ts->type, ts->val, 327059d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset)) { 327159d7c14eSRichard Henderson break; 327259d7c14eSRichard Henderson } 327359d7c14eSRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 327498b4e186SRichard Henderson allocated_regs, preferred_regs); 327559d7c14eSRichard Henderson /* fallthrough */ 327659d7c14eSRichard Henderson 327759d7c14eSRichard Henderson case TEMP_VAL_REG: 327859d7c14eSRichard Henderson tcg_out_st(s, ts->type, ts->reg, 327959d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset); 328059d7c14eSRichard Henderson break; 328159d7c14eSRichard Henderson 328259d7c14eSRichard Henderson case TEMP_VAL_MEM: 328359d7c14eSRichard Henderson break; 328459d7c14eSRichard Henderson 328559d7c14eSRichard Henderson case TEMP_VAL_DEAD: 328659d7c14eSRichard Henderson default: 328759d7c14eSRichard Henderson tcg_abort(); 3288c896fe29Sbellard } 32897f6ceedfSAurelien Jarno ts->mem_coherent = 1; 32907f6ceedfSAurelien Jarno } 329159d7c14eSRichard Henderson if (free_or_dead) { 329259d7c14eSRichard Henderson temp_free_or_dead(s, ts, free_or_dead); 329359d7c14eSRichard Henderson } 329459d7c14eSRichard Henderson } 32957f6ceedfSAurelien Jarno 32967f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */ 3297b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs) 32987f6ceedfSAurelien Jarno { 3299f8b2f202SRichard Henderson TCGTemp *ts = s->reg_to_temp[reg]; 3300f8b2f202SRichard Henderson if (ts != NULL) { 330198b4e186SRichard Henderson temp_sync(s, ts, allocated_regs, 0, -1); 3302c896fe29Sbellard } 3303c896fe29Sbellard } 3304c896fe29Sbellard 3305b016486eSRichard Henderson /** 3306b016486eSRichard Henderson * tcg_reg_alloc: 3307b016486eSRichard Henderson * @required_regs: Set of registers in which we must allocate. 3308b016486eSRichard Henderson * @allocated_regs: Set of registers which must be avoided. 3309b016486eSRichard Henderson * @preferred_regs: Set of registers we should prefer. 3310b016486eSRichard Henderson * @rev: True if we search the registers in "indirect" order. 3311b016486eSRichard Henderson * 3312b016486eSRichard Henderson * The allocated register must be in @required_regs & ~@allocated_regs, 3313b016486eSRichard Henderson * but if we can put it in @preferred_regs we may save a move later. 3314b016486eSRichard Henderson */ 3315b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs, 3316b016486eSRichard Henderson TCGRegSet allocated_regs, 3317b016486eSRichard Henderson TCGRegSet preferred_regs, bool rev) 3318c896fe29Sbellard { 3319b016486eSRichard Henderson int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order); 3320b016486eSRichard Henderson TCGRegSet reg_ct[2]; 332191478cefSRichard Henderson const int *order; 3322c896fe29Sbellard 3323b016486eSRichard Henderson reg_ct[1] = required_regs & ~allocated_regs; 3324b016486eSRichard Henderson tcg_debug_assert(reg_ct[1] != 0); 3325b016486eSRichard Henderson reg_ct[0] = reg_ct[1] & preferred_regs; 3326b016486eSRichard Henderson 3327b016486eSRichard Henderson /* Skip the preferred_regs option if it cannot be satisfied, 3328b016486eSRichard Henderson or if the preference made no difference. */ 3329b016486eSRichard Henderson f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1]; 3330b016486eSRichard Henderson 333191478cefSRichard Henderson order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order; 3332c896fe29Sbellard 3333b016486eSRichard Henderson /* Try free registers, preferences first. */ 3334b016486eSRichard Henderson for (j = f; j < 2; j++) { 3335b016486eSRichard Henderson TCGRegSet set = reg_ct[j]; 3336b016486eSRichard Henderson 3337b016486eSRichard Henderson if (tcg_regset_single(set)) { 3338b016486eSRichard Henderson /* One register in the set. */ 3339b016486eSRichard Henderson TCGReg reg = tcg_regset_first(set); 3340b016486eSRichard Henderson if (s->reg_to_temp[reg] == NULL) { 3341c896fe29Sbellard return reg; 3342c896fe29Sbellard } 3343b016486eSRichard Henderson } else { 334491478cefSRichard Henderson for (i = 0; i < n; i++) { 3345b016486eSRichard Henderson TCGReg reg = order[i]; 3346b016486eSRichard Henderson if (s->reg_to_temp[reg] == NULL && 3347b016486eSRichard Henderson tcg_regset_test_reg(set, reg)) { 3348b016486eSRichard Henderson return reg; 3349b016486eSRichard Henderson } 3350b016486eSRichard Henderson } 3351b016486eSRichard Henderson } 3352b016486eSRichard Henderson } 3353b016486eSRichard Henderson 3354b016486eSRichard Henderson /* We must spill something. */ 3355b016486eSRichard Henderson for (j = f; j < 2; j++) { 3356b016486eSRichard Henderson TCGRegSet set = reg_ct[j]; 3357b016486eSRichard Henderson 3358b016486eSRichard Henderson if (tcg_regset_single(set)) { 3359b016486eSRichard Henderson /* One register in the set. */ 3360b016486eSRichard Henderson TCGReg reg = tcg_regset_first(set); 3361b3915dbbSRichard Henderson tcg_reg_free(s, reg, allocated_regs); 3362c896fe29Sbellard return reg; 3363b016486eSRichard Henderson } else { 3364b016486eSRichard Henderson for (i = 0; i < n; i++) { 3365b016486eSRichard Henderson TCGReg reg = order[i]; 3366b016486eSRichard Henderson if (tcg_regset_test_reg(set, reg)) { 3367b016486eSRichard Henderson tcg_reg_free(s, reg, allocated_regs); 3368b016486eSRichard Henderson return reg; 3369b016486eSRichard Henderson } 3370b016486eSRichard Henderson } 3371c896fe29Sbellard } 3372c896fe29Sbellard } 3373c896fe29Sbellard 3374c896fe29Sbellard tcg_abort(); 3375c896fe29Sbellard } 3376c896fe29Sbellard 337740ae5c62SRichard Henderson /* Make sure the temporary is in a register. If needed, allocate the register 337840ae5c62SRichard Henderson from DESIRED while avoiding ALLOCATED. */ 337940ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs, 3380b722452aSRichard Henderson TCGRegSet allocated_regs, TCGRegSet preferred_regs) 338140ae5c62SRichard Henderson { 338240ae5c62SRichard Henderson TCGReg reg; 338340ae5c62SRichard Henderson 338440ae5c62SRichard Henderson switch (ts->val_type) { 338540ae5c62SRichard Henderson case TEMP_VAL_REG: 338640ae5c62SRichard Henderson return; 338740ae5c62SRichard Henderson case TEMP_VAL_CONST: 3388b016486eSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs, 3389b722452aSRichard Henderson preferred_regs, ts->indirect_base); 339040ae5c62SRichard Henderson tcg_out_movi(s, ts->type, reg, ts->val); 339140ae5c62SRichard Henderson ts->mem_coherent = 0; 339240ae5c62SRichard Henderson break; 339340ae5c62SRichard Henderson case TEMP_VAL_MEM: 3394b016486eSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs, 3395b722452aSRichard Henderson preferred_regs, ts->indirect_base); 339640ae5c62SRichard Henderson tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset); 339740ae5c62SRichard Henderson ts->mem_coherent = 1; 339840ae5c62SRichard Henderson break; 339940ae5c62SRichard Henderson case TEMP_VAL_DEAD: 340040ae5c62SRichard Henderson default: 340140ae5c62SRichard Henderson tcg_abort(); 340240ae5c62SRichard Henderson } 340340ae5c62SRichard Henderson ts->reg = reg; 340440ae5c62SRichard Henderson ts->val_type = TEMP_VAL_REG; 340540ae5c62SRichard Henderson s->reg_to_temp[reg] = ts; 340640ae5c62SRichard Henderson } 340740ae5c62SRichard Henderson 340859d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a 3409e8996ee0Sbellard temporary registers needs to be allocated to store a constant. */ 341059d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs) 34111ad80729SAurelien Jarno { 34122c0366f0SAurelien Jarno /* The liveness analysis already ensures that globals are back 3413eabb7b91SAurelien Jarno in memory. Keep an tcg_debug_assert for safety. */ 3414f8bf00f1SRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || ts->fixed_reg); 34151ad80729SAurelien Jarno } 34161ad80729SAurelien Jarno 34179814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be 3418641d5fbeSbellard modified be the following code. 'allocated_regs' is used in case a 3419641d5fbeSbellard temporary registers needs to be allocated to store a constant. */ 3420641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs) 3421641d5fbeSbellard { 3422ac3b8891SRichard Henderson int i, n; 3423641d5fbeSbellard 3424ac3b8891SRichard Henderson for (i = 0, n = s->nb_globals; i < n; i++) { 3425b13eb728SRichard Henderson temp_save(s, &s->temps[i], allocated_regs); 3426641d5fbeSbellard } 3427e5097dc8Sbellard } 3428e5097dc8Sbellard 34293d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be 34303d5c5f87SAurelien Jarno read by the following code. 'allocated_regs' is used in case a 34313d5c5f87SAurelien Jarno temporary registers needs to be allocated to store a constant. */ 34323d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs) 34333d5c5f87SAurelien Jarno { 3434ac3b8891SRichard Henderson int i, n; 34353d5c5f87SAurelien Jarno 3436ac3b8891SRichard Henderson for (i = 0, n = s->nb_globals; i < n; i++) { 343712b9b11aSRichard Henderson TCGTemp *ts = &s->temps[i]; 343812b9b11aSRichard Henderson tcg_debug_assert(ts->val_type != TEMP_VAL_REG 343912b9b11aSRichard Henderson || ts->fixed_reg 344012b9b11aSRichard Henderson || ts->mem_coherent); 34413d5c5f87SAurelien Jarno } 34423d5c5f87SAurelien Jarno } 34433d5c5f87SAurelien Jarno 3444e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and 3445e8996ee0Sbellard all globals are stored at their canonical location. */ 3446e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs) 3447e5097dc8Sbellard { 3448e5097dc8Sbellard int i; 3449e5097dc8Sbellard 3450c896fe29Sbellard for (i = s->nb_globals; i < s->nb_temps; i++) { 3451b13eb728SRichard Henderson TCGTemp *ts = &s->temps[i]; 3452641d5fbeSbellard if (ts->temp_local) { 3453b13eb728SRichard Henderson temp_save(s, ts, allocated_regs); 3454641d5fbeSbellard } else { 34552c0366f0SAurelien Jarno /* The liveness analysis already ensures that temps are dead. 3456eabb7b91SAurelien Jarno Keep an tcg_debug_assert for safety. */ 3457eabb7b91SAurelien Jarno tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD); 3458c896fe29Sbellard } 3459641d5fbeSbellard } 3460e8996ee0Sbellard 3461e8996ee0Sbellard save_globals(s, allocated_regs); 3462c896fe29Sbellard } 3463c896fe29Sbellard 3464bab1671fSRichard Henderson /* 3465b4cb76e6SRichard Henderson * At a conditional branch, we assume all temporaries are dead and 3466b4cb76e6SRichard Henderson * all globals and local temps are synced to their location. 3467b4cb76e6SRichard Henderson */ 3468b4cb76e6SRichard Henderson static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs) 3469b4cb76e6SRichard Henderson { 3470b4cb76e6SRichard Henderson sync_globals(s, allocated_regs); 3471b4cb76e6SRichard Henderson 3472b4cb76e6SRichard Henderson for (int i = s->nb_globals; i < s->nb_temps; i++) { 3473b4cb76e6SRichard Henderson TCGTemp *ts = &s->temps[i]; 3474b4cb76e6SRichard Henderson /* 3475b4cb76e6SRichard Henderson * The liveness analysis already ensures that temps are dead. 3476b4cb76e6SRichard Henderson * Keep tcg_debug_asserts for safety. 3477b4cb76e6SRichard Henderson */ 3478b4cb76e6SRichard Henderson if (ts->temp_local) { 3479b4cb76e6SRichard Henderson tcg_debug_assert(ts->val_type != TEMP_VAL_REG || ts->mem_coherent); 3480b4cb76e6SRichard Henderson } else { 3481b4cb76e6SRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD); 3482b4cb76e6SRichard Henderson } 3483b4cb76e6SRichard Henderson } 3484b4cb76e6SRichard Henderson } 3485b4cb76e6SRichard Henderson 3486b4cb76e6SRichard Henderson /* 3487bab1671fSRichard Henderson * Specialized code generation for INDEX_op_movi_*. 3488bab1671fSRichard Henderson */ 34890fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots, 3490ba87719cSRichard Henderson tcg_target_ulong val, TCGLifeData arg_life, 3491ba87719cSRichard Henderson TCGRegSet preferred_regs) 3492e8996ee0Sbellard { 3493d63e3b6eSRichard Henderson /* ENV should not be modified. */ 3494d63e3b6eSRichard Henderson tcg_debug_assert(!ots->fixed_reg); 349559d7c14eSRichard Henderson 349659d7c14eSRichard Henderson /* The movi is not explicitly generated here. */ 3497f8b2f202SRichard Henderson if (ots->val_type == TEMP_VAL_REG) { 3498f8b2f202SRichard Henderson s->reg_to_temp[ots->reg] = NULL; 3499f8b2f202SRichard Henderson } 3500e8996ee0Sbellard ots->val_type = TEMP_VAL_CONST; 3501e8996ee0Sbellard ots->val = val; 350259d7c14eSRichard Henderson ots->mem_coherent = 0; 3503ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) { 3504ba87719cSRichard Henderson temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0)); 350559d7c14eSRichard Henderson } else if (IS_DEAD_ARG(0)) { 3506f8bf00f1SRichard Henderson temp_dead(s, ots); 35074c4e1ab2SAurelien Jarno } 3508e8996ee0Sbellard } 3509e8996ee0Sbellard 3510dd186292SRichard Henderson static void tcg_reg_alloc_movi(TCGContext *s, const TCGOp *op) 35110fe4fca4SPaolo Bonzini { 351243439139SRichard Henderson TCGTemp *ots = arg_temp(op->args[0]); 3513dd186292SRichard Henderson tcg_target_ulong val = op->args[1]; 35140fe4fca4SPaolo Bonzini 351569e3706dSRichard Henderson tcg_reg_alloc_do_movi(s, ots, val, op->life, op->output_pref[0]); 35160fe4fca4SPaolo Bonzini } 35170fe4fca4SPaolo Bonzini 3518bab1671fSRichard Henderson /* 3519bab1671fSRichard Henderson * Specialized code generation for INDEX_op_mov_*. 3520bab1671fSRichard Henderson */ 3521dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op) 3522c896fe29Sbellard { 3523dd186292SRichard Henderson const TCGLifeData arg_life = op->life; 352469e3706dSRichard Henderson TCGRegSet allocated_regs, preferred_regs; 3525c896fe29Sbellard TCGTemp *ts, *ots; 3526450445d5SRichard Henderson TCGType otype, itype; 3527c896fe29Sbellard 3528d21369f5SRichard Henderson allocated_regs = s->reserved_regs; 352969e3706dSRichard Henderson preferred_regs = op->output_pref[0]; 353043439139SRichard Henderson ots = arg_temp(op->args[0]); 353143439139SRichard Henderson ts = arg_temp(op->args[1]); 3532450445d5SRichard Henderson 3533d63e3b6eSRichard Henderson /* ENV should not be modified. */ 3534d63e3b6eSRichard Henderson tcg_debug_assert(!ots->fixed_reg); 3535d63e3b6eSRichard Henderson 3536450445d5SRichard Henderson /* Note that otype != itype for no-op truncation. */ 3537450445d5SRichard Henderson otype = ots->type; 3538450445d5SRichard Henderson itype = ts->type; 3539c896fe29Sbellard 35400fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_CONST) { 35410fe4fca4SPaolo Bonzini /* propagate constant or generate sti */ 35420fe4fca4SPaolo Bonzini tcg_target_ulong val = ts->val; 35430fe4fca4SPaolo Bonzini if (IS_DEAD_ARG(1)) { 35440fe4fca4SPaolo Bonzini temp_dead(s, ts); 35450fe4fca4SPaolo Bonzini } 354669e3706dSRichard Henderson tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs); 35470fe4fca4SPaolo Bonzini return; 35480fe4fca4SPaolo Bonzini } 35490fe4fca4SPaolo Bonzini 35500fe4fca4SPaolo Bonzini /* If the source value is in memory we're going to be forced 35510fe4fca4SPaolo Bonzini to have it in a register in order to perform the copy. Copy 35520fe4fca4SPaolo Bonzini the SOURCE value into its own register first, that way we 35530fe4fca4SPaolo Bonzini don't have to reload SOURCE the next time it is used. */ 35540fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_MEM) { 355569e3706dSRichard Henderson temp_load(s, ts, tcg_target_available_regs[itype], 355669e3706dSRichard Henderson allocated_regs, preferred_regs); 3557c29c1d7eSAurelien Jarno } 3558c29c1d7eSAurelien Jarno 35590fe4fca4SPaolo Bonzini tcg_debug_assert(ts->val_type == TEMP_VAL_REG); 3560d63e3b6eSRichard Henderson if (IS_DEAD_ARG(0)) { 3561c29c1d7eSAurelien Jarno /* mov to a non-saved dead register makes no sense (even with 3562c29c1d7eSAurelien Jarno liveness analysis disabled). */ 3563eabb7b91SAurelien Jarno tcg_debug_assert(NEED_SYNC_ARG(0)); 3564c29c1d7eSAurelien Jarno if (!ots->mem_allocated) { 35652272e4a7SRichard Henderson temp_allocate_frame(s, ots); 3566c29c1d7eSAurelien Jarno } 3567b3a62939SRichard Henderson tcg_out_st(s, otype, ts->reg, ots->mem_base->reg, ots->mem_offset); 3568c29c1d7eSAurelien Jarno if (IS_DEAD_ARG(1)) { 3569f8bf00f1SRichard Henderson temp_dead(s, ts); 3570c29c1d7eSAurelien Jarno } 3571f8bf00f1SRichard Henderson temp_dead(s, ots); 3572e8996ee0Sbellard } else { 3573d63e3b6eSRichard Henderson if (IS_DEAD_ARG(1) && !ts->fixed_reg) { 3574c29c1d7eSAurelien Jarno /* the mov can be suppressed */ 3575c29c1d7eSAurelien Jarno if (ots->val_type == TEMP_VAL_REG) { 3576f8b2f202SRichard Henderson s->reg_to_temp[ots->reg] = NULL; 3577c896fe29Sbellard } 3578c29c1d7eSAurelien Jarno ots->reg = ts->reg; 3579f8bf00f1SRichard Henderson temp_dead(s, ts); 3580c29c1d7eSAurelien Jarno } else { 3581c29c1d7eSAurelien Jarno if (ots->val_type != TEMP_VAL_REG) { 3582c29c1d7eSAurelien Jarno /* When allocating a new register, make sure to not spill the 3583c29c1d7eSAurelien Jarno input one. */ 3584c29c1d7eSAurelien Jarno tcg_regset_set_reg(allocated_regs, ts->reg); 3585450445d5SRichard Henderson ots->reg = tcg_reg_alloc(s, tcg_target_available_regs[otype], 358669e3706dSRichard Henderson allocated_regs, preferred_regs, 3587b016486eSRichard Henderson ots->indirect_base); 3588c29c1d7eSAurelien Jarno } 358978113e83SRichard Henderson if (!tcg_out_mov(s, otype, ots->reg, ts->reg)) { 3590240c08d0SRichard Henderson /* 3591240c08d0SRichard Henderson * Cross register class move not supported. 3592240c08d0SRichard Henderson * Store the source register into the destination slot 3593240c08d0SRichard Henderson * and leave the destination temp as TEMP_VAL_MEM. 3594240c08d0SRichard Henderson */ 3595240c08d0SRichard Henderson assert(!ots->fixed_reg); 3596240c08d0SRichard Henderson if (!ts->mem_allocated) { 3597240c08d0SRichard Henderson temp_allocate_frame(s, ots); 3598240c08d0SRichard Henderson } 3599240c08d0SRichard Henderson tcg_out_st(s, ts->type, ts->reg, 3600240c08d0SRichard Henderson ots->mem_base->reg, ots->mem_offset); 3601240c08d0SRichard Henderson ots->mem_coherent = 1; 3602240c08d0SRichard Henderson temp_free_or_dead(s, ots, -1); 3603240c08d0SRichard Henderson return; 360478113e83SRichard Henderson } 3605c29c1d7eSAurelien Jarno } 3606c896fe29Sbellard ots->val_type = TEMP_VAL_REG; 3607c896fe29Sbellard ots->mem_coherent = 0; 3608f8b2f202SRichard Henderson s->reg_to_temp[ots->reg] = ots; 3609ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) { 361098b4e186SRichard Henderson temp_sync(s, ots, allocated_regs, 0, 0); 3611c29c1d7eSAurelien Jarno } 3612ec7a869dSAurelien Jarno } 3613c896fe29Sbellard } 3614c896fe29Sbellard 3615bab1671fSRichard Henderson /* 3616bab1671fSRichard Henderson * Specialized code generation for INDEX_op_dup_vec. 3617bab1671fSRichard Henderson */ 3618bab1671fSRichard Henderson static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op) 3619bab1671fSRichard Henderson { 3620bab1671fSRichard Henderson const TCGLifeData arg_life = op->life; 3621bab1671fSRichard Henderson TCGRegSet dup_out_regs, dup_in_regs; 3622bab1671fSRichard Henderson TCGTemp *its, *ots; 3623bab1671fSRichard Henderson TCGType itype, vtype; 3624d6ecb4a9SRichard Henderson intptr_t endian_fixup; 3625bab1671fSRichard Henderson unsigned vece; 3626bab1671fSRichard Henderson bool ok; 3627bab1671fSRichard Henderson 3628bab1671fSRichard Henderson ots = arg_temp(op->args[0]); 3629bab1671fSRichard Henderson its = arg_temp(op->args[1]); 3630bab1671fSRichard Henderson 3631bab1671fSRichard Henderson /* ENV should not be modified. */ 3632bab1671fSRichard Henderson tcg_debug_assert(!ots->fixed_reg); 3633bab1671fSRichard Henderson 3634bab1671fSRichard Henderson itype = its->type; 3635bab1671fSRichard Henderson vece = TCGOP_VECE(op); 3636bab1671fSRichard Henderson vtype = TCGOP_VECL(op) + TCG_TYPE_V64; 3637bab1671fSRichard Henderson 3638bab1671fSRichard Henderson if (its->val_type == TEMP_VAL_CONST) { 3639bab1671fSRichard Henderson /* Propagate constant via movi -> dupi. */ 3640bab1671fSRichard Henderson tcg_target_ulong val = its->val; 3641bab1671fSRichard Henderson if (IS_DEAD_ARG(1)) { 3642bab1671fSRichard Henderson temp_dead(s, its); 3643bab1671fSRichard Henderson } 3644bab1671fSRichard Henderson tcg_reg_alloc_do_movi(s, ots, val, arg_life, op->output_pref[0]); 3645bab1671fSRichard Henderson return; 3646bab1671fSRichard Henderson } 3647bab1671fSRichard Henderson 36489be0d080SRichard Henderson dup_out_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs; 36499be0d080SRichard Henderson dup_in_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[1].regs; 3650bab1671fSRichard Henderson 3651bab1671fSRichard Henderson /* Allocate the output register now. */ 3652bab1671fSRichard Henderson if (ots->val_type != TEMP_VAL_REG) { 3653bab1671fSRichard Henderson TCGRegSet allocated_regs = s->reserved_regs; 3654bab1671fSRichard Henderson 3655bab1671fSRichard Henderson if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) { 3656bab1671fSRichard Henderson /* Make sure to not spill the input register. */ 3657bab1671fSRichard Henderson tcg_regset_set_reg(allocated_regs, its->reg); 3658bab1671fSRichard Henderson } 3659bab1671fSRichard Henderson ots->reg = tcg_reg_alloc(s, dup_out_regs, allocated_regs, 3660bab1671fSRichard Henderson op->output_pref[0], ots->indirect_base); 3661bab1671fSRichard Henderson ots->val_type = TEMP_VAL_REG; 3662bab1671fSRichard Henderson ots->mem_coherent = 0; 3663bab1671fSRichard Henderson s->reg_to_temp[ots->reg] = ots; 3664bab1671fSRichard Henderson } 3665bab1671fSRichard Henderson 3666bab1671fSRichard Henderson switch (its->val_type) { 3667bab1671fSRichard Henderson case TEMP_VAL_REG: 3668bab1671fSRichard Henderson /* 3669bab1671fSRichard Henderson * The dup constriaints must be broad, covering all possible VECE. 3670bab1671fSRichard Henderson * However, tcg_op_dup_vec() gets to see the VECE and we allow it 3671bab1671fSRichard Henderson * to fail, indicating that extra moves are required for that case. 3672bab1671fSRichard Henderson */ 3673bab1671fSRichard Henderson if (tcg_regset_test_reg(dup_in_regs, its->reg)) { 3674bab1671fSRichard Henderson if (tcg_out_dup_vec(s, vtype, vece, ots->reg, its->reg)) { 3675bab1671fSRichard Henderson goto done; 3676bab1671fSRichard Henderson } 3677bab1671fSRichard Henderson /* Try again from memory or a vector input register. */ 3678bab1671fSRichard Henderson } 3679bab1671fSRichard Henderson if (!its->mem_coherent) { 3680bab1671fSRichard Henderson /* 3681bab1671fSRichard Henderson * The input register is not synced, and so an extra store 3682bab1671fSRichard Henderson * would be required to use memory. Attempt an integer-vector 3683bab1671fSRichard Henderson * register move first. We do not have a TCGRegSet for this. 3684bab1671fSRichard Henderson */ 3685bab1671fSRichard Henderson if (tcg_out_mov(s, itype, ots->reg, its->reg)) { 3686bab1671fSRichard Henderson break; 3687bab1671fSRichard Henderson } 3688bab1671fSRichard Henderson /* Sync the temp back to its slot and load from there. */ 3689bab1671fSRichard Henderson temp_sync(s, its, s->reserved_regs, 0, 0); 3690bab1671fSRichard Henderson } 3691bab1671fSRichard Henderson /* fall through */ 3692bab1671fSRichard Henderson 3693bab1671fSRichard Henderson case TEMP_VAL_MEM: 3694d6ecb4a9SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 3695d6ecb4a9SRichard Henderson endian_fixup = itype == TCG_TYPE_I32 ? 4 : 8; 3696d6ecb4a9SRichard Henderson endian_fixup -= 1 << vece; 3697d6ecb4a9SRichard Henderson #else 3698d6ecb4a9SRichard Henderson endian_fixup = 0; 3699d6ecb4a9SRichard Henderson #endif 3700d6ecb4a9SRichard Henderson if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg, 3701d6ecb4a9SRichard Henderson its->mem_offset + endian_fixup)) { 3702d6ecb4a9SRichard Henderson goto done; 3703d6ecb4a9SRichard Henderson } 3704bab1671fSRichard Henderson tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset); 3705bab1671fSRichard Henderson break; 3706bab1671fSRichard Henderson 3707bab1671fSRichard Henderson default: 3708bab1671fSRichard Henderson g_assert_not_reached(); 3709bab1671fSRichard Henderson } 3710bab1671fSRichard Henderson 3711bab1671fSRichard Henderson /* We now have a vector input register, so dup must succeed. */ 3712bab1671fSRichard Henderson ok = tcg_out_dup_vec(s, vtype, vece, ots->reg, ots->reg); 3713bab1671fSRichard Henderson tcg_debug_assert(ok); 3714bab1671fSRichard Henderson 3715bab1671fSRichard Henderson done: 3716bab1671fSRichard Henderson if (IS_DEAD_ARG(1)) { 3717bab1671fSRichard Henderson temp_dead(s, its); 3718bab1671fSRichard Henderson } 3719bab1671fSRichard Henderson if (NEED_SYNC_ARG(0)) { 3720bab1671fSRichard Henderson temp_sync(s, ots, s->reserved_regs, 0, 0); 3721bab1671fSRichard Henderson } 3722bab1671fSRichard Henderson if (IS_DEAD_ARG(0)) { 3723bab1671fSRichard Henderson temp_dead(s, ots); 3724bab1671fSRichard Henderson } 3725bab1671fSRichard Henderson } 3726bab1671fSRichard Henderson 3727dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) 3728c896fe29Sbellard { 3729dd186292SRichard Henderson const TCGLifeData arg_life = op->life; 3730dd186292SRichard Henderson const TCGOpDef * const def = &tcg_op_defs[op->opc]; 373182790a87SRichard Henderson TCGRegSet i_allocated_regs; 373282790a87SRichard Henderson TCGRegSet o_allocated_regs; 3733b6638662SRichard Henderson int i, k, nb_iargs, nb_oargs; 3734b6638662SRichard Henderson TCGReg reg; 3735c896fe29Sbellard TCGArg arg; 3736c896fe29Sbellard const TCGArgConstraint *arg_ct; 3737c896fe29Sbellard TCGTemp *ts; 3738c896fe29Sbellard TCGArg new_args[TCG_MAX_OP_ARGS]; 3739c896fe29Sbellard int const_args[TCG_MAX_OP_ARGS]; 3740c896fe29Sbellard 3741c896fe29Sbellard nb_oargs = def->nb_oargs; 3742c896fe29Sbellard nb_iargs = def->nb_iargs; 3743c896fe29Sbellard 3744c896fe29Sbellard /* copy constants */ 3745c896fe29Sbellard memcpy(new_args + nb_oargs + nb_iargs, 3746dd186292SRichard Henderson op->args + nb_oargs + nb_iargs, 3747c896fe29Sbellard sizeof(TCGArg) * def->nb_cargs); 3748c896fe29Sbellard 3749d21369f5SRichard Henderson i_allocated_regs = s->reserved_regs; 3750d21369f5SRichard Henderson o_allocated_regs = s->reserved_regs; 375182790a87SRichard Henderson 3752c896fe29Sbellard /* satisfy input constraints */ 3753c896fe29Sbellard for (k = 0; k < nb_iargs; k++) { 3754d62816f2SRichard Henderson TCGRegSet i_preferred_regs, o_preferred_regs; 3755d62816f2SRichard Henderson 375666792f90SRichard Henderson i = def->args_ct[nb_oargs + k].sort_index; 3757dd186292SRichard Henderson arg = op->args[i]; 3758c896fe29Sbellard arg_ct = &def->args_ct[i]; 375943439139SRichard Henderson ts = arg_temp(arg); 376040ae5c62SRichard Henderson 376140ae5c62SRichard Henderson if (ts->val_type == TEMP_VAL_CONST 376240ae5c62SRichard Henderson && tcg_target_const_match(ts->val, ts->type, arg_ct)) { 3763c896fe29Sbellard /* constant is OK for instruction */ 3764c896fe29Sbellard const_args[i] = 1; 3765c896fe29Sbellard new_args[i] = ts->val; 3766d62816f2SRichard Henderson continue; 3767c896fe29Sbellard } 376840ae5c62SRichard Henderson 3769d62816f2SRichard Henderson i_preferred_regs = o_preferred_regs = 0; 3770bc2b17e6SRichard Henderson if (arg_ct->ialias) { 3771d62816f2SRichard Henderson o_preferred_regs = op->output_pref[arg_ct->alias_index]; 37725ff9d6a4Sbellard if (ts->fixed_reg) { 37735ff9d6a4Sbellard /* if fixed register, we must allocate a new register 37745ff9d6a4Sbellard if the alias is not the same register */ 3775d62816f2SRichard Henderson if (arg != op->args[arg_ct->alias_index]) { 37765ff9d6a4Sbellard goto allocate_in_reg; 3777d62816f2SRichard Henderson } 37785ff9d6a4Sbellard } else { 3779c896fe29Sbellard /* if the input is aliased to an output and if it is 3780c896fe29Sbellard not dead after the instruction, we must allocate 3781c896fe29Sbellard a new register and move it */ 3782866cb6cbSAurelien Jarno if (!IS_DEAD_ARG(i)) { 3783c896fe29Sbellard goto allocate_in_reg; 3784c896fe29Sbellard } 3785d62816f2SRichard Henderson 37867e1df267SAurelien Jarno /* check if the current register has already been allocated 37877e1df267SAurelien Jarno for another input aliased to an output */ 3788d62816f2SRichard Henderson if (ts->val_type == TEMP_VAL_REG) { 37897e1df267SAurelien Jarno int k2, i2; 3790d62816f2SRichard Henderson reg = ts->reg; 37917e1df267SAurelien Jarno for (k2 = 0 ; k2 < k ; k2++) { 379266792f90SRichard Henderson i2 = def->args_ct[nb_oargs + k2].sort_index; 3793bc2b17e6SRichard Henderson if (def->args_ct[i2].ialias && reg == new_args[i2]) { 37947e1df267SAurelien Jarno goto allocate_in_reg; 37957e1df267SAurelien Jarno } 37967e1df267SAurelien Jarno } 37975ff9d6a4Sbellard } 3798d62816f2SRichard Henderson i_preferred_regs = o_preferred_regs; 3799866cb6cbSAurelien Jarno } 3800d62816f2SRichard Henderson } 3801d62816f2SRichard Henderson 38029be0d080SRichard Henderson temp_load(s, ts, arg_ct->regs, i_allocated_regs, i_preferred_regs); 3803c896fe29Sbellard reg = ts->reg; 3804d62816f2SRichard Henderson 38059be0d080SRichard Henderson if (tcg_regset_test_reg(arg_ct->regs, reg)) { 3806c896fe29Sbellard /* nothing to do : the constraint is satisfied */ 3807c896fe29Sbellard } else { 3808c896fe29Sbellard allocate_in_reg: 3809c896fe29Sbellard /* allocate a new register matching the constraint 3810c896fe29Sbellard and move the temporary register into it */ 3811d62816f2SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 3812d62816f2SRichard Henderson i_allocated_regs, 0); 38139be0d080SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->regs, i_allocated_regs, 3814d62816f2SRichard Henderson o_preferred_regs, ts->indirect_base); 381578113e83SRichard Henderson if (!tcg_out_mov(s, ts->type, reg, ts->reg)) { 3816240c08d0SRichard Henderson /* 3817240c08d0SRichard Henderson * Cross register class move not supported. Sync the 3818240c08d0SRichard Henderson * temp back to its slot and load from there. 3819240c08d0SRichard Henderson */ 3820240c08d0SRichard Henderson temp_sync(s, ts, i_allocated_regs, 0, 0); 3821240c08d0SRichard Henderson tcg_out_ld(s, ts->type, reg, 3822240c08d0SRichard Henderson ts->mem_base->reg, ts->mem_offset); 382378113e83SRichard Henderson } 3824c896fe29Sbellard } 3825c896fe29Sbellard new_args[i] = reg; 3826c896fe29Sbellard const_args[i] = 0; 382782790a87SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg); 3828c896fe29Sbellard } 3829c896fe29Sbellard 3830c896fe29Sbellard /* mark dead temporaries and free the associated registers */ 3831866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 3832866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) { 383343439139SRichard Henderson temp_dead(s, arg_temp(op->args[i])); 3834c896fe29Sbellard } 3835c896fe29Sbellard } 3836c896fe29Sbellard 3837b4cb76e6SRichard Henderson if (def->flags & TCG_OPF_COND_BRANCH) { 3838b4cb76e6SRichard Henderson tcg_reg_alloc_cbranch(s, i_allocated_regs); 3839b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 384082790a87SRichard Henderson tcg_reg_alloc_bb_end(s, i_allocated_regs); 3841a52ad07eSAurelien Jarno } else { 3842c896fe29Sbellard if (def->flags & TCG_OPF_CALL_CLOBBER) { 3843b03cce8eSbellard /* XXX: permit generic clobber register list ? */ 3844c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) { 3845c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { 384682790a87SRichard Henderson tcg_reg_free(s, i, i_allocated_regs); 3847c896fe29Sbellard } 3848c896fe29Sbellard } 38493d5c5f87SAurelien Jarno } 38503d5c5f87SAurelien Jarno if (def->flags & TCG_OPF_SIDE_EFFECTS) { 38513d5c5f87SAurelien Jarno /* sync globals if the op has side effects and might trigger 38523d5c5f87SAurelien Jarno an exception. */ 385382790a87SRichard Henderson sync_globals(s, i_allocated_regs); 3854c896fe29Sbellard } 3855c896fe29Sbellard 3856c896fe29Sbellard /* satisfy the output constraints */ 3857c896fe29Sbellard for(k = 0; k < nb_oargs; k++) { 385866792f90SRichard Henderson i = def->args_ct[k].sort_index; 3859dd186292SRichard Henderson arg = op->args[i]; 3860c896fe29Sbellard arg_ct = &def->args_ct[i]; 386143439139SRichard Henderson ts = arg_temp(arg); 3862d63e3b6eSRichard Henderson 3863d63e3b6eSRichard Henderson /* ENV should not be modified. */ 3864d63e3b6eSRichard Henderson tcg_debug_assert(!ts->fixed_reg); 3865d63e3b6eSRichard Henderson 3866bc2b17e6SRichard Henderson if (arg_ct->oalias && !const_args[arg_ct->alias_index]) { 38675ff9d6a4Sbellard reg = new_args[arg_ct->alias_index]; 3868bc2b17e6SRichard Henderson } else if (arg_ct->newreg) { 38699be0d080SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->regs, 387082790a87SRichard Henderson i_allocated_regs | o_allocated_regs, 387169e3706dSRichard Henderson op->output_pref[k], ts->indirect_base); 3872c896fe29Sbellard } else { 38739be0d080SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs, 387469e3706dSRichard Henderson op->output_pref[k], ts->indirect_base); 3875c896fe29Sbellard } 387682790a87SRichard Henderson tcg_regset_set_reg(o_allocated_regs, reg); 3877639368ddSAurelien Jarno if (ts->val_type == TEMP_VAL_REG) { 3878f8b2f202SRichard Henderson s->reg_to_temp[ts->reg] = NULL; 3879639368ddSAurelien Jarno } 3880c896fe29Sbellard ts->val_type = TEMP_VAL_REG; 3881c896fe29Sbellard ts->reg = reg; 3882d63e3b6eSRichard Henderson /* 3883d63e3b6eSRichard Henderson * Temp value is modified, so the value kept in memory is 3884d63e3b6eSRichard Henderson * potentially not the same. 3885d63e3b6eSRichard Henderson */ 3886c896fe29Sbellard ts->mem_coherent = 0; 3887f8b2f202SRichard Henderson s->reg_to_temp[reg] = ts; 3888c896fe29Sbellard new_args[i] = reg; 3889c896fe29Sbellard } 3890e8996ee0Sbellard } 3891c896fe29Sbellard 3892c896fe29Sbellard /* emit instruction */ 3893d2fd745fSRichard Henderson if (def->flags & TCG_OPF_VECTOR) { 3894d2fd745fSRichard Henderson tcg_out_vec_op(s, op->opc, TCGOP_VECL(op), TCGOP_VECE(op), 3895d2fd745fSRichard Henderson new_args, const_args); 3896d2fd745fSRichard Henderson } else { 3897dd186292SRichard Henderson tcg_out_op(s, op->opc, new_args, const_args); 3898d2fd745fSRichard Henderson } 3899c896fe29Sbellard 3900c896fe29Sbellard /* move the outputs in the correct register if needed */ 3901c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 390243439139SRichard Henderson ts = arg_temp(op->args[i]); 3903d63e3b6eSRichard Henderson 3904d63e3b6eSRichard Henderson /* ENV should not be modified. */ 3905d63e3b6eSRichard Henderson tcg_debug_assert(!ts->fixed_reg); 3906d63e3b6eSRichard Henderson 3907ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) { 390898b4e186SRichard Henderson temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i)); 390959d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) { 3910f8bf00f1SRichard Henderson temp_dead(s, ts); 3911ec7a869dSAurelien Jarno } 3912c896fe29Sbellard } 3913c896fe29Sbellard } 3914c896fe29Sbellard 3915b03cce8eSbellard #ifdef TCG_TARGET_STACK_GROWSUP 3916b03cce8eSbellard #define STACK_DIR(x) (-(x)) 3917b03cce8eSbellard #else 3918b03cce8eSbellard #define STACK_DIR(x) (x) 3919b03cce8eSbellard #endif 3920b03cce8eSbellard 3921dd186292SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op) 3922c896fe29Sbellard { 3923cd9090aaSRichard Henderson const int nb_oargs = TCGOP_CALLO(op); 3924cd9090aaSRichard Henderson const int nb_iargs = TCGOP_CALLI(op); 3925dd186292SRichard Henderson const TCGLifeData arg_life = op->life; 3926b6638662SRichard Henderson int flags, nb_regs, i; 3927b6638662SRichard Henderson TCGReg reg; 3928cf066674SRichard Henderson TCGArg arg; 3929c896fe29Sbellard TCGTemp *ts; 3930d3452f1fSRichard Henderson intptr_t stack_offset; 3931d3452f1fSRichard Henderson size_t call_stack_size; 3932cf066674SRichard Henderson tcg_insn_unit *func_addr; 3933cf066674SRichard Henderson int allocate_args; 3934c896fe29Sbellard TCGRegSet allocated_regs; 3935c896fe29Sbellard 3936dd186292SRichard Henderson func_addr = (tcg_insn_unit *)(intptr_t)op->args[nb_oargs + nb_iargs]; 3937dd186292SRichard Henderson flags = op->args[nb_oargs + nb_iargs + 1]; 3938c896fe29Sbellard 39396e17d0c5SStefan Weil nb_regs = ARRAY_SIZE(tcg_target_call_iarg_regs); 3940c45cb8bbSRichard Henderson if (nb_regs > nb_iargs) { 3941c45cb8bbSRichard Henderson nb_regs = nb_iargs; 3942cf066674SRichard Henderson } 3943c896fe29Sbellard 3944c896fe29Sbellard /* assign stack slots first */ 3945c45cb8bbSRichard Henderson call_stack_size = (nb_iargs - nb_regs) * sizeof(tcg_target_long); 3946c896fe29Sbellard call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) & 3947c896fe29Sbellard ~(TCG_TARGET_STACK_ALIGN - 1); 3948b03cce8eSbellard allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE); 3949b03cce8eSbellard if (allocate_args) { 3950345649c0SBlue Swirl /* XXX: if more than TCG_STATIC_CALL_ARGS_SIZE is needed, 3951345649c0SBlue Swirl preallocate call stack */ 3952345649c0SBlue Swirl tcg_abort(); 3953b03cce8eSbellard } 395439cf05d3Sbellard 395539cf05d3Sbellard stack_offset = TCG_TARGET_CALL_STACK_OFFSET; 3956c45cb8bbSRichard Henderson for (i = nb_regs; i < nb_iargs; i++) { 3957dd186292SRichard Henderson arg = op->args[nb_oargs + i]; 395839cf05d3Sbellard #ifdef TCG_TARGET_STACK_GROWSUP 395939cf05d3Sbellard stack_offset -= sizeof(tcg_target_long); 396039cf05d3Sbellard #endif 396139cf05d3Sbellard if (arg != TCG_CALL_DUMMY_ARG) { 396243439139SRichard Henderson ts = arg_temp(arg); 396340ae5c62SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 3964b722452aSRichard Henderson s->reserved_regs, 0); 3965e4d5434cSblueswir1 tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset); 396639cf05d3Sbellard } 396739cf05d3Sbellard #ifndef TCG_TARGET_STACK_GROWSUP 396839cf05d3Sbellard stack_offset += sizeof(tcg_target_long); 396939cf05d3Sbellard #endif 3970c896fe29Sbellard } 3971c896fe29Sbellard 3972c896fe29Sbellard /* assign input registers */ 3973d21369f5SRichard Henderson allocated_regs = s->reserved_regs; 3974c896fe29Sbellard for (i = 0; i < nb_regs; i++) { 3975dd186292SRichard Henderson arg = op->args[nb_oargs + i]; 397639cf05d3Sbellard if (arg != TCG_CALL_DUMMY_ARG) { 397743439139SRichard Henderson ts = arg_temp(arg); 3978c896fe29Sbellard reg = tcg_target_call_iarg_regs[i]; 397940ae5c62SRichard Henderson 3980c896fe29Sbellard if (ts->val_type == TEMP_VAL_REG) { 3981c896fe29Sbellard if (ts->reg != reg) { 39824250da10SRichard Henderson tcg_reg_free(s, reg, allocated_regs); 398378113e83SRichard Henderson if (!tcg_out_mov(s, ts->type, reg, ts->reg)) { 3984240c08d0SRichard Henderson /* 3985240c08d0SRichard Henderson * Cross register class move not supported. Sync the 3986240c08d0SRichard Henderson * temp back to its slot and load from there. 3987240c08d0SRichard Henderson */ 3988240c08d0SRichard Henderson temp_sync(s, ts, allocated_regs, 0, 0); 3989240c08d0SRichard Henderson tcg_out_ld(s, ts->type, reg, 3990240c08d0SRichard Henderson ts->mem_base->reg, ts->mem_offset); 399178113e83SRichard Henderson } 3992c896fe29Sbellard } 3993c896fe29Sbellard } else { 3994ccb1bb66SRichard Henderson TCGRegSet arg_set = 0; 399540ae5c62SRichard Henderson 39964250da10SRichard Henderson tcg_reg_free(s, reg, allocated_regs); 399740ae5c62SRichard Henderson tcg_regset_set_reg(arg_set, reg); 3998b722452aSRichard Henderson temp_load(s, ts, arg_set, allocated_regs, 0); 3999c896fe29Sbellard } 400040ae5c62SRichard Henderson 4001c896fe29Sbellard tcg_regset_set_reg(allocated_regs, reg); 4002c896fe29Sbellard } 400339cf05d3Sbellard } 4004c896fe29Sbellard 4005c896fe29Sbellard /* mark dead temporaries and free the associated registers */ 4006866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 4007866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) { 400843439139SRichard Henderson temp_dead(s, arg_temp(op->args[i])); 4009c896fe29Sbellard } 4010c896fe29Sbellard } 4011c896fe29Sbellard 4012c896fe29Sbellard /* clobber call registers */ 4013c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) { 4014c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { 4015b3915dbbSRichard Henderson tcg_reg_free(s, i, allocated_regs); 4016c896fe29Sbellard } 4017c896fe29Sbellard } 4018c896fe29Sbellard 401978505279SAurelien Jarno /* Save globals if they might be written by the helper, sync them if 402078505279SAurelien Jarno they might be read. */ 402178505279SAurelien Jarno if (flags & TCG_CALL_NO_READ_GLOBALS) { 402278505279SAurelien Jarno /* Nothing to do */ 402378505279SAurelien Jarno } else if (flags & TCG_CALL_NO_WRITE_GLOBALS) { 402478505279SAurelien Jarno sync_globals(s, allocated_regs); 402578505279SAurelien Jarno } else { 4026e8996ee0Sbellard save_globals(s, allocated_regs); 4027b9c18f56Saurel32 } 4028c896fe29Sbellard 4029cf066674SRichard Henderson tcg_out_call(s, func_addr); 4030c896fe29Sbellard 4031c896fe29Sbellard /* assign output registers and emit moves if needed */ 4032c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 4033dd186292SRichard Henderson arg = op->args[i]; 403443439139SRichard Henderson ts = arg_temp(arg); 4035d63e3b6eSRichard Henderson 4036d63e3b6eSRichard Henderson /* ENV should not be modified. */ 4037d63e3b6eSRichard Henderson tcg_debug_assert(!ts->fixed_reg); 4038d63e3b6eSRichard Henderson 4039c896fe29Sbellard reg = tcg_target_call_oarg_regs[i]; 4040eabb7b91SAurelien Jarno tcg_debug_assert(s->reg_to_temp[reg] == NULL); 4041639368ddSAurelien Jarno if (ts->val_type == TEMP_VAL_REG) { 4042f8b2f202SRichard Henderson s->reg_to_temp[ts->reg] = NULL; 4043639368ddSAurelien Jarno } 4044c896fe29Sbellard ts->val_type = TEMP_VAL_REG; 4045c896fe29Sbellard ts->reg = reg; 4046c896fe29Sbellard ts->mem_coherent = 0; 4047f8b2f202SRichard Henderson s->reg_to_temp[reg] = ts; 4048ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) { 404998b4e186SRichard Henderson temp_sync(s, ts, allocated_regs, 0, IS_DEAD_ARG(i)); 405059d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) { 4051f8bf00f1SRichard Henderson temp_dead(s, ts); 4052c896fe29Sbellard } 4053c896fe29Sbellard } 40548c11ad25SAurelien Jarno } 4055c896fe29Sbellard 4056c896fe29Sbellard #ifdef CONFIG_PROFILER 4057c896fe29Sbellard 4058c3fac113SEmilio G. Cota /* avoid copy/paste errors */ 4059c3fac113SEmilio G. Cota #define PROF_ADD(to, from, field) \ 4060c3fac113SEmilio G. Cota do { \ 4061d73415a3SStefan Hajnoczi (to)->field += qatomic_read(&((from)->field)); \ 4062c3fac113SEmilio G. Cota } while (0) 4063c896fe29Sbellard 4064c3fac113SEmilio G. Cota #define PROF_MAX(to, from, field) \ 4065c3fac113SEmilio G. Cota do { \ 4066d73415a3SStefan Hajnoczi typeof((from)->field) val__ = qatomic_read(&((from)->field)); \ 4067c3fac113SEmilio G. Cota if (val__ > (to)->field) { \ 4068c3fac113SEmilio G. Cota (to)->field = val__; \ 4069c3fac113SEmilio G. Cota } \ 4070c3fac113SEmilio G. Cota } while (0) 4071c3fac113SEmilio G. Cota 4072c3fac113SEmilio G. Cota /* Pass in a zero'ed @prof */ 4073c3fac113SEmilio G. Cota static inline 4074c3fac113SEmilio G. Cota void tcg_profile_snapshot(TCGProfile *prof, bool counters, bool table) 4075c896fe29Sbellard { 4076d73415a3SStefan Hajnoczi unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs); 4077c3fac113SEmilio G. Cota unsigned int i; 4078c3fac113SEmilio G. Cota 40793468b59eSEmilio G. Cota for (i = 0; i < n_ctxs; i++) { 4080d73415a3SStefan Hajnoczi TCGContext *s = qatomic_read(&tcg_ctxs[i]); 40813468b59eSEmilio G. Cota const TCGProfile *orig = &s->prof; 4082c3fac113SEmilio G. Cota 4083c3fac113SEmilio G. Cota if (counters) { 408472fd2efbSEmilio G. Cota PROF_ADD(prof, orig, cpu_exec_time); 4085c3fac113SEmilio G. Cota PROF_ADD(prof, orig, tb_count1); 4086c3fac113SEmilio G. Cota PROF_ADD(prof, orig, tb_count); 4087c3fac113SEmilio G. Cota PROF_ADD(prof, orig, op_count); 4088c3fac113SEmilio G. Cota PROF_MAX(prof, orig, op_count_max); 4089c3fac113SEmilio G. Cota PROF_ADD(prof, orig, temp_count); 4090c3fac113SEmilio G. Cota PROF_MAX(prof, orig, temp_count_max); 4091c3fac113SEmilio G. Cota PROF_ADD(prof, orig, del_op_count); 4092c3fac113SEmilio G. Cota PROF_ADD(prof, orig, code_in_len); 4093c3fac113SEmilio G. Cota PROF_ADD(prof, orig, code_out_len); 4094c3fac113SEmilio G. Cota PROF_ADD(prof, orig, search_out_len); 4095c3fac113SEmilio G. Cota PROF_ADD(prof, orig, interm_time); 4096c3fac113SEmilio G. Cota PROF_ADD(prof, orig, code_time); 4097c3fac113SEmilio G. Cota PROF_ADD(prof, orig, la_time); 4098c3fac113SEmilio G. Cota PROF_ADD(prof, orig, opt_time); 4099c3fac113SEmilio G. Cota PROF_ADD(prof, orig, restore_count); 4100c3fac113SEmilio G. Cota PROF_ADD(prof, orig, restore_time); 4101c3fac113SEmilio G. Cota } 4102c3fac113SEmilio G. Cota if (table) { 4103c896fe29Sbellard int i; 4104d70724ceSzhanghailiang 410515fc7daaSRichard Henderson for (i = 0; i < NB_OPS; i++) { 4106c3fac113SEmilio G. Cota PROF_ADD(prof, orig, table_op_count[i]); 4107c3fac113SEmilio G. Cota } 4108c3fac113SEmilio G. Cota } 4109c3fac113SEmilio G. Cota } 4110c3fac113SEmilio G. Cota } 4111c3fac113SEmilio G. Cota 4112c3fac113SEmilio G. Cota #undef PROF_ADD 4113c3fac113SEmilio G. Cota #undef PROF_MAX 4114c3fac113SEmilio G. Cota 4115c3fac113SEmilio G. Cota static void tcg_profile_snapshot_counters(TCGProfile *prof) 4116c3fac113SEmilio G. Cota { 4117c3fac113SEmilio G. Cota tcg_profile_snapshot(prof, true, false); 4118c3fac113SEmilio G. Cota } 4119c3fac113SEmilio G. Cota 4120c3fac113SEmilio G. Cota static void tcg_profile_snapshot_table(TCGProfile *prof) 4121c3fac113SEmilio G. Cota { 4122c3fac113SEmilio G. Cota tcg_profile_snapshot(prof, false, true); 4123c3fac113SEmilio G. Cota } 4124c3fac113SEmilio G. Cota 4125d4c51a0aSMarkus Armbruster void tcg_dump_op_count(void) 4126c3fac113SEmilio G. Cota { 4127c3fac113SEmilio G. Cota TCGProfile prof = {}; 4128c3fac113SEmilio G. Cota int i; 4129c3fac113SEmilio G. Cota 4130c3fac113SEmilio G. Cota tcg_profile_snapshot_table(&prof); 4131c3fac113SEmilio G. Cota for (i = 0; i < NB_OPS; i++) { 4132d4c51a0aSMarkus Armbruster qemu_printf("%s %" PRId64 "\n", tcg_op_defs[i].name, 4133c3fac113SEmilio G. Cota prof.table_op_count[i]); 4134c896fe29Sbellard } 4135c896fe29Sbellard } 413672fd2efbSEmilio G. Cota 413772fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void) 413872fd2efbSEmilio G. Cota { 4139d73415a3SStefan Hajnoczi unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs); 414072fd2efbSEmilio G. Cota unsigned int i; 414172fd2efbSEmilio G. Cota int64_t ret = 0; 414272fd2efbSEmilio G. Cota 414372fd2efbSEmilio G. Cota for (i = 0; i < n_ctxs; i++) { 4144d73415a3SStefan Hajnoczi const TCGContext *s = qatomic_read(&tcg_ctxs[i]); 414572fd2efbSEmilio G. Cota const TCGProfile *prof = &s->prof; 414672fd2efbSEmilio G. Cota 4147d73415a3SStefan Hajnoczi ret += qatomic_read(&prof->cpu_exec_time); 414872fd2efbSEmilio G. Cota } 414972fd2efbSEmilio G. Cota return ret; 415072fd2efbSEmilio G. Cota } 4151246ae24dSMax Filippov #else 4152d4c51a0aSMarkus Armbruster void tcg_dump_op_count(void) 4153246ae24dSMax Filippov { 4154d4c51a0aSMarkus Armbruster qemu_printf("[TCG profiler not compiled]\n"); 4155246ae24dSMax Filippov } 415672fd2efbSEmilio G. Cota 415772fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void) 415872fd2efbSEmilio G. Cota { 415972fd2efbSEmilio G. Cota error_report("%s: TCG profiler not compiled", __func__); 416072fd2efbSEmilio G. Cota exit(EXIT_FAILURE); 416172fd2efbSEmilio G. Cota } 4162c896fe29Sbellard #endif 4163c896fe29Sbellard 4164c896fe29Sbellard 41655bd2ec3dSAlex Bennée int tcg_gen_code(TCGContext *s, TranslationBlock *tb) 4166c896fe29Sbellard { 4167c3fac113SEmilio G. Cota #ifdef CONFIG_PROFILER 4168c3fac113SEmilio G. Cota TCGProfile *prof = &s->prof; 4169c3fac113SEmilio G. Cota #endif 417015fa08f8SRichard Henderson int i, num_insns; 417115fa08f8SRichard Henderson TCGOp *op; 4172c896fe29Sbellard 417304fe6400SRichard Henderson #ifdef CONFIG_PROFILER 417404fe6400SRichard Henderson { 4175c1f543b7SEmilio G. Cota int n = 0; 417604fe6400SRichard Henderson 417715fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 417815fa08f8SRichard Henderson n++; 417915fa08f8SRichard Henderson } 4180d73415a3SStefan Hajnoczi qatomic_set(&prof->op_count, prof->op_count + n); 4181c3fac113SEmilio G. Cota if (n > prof->op_count_max) { 4182d73415a3SStefan Hajnoczi qatomic_set(&prof->op_count_max, n); 418304fe6400SRichard Henderson } 418404fe6400SRichard Henderson 418504fe6400SRichard Henderson n = s->nb_temps; 4186d73415a3SStefan Hajnoczi qatomic_set(&prof->temp_count, prof->temp_count + n); 4187c3fac113SEmilio G. Cota if (n > prof->temp_count_max) { 4188d73415a3SStefan Hajnoczi qatomic_set(&prof->temp_count_max, n); 418904fe6400SRichard Henderson } 419004fe6400SRichard Henderson } 419104fe6400SRichard Henderson #endif 419204fe6400SRichard Henderson 4193c896fe29Sbellard #ifdef DEBUG_DISAS 4194d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP) 4195d977e1c2SAlex Bennée && qemu_log_in_addr_range(tb->pc))) { 4196fc59d2d8SRobert Foley FILE *logfile = qemu_log_lock(); 419793fcfe39Saliguori qemu_log("OP:\n"); 41981894f69aSRichard Henderson tcg_dump_ops(s, false); 419993fcfe39Saliguori qemu_log("\n"); 4200fc59d2d8SRobert Foley qemu_log_unlock(logfile); 4201c896fe29Sbellard } 4202c896fe29Sbellard #endif 4203c896fe29Sbellard 4204bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG 4205bef16ab4SRichard Henderson /* Ensure all labels referenced have been emitted. */ 4206bef16ab4SRichard Henderson { 4207bef16ab4SRichard Henderson TCGLabel *l; 4208bef16ab4SRichard Henderson bool error = false; 4209bef16ab4SRichard Henderson 4210bef16ab4SRichard Henderson QSIMPLEQ_FOREACH(l, &s->labels, next) { 4211bef16ab4SRichard Henderson if (unlikely(!l->present) && l->refs) { 4212bef16ab4SRichard Henderson qemu_log_mask(CPU_LOG_TB_OP, 4213bef16ab4SRichard Henderson "$L%d referenced but not present.\n", l->id); 4214bef16ab4SRichard Henderson error = true; 4215bef16ab4SRichard Henderson } 4216bef16ab4SRichard Henderson } 4217bef16ab4SRichard Henderson assert(!error); 4218bef16ab4SRichard Henderson } 4219bef16ab4SRichard Henderson #endif 4220bef16ab4SRichard Henderson 4221c5cc28ffSAurelien Jarno #ifdef CONFIG_PROFILER 4222d73415a3SStefan Hajnoczi qatomic_set(&prof->opt_time, prof->opt_time - profile_getclock()); 4223c5cc28ffSAurelien Jarno #endif 4224c5cc28ffSAurelien Jarno 42258f2e8c07SKirill Batuzov #ifdef USE_TCG_OPTIMIZATIONS 4226c45cb8bbSRichard Henderson tcg_optimize(s); 42278f2e8c07SKirill Batuzov #endif 42288f2e8c07SKirill Batuzov 4229a23a9ec6Sbellard #ifdef CONFIG_PROFILER 4230d73415a3SStefan Hajnoczi qatomic_set(&prof->opt_time, prof->opt_time + profile_getclock()); 4231d73415a3SStefan Hajnoczi qatomic_set(&prof->la_time, prof->la_time - profile_getclock()); 4232a23a9ec6Sbellard #endif 4233c5cc28ffSAurelien Jarno 4234b4fc67c7SRichard Henderson reachable_code_pass(s); 4235b83eabeaSRichard Henderson liveness_pass_1(s); 42365a18407fSRichard Henderson 42375a18407fSRichard Henderson if (s->nb_indirects > 0) { 42385a18407fSRichard Henderson #ifdef DEBUG_DISAS 42395a18407fSRichard Henderson if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND) 42405a18407fSRichard Henderson && qemu_log_in_addr_range(tb->pc))) { 4241fc59d2d8SRobert Foley FILE *logfile = qemu_log_lock(); 42425a18407fSRichard Henderson qemu_log("OP before indirect lowering:\n"); 42431894f69aSRichard Henderson tcg_dump_ops(s, false); 42445a18407fSRichard Henderson qemu_log("\n"); 4245fc59d2d8SRobert Foley qemu_log_unlock(logfile); 42465a18407fSRichard Henderson } 42475a18407fSRichard Henderson #endif 42485a18407fSRichard Henderson /* Replace indirect temps with direct temps. */ 4249b83eabeaSRichard Henderson if (liveness_pass_2(s)) { 42505a18407fSRichard Henderson /* If changes were made, re-run liveness. */ 4251b83eabeaSRichard Henderson liveness_pass_1(s); 42525a18407fSRichard Henderson } 42535a18407fSRichard Henderson } 4254c5cc28ffSAurelien Jarno 4255a23a9ec6Sbellard #ifdef CONFIG_PROFILER 4256d73415a3SStefan Hajnoczi qatomic_set(&prof->la_time, prof->la_time + profile_getclock()); 4257a23a9ec6Sbellard #endif 4258c896fe29Sbellard 4259c896fe29Sbellard #ifdef DEBUG_DISAS 4260d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT) 4261d977e1c2SAlex Bennée && qemu_log_in_addr_range(tb->pc))) { 4262fc59d2d8SRobert Foley FILE *logfile = qemu_log_lock(); 4263c5cc28ffSAurelien Jarno qemu_log("OP after optimization and liveness analysis:\n"); 42641894f69aSRichard Henderson tcg_dump_ops(s, true); 426593fcfe39Saliguori qemu_log("\n"); 4266fc59d2d8SRobert Foley qemu_log_unlock(logfile); 4267c896fe29Sbellard } 4268c896fe29Sbellard #endif 4269c896fe29Sbellard 4270c896fe29Sbellard tcg_reg_alloc_start(s); 4271c896fe29Sbellard 4272db0c51a3SRichard Henderson /* 4273db0c51a3SRichard Henderson * Reset the buffer pointers when restarting after overflow. 4274db0c51a3SRichard Henderson * TODO: Move this into translate-all.c with the rest of the 4275db0c51a3SRichard Henderson * buffer management. Having only this done here is confusing. 4276db0c51a3SRichard Henderson */ 4277db0c51a3SRichard Henderson s->code_buf = tcg_splitwx_to_rw(tb->tc.ptr); 4278db0c51a3SRichard Henderson s->code_ptr = s->code_buf; 4279c896fe29Sbellard 4280659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS 42816001f772SLaurent Vivier QSIMPLEQ_INIT(&s->ldst_labels); 4282659ef5cbSRichard Henderson #endif 428357a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 428457a26946SRichard Henderson s->pool_labels = NULL; 428557a26946SRichard Henderson #endif 42869ecefc84SRichard Henderson 4287fca8a500SRichard Henderson num_insns = -1; 428815fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 4289c45cb8bbSRichard Henderson TCGOpcode opc = op->opc; 4290b3db8758Sblueswir1 4291c896fe29Sbellard #ifdef CONFIG_PROFILER 4292d73415a3SStefan Hajnoczi qatomic_set(&prof->table_op_count[opc], prof->table_op_count[opc] + 1); 4293c896fe29Sbellard #endif 4294c45cb8bbSRichard Henderson 4295c896fe29Sbellard switch (opc) { 4296c896fe29Sbellard case INDEX_op_mov_i32: 4297c896fe29Sbellard case INDEX_op_mov_i64: 4298d2fd745fSRichard Henderson case INDEX_op_mov_vec: 4299dd186292SRichard Henderson tcg_reg_alloc_mov(s, op); 4300c896fe29Sbellard break; 4301e8996ee0Sbellard case INDEX_op_movi_i32: 4302e8996ee0Sbellard case INDEX_op_movi_i64: 4303d2fd745fSRichard Henderson case INDEX_op_dupi_vec: 4304dd186292SRichard Henderson tcg_reg_alloc_movi(s, op); 4305e8996ee0Sbellard break; 4306bab1671fSRichard Henderson case INDEX_op_dup_vec: 4307bab1671fSRichard Henderson tcg_reg_alloc_dup(s, op); 4308bab1671fSRichard Henderson break; 4309765b842aSRichard Henderson case INDEX_op_insn_start: 4310fca8a500SRichard Henderson if (num_insns >= 0) { 43119f754620SRichard Henderson size_t off = tcg_current_code_size(s); 43129f754620SRichard Henderson s->gen_insn_end_off[num_insns] = off; 43139f754620SRichard Henderson /* Assert that we do not overflow our stored offset. */ 43149f754620SRichard Henderson assert(s->gen_insn_end_off[num_insns] == off); 4315fca8a500SRichard Henderson } 4316fca8a500SRichard Henderson num_insns++; 4317bad729e2SRichard Henderson for (i = 0; i < TARGET_INSN_START_WORDS; ++i) { 4318bad729e2SRichard Henderson target_ulong a; 4319bad729e2SRichard Henderson #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS 4320efee3746SRichard Henderson a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]); 4321bad729e2SRichard Henderson #else 4322efee3746SRichard Henderson a = op->args[i]; 4323bad729e2SRichard Henderson #endif 4324fca8a500SRichard Henderson s->gen_insn_data[num_insns][i] = a; 4325bad729e2SRichard Henderson } 4326c896fe29Sbellard break; 43275ff9d6a4Sbellard case INDEX_op_discard: 432843439139SRichard Henderson temp_dead(s, arg_temp(op->args[0])); 43295ff9d6a4Sbellard break; 4330c896fe29Sbellard case INDEX_op_set_label: 4331e8996ee0Sbellard tcg_reg_alloc_bb_end(s, s->reserved_regs); 433292ab8e7dSRichard Henderson tcg_out_label(s, arg_label(op->args[0])); 4333c896fe29Sbellard break; 4334c896fe29Sbellard case INDEX_op_call: 4335dd186292SRichard Henderson tcg_reg_alloc_call(s, op); 4336c45cb8bbSRichard Henderson break; 4337c896fe29Sbellard default: 433825c4d9ccSRichard Henderson /* Sanity check that we've not introduced any unhandled opcodes. */ 4339be0f34b5SRichard Henderson tcg_debug_assert(tcg_op_supported(opc)); 4340c896fe29Sbellard /* Note: in order to speed up the code, it would be much 4341c896fe29Sbellard faster to have specialized register allocator functions for 4342c896fe29Sbellard some common argument patterns */ 4343dd186292SRichard Henderson tcg_reg_alloc_op(s, op); 4344c896fe29Sbellard break; 4345c896fe29Sbellard } 43468d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG 4347c896fe29Sbellard check_regs(s); 4348c896fe29Sbellard #endif 4349b125f9dcSRichard Henderson /* Test for (pending) buffer overflow. The assumption is that any 4350b125f9dcSRichard Henderson one operation beginning below the high water mark cannot overrun 4351b125f9dcSRichard Henderson the buffer completely. Thus we can test for overflow after 4352b125f9dcSRichard Henderson generating code without having to check during generation. */ 4353644da9b3SJohn Clarke if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) { 4354b125f9dcSRichard Henderson return -1; 4355b125f9dcSRichard Henderson } 43566e6c4efeSRichard Henderson /* Test for TB overflow, as seen by gen_insn_end_off. */ 43576e6c4efeSRichard Henderson if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) { 43586e6c4efeSRichard Henderson return -2; 43596e6c4efeSRichard Henderson } 4360c896fe29Sbellard } 4361fca8a500SRichard Henderson tcg_debug_assert(num_insns >= 0); 4362fca8a500SRichard Henderson s->gen_insn_end_off[num_insns] = tcg_current_code_size(s); 4363c45cb8bbSRichard Henderson 4364b76f0d8cSYeongkyoon Lee /* Generate TB finalization at the end of block */ 4365659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS 4366aeee05f5SRichard Henderson i = tcg_out_ldst_finalize(s); 4367aeee05f5SRichard Henderson if (i < 0) { 4368aeee05f5SRichard Henderson return i; 436923dceda6SRichard Henderson } 4370659ef5cbSRichard Henderson #endif 437157a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 43721768987bSRichard Henderson i = tcg_out_pool_finalize(s); 43731768987bSRichard Henderson if (i < 0) { 43741768987bSRichard Henderson return i; 437557a26946SRichard Henderson } 437657a26946SRichard Henderson #endif 43777ecd02a0SRichard Henderson if (!tcg_resolve_relocs(s)) { 43787ecd02a0SRichard Henderson return -2; 43797ecd02a0SRichard Henderson } 4380c896fe29Sbellard 4381df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 4382c896fe29Sbellard /* flush instruction cache */ 4383db0c51a3SRichard Henderson flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf), 4384db0c51a3SRichard Henderson (uintptr_t)s->code_buf, 43851da8de39SRichard Henderson tcg_ptr_byte_diff(s->code_ptr, s->code_buf)); 4386df5d2b16SRichard Henderson #endif 43872aeabc08SStefan Weil 43881813e175SRichard Henderson return tcg_current_code_size(s); 4389c896fe29Sbellard } 4390c896fe29Sbellard 4391a23a9ec6Sbellard #ifdef CONFIG_PROFILER 43923de2faa9SMarkus Armbruster void tcg_dump_info(void) 4393a23a9ec6Sbellard { 4394c3fac113SEmilio G. Cota TCGProfile prof = {}; 4395c3fac113SEmilio G. Cota const TCGProfile *s; 4396c3fac113SEmilio G. Cota int64_t tb_count; 4397c3fac113SEmilio G. Cota int64_t tb_div_count; 4398c3fac113SEmilio G. Cota int64_t tot; 4399c3fac113SEmilio G. Cota 4400c3fac113SEmilio G. Cota tcg_profile_snapshot_counters(&prof); 4401c3fac113SEmilio G. Cota s = &prof; 4402c3fac113SEmilio G. Cota tb_count = s->tb_count; 4403c3fac113SEmilio G. Cota tb_div_count = tb_count ? tb_count : 1; 4404c3fac113SEmilio G. Cota tot = s->interm_time + s->code_time; 4405a23a9ec6Sbellard 44063de2faa9SMarkus Armbruster qemu_printf("JIT cycles %" PRId64 " (%0.3f s at 2.4 GHz)\n", 4407a23a9ec6Sbellard tot, tot / 2.4e9); 44083de2faa9SMarkus Armbruster qemu_printf("translated TBs %" PRId64 " (aborted=%" PRId64 44093de2faa9SMarkus Armbruster " %0.1f%%)\n", 4410fca8a500SRichard Henderson tb_count, s->tb_count1 - tb_count, 4411fca8a500SRichard Henderson (double)(s->tb_count1 - s->tb_count) 4412fca8a500SRichard Henderson / (s->tb_count1 ? s->tb_count1 : 1) * 100.0); 44133de2faa9SMarkus Armbruster qemu_printf("avg ops/TB %0.1f max=%d\n", 4414fca8a500SRichard Henderson (double)s->op_count / tb_div_count, s->op_count_max); 44153de2faa9SMarkus Armbruster qemu_printf("deleted ops/TB %0.2f\n", 4416fca8a500SRichard Henderson (double)s->del_op_count / tb_div_count); 44173de2faa9SMarkus Armbruster qemu_printf("avg temps/TB %0.2f max=%d\n", 4418fca8a500SRichard Henderson (double)s->temp_count / tb_div_count, s->temp_count_max); 44193de2faa9SMarkus Armbruster qemu_printf("avg host code/TB %0.1f\n", 4420fca8a500SRichard Henderson (double)s->code_out_len / tb_div_count); 44213de2faa9SMarkus Armbruster qemu_printf("avg search data/TB %0.1f\n", 4422fca8a500SRichard Henderson (double)s->search_out_len / tb_div_count); 4423a23a9ec6Sbellard 44243de2faa9SMarkus Armbruster qemu_printf("cycles/op %0.1f\n", 4425a23a9ec6Sbellard s->op_count ? (double)tot / s->op_count : 0); 44263de2faa9SMarkus Armbruster qemu_printf("cycles/in byte %0.1f\n", 4427a23a9ec6Sbellard s->code_in_len ? (double)tot / s->code_in_len : 0); 44283de2faa9SMarkus Armbruster qemu_printf("cycles/out byte %0.1f\n", 4429a23a9ec6Sbellard s->code_out_len ? (double)tot / s->code_out_len : 0); 44303de2faa9SMarkus Armbruster qemu_printf("cycles/search byte %0.1f\n", 4431fca8a500SRichard Henderson s->search_out_len ? (double)tot / s->search_out_len : 0); 4432fca8a500SRichard Henderson if (tot == 0) { 4433a23a9ec6Sbellard tot = 1; 4434fca8a500SRichard Henderson } 44353de2faa9SMarkus Armbruster qemu_printf(" gen_interm time %0.1f%%\n", 4436a23a9ec6Sbellard (double)s->interm_time / tot * 100.0); 44373de2faa9SMarkus Armbruster qemu_printf(" gen_code time %0.1f%%\n", 4438a23a9ec6Sbellard (double)s->code_time / tot * 100.0); 44393de2faa9SMarkus Armbruster qemu_printf("optim./code time %0.1f%%\n", 4440c5cc28ffSAurelien Jarno (double)s->opt_time / (s->code_time ? s->code_time : 1) 4441c5cc28ffSAurelien Jarno * 100.0); 44423de2faa9SMarkus Armbruster qemu_printf("liveness/code time %0.1f%%\n", 4443a23a9ec6Sbellard (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0); 44443de2faa9SMarkus Armbruster qemu_printf("cpu_restore count %" PRId64 "\n", 4445a23a9ec6Sbellard s->restore_count); 44463de2faa9SMarkus Armbruster qemu_printf(" avg cycles %0.1f\n", 4447a23a9ec6Sbellard s->restore_count ? (double)s->restore_time / s->restore_count : 0); 4448a23a9ec6Sbellard } 4449a23a9ec6Sbellard #else 44503de2faa9SMarkus Armbruster void tcg_dump_info(void) 4451a23a9ec6Sbellard { 44523de2faa9SMarkus Armbruster qemu_printf("[TCG profiler not compiled]\n"); 4453a23a9ec6Sbellard } 4454a23a9ec6Sbellard #endif 4455813da627SRichard Henderson 4456813da627SRichard Henderson #ifdef ELF_HOST_MACHINE 44575872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things: 44585872bbf2SRichard Henderson 44595872bbf2SRichard Henderson (1) Define ELF_HOST_MACHINE to indicate both what value to 44605872bbf2SRichard Henderson put into the ELF image and to indicate support for the feature. 44615872bbf2SRichard Henderson 44625872bbf2SRichard Henderson (2) Define tcg_register_jit. This should create a buffer containing 44635872bbf2SRichard Henderson the contents of a .debug_frame section that describes the post- 44645872bbf2SRichard Henderson prologue unwind info for the tcg machine. 44655872bbf2SRichard Henderson 44665872bbf2SRichard Henderson (3) Call tcg_register_jit_int, with the constructed .debug_frame. 44675872bbf2SRichard Henderson */ 4468813da627SRichard Henderson 4469813da627SRichard Henderson /* Begin GDB interface. THE FOLLOWING MUST MATCH GDB DOCS. */ 4470813da627SRichard Henderson typedef enum { 4471813da627SRichard Henderson JIT_NOACTION = 0, 4472813da627SRichard Henderson JIT_REGISTER_FN, 4473813da627SRichard Henderson JIT_UNREGISTER_FN 4474813da627SRichard Henderson } jit_actions_t; 4475813da627SRichard Henderson 4476813da627SRichard Henderson struct jit_code_entry { 4477813da627SRichard Henderson struct jit_code_entry *next_entry; 4478813da627SRichard Henderson struct jit_code_entry *prev_entry; 4479813da627SRichard Henderson const void *symfile_addr; 4480813da627SRichard Henderson uint64_t symfile_size; 4481813da627SRichard Henderson }; 4482813da627SRichard Henderson 4483813da627SRichard Henderson struct jit_descriptor { 4484813da627SRichard Henderson uint32_t version; 4485813da627SRichard Henderson uint32_t action_flag; 4486813da627SRichard Henderson struct jit_code_entry *relevant_entry; 4487813da627SRichard Henderson struct jit_code_entry *first_entry; 4488813da627SRichard Henderson }; 4489813da627SRichard Henderson 4490813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline)); 4491813da627SRichard Henderson void __jit_debug_register_code(void) 4492813da627SRichard Henderson { 4493813da627SRichard Henderson asm(""); 4494813da627SRichard Henderson } 4495813da627SRichard Henderson 4496813da627SRichard Henderson /* Must statically initialize the version, because GDB may check 4497813da627SRichard Henderson the version before we can set it. */ 4498813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 }; 4499813da627SRichard Henderson 4500813da627SRichard Henderson /* End GDB interface. */ 4501813da627SRichard Henderson 4502813da627SRichard Henderson static int find_string(const char *strtab, const char *str) 4503813da627SRichard Henderson { 4504813da627SRichard Henderson const char *p = strtab + 1; 4505813da627SRichard Henderson 4506813da627SRichard Henderson while (1) { 4507813da627SRichard Henderson if (strcmp(p, str) == 0) { 4508813da627SRichard Henderson return p - strtab; 4509813da627SRichard Henderson } 4510813da627SRichard Henderson p += strlen(p) + 1; 4511813da627SRichard Henderson } 4512813da627SRichard Henderson } 4513813da627SRichard Henderson 4514755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf_ptr, size_t buf_size, 45152c90784aSRichard Henderson const void *debug_frame, 45162c90784aSRichard Henderson size_t debug_frame_size) 4517813da627SRichard Henderson { 45185872bbf2SRichard Henderson struct __attribute__((packed)) DebugInfo { 45195872bbf2SRichard Henderson uint32_t len; 45205872bbf2SRichard Henderson uint16_t version; 45215872bbf2SRichard Henderson uint32_t abbrev; 45225872bbf2SRichard Henderson uint8_t ptr_size; 45235872bbf2SRichard Henderson uint8_t cu_die; 45245872bbf2SRichard Henderson uint16_t cu_lang; 45255872bbf2SRichard Henderson uintptr_t cu_low_pc; 45265872bbf2SRichard Henderson uintptr_t cu_high_pc; 45275872bbf2SRichard Henderson uint8_t fn_die; 45285872bbf2SRichard Henderson char fn_name[16]; 45295872bbf2SRichard Henderson uintptr_t fn_low_pc; 45305872bbf2SRichard Henderson uintptr_t fn_high_pc; 45315872bbf2SRichard Henderson uint8_t cu_eoc; 45325872bbf2SRichard Henderson }; 4533813da627SRichard Henderson 4534813da627SRichard Henderson struct ElfImage { 4535813da627SRichard Henderson ElfW(Ehdr) ehdr; 4536813da627SRichard Henderson ElfW(Phdr) phdr; 45375872bbf2SRichard Henderson ElfW(Shdr) shdr[7]; 45385872bbf2SRichard Henderson ElfW(Sym) sym[2]; 45395872bbf2SRichard Henderson struct DebugInfo di; 45405872bbf2SRichard Henderson uint8_t da[24]; 45415872bbf2SRichard Henderson char str[80]; 45425872bbf2SRichard Henderson }; 45435872bbf2SRichard Henderson 45445872bbf2SRichard Henderson struct ElfImage *img; 45455872bbf2SRichard Henderson 45465872bbf2SRichard Henderson static const struct ElfImage img_template = { 45475872bbf2SRichard Henderson .ehdr = { 45485872bbf2SRichard Henderson .e_ident[EI_MAG0] = ELFMAG0, 45495872bbf2SRichard Henderson .e_ident[EI_MAG1] = ELFMAG1, 45505872bbf2SRichard Henderson .e_ident[EI_MAG2] = ELFMAG2, 45515872bbf2SRichard Henderson .e_ident[EI_MAG3] = ELFMAG3, 45525872bbf2SRichard Henderson .e_ident[EI_CLASS] = ELF_CLASS, 45535872bbf2SRichard Henderson .e_ident[EI_DATA] = ELF_DATA, 45545872bbf2SRichard Henderson .e_ident[EI_VERSION] = EV_CURRENT, 45555872bbf2SRichard Henderson .e_type = ET_EXEC, 45565872bbf2SRichard Henderson .e_machine = ELF_HOST_MACHINE, 45575872bbf2SRichard Henderson .e_version = EV_CURRENT, 45585872bbf2SRichard Henderson .e_phoff = offsetof(struct ElfImage, phdr), 45595872bbf2SRichard Henderson .e_shoff = offsetof(struct ElfImage, shdr), 45605872bbf2SRichard Henderson .e_ehsize = sizeof(ElfW(Shdr)), 45615872bbf2SRichard Henderson .e_phentsize = sizeof(ElfW(Phdr)), 45625872bbf2SRichard Henderson .e_phnum = 1, 45635872bbf2SRichard Henderson .e_shentsize = sizeof(ElfW(Shdr)), 45645872bbf2SRichard Henderson .e_shnum = ARRAY_SIZE(img->shdr), 45655872bbf2SRichard Henderson .e_shstrndx = ARRAY_SIZE(img->shdr) - 1, 4566abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS 4567abbb3eaeSRichard Henderson .e_flags = ELF_HOST_FLAGS, 4568abbb3eaeSRichard Henderson #endif 4569abbb3eaeSRichard Henderson #ifdef ELF_OSABI 4570abbb3eaeSRichard Henderson .e_ident[EI_OSABI] = ELF_OSABI, 4571abbb3eaeSRichard Henderson #endif 45725872bbf2SRichard Henderson }, 45735872bbf2SRichard Henderson .phdr = { 45745872bbf2SRichard Henderson .p_type = PT_LOAD, 45755872bbf2SRichard Henderson .p_flags = PF_X, 45765872bbf2SRichard Henderson }, 45775872bbf2SRichard Henderson .shdr = { 45785872bbf2SRichard Henderson [0] = { .sh_type = SHT_NULL }, 45795872bbf2SRichard Henderson /* Trick: The contents of code_gen_buffer are not present in 45805872bbf2SRichard Henderson this fake ELF file; that got allocated elsewhere. Therefore 45815872bbf2SRichard Henderson we mark .text as SHT_NOBITS (similar to .bss) so that readers 45825872bbf2SRichard Henderson will not look for contents. We can record any address. */ 45835872bbf2SRichard Henderson [1] = { /* .text */ 45845872bbf2SRichard Henderson .sh_type = SHT_NOBITS, 45855872bbf2SRichard Henderson .sh_flags = SHF_EXECINSTR | SHF_ALLOC, 45865872bbf2SRichard Henderson }, 45875872bbf2SRichard Henderson [2] = { /* .debug_info */ 45885872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 45895872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, di), 45905872bbf2SRichard Henderson .sh_size = sizeof(struct DebugInfo), 45915872bbf2SRichard Henderson }, 45925872bbf2SRichard Henderson [3] = { /* .debug_abbrev */ 45935872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 45945872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, da), 45955872bbf2SRichard Henderson .sh_size = sizeof(img->da), 45965872bbf2SRichard Henderson }, 45975872bbf2SRichard Henderson [4] = { /* .debug_frame */ 45985872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 45995872bbf2SRichard Henderson .sh_offset = sizeof(struct ElfImage), 46005872bbf2SRichard Henderson }, 46015872bbf2SRichard Henderson [5] = { /* .symtab */ 46025872bbf2SRichard Henderson .sh_type = SHT_SYMTAB, 46035872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, sym), 46045872bbf2SRichard Henderson .sh_size = sizeof(img->sym), 46055872bbf2SRichard Henderson .sh_info = 1, 46065872bbf2SRichard Henderson .sh_link = ARRAY_SIZE(img->shdr) - 1, 46075872bbf2SRichard Henderson .sh_entsize = sizeof(ElfW(Sym)), 46085872bbf2SRichard Henderson }, 46095872bbf2SRichard Henderson [6] = { /* .strtab */ 46105872bbf2SRichard Henderson .sh_type = SHT_STRTAB, 46115872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, str), 46125872bbf2SRichard Henderson .sh_size = sizeof(img->str), 46135872bbf2SRichard Henderson } 46145872bbf2SRichard Henderson }, 46155872bbf2SRichard Henderson .sym = { 46165872bbf2SRichard Henderson [1] = { /* code_gen_buffer */ 46175872bbf2SRichard Henderson .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC), 46185872bbf2SRichard Henderson .st_shndx = 1, 46195872bbf2SRichard Henderson } 46205872bbf2SRichard Henderson }, 46215872bbf2SRichard Henderson .di = { 46225872bbf2SRichard Henderson .len = sizeof(struct DebugInfo) - 4, 46235872bbf2SRichard Henderson .version = 2, 46245872bbf2SRichard Henderson .ptr_size = sizeof(void *), 46255872bbf2SRichard Henderson .cu_die = 1, 46265872bbf2SRichard Henderson .cu_lang = 0x8001, /* DW_LANG_Mips_Assembler */ 46275872bbf2SRichard Henderson .fn_die = 2, 46285872bbf2SRichard Henderson .fn_name = "code_gen_buffer" 46295872bbf2SRichard Henderson }, 46305872bbf2SRichard Henderson .da = { 46315872bbf2SRichard Henderson 1, /* abbrev number (the cu) */ 46325872bbf2SRichard Henderson 0x11, 1, /* DW_TAG_compile_unit, has children */ 46335872bbf2SRichard Henderson 0x13, 0x5, /* DW_AT_language, DW_FORM_data2 */ 46345872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */ 46355872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */ 46365872bbf2SRichard Henderson 0, 0, /* end of abbrev */ 46375872bbf2SRichard Henderson 2, /* abbrev number (the fn) */ 46385872bbf2SRichard Henderson 0x2e, 0, /* DW_TAG_subprogram, no children */ 46395872bbf2SRichard Henderson 0x3, 0x8, /* DW_AT_name, DW_FORM_string */ 46405872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */ 46415872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */ 46425872bbf2SRichard Henderson 0, 0, /* end of abbrev */ 46435872bbf2SRichard Henderson 0 /* no more abbrev */ 46445872bbf2SRichard Henderson }, 46455872bbf2SRichard Henderson .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0" 46465872bbf2SRichard Henderson ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer", 4647813da627SRichard Henderson }; 4648813da627SRichard Henderson 4649813da627SRichard Henderson /* We only need a single jit entry; statically allocate it. */ 4650813da627SRichard Henderson static struct jit_code_entry one_entry; 4651813da627SRichard Henderson 46525872bbf2SRichard Henderson uintptr_t buf = (uintptr_t)buf_ptr; 4653813da627SRichard Henderson size_t img_size = sizeof(struct ElfImage) + debug_frame_size; 46542c90784aSRichard Henderson DebugFrameHeader *dfh; 4655813da627SRichard Henderson 46565872bbf2SRichard Henderson img = g_malloc(img_size); 46575872bbf2SRichard Henderson *img = img_template; 4658813da627SRichard Henderson 46595872bbf2SRichard Henderson img->phdr.p_vaddr = buf; 46605872bbf2SRichard Henderson img->phdr.p_paddr = buf; 46615872bbf2SRichard Henderson img->phdr.p_memsz = buf_size; 4662813da627SRichard Henderson 46635872bbf2SRichard Henderson img->shdr[1].sh_name = find_string(img->str, ".text"); 46645872bbf2SRichard Henderson img->shdr[1].sh_addr = buf; 46655872bbf2SRichard Henderson img->shdr[1].sh_size = buf_size; 4666813da627SRichard Henderson 46675872bbf2SRichard Henderson img->shdr[2].sh_name = find_string(img->str, ".debug_info"); 46685872bbf2SRichard Henderson img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev"); 46695872bbf2SRichard Henderson 46705872bbf2SRichard Henderson img->shdr[4].sh_name = find_string(img->str, ".debug_frame"); 46715872bbf2SRichard Henderson img->shdr[4].sh_size = debug_frame_size; 46725872bbf2SRichard Henderson 46735872bbf2SRichard Henderson img->shdr[5].sh_name = find_string(img->str, ".symtab"); 46745872bbf2SRichard Henderson img->shdr[6].sh_name = find_string(img->str, ".strtab"); 46755872bbf2SRichard Henderson 46765872bbf2SRichard Henderson img->sym[1].st_name = find_string(img->str, "code_gen_buffer"); 46775872bbf2SRichard Henderson img->sym[1].st_value = buf; 46785872bbf2SRichard Henderson img->sym[1].st_size = buf_size; 46795872bbf2SRichard Henderson 46805872bbf2SRichard Henderson img->di.cu_low_pc = buf; 468145aba097SRichard Henderson img->di.cu_high_pc = buf + buf_size; 46825872bbf2SRichard Henderson img->di.fn_low_pc = buf; 468345aba097SRichard Henderson img->di.fn_high_pc = buf + buf_size; 4684813da627SRichard Henderson 46852c90784aSRichard Henderson dfh = (DebugFrameHeader *)(img + 1); 46862c90784aSRichard Henderson memcpy(dfh, debug_frame, debug_frame_size); 46872c90784aSRichard Henderson dfh->fde.func_start = buf; 46882c90784aSRichard Henderson dfh->fde.func_len = buf_size; 46892c90784aSRichard Henderson 4690813da627SRichard Henderson #ifdef DEBUG_JIT 4691813da627SRichard Henderson /* Enable this block to be able to debug the ELF image file creation. 4692813da627SRichard Henderson One can use readelf, objdump, or other inspection utilities. */ 4693813da627SRichard Henderson { 4694813da627SRichard Henderson FILE *f = fopen("/tmp/qemu.jit", "w+b"); 4695813da627SRichard Henderson if (f) { 46965872bbf2SRichard Henderson if (fwrite(img, img_size, 1, f) != img_size) { 4697813da627SRichard Henderson /* Avoid stupid unused return value warning for fwrite. */ 4698813da627SRichard Henderson } 4699813da627SRichard Henderson fclose(f); 4700813da627SRichard Henderson } 4701813da627SRichard Henderson } 4702813da627SRichard Henderson #endif 4703813da627SRichard Henderson 4704813da627SRichard Henderson one_entry.symfile_addr = img; 4705813da627SRichard Henderson one_entry.symfile_size = img_size; 4706813da627SRichard Henderson 4707813da627SRichard Henderson __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; 4708813da627SRichard Henderson __jit_debug_descriptor.relevant_entry = &one_entry; 4709813da627SRichard Henderson __jit_debug_descriptor.first_entry = &one_entry; 4710813da627SRichard Henderson __jit_debug_register_code(); 4711813da627SRichard Henderson } 4712813da627SRichard Henderson #else 47135872bbf2SRichard Henderson /* No support for the feature. Provide the entry point expected by exec.c, 47145872bbf2SRichard Henderson and implement the internal function we declared earlier. */ 4715813da627SRichard Henderson 4716755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size, 47172c90784aSRichard Henderson const void *debug_frame, 47182c90784aSRichard Henderson size_t debug_frame_size) 4719813da627SRichard Henderson { 4720813da627SRichard Henderson } 4721813da627SRichard Henderson 4722755bf9e5SRichard Henderson void tcg_register_jit(const void *buf, size_t buf_size) 4723813da627SRichard Henderson { 4724813da627SRichard Henderson } 4725813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */ 4726db432672SRichard Henderson 4727db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec 4728db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...) 4729db432672SRichard Henderson { 4730db432672SRichard Henderson g_assert_not_reached(); 4731db432672SRichard Henderson } 4732db432672SRichard Henderson #endif 4733