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 33f348b6d1SVeronia Bahaa #include "qemu/cutils.h" 341de7afc9SPaolo Bonzini #include "qemu/host-utils.h" 351de7afc9SPaolo Bonzini #include "qemu/timer.h" 36c896fe29Sbellard 37c5d3c498SStefan Weil /* Note: the long term plan is to reduce the dependencies on the QEMU 38c896fe29Sbellard CPU definitions. Currently they are used for qemu_ld/st 39c896fe29Sbellard instructions */ 40c896fe29Sbellard #define NO_CPU_IO_DEFS 41c896fe29Sbellard #include "cpu.h" 42c896fe29Sbellard 4363c91552SPaolo Bonzini #include "exec/cpu-common.h" 4463c91552SPaolo Bonzini #include "exec/exec-all.h" 4563c91552SPaolo Bonzini 46c896fe29Sbellard #include "tcg-op.h" 47813da627SRichard Henderson 48edee2579SRichard Henderson #if UINTPTR_MAX == UINT32_MAX 49813da627SRichard Henderson # define ELF_CLASS ELFCLASS32 50edee2579SRichard Henderson #else 51edee2579SRichard Henderson # define ELF_CLASS ELFCLASS64 52813da627SRichard Henderson #endif 53813da627SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 54813da627SRichard Henderson # define ELF_DATA ELFDATA2MSB 55813da627SRichard Henderson #else 56813da627SRichard Henderson # define ELF_DATA ELFDATA2LSB 57813da627SRichard Henderson #endif 58813da627SRichard Henderson 59c896fe29Sbellard #include "elf.h" 60508127e2SPaolo Bonzini #include "exec/log.h" 61c896fe29Sbellard 62ce151109SPeter Maydell /* Forward declarations for functions declared in tcg-target.inc.c and 63ce151109SPeter Maydell used here. */ 64e4d58b41SRichard Henderson static void tcg_target_init(TCGContext *s); 65f69d277eSRichard Henderson static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode); 66e4d58b41SRichard Henderson static void tcg_target_qemu_prologue(TCGContext *s); 671813e175SRichard Henderson static void patch_reloc(tcg_insn_unit *code_ptr, int type, 682ba7fae2SRichard Henderson intptr_t value, intptr_t addend); 69c896fe29Sbellard 70497a22ebSRichard Henderson /* The CIE and FDE header definitions will be common to all hosts. */ 71497a22ebSRichard Henderson typedef struct { 72497a22ebSRichard Henderson uint32_t len __attribute__((aligned((sizeof(void *))))); 73497a22ebSRichard Henderson uint32_t id; 74497a22ebSRichard Henderson uint8_t version; 75497a22ebSRichard Henderson char augmentation[1]; 76497a22ebSRichard Henderson uint8_t code_align; 77497a22ebSRichard Henderson uint8_t data_align; 78497a22ebSRichard Henderson uint8_t return_column; 79497a22ebSRichard Henderson } DebugFrameCIE; 80497a22ebSRichard Henderson 81497a22ebSRichard Henderson typedef struct QEMU_PACKED { 82497a22ebSRichard Henderson uint32_t len __attribute__((aligned((sizeof(void *))))); 83497a22ebSRichard Henderson uint32_t cie_offset; 84edee2579SRichard Henderson uintptr_t func_start; 85edee2579SRichard Henderson uintptr_t func_len; 86497a22ebSRichard Henderson } DebugFrameFDEHeader; 87497a22ebSRichard Henderson 882c90784aSRichard Henderson typedef struct QEMU_PACKED { 892c90784aSRichard Henderson DebugFrameCIE cie; 902c90784aSRichard Henderson DebugFrameFDEHeader fde; 912c90784aSRichard Henderson } DebugFrameHeader; 922c90784aSRichard Henderson 93813da627SRichard Henderson static void tcg_register_jit_int(void *buf, size_t size, 942c90784aSRichard Henderson const void *debug_frame, 952c90784aSRichard Henderson size_t debug_frame_size) 96813da627SRichard Henderson __attribute__((unused)); 97813da627SRichard Henderson 98ce151109SPeter Maydell /* Forward declarations for functions declared and used in tcg-target.inc.c. */ 99069ea736SRichard Henderson static const char *target_parse_constraint(TCGArgConstraint *ct, 100069ea736SRichard Henderson const char *ct_str, TCGType type); 1012a534affSRichard Henderson static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1, 102a05b5b9bSRichard Henderson intptr_t arg2); 1032a534affSRichard Henderson static void tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg); 104c0ad3001SStefan Weil static void tcg_out_movi(TCGContext *s, TCGType type, 1052a534affSRichard Henderson TCGReg ret, tcg_target_long arg); 106c0ad3001SStefan Weil static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, 107c0ad3001SStefan Weil const int *const_args); 1082a534affSRichard Henderson static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1, 109a05b5b9bSRichard Henderson intptr_t arg2); 11059d7c14eSRichard Henderson static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val, 11159d7c14eSRichard Henderson TCGReg base, intptr_t ofs); 112cf066674SRichard Henderson static void tcg_out_call(TCGContext *s, tcg_insn_unit *target); 113f6c6afc1SRichard Henderson static int tcg_target_const_match(tcg_target_long val, TCGType type, 114c0ad3001SStefan Weil const TCGArgConstraint *arg_ct); 115659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS 116659ef5cbSRichard Henderson static bool tcg_out_ldst_finalize(TCGContext *s); 117659ef5cbSRichard Henderson #endif 118c896fe29Sbellard 119b1d8e52eSblueswir1 static TCGRegSet tcg_target_available_regs[2]; 120b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs; 121c896fe29Sbellard 1221813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1 1234196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v) 124c896fe29Sbellard { 125c896fe29Sbellard *s->code_ptr++ = v; 126c896fe29Sbellard } 127c896fe29Sbellard 1284196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p, 1294196dca6SPeter Maydell uint8_t v) 1305c53bb81SPeter Maydell { 1311813e175SRichard Henderson *p = v; 1325c53bb81SPeter Maydell } 1331813e175SRichard Henderson #endif 1345c53bb81SPeter Maydell 1351813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2 1364196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v) 137c896fe29Sbellard { 1381813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 2) { 1391813e175SRichard Henderson *s->code_ptr++ = v; 1401813e175SRichard Henderson } else { 1411813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 1424387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 1431813e175SRichard Henderson s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE); 1441813e175SRichard Henderson } 145c896fe29Sbellard } 146c896fe29Sbellard 1474196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p, 1484196dca6SPeter Maydell uint16_t v) 1495c53bb81SPeter Maydell { 1501813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 2) { 1511813e175SRichard Henderson *p = v; 1521813e175SRichard Henderson } else { 1535c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 1545c53bb81SPeter Maydell } 1551813e175SRichard Henderson } 1561813e175SRichard Henderson #endif 1575c53bb81SPeter Maydell 1581813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4 1594196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v) 160c896fe29Sbellard { 1611813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 4) { 1621813e175SRichard Henderson *s->code_ptr++ = v; 1631813e175SRichard Henderson } else { 1641813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 1654387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 1661813e175SRichard Henderson s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE); 1671813e175SRichard Henderson } 168c896fe29Sbellard } 169c896fe29Sbellard 1704196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p, 1714196dca6SPeter Maydell uint32_t v) 1725c53bb81SPeter Maydell { 1731813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 4) { 1741813e175SRichard Henderson *p = v; 1751813e175SRichard Henderson } else { 1765c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 1775c53bb81SPeter Maydell } 1781813e175SRichard Henderson } 1791813e175SRichard Henderson #endif 1805c53bb81SPeter Maydell 1811813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 8 1824196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v) 183ac26eb69SRichard Henderson { 1841813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 8) { 1851813e175SRichard Henderson *s->code_ptr++ = v; 1861813e175SRichard Henderson } else { 1871813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 1884387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 1891813e175SRichard Henderson s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE); 1901813e175SRichard Henderson } 191ac26eb69SRichard Henderson } 192ac26eb69SRichard Henderson 1934196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p, 1944196dca6SPeter Maydell uint64_t v) 1955c53bb81SPeter Maydell { 1961813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 8) { 1971813e175SRichard Henderson *p = v; 1981813e175SRichard Henderson } else { 1995c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 2005c53bb81SPeter Maydell } 2011813e175SRichard Henderson } 2021813e175SRichard Henderson #endif 2035c53bb81SPeter Maydell 204c896fe29Sbellard /* label relocation processing */ 205c896fe29Sbellard 2061813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type, 207bec16311SRichard Henderson TCGLabel *l, intptr_t addend) 208c896fe29Sbellard { 209c896fe29Sbellard TCGRelocation *r; 210c896fe29Sbellard 211c896fe29Sbellard if (l->has_value) { 212623e265cSpbrook /* FIXME: This may break relocations on RISC targets that 213623e265cSpbrook modify instruction fields in place. The caller may not have 214623e265cSpbrook written the initial value. */ 215f54b3f92Saurel32 patch_reloc(code_ptr, type, l->u.value, addend); 216c896fe29Sbellard } else { 217c896fe29Sbellard /* add a new relocation entry */ 218c896fe29Sbellard r = tcg_malloc(sizeof(TCGRelocation)); 219c896fe29Sbellard r->type = type; 220c896fe29Sbellard r->ptr = code_ptr; 221c896fe29Sbellard r->addend = addend; 222c896fe29Sbellard r->next = l->u.first_reloc; 223c896fe29Sbellard l->u.first_reloc = r; 224c896fe29Sbellard } 225c896fe29Sbellard } 226c896fe29Sbellard 227bec16311SRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l, tcg_insn_unit *ptr) 228c896fe29Sbellard { 2292ba7fae2SRichard Henderson intptr_t value = (intptr_t)ptr; 2301813e175SRichard Henderson TCGRelocation *r; 231c896fe29Sbellard 232eabb7b91SAurelien Jarno tcg_debug_assert(!l->has_value); 2331813e175SRichard Henderson 2341813e175SRichard Henderson for (r = l->u.first_reloc; r != NULL; r = r->next) { 235f54b3f92Saurel32 patch_reloc(r->ptr, r->type, value, r->addend); 236c896fe29Sbellard } 2371813e175SRichard Henderson 238c896fe29Sbellard l->has_value = 1; 2391813e175SRichard Henderson l->u.value_ptr = ptr; 240c896fe29Sbellard } 241c896fe29Sbellard 24242a268c2SRichard Henderson TCGLabel *gen_new_label(void) 243c896fe29Sbellard { 244c896fe29Sbellard TCGContext *s = &tcg_ctx; 24551e3972cSRichard Henderson TCGLabel *l = tcg_malloc(sizeof(TCGLabel)); 246c896fe29Sbellard 24751e3972cSRichard Henderson *l = (TCGLabel){ 24851e3972cSRichard Henderson .id = s->nb_labels++ 24951e3972cSRichard Henderson }; 25042a268c2SRichard Henderson 25142a268c2SRichard Henderson return l; 252c896fe29Sbellard } 253c896fe29Sbellard 254ce151109SPeter Maydell #include "tcg-target.inc.c" 255c896fe29Sbellard 256c896fe29Sbellard /* pool based memory allocation */ 257c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size) 258c896fe29Sbellard { 259c896fe29Sbellard TCGPool *p; 260c896fe29Sbellard int pool_size; 261c896fe29Sbellard 262c896fe29Sbellard if (size > TCG_POOL_CHUNK_SIZE) { 263c896fe29Sbellard /* big malloc: insert a new pool (XXX: could optimize) */ 2647267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + size); 265c896fe29Sbellard p->size = size; 2664055299eSKirill Batuzov p->next = s->pool_first_large; 2674055299eSKirill Batuzov s->pool_first_large = p; 2684055299eSKirill Batuzov return p->data; 269c896fe29Sbellard } else { 270c896fe29Sbellard p = s->pool_current; 271c896fe29Sbellard if (!p) { 272c896fe29Sbellard p = s->pool_first; 273c896fe29Sbellard if (!p) 274c896fe29Sbellard goto new_pool; 275c896fe29Sbellard } else { 276c896fe29Sbellard if (!p->next) { 277c896fe29Sbellard new_pool: 278c896fe29Sbellard pool_size = TCG_POOL_CHUNK_SIZE; 2797267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + pool_size); 280c896fe29Sbellard p->size = pool_size; 281c896fe29Sbellard p->next = NULL; 282c896fe29Sbellard if (s->pool_current) 283c896fe29Sbellard s->pool_current->next = p; 284c896fe29Sbellard else 285c896fe29Sbellard s->pool_first = p; 286c896fe29Sbellard } else { 287c896fe29Sbellard p = p->next; 288c896fe29Sbellard } 289c896fe29Sbellard } 290c896fe29Sbellard } 291c896fe29Sbellard s->pool_current = p; 292c896fe29Sbellard s->pool_cur = p->data + size; 293c896fe29Sbellard s->pool_end = p->data + p->size; 294c896fe29Sbellard return p->data; 295c896fe29Sbellard } 296c896fe29Sbellard 297c896fe29Sbellard void tcg_pool_reset(TCGContext *s) 298c896fe29Sbellard { 2994055299eSKirill Batuzov TCGPool *p, *t; 3004055299eSKirill Batuzov for (p = s->pool_first_large; p; p = t) { 3014055299eSKirill Batuzov t = p->next; 3024055299eSKirill Batuzov g_free(p); 3034055299eSKirill Batuzov } 3044055299eSKirill Batuzov s->pool_first_large = NULL; 305c896fe29Sbellard s->pool_cur = s->pool_end = NULL; 306c896fe29Sbellard s->pool_current = NULL; 307c896fe29Sbellard } 308c896fe29Sbellard 309100b5e01SRichard Henderson typedef struct TCGHelperInfo { 310100b5e01SRichard Henderson void *func; 311100b5e01SRichard Henderson const char *name; 312afb49896SRichard Henderson unsigned flags; 313afb49896SRichard Henderson unsigned sizemask; 314100b5e01SRichard Henderson } TCGHelperInfo; 315100b5e01SRichard Henderson 3162ef6175aSRichard Henderson #include "exec/helper-proto.h" 3172ef6175aSRichard Henderson 318100b5e01SRichard Henderson static const TCGHelperInfo all_helpers[] = { 3192ef6175aSRichard Henderson #include "exec/helper-tcg.h" 320100b5e01SRichard Henderson }; 321100b5e01SRichard Henderson 32291478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)]; 323f69d277eSRichard Henderson static void process_op_defs(TCGContext *s); 32491478cefSRichard Henderson 325c896fe29Sbellard void tcg_context_init(TCGContext *s) 326c896fe29Sbellard { 327100b5e01SRichard Henderson int op, total_args, n, i; 328c896fe29Sbellard TCGOpDef *def; 329c896fe29Sbellard TCGArgConstraint *args_ct; 330c896fe29Sbellard int *sorted_args; 33184fd9dd3SRichard Henderson GHashTable *helper_table; 332c896fe29Sbellard 333c896fe29Sbellard memset(s, 0, sizeof(*s)); 334c896fe29Sbellard s->nb_globals = 0; 335c896fe29Sbellard 336c896fe29Sbellard /* Count total number of arguments and allocate the corresponding 337c896fe29Sbellard space */ 338c896fe29Sbellard total_args = 0; 339c896fe29Sbellard for(op = 0; op < NB_OPS; op++) { 340c896fe29Sbellard def = &tcg_op_defs[op]; 341c896fe29Sbellard n = def->nb_iargs + def->nb_oargs; 342c896fe29Sbellard total_args += n; 343c896fe29Sbellard } 344c896fe29Sbellard 3457267c094SAnthony Liguori args_ct = g_malloc(sizeof(TCGArgConstraint) * total_args); 3467267c094SAnthony Liguori sorted_args = g_malloc(sizeof(int) * total_args); 347c896fe29Sbellard 348c896fe29Sbellard for(op = 0; op < NB_OPS; op++) { 349c896fe29Sbellard def = &tcg_op_defs[op]; 350c896fe29Sbellard def->args_ct = args_ct; 351c896fe29Sbellard def->sorted_args = sorted_args; 352c896fe29Sbellard n = def->nb_iargs + def->nb_oargs; 353c896fe29Sbellard sorted_args += n; 354c896fe29Sbellard args_ct += n; 355c896fe29Sbellard } 356c896fe29Sbellard 3575cd8f621SRichard Henderson /* Register helpers. */ 35884fd9dd3SRichard Henderson /* Use g_direct_hash/equal for direct pointer comparisons on func. */ 35984fd9dd3SRichard Henderson s->helpers = helper_table = g_hash_table_new(NULL, NULL); 36084fd9dd3SRichard Henderson 361100b5e01SRichard Henderson for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) { 36284fd9dd3SRichard Henderson g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func, 36372866e82SRichard Henderson (gpointer)&all_helpers[i]); 364100b5e01SRichard Henderson } 3655cd8f621SRichard Henderson 366c896fe29Sbellard tcg_target_init(s); 367f69d277eSRichard Henderson process_op_defs(s); 36891478cefSRichard Henderson 36991478cefSRichard Henderson /* Reverse the order of the saved registers, assuming they're all at 37091478cefSRichard Henderson the start of tcg_target_reg_alloc_order. */ 37191478cefSRichard Henderson for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) { 37291478cefSRichard Henderson int r = tcg_target_reg_alloc_order[n]; 37391478cefSRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) { 37491478cefSRichard Henderson break; 37591478cefSRichard Henderson } 37691478cefSRichard Henderson } 37791478cefSRichard Henderson for (i = 0; i < n; ++i) { 37891478cefSRichard Henderson indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i]; 37991478cefSRichard Henderson } 38091478cefSRichard Henderson for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) { 38191478cefSRichard Henderson indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i]; 38291478cefSRichard Henderson } 3839002ec79SRichard Henderson } 384b03cce8eSbellard 3856e3b2bfdSEmilio G. Cota /* 3866e3b2bfdSEmilio G. Cota * Allocate TBs right before their corresponding translated code, making 3876e3b2bfdSEmilio G. Cota * sure that TBs and code are on different cache lines. 3886e3b2bfdSEmilio G. Cota */ 3896e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s) 3906e3b2bfdSEmilio G. Cota { 3916e3b2bfdSEmilio G. Cota uintptr_t align = qemu_icache_linesize; 3926e3b2bfdSEmilio G. Cota TranslationBlock *tb; 3936e3b2bfdSEmilio G. Cota void *next; 3946e3b2bfdSEmilio G. Cota 3956e3b2bfdSEmilio G. Cota tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align); 3966e3b2bfdSEmilio G. Cota next = (void *)ROUND_UP((uintptr_t)(tb + 1), align); 3976e3b2bfdSEmilio G. Cota 3986e3b2bfdSEmilio G. Cota if (unlikely(next > s->code_gen_highwater)) { 3996e3b2bfdSEmilio G. Cota return NULL; 4006e3b2bfdSEmilio G. Cota } 4016e3b2bfdSEmilio G. Cota s->code_gen_ptr = next; 402*57a26946SRichard Henderson s->data_gen_ptr = NULL; 4036e3b2bfdSEmilio G. Cota return tb; 4046e3b2bfdSEmilio G. Cota } 4056e3b2bfdSEmilio G. Cota 4069002ec79SRichard Henderson void tcg_prologue_init(TCGContext *s) 4079002ec79SRichard Henderson { 4088163b749SRichard Henderson size_t prologue_size, total_size; 4098163b749SRichard Henderson void *buf0, *buf1; 4108163b749SRichard Henderson 4118163b749SRichard Henderson /* Put the prologue at the beginning of code_gen_buffer. */ 4128163b749SRichard Henderson buf0 = s->code_gen_buffer; 4138163b749SRichard Henderson s->code_ptr = buf0; 4148163b749SRichard Henderson s->code_buf = buf0; 4158163b749SRichard Henderson s->code_gen_prologue = buf0; 4168163b749SRichard Henderson 4178163b749SRichard Henderson /* Generate the prologue. */ 418b03cce8eSbellard tcg_target_qemu_prologue(s); 4198163b749SRichard Henderson buf1 = s->code_ptr; 4208163b749SRichard Henderson flush_icache_range((uintptr_t)buf0, (uintptr_t)buf1); 4218163b749SRichard Henderson 4228163b749SRichard Henderson /* Deduct the prologue from the buffer. */ 4238163b749SRichard Henderson prologue_size = tcg_current_code_size(s); 4248163b749SRichard Henderson s->code_gen_ptr = buf1; 4258163b749SRichard Henderson s->code_gen_buffer = buf1; 4268163b749SRichard Henderson s->code_buf = buf1; 4278163b749SRichard Henderson total_size = s->code_gen_buffer_size - prologue_size; 4288163b749SRichard Henderson s->code_gen_buffer_size = total_size; 4298163b749SRichard Henderson 430b125f9dcSRichard Henderson /* Compute a high-water mark, at which we voluntarily flush the buffer 431b125f9dcSRichard Henderson and start over. The size here is arbitrary, significantly larger 432b125f9dcSRichard Henderson than we expect the code generation for any one opcode to require. */ 43323dceda6SRichard Henderson s->code_gen_highwater = s->code_gen_buffer + (total_size - 1024); 4348163b749SRichard Henderson 4358163b749SRichard Henderson tcg_register_jit(s->code_gen_buffer, total_size); 436d6b64b2bSRichard Henderson 437d6b64b2bSRichard Henderson #ifdef DEBUG_DISAS 438d6b64b2bSRichard Henderson if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) { 4391ee73216SRichard Henderson qemu_log_lock(); 4408163b749SRichard Henderson qemu_log("PROLOGUE: [size=%zu]\n", prologue_size); 4418163b749SRichard Henderson log_disas(buf0, prologue_size); 442d6b64b2bSRichard Henderson qemu_log("\n"); 443d6b64b2bSRichard Henderson qemu_log_flush(); 4441ee73216SRichard Henderson qemu_log_unlock(); 445d6b64b2bSRichard Henderson } 446d6b64b2bSRichard Henderson #endif 447cedbcb01SEmilio G. Cota 448cedbcb01SEmilio G. Cota /* Assert that goto_ptr is implemented completely. */ 449cedbcb01SEmilio G. Cota if (TCG_TARGET_HAS_goto_ptr) { 450cedbcb01SEmilio G. Cota tcg_debug_assert(s->code_gen_epilogue != NULL); 451cedbcb01SEmilio G. Cota } 452c896fe29Sbellard } 453c896fe29Sbellard 454c896fe29Sbellard void tcg_func_start(TCGContext *s) 455c896fe29Sbellard { 456c896fe29Sbellard tcg_pool_reset(s); 457c896fe29Sbellard s->nb_temps = s->nb_globals; 4580ec9eabcSRichard Henderson 4590ec9eabcSRichard Henderson /* No temps have been previously allocated for size or locality. */ 4600ec9eabcSRichard Henderson memset(s->free_temps, 0, sizeof(s->free_temps)); 4610ec9eabcSRichard Henderson 462c896fe29Sbellard s->nb_labels = 0; 463c896fe29Sbellard s->current_frame_offset = s->frame_start; 464c896fe29Sbellard 4650a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG 4660a209d4bSRichard Henderson s->goto_tb_issue_mask = 0; 4670a209d4bSRichard Henderson #endif 4680a209d4bSRichard Henderson 469dcb8e758SRichard Henderson s->gen_op_buf[0].next = 1; 470dcb8e758SRichard Henderson s->gen_op_buf[0].prev = 0; 471dcb8e758SRichard Henderson s->gen_next_op_idx = 1; 472c45cb8bbSRichard Henderson s->gen_next_parm_idx = 0; 473c896fe29Sbellard } 474c896fe29Sbellard 4757ca4b752SRichard Henderson static inline int temp_idx(TCGContext *s, TCGTemp *ts) 476c896fe29Sbellard { 4777ca4b752SRichard Henderson ptrdiff_t n = ts - s->temps; 4787ca4b752SRichard Henderson tcg_debug_assert(n >= 0 && n < s->nb_temps); 4797ca4b752SRichard Henderson return n; 4807ca4b752SRichard Henderson } 4817ca4b752SRichard Henderson 4827ca4b752SRichard Henderson static inline TCGTemp *tcg_temp_alloc(TCGContext *s) 4837ca4b752SRichard Henderson { 4847ca4b752SRichard Henderson int n = s->nb_temps++; 4857ca4b752SRichard Henderson tcg_debug_assert(n < TCG_MAX_TEMPS); 4867ca4b752SRichard Henderson return memset(&s->temps[n], 0, sizeof(TCGTemp)); 4877ca4b752SRichard Henderson } 4887ca4b752SRichard Henderson 4897ca4b752SRichard Henderson static inline TCGTemp *tcg_global_alloc(TCGContext *s) 4907ca4b752SRichard Henderson { 4917ca4b752SRichard Henderson tcg_debug_assert(s->nb_globals == s->nb_temps); 4927ca4b752SRichard Henderson s->nb_globals++; 4937ca4b752SRichard Henderson return tcg_temp_alloc(s); 494c896fe29Sbellard } 495c896fe29Sbellard 496b3a62939SRichard Henderson static int tcg_global_reg_new_internal(TCGContext *s, TCGType type, 497b6638662SRichard Henderson TCGReg reg, const char *name) 498c896fe29Sbellard { 499c896fe29Sbellard TCGTemp *ts; 500c896fe29Sbellard 501b3a62939SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type != TCG_TYPE_I32) { 502c896fe29Sbellard tcg_abort(); 503b3a62939SRichard Henderson } 5047ca4b752SRichard Henderson 5057ca4b752SRichard Henderson ts = tcg_global_alloc(s); 506c896fe29Sbellard ts->base_type = type; 507c896fe29Sbellard ts->type = type; 508c896fe29Sbellard ts->fixed_reg = 1; 509c896fe29Sbellard ts->reg = reg; 510c896fe29Sbellard ts->name = name; 511c896fe29Sbellard tcg_regset_set_reg(s->reserved_regs, reg); 5127ca4b752SRichard Henderson 5137ca4b752SRichard Henderson return temp_idx(s, ts); 514a7812ae4Spbrook } 515a7812ae4Spbrook 516b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size) 517a7812ae4Spbrook { 518a7812ae4Spbrook int idx; 519b3a62939SRichard Henderson s->frame_start = start; 520b3a62939SRichard Henderson s->frame_end = start + size; 521b3a62939SRichard Henderson idx = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame"); 522b3a62939SRichard Henderson s->frame_temp = &s->temps[idx]; 523b3a62939SRichard Henderson } 524a7812ae4Spbrook 525b6638662SRichard Henderson TCGv_i32 tcg_global_reg_new_i32(TCGReg reg, const char *name) 526b3a62939SRichard Henderson { 527b3a62939SRichard Henderson TCGContext *s = &tcg_ctx; 528b3a62939SRichard Henderson int idx; 529b3a62939SRichard Henderson 530b3a62939SRichard Henderson if (tcg_regset_test_reg(s->reserved_regs, reg)) { 531b3a62939SRichard Henderson tcg_abort(); 532b3a62939SRichard Henderson } 533b3a62939SRichard Henderson idx = tcg_global_reg_new_internal(s, TCG_TYPE_I32, reg, name); 534a7812ae4Spbrook return MAKE_TCGV_I32(idx); 535a7812ae4Spbrook } 536a7812ae4Spbrook 537b6638662SRichard Henderson TCGv_i64 tcg_global_reg_new_i64(TCGReg reg, const char *name) 538a7812ae4Spbrook { 539b3a62939SRichard Henderson TCGContext *s = &tcg_ctx; 540a7812ae4Spbrook int idx; 541a7812ae4Spbrook 542b3a62939SRichard Henderson if (tcg_regset_test_reg(s->reserved_regs, reg)) { 543b3a62939SRichard Henderson tcg_abort(); 544b3a62939SRichard Henderson } 545b3a62939SRichard Henderson idx = tcg_global_reg_new_internal(s, TCG_TYPE_I64, reg, name); 546a7812ae4Spbrook return MAKE_TCGV_I64(idx); 547c896fe29Sbellard } 548c896fe29Sbellard 549e1ccc054SRichard Henderson int tcg_global_mem_new_internal(TCGType type, TCGv_ptr base, 550e1ccc054SRichard Henderson intptr_t offset, const char *name) 551c896fe29Sbellard { 552c896fe29Sbellard TCGContext *s = &tcg_ctx; 5537ca4b752SRichard Henderson TCGTemp *base_ts = &s->temps[GET_TCGV_PTR(base)]; 5547ca4b752SRichard Henderson TCGTemp *ts = tcg_global_alloc(s); 555b3915dbbSRichard Henderson int indirect_reg = 0, bigendian = 0; 5567ca4b752SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 5577ca4b752SRichard Henderson bigendian = 1; 5587ca4b752SRichard Henderson #endif 559c896fe29Sbellard 560b3915dbbSRichard Henderson if (!base_ts->fixed_reg) { 5615a18407fSRichard Henderson /* We do not support double-indirect registers. */ 5625a18407fSRichard Henderson tcg_debug_assert(!base_ts->indirect_reg); 563b3915dbbSRichard Henderson base_ts->indirect_base = 1; 5645a18407fSRichard Henderson s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64 5655a18407fSRichard Henderson ? 2 : 1); 5665a18407fSRichard Henderson indirect_reg = 1; 567b3915dbbSRichard Henderson } 568b3915dbbSRichard Henderson 5697ca4b752SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { 5707ca4b752SRichard Henderson TCGTemp *ts2 = tcg_global_alloc(s); 571c896fe29Sbellard char buf[64]; 5727ca4b752SRichard Henderson 5737ca4b752SRichard Henderson ts->base_type = TCG_TYPE_I64; 574c896fe29Sbellard ts->type = TCG_TYPE_I32; 575b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg; 576c896fe29Sbellard ts->mem_allocated = 1; 577b3a62939SRichard Henderson ts->mem_base = base_ts; 5787ca4b752SRichard Henderson ts->mem_offset = offset + bigendian * 4; 579c896fe29Sbellard pstrcpy(buf, sizeof(buf), name); 580c896fe29Sbellard pstrcat(buf, sizeof(buf), "_0"); 581c896fe29Sbellard ts->name = strdup(buf); 582c896fe29Sbellard 5837ca4b752SRichard Henderson tcg_debug_assert(ts2 == ts + 1); 5847ca4b752SRichard Henderson ts2->base_type = TCG_TYPE_I64; 5857ca4b752SRichard Henderson ts2->type = TCG_TYPE_I32; 586b3915dbbSRichard Henderson ts2->indirect_reg = indirect_reg; 5877ca4b752SRichard Henderson ts2->mem_allocated = 1; 5887ca4b752SRichard Henderson ts2->mem_base = base_ts; 5897ca4b752SRichard Henderson ts2->mem_offset = offset + (1 - bigendian) * 4; 590c896fe29Sbellard pstrcpy(buf, sizeof(buf), name); 591c896fe29Sbellard pstrcat(buf, sizeof(buf), "_1"); 592120c1084SRichard Henderson ts2->name = strdup(buf); 5937ca4b752SRichard Henderson } else { 594c896fe29Sbellard ts->base_type = type; 595c896fe29Sbellard ts->type = type; 596b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg; 597c896fe29Sbellard ts->mem_allocated = 1; 598b3a62939SRichard Henderson ts->mem_base = base_ts; 599c896fe29Sbellard ts->mem_offset = offset; 600c896fe29Sbellard ts->name = name; 601c896fe29Sbellard } 6027ca4b752SRichard Henderson return temp_idx(s, ts); 603c896fe29Sbellard } 604c896fe29Sbellard 6057ca4b752SRichard Henderson static int tcg_temp_new_internal(TCGType type, int temp_local) 606c896fe29Sbellard { 607c896fe29Sbellard TCGContext *s = &tcg_ctx; 608c896fe29Sbellard TCGTemp *ts; 609641d5fbeSbellard int idx, k; 610c896fe29Sbellard 6110ec9eabcSRichard Henderson k = type + (temp_local ? TCG_TYPE_COUNT : 0); 6120ec9eabcSRichard Henderson idx = find_first_bit(s->free_temps[k].l, TCG_MAX_TEMPS); 6130ec9eabcSRichard Henderson if (idx < TCG_MAX_TEMPS) { 6140ec9eabcSRichard Henderson /* There is already an available temp with the right type. */ 6150ec9eabcSRichard Henderson clear_bit(idx, s->free_temps[k].l); 6160ec9eabcSRichard Henderson 617e8996ee0Sbellard ts = &s->temps[idx]; 618e8996ee0Sbellard ts->temp_allocated = 1; 6197ca4b752SRichard Henderson tcg_debug_assert(ts->base_type == type); 6207ca4b752SRichard Henderson tcg_debug_assert(ts->temp_local == temp_local); 621e8996ee0Sbellard } else { 6227ca4b752SRichard Henderson ts = tcg_temp_alloc(s); 6237ca4b752SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { 6247ca4b752SRichard Henderson TCGTemp *ts2 = tcg_temp_alloc(s); 6257ca4b752SRichard Henderson 626c896fe29Sbellard ts->base_type = type; 627c896fe29Sbellard ts->type = TCG_TYPE_I32; 628e8996ee0Sbellard ts->temp_allocated = 1; 629641d5fbeSbellard ts->temp_local = temp_local; 6307ca4b752SRichard Henderson 6317ca4b752SRichard Henderson tcg_debug_assert(ts2 == ts + 1); 6327ca4b752SRichard Henderson ts2->base_type = TCG_TYPE_I64; 6337ca4b752SRichard Henderson ts2->type = TCG_TYPE_I32; 6347ca4b752SRichard Henderson ts2->temp_allocated = 1; 6357ca4b752SRichard Henderson ts2->temp_local = temp_local; 6367ca4b752SRichard Henderson } else { 637c896fe29Sbellard ts->base_type = type; 638c896fe29Sbellard ts->type = type; 639e8996ee0Sbellard ts->temp_allocated = 1; 640641d5fbeSbellard ts->temp_local = temp_local; 641c896fe29Sbellard } 6427ca4b752SRichard Henderson idx = temp_idx(s, ts); 643e8996ee0Sbellard } 64427bfd83cSPeter Maydell 64527bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG) 64627bfd83cSPeter Maydell s->temps_in_use++; 64727bfd83cSPeter Maydell #endif 648a7812ae4Spbrook return idx; 649c896fe29Sbellard } 650c896fe29Sbellard 651a7812ae4Spbrook TCGv_i32 tcg_temp_new_internal_i32(int temp_local) 652a7812ae4Spbrook { 653a7812ae4Spbrook int idx; 654a7812ae4Spbrook 655a7812ae4Spbrook idx = tcg_temp_new_internal(TCG_TYPE_I32, temp_local); 656a7812ae4Spbrook return MAKE_TCGV_I32(idx); 657a7812ae4Spbrook } 658a7812ae4Spbrook 659a7812ae4Spbrook TCGv_i64 tcg_temp_new_internal_i64(int temp_local) 660a7812ae4Spbrook { 661a7812ae4Spbrook int idx; 662a7812ae4Spbrook 663a7812ae4Spbrook idx = tcg_temp_new_internal(TCG_TYPE_I64, temp_local); 664a7812ae4Spbrook return MAKE_TCGV_I64(idx); 665a7812ae4Spbrook } 666a7812ae4Spbrook 6670ec9eabcSRichard Henderson static void tcg_temp_free_internal(int idx) 668c896fe29Sbellard { 669c896fe29Sbellard TCGContext *s = &tcg_ctx; 670c896fe29Sbellard TCGTemp *ts; 671641d5fbeSbellard int k; 672c896fe29Sbellard 67327bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG) 67427bfd83cSPeter Maydell s->temps_in_use--; 67527bfd83cSPeter Maydell if (s->temps_in_use < 0) { 67627bfd83cSPeter Maydell fprintf(stderr, "More temporaries freed than allocated!\n"); 67727bfd83cSPeter Maydell } 67827bfd83cSPeter Maydell #endif 67927bfd83cSPeter Maydell 680eabb7b91SAurelien Jarno tcg_debug_assert(idx >= s->nb_globals && idx < s->nb_temps); 681c896fe29Sbellard ts = &s->temps[idx]; 682eabb7b91SAurelien Jarno tcg_debug_assert(ts->temp_allocated != 0); 683e8996ee0Sbellard ts->temp_allocated = 0; 6840ec9eabcSRichard Henderson 68518d13fa2SAlexander Graf k = ts->base_type + (ts->temp_local ? TCG_TYPE_COUNT : 0); 6860ec9eabcSRichard Henderson set_bit(idx, s->free_temps[k].l); 687e8996ee0Sbellard } 688e8996ee0Sbellard 689a7812ae4Spbrook void tcg_temp_free_i32(TCGv_i32 arg) 690e8996ee0Sbellard { 691a7812ae4Spbrook tcg_temp_free_internal(GET_TCGV_I32(arg)); 692a7812ae4Spbrook } 693a7812ae4Spbrook 694a7812ae4Spbrook void tcg_temp_free_i64(TCGv_i64 arg) 695a7812ae4Spbrook { 696a7812ae4Spbrook tcg_temp_free_internal(GET_TCGV_I64(arg)); 697a7812ae4Spbrook } 698a7812ae4Spbrook 699a7812ae4Spbrook TCGv_i32 tcg_const_i32(int32_t val) 700a7812ae4Spbrook { 701a7812ae4Spbrook TCGv_i32 t0; 702a7812ae4Spbrook t0 = tcg_temp_new_i32(); 703e8996ee0Sbellard tcg_gen_movi_i32(t0, val); 704e8996ee0Sbellard return t0; 705c896fe29Sbellard } 706c896fe29Sbellard 707a7812ae4Spbrook TCGv_i64 tcg_const_i64(int64_t val) 708c896fe29Sbellard { 709a7812ae4Spbrook TCGv_i64 t0; 710a7812ae4Spbrook t0 = tcg_temp_new_i64(); 711e8996ee0Sbellard tcg_gen_movi_i64(t0, val); 712e8996ee0Sbellard return t0; 713c896fe29Sbellard } 714c896fe29Sbellard 715a7812ae4Spbrook TCGv_i32 tcg_const_local_i32(int32_t val) 716bdffd4a9Saurel32 { 717a7812ae4Spbrook TCGv_i32 t0; 718a7812ae4Spbrook t0 = tcg_temp_local_new_i32(); 719bdffd4a9Saurel32 tcg_gen_movi_i32(t0, val); 720bdffd4a9Saurel32 return t0; 721bdffd4a9Saurel32 } 722bdffd4a9Saurel32 723a7812ae4Spbrook TCGv_i64 tcg_const_local_i64(int64_t val) 724bdffd4a9Saurel32 { 725a7812ae4Spbrook TCGv_i64 t0; 726a7812ae4Spbrook t0 = tcg_temp_local_new_i64(); 727bdffd4a9Saurel32 tcg_gen_movi_i64(t0, val); 728bdffd4a9Saurel32 return t0; 729bdffd4a9Saurel32 } 730bdffd4a9Saurel32 73127bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG) 73227bfd83cSPeter Maydell void tcg_clear_temp_count(void) 73327bfd83cSPeter Maydell { 73427bfd83cSPeter Maydell TCGContext *s = &tcg_ctx; 73527bfd83cSPeter Maydell s->temps_in_use = 0; 73627bfd83cSPeter Maydell } 73727bfd83cSPeter Maydell 73827bfd83cSPeter Maydell int tcg_check_temp_count(void) 73927bfd83cSPeter Maydell { 74027bfd83cSPeter Maydell TCGContext *s = &tcg_ctx; 74127bfd83cSPeter Maydell if (s->temps_in_use) { 74227bfd83cSPeter Maydell /* Clear the count so that we don't give another 74327bfd83cSPeter Maydell * warning immediately next time around. 74427bfd83cSPeter Maydell */ 74527bfd83cSPeter Maydell s->temps_in_use = 0; 74627bfd83cSPeter Maydell return 1; 74727bfd83cSPeter Maydell } 74827bfd83cSPeter Maydell return 0; 74927bfd83cSPeter Maydell } 75027bfd83cSPeter Maydell #endif 75127bfd83cSPeter Maydell 75239cf05d3Sbellard /* Note: we convert the 64 bit args to 32 bit and do some alignment 75339cf05d3Sbellard and endian swap. Maybe it would be better to do the alignment 75439cf05d3Sbellard and endian swap in tcg_reg_alloc_call(). */ 755bbb8a1b4SRichard Henderson void tcg_gen_callN(TCGContext *s, void *func, TCGArg ret, 756bbb8a1b4SRichard Henderson int nargs, TCGArg *args) 757c896fe29Sbellard { 758c45cb8bbSRichard Henderson int i, real_args, nb_rets, pi, pi_first; 759bbb8a1b4SRichard Henderson unsigned sizemask, flags; 760afb49896SRichard Henderson TCGHelperInfo *info; 761afb49896SRichard Henderson 762afb49896SRichard Henderson info = g_hash_table_lookup(s->helpers, (gpointer)func); 763bbb8a1b4SRichard Henderson flags = info->flags; 764bbb8a1b4SRichard Henderson sizemask = info->sizemask; 7652bece2c8SRichard Henderson 76634b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \ 76734b1a49cSRichard Henderson && !defined(CONFIG_TCG_INTERPRETER) 76834b1a49cSRichard Henderson /* We have 64-bit values in one register, but need to pass as two 76934b1a49cSRichard Henderson separate parameters. Split them. */ 77034b1a49cSRichard Henderson int orig_sizemask = sizemask; 77134b1a49cSRichard Henderson int orig_nargs = nargs; 77234b1a49cSRichard Henderson TCGv_i64 retl, reth; 77334b1a49cSRichard Henderson 77434b1a49cSRichard Henderson TCGV_UNUSED_I64(retl); 77534b1a49cSRichard Henderson TCGV_UNUSED_I64(reth); 77634b1a49cSRichard Henderson if (sizemask != 0) { 77734b1a49cSRichard Henderson TCGArg *split_args = __builtin_alloca(sizeof(TCGArg) * nargs * 2); 77834b1a49cSRichard Henderson for (i = real_args = 0; i < nargs; ++i) { 77934b1a49cSRichard Henderson int is_64bit = sizemask & (1 << (i+1)*2); 78034b1a49cSRichard Henderson if (is_64bit) { 78134b1a49cSRichard Henderson TCGv_i64 orig = MAKE_TCGV_I64(args[i]); 78234b1a49cSRichard Henderson TCGv_i32 h = tcg_temp_new_i32(); 78334b1a49cSRichard Henderson TCGv_i32 l = tcg_temp_new_i32(); 78434b1a49cSRichard Henderson tcg_gen_extr_i64_i32(l, h, orig); 78534b1a49cSRichard Henderson split_args[real_args++] = GET_TCGV_I32(h); 78634b1a49cSRichard Henderson split_args[real_args++] = GET_TCGV_I32(l); 78734b1a49cSRichard Henderson } else { 78834b1a49cSRichard Henderson split_args[real_args++] = args[i]; 78934b1a49cSRichard Henderson } 79034b1a49cSRichard Henderson } 79134b1a49cSRichard Henderson nargs = real_args; 79234b1a49cSRichard Henderson args = split_args; 79334b1a49cSRichard Henderson sizemask = 0; 79434b1a49cSRichard Henderson } 79534b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64 7962bece2c8SRichard Henderson for (i = 0; i < nargs; ++i) { 7972bece2c8SRichard Henderson int is_64bit = sizemask & (1 << (i+1)*2); 7982bece2c8SRichard Henderson int is_signed = sizemask & (2 << (i+1)*2); 7992bece2c8SRichard Henderson if (!is_64bit) { 8002bece2c8SRichard Henderson TCGv_i64 temp = tcg_temp_new_i64(); 8012bece2c8SRichard Henderson TCGv_i64 orig = MAKE_TCGV_I64(args[i]); 8022bece2c8SRichard Henderson if (is_signed) { 8032bece2c8SRichard Henderson tcg_gen_ext32s_i64(temp, orig); 8042bece2c8SRichard Henderson } else { 8052bece2c8SRichard Henderson tcg_gen_ext32u_i64(temp, orig); 8062bece2c8SRichard Henderson } 8072bece2c8SRichard Henderson args[i] = GET_TCGV_I64(temp); 8082bece2c8SRichard Henderson } 8092bece2c8SRichard Henderson } 8102bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */ 8112bece2c8SRichard Henderson 812c45cb8bbSRichard Henderson pi_first = pi = s->gen_next_parm_idx; 813a7812ae4Spbrook if (ret != TCG_CALL_DUMMY_ARG) { 81434b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \ 81534b1a49cSRichard Henderson && !defined(CONFIG_TCG_INTERPRETER) 81634b1a49cSRichard Henderson if (orig_sizemask & 1) { 81734b1a49cSRichard Henderson /* The 32-bit ABI is going to return the 64-bit value in 81834b1a49cSRichard Henderson the %o0/%o1 register pair. Prepare for this by using 81934b1a49cSRichard Henderson two return temporaries, and reassemble below. */ 82034b1a49cSRichard Henderson retl = tcg_temp_new_i64(); 82134b1a49cSRichard Henderson reth = tcg_temp_new_i64(); 822c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = GET_TCGV_I64(reth); 823c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = GET_TCGV_I64(retl); 82434b1a49cSRichard Henderson nb_rets = 2; 82534b1a49cSRichard Henderson } else { 826c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = ret; 82734b1a49cSRichard Henderson nb_rets = 1; 82834b1a49cSRichard Henderson } 82934b1a49cSRichard Henderson #else 83034b1a49cSRichard Henderson if (TCG_TARGET_REG_BITS < 64 && (sizemask & 1)) { 83102eb19d0SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 832c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = ret + 1; 833c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = ret; 834a7812ae4Spbrook #else 835c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = ret; 836c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = ret + 1; 837a7812ae4Spbrook #endif 838a7812ae4Spbrook nb_rets = 2; 83934b1a49cSRichard Henderson } else { 840c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = ret; 841a7812ae4Spbrook nb_rets = 1; 842a7812ae4Spbrook } 84334b1a49cSRichard Henderson #endif 844a7812ae4Spbrook } else { 845a7812ae4Spbrook nb_rets = 0; 846a7812ae4Spbrook } 847a7812ae4Spbrook real_args = 0; 848a7812ae4Spbrook for (i = 0; i < nargs; i++) { 8492bece2c8SRichard Henderson int is_64bit = sizemask & (1 << (i+1)*2); 850bbb8a1b4SRichard Henderson if (TCG_TARGET_REG_BITS < 64 && is_64bit) { 85139cf05d3Sbellard #ifdef TCG_TARGET_CALL_ALIGN_ARGS 85239cf05d3Sbellard /* some targets want aligned 64 bit args */ 853ebd486d5Smalc if (real_args & 1) { 854c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = TCG_CALL_DUMMY_ARG; 855ebd486d5Smalc real_args++; 85639cf05d3Sbellard } 85739cf05d3Sbellard #endif 8583f90f252SRichard Henderson /* If stack grows up, then we will be placing successive 8593f90f252SRichard Henderson arguments at lower addresses, which means we need to 8603f90f252SRichard Henderson reverse the order compared to how we would normally 8613f90f252SRichard Henderson treat either big or little-endian. For those arguments 8623f90f252SRichard Henderson that will wind up in registers, this still works for 8633f90f252SRichard Henderson HPPA (the only current STACK_GROWSUP target) since the 8643f90f252SRichard Henderson argument registers are *also* allocated in decreasing 8653f90f252SRichard Henderson order. If another such target is added, this logic may 8663f90f252SRichard Henderson have to get more complicated to differentiate between 8673f90f252SRichard Henderson stack arguments and register arguments. */ 86802eb19d0SRichard Henderson #if defined(HOST_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP) 869c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = args[i] + 1; 870c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = args[i]; 871c896fe29Sbellard #else 872c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = args[i]; 873c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = args[i] + 1; 874c896fe29Sbellard #endif 875a7812ae4Spbrook real_args += 2; 8762bece2c8SRichard Henderson continue; 8772bece2c8SRichard Henderson } 8782bece2c8SRichard Henderson 879c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = args[i]; 880a7812ae4Spbrook real_args++; 881c896fe29Sbellard } 882c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = (uintptr_t)func; 883c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = flags; 884a7812ae4Spbrook 885c45cb8bbSRichard Henderson i = s->gen_next_op_idx; 886c45cb8bbSRichard Henderson tcg_debug_assert(i < OPC_BUF_SIZE); 887c45cb8bbSRichard Henderson tcg_debug_assert(pi <= OPPARAM_BUF_SIZE); 888a7812ae4Spbrook 889c45cb8bbSRichard Henderson /* Set links for sequential allocation during translation. */ 890c45cb8bbSRichard Henderson s->gen_op_buf[i] = (TCGOp){ 891c45cb8bbSRichard Henderson .opc = INDEX_op_call, 892c45cb8bbSRichard Henderson .callo = nb_rets, 893c45cb8bbSRichard Henderson .calli = real_args, 894c45cb8bbSRichard Henderson .args = pi_first, 895c45cb8bbSRichard Henderson .prev = i - 1, 896c45cb8bbSRichard Henderson .next = i + 1 897c45cb8bbSRichard Henderson }; 898c45cb8bbSRichard Henderson 899c45cb8bbSRichard Henderson /* Make sure the calli field didn't overflow. */ 900c45cb8bbSRichard Henderson tcg_debug_assert(s->gen_op_buf[i].calli == real_args); 901c45cb8bbSRichard Henderson 902dcb8e758SRichard Henderson s->gen_op_buf[0].prev = i; 903c45cb8bbSRichard Henderson s->gen_next_op_idx = i + 1; 904c45cb8bbSRichard Henderson s->gen_next_parm_idx = pi; 9052bece2c8SRichard Henderson 90634b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \ 90734b1a49cSRichard Henderson && !defined(CONFIG_TCG_INTERPRETER) 90834b1a49cSRichard Henderson /* Free all of the parts we allocated above. */ 90934b1a49cSRichard Henderson for (i = real_args = 0; i < orig_nargs; ++i) { 91034b1a49cSRichard Henderson int is_64bit = orig_sizemask & (1 << (i+1)*2); 91134b1a49cSRichard Henderson if (is_64bit) { 91234b1a49cSRichard Henderson TCGv_i32 h = MAKE_TCGV_I32(args[real_args++]); 91334b1a49cSRichard Henderson TCGv_i32 l = MAKE_TCGV_I32(args[real_args++]); 91434b1a49cSRichard Henderson tcg_temp_free_i32(h); 91534b1a49cSRichard Henderson tcg_temp_free_i32(l); 91634b1a49cSRichard Henderson } else { 91734b1a49cSRichard Henderson real_args++; 91834b1a49cSRichard Henderson } 91934b1a49cSRichard Henderson } 92034b1a49cSRichard Henderson if (orig_sizemask & 1) { 92134b1a49cSRichard Henderson /* The 32-bit ABI returned two 32-bit pieces. Re-assemble them. 92234b1a49cSRichard Henderson Note that describing these as TCGv_i64 eliminates an unnecessary 92334b1a49cSRichard Henderson zero-extension that tcg_gen_concat_i32_i64 would create. */ 92434b1a49cSRichard Henderson tcg_gen_concat32_i64(MAKE_TCGV_I64(ret), retl, reth); 92534b1a49cSRichard Henderson tcg_temp_free_i64(retl); 92634b1a49cSRichard Henderson tcg_temp_free_i64(reth); 92734b1a49cSRichard Henderson } 92834b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64 9292bece2c8SRichard Henderson for (i = 0; i < nargs; ++i) { 9302bece2c8SRichard Henderson int is_64bit = sizemask & (1 << (i+1)*2); 9312bece2c8SRichard Henderson if (!is_64bit) { 9322bece2c8SRichard Henderson TCGv_i64 temp = MAKE_TCGV_I64(args[i]); 9332bece2c8SRichard Henderson tcg_temp_free_i64(temp); 9342bece2c8SRichard Henderson } 9352bece2c8SRichard Henderson } 9362bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */ 937a7812ae4Spbrook } 938c896fe29Sbellard 9398fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s) 940c896fe29Sbellard { 941c896fe29Sbellard int i; 942c896fe29Sbellard TCGTemp *ts; 943c896fe29Sbellard for(i = 0; i < s->nb_globals; i++) { 944c896fe29Sbellard ts = &s->temps[i]; 945c896fe29Sbellard if (ts->fixed_reg) { 946c896fe29Sbellard ts->val_type = TEMP_VAL_REG; 947c896fe29Sbellard } else { 948c896fe29Sbellard ts->val_type = TEMP_VAL_MEM; 949c896fe29Sbellard } 950c896fe29Sbellard } 951e8996ee0Sbellard for(i = s->nb_globals; i < s->nb_temps; i++) { 952e8996ee0Sbellard ts = &s->temps[i]; 9537dfd8c6aSAurelien Jarno if (ts->temp_local) { 9547dfd8c6aSAurelien Jarno ts->val_type = TEMP_VAL_MEM; 9557dfd8c6aSAurelien Jarno } else { 956e8996ee0Sbellard ts->val_type = TEMP_VAL_DEAD; 9577dfd8c6aSAurelien Jarno } 958e8996ee0Sbellard ts->mem_allocated = 0; 959e8996ee0Sbellard ts->fixed_reg = 0; 960e8996ee0Sbellard } 961f8b2f202SRichard Henderson 962f8b2f202SRichard Henderson memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp)); 963c896fe29Sbellard } 964c896fe29Sbellard 965f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size, 966f8b2f202SRichard Henderson TCGTemp *ts) 967c896fe29Sbellard { 968f8b2f202SRichard Henderson int idx = temp_idx(s, ts); 969ac56dd48Spbrook 970ac56dd48Spbrook if (idx < s->nb_globals) { 971ac56dd48Spbrook pstrcpy(buf, buf_size, ts->name); 972f8b2f202SRichard Henderson } else if (ts->temp_local) { 973641d5fbeSbellard snprintf(buf, buf_size, "loc%d", idx - s->nb_globals); 974f8b2f202SRichard Henderson } else { 975ac56dd48Spbrook snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals); 976c896fe29Sbellard } 977c896fe29Sbellard return buf; 978c896fe29Sbellard } 979c896fe29Sbellard 980f8b2f202SRichard Henderson static char *tcg_get_arg_str_idx(TCGContext *s, char *buf, 981f8b2f202SRichard Henderson int buf_size, int idx) 982f8b2f202SRichard Henderson { 983eabb7b91SAurelien Jarno tcg_debug_assert(idx >= 0 && idx < s->nb_temps); 984f8b2f202SRichard Henderson return tcg_get_arg_str_ptr(s, buf, buf_size, &s->temps[idx]); 985f8b2f202SRichard Henderson } 986f8b2f202SRichard Henderson 9876e085f72SRichard Henderson /* Find helper name. */ 9886e085f72SRichard Henderson static inline const char *tcg_find_helper(TCGContext *s, uintptr_t val) 989e8996ee0Sbellard { 9906e085f72SRichard Henderson const char *ret = NULL; 9916e085f72SRichard Henderson if (s->helpers) { 99272866e82SRichard Henderson TCGHelperInfo *info = g_hash_table_lookup(s->helpers, (gpointer)val); 99372866e82SRichard Henderson if (info) { 99472866e82SRichard Henderson ret = info->name; 99572866e82SRichard Henderson } 996e8996ee0Sbellard } 9976e085f72SRichard Henderson return ret; 9984dc81f28Sbellard } 9994dc81f28Sbellard 1000f48f3edeSblueswir1 static const char * const cond_name[] = 1001f48f3edeSblueswir1 { 10020aed257fSRichard Henderson [TCG_COND_NEVER] = "never", 10030aed257fSRichard Henderson [TCG_COND_ALWAYS] = "always", 1004f48f3edeSblueswir1 [TCG_COND_EQ] = "eq", 1005f48f3edeSblueswir1 [TCG_COND_NE] = "ne", 1006f48f3edeSblueswir1 [TCG_COND_LT] = "lt", 1007f48f3edeSblueswir1 [TCG_COND_GE] = "ge", 1008f48f3edeSblueswir1 [TCG_COND_LE] = "le", 1009f48f3edeSblueswir1 [TCG_COND_GT] = "gt", 1010f48f3edeSblueswir1 [TCG_COND_LTU] = "ltu", 1011f48f3edeSblueswir1 [TCG_COND_GEU] = "geu", 1012f48f3edeSblueswir1 [TCG_COND_LEU] = "leu", 1013f48f3edeSblueswir1 [TCG_COND_GTU] = "gtu" 1014f48f3edeSblueswir1 }; 1015f48f3edeSblueswir1 1016f713d6adSRichard Henderson static const char * const ldst_name[] = 1017f713d6adSRichard Henderson { 1018f713d6adSRichard Henderson [MO_UB] = "ub", 1019f713d6adSRichard Henderson [MO_SB] = "sb", 1020f713d6adSRichard Henderson [MO_LEUW] = "leuw", 1021f713d6adSRichard Henderson [MO_LESW] = "lesw", 1022f713d6adSRichard Henderson [MO_LEUL] = "leul", 1023f713d6adSRichard Henderson [MO_LESL] = "lesl", 1024f713d6adSRichard Henderson [MO_LEQ] = "leq", 1025f713d6adSRichard Henderson [MO_BEUW] = "beuw", 1026f713d6adSRichard Henderson [MO_BESW] = "besw", 1027f713d6adSRichard Henderson [MO_BEUL] = "beul", 1028f713d6adSRichard Henderson [MO_BESL] = "besl", 1029f713d6adSRichard Henderson [MO_BEQ] = "beq", 1030f713d6adSRichard Henderson }; 1031f713d6adSRichard Henderson 10321f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = { 10331f00b27fSSergey Sorokin #ifdef ALIGNED_ONLY 10341f00b27fSSergey Sorokin [MO_UNALN >> MO_ASHIFT] = "un+", 10351f00b27fSSergey Sorokin [MO_ALIGN >> MO_ASHIFT] = "", 10361f00b27fSSergey Sorokin #else 10371f00b27fSSergey Sorokin [MO_UNALN >> MO_ASHIFT] = "", 10381f00b27fSSergey Sorokin [MO_ALIGN >> MO_ASHIFT] = "al+", 10391f00b27fSSergey Sorokin #endif 10401f00b27fSSergey Sorokin [MO_ALIGN_2 >> MO_ASHIFT] = "al2+", 10411f00b27fSSergey Sorokin [MO_ALIGN_4 >> MO_ASHIFT] = "al4+", 10421f00b27fSSergey Sorokin [MO_ALIGN_8 >> MO_ASHIFT] = "al8+", 10431f00b27fSSergey Sorokin [MO_ALIGN_16 >> MO_ASHIFT] = "al16+", 10441f00b27fSSergey Sorokin [MO_ALIGN_32 >> MO_ASHIFT] = "al32+", 10451f00b27fSSergey Sorokin [MO_ALIGN_64 >> MO_ASHIFT] = "al64+", 10461f00b27fSSergey Sorokin }; 10471f00b27fSSergey Sorokin 1048eeacee4dSBlue Swirl void tcg_dump_ops(TCGContext *s) 1049c896fe29Sbellard { 1050c896fe29Sbellard char buf[128]; 1051c45cb8bbSRichard Henderson TCGOp *op; 1052c45cb8bbSRichard Henderson int oi; 1053c896fe29Sbellard 1054dcb8e758SRichard Henderson for (oi = s->gen_op_buf[0].next; oi != 0; oi = op->next) { 1055c45cb8bbSRichard Henderson int i, k, nb_oargs, nb_iargs, nb_cargs; 1056c45cb8bbSRichard Henderson const TCGOpDef *def; 1057c45cb8bbSRichard Henderson const TCGArg *args; 1058c45cb8bbSRichard Henderson TCGOpcode c; 1059bdfb460eSRichard Henderson int col = 0; 1060c45cb8bbSRichard Henderson 1061c45cb8bbSRichard Henderson op = &s->gen_op_buf[oi]; 1062c45cb8bbSRichard Henderson c = op->opc; 1063c896fe29Sbellard def = &tcg_op_defs[c]; 1064c45cb8bbSRichard Henderson args = &s->gen_opparam_buf[op->args]; 1065c45cb8bbSRichard Henderson 1066765b842aSRichard Henderson if (c == INDEX_op_insn_start) { 1067bdfb460eSRichard Henderson col += qemu_log("%s ----", oi != s->gen_op_buf[0].next ? "\n" : ""); 10689aef40edSRichard Henderson 10699aef40edSRichard Henderson for (i = 0; i < TARGET_INSN_START_WORDS; ++i) { 10709aef40edSRichard Henderson target_ulong a; 10717e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS 10729aef40edSRichard Henderson a = ((target_ulong)args[i * 2 + 1] << 32) | args[i * 2]; 10737e4597d7Sbellard #else 10749aef40edSRichard Henderson a = args[i]; 10757e4597d7Sbellard #endif 1076bdfb460eSRichard Henderson col += qemu_log(" " TARGET_FMT_lx, a); 1077eeacee4dSBlue Swirl } 10787e4597d7Sbellard } else if (c == INDEX_op_call) { 1079c896fe29Sbellard /* variable number of arguments */ 1080c45cb8bbSRichard Henderson nb_oargs = op->callo; 1081c45cb8bbSRichard Henderson nb_iargs = op->calli; 1082c896fe29Sbellard nb_cargs = def->nb_cargs; 1083b03cce8eSbellard 1084cf066674SRichard Henderson /* function name, flags, out args */ 1085bdfb460eSRichard Henderson col += qemu_log(" %s %s,$0x%" TCG_PRIlx ",$%d", def->name, 1086cf066674SRichard Henderson tcg_find_helper(s, args[nb_oargs + nb_iargs]), 1087cf066674SRichard Henderson args[nb_oargs + nb_iargs + 1], nb_oargs); 1088b03cce8eSbellard for (i = 0; i < nb_oargs; i++) { 1089bdfb460eSRichard Henderson col += qemu_log(",%s", tcg_get_arg_str_idx(s, buf, sizeof(buf), 1090eeacee4dSBlue Swirl args[i])); 1091b03cce8eSbellard } 1092cf066674SRichard Henderson for (i = 0; i < nb_iargs; i++) { 1093cf066674SRichard Henderson TCGArg arg = args[nb_oargs + i]; 1094cf066674SRichard Henderson const char *t = "<dummy>"; 1095cf066674SRichard Henderson if (arg != TCG_CALL_DUMMY_ARG) { 1096cf066674SRichard Henderson t = tcg_get_arg_str_idx(s, buf, sizeof(buf), arg); 1097b03cce8eSbellard } 1098bdfb460eSRichard Henderson col += qemu_log(",%s", t); 1099e8996ee0Sbellard } 1100b03cce8eSbellard } else { 1101bdfb460eSRichard Henderson col += qemu_log(" %s ", def->name); 1102c45cb8bbSRichard Henderson 1103c896fe29Sbellard nb_oargs = def->nb_oargs; 1104c896fe29Sbellard nb_iargs = def->nb_iargs; 1105c896fe29Sbellard nb_cargs = def->nb_cargs; 1106c896fe29Sbellard 1107c896fe29Sbellard k = 0; 1108c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 1109eeacee4dSBlue Swirl if (k != 0) { 1110bdfb460eSRichard Henderson col += qemu_log(","); 1111eeacee4dSBlue Swirl } 1112bdfb460eSRichard Henderson col += qemu_log("%s", tcg_get_arg_str_idx(s, buf, sizeof(buf), 1113eeacee4dSBlue Swirl args[k++])); 1114c896fe29Sbellard } 1115c896fe29Sbellard for (i = 0; i < nb_iargs; i++) { 1116eeacee4dSBlue Swirl if (k != 0) { 1117bdfb460eSRichard Henderson col += qemu_log(","); 1118eeacee4dSBlue Swirl } 1119bdfb460eSRichard Henderson col += qemu_log("%s", tcg_get_arg_str_idx(s, buf, sizeof(buf), 1120eeacee4dSBlue Swirl args[k++])); 1121c896fe29Sbellard } 1122be210acbSRichard Henderson switch (c) { 1123be210acbSRichard Henderson case INDEX_op_brcond_i32: 1124ffc5ea09SRichard Henderson case INDEX_op_setcond_i32: 1125ffc5ea09SRichard Henderson case INDEX_op_movcond_i32: 1126be210acbSRichard Henderson case INDEX_op_brcond2_i32: 1127be210acbSRichard Henderson case INDEX_op_setcond2_i32: 1128ffc5ea09SRichard Henderson case INDEX_op_brcond_i64: 1129be210acbSRichard Henderson case INDEX_op_setcond_i64: 1130ffc5ea09SRichard Henderson case INDEX_op_movcond_i64: 1131eeacee4dSBlue Swirl if (args[k] < ARRAY_SIZE(cond_name) && cond_name[args[k]]) { 1132bdfb460eSRichard Henderson col += qemu_log(",%s", cond_name[args[k++]]); 1133eeacee4dSBlue Swirl } else { 1134bdfb460eSRichard Henderson col += qemu_log(",$0x%" TCG_PRIlx, args[k++]); 1135eeacee4dSBlue Swirl } 1136f48f3edeSblueswir1 i = 1; 1137be210acbSRichard Henderson break; 1138f713d6adSRichard Henderson case INDEX_op_qemu_ld_i32: 1139f713d6adSRichard Henderson case INDEX_op_qemu_st_i32: 1140f713d6adSRichard Henderson case INDEX_op_qemu_ld_i64: 1141f713d6adSRichard Henderson case INDEX_op_qemu_st_i64: 114259227d5dSRichard Henderson { 114359227d5dSRichard Henderson TCGMemOpIdx oi = args[k++]; 114459227d5dSRichard Henderson TCGMemOp op = get_memop(oi); 114559227d5dSRichard Henderson unsigned ix = get_mmuidx(oi); 114659227d5dSRichard Henderson 114759c4b7e8SRichard Henderson if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) { 1148bdfb460eSRichard Henderson col += qemu_log(",$0x%x,%u", op, ix); 114959c4b7e8SRichard Henderson } else { 11501f00b27fSSergey Sorokin const char *s_al, *s_op; 11511f00b27fSSergey Sorokin s_al = alignment_name[(op & MO_AMASK) >> MO_ASHIFT]; 115259c4b7e8SRichard Henderson s_op = ldst_name[op & (MO_BSWAP | MO_SSIZE)]; 1153bdfb460eSRichard Henderson col += qemu_log(",%s%s,%u", s_al, s_op, ix); 1154f713d6adSRichard Henderson } 1155f713d6adSRichard Henderson i = 1; 115659227d5dSRichard Henderson } 1157f713d6adSRichard Henderson break; 1158be210acbSRichard Henderson default: 1159f48f3edeSblueswir1 i = 0; 1160be210acbSRichard Henderson break; 1161be210acbSRichard Henderson } 116251e3972cSRichard Henderson switch (c) { 116351e3972cSRichard Henderson case INDEX_op_set_label: 116451e3972cSRichard Henderson case INDEX_op_br: 116551e3972cSRichard Henderson case INDEX_op_brcond_i32: 116651e3972cSRichard Henderson case INDEX_op_brcond_i64: 116751e3972cSRichard Henderson case INDEX_op_brcond2_i32: 1168bdfb460eSRichard Henderson col += qemu_log("%s$L%d", k ? "," : "", arg_label(args[k])->id); 116951e3972cSRichard Henderson i++, k++; 117051e3972cSRichard Henderson break; 117151e3972cSRichard Henderson default: 117251e3972cSRichard Henderson break; 1173eeacee4dSBlue Swirl } 117451e3972cSRichard Henderson for (; i < nb_cargs; i++, k++) { 1175bdfb460eSRichard Henderson col += qemu_log("%s$0x%" TCG_PRIlx, k ? "," : "", args[k]); 1176bdfb460eSRichard Henderson } 1177bdfb460eSRichard Henderson } 1178bdfb460eSRichard Henderson if (op->life) { 1179bdfb460eSRichard Henderson unsigned life = op->life; 1180bdfb460eSRichard Henderson 1181bdfb460eSRichard Henderson for (; col < 48; ++col) { 1182bdfb460eSRichard Henderson putc(' ', qemu_logfile); 1183bdfb460eSRichard Henderson } 1184bdfb460eSRichard Henderson 1185bdfb460eSRichard Henderson if (life & (SYNC_ARG * 3)) { 1186bdfb460eSRichard Henderson qemu_log(" sync:"); 1187bdfb460eSRichard Henderson for (i = 0; i < 2; ++i) { 1188bdfb460eSRichard Henderson if (life & (SYNC_ARG << i)) { 1189bdfb460eSRichard Henderson qemu_log(" %d", i); 1190bdfb460eSRichard Henderson } 1191bdfb460eSRichard Henderson } 1192bdfb460eSRichard Henderson } 1193bdfb460eSRichard Henderson life /= DEAD_ARG; 1194bdfb460eSRichard Henderson if (life) { 1195bdfb460eSRichard Henderson qemu_log(" dead:"); 1196bdfb460eSRichard Henderson for (i = 0; life; ++i, life >>= 1) { 1197bdfb460eSRichard Henderson if (life & 1) { 1198bdfb460eSRichard Henderson qemu_log(" %d", i); 1199bdfb460eSRichard Henderson } 1200bdfb460eSRichard Henderson } 1201c896fe29Sbellard } 1202b03cce8eSbellard } 1203eeacee4dSBlue Swirl qemu_log("\n"); 1204c896fe29Sbellard } 1205c896fe29Sbellard } 1206c896fe29Sbellard 1207c896fe29Sbellard /* we give more priority to constraints with less registers */ 1208c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k) 1209c896fe29Sbellard { 1210c896fe29Sbellard const TCGArgConstraint *arg_ct; 1211c896fe29Sbellard 1212c896fe29Sbellard int i, n; 1213c896fe29Sbellard arg_ct = &def->args_ct[k]; 1214c896fe29Sbellard if (arg_ct->ct & TCG_CT_ALIAS) { 1215c896fe29Sbellard /* an alias is equivalent to a single register */ 1216c896fe29Sbellard n = 1; 1217c896fe29Sbellard } else { 1218c896fe29Sbellard if (!(arg_ct->ct & TCG_CT_REG)) 1219c896fe29Sbellard return 0; 1220c896fe29Sbellard n = 0; 1221c896fe29Sbellard for(i = 0; i < TCG_TARGET_NB_REGS; i++) { 1222c896fe29Sbellard if (tcg_regset_test_reg(arg_ct->u.regs, i)) 1223c896fe29Sbellard n++; 1224c896fe29Sbellard } 1225c896fe29Sbellard } 1226c896fe29Sbellard return TCG_TARGET_NB_REGS - n + 1; 1227c896fe29Sbellard } 1228c896fe29Sbellard 1229c896fe29Sbellard /* sort from highest priority to lowest */ 1230c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n) 1231c896fe29Sbellard { 1232c896fe29Sbellard int i, j, p1, p2, tmp; 1233c896fe29Sbellard 1234c896fe29Sbellard for(i = 0; i < n; i++) 1235c896fe29Sbellard def->sorted_args[start + i] = start + i; 1236c896fe29Sbellard if (n <= 1) 1237c896fe29Sbellard return; 1238c896fe29Sbellard for(i = 0; i < n - 1; i++) { 1239c896fe29Sbellard for(j = i + 1; j < n; j++) { 1240c896fe29Sbellard p1 = get_constraint_priority(def, def->sorted_args[start + i]); 1241c896fe29Sbellard p2 = get_constraint_priority(def, def->sorted_args[start + j]); 1242c896fe29Sbellard if (p1 < p2) { 1243c896fe29Sbellard tmp = def->sorted_args[start + i]; 1244c896fe29Sbellard def->sorted_args[start + i] = def->sorted_args[start + j]; 1245c896fe29Sbellard def->sorted_args[start + j] = tmp; 1246c896fe29Sbellard } 1247c896fe29Sbellard } 1248c896fe29Sbellard } 1249c896fe29Sbellard } 1250c896fe29Sbellard 1251f69d277eSRichard Henderson static void process_op_defs(TCGContext *s) 1252c896fe29Sbellard { 1253a9751609SRichard Henderson TCGOpcode op; 1254c896fe29Sbellard 1255f69d277eSRichard Henderson for (op = 0; op < NB_OPS; op++) { 1256f69d277eSRichard Henderson TCGOpDef *def = &tcg_op_defs[op]; 1257f69d277eSRichard Henderson const TCGTargetOpDef *tdefs; 1258069ea736SRichard Henderson TCGType type; 1259069ea736SRichard Henderson int i, nb_args; 1260f69d277eSRichard Henderson 1261f69d277eSRichard Henderson if (def->flags & TCG_OPF_NOT_PRESENT) { 1262f69d277eSRichard Henderson continue; 1263f69d277eSRichard Henderson } 1264f69d277eSRichard Henderson 1265c896fe29Sbellard nb_args = def->nb_iargs + def->nb_oargs; 1266f69d277eSRichard Henderson if (nb_args == 0) { 1267f69d277eSRichard Henderson continue; 1268f69d277eSRichard Henderson } 1269f69d277eSRichard Henderson 1270f69d277eSRichard Henderson tdefs = tcg_target_op_def(op); 1271f69d277eSRichard Henderson /* Missing TCGTargetOpDef entry. */ 1272f69d277eSRichard Henderson tcg_debug_assert(tdefs != NULL); 1273f69d277eSRichard Henderson 1274069ea736SRichard Henderson type = (def->flags & TCG_OPF_64BIT ? TCG_TYPE_I64 : TCG_TYPE_I32); 1275c896fe29Sbellard for (i = 0; i < nb_args; i++) { 1276f69d277eSRichard Henderson const char *ct_str = tdefs->args_ct_str[i]; 1277f69d277eSRichard Henderson /* Incomplete TCGTargetOpDef entry. */ 1278eabb7b91SAurelien Jarno tcg_debug_assert(ct_str != NULL); 1279f69d277eSRichard Henderson 1280c896fe29Sbellard tcg_regset_clear(def->args_ct[i].u.regs); 1281c896fe29Sbellard def->args_ct[i].ct = 0; 128217280ff4SRichard Henderson while (*ct_str != '\0') { 128317280ff4SRichard Henderson switch(*ct_str) { 128417280ff4SRichard Henderson case '0' ... '9': 128517280ff4SRichard Henderson { 128617280ff4SRichard Henderson int oarg = *ct_str - '0'; 128717280ff4SRichard Henderson tcg_debug_assert(ct_str == tdefs->args_ct_str[i]); 1288eabb7b91SAurelien Jarno tcg_debug_assert(oarg < def->nb_oargs); 1289eabb7b91SAurelien Jarno tcg_debug_assert(def->args_ct[oarg].ct & TCG_CT_REG); 129017280ff4SRichard Henderson /* TCG_CT_ALIAS is for the output arguments. 129117280ff4SRichard Henderson The input is tagged with TCG_CT_IALIAS. */ 1292c896fe29Sbellard def->args_ct[i] = def->args_ct[oarg]; 129317280ff4SRichard Henderson def->args_ct[oarg].ct |= TCG_CT_ALIAS; 12945ff9d6a4Sbellard def->args_ct[oarg].alias_index = i; 1295c896fe29Sbellard def->args_ct[i].ct |= TCG_CT_IALIAS; 12965ff9d6a4Sbellard def->args_ct[i].alias_index = oarg; 129717280ff4SRichard Henderson } 129817280ff4SRichard Henderson ct_str++; 1299c896fe29Sbellard break; 130082790a87SRichard Henderson case '&': 130182790a87SRichard Henderson def->args_ct[i].ct |= TCG_CT_NEWREG; 130282790a87SRichard Henderson ct_str++; 130382790a87SRichard Henderson break; 1304c896fe29Sbellard case 'i': 1305c896fe29Sbellard def->args_ct[i].ct |= TCG_CT_CONST; 1306c896fe29Sbellard ct_str++; 1307c896fe29Sbellard break; 1308c896fe29Sbellard default: 1309069ea736SRichard Henderson ct_str = target_parse_constraint(&def->args_ct[i], 1310069ea736SRichard Henderson ct_str, type); 1311f69d277eSRichard Henderson /* Typo in TCGTargetOpDef constraint. */ 1312069ea736SRichard Henderson tcg_debug_assert(ct_str != NULL); 1313c896fe29Sbellard } 1314c896fe29Sbellard } 1315c896fe29Sbellard } 1316c896fe29Sbellard 1317c68aaa18SStefan Weil /* TCGTargetOpDef entry with too much information? */ 1318eabb7b91SAurelien Jarno tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL); 1319c68aaa18SStefan Weil 1320c896fe29Sbellard /* sort the constraints (XXX: this is just an heuristic) */ 1321c896fe29Sbellard sort_constraints(def, 0, def->nb_oargs); 1322c896fe29Sbellard sort_constraints(def, def->nb_oargs, def->nb_iargs); 1323c896fe29Sbellard } 1324c896fe29Sbellard } 1325c896fe29Sbellard 13260c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op) 13270c627cdcSRichard Henderson { 13280c627cdcSRichard Henderson int next = op->next; 13290c627cdcSRichard Henderson int prev = op->prev; 13300c627cdcSRichard Henderson 1331dcb8e758SRichard Henderson /* We should never attempt to remove the list terminator. */ 1332dcb8e758SRichard Henderson tcg_debug_assert(op != &s->gen_op_buf[0]); 13330c627cdcSRichard Henderson 1334dcb8e758SRichard Henderson s->gen_op_buf[next].prev = prev; 1335dcb8e758SRichard Henderson s->gen_op_buf[prev].next = next; 1336dcb8e758SRichard Henderson 1337dcb8e758SRichard Henderson memset(op, 0, sizeof(*op)); 13380c627cdcSRichard Henderson 13390c627cdcSRichard Henderson #ifdef CONFIG_PROFILER 13400c627cdcSRichard Henderson s->del_op_count++; 13410c627cdcSRichard Henderson #endif 13420c627cdcSRichard Henderson } 13430c627cdcSRichard Henderson 13445a18407fSRichard Henderson TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op, 13455a18407fSRichard Henderson TCGOpcode opc, int nargs) 13465a18407fSRichard Henderson { 13475a18407fSRichard Henderson int oi = s->gen_next_op_idx; 13485a18407fSRichard Henderson int pi = s->gen_next_parm_idx; 13495a18407fSRichard Henderson int prev = old_op->prev; 13505a18407fSRichard Henderson int next = old_op - s->gen_op_buf; 13515a18407fSRichard Henderson TCGOp *new_op; 13525a18407fSRichard Henderson 13535a18407fSRichard Henderson tcg_debug_assert(oi < OPC_BUF_SIZE); 13545a18407fSRichard Henderson tcg_debug_assert(pi + nargs <= OPPARAM_BUF_SIZE); 13555a18407fSRichard Henderson s->gen_next_op_idx = oi + 1; 13565a18407fSRichard Henderson s->gen_next_parm_idx = pi + nargs; 13575a18407fSRichard Henderson 13585a18407fSRichard Henderson new_op = &s->gen_op_buf[oi]; 13595a18407fSRichard Henderson *new_op = (TCGOp){ 13605a18407fSRichard Henderson .opc = opc, 13615a18407fSRichard Henderson .args = pi, 13625a18407fSRichard Henderson .prev = prev, 13635a18407fSRichard Henderson .next = next 13645a18407fSRichard Henderson }; 13655a18407fSRichard Henderson s->gen_op_buf[prev].next = oi; 13665a18407fSRichard Henderson old_op->prev = oi; 13675a18407fSRichard Henderson 13685a18407fSRichard Henderson return new_op; 13695a18407fSRichard Henderson } 13705a18407fSRichard Henderson 13715a18407fSRichard Henderson TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, 13725a18407fSRichard Henderson TCGOpcode opc, int nargs) 13735a18407fSRichard Henderson { 13745a18407fSRichard Henderson int oi = s->gen_next_op_idx; 13755a18407fSRichard Henderson int pi = s->gen_next_parm_idx; 13765a18407fSRichard Henderson int prev = old_op - s->gen_op_buf; 13775a18407fSRichard Henderson int next = old_op->next; 13785a18407fSRichard Henderson TCGOp *new_op; 13795a18407fSRichard Henderson 13805a18407fSRichard Henderson tcg_debug_assert(oi < OPC_BUF_SIZE); 13815a18407fSRichard Henderson tcg_debug_assert(pi + nargs <= OPPARAM_BUF_SIZE); 13825a18407fSRichard Henderson s->gen_next_op_idx = oi + 1; 13835a18407fSRichard Henderson s->gen_next_parm_idx = pi + nargs; 13845a18407fSRichard Henderson 13855a18407fSRichard Henderson new_op = &s->gen_op_buf[oi]; 13865a18407fSRichard Henderson *new_op = (TCGOp){ 13875a18407fSRichard Henderson .opc = opc, 13885a18407fSRichard Henderson .args = pi, 13895a18407fSRichard Henderson .prev = prev, 13905a18407fSRichard Henderson .next = next 13915a18407fSRichard Henderson }; 13925a18407fSRichard Henderson s->gen_op_buf[next].prev = oi; 13935a18407fSRichard Henderson old_op->next = oi; 13945a18407fSRichard Henderson 13955a18407fSRichard Henderson return new_op; 13965a18407fSRichard Henderson } 13975a18407fSRichard Henderson 1398c70fbf0aSRichard Henderson #define TS_DEAD 1 1399c70fbf0aSRichard Henderson #define TS_MEM 2 1400c70fbf0aSRichard Henderson 14015a18407fSRichard Henderson #define IS_DEAD_ARG(n) (arg_life & (DEAD_ARG << (n))) 14025a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n))) 14035a18407fSRichard Henderson 14049c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals 14059c43b68dSAurelien Jarno should be in memory. */ 1406c70fbf0aSRichard Henderson static inline void tcg_la_func_end(TCGContext *s, uint8_t *temp_state) 1407c896fe29Sbellard { 1408c70fbf0aSRichard Henderson memset(temp_state, TS_DEAD | TS_MEM, s->nb_globals); 1409c70fbf0aSRichard Henderson memset(temp_state + s->nb_globals, TS_DEAD, s->nb_temps - s->nb_globals); 1410c896fe29Sbellard } 1411c896fe29Sbellard 14129c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals 14139c43b68dSAurelien Jarno and local temps should be in memory. */ 1414c70fbf0aSRichard Henderson static inline void tcg_la_bb_end(TCGContext *s, uint8_t *temp_state) 1415641d5fbeSbellard { 1416c70fbf0aSRichard Henderson int i, n; 1417641d5fbeSbellard 1418c70fbf0aSRichard Henderson tcg_la_func_end(s, temp_state); 1419c70fbf0aSRichard Henderson for (i = s->nb_globals, n = s->nb_temps; i < n; i++) { 1420c70fbf0aSRichard Henderson if (s->temps[i].temp_local) { 1421c70fbf0aSRichard Henderson temp_state[i] |= TS_MEM; 1422c70fbf0aSRichard Henderson } 1423641d5fbeSbellard } 1424641d5fbeSbellard } 1425641d5fbeSbellard 1426a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a 1427c896fe29Sbellard given input arguments is dead. Instructions updating dead 1428c896fe29Sbellard temporaries are removed. */ 14295a18407fSRichard Henderson static void liveness_pass_1(TCGContext *s, uint8_t *temp_state) 1430c896fe29Sbellard { 1431c70fbf0aSRichard Henderson int nb_globals = s->nb_globals; 14325a18407fSRichard Henderson int oi, oi_prev; 1433c896fe29Sbellard 1434c70fbf0aSRichard Henderson tcg_la_func_end(s, temp_state); 1435c896fe29Sbellard 1436dcb8e758SRichard Henderson for (oi = s->gen_op_buf[0].prev; oi != 0; oi = oi_prev) { 1437c45cb8bbSRichard Henderson int i, nb_iargs, nb_oargs; 1438c45cb8bbSRichard Henderson TCGOpcode opc_new, opc_new2; 1439c45cb8bbSRichard Henderson bool have_opc_new2; 1440a1b3c48dSRichard Henderson TCGLifeData arg_life = 0; 1441c45cb8bbSRichard Henderson TCGArg arg; 1442c45cb8bbSRichard Henderson 1443c45cb8bbSRichard Henderson TCGOp * const op = &s->gen_op_buf[oi]; 1444c45cb8bbSRichard Henderson TCGArg * const args = &s->gen_opparam_buf[op->args]; 1445c45cb8bbSRichard Henderson TCGOpcode opc = op->opc; 1446c45cb8bbSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 1447c45cb8bbSRichard Henderson 1448c45cb8bbSRichard Henderson oi_prev = op->prev; 1449c45cb8bbSRichard Henderson 1450c45cb8bbSRichard Henderson switch (opc) { 1451c896fe29Sbellard case INDEX_op_call: 1452c6e113f5Sbellard { 1453c6e113f5Sbellard int call_flags; 1454c6e113f5Sbellard 1455c45cb8bbSRichard Henderson nb_oargs = op->callo; 1456c45cb8bbSRichard Henderson nb_iargs = op->calli; 1457cf066674SRichard Henderson call_flags = args[nb_oargs + nb_iargs + 1]; 1458c6e113f5Sbellard 1459c45cb8bbSRichard Henderson /* pure functions can be removed if their result is unused */ 146078505279SAurelien Jarno if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) { 1461c6e113f5Sbellard for (i = 0; i < nb_oargs; i++) { 1462c6e113f5Sbellard arg = args[i]; 1463c70fbf0aSRichard Henderson if (temp_state[arg] != TS_DEAD) { 1464c6e113f5Sbellard goto do_not_remove_call; 1465c6e113f5Sbellard } 14669c43b68dSAurelien Jarno } 1467c45cb8bbSRichard Henderson goto do_remove; 1468c6e113f5Sbellard } else { 1469c6e113f5Sbellard do_not_remove_call: 1470c896fe29Sbellard 1471c896fe29Sbellard /* output args are dead */ 1472c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 1473c896fe29Sbellard arg = args[i]; 1474c70fbf0aSRichard Henderson if (temp_state[arg] & TS_DEAD) { 1475a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 14766b64b624SAurelien Jarno } 1477c70fbf0aSRichard Henderson if (temp_state[arg] & TS_MEM) { 1478a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i; 14799c43b68dSAurelien Jarno } 1480c70fbf0aSRichard Henderson temp_state[arg] = TS_DEAD; 1481c896fe29Sbellard } 1482c896fe29Sbellard 148378505279SAurelien Jarno if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS | 148478505279SAurelien Jarno TCG_CALL_NO_READ_GLOBALS))) { 14859c43b68dSAurelien Jarno /* globals should go back to memory */ 1486c70fbf0aSRichard Henderson memset(temp_state, TS_DEAD | TS_MEM, nb_globals); 1487c70fbf0aSRichard Henderson } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) { 1488c70fbf0aSRichard Henderson /* globals should be synced to memory */ 1489c70fbf0aSRichard Henderson for (i = 0; i < nb_globals; i++) { 1490c70fbf0aSRichard Henderson temp_state[i] |= TS_MEM; 1491c70fbf0aSRichard Henderson } 1492b9c18f56Saurel32 } 1493c896fe29Sbellard 1494c19f47bfSAurelien Jarno /* record arguments that die in this helper */ 1495866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 1496866cb6cbSAurelien Jarno arg = args[i]; 149739cf05d3Sbellard if (arg != TCG_CALL_DUMMY_ARG) { 1498c70fbf0aSRichard Henderson if (temp_state[arg] & TS_DEAD) { 1499a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 1500c896fe29Sbellard } 1501c896fe29Sbellard } 150239cf05d3Sbellard } 150367cc32ebSVeres Lajos /* input arguments are live for preceding opcodes */ 1504c70fbf0aSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 1505c19f47bfSAurelien Jarno arg = args[i]; 1506c70fbf0aSRichard Henderson if (arg != TCG_CALL_DUMMY_ARG) { 1507c70fbf0aSRichard Henderson temp_state[arg] &= ~TS_DEAD; 1508c70fbf0aSRichard Henderson } 1509c19f47bfSAurelien Jarno } 1510c6e113f5Sbellard } 1511c6e113f5Sbellard } 1512c896fe29Sbellard break; 1513765b842aSRichard Henderson case INDEX_op_insn_start: 1514c896fe29Sbellard break; 15155ff9d6a4Sbellard case INDEX_op_discard: 15165ff9d6a4Sbellard /* mark the temporary as dead */ 1517c70fbf0aSRichard Henderson temp_state[args[0]] = TS_DEAD; 15185ff9d6a4Sbellard break; 15191305c451SRichard Henderson 15201305c451SRichard Henderson case INDEX_op_add2_i32: 1521c45cb8bbSRichard Henderson opc_new = INDEX_op_add_i32; 1522f1fae40cSRichard Henderson goto do_addsub2; 15231305c451SRichard Henderson case INDEX_op_sub2_i32: 1524c45cb8bbSRichard Henderson opc_new = INDEX_op_sub_i32; 1525f1fae40cSRichard Henderson goto do_addsub2; 1526f1fae40cSRichard Henderson case INDEX_op_add2_i64: 1527c45cb8bbSRichard Henderson opc_new = INDEX_op_add_i64; 1528f1fae40cSRichard Henderson goto do_addsub2; 1529f1fae40cSRichard Henderson case INDEX_op_sub2_i64: 1530c45cb8bbSRichard Henderson opc_new = INDEX_op_sub_i64; 1531f1fae40cSRichard Henderson do_addsub2: 15321305c451SRichard Henderson nb_iargs = 4; 15331305c451SRichard Henderson nb_oargs = 2; 15341305c451SRichard Henderson /* Test if the high part of the operation is dead, but not 15351305c451SRichard Henderson the low part. The result can be optimized to a simple 15361305c451SRichard Henderson add or sub. This happens often for x86_64 guest when the 15371305c451SRichard Henderson cpu mode is set to 32 bit. */ 1538c70fbf0aSRichard Henderson if (temp_state[args[1]] == TS_DEAD) { 1539c70fbf0aSRichard Henderson if (temp_state[args[0]] == TS_DEAD) { 15401305c451SRichard Henderson goto do_remove; 15411305c451SRichard Henderson } 1542c45cb8bbSRichard Henderson /* Replace the opcode and adjust the args in place, 1543c45cb8bbSRichard Henderson leaving 3 unused args at the end. */ 1544c45cb8bbSRichard Henderson op->opc = opc = opc_new; 15451305c451SRichard Henderson args[1] = args[2]; 15461305c451SRichard Henderson args[2] = args[4]; 15471305c451SRichard Henderson /* Fall through and mark the single-word operation live. */ 15481305c451SRichard Henderson nb_iargs = 2; 15491305c451SRichard Henderson nb_oargs = 1; 15501305c451SRichard Henderson } 15511305c451SRichard Henderson goto do_not_remove; 15521305c451SRichard Henderson 15531414968aSRichard Henderson case INDEX_op_mulu2_i32: 1554c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i32; 1555c45cb8bbSRichard Henderson opc_new2 = INDEX_op_muluh_i32; 1556c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_muluh_i32; 155703271524SRichard Henderson goto do_mul2; 1558f1fae40cSRichard Henderson case INDEX_op_muls2_i32: 1559c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i32; 1560c45cb8bbSRichard Henderson opc_new2 = INDEX_op_mulsh_i32; 1561c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_mulsh_i32; 1562f1fae40cSRichard Henderson goto do_mul2; 1563f1fae40cSRichard Henderson case INDEX_op_mulu2_i64: 1564c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i64; 1565c45cb8bbSRichard Henderson opc_new2 = INDEX_op_muluh_i64; 1566c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_muluh_i64; 156703271524SRichard Henderson goto do_mul2; 1568f1fae40cSRichard Henderson case INDEX_op_muls2_i64: 1569c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i64; 1570c45cb8bbSRichard Henderson opc_new2 = INDEX_op_mulsh_i64; 1571c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_mulsh_i64; 157203271524SRichard Henderson goto do_mul2; 1573f1fae40cSRichard Henderson do_mul2: 15741414968aSRichard Henderson nb_iargs = 2; 15751414968aSRichard Henderson nb_oargs = 2; 1576c70fbf0aSRichard Henderson if (temp_state[args[1]] == TS_DEAD) { 1577c70fbf0aSRichard Henderson if (temp_state[args[0]] == TS_DEAD) { 157803271524SRichard Henderson /* Both parts of the operation are dead. */ 15791414968aSRichard Henderson goto do_remove; 15801414968aSRichard Henderson } 158103271524SRichard Henderson /* The high part of the operation is dead; generate the low. */ 1582c45cb8bbSRichard Henderson op->opc = opc = opc_new; 15831414968aSRichard Henderson args[1] = args[2]; 15841414968aSRichard Henderson args[2] = args[3]; 1585c70fbf0aSRichard Henderson } else if (temp_state[args[0]] == TS_DEAD && have_opc_new2) { 158603271524SRichard Henderson /* The low part of the operation is dead; generate the high. */ 1587c45cb8bbSRichard Henderson op->opc = opc = opc_new2; 158803271524SRichard Henderson args[0] = args[1]; 158903271524SRichard Henderson args[1] = args[2]; 159003271524SRichard Henderson args[2] = args[3]; 159103271524SRichard Henderson } else { 159203271524SRichard Henderson goto do_not_remove; 159303271524SRichard Henderson } 159403271524SRichard Henderson /* Mark the single-word operation live. */ 15951414968aSRichard Henderson nb_oargs = 1; 15961414968aSRichard Henderson goto do_not_remove; 15971414968aSRichard Henderson 1598c896fe29Sbellard default: 15991305c451SRichard Henderson /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */ 1600c896fe29Sbellard nb_iargs = def->nb_iargs; 1601c896fe29Sbellard nb_oargs = def->nb_oargs; 1602c896fe29Sbellard 1603c896fe29Sbellard /* Test if the operation can be removed because all 16045ff9d6a4Sbellard its outputs are dead. We assume that nb_oargs == 0 16055ff9d6a4Sbellard implies side effects */ 16065ff9d6a4Sbellard if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) { 1607c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 1608c70fbf0aSRichard Henderson if (temp_state[args[i]] != TS_DEAD) { 1609c896fe29Sbellard goto do_not_remove; 1610c896fe29Sbellard } 16119c43b68dSAurelien Jarno } 16121305c451SRichard Henderson do_remove: 16130c627cdcSRichard Henderson tcg_op_remove(s, op); 1614c896fe29Sbellard } else { 1615c896fe29Sbellard do_not_remove: 1616c896fe29Sbellard /* output args are dead */ 1617c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 1618c896fe29Sbellard arg = args[i]; 1619c70fbf0aSRichard Henderson if (temp_state[arg] & TS_DEAD) { 1620a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 16216b64b624SAurelien Jarno } 1622c70fbf0aSRichard Henderson if (temp_state[arg] & TS_MEM) { 1623a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i; 16249c43b68dSAurelien Jarno } 1625c70fbf0aSRichard Henderson temp_state[arg] = TS_DEAD; 1626c896fe29Sbellard } 1627c896fe29Sbellard 1628c896fe29Sbellard /* if end of basic block, update */ 1629c896fe29Sbellard if (def->flags & TCG_OPF_BB_END) { 1630c70fbf0aSRichard Henderson tcg_la_bb_end(s, temp_state); 16313d5c5f87SAurelien Jarno } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { 16323d5c5f87SAurelien Jarno /* globals should be synced to memory */ 1633c70fbf0aSRichard Henderson for (i = 0; i < nb_globals; i++) { 1634c70fbf0aSRichard Henderson temp_state[i] |= TS_MEM; 1635c70fbf0aSRichard Henderson } 1636c896fe29Sbellard } 1637c896fe29Sbellard 1638c19f47bfSAurelien Jarno /* record arguments that die in this opcode */ 1639866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 1640866cb6cbSAurelien Jarno arg = args[i]; 1641c70fbf0aSRichard Henderson if (temp_state[arg] & TS_DEAD) { 1642a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 1643c896fe29Sbellard } 1644c19f47bfSAurelien Jarno } 164567cc32ebSVeres Lajos /* input arguments are live for preceding opcodes */ 1646c19f47bfSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 1647c70fbf0aSRichard Henderson temp_state[args[i]] &= ~TS_DEAD; 1648c896fe29Sbellard } 1649c896fe29Sbellard } 1650c896fe29Sbellard break; 1651c896fe29Sbellard } 1652bee158cbSRichard Henderson op->life = arg_life; 1653c896fe29Sbellard } 16541ff0a2c5SEvgeny Voevodin } 1655c896fe29Sbellard 16565a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries. */ 16575a18407fSRichard Henderson static bool liveness_pass_2(TCGContext *s, uint8_t *temp_state) 16585a18407fSRichard Henderson { 16595a18407fSRichard Henderson int nb_globals = s->nb_globals; 16605a18407fSRichard Henderson int16_t *dir_temps; 16615a18407fSRichard Henderson int i, oi, oi_next; 16625a18407fSRichard Henderson bool changes = false; 16635a18407fSRichard Henderson 16645a18407fSRichard Henderson dir_temps = tcg_malloc(nb_globals * sizeof(int16_t)); 16655a18407fSRichard Henderson memset(dir_temps, 0, nb_globals * sizeof(int16_t)); 16665a18407fSRichard Henderson 16675a18407fSRichard Henderson /* Create a temporary for each indirect global. */ 16685a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 16695a18407fSRichard Henderson TCGTemp *its = &s->temps[i]; 16705a18407fSRichard Henderson if (its->indirect_reg) { 16715a18407fSRichard Henderson TCGTemp *dts = tcg_temp_alloc(s); 16725a18407fSRichard Henderson dts->type = its->type; 16735a18407fSRichard Henderson dts->base_type = its->base_type; 16745a18407fSRichard Henderson dir_temps[i] = temp_idx(s, dts); 16755a18407fSRichard Henderson } 16765a18407fSRichard Henderson } 16775a18407fSRichard Henderson 16785a18407fSRichard Henderson memset(temp_state, TS_DEAD, nb_globals); 16795a18407fSRichard Henderson 16805a18407fSRichard Henderson for (oi = s->gen_op_buf[0].next; oi != 0; oi = oi_next) { 16815a18407fSRichard Henderson TCGOp *op = &s->gen_op_buf[oi]; 16825a18407fSRichard Henderson TCGArg *args = &s->gen_opparam_buf[op->args]; 16835a18407fSRichard Henderson TCGOpcode opc = op->opc; 16845a18407fSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 16855a18407fSRichard Henderson TCGLifeData arg_life = op->life; 16865a18407fSRichard Henderson int nb_iargs, nb_oargs, call_flags; 16875a18407fSRichard Henderson TCGArg arg, dir; 16885a18407fSRichard Henderson 16895a18407fSRichard Henderson oi_next = op->next; 16905a18407fSRichard Henderson 16915a18407fSRichard Henderson if (opc == INDEX_op_call) { 16925a18407fSRichard Henderson nb_oargs = op->callo; 16935a18407fSRichard Henderson nb_iargs = op->calli; 16945a18407fSRichard Henderson call_flags = args[nb_oargs + nb_iargs + 1]; 16955a18407fSRichard Henderson } else { 16965a18407fSRichard Henderson nb_iargs = def->nb_iargs; 16975a18407fSRichard Henderson nb_oargs = def->nb_oargs; 16985a18407fSRichard Henderson 16995a18407fSRichard Henderson /* Set flags similar to how calls require. */ 17005a18407fSRichard Henderson if (def->flags & TCG_OPF_BB_END) { 17015a18407fSRichard Henderson /* Like writing globals: save_globals */ 17025a18407fSRichard Henderson call_flags = 0; 17035a18407fSRichard Henderson } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { 17045a18407fSRichard Henderson /* Like reading globals: sync_globals */ 17055a18407fSRichard Henderson call_flags = TCG_CALL_NO_WRITE_GLOBALS; 17065a18407fSRichard Henderson } else { 17075a18407fSRichard Henderson /* No effect on globals. */ 17085a18407fSRichard Henderson call_flags = (TCG_CALL_NO_READ_GLOBALS | 17095a18407fSRichard Henderson TCG_CALL_NO_WRITE_GLOBALS); 17105a18407fSRichard Henderson } 17115a18407fSRichard Henderson } 17125a18407fSRichard Henderson 17135a18407fSRichard Henderson /* Make sure that input arguments are available. */ 17145a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 17155a18407fSRichard Henderson arg = args[i]; 17165a18407fSRichard Henderson /* Note this unsigned test catches TCG_CALL_ARG_DUMMY too. */ 17175a18407fSRichard Henderson if (arg < nb_globals) { 17185a18407fSRichard Henderson dir = dir_temps[arg]; 17195a18407fSRichard Henderson if (dir != 0 && temp_state[arg] == TS_DEAD) { 17205a18407fSRichard Henderson TCGTemp *its = &s->temps[arg]; 17215a18407fSRichard Henderson TCGOpcode lopc = (its->type == TCG_TYPE_I32 17225a18407fSRichard Henderson ? INDEX_op_ld_i32 17235a18407fSRichard Henderson : INDEX_op_ld_i64); 17245a18407fSRichard Henderson TCGOp *lop = tcg_op_insert_before(s, op, lopc, 3); 17255a18407fSRichard Henderson TCGArg *largs = &s->gen_opparam_buf[lop->args]; 17265a18407fSRichard Henderson 17275a18407fSRichard Henderson largs[0] = dir; 17285a18407fSRichard Henderson largs[1] = temp_idx(s, its->mem_base); 17295a18407fSRichard Henderson largs[2] = its->mem_offset; 17305a18407fSRichard Henderson 17315a18407fSRichard Henderson /* Loaded, but synced with memory. */ 17325a18407fSRichard Henderson temp_state[arg] = TS_MEM; 17335a18407fSRichard Henderson } 17345a18407fSRichard Henderson } 17355a18407fSRichard Henderson } 17365a18407fSRichard Henderson 17375a18407fSRichard Henderson /* Perform input replacement, and mark inputs that became dead. 17385a18407fSRichard Henderson No action is required except keeping temp_state up to date 17395a18407fSRichard Henderson so that we reload when needed. */ 17405a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 17415a18407fSRichard Henderson arg = args[i]; 17425a18407fSRichard Henderson if (arg < nb_globals) { 17435a18407fSRichard Henderson dir = dir_temps[arg]; 17445a18407fSRichard Henderson if (dir != 0) { 17455a18407fSRichard Henderson args[i] = dir; 17465a18407fSRichard Henderson changes = true; 17475a18407fSRichard Henderson if (IS_DEAD_ARG(i)) { 17485a18407fSRichard Henderson temp_state[arg] = TS_DEAD; 17495a18407fSRichard Henderson } 17505a18407fSRichard Henderson } 17515a18407fSRichard Henderson } 17525a18407fSRichard Henderson } 17535a18407fSRichard Henderson 17545a18407fSRichard Henderson /* Liveness analysis should ensure that the following are 17555a18407fSRichard Henderson all correct, for call sites and basic block end points. */ 17565a18407fSRichard Henderson if (call_flags & TCG_CALL_NO_READ_GLOBALS) { 17575a18407fSRichard Henderson /* Nothing to do */ 17585a18407fSRichard Henderson } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) { 17595a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 17605a18407fSRichard Henderson /* Liveness should see that globals are synced back, 17615a18407fSRichard Henderson that is, either TS_DEAD or TS_MEM. */ 17625a18407fSRichard Henderson tcg_debug_assert(dir_temps[i] == 0 17635a18407fSRichard Henderson || temp_state[i] != 0); 17645a18407fSRichard Henderson } 17655a18407fSRichard Henderson } else { 17665a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 17675a18407fSRichard Henderson /* Liveness should see that globals are saved back, 17685a18407fSRichard Henderson that is, TS_DEAD, waiting to be reloaded. */ 17695a18407fSRichard Henderson tcg_debug_assert(dir_temps[i] == 0 17705a18407fSRichard Henderson || temp_state[i] == TS_DEAD); 17715a18407fSRichard Henderson } 17725a18407fSRichard Henderson } 17735a18407fSRichard Henderson 17745a18407fSRichard Henderson /* Outputs become available. */ 17755a18407fSRichard Henderson for (i = 0; i < nb_oargs; i++) { 17765a18407fSRichard Henderson arg = args[i]; 17775a18407fSRichard Henderson if (arg >= nb_globals) { 17785a18407fSRichard Henderson continue; 17795a18407fSRichard Henderson } 17805a18407fSRichard Henderson dir = dir_temps[arg]; 17815a18407fSRichard Henderson if (dir == 0) { 17825a18407fSRichard Henderson continue; 17835a18407fSRichard Henderson } 17845a18407fSRichard Henderson args[i] = dir; 17855a18407fSRichard Henderson changes = true; 17865a18407fSRichard Henderson 17875a18407fSRichard Henderson /* The output is now live and modified. */ 17885a18407fSRichard Henderson temp_state[arg] = 0; 17895a18407fSRichard Henderson 17905a18407fSRichard Henderson /* Sync outputs upon their last write. */ 17915a18407fSRichard Henderson if (NEED_SYNC_ARG(i)) { 17925a18407fSRichard Henderson TCGTemp *its = &s->temps[arg]; 17935a18407fSRichard Henderson TCGOpcode sopc = (its->type == TCG_TYPE_I32 17945a18407fSRichard Henderson ? INDEX_op_st_i32 17955a18407fSRichard Henderson : INDEX_op_st_i64); 17965a18407fSRichard Henderson TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3); 17975a18407fSRichard Henderson TCGArg *sargs = &s->gen_opparam_buf[sop->args]; 17985a18407fSRichard Henderson 17995a18407fSRichard Henderson sargs[0] = dir; 18005a18407fSRichard Henderson sargs[1] = temp_idx(s, its->mem_base); 18015a18407fSRichard Henderson sargs[2] = its->mem_offset; 18025a18407fSRichard Henderson 18035a18407fSRichard Henderson temp_state[arg] = TS_MEM; 18045a18407fSRichard Henderson } 18055a18407fSRichard Henderson /* Drop outputs that are dead. */ 18065a18407fSRichard Henderson if (IS_DEAD_ARG(i)) { 18075a18407fSRichard Henderson temp_state[arg] = TS_DEAD; 18085a18407fSRichard Henderson } 18095a18407fSRichard Henderson } 18105a18407fSRichard Henderson } 18115a18407fSRichard Henderson 18125a18407fSRichard Henderson return changes; 18135a18407fSRichard Henderson } 18145a18407fSRichard Henderson 18158d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG 1816c896fe29Sbellard static void dump_regs(TCGContext *s) 1817c896fe29Sbellard { 1818c896fe29Sbellard TCGTemp *ts; 1819c896fe29Sbellard int i; 1820c896fe29Sbellard char buf[64]; 1821c896fe29Sbellard 1822c896fe29Sbellard for(i = 0; i < s->nb_temps; i++) { 1823c896fe29Sbellard ts = &s->temps[i]; 1824ac56dd48Spbrook printf(" %10s: ", tcg_get_arg_str_idx(s, buf, sizeof(buf), i)); 1825c896fe29Sbellard switch(ts->val_type) { 1826c896fe29Sbellard case TEMP_VAL_REG: 1827c896fe29Sbellard printf("%s", tcg_target_reg_names[ts->reg]); 1828c896fe29Sbellard break; 1829c896fe29Sbellard case TEMP_VAL_MEM: 1830b3a62939SRichard Henderson printf("%d(%s)", (int)ts->mem_offset, 1831b3a62939SRichard Henderson tcg_target_reg_names[ts->mem_base->reg]); 1832c896fe29Sbellard break; 1833c896fe29Sbellard case TEMP_VAL_CONST: 1834c896fe29Sbellard printf("$0x%" TCG_PRIlx, ts->val); 1835c896fe29Sbellard break; 1836c896fe29Sbellard case TEMP_VAL_DEAD: 1837c896fe29Sbellard printf("D"); 1838c896fe29Sbellard break; 1839c896fe29Sbellard default: 1840c896fe29Sbellard printf("???"); 1841c896fe29Sbellard break; 1842c896fe29Sbellard } 1843c896fe29Sbellard printf("\n"); 1844c896fe29Sbellard } 1845c896fe29Sbellard 1846c896fe29Sbellard for(i = 0; i < TCG_TARGET_NB_REGS; i++) { 1847f8b2f202SRichard Henderson if (s->reg_to_temp[i] != NULL) { 1848c896fe29Sbellard printf("%s: %s\n", 1849c896fe29Sbellard tcg_target_reg_names[i], 1850f8b2f202SRichard Henderson tcg_get_arg_str_ptr(s, buf, sizeof(buf), s->reg_to_temp[i])); 1851c896fe29Sbellard } 1852c896fe29Sbellard } 1853c896fe29Sbellard } 1854c896fe29Sbellard 1855c896fe29Sbellard static void check_regs(TCGContext *s) 1856c896fe29Sbellard { 1857869938aeSRichard Henderson int reg; 1858b6638662SRichard Henderson int k; 1859c896fe29Sbellard TCGTemp *ts; 1860c896fe29Sbellard char buf[64]; 1861c896fe29Sbellard 1862c896fe29Sbellard for (reg = 0; reg < TCG_TARGET_NB_REGS; reg++) { 1863f8b2f202SRichard Henderson ts = s->reg_to_temp[reg]; 1864f8b2f202SRichard Henderson if (ts != NULL) { 1865f8b2f202SRichard Henderson if (ts->val_type != TEMP_VAL_REG || ts->reg != reg) { 1866c896fe29Sbellard printf("Inconsistency for register %s:\n", 1867c896fe29Sbellard tcg_target_reg_names[reg]); 1868b03cce8eSbellard goto fail; 1869c896fe29Sbellard } 1870c896fe29Sbellard } 1871c896fe29Sbellard } 1872c896fe29Sbellard for (k = 0; k < s->nb_temps; k++) { 1873c896fe29Sbellard ts = &s->temps[k]; 1874f8b2f202SRichard Henderson if (ts->val_type == TEMP_VAL_REG && !ts->fixed_reg 1875f8b2f202SRichard Henderson && s->reg_to_temp[ts->reg] != ts) { 1876c896fe29Sbellard printf("Inconsistency for temp %s:\n", 1877f8b2f202SRichard Henderson tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts)); 1878b03cce8eSbellard fail: 1879c896fe29Sbellard printf("reg state:\n"); 1880c896fe29Sbellard dump_regs(s); 1881c896fe29Sbellard tcg_abort(); 1882c896fe29Sbellard } 1883c896fe29Sbellard } 1884c896fe29Sbellard } 1885c896fe29Sbellard #endif 1886c896fe29Sbellard 1887c896fe29Sbellard static void temp_allocate_frame(TCGContext *s, int temp) 1888c896fe29Sbellard { 1889c896fe29Sbellard TCGTemp *ts; 1890c896fe29Sbellard ts = &s->temps[temp]; 18919b9c37c3SRichard Henderson #if !(defined(__sparc__) && TCG_TARGET_REG_BITS == 64) 18929b9c37c3SRichard Henderson /* Sparc64 stack is accessed with offset of 2047 */ 1893b591dc59SBlue Swirl s->current_frame_offset = (s->current_frame_offset + 1894b591dc59SBlue Swirl (tcg_target_long)sizeof(tcg_target_long) - 1) & 1895b591dc59SBlue Swirl ~(sizeof(tcg_target_long) - 1); 1896f44c9960SBlue Swirl #endif 1897b591dc59SBlue Swirl if (s->current_frame_offset + (tcg_target_long)sizeof(tcg_target_long) > 1898b591dc59SBlue Swirl s->frame_end) { 18995ff9d6a4Sbellard tcg_abort(); 1900b591dc59SBlue Swirl } 1901c896fe29Sbellard ts->mem_offset = s->current_frame_offset; 1902b3a62939SRichard Henderson ts->mem_base = s->frame_temp; 1903c896fe29Sbellard ts->mem_allocated = 1; 1904e2c6d1b4SRichard Henderson s->current_frame_offset += sizeof(tcg_target_long); 1905c896fe29Sbellard } 1906c896fe29Sbellard 1907b3915dbbSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet); 1908b3915dbbSRichard Henderson 190959d7c14eSRichard Henderson /* Mark a temporary as free or dead. If 'free_or_dead' is negative, 191059d7c14eSRichard Henderson mark it free; otherwise mark it dead. */ 191159d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead) 1912c896fe29Sbellard { 191359d7c14eSRichard Henderson if (ts->fixed_reg) { 191459d7c14eSRichard Henderson return; 191559d7c14eSRichard Henderson } 191659d7c14eSRichard Henderson if (ts->val_type == TEMP_VAL_REG) { 191759d7c14eSRichard Henderson s->reg_to_temp[ts->reg] = NULL; 191859d7c14eSRichard Henderson } 191959d7c14eSRichard Henderson ts->val_type = (free_or_dead < 0 192059d7c14eSRichard Henderson || ts->temp_local 192159d7c14eSRichard Henderson || temp_idx(s, ts) < s->nb_globals 192259d7c14eSRichard Henderson ? TEMP_VAL_MEM : TEMP_VAL_DEAD); 192359d7c14eSRichard Henderson } 1924c896fe29Sbellard 192559d7c14eSRichard Henderson /* Mark a temporary as dead. */ 192659d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts) 192759d7c14eSRichard Henderson { 192859d7c14eSRichard Henderson temp_free_or_dead(s, ts, 1); 192959d7c14eSRichard Henderson } 193059d7c14eSRichard Henderson 193159d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary 193259d7c14eSRichard Henderson registers needs to be allocated to store a constant. If 'free_or_dead' 193359d7c14eSRichard Henderson is non-zero, subsequently release the temporary; if it is positive, the 193459d7c14eSRichard Henderson temp is dead; if it is negative, the temp is free. */ 193559d7c14eSRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, 193659d7c14eSRichard Henderson TCGRegSet allocated_regs, int free_or_dead) 193759d7c14eSRichard Henderson { 193859d7c14eSRichard Henderson if (ts->fixed_reg) { 193959d7c14eSRichard Henderson return; 194059d7c14eSRichard Henderson } 194159d7c14eSRichard Henderson if (!ts->mem_coherent) { 19427f6ceedfSAurelien Jarno if (!ts->mem_allocated) { 1943f8b2f202SRichard Henderson temp_allocate_frame(s, temp_idx(s, ts)); 194459d7c14eSRichard Henderson } 194559d7c14eSRichard Henderson switch (ts->val_type) { 194659d7c14eSRichard Henderson case TEMP_VAL_CONST: 194759d7c14eSRichard Henderson /* If we're going to free the temp immediately, then we won't 194859d7c14eSRichard Henderson require it later in a register, so attempt to store the 194959d7c14eSRichard Henderson constant to memory directly. */ 195059d7c14eSRichard Henderson if (free_or_dead 195159d7c14eSRichard Henderson && tcg_out_sti(s, ts->type, ts->val, 195259d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset)) { 195359d7c14eSRichard Henderson break; 195459d7c14eSRichard Henderson } 195559d7c14eSRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 195659d7c14eSRichard Henderson allocated_regs); 195759d7c14eSRichard Henderson /* fallthrough */ 195859d7c14eSRichard Henderson 195959d7c14eSRichard Henderson case TEMP_VAL_REG: 196059d7c14eSRichard Henderson tcg_out_st(s, ts->type, ts->reg, 196159d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset); 196259d7c14eSRichard Henderson break; 196359d7c14eSRichard Henderson 196459d7c14eSRichard Henderson case TEMP_VAL_MEM: 196559d7c14eSRichard Henderson break; 196659d7c14eSRichard Henderson 196759d7c14eSRichard Henderson case TEMP_VAL_DEAD: 196859d7c14eSRichard Henderson default: 196959d7c14eSRichard Henderson tcg_abort(); 1970c896fe29Sbellard } 19717f6ceedfSAurelien Jarno ts->mem_coherent = 1; 19727f6ceedfSAurelien Jarno } 197359d7c14eSRichard Henderson if (free_or_dead) { 197459d7c14eSRichard Henderson temp_free_or_dead(s, ts, free_or_dead); 197559d7c14eSRichard Henderson } 197659d7c14eSRichard Henderson } 19777f6ceedfSAurelien Jarno 19787f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */ 1979b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs) 19807f6ceedfSAurelien Jarno { 1981f8b2f202SRichard Henderson TCGTemp *ts = s->reg_to_temp[reg]; 1982f8b2f202SRichard Henderson if (ts != NULL) { 198359d7c14eSRichard Henderson temp_sync(s, ts, allocated_regs, -1); 1984c896fe29Sbellard } 1985c896fe29Sbellard } 1986c896fe29Sbellard 1987c896fe29Sbellard /* Allocate a register belonging to reg1 & ~reg2 */ 1988b3915dbbSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet desired_regs, 198991478cefSRichard Henderson TCGRegSet allocated_regs, bool rev) 1990c896fe29Sbellard { 199191478cefSRichard Henderson int i, n = ARRAY_SIZE(tcg_target_reg_alloc_order); 199291478cefSRichard Henderson const int *order; 1993b6638662SRichard Henderson TCGReg reg; 1994c896fe29Sbellard TCGRegSet reg_ct; 1995c896fe29Sbellard 1996b3915dbbSRichard Henderson tcg_regset_andnot(reg_ct, desired_regs, allocated_regs); 199791478cefSRichard Henderson order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order; 1998c896fe29Sbellard 1999c896fe29Sbellard /* first try free registers */ 200091478cefSRichard Henderson for(i = 0; i < n; i++) { 200191478cefSRichard Henderson reg = order[i]; 2002f8b2f202SRichard Henderson if (tcg_regset_test_reg(reg_ct, reg) && s->reg_to_temp[reg] == NULL) 2003c896fe29Sbellard return reg; 2004c896fe29Sbellard } 2005c896fe29Sbellard 2006c896fe29Sbellard /* XXX: do better spill choice */ 200791478cefSRichard Henderson for(i = 0; i < n; i++) { 200891478cefSRichard Henderson reg = order[i]; 2009c896fe29Sbellard if (tcg_regset_test_reg(reg_ct, reg)) { 2010b3915dbbSRichard Henderson tcg_reg_free(s, reg, allocated_regs); 2011c896fe29Sbellard return reg; 2012c896fe29Sbellard } 2013c896fe29Sbellard } 2014c896fe29Sbellard 2015c896fe29Sbellard tcg_abort(); 2016c896fe29Sbellard } 2017c896fe29Sbellard 201840ae5c62SRichard Henderson /* Make sure the temporary is in a register. If needed, allocate the register 201940ae5c62SRichard Henderson from DESIRED while avoiding ALLOCATED. */ 202040ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs, 202140ae5c62SRichard Henderson TCGRegSet allocated_regs) 202240ae5c62SRichard Henderson { 202340ae5c62SRichard Henderson TCGReg reg; 202440ae5c62SRichard Henderson 202540ae5c62SRichard Henderson switch (ts->val_type) { 202640ae5c62SRichard Henderson case TEMP_VAL_REG: 202740ae5c62SRichard Henderson return; 202840ae5c62SRichard Henderson case TEMP_VAL_CONST: 202991478cefSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs, ts->indirect_base); 203040ae5c62SRichard Henderson tcg_out_movi(s, ts->type, reg, ts->val); 203140ae5c62SRichard Henderson ts->mem_coherent = 0; 203240ae5c62SRichard Henderson break; 203340ae5c62SRichard Henderson case TEMP_VAL_MEM: 203491478cefSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs, ts->indirect_base); 203540ae5c62SRichard Henderson tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset); 203640ae5c62SRichard Henderson ts->mem_coherent = 1; 203740ae5c62SRichard Henderson break; 203840ae5c62SRichard Henderson case TEMP_VAL_DEAD: 203940ae5c62SRichard Henderson default: 204040ae5c62SRichard Henderson tcg_abort(); 204140ae5c62SRichard Henderson } 204240ae5c62SRichard Henderson ts->reg = reg; 204340ae5c62SRichard Henderson ts->val_type = TEMP_VAL_REG; 204440ae5c62SRichard Henderson s->reg_to_temp[reg] = ts; 204540ae5c62SRichard Henderson } 204640ae5c62SRichard Henderson 204759d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a 2048e8996ee0Sbellard temporary registers needs to be allocated to store a constant. */ 204959d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs) 20501ad80729SAurelien Jarno { 20512c0366f0SAurelien Jarno /* The liveness analysis already ensures that globals are back 2052eabb7b91SAurelien Jarno in memory. Keep an tcg_debug_assert for safety. */ 2053f8bf00f1SRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || ts->fixed_reg); 20541ad80729SAurelien Jarno } 20551ad80729SAurelien Jarno 20569814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be 2057641d5fbeSbellard modified be the following code. 'allocated_regs' is used in case a 2058641d5fbeSbellard temporary registers needs to be allocated to store a constant. */ 2059641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs) 2060641d5fbeSbellard { 2061641d5fbeSbellard int i; 2062641d5fbeSbellard 2063641d5fbeSbellard for (i = 0; i < s->nb_globals; i++) { 2064b13eb728SRichard Henderson temp_save(s, &s->temps[i], allocated_regs); 2065641d5fbeSbellard } 2066e5097dc8Sbellard } 2067e5097dc8Sbellard 20683d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be 20693d5c5f87SAurelien Jarno read by the following code. 'allocated_regs' is used in case a 20703d5c5f87SAurelien Jarno temporary registers needs to be allocated to store a constant. */ 20713d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs) 20723d5c5f87SAurelien Jarno { 20733d5c5f87SAurelien Jarno int i; 20743d5c5f87SAurelien Jarno 20753d5c5f87SAurelien Jarno for (i = 0; i < s->nb_globals; i++) { 207612b9b11aSRichard Henderson TCGTemp *ts = &s->temps[i]; 207712b9b11aSRichard Henderson tcg_debug_assert(ts->val_type != TEMP_VAL_REG 207812b9b11aSRichard Henderson || ts->fixed_reg 207912b9b11aSRichard Henderson || ts->mem_coherent); 20803d5c5f87SAurelien Jarno } 20813d5c5f87SAurelien Jarno } 20823d5c5f87SAurelien Jarno 2083e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and 2084e8996ee0Sbellard all globals are stored at their canonical location. */ 2085e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs) 2086e5097dc8Sbellard { 2087e5097dc8Sbellard int i; 2088e5097dc8Sbellard 2089c896fe29Sbellard for (i = s->nb_globals; i < s->nb_temps; i++) { 2090b13eb728SRichard Henderson TCGTemp *ts = &s->temps[i]; 2091641d5fbeSbellard if (ts->temp_local) { 2092b13eb728SRichard Henderson temp_save(s, ts, allocated_regs); 2093641d5fbeSbellard } else { 20942c0366f0SAurelien Jarno /* The liveness analysis already ensures that temps are dead. 2095eabb7b91SAurelien Jarno Keep an tcg_debug_assert for safety. */ 2096eabb7b91SAurelien Jarno tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD); 2097c896fe29Sbellard } 2098641d5fbeSbellard } 2099e8996ee0Sbellard 2100e8996ee0Sbellard save_globals(s, allocated_regs); 2101c896fe29Sbellard } 2102c896fe29Sbellard 21030fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots, 21040fe4fca4SPaolo Bonzini tcg_target_ulong val, TCGLifeData arg_life) 2105e8996ee0Sbellard { 2106e8996ee0Sbellard if (ots->fixed_reg) { 210759d7c14eSRichard Henderson /* For fixed registers, we do not do any constant propagation. */ 2108e8996ee0Sbellard tcg_out_movi(s, ots->type, ots->reg, val); 210959d7c14eSRichard Henderson return; 211059d7c14eSRichard Henderson } 211159d7c14eSRichard Henderson 211259d7c14eSRichard Henderson /* The movi is not explicitly generated here. */ 2113f8b2f202SRichard Henderson if (ots->val_type == TEMP_VAL_REG) { 2114f8b2f202SRichard Henderson s->reg_to_temp[ots->reg] = NULL; 2115f8b2f202SRichard Henderson } 2116e8996ee0Sbellard ots->val_type = TEMP_VAL_CONST; 2117e8996ee0Sbellard ots->val = val; 211859d7c14eSRichard Henderson ots->mem_coherent = 0; 2119ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) { 212059d7c14eSRichard Henderson temp_sync(s, ots, s->reserved_regs, IS_DEAD_ARG(0)); 212159d7c14eSRichard Henderson } else if (IS_DEAD_ARG(0)) { 2122f8bf00f1SRichard Henderson temp_dead(s, ots); 21234c4e1ab2SAurelien Jarno } 2124e8996ee0Sbellard } 2125e8996ee0Sbellard 21260fe4fca4SPaolo Bonzini static void tcg_reg_alloc_movi(TCGContext *s, const TCGArg *args, 21270fe4fca4SPaolo Bonzini TCGLifeData arg_life) 21280fe4fca4SPaolo Bonzini { 21290fe4fca4SPaolo Bonzini TCGTemp *ots = &s->temps[args[0]]; 21300fe4fca4SPaolo Bonzini tcg_target_ulong val = args[1]; 21310fe4fca4SPaolo Bonzini 21320fe4fca4SPaolo Bonzini tcg_reg_alloc_do_movi(s, ots, val, arg_life); 21330fe4fca4SPaolo Bonzini } 21340fe4fca4SPaolo Bonzini 2135c896fe29Sbellard static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def, 2136a1b3c48dSRichard Henderson const TCGArg *args, TCGLifeData arg_life) 2137c896fe29Sbellard { 2138c29c1d7eSAurelien Jarno TCGRegSet allocated_regs; 2139c896fe29Sbellard TCGTemp *ts, *ots; 2140450445d5SRichard Henderson TCGType otype, itype; 2141c896fe29Sbellard 2142c29c1d7eSAurelien Jarno tcg_regset_set(allocated_regs, s->reserved_regs); 2143c896fe29Sbellard ots = &s->temps[args[0]]; 2144c896fe29Sbellard ts = &s->temps[args[1]]; 2145450445d5SRichard Henderson 2146450445d5SRichard Henderson /* Note that otype != itype for no-op truncation. */ 2147450445d5SRichard Henderson otype = ots->type; 2148450445d5SRichard Henderson itype = ts->type; 2149c896fe29Sbellard 21500fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_CONST) { 21510fe4fca4SPaolo Bonzini /* propagate constant or generate sti */ 21520fe4fca4SPaolo Bonzini tcg_target_ulong val = ts->val; 21530fe4fca4SPaolo Bonzini if (IS_DEAD_ARG(1)) { 21540fe4fca4SPaolo Bonzini temp_dead(s, ts); 21550fe4fca4SPaolo Bonzini } 21560fe4fca4SPaolo Bonzini tcg_reg_alloc_do_movi(s, ots, val, arg_life); 21570fe4fca4SPaolo Bonzini return; 21580fe4fca4SPaolo Bonzini } 21590fe4fca4SPaolo Bonzini 21600fe4fca4SPaolo Bonzini /* If the source value is in memory we're going to be forced 21610fe4fca4SPaolo Bonzini to have it in a register in order to perform the copy. Copy 21620fe4fca4SPaolo Bonzini the SOURCE value into its own register first, that way we 21630fe4fca4SPaolo Bonzini don't have to reload SOURCE the next time it is used. */ 21640fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_MEM) { 216540ae5c62SRichard Henderson temp_load(s, ts, tcg_target_available_regs[itype], allocated_regs); 2166c29c1d7eSAurelien Jarno } 2167c29c1d7eSAurelien Jarno 21680fe4fca4SPaolo Bonzini tcg_debug_assert(ts->val_type == TEMP_VAL_REG); 2169c29c1d7eSAurelien Jarno if (IS_DEAD_ARG(0) && !ots->fixed_reg) { 2170c29c1d7eSAurelien Jarno /* mov to a non-saved dead register makes no sense (even with 2171c29c1d7eSAurelien Jarno liveness analysis disabled). */ 2172eabb7b91SAurelien Jarno tcg_debug_assert(NEED_SYNC_ARG(0)); 2173c29c1d7eSAurelien Jarno if (!ots->mem_allocated) { 2174c29c1d7eSAurelien Jarno temp_allocate_frame(s, args[0]); 2175c29c1d7eSAurelien Jarno } 2176b3a62939SRichard Henderson tcg_out_st(s, otype, ts->reg, ots->mem_base->reg, ots->mem_offset); 2177c29c1d7eSAurelien Jarno if (IS_DEAD_ARG(1)) { 2178f8bf00f1SRichard Henderson temp_dead(s, ts); 2179c29c1d7eSAurelien Jarno } 2180f8bf00f1SRichard Henderson temp_dead(s, ots); 2181e8996ee0Sbellard } else { 2182c29c1d7eSAurelien Jarno if (IS_DEAD_ARG(1) && !ts->fixed_reg && !ots->fixed_reg) { 2183c29c1d7eSAurelien Jarno /* the mov can be suppressed */ 2184c29c1d7eSAurelien Jarno if (ots->val_type == TEMP_VAL_REG) { 2185f8b2f202SRichard Henderson s->reg_to_temp[ots->reg] = NULL; 2186c896fe29Sbellard } 2187c29c1d7eSAurelien Jarno ots->reg = ts->reg; 2188f8bf00f1SRichard Henderson temp_dead(s, ts); 2189c29c1d7eSAurelien Jarno } else { 2190c29c1d7eSAurelien Jarno if (ots->val_type != TEMP_VAL_REG) { 2191c29c1d7eSAurelien Jarno /* When allocating a new register, make sure to not spill the 2192c29c1d7eSAurelien Jarno input one. */ 2193c29c1d7eSAurelien Jarno tcg_regset_set_reg(allocated_regs, ts->reg); 2194450445d5SRichard Henderson ots->reg = tcg_reg_alloc(s, tcg_target_available_regs[otype], 219591478cefSRichard Henderson allocated_regs, ots->indirect_base); 2196c29c1d7eSAurelien Jarno } 2197450445d5SRichard Henderson tcg_out_mov(s, otype, ots->reg, ts->reg); 2198c29c1d7eSAurelien Jarno } 2199c896fe29Sbellard ots->val_type = TEMP_VAL_REG; 2200c896fe29Sbellard ots->mem_coherent = 0; 2201f8b2f202SRichard Henderson s->reg_to_temp[ots->reg] = ots; 2202ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) { 220359d7c14eSRichard Henderson temp_sync(s, ots, allocated_regs, 0); 2204c29c1d7eSAurelien Jarno } 2205ec7a869dSAurelien Jarno } 2206c896fe29Sbellard } 2207c896fe29Sbellard 2208c896fe29Sbellard static void tcg_reg_alloc_op(TCGContext *s, 2209a9751609SRichard Henderson const TCGOpDef *def, TCGOpcode opc, 2210a1b3c48dSRichard Henderson const TCGArg *args, TCGLifeData arg_life) 2211c896fe29Sbellard { 221282790a87SRichard Henderson TCGRegSet i_allocated_regs; 221382790a87SRichard Henderson TCGRegSet o_allocated_regs; 2214b6638662SRichard Henderson int i, k, nb_iargs, nb_oargs; 2215b6638662SRichard Henderson TCGReg reg; 2216c896fe29Sbellard TCGArg arg; 2217c896fe29Sbellard const TCGArgConstraint *arg_ct; 2218c896fe29Sbellard TCGTemp *ts; 2219c896fe29Sbellard TCGArg new_args[TCG_MAX_OP_ARGS]; 2220c896fe29Sbellard int const_args[TCG_MAX_OP_ARGS]; 2221c896fe29Sbellard 2222c896fe29Sbellard nb_oargs = def->nb_oargs; 2223c896fe29Sbellard nb_iargs = def->nb_iargs; 2224c896fe29Sbellard 2225c896fe29Sbellard /* copy constants */ 2226c896fe29Sbellard memcpy(new_args + nb_oargs + nb_iargs, 2227c896fe29Sbellard args + nb_oargs + nb_iargs, 2228c896fe29Sbellard sizeof(TCGArg) * def->nb_cargs); 2229c896fe29Sbellard 223082790a87SRichard Henderson tcg_regset_set(i_allocated_regs, s->reserved_regs); 223182790a87SRichard Henderson tcg_regset_set(o_allocated_regs, s->reserved_regs); 223282790a87SRichard Henderson 2233c896fe29Sbellard /* satisfy input constraints */ 2234c896fe29Sbellard for(k = 0; k < nb_iargs; k++) { 2235c896fe29Sbellard i = def->sorted_args[nb_oargs + k]; 2236c896fe29Sbellard arg = args[i]; 2237c896fe29Sbellard arg_ct = &def->args_ct[i]; 2238c896fe29Sbellard ts = &s->temps[arg]; 223940ae5c62SRichard Henderson 224040ae5c62SRichard Henderson if (ts->val_type == TEMP_VAL_CONST 224140ae5c62SRichard Henderson && tcg_target_const_match(ts->val, ts->type, arg_ct)) { 2242c896fe29Sbellard /* constant is OK for instruction */ 2243c896fe29Sbellard const_args[i] = 1; 2244c896fe29Sbellard new_args[i] = ts->val; 2245c896fe29Sbellard goto iarg_end; 2246c896fe29Sbellard } 224740ae5c62SRichard Henderson 224882790a87SRichard Henderson temp_load(s, ts, arg_ct->u.regs, i_allocated_regs); 224940ae5c62SRichard Henderson 22505ff9d6a4Sbellard if (arg_ct->ct & TCG_CT_IALIAS) { 22515ff9d6a4Sbellard if (ts->fixed_reg) { 22525ff9d6a4Sbellard /* if fixed register, we must allocate a new register 22535ff9d6a4Sbellard if the alias is not the same register */ 22545ff9d6a4Sbellard if (arg != args[arg_ct->alias_index]) 22555ff9d6a4Sbellard goto allocate_in_reg; 22565ff9d6a4Sbellard } else { 2257c896fe29Sbellard /* if the input is aliased to an output and if it is 2258c896fe29Sbellard not dead after the instruction, we must allocate 2259c896fe29Sbellard a new register and move it */ 2260866cb6cbSAurelien Jarno if (!IS_DEAD_ARG(i)) { 2261c896fe29Sbellard goto allocate_in_reg; 2262c896fe29Sbellard } 22637e1df267SAurelien Jarno /* check if the current register has already been allocated 22647e1df267SAurelien Jarno for another input aliased to an output */ 22657e1df267SAurelien Jarno int k2, i2; 22667e1df267SAurelien Jarno for (k2 = 0 ; k2 < k ; k2++) { 22677e1df267SAurelien Jarno i2 = def->sorted_args[nb_oargs + k2]; 22687e1df267SAurelien Jarno if ((def->args_ct[i2].ct & TCG_CT_IALIAS) && 22697e1df267SAurelien Jarno (new_args[i2] == ts->reg)) { 22707e1df267SAurelien Jarno goto allocate_in_reg; 22717e1df267SAurelien Jarno } 22727e1df267SAurelien Jarno } 22735ff9d6a4Sbellard } 2274866cb6cbSAurelien Jarno } 2275c896fe29Sbellard reg = ts->reg; 2276c896fe29Sbellard if (tcg_regset_test_reg(arg_ct->u.regs, reg)) { 2277c896fe29Sbellard /* nothing to do : the constraint is satisfied */ 2278c896fe29Sbellard } else { 2279c896fe29Sbellard allocate_in_reg: 2280c896fe29Sbellard /* allocate a new register matching the constraint 2281c896fe29Sbellard and move the temporary register into it */ 228282790a87SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->u.regs, i_allocated_regs, 228391478cefSRichard Henderson ts->indirect_base); 22843b6dac34SRichard Henderson tcg_out_mov(s, ts->type, reg, ts->reg); 2285c896fe29Sbellard } 2286c896fe29Sbellard new_args[i] = reg; 2287c896fe29Sbellard const_args[i] = 0; 228882790a87SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg); 2289c896fe29Sbellard iarg_end: ; 2290c896fe29Sbellard } 2291c896fe29Sbellard 2292c896fe29Sbellard /* mark dead temporaries and free the associated registers */ 2293866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 2294866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) { 2295f8bf00f1SRichard Henderson temp_dead(s, &s->temps[args[i]]); 2296c896fe29Sbellard } 2297c896fe29Sbellard } 2298c896fe29Sbellard 2299a52ad07eSAurelien Jarno if (def->flags & TCG_OPF_BB_END) { 230082790a87SRichard Henderson tcg_reg_alloc_bb_end(s, i_allocated_regs); 2301a52ad07eSAurelien Jarno } else { 2302c896fe29Sbellard if (def->flags & TCG_OPF_CALL_CLOBBER) { 2303b03cce8eSbellard /* XXX: permit generic clobber register list ? */ 2304c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) { 2305c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { 230682790a87SRichard Henderson tcg_reg_free(s, i, i_allocated_regs); 2307c896fe29Sbellard } 2308c896fe29Sbellard } 23093d5c5f87SAurelien Jarno } 23103d5c5f87SAurelien Jarno if (def->flags & TCG_OPF_SIDE_EFFECTS) { 23113d5c5f87SAurelien Jarno /* sync globals if the op has side effects and might trigger 23123d5c5f87SAurelien Jarno an exception. */ 231382790a87SRichard Henderson sync_globals(s, i_allocated_regs); 2314c896fe29Sbellard } 2315c896fe29Sbellard 2316c896fe29Sbellard /* satisfy the output constraints */ 2317c896fe29Sbellard for(k = 0; k < nb_oargs; k++) { 2318c896fe29Sbellard i = def->sorted_args[k]; 2319c896fe29Sbellard arg = args[i]; 2320c896fe29Sbellard arg_ct = &def->args_ct[i]; 2321c896fe29Sbellard ts = &s->temps[arg]; 232217280ff4SRichard Henderson if ((arg_ct->ct & TCG_CT_ALIAS) 232317280ff4SRichard Henderson && !const_args[arg_ct->alias_index]) { 23245ff9d6a4Sbellard reg = new_args[arg_ct->alias_index]; 232582790a87SRichard Henderson } else if (arg_ct->ct & TCG_CT_NEWREG) { 232682790a87SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->u.regs, 232782790a87SRichard Henderson i_allocated_regs | o_allocated_regs, 232882790a87SRichard Henderson ts->indirect_base); 2329c896fe29Sbellard } else { 2330c896fe29Sbellard /* if fixed register, we try to use it */ 2331c896fe29Sbellard reg = ts->reg; 2332c896fe29Sbellard if (ts->fixed_reg && 2333c896fe29Sbellard tcg_regset_test_reg(arg_ct->u.regs, reg)) { 2334c896fe29Sbellard goto oarg_end; 2335c896fe29Sbellard } 233682790a87SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->u.regs, o_allocated_regs, 233791478cefSRichard Henderson ts->indirect_base); 2338c896fe29Sbellard } 233982790a87SRichard Henderson tcg_regset_set_reg(o_allocated_regs, reg); 2340c896fe29Sbellard /* if a fixed register is used, then a move will be done afterwards */ 2341c896fe29Sbellard if (!ts->fixed_reg) { 2342639368ddSAurelien Jarno if (ts->val_type == TEMP_VAL_REG) { 2343f8b2f202SRichard Henderson s->reg_to_temp[ts->reg] = NULL; 2344639368ddSAurelien Jarno } 2345c896fe29Sbellard ts->val_type = TEMP_VAL_REG; 2346c896fe29Sbellard ts->reg = reg; 2347c896fe29Sbellard /* temp value is modified, so the value kept in memory is 2348c896fe29Sbellard potentially not the same */ 2349c896fe29Sbellard ts->mem_coherent = 0; 2350f8b2f202SRichard Henderson s->reg_to_temp[reg] = ts; 2351c896fe29Sbellard } 2352c896fe29Sbellard oarg_end: 2353c896fe29Sbellard new_args[i] = reg; 2354c896fe29Sbellard } 2355e8996ee0Sbellard } 2356c896fe29Sbellard 2357c896fe29Sbellard /* emit instruction */ 2358c896fe29Sbellard tcg_out_op(s, opc, new_args, const_args); 2359c896fe29Sbellard 2360c896fe29Sbellard /* move the outputs in the correct register if needed */ 2361c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 2362c896fe29Sbellard ts = &s->temps[args[i]]; 2363c896fe29Sbellard reg = new_args[i]; 2364c896fe29Sbellard if (ts->fixed_reg && ts->reg != reg) { 23653b6dac34SRichard Henderson tcg_out_mov(s, ts->type, ts->reg, reg); 2366c896fe29Sbellard } 2367ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) { 236882790a87SRichard Henderson temp_sync(s, ts, o_allocated_regs, IS_DEAD_ARG(i)); 236959d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) { 2370f8bf00f1SRichard Henderson temp_dead(s, ts); 2371ec7a869dSAurelien Jarno } 2372c896fe29Sbellard } 2373c896fe29Sbellard } 2374c896fe29Sbellard 2375b03cce8eSbellard #ifdef TCG_TARGET_STACK_GROWSUP 2376b03cce8eSbellard #define STACK_DIR(x) (-(x)) 2377b03cce8eSbellard #else 2378b03cce8eSbellard #define STACK_DIR(x) (x) 2379b03cce8eSbellard #endif 2380b03cce8eSbellard 2381c45cb8bbSRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, int nb_oargs, int nb_iargs, 2382a1b3c48dSRichard Henderson const TCGArg * const args, TCGLifeData arg_life) 2383c896fe29Sbellard { 2384b6638662SRichard Henderson int flags, nb_regs, i; 2385b6638662SRichard Henderson TCGReg reg; 2386cf066674SRichard Henderson TCGArg arg; 2387c896fe29Sbellard TCGTemp *ts; 2388d3452f1fSRichard Henderson intptr_t stack_offset; 2389d3452f1fSRichard Henderson size_t call_stack_size; 2390cf066674SRichard Henderson tcg_insn_unit *func_addr; 2391cf066674SRichard Henderson int allocate_args; 2392c896fe29Sbellard TCGRegSet allocated_regs; 2393c896fe29Sbellard 2394cf066674SRichard Henderson func_addr = (tcg_insn_unit *)(intptr_t)args[nb_oargs + nb_iargs]; 2395cf066674SRichard Henderson flags = args[nb_oargs + nb_iargs + 1]; 2396c896fe29Sbellard 23976e17d0c5SStefan Weil nb_regs = ARRAY_SIZE(tcg_target_call_iarg_regs); 2398c45cb8bbSRichard Henderson if (nb_regs > nb_iargs) { 2399c45cb8bbSRichard Henderson nb_regs = nb_iargs; 2400cf066674SRichard Henderson } 2401c896fe29Sbellard 2402c896fe29Sbellard /* assign stack slots first */ 2403c45cb8bbSRichard Henderson call_stack_size = (nb_iargs - nb_regs) * sizeof(tcg_target_long); 2404c896fe29Sbellard call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) & 2405c896fe29Sbellard ~(TCG_TARGET_STACK_ALIGN - 1); 2406b03cce8eSbellard allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE); 2407b03cce8eSbellard if (allocate_args) { 2408345649c0SBlue Swirl /* XXX: if more than TCG_STATIC_CALL_ARGS_SIZE is needed, 2409345649c0SBlue Swirl preallocate call stack */ 2410345649c0SBlue Swirl tcg_abort(); 2411b03cce8eSbellard } 241239cf05d3Sbellard 241339cf05d3Sbellard stack_offset = TCG_TARGET_CALL_STACK_OFFSET; 2414c45cb8bbSRichard Henderson for(i = nb_regs; i < nb_iargs; i++) { 2415c896fe29Sbellard arg = args[nb_oargs + i]; 241639cf05d3Sbellard #ifdef TCG_TARGET_STACK_GROWSUP 241739cf05d3Sbellard stack_offset -= sizeof(tcg_target_long); 241839cf05d3Sbellard #endif 241939cf05d3Sbellard if (arg != TCG_CALL_DUMMY_ARG) { 2420c896fe29Sbellard ts = &s->temps[arg]; 242140ae5c62SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 242240ae5c62SRichard Henderson s->reserved_regs); 2423e4d5434cSblueswir1 tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset); 242439cf05d3Sbellard } 242539cf05d3Sbellard #ifndef TCG_TARGET_STACK_GROWSUP 242639cf05d3Sbellard stack_offset += sizeof(tcg_target_long); 242739cf05d3Sbellard #endif 2428c896fe29Sbellard } 2429c896fe29Sbellard 2430c896fe29Sbellard /* assign input registers */ 2431c896fe29Sbellard tcg_regset_set(allocated_regs, s->reserved_regs); 2432c896fe29Sbellard for(i = 0; i < nb_regs; i++) { 2433c896fe29Sbellard arg = args[nb_oargs + i]; 243439cf05d3Sbellard if (arg != TCG_CALL_DUMMY_ARG) { 2435c896fe29Sbellard ts = &s->temps[arg]; 2436c896fe29Sbellard reg = tcg_target_call_iarg_regs[i]; 2437b3915dbbSRichard Henderson tcg_reg_free(s, reg, allocated_regs); 243840ae5c62SRichard Henderson 2439c896fe29Sbellard if (ts->val_type == TEMP_VAL_REG) { 2440c896fe29Sbellard if (ts->reg != reg) { 24413b6dac34SRichard Henderson tcg_out_mov(s, ts->type, reg, ts->reg); 2442c896fe29Sbellard } 2443c896fe29Sbellard } else { 244440ae5c62SRichard Henderson TCGRegSet arg_set; 244540ae5c62SRichard Henderson 244640ae5c62SRichard Henderson tcg_regset_clear(arg_set); 244740ae5c62SRichard Henderson tcg_regset_set_reg(arg_set, reg); 244840ae5c62SRichard Henderson temp_load(s, ts, arg_set, allocated_regs); 2449c896fe29Sbellard } 245040ae5c62SRichard Henderson 2451c896fe29Sbellard tcg_regset_set_reg(allocated_regs, reg); 2452c896fe29Sbellard } 245339cf05d3Sbellard } 2454c896fe29Sbellard 2455c896fe29Sbellard /* mark dead temporaries and free the associated registers */ 2456866cb6cbSAurelien Jarno for(i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 2457866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) { 2458f8bf00f1SRichard Henderson temp_dead(s, &s->temps[args[i]]); 2459c896fe29Sbellard } 2460c896fe29Sbellard } 2461c896fe29Sbellard 2462c896fe29Sbellard /* clobber call registers */ 2463c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) { 2464c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { 2465b3915dbbSRichard Henderson tcg_reg_free(s, i, allocated_regs); 2466c896fe29Sbellard } 2467c896fe29Sbellard } 2468c896fe29Sbellard 246978505279SAurelien Jarno /* Save globals if they might be written by the helper, sync them if 247078505279SAurelien Jarno they might be read. */ 247178505279SAurelien Jarno if (flags & TCG_CALL_NO_READ_GLOBALS) { 247278505279SAurelien Jarno /* Nothing to do */ 247378505279SAurelien Jarno } else if (flags & TCG_CALL_NO_WRITE_GLOBALS) { 247478505279SAurelien Jarno sync_globals(s, allocated_regs); 247578505279SAurelien Jarno } else { 2476e8996ee0Sbellard save_globals(s, allocated_regs); 2477b9c18f56Saurel32 } 2478c896fe29Sbellard 2479cf066674SRichard Henderson tcg_out_call(s, func_addr); 2480c896fe29Sbellard 2481c896fe29Sbellard /* assign output registers and emit moves if needed */ 2482c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 2483c896fe29Sbellard arg = args[i]; 2484c896fe29Sbellard ts = &s->temps[arg]; 2485c896fe29Sbellard reg = tcg_target_call_oarg_regs[i]; 2486eabb7b91SAurelien Jarno tcg_debug_assert(s->reg_to_temp[reg] == NULL); 248734b1a49cSRichard Henderson 2488c896fe29Sbellard if (ts->fixed_reg) { 2489c896fe29Sbellard if (ts->reg != reg) { 24903b6dac34SRichard Henderson tcg_out_mov(s, ts->type, ts->reg, reg); 2491c896fe29Sbellard } 2492c896fe29Sbellard } else { 2493639368ddSAurelien Jarno if (ts->val_type == TEMP_VAL_REG) { 2494f8b2f202SRichard Henderson s->reg_to_temp[ts->reg] = NULL; 2495639368ddSAurelien Jarno } 2496c896fe29Sbellard ts->val_type = TEMP_VAL_REG; 2497c896fe29Sbellard ts->reg = reg; 2498c896fe29Sbellard ts->mem_coherent = 0; 2499f8b2f202SRichard Henderson s->reg_to_temp[reg] = ts; 2500ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) { 250159d7c14eSRichard Henderson temp_sync(s, ts, allocated_regs, IS_DEAD_ARG(i)); 250259d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) { 2503f8bf00f1SRichard Henderson temp_dead(s, ts); 2504c896fe29Sbellard } 2505c896fe29Sbellard } 25068c11ad25SAurelien Jarno } 2507c896fe29Sbellard } 2508c896fe29Sbellard 2509c896fe29Sbellard #ifdef CONFIG_PROFILER 2510c896fe29Sbellard 251154604f74Saurel32 static int64_t tcg_table_op_count[NB_OPS]; 2512c896fe29Sbellard 2513246ae24dSMax Filippov void tcg_dump_op_count(FILE *f, fprintf_function cpu_fprintf) 2514c896fe29Sbellard { 2515c896fe29Sbellard int i; 2516d70724ceSzhanghailiang 251715fc7daaSRichard Henderson for (i = 0; i < NB_OPS; i++) { 2518246ae24dSMax Filippov cpu_fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name, 2519246ae24dSMax Filippov tcg_table_op_count[i]); 2520c896fe29Sbellard } 2521c896fe29Sbellard } 2522246ae24dSMax Filippov #else 2523246ae24dSMax Filippov void tcg_dump_op_count(FILE *f, fprintf_function cpu_fprintf) 2524246ae24dSMax Filippov { 2525246ae24dSMax Filippov cpu_fprintf(f, "[TCG profiler not compiled]\n"); 2526246ae24dSMax Filippov } 2527c896fe29Sbellard #endif 2528c896fe29Sbellard 2529c896fe29Sbellard 25305bd2ec3dSAlex Bennée int tcg_gen_code(TCGContext *s, TranslationBlock *tb) 2531c896fe29Sbellard { 2532fca8a500SRichard Henderson int i, oi, oi_next, num_insns; 2533c896fe29Sbellard 253404fe6400SRichard Henderson #ifdef CONFIG_PROFILER 253504fe6400SRichard Henderson { 253604fe6400SRichard Henderson int n; 253704fe6400SRichard Henderson 2538dcb8e758SRichard Henderson n = s->gen_op_buf[0].prev + 1; 253904fe6400SRichard Henderson s->op_count += n; 254004fe6400SRichard Henderson if (n > s->op_count_max) { 254104fe6400SRichard Henderson s->op_count_max = n; 254204fe6400SRichard Henderson } 254304fe6400SRichard Henderson 254404fe6400SRichard Henderson n = s->nb_temps; 254504fe6400SRichard Henderson s->temp_count += n; 254604fe6400SRichard Henderson if (n > s->temp_count_max) { 254704fe6400SRichard Henderson s->temp_count_max = n; 254804fe6400SRichard Henderson } 254904fe6400SRichard Henderson } 255004fe6400SRichard Henderson #endif 255104fe6400SRichard Henderson 2552c896fe29Sbellard #ifdef DEBUG_DISAS 2553d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP) 2554d977e1c2SAlex Bennée && qemu_log_in_addr_range(tb->pc))) { 25551ee73216SRichard Henderson qemu_log_lock(); 255693fcfe39Saliguori qemu_log("OP:\n"); 2557eeacee4dSBlue Swirl tcg_dump_ops(s); 255893fcfe39Saliguori qemu_log("\n"); 25591ee73216SRichard Henderson qemu_log_unlock(); 2560c896fe29Sbellard } 2561c896fe29Sbellard #endif 2562c896fe29Sbellard 2563c5cc28ffSAurelien Jarno #ifdef CONFIG_PROFILER 2564c5cc28ffSAurelien Jarno s->opt_time -= profile_getclock(); 2565c5cc28ffSAurelien Jarno #endif 2566c5cc28ffSAurelien Jarno 25678f2e8c07SKirill Batuzov #ifdef USE_TCG_OPTIMIZATIONS 2568c45cb8bbSRichard Henderson tcg_optimize(s); 25698f2e8c07SKirill Batuzov #endif 25708f2e8c07SKirill Batuzov 2571a23a9ec6Sbellard #ifdef CONFIG_PROFILER 2572c5cc28ffSAurelien Jarno s->opt_time += profile_getclock(); 2573a23a9ec6Sbellard s->la_time -= profile_getclock(); 2574a23a9ec6Sbellard #endif 2575c5cc28ffSAurelien Jarno 25765a18407fSRichard Henderson { 25775a18407fSRichard Henderson uint8_t *temp_state = tcg_malloc(s->nb_temps + s->nb_indirects); 25785a18407fSRichard Henderson 25795a18407fSRichard Henderson liveness_pass_1(s, temp_state); 25805a18407fSRichard Henderson 25815a18407fSRichard Henderson if (s->nb_indirects > 0) { 25825a18407fSRichard Henderson #ifdef DEBUG_DISAS 25835a18407fSRichard Henderson if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND) 25845a18407fSRichard Henderson && qemu_log_in_addr_range(tb->pc))) { 25851ee73216SRichard Henderson qemu_log_lock(); 25865a18407fSRichard Henderson qemu_log("OP before indirect lowering:\n"); 25875a18407fSRichard Henderson tcg_dump_ops(s); 25885a18407fSRichard Henderson qemu_log("\n"); 25891ee73216SRichard Henderson qemu_log_unlock(); 25905a18407fSRichard Henderson } 25915a18407fSRichard Henderson #endif 25925a18407fSRichard Henderson /* Replace indirect temps with direct temps. */ 25935a18407fSRichard Henderson if (liveness_pass_2(s, temp_state)) { 25945a18407fSRichard Henderson /* If changes were made, re-run liveness. */ 25955a18407fSRichard Henderson liveness_pass_1(s, temp_state); 25965a18407fSRichard Henderson } 25975a18407fSRichard Henderson } 25985a18407fSRichard Henderson } 2599c5cc28ffSAurelien Jarno 2600a23a9ec6Sbellard #ifdef CONFIG_PROFILER 2601a23a9ec6Sbellard s->la_time += profile_getclock(); 2602a23a9ec6Sbellard #endif 2603c896fe29Sbellard 2604c896fe29Sbellard #ifdef DEBUG_DISAS 2605d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT) 2606d977e1c2SAlex Bennée && qemu_log_in_addr_range(tb->pc))) { 26071ee73216SRichard Henderson qemu_log_lock(); 2608c5cc28ffSAurelien Jarno qemu_log("OP after optimization and liveness analysis:\n"); 2609eeacee4dSBlue Swirl tcg_dump_ops(s); 261093fcfe39Saliguori qemu_log("\n"); 26111ee73216SRichard Henderson qemu_log_unlock(); 2612c896fe29Sbellard } 2613c896fe29Sbellard #endif 2614c896fe29Sbellard 2615c896fe29Sbellard tcg_reg_alloc_start(s); 2616c896fe29Sbellard 26175bd2ec3dSAlex Bennée s->code_buf = tb->tc_ptr; 26185bd2ec3dSAlex Bennée s->code_ptr = tb->tc_ptr; 2619c896fe29Sbellard 2620659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS 2621659ef5cbSRichard Henderson s->ldst_labels = NULL; 2622659ef5cbSRichard Henderson #endif 2623*57a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 2624*57a26946SRichard Henderson s->pool_labels = NULL; 2625*57a26946SRichard Henderson #endif 26269ecefc84SRichard Henderson 2627fca8a500SRichard Henderson num_insns = -1; 2628dcb8e758SRichard Henderson for (oi = s->gen_op_buf[0].next; oi != 0; oi = oi_next) { 2629c45cb8bbSRichard Henderson TCGOp * const op = &s->gen_op_buf[oi]; 2630c45cb8bbSRichard Henderson TCGArg * const args = &s->gen_opparam_buf[op->args]; 2631c45cb8bbSRichard Henderson TCGOpcode opc = op->opc; 2632c45cb8bbSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 2633bee158cbSRichard Henderson TCGLifeData arg_life = op->life; 2634b3db8758Sblueswir1 2635c45cb8bbSRichard Henderson oi_next = op->next; 2636c896fe29Sbellard #ifdef CONFIG_PROFILER 263754604f74Saurel32 tcg_table_op_count[opc]++; 2638c896fe29Sbellard #endif 2639c45cb8bbSRichard Henderson 2640c896fe29Sbellard switch (opc) { 2641c896fe29Sbellard case INDEX_op_mov_i32: 2642c896fe29Sbellard case INDEX_op_mov_i64: 2643a1b3c48dSRichard Henderson tcg_reg_alloc_mov(s, def, args, arg_life); 2644c896fe29Sbellard break; 2645e8996ee0Sbellard case INDEX_op_movi_i32: 2646e8996ee0Sbellard case INDEX_op_movi_i64: 2647a1b3c48dSRichard Henderson tcg_reg_alloc_movi(s, args, arg_life); 2648e8996ee0Sbellard break; 2649765b842aSRichard Henderson case INDEX_op_insn_start: 2650fca8a500SRichard Henderson if (num_insns >= 0) { 2651fca8a500SRichard Henderson s->gen_insn_end_off[num_insns] = tcg_current_code_size(s); 2652fca8a500SRichard Henderson } 2653fca8a500SRichard Henderson num_insns++; 2654bad729e2SRichard Henderson for (i = 0; i < TARGET_INSN_START_WORDS; ++i) { 2655bad729e2SRichard Henderson target_ulong a; 2656bad729e2SRichard Henderson #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS 2657bad729e2SRichard Henderson a = ((target_ulong)args[i * 2 + 1] << 32) | args[i * 2]; 2658bad729e2SRichard Henderson #else 2659bad729e2SRichard Henderson a = args[i]; 2660bad729e2SRichard Henderson #endif 2661fca8a500SRichard Henderson s->gen_insn_data[num_insns][i] = a; 2662bad729e2SRichard Henderson } 2663c896fe29Sbellard break; 26645ff9d6a4Sbellard case INDEX_op_discard: 2665f8bf00f1SRichard Henderson temp_dead(s, &s->temps[args[0]]); 26665ff9d6a4Sbellard break; 2667c896fe29Sbellard case INDEX_op_set_label: 2668e8996ee0Sbellard tcg_reg_alloc_bb_end(s, s->reserved_regs); 2669bec16311SRichard Henderson tcg_out_label(s, arg_label(args[0]), s->code_ptr); 2670c896fe29Sbellard break; 2671c896fe29Sbellard case INDEX_op_call: 2672a1b3c48dSRichard Henderson tcg_reg_alloc_call(s, op->callo, op->calli, args, arg_life); 2673c45cb8bbSRichard Henderson break; 2674c896fe29Sbellard default: 267525c4d9ccSRichard Henderson /* Sanity check that we've not introduced any unhandled opcodes. */ 267625c4d9ccSRichard Henderson if (def->flags & TCG_OPF_NOT_PRESENT) { 267725c4d9ccSRichard Henderson tcg_abort(); 267825c4d9ccSRichard Henderson } 2679c896fe29Sbellard /* Note: in order to speed up the code, it would be much 2680c896fe29Sbellard faster to have specialized register allocator functions for 2681c896fe29Sbellard some common argument patterns */ 2682a1b3c48dSRichard Henderson tcg_reg_alloc_op(s, def, opc, args, arg_life); 2683c896fe29Sbellard break; 2684c896fe29Sbellard } 26858d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG 2686c896fe29Sbellard check_regs(s); 2687c896fe29Sbellard #endif 2688b125f9dcSRichard Henderson /* Test for (pending) buffer overflow. The assumption is that any 2689b125f9dcSRichard Henderson one operation beginning below the high water mark cannot overrun 2690b125f9dcSRichard Henderson the buffer completely. Thus we can test for overflow after 2691b125f9dcSRichard Henderson generating code without having to check during generation. */ 2692644da9b3SJohn Clarke if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) { 2693b125f9dcSRichard Henderson return -1; 2694b125f9dcSRichard Henderson } 2695c896fe29Sbellard } 2696fca8a500SRichard Henderson tcg_debug_assert(num_insns >= 0); 2697fca8a500SRichard Henderson s->gen_insn_end_off[num_insns] = tcg_current_code_size(s); 2698c45cb8bbSRichard Henderson 2699b76f0d8cSYeongkyoon Lee /* Generate TB finalization at the end of block */ 2700659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS 2701659ef5cbSRichard Henderson if (!tcg_out_ldst_finalize(s)) { 270223dceda6SRichard Henderson return -1; 270323dceda6SRichard Henderson } 2704659ef5cbSRichard Henderson #endif 2705*57a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 2706*57a26946SRichard Henderson if (!tcg_out_pool_finalize(s)) { 2707*57a26946SRichard Henderson return -1; 2708*57a26946SRichard Henderson } 2709*57a26946SRichard Henderson #endif 2710c896fe29Sbellard 2711c896fe29Sbellard /* flush instruction cache */ 27121813e175SRichard Henderson flush_icache_range((uintptr_t)s->code_buf, (uintptr_t)s->code_ptr); 27132aeabc08SStefan Weil 27141813e175SRichard Henderson return tcg_current_code_size(s); 2715c896fe29Sbellard } 2716c896fe29Sbellard 2717a23a9ec6Sbellard #ifdef CONFIG_PROFILER 2718405cf9ffSStefan Weil void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf) 2719a23a9ec6Sbellard { 2720a23a9ec6Sbellard TCGContext *s = &tcg_ctx; 2721fca8a500SRichard Henderson int64_t tb_count = s->tb_count; 2722fca8a500SRichard Henderson int64_t tb_div_count = tb_count ? tb_count : 1; 2723fca8a500SRichard Henderson int64_t tot = s->interm_time + s->code_time; 2724a23a9ec6Sbellard 2725a23a9ec6Sbellard cpu_fprintf(f, "JIT cycles %" PRId64 " (%0.3f s at 2.4 GHz)\n", 2726a23a9ec6Sbellard tot, tot / 2.4e9); 2727a23a9ec6Sbellard cpu_fprintf(f, "translated TBs %" PRId64 " (aborted=%" PRId64 " %0.1f%%)\n", 2728fca8a500SRichard Henderson tb_count, s->tb_count1 - tb_count, 2729fca8a500SRichard Henderson (double)(s->tb_count1 - s->tb_count) 2730fca8a500SRichard Henderson / (s->tb_count1 ? s->tb_count1 : 1) * 100.0); 2731a23a9ec6Sbellard cpu_fprintf(f, "avg ops/TB %0.1f max=%d\n", 2732fca8a500SRichard Henderson (double)s->op_count / tb_div_count, s->op_count_max); 2733a23a9ec6Sbellard cpu_fprintf(f, "deleted ops/TB %0.2f\n", 2734fca8a500SRichard Henderson (double)s->del_op_count / tb_div_count); 2735a23a9ec6Sbellard cpu_fprintf(f, "avg temps/TB %0.2f max=%d\n", 2736fca8a500SRichard Henderson (double)s->temp_count / tb_div_count, s->temp_count_max); 2737fca8a500SRichard Henderson cpu_fprintf(f, "avg host code/TB %0.1f\n", 2738fca8a500SRichard Henderson (double)s->code_out_len / tb_div_count); 2739fca8a500SRichard Henderson cpu_fprintf(f, "avg search data/TB %0.1f\n", 2740fca8a500SRichard Henderson (double)s->search_out_len / tb_div_count); 2741a23a9ec6Sbellard 2742a23a9ec6Sbellard cpu_fprintf(f, "cycles/op %0.1f\n", 2743a23a9ec6Sbellard s->op_count ? (double)tot / s->op_count : 0); 2744a23a9ec6Sbellard cpu_fprintf(f, "cycles/in byte %0.1f\n", 2745a23a9ec6Sbellard s->code_in_len ? (double)tot / s->code_in_len : 0); 2746a23a9ec6Sbellard cpu_fprintf(f, "cycles/out byte %0.1f\n", 2747a23a9ec6Sbellard s->code_out_len ? (double)tot / s->code_out_len : 0); 2748fca8a500SRichard Henderson cpu_fprintf(f, "cycles/search byte %0.1f\n", 2749fca8a500SRichard Henderson s->search_out_len ? (double)tot / s->search_out_len : 0); 2750fca8a500SRichard Henderson if (tot == 0) { 2751a23a9ec6Sbellard tot = 1; 2752fca8a500SRichard Henderson } 2753a23a9ec6Sbellard cpu_fprintf(f, " gen_interm time %0.1f%%\n", 2754a23a9ec6Sbellard (double)s->interm_time / tot * 100.0); 2755a23a9ec6Sbellard cpu_fprintf(f, " gen_code time %0.1f%%\n", 2756a23a9ec6Sbellard (double)s->code_time / tot * 100.0); 2757c5cc28ffSAurelien Jarno cpu_fprintf(f, "optim./code time %0.1f%%\n", 2758c5cc28ffSAurelien Jarno (double)s->opt_time / (s->code_time ? s->code_time : 1) 2759c5cc28ffSAurelien Jarno * 100.0); 2760a23a9ec6Sbellard cpu_fprintf(f, "liveness/code time %0.1f%%\n", 2761a23a9ec6Sbellard (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0); 2762a23a9ec6Sbellard cpu_fprintf(f, "cpu_restore count %" PRId64 "\n", 2763a23a9ec6Sbellard s->restore_count); 2764a23a9ec6Sbellard cpu_fprintf(f, " avg cycles %0.1f\n", 2765a23a9ec6Sbellard s->restore_count ? (double)s->restore_time / s->restore_count : 0); 2766a23a9ec6Sbellard } 2767a23a9ec6Sbellard #else 2768405cf9ffSStefan Weil void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf) 2769a23a9ec6Sbellard { 277024bf7b3aSbellard cpu_fprintf(f, "[TCG profiler not compiled]\n"); 2771a23a9ec6Sbellard } 2772a23a9ec6Sbellard #endif 2773813da627SRichard Henderson 2774813da627SRichard Henderson #ifdef ELF_HOST_MACHINE 27755872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things: 27765872bbf2SRichard Henderson 27775872bbf2SRichard Henderson (1) Define ELF_HOST_MACHINE to indicate both what value to 27785872bbf2SRichard Henderson put into the ELF image and to indicate support for the feature. 27795872bbf2SRichard Henderson 27805872bbf2SRichard Henderson (2) Define tcg_register_jit. This should create a buffer containing 27815872bbf2SRichard Henderson the contents of a .debug_frame section that describes the post- 27825872bbf2SRichard Henderson prologue unwind info for the tcg machine. 27835872bbf2SRichard Henderson 27845872bbf2SRichard Henderson (3) Call tcg_register_jit_int, with the constructed .debug_frame. 27855872bbf2SRichard Henderson */ 2786813da627SRichard Henderson 2787813da627SRichard Henderson /* Begin GDB interface. THE FOLLOWING MUST MATCH GDB DOCS. */ 2788813da627SRichard Henderson typedef enum { 2789813da627SRichard Henderson JIT_NOACTION = 0, 2790813da627SRichard Henderson JIT_REGISTER_FN, 2791813da627SRichard Henderson JIT_UNREGISTER_FN 2792813da627SRichard Henderson } jit_actions_t; 2793813da627SRichard Henderson 2794813da627SRichard Henderson struct jit_code_entry { 2795813da627SRichard Henderson struct jit_code_entry *next_entry; 2796813da627SRichard Henderson struct jit_code_entry *prev_entry; 2797813da627SRichard Henderson const void *symfile_addr; 2798813da627SRichard Henderson uint64_t symfile_size; 2799813da627SRichard Henderson }; 2800813da627SRichard Henderson 2801813da627SRichard Henderson struct jit_descriptor { 2802813da627SRichard Henderson uint32_t version; 2803813da627SRichard Henderson uint32_t action_flag; 2804813da627SRichard Henderson struct jit_code_entry *relevant_entry; 2805813da627SRichard Henderson struct jit_code_entry *first_entry; 2806813da627SRichard Henderson }; 2807813da627SRichard Henderson 2808813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline)); 2809813da627SRichard Henderson void __jit_debug_register_code(void) 2810813da627SRichard Henderson { 2811813da627SRichard Henderson asm(""); 2812813da627SRichard Henderson } 2813813da627SRichard Henderson 2814813da627SRichard Henderson /* Must statically initialize the version, because GDB may check 2815813da627SRichard Henderson the version before we can set it. */ 2816813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 }; 2817813da627SRichard Henderson 2818813da627SRichard Henderson /* End GDB interface. */ 2819813da627SRichard Henderson 2820813da627SRichard Henderson static int find_string(const char *strtab, const char *str) 2821813da627SRichard Henderson { 2822813da627SRichard Henderson const char *p = strtab + 1; 2823813da627SRichard Henderson 2824813da627SRichard Henderson while (1) { 2825813da627SRichard Henderson if (strcmp(p, str) == 0) { 2826813da627SRichard Henderson return p - strtab; 2827813da627SRichard Henderson } 2828813da627SRichard Henderson p += strlen(p) + 1; 2829813da627SRichard Henderson } 2830813da627SRichard Henderson } 2831813da627SRichard Henderson 28325872bbf2SRichard Henderson static void tcg_register_jit_int(void *buf_ptr, size_t buf_size, 28332c90784aSRichard Henderson const void *debug_frame, 28342c90784aSRichard Henderson size_t debug_frame_size) 2835813da627SRichard Henderson { 28365872bbf2SRichard Henderson struct __attribute__((packed)) DebugInfo { 28375872bbf2SRichard Henderson uint32_t len; 28385872bbf2SRichard Henderson uint16_t version; 28395872bbf2SRichard Henderson uint32_t abbrev; 28405872bbf2SRichard Henderson uint8_t ptr_size; 28415872bbf2SRichard Henderson uint8_t cu_die; 28425872bbf2SRichard Henderson uint16_t cu_lang; 28435872bbf2SRichard Henderson uintptr_t cu_low_pc; 28445872bbf2SRichard Henderson uintptr_t cu_high_pc; 28455872bbf2SRichard Henderson uint8_t fn_die; 28465872bbf2SRichard Henderson char fn_name[16]; 28475872bbf2SRichard Henderson uintptr_t fn_low_pc; 28485872bbf2SRichard Henderson uintptr_t fn_high_pc; 28495872bbf2SRichard Henderson uint8_t cu_eoc; 28505872bbf2SRichard Henderson }; 2851813da627SRichard Henderson 2852813da627SRichard Henderson struct ElfImage { 2853813da627SRichard Henderson ElfW(Ehdr) ehdr; 2854813da627SRichard Henderson ElfW(Phdr) phdr; 28555872bbf2SRichard Henderson ElfW(Shdr) shdr[7]; 28565872bbf2SRichard Henderson ElfW(Sym) sym[2]; 28575872bbf2SRichard Henderson struct DebugInfo di; 28585872bbf2SRichard Henderson uint8_t da[24]; 28595872bbf2SRichard Henderson char str[80]; 28605872bbf2SRichard Henderson }; 28615872bbf2SRichard Henderson 28625872bbf2SRichard Henderson struct ElfImage *img; 28635872bbf2SRichard Henderson 28645872bbf2SRichard Henderson static const struct ElfImage img_template = { 28655872bbf2SRichard Henderson .ehdr = { 28665872bbf2SRichard Henderson .e_ident[EI_MAG0] = ELFMAG0, 28675872bbf2SRichard Henderson .e_ident[EI_MAG1] = ELFMAG1, 28685872bbf2SRichard Henderson .e_ident[EI_MAG2] = ELFMAG2, 28695872bbf2SRichard Henderson .e_ident[EI_MAG3] = ELFMAG3, 28705872bbf2SRichard Henderson .e_ident[EI_CLASS] = ELF_CLASS, 28715872bbf2SRichard Henderson .e_ident[EI_DATA] = ELF_DATA, 28725872bbf2SRichard Henderson .e_ident[EI_VERSION] = EV_CURRENT, 28735872bbf2SRichard Henderson .e_type = ET_EXEC, 28745872bbf2SRichard Henderson .e_machine = ELF_HOST_MACHINE, 28755872bbf2SRichard Henderson .e_version = EV_CURRENT, 28765872bbf2SRichard Henderson .e_phoff = offsetof(struct ElfImage, phdr), 28775872bbf2SRichard Henderson .e_shoff = offsetof(struct ElfImage, shdr), 28785872bbf2SRichard Henderson .e_ehsize = sizeof(ElfW(Shdr)), 28795872bbf2SRichard Henderson .e_phentsize = sizeof(ElfW(Phdr)), 28805872bbf2SRichard Henderson .e_phnum = 1, 28815872bbf2SRichard Henderson .e_shentsize = sizeof(ElfW(Shdr)), 28825872bbf2SRichard Henderson .e_shnum = ARRAY_SIZE(img->shdr), 28835872bbf2SRichard Henderson .e_shstrndx = ARRAY_SIZE(img->shdr) - 1, 2884abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS 2885abbb3eaeSRichard Henderson .e_flags = ELF_HOST_FLAGS, 2886abbb3eaeSRichard Henderson #endif 2887abbb3eaeSRichard Henderson #ifdef ELF_OSABI 2888abbb3eaeSRichard Henderson .e_ident[EI_OSABI] = ELF_OSABI, 2889abbb3eaeSRichard Henderson #endif 28905872bbf2SRichard Henderson }, 28915872bbf2SRichard Henderson .phdr = { 28925872bbf2SRichard Henderson .p_type = PT_LOAD, 28935872bbf2SRichard Henderson .p_flags = PF_X, 28945872bbf2SRichard Henderson }, 28955872bbf2SRichard Henderson .shdr = { 28965872bbf2SRichard Henderson [0] = { .sh_type = SHT_NULL }, 28975872bbf2SRichard Henderson /* Trick: The contents of code_gen_buffer are not present in 28985872bbf2SRichard Henderson this fake ELF file; that got allocated elsewhere. Therefore 28995872bbf2SRichard Henderson we mark .text as SHT_NOBITS (similar to .bss) so that readers 29005872bbf2SRichard Henderson will not look for contents. We can record any address. */ 29015872bbf2SRichard Henderson [1] = { /* .text */ 29025872bbf2SRichard Henderson .sh_type = SHT_NOBITS, 29035872bbf2SRichard Henderson .sh_flags = SHF_EXECINSTR | SHF_ALLOC, 29045872bbf2SRichard Henderson }, 29055872bbf2SRichard Henderson [2] = { /* .debug_info */ 29065872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 29075872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, di), 29085872bbf2SRichard Henderson .sh_size = sizeof(struct DebugInfo), 29095872bbf2SRichard Henderson }, 29105872bbf2SRichard Henderson [3] = { /* .debug_abbrev */ 29115872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 29125872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, da), 29135872bbf2SRichard Henderson .sh_size = sizeof(img->da), 29145872bbf2SRichard Henderson }, 29155872bbf2SRichard Henderson [4] = { /* .debug_frame */ 29165872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 29175872bbf2SRichard Henderson .sh_offset = sizeof(struct ElfImage), 29185872bbf2SRichard Henderson }, 29195872bbf2SRichard Henderson [5] = { /* .symtab */ 29205872bbf2SRichard Henderson .sh_type = SHT_SYMTAB, 29215872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, sym), 29225872bbf2SRichard Henderson .sh_size = sizeof(img->sym), 29235872bbf2SRichard Henderson .sh_info = 1, 29245872bbf2SRichard Henderson .sh_link = ARRAY_SIZE(img->shdr) - 1, 29255872bbf2SRichard Henderson .sh_entsize = sizeof(ElfW(Sym)), 29265872bbf2SRichard Henderson }, 29275872bbf2SRichard Henderson [6] = { /* .strtab */ 29285872bbf2SRichard Henderson .sh_type = SHT_STRTAB, 29295872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, str), 29305872bbf2SRichard Henderson .sh_size = sizeof(img->str), 29315872bbf2SRichard Henderson } 29325872bbf2SRichard Henderson }, 29335872bbf2SRichard Henderson .sym = { 29345872bbf2SRichard Henderson [1] = { /* code_gen_buffer */ 29355872bbf2SRichard Henderson .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC), 29365872bbf2SRichard Henderson .st_shndx = 1, 29375872bbf2SRichard Henderson } 29385872bbf2SRichard Henderson }, 29395872bbf2SRichard Henderson .di = { 29405872bbf2SRichard Henderson .len = sizeof(struct DebugInfo) - 4, 29415872bbf2SRichard Henderson .version = 2, 29425872bbf2SRichard Henderson .ptr_size = sizeof(void *), 29435872bbf2SRichard Henderson .cu_die = 1, 29445872bbf2SRichard Henderson .cu_lang = 0x8001, /* DW_LANG_Mips_Assembler */ 29455872bbf2SRichard Henderson .fn_die = 2, 29465872bbf2SRichard Henderson .fn_name = "code_gen_buffer" 29475872bbf2SRichard Henderson }, 29485872bbf2SRichard Henderson .da = { 29495872bbf2SRichard Henderson 1, /* abbrev number (the cu) */ 29505872bbf2SRichard Henderson 0x11, 1, /* DW_TAG_compile_unit, has children */ 29515872bbf2SRichard Henderson 0x13, 0x5, /* DW_AT_language, DW_FORM_data2 */ 29525872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */ 29535872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */ 29545872bbf2SRichard Henderson 0, 0, /* end of abbrev */ 29555872bbf2SRichard Henderson 2, /* abbrev number (the fn) */ 29565872bbf2SRichard Henderson 0x2e, 0, /* DW_TAG_subprogram, no children */ 29575872bbf2SRichard Henderson 0x3, 0x8, /* DW_AT_name, DW_FORM_string */ 29585872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */ 29595872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */ 29605872bbf2SRichard Henderson 0, 0, /* end of abbrev */ 29615872bbf2SRichard Henderson 0 /* no more abbrev */ 29625872bbf2SRichard Henderson }, 29635872bbf2SRichard Henderson .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0" 29645872bbf2SRichard Henderson ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer", 2965813da627SRichard Henderson }; 2966813da627SRichard Henderson 2967813da627SRichard Henderson /* We only need a single jit entry; statically allocate it. */ 2968813da627SRichard Henderson static struct jit_code_entry one_entry; 2969813da627SRichard Henderson 29705872bbf2SRichard Henderson uintptr_t buf = (uintptr_t)buf_ptr; 2971813da627SRichard Henderson size_t img_size = sizeof(struct ElfImage) + debug_frame_size; 29722c90784aSRichard Henderson DebugFrameHeader *dfh; 2973813da627SRichard Henderson 29745872bbf2SRichard Henderson img = g_malloc(img_size); 29755872bbf2SRichard Henderson *img = img_template; 2976813da627SRichard Henderson 29775872bbf2SRichard Henderson img->phdr.p_vaddr = buf; 29785872bbf2SRichard Henderson img->phdr.p_paddr = buf; 29795872bbf2SRichard Henderson img->phdr.p_memsz = buf_size; 2980813da627SRichard Henderson 29815872bbf2SRichard Henderson img->shdr[1].sh_name = find_string(img->str, ".text"); 29825872bbf2SRichard Henderson img->shdr[1].sh_addr = buf; 29835872bbf2SRichard Henderson img->shdr[1].sh_size = buf_size; 2984813da627SRichard Henderson 29855872bbf2SRichard Henderson img->shdr[2].sh_name = find_string(img->str, ".debug_info"); 29865872bbf2SRichard Henderson img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev"); 29875872bbf2SRichard Henderson 29885872bbf2SRichard Henderson img->shdr[4].sh_name = find_string(img->str, ".debug_frame"); 29895872bbf2SRichard Henderson img->shdr[4].sh_size = debug_frame_size; 29905872bbf2SRichard Henderson 29915872bbf2SRichard Henderson img->shdr[5].sh_name = find_string(img->str, ".symtab"); 29925872bbf2SRichard Henderson img->shdr[6].sh_name = find_string(img->str, ".strtab"); 29935872bbf2SRichard Henderson 29945872bbf2SRichard Henderson img->sym[1].st_name = find_string(img->str, "code_gen_buffer"); 29955872bbf2SRichard Henderson img->sym[1].st_value = buf; 29965872bbf2SRichard Henderson img->sym[1].st_size = buf_size; 29975872bbf2SRichard Henderson 29985872bbf2SRichard Henderson img->di.cu_low_pc = buf; 299945aba097SRichard Henderson img->di.cu_high_pc = buf + buf_size; 30005872bbf2SRichard Henderson img->di.fn_low_pc = buf; 300145aba097SRichard Henderson img->di.fn_high_pc = buf + buf_size; 3002813da627SRichard Henderson 30032c90784aSRichard Henderson dfh = (DebugFrameHeader *)(img + 1); 30042c90784aSRichard Henderson memcpy(dfh, debug_frame, debug_frame_size); 30052c90784aSRichard Henderson dfh->fde.func_start = buf; 30062c90784aSRichard Henderson dfh->fde.func_len = buf_size; 30072c90784aSRichard Henderson 3008813da627SRichard Henderson #ifdef DEBUG_JIT 3009813da627SRichard Henderson /* Enable this block to be able to debug the ELF image file creation. 3010813da627SRichard Henderson One can use readelf, objdump, or other inspection utilities. */ 3011813da627SRichard Henderson { 3012813da627SRichard Henderson FILE *f = fopen("/tmp/qemu.jit", "w+b"); 3013813da627SRichard Henderson if (f) { 30145872bbf2SRichard Henderson if (fwrite(img, img_size, 1, f) != img_size) { 3015813da627SRichard Henderson /* Avoid stupid unused return value warning for fwrite. */ 3016813da627SRichard Henderson } 3017813da627SRichard Henderson fclose(f); 3018813da627SRichard Henderson } 3019813da627SRichard Henderson } 3020813da627SRichard Henderson #endif 3021813da627SRichard Henderson 3022813da627SRichard Henderson one_entry.symfile_addr = img; 3023813da627SRichard Henderson one_entry.symfile_size = img_size; 3024813da627SRichard Henderson 3025813da627SRichard Henderson __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; 3026813da627SRichard Henderson __jit_debug_descriptor.relevant_entry = &one_entry; 3027813da627SRichard Henderson __jit_debug_descriptor.first_entry = &one_entry; 3028813da627SRichard Henderson __jit_debug_register_code(); 3029813da627SRichard Henderson } 3030813da627SRichard Henderson #else 30315872bbf2SRichard Henderson /* No support for the feature. Provide the entry point expected by exec.c, 30325872bbf2SRichard Henderson and implement the internal function we declared earlier. */ 3033813da627SRichard Henderson 3034813da627SRichard Henderson static void tcg_register_jit_int(void *buf, size_t size, 30352c90784aSRichard Henderson const void *debug_frame, 30362c90784aSRichard Henderson size_t debug_frame_size) 3037813da627SRichard Henderson { 3038813da627SRichard Henderson } 3039813da627SRichard Henderson 3040813da627SRichard Henderson void tcg_register_jit(void *buf, size_t buf_size) 3041813da627SRichard Henderson { 3042813da627SRichard Henderson } 3043813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */ 3044