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. */ 99*069ea736SRichard Henderson static const char *target_parse_constraint(TCGArgConstraint *ct, 100*069ea736SRichard 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); 1159ecefc84SRichard Henderson static void tcg_out_tb_init(TCGContext *s); 11623dceda6SRichard Henderson static bool tcg_out_tb_finalize(TCGContext *s); 1179ecefc84SRichard Henderson 118c0ad3001SStefan Weil 119c896fe29Sbellard 120b1d8e52eSblueswir1 static TCGRegSet tcg_target_available_regs[2]; 121b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs; 122c896fe29Sbellard 1231813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1 1244196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v) 125c896fe29Sbellard { 126c896fe29Sbellard *s->code_ptr++ = v; 127c896fe29Sbellard } 128c896fe29Sbellard 1294196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p, 1304196dca6SPeter Maydell uint8_t v) 1315c53bb81SPeter Maydell { 1321813e175SRichard Henderson *p = v; 1335c53bb81SPeter Maydell } 1341813e175SRichard Henderson #endif 1355c53bb81SPeter Maydell 1361813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2 1374196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v) 138c896fe29Sbellard { 1391813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 2) { 1401813e175SRichard Henderson *s->code_ptr++ = v; 1411813e175SRichard Henderson } else { 1421813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 1434387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 1441813e175SRichard Henderson s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE); 1451813e175SRichard Henderson } 146c896fe29Sbellard } 147c896fe29Sbellard 1484196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p, 1494196dca6SPeter Maydell uint16_t v) 1505c53bb81SPeter Maydell { 1511813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 2) { 1521813e175SRichard Henderson *p = v; 1531813e175SRichard Henderson } else { 1545c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 1555c53bb81SPeter Maydell } 1561813e175SRichard Henderson } 1571813e175SRichard Henderson #endif 1585c53bb81SPeter Maydell 1591813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4 1604196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v) 161c896fe29Sbellard { 1621813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 4) { 1631813e175SRichard Henderson *s->code_ptr++ = v; 1641813e175SRichard Henderson } else { 1651813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 1664387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 1671813e175SRichard Henderson s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE); 1681813e175SRichard Henderson } 169c896fe29Sbellard } 170c896fe29Sbellard 1714196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p, 1724196dca6SPeter Maydell uint32_t v) 1735c53bb81SPeter Maydell { 1741813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 4) { 1751813e175SRichard Henderson *p = v; 1761813e175SRichard Henderson } else { 1775c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 1785c53bb81SPeter Maydell } 1791813e175SRichard Henderson } 1801813e175SRichard Henderson #endif 1815c53bb81SPeter Maydell 1821813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 8 1834196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v) 184ac26eb69SRichard Henderson { 1851813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 8) { 1861813e175SRichard Henderson *s->code_ptr++ = v; 1871813e175SRichard Henderson } else { 1881813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 1894387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 1901813e175SRichard Henderson s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE); 1911813e175SRichard Henderson } 192ac26eb69SRichard Henderson } 193ac26eb69SRichard Henderson 1944196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p, 1954196dca6SPeter Maydell uint64_t v) 1965c53bb81SPeter Maydell { 1971813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 8) { 1981813e175SRichard Henderson *p = v; 1991813e175SRichard Henderson } else { 2005c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 2015c53bb81SPeter Maydell } 2021813e175SRichard Henderson } 2031813e175SRichard Henderson #endif 2045c53bb81SPeter Maydell 205c896fe29Sbellard /* label relocation processing */ 206c896fe29Sbellard 2071813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type, 208bec16311SRichard Henderson TCGLabel *l, intptr_t addend) 209c896fe29Sbellard { 210c896fe29Sbellard TCGRelocation *r; 211c896fe29Sbellard 212c896fe29Sbellard if (l->has_value) { 213623e265cSpbrook /* FIXME: This may break relocations on RISC targets that 214623e265cSpbrook modify instruction fields in place. The caller may not have 215623e265cSpbrook written the initial value. */ 216f54b3f92Saurel32 patch_reloc(code_ptr, type, l->u.value, addend); 217c896fe29Sbellard } else { 218c896fe29Sbellard /* add a new relocation entry */ 219c896fe29Sbellard r = tcg_malloc(sizeof(TCGRelocation)); 220c896fe29Sbellard r->type = type; 221c896fe29Sbellard r->ptr = code_ptr; 222c896fe29Sbellard r->addend = addend; 223c896fe29Sbellard r->next = l->u.first_reloc; 224c896fe29Sbellard l->u.first_reloc = r; 225c896fe29Sbellard } 226c896fe29Sbellard } 227c896fe29Sbellard 228bec16311SRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l, tcg_insn_unit *ptr) 229c896fe29Sbellard { 2302ba7fae2SRichard Henderson intptr_t value = (intptr_t)ptr; 2311813e175SRichard Henderson TCGRelocation *r; 232c896fe29Sbellard 233eabb7b91SAurelien Jarno tcg_debug_assert(!l->has_value); 2341813e175SRichard Henderson 2351813e175SRichard Henderson for (r = l->u.first_reloc; r != NULL; r = r->next) { 236f54b3f92Saurel32 patch_reloc(r->ptr, r->type, value, r->addend); 237c896fe29Sbellard } 2381813e175SRichard Henderson 239c896fe29Sbellard l->has_value = 1; 2401813e175SRichard Henderson l->u.value_ptr = ptr; 241c896fe29Sbellard } 242c896fe29Sbellard 24342a268c2SRichard Henderson TCGLabel *gen_new_label(void) 244c896fe29Sbellard { 245c896fe29Sbellard TCGContext *s = &tcg_ctx; 24651e3972cSRichard Henderson TCGLabel *l = tcg_malloc(sizeof(TCGLabel)); 247c896fe29Sbellard 24851e3972cSRichard Henderson *l = (TCGLabel){ 24951e3972cSRichard Henderson .id = s->nb_labels++ 25051e3972cSRichard Henderson }; 25142a268c2SRichard Henderson 25242a268c2SRichard Henderson return l; 253c896fe29Sbellard } 254c896fe29Sbellard 255ce151109SPeter Maydell #include "tcg-target.inc.c" 256c896fe29Sbellard 257c896fe29Sbellard /* pool based memory allocation */ 258c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size) 259c896fe29Sbellard { 260c896fe29Sbellard TCGPool *p; 261c896fe29Sbellard int pool_size; 262c896fe29Sbellard 263c896fe29Sbellard if (size > TCG_POOL_CHUNK_SIZE) { 264c896fe29Sbellard /* big malloc: insert a new pool (XXX: could optimize) */ 2657267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + size); 266c896fe29Sbellard p->size = size; 2674055299eSKirill Batuzov p->next = s->pool_first_large; 2684055299eSKirill Batuzov s->pool_first_large = p; 2694055299eSKirill Batuzov return p->data; 270c896fe29Sbellard } else { 271c896fe29Sbellard p = s->pool_current; 272c896fe29Sbellard if (!p) { 273c896fe29Sbellard p = s->pool_first; 274c896fe29Sbellard if (!p) 275c896fe29Sbellard goto new_pool; 276c896fe29Sbellard } else { 277c896fe29Sbellard if (!p->next) { 278c896fe29Sbellard new_pool: 279c896fe29Sbellard pool_size = TCG_POOL_CHUNK_SIZE; 2807267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + pool_size); 281c896fe29Sbellard p->size = pool_size; 282c896fe29Sbellard p->next = NULL; 283c896fe29Sbellard if (s->pool_current) 284c896fe29Sbellard s->pool_current->next = p; 285c896fe29Sbellard else 286c896fe29Sbellard s->pool_first = p; 287c896fe29Sbellard } else { 288c896fe29Sbellard p = p->next; 289c896fe29Sbellard } 290c896fe29Sbellard } 291c896fe29Sbellard } 292c896fe29Sbellard s->pool_current = p; 293c896fe29Sbellard s->pool_cur = p->data + size; 294c896fe29Sbellard s->pool_end = p->data + p->size; 295c896fe29Sbellard return p->data; 296c896fe29Sbellard } 297c896fe29Sbellard 298c896fe29Sbellard void tcg_pool_reset(TCGContext *s) 299c896fe29Sbellard { 3004055299eSKirill Batuzov TCGPool *p, *t; 3014055299eSKirill Batuzov for (p = s->pool_first_large; p; p = t) { 3024055299eSKirill Batuzov t = p->next; 3034055299eSKirill Batuzov g_free(p); 3044055299eSKirill Batuzov } 3054055299eSKirill Batuzov s->pool_first_large = NULL; 306c896fe29Sbellard s->pool_cur = s->pool_end = NULL; 307c896fe29Sbellard s->pool_current = NULL; 308c896fe29Sbellard } 309c896fe29Sbellard 310100b5e01SRichard Henderson typedef struct TCGHelperInfo { 311100b5e01SRichard Henderson void *func; 312100b5e01SRichard Henderson const char *name; 313afb49896SRichard Henderson unsigned flags; 314afb49896SRichard Henderson unsigned sizemask; 315100b5e01SRichard Henderson } TCGHelperInfo; 316100b5e01SRichard Henderson 3172ef6175aSRichard Henderson #include "exec/helper-proto.h" 3182ef6175aSRichard Henderson 319100b5e01SRichard Henderson static const TCGHelperInfo all_helpers[] = { 3202ef6175aSRichard Henderson #include "exec/helper-tcg.h" 321100b5e01SRichard Henderson }; 322100b5e01SRichard Henderson 32391478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)]; 324f69d277eSRichard Henderson static void process_op_defs(TCGContext *s); 32591478cefSRichard Henderson 326c896fe29Sbellard void tcg_context_init(TCGContext *s) 327c896fe29Sbellard { 328100b5e01SRichard Henderson int op, total_args, n, i; 329c896fe29Sbellard TCGOpDef *def; 330c896fe29Sbellard TCGArgConstraint *args_ct; 331c896fe29Sbellard int *sorted_args; 33284fd9dd3SRichard Henderson GHashTable *helper_table; 333c896fe29Sbellard 334c896fe29Sbellard memset(s, 0, sizeof(*s)); 335c896fe29Sbellard s->nb_globals = 0; 336c896fe29Sbellard 337c896fe29Sbellard /* Count total number of arguments and allocate the corresponding 338c896fe29Sbellard space */ 339c896fe29Sbellard total_args = 0; 340c896fe29Sbellard for(op = 0; op < NB_OPS; op++) { 341c896fe29Sbellard def = &tcg_op_defs[op]; 342c896fe29Sbellard n = def->nb_iargs + def->nb_oargs; 343c896fe29Sbellard total_args += n; 344c896fe29Sbellard } 345c896fe29Sbellard 3467267c094SAnthony Liguori args_ct = g_malloc(sizeof(TCGArgConstraint) * total_args); 3477267c094SAnthony Liguori sorted_args = g_malloc(sizeof(int) * total_args); 348c896fe29Sbellard 349c896fe29Sbellard for(op = 0; op < NB_OPS; op++) { 350c896fe29Sbellard def = &tcg_op_defs[op]; 351c896fe29Sbellard def->args_ct = args_ct; 352c896fe29Sbellard def->sorted_args = sorted_args; 353c896fe29Sbellard n = def->nb_iargs + def->nb_oargs; 354c896fe29Sbellard sorted_args += n; 355c896fe29Sbellard args_ct += n; 356c896fe29Sbellard } 357c896fe29Sbellard 3585cd8f621SRichard Henderson /* Register helpers. */ 35984fd9dd3SRichard Henderson /* Use g_direct_hash/equal for direct pointer comparisons on func. */ 36084fd9dd3SRichard Henderson s->helpers = helper_table = g_hash_table_new(NULL, NULL); 36184fd9dd3SRichard Henderson 362100b5e01SRichard Henderson for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) { 36384fd9dd3SRichard Henderson g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func, 36472866e82SRichard Henderson (gpointer)&all_helpers[i]); 365100b5e01SRichard Henderson } 3665cd8f621SRichard Henderson 367c896fe29Sbellard tcg_target_init(s); 368f69d277eSRichard Henderson process_op_defs(s); 36991478cefSRichard Henderson 37091478cefSRichard Henderson /* Reverse the order of the saved registers, assuming they're all at 37191478cefSRichard Henderson the start of tcg_target_reg_alloc_order. */ 37291478cefSRichard Henderson for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) { 37391478cefSRichard Henderson int r = tcg_target_reg_alloc_order[n]; 37491478cefSRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) { 37591478cefSRichard Henderson break; 37691478cefSRichard Henderson } 37791478cefSRichard Henderson } 37891478cefSRichard Henderson for (i = 0; i < n; ++i) { 37991478cefSRichard Henderson indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i]; 38091478cefSRichard Henderson } 38191478cefSRichard Henderson for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) { 38291478cefSRichard Henderson indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i]; 38391478cefSRichard Henderson } 3849002ec79SRichard Henderson } 385b03cce8eSbellard 3869002ec79SRichard Henderson void tcg_prologue_init(TCGContext *s) 3879002ec79SRichard Henderson { 3888163b749SRichard Henderson size_t prologue_size, total_size; 3898163b749SRichard Henderson void *buf0, *buf1; 3908163b749SRichard Henderson 3918163b749SRichard Henderson /* Put the prologue at the beginning of code_gen_buffer. */ 3928163b749SRichard Henderson buf0 = s->code_gen_buffer; 3938163b749SRichard Henderson s->code_ptr = buf0; 3948163b749SRichard Henderson s->code_buf = buf0; 3958163b749SRichard Henderson s->code_gen_prologue = buf0; 3968163b749SRichard Henderson 3978163b749SRichard Henderson /* Generate the prologue. */ 398b03cce8eSbellard tcg_target_qemu_prologue(s); 3998163b749SRichard Henderson buf1 = s->code_ptr; 4008163b749SRichard Henderson flush_icache_range((uintptr_t)buf0, (uintptr_t)buf1); 4018163b749SRichard Henderson 4028163b749SRichard Henderson /* Deduct the prologue from the buffer. */ 4038163b749SRichard Henderson prologue_size = tcg_current_code_size(s); 4048163b749SRichard Henderson s->code_gen_ptr = buf1; 4058163b749SRichard Henderson s->code_gen_buffer = buf1; 4068163b749SRichard Henderson s->code_buf = buf1; 4078163b749SRichard Henderson total_size = s->code_gen_buffer_size - prologue_size; 4088163b749SRichard Henderson s->code_gen_buffer_size = total_size; 4098163b749SRichard Henderson 410b125f9dcSRichard Henderson /* Compute a high-water mark, at which we voluntarily flush the buffer 411b125f9dcSRichard Henderson and start over. The size here is arbitrary, significantly larger 412b125f9dcSRichard Henderson than we expect the code generation for any one opcode to require. */ 41323dceda6SRichard Henderson s->code_gen_highwater = s->code_gen_buffer + (total_size - 1024); 4148163b749SRichard Henderson 4158163b749SRichard Henderson tcg_register_jit(s->code_gen_buffer, total_size); 416d6b64b2bSRichard Henderson 417d6b64b2bSRichard Henderson #ifdef DEBUG_DISAS 418d6b64b2bSRichard Henderson if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) { 4191ee73216SRichard Henderson qemu_log_lock(); 4208163b749SRichard Henderson qemu_log("PROLOGUE: [size=%zu]\n", prologue_size); 4218163b749SRichard Henderson log_disas(buf0, prologue_size); 422d6b64b2bSRichard Henderson qemu_log("\n"); 423d6b64b2bSRichard Henderson qemu_log_flush(); 4241ee73216SRichard Henderson qemu_log_unlock(); 425d6b64b2bSRichard Henderson } 426d6b64b2bSRichard Henderson #endif 427c896fe29Sbellard } 428c896fe29Sbellard 429c896fe29Sbellard void tcg_func_start(TCGContext *s) 430c896fe29Sbellard { 431c896fe29Sbellard tcg_pool_reset(s); 432c896fe29Sbellard s->nb_temps = s->nb_globals; 4330ec9eabcSRichard Henderson 4340ec9eabcSRichard Henderson /* No temps have been previously allocated for size or locality. */ 4350ec9eabcSRichard Henderson memset(s->free_temps, 0, sizeof(s->free_temps)); 4360ec9eabcSRichard Henderson 437c896fe29Sbellard s->nb_labels = 0; 438c896fe29Sbellard s->current_frame_offset = s->frame_start; 439c896fe29Sbellard 4400a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG 4410a209d4bSRichard Henderson s->goto_tb_issue_mask = 0; 4420a209d4bSRichard Henderson #endif 4430a209d4bSRichard Henderson 444dcb8e758SRichard Henderson s->gen_op_buf[0].next = 1; 445dcb8e758SRichard Henderson s->gen_op_buf[0].prev = 0; 446dcb8e758SRichard Henderson s->gen_next_op_idx = 1; 447c45cb8bbSRichard Henderson s->gen_next_parm_idx = 0; 448b76f0d8cSYeongkyoon Lee 4499ecefc84SRichard Henderson s->be = tcg_malloc(sizeof(TCGBackendData)); 450c896fe29Sbellard } 451c896fe29Sbellard 4527ca4b752SRichard Henderson static inline int temp_idx(TCGContext *s, TCGTemp *ts) 453c896fe29Sbellard { 4547ca4b752SRichard Henderson ptrdiff_t n = ts - s->temps; 4557ca4b752SRichard Henderson tcg_debug_assert(n >= 0 && n < s->nb_temps); 4567ca4b752SRichard Henderson return n; 4577ca4b752SRichard Henderson } 4587ca4b752SRichard Henderson 4597ca4b752SRichard Henderson static inline TCGTemp *tcg_temp_alloc(TCGContext *s) 4607ca4b752SRichard Henderson { 4617ca4b752SRichard Henderson int n = s->nb_temps++; 4627ca4b752SRichard Henderson tcg_debug_assert(n < TCG_MAX_TEMPS); 4637ca4b752SRichard Henderson return memset(&s->temps[n], 0, sizeof(TCGTemp)); 4647ca4b752SRichard Henderson } 4657ca4b752SRichard Henderson 4667ca4b752SRichard Henderson static inline TCGTemp *tcg_global_alloc(TCGContext *s) 4677ca4b752SRichard Henderson { 4687ca4b752SRichard Henderson tcg_debug_assert(s->nb_globals == s->nb_temps); 4697ca4b752SRichard Henderson s->nb_globals++; 4707ca4b752SRichard Henderson return tcg_temp_alloc(s); 471c896fe29Sbellard } 472c896fe29Sbellard 473b3a62939SRichard Henderson static int tcg_global_reg_new_internal(TCGContext *s, TCGType type, 474b6638662SRichard Henderson TCGReg reg, const char *name) 475c896fe29Sbellard { 476c896fe29Sbellard TCGTemp *ts; 477c896fe29Sbellard 478b3a62939SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type != TCG_TYPE_I32) { 479c896fe29Sbellard tcg_abort(); 480b3a62939SRichard Henderson } 4817ca4b752SRichard Henderson 4827ca4b752SRichard Henderson ts = tcg_global_alloc(s); 483c896fe29Sbellard ts->base_type = type; 484c896fe29Sbellard ts->type = type; 485c896fe29Sbellard ts->fixed_reg = 1; 486c896fe29Sbellard ts->reg = reg; 487c896fe29Sbellard ts->name = name; 488c896fe29Sbellard tcg_regset_set_reg(s->reserved_regs, reg); 4897ca4b752SRichard Henderson 4907ca4b752SRichard Henderson return temp_idx(s, ts); 491a7812ae4Spbrook } 492a7812ae4Spbrook 493b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size) 494a7812ae4Spbrook { 495a7812ae4Spbrook int idx; 496b3a62939SRichard Henderson s->frame_start = start; 497b3a62939SRichard Henderson s->frame_end = start + size; 498b3a62939SRichard Henderson idx = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame"); 499b3a62939SRichard Henderson s->frame_temp = &s->temps[idx]; 500b3a62939SRichard Henderson } 501a7812ae4Spbrook 502b6638662SRichard Henderson TCGv_i32 tcg_global_reg_new_i32(TCGReg reg, const char *name) 503b3a62939SRichard Henderson { 504b3a62939SRichard Henderson TCGContext *s = &tcg_ctx; 505b3a62939SRichard Henderson int idx; 506b3a62939SRichard Henderson 507b3a62939SRichard Henderson if (tcg_regset_test_reg(s->reserved_regs, reg)) { 508b3a62939SRichard Henderson tcg_abort(); 509b3a62939SRichard Henderson } 510b3a62939SRichard Henderson idx = tcg_global_reg_new_internal(s, TCG_TYPE_I32, reg, name); 511a7812ae4Spbrook return MAKE_TCGV_I32(idx); 512a7812ae4Spbrook } 513a7812ae4Spbrook 514b6638662SRichard Henderson TCGv_i64 tcg_global_reg_new_i64(TCGReg reg, const char *name) 515a7812ae4Spbrook { 516b3a62939SRichard Henderson TCGContext *s = &tcg_ctx; 517a7812ae4Spbrook int idx; 518a7812ae4Spbrook 519b3a62939SRichard Henderson if (tcg_regset_test_reg(s->reserved_regs, reg)) { 520b3a62939SRichard Henderson tcg_abort(); 521b3a62939SRichard Henderson } 522b3a62939SRichard Henderson idx = tcg_global_reg_new_internal(s, TCG_TYPE_I64, reg, name); 523a7812ae4Spbrook return MAKE_TCGV_I64(idx); 524c896fe29Sbellard } 525c896fe29Sbellard 526e1ccc054SRichard Henderson int tcg_global_mem_new_internal(TCGType type, TCGv_ptr base, 527e1ccc054SRichard Henderson intptr_t offset, const char *name) 528c896fe29Sbellard { 529c896fe29Sbellard TCGContext *s = &tcg_ctx; 5307ca4b752SRichard Henderson TCGTemp *base_ts = &s->temps[GET_TCGV_PTR(base)]; 5317ca4b752SRichard Henderson TCGTemp *ts = tcg_global_alloc(s); 532b3915dbbSRichard Henderson int indirect_reg = 0, bigendian = 0; 5337ca4b752SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 5347ca4b752SRichard Henderson bigendian = 1; 5357ca4b752SRichard Henderson #endif 536c896fe29Sbellard 537b3915dbbSRichard Henderson if (!base_ts->fixed_reg) { 5385a18407fSRichard Henderson /* We do not support double-indirect registers. */ 5395a18407fSRichard Henderson tcg_debug_assert(!base_ts->indirect_reg); 540b3915dbbSRichard Henderson base_ts->indirect_base = 1; 5415a18407fSRichard Henderson s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64 5425a18407fSRichard Henderson ? 2 : 1); 5435a18407fSRichard Henderson indirect_reg = 1; 544b3915dbbSRichard Henderson } 545b3915dbbSRichard Henderson 5467ca4b752SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { 5477ca4b752SRichard Henderson TCGTemp *ts2 = tcg_global_alloc(s); 548c896fe29Sbellard char buf[64]; 5497ca4b752SRichard Henderson 5507ca4b752SRichard Henderson ts->base_type = TCG_TYPE_I64; 551c896fe29Sbellard ts->type = TCG_TYPE_I32; 552b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg; 553c896fe29Sbellard ts->mem_allocated = 1; 554b3a62939SRichard Henderson ts->mem_base = base_ts; 5557ca4b752SRichard Henderson ts->mem_offset = offset + bigendian * 4; 556c896fe29Sbellard pstrcpy(buf, sizeof(buf), name); 557c896fe29Sbellard pstrcat(buf, sizeof(buf), "_0"); 558c896fe29Sbellard ts->name = strdup(buf); 559c896fe29Sbellard 5607ca4b752SRichard Henderson tcg_debug_assert(ts2 == ts + 1); 5617ca4b752SRichard Henderson ts2->base_type = TCG_TYPE_I64; 5627ca4b752SRichard Henderson ts2->type = TCG_TYPE_I32; 563b3915dbbSRichard Henderson ts2->indirect_reg = indirect_reg; 5647ca4b752SRichard Henderson ts2->mem_allocated = 1; 5657ca4b752SRichard Henderson ts2->mem_base = base_ts; 5667ca4b752SRichard Henderson ts2->mem_offset = offset + (1 - bigendian) * 4; 567c896fe29Sbellard pstrcpy(buf, sizeof(buf), name); 568c896fe29Sbellard pstrcat(buf, sizeof(buf), "_1"); 569120c1084SRichard Henderson ts2->name = strdup(buf); 5707ca4b752SRichard Henderson } else { 571c896fe29Sbellard ts->base_type = type; 572c896fe29Sbellard ts->type = type; 573b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg; 574c896fe29Sbellard ts->mem_allocated = 1; 575b3a62939SRichard Henderson ts->mem_base = base_ts; 576c896fe29Sbellard ts->mem_offset = offset; 577c896fe29Sbellard ts->name = name; 578c896fe29Sbellard } 5797ca4b752SRichard Henderson return temp_idx(s, ts); 580c896fe29Sbellard } 581c896fe29Sbellard 5827ca4b752SRichard Henderson static int tcg_temp_new_internal(TCGType type, int temp_local) 583c896fe29Sbellard { 584c896fe29Sbellard TCGContext *s = &tcg_ctx; 585c896fe29Sbellard TCGTemp *ts; 586641d5fbeSbellard int idx, k; 587c896fe29Sbellard 5880ec9eabcSRichard Henderson k = type + (temp_local ? TCG_TYPE_COUNT : 0); 5890ec9eabcSRichard Henderson idx = find_first_bit(s->free_temps[k].l, TCG_MAX_TEMPS); 5900ec9eabcSRichard Henderson if (idx < TCG_MAX_TEMPS) { 5910ec9eabcSRichard Henderson /* There is already an available temp with the right type. */ 5920ec9eabcSRichard Henderson clear_bit(idx, s->free_temps[k].l); 5930ec9eabcSRichard Henderson 594e8996ee0Sbellard ts = &s->temps[idx]; 595e8996ee0Sbellard ts->temp_allocated = 1; 5967ca4b752SRichard Henderson tcg_debug_assert(ts->base_type == type); 5977ca4b752SRichard Henderson tcg_debug_assert(ts->temp_local == temp_local); 598e8996ee0Sbellard } else { 5997ca4b752SRichard Henderson ts = tcg_temp_alloc(s); 6007ca4b752SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { 6017ca4b752SRichard Henderson TCGTemp *ts2 = tcg_temp_alloc(s); 6027ca4b752SRichard Henderson 603c896fe29Sbellard ts->base_type = type; 604c896fe29Sbellard ts->type = TCG_TYPE_I32; 605e8996ee0Sbellard ts->temp_allocated = 1; 606641d5fbeSbellard ts->temp_local = temp_local; 6077ca4b752SRichard Henderson 6087ca4b752SRichard Henderson tcg_debug_assert(ts2 == ts + 1); 6097ca4b752SRichard Henderson ts2->base_type = TCG_TYPE_I64; 6107ca4b752SRichard Henderson ts2->type = TCG_TYPE_I32; 6117ca4b752SRichard Henderson ts2->temp_allocated = 1; 6127ca4b752SRichard Henderson ts2->temp_local = temp_local; 6137ca4b752SRichard Henderson } else { 614c896fe29Sbellard ts->base_type = type; 615c896fe29Sbellard ts->type = type; 616e8996ee0Sbellard ts->temp_allocated = 1; 617641d5fbeSbellard ts->temp_local = temp_local; 618c896fe29Sbellard } 6197ca4b752SRichard Henderson idx = temp_idx(s, ts); 620e8996ee0Sbellard } 62127bfd83cSPeter Maydell 62227bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG) 62327bfd83cSPeter Maydell s->temps_in_use++; 62427bfd83cSPeter Maydell #endif 625a7812ae4Spbrook return idx; 626c896fe29Sbellard } 627c896fe29Sbellard 628a7812ae4Spbrook TCGv_i32 tcg_temp_new_internal_i32(int temp_local) 629a7812ae4Spbrook { 630a7812ae4Spbrook int idx; 631a7812ae4Spbrook 632a7812ae4Spbrook idx = tcg_temp_new_internal(TCG_TYPE_I32, temp_local); 633a7812ae4Spbrook return MAKE_TCGV_I32(idx); 634a7812ae4Spbrook } 635a7812ae4Spbrook 636a7812ae4Spbrook TCGv_i64 tcg_temp_new_internal_i64(int temp_local) 637a7812ae4Spbrook { 638a7812ae4Spbrook int idx; 639a7812ae4Spbrook 640a7812ae4Spbrook idx = tcg_temp_new_internal(TCG_TYPE_I64, temp_local); 641a7812ae4Spbrook return MAKE_TCGV_I64(idx); 642a7812ae4Spbrook } 643a7812ae4Spbrook 6440ec9eabcSRichard Henderson static void tcg_temp_free_internal(int idx) 645c896fe29Sbellard { 646c896fe29Sbellard TCGContext *s = &tcg_ctx; 647c896fe29Sbellard TCGTemp *ts; 648641d5fbeSbellard int k; 649c896fe29Sbellard 65027bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG) 65127bfd83cSPeter Maydell s->temps_in_use--; 65227bfd83cSPeter Maydell if (s->temps_in_use < 0) { 65327bfd83cSPeter Maydell fprintf(stderr, "More temporaries freed than allocated!\n"); 65427bfd83cSPeter Maydell } 65527bfd83cSPeter Maydell #endif 65627bfd83cSPeter Maydell 657eabb7b91SAurelien Jarno tcg_debug_assert(idx >= s->nb_globals && idx < s->nb_temps); 658c896fe29Sbellard ts = &s->temps[idx]; 659eabb7b91SAurelien Jarno tcg_debug_assert(ts->temp_allocated != 0); 660e8996ee0Sbellard ts->temp_allocated = 0; 6610ec9eabcSRichard Henderson 66218d13fa2SAlexander Graf k = ts->base_type + (ts->temp_local ? TCG_TYPE_COUNT : 0); 6630ec9eabcSRichard Henderson set_bit(idx, s->free_temps[k].l); 664e8996ee0Sbellard } 665e8996ee0Sbellard 666a7812ae4Spbrook void tcg_temp_free_i32(TCGv_i32 arg) 667e8996ee0Sbellard { 668a7812ae4Spbrook tcg_temp_free_internal(GET_TCGV_I32(arg)); 669a7812ae4Spbrook } 670a7812ae4Spbrook 671a7812ae4Spbrook void tcg_temp_free_i64(TCGv_i64 arg) 672a7812ae4Spbrook { 673a7812ae4Spbrook tcg_temp_free_internal(GET_TCGV_I64(arg)); 674a7812ae4Spbrook } 675a7812ae4Spbrook 676a7812ae4Spbrook TCGv_i32 tcg_const_i32(int32_t val) 677a7812ae4Spbrook { 678a7812ae4Spbrook TCGv_i32 t0; 679a7812ae4Spbrook t0 = tcg_temp_new_i32(); 680e8996ee0Sbellard tcg_gen_movi_i32(t0, val); 681e8996ee0Sbellard return t0; 682c896fe29Sbellard } 683c896fe29Sbellard 684a7812ae4Spbrook TCGv_i64 tcg_const_i64(int64_t val) 685c896fe29Sbellard { 686a7812ae4Spbrook TCGv_i64 t0; 687a7812ae4Spbrook t0 = tcg_temp_new_i64(); 688e8996ee0Sbellard tcg_gen_movi_i64(t0, val); 689e8996ee0Sbellard return t0; 690c896fe29Sbellard } 691c896fe29Sbellard 692a7812ae4Spbrook TCGv_i32 tcg_const_local_i32(int32_t val) 693bdffd4a9Saurel32 { 694a7812ae4Spbrook TCGv_i32 t0; 695a7812ae4Spbrook t0 = tcg_temp_local_new_i32(); 696bdffd4a9Saurel32 tcg_gen_movi_i32(t0, val); 697bdffd4a9Saurel32 return t0; 698bdffd4a9Saurel32 } 699bdffd4a9Saurel32 700a7812ae4Spbrook TCGv_i64 tcg_const_local_i64(int64_t val) 701bdffd4a9Saurel32 { 702a7812ae4Spbrook TCGv_i64 t0; 703a7812ae4Spbrook t0 = tcg_temp_local_new_i64(); 704bdffd4a9Saurel32 tcg_gen_movi_i64(t0, val); 705bdffd4a9Saurel32 return t0; 706bdffd4a9Saurel32 } 707bdffd4a9Saurel32 70827bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG) 70927bfd83cSPeter Maydell void tcg_clear_temp_count(void) 71027bfd83cSPeter Maydell { 71127bfd83cSPeter Maydell TCGContext *s = &tcg_ctx; 71227bfd83cSPeter Maydell s->temps_in_use = 0; 71327bfd83cSPeter Maydell } 71427bfd83cSPeter Maydell 71527bfd83cSPeter Maydell int tcg_check_temp_count(void) 71627bfd83cSPeter Maydell { 71727bfd83cSPeter Maydell TCGContext *s = &tcg_ctx; 71827bfd83cSPeter Maydell if (s->temps_in_use) { 71927bfd83cSPeter Maydell /* Clear the count so that we don't give another 72027bfd83cSPeter Maydell * warning immediately next time around. 72127bfd83cSPeter Maydell */ 72227bfd83cSPeter Maydell s->temps_in_use = 0; 72327bfd83cSPeter Maydell return 1; 72427bfd83cSPeter Maydell } 72527bfd83cSPeter Maydell return 0; 72627bfd83cSPeter Maydell } 72727bfd83cSPeter Maydell #endif 72827bfd83cSPeter Maydell 72939cf05d3Sbellard /* Note: we convert the 64 bit args to 32 bit and do some alignment 73039cf05d3Sbellard and endian swap. Maybe it would be better to do the alignment 73139cf05d3Sbellard and endian swap in tcg_reg_alloc_call(). */ 732bbb8a1b4SRichard Henderson void tcg_gen_callN(TCGContext *s, void *func, TCGArg ret, 733bbb8a1b4SRichard Henderson int nargs, TCGArg *args) 734c896fe29Sbellard { 735c45cb8bbSRichard Henderson int i, real_args, nb_rets, pi, pi_first; 736bbb8a1b4SRichard Henderson unsigned sizemask, flags; 737afb49896SRichard Henderson TCGHelperInfo *info; 738afb49896SRichard Henderson 739afb49896SRichard Henderson info = g_hash_table_lookup(s->helpers, (gpointer)func); 740bbb8a1b4SRichard Henderson flags = info->flags; 741bbb8a1b4SRichard Henderson sizemask = info->sizemask; 7422bece2c8SRichard Henderson 74334b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \ 74434b1a49cSRichard Henderson && !defined(CONFIG_TCG_INTERPRETER) 74534b1a49cSRichard Henderson /* We have 64-bit values in one register, but need to pass as two 74634b1a49cSRichard Henderson separate parameters. Split them. */ 74734b1a49cSRichard Henderson int orig_sizemask = sizemask; 74834b1a49cSRichard Henderson int orig_nargs = nargs; 74934b1a49cSRichard Henderson TCGv_i64 retl, reth; 75034b1a49cSRichard Henderson 75134b1a49cSRichard Henderson TCGV_UNUSED_I64(retl); 75234b1a49cSRichard Henderson TCGV_UNUSED_I64(reth); 75334b1a49cSRichard Henderson if (sizemask != 0) { 75434b1a49cSRichard Henderson TCGArg *split_args = __builtin_alloca(sizeof(TCGArg) * nargs * 2); 75534b1a49cSRichard Henderson for (i = real_args = 0; i < nargs; ++i) { 75634b1a49cSRichard Henderson int is_64bit = sizemask & (1 << (i+1)*2); 75734b1a49cSRichard Henderson if (is_64bit) { 75834b1a49cSRichard Henderson TCGv_i64 orig = MAKE_TCGV_I64(args[i]); 75934b1a49cSRichard Henderson TCGv_i32 h = tcg_temp_new_i32(); 76034b1a49cSRichard Henderson TCGv_i32 l = tcg_temp_new_i32(); 76134b1a49cSRichard Henderson tcg_gen_extr_i64_i32(l, h, orig); 76234b1a49cSRichard Henderson split_args[real_args++] = GET_TCGV_I32(h); 76334b1a49cSRichard Henderson split_args[real_args++] = GET_TCGV_I32(l); 76434b1a49cSRichard Henderson } else { 76534b1a49cSRichard Henderson split_args[real_args++] = args[i]; 76634b1a49cSRichard Henderson } 76734b1a49cSRichard Henderson } 76834b1a49cSRichard Henderson nargs = real_args; 76934b1a49cSRichard Henderson args = split_args; 77034b1a49cSRichard Henderson sizemask = 0; 77134b1a49cSRichard Henderson } 77234b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64 7732bece2c8SRichard Henderson for (i = 0; i < nargs; ++i) { 7742bece2c8SRichard Henderson int is_64bit = sizemask & (1 << (i+1)*2); 7752bece2c8SRichard Henderson int is_signed = sizemask & (2 << (i+1)*2); 7762bece2c8SRichard Henderson if (!is_64bit) { 7772bece2c8SRichard Henderson TCGv_i64 temp = tcg_temp_new_i64(); 7782bece2c8SRichard Henderson TCGv_i64 orig = MAKE_TCGV_I64(args[i]); 7792bece2c8SRichard Henderson if (is_signed) { 7802bece2c8SRichard Henderson tcg_gen_ext32s_i64(temp, orig); 7812bece2c8SRichard Henderson } else { 7822bece2c8SRichard Henderson tcg_gen_ext32u_i64(temp, orig); 7832bece2c8SRichard Henderson } 7842bece2c8SRichard Henderson args[i] = GET_TCGV_I64(temp); 7852bece2c8SRichard Henderson } 7862bece2c8SRichard Henderson } 7872bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */ 7882bece2c8SRichard Henderson 789c45cb8bbSRichard Henderson pi_first = pi = s->gen_next_parm_idx; 790a7812ae4Spbrook if (ret != TCG_CALL_DUMMY_ARG) { 79134b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \ 79234b1a49cSRichard Henderson && !defined(CONFIG_TCG_INTERPRETER) 79334b1a49cSRichard Henderson if (orig_sizemask & 1) { 79434b1a49cSRichard Henderson /* The 32-bit ABI is going to return the 64-bit value in 79534b1a49cSRichard Henderson the %o0/%o1 register pair. Prepare for this by using 79634b1a49cSRichard Henderson two return temporaries, and reassemble below. */ 79734b1a49cSRichard Henderson retl = tcg_temp_new_i64(); 79834b1a49cSRichard Henderson reth = tcg_temp_new_i64(); 799c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = GET_TCGV_I64(reth); 800c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = GET_TCGV_I64(retl); 80134b1a49cSRichard Henderson nb_rets = 2; 80234b1a49cSRichard Henderson } else { 803c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = ret; 80434b1a49cSRichard Henderson nb_rets = 1; 80534b1a49cSRichard Henderson } 80634b1a49cSRichard Henderson #else 80734b1a49cSRichard Henderson if (TCG_TARGET_REG_BITS < 64 && (sizemask & 1)) { 80802eb19d0SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 809c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = ret + 1; 810c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = ret; 811a7812ae4Spbrook #else 812c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = ret; 813c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = ret + 1; 814a7812ae4Spbrook #endif 815a7812ae4Spbrook nb_rets = 2; 81634b1a49cSRichard Henderson } else { 817c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = ret; 818a7812ae4Spbrook nb_rets = 1; 819a7812ae4Spbrook } 82034b1a49cSRichard Henderson #endif 821a7812ae4Spbrook } else { 822a7812ae4Spbrook nb_rets = 0; 823a7812ae4Spbrook } 824a7812ae4Spbrook real_args = 0; 825a7812ae4Spbrook for (i = 0; i < nargs; i++) { 8262bece2c8SRichard Henderson int is_64bit = sizemask & (1 << (i+1)*2); 827bbb8a1b4SRichard Henderson if (TCG_TARGET_REG_BITS < 64 && is_64bit) { 82839cf05d3Sbellard #ifdef TCG_TARGET_CALL_ALIGN_ARGS 82939cf05d3Sbellard /* some targets want aligned 64 bit args */ 830ebd486d5Smalc if (real_args & 1) { 831c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = TCG_CALL_DUMMY_ARG; 832ebd486d5Smalc real_args++; 83339cf05d3Sbellard } 83439cf05d3Sbellard #endif 8353f90f252SRichard Henderson /* If stack grows up, then we will be placing successive 8363f90f252SRichard Henderson arguments at lower addresses, which means we need to 8373f90f252SRichard Henderson reverse the order compared to how we would normally 8383f90f252SRichard Henderson treat either big or little-endian. For those arguments 8393f90f252SRichard Henderson that will wind up in registers, this still works for 8403f90f252SRichard Henderson HPPA (the only current STACK_GROWSUP target) since the 8413f90f252SRichard Henderson argument registers are *also* allocated in decreasing 8423f90f252SRichard Henderson order. If another such target is added, this logic may 8433f90f252SRichard Henderson have to get more complicated to differentiate between 8443f90f252SRichard Henderson stack arguments and register arguments. */ 84502eb19d0SRichard Henderson #if defined(HOST_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP) 846c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = args[i] + 1; 847c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = args[i]; 848c896fe29Sbellard #else 849c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = args[i]; 850c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = args[i] + 1; 851c896fe29Sbellard #endif 852a7812ae4Spbrook real_args += 2; 8532bece2c8SRichard Henderson continue; 8542bece2c8SRichard Henderson } 8552bece2c8SRichard Henderson 856c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = args[i]; 857a7812ae4Spbrook real_args++; 858c896fe29Sbellard } 859c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = (uintptr_t)func; 860c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = flags; 861a7812ae4Spbrook 862c45cb8bbSRichard Henderson i = s->gen_next_op_idx; 863c45cb8bbSRichard Henderson tcg_debug_assert(i < OPC_BUF_SIZE); 864c45cb8bbSRichard Henderson tcg_debug_assert(pi <= OPPARAM_BUF_SIZE); 865a7812ae4Spbrook 866c45cb8bbSRichard Henderson /* Set links for sequential allocation during translation. */ 867c45cb8bbSRichard Henderson s->gen_op_buf[i] = (TCGOp){ 868c45cb8bbSRichard Henderson .opc = INDEX_op_call, 869c45cb8bbSRichard Henderson .callo = nb_rets, 870c45cb8bbSRichard Henderson .calli = real_args, 871c45cb8bbSRichard Henderson .args = pi_first, 872c45cb8bbSRichard Henderson .prev = i - 1, 873c45cb8bbSRichard Henderson .next = i + 1 874c45cb8bbSRichard Henderson }; 875c45cb8bbSRichard Henderson 876c45cb8bbSRichard Henderson /* Make sure the calli field didn't overflow. */ 877c45cb8bbSRichard Henderson tcg_debug_assert(s->gen_op_buf[i].calli == real_args); 878c45cb8bbSRichard Henderson 879dcb8e758SRichard Henderson s->gen_op_buf[0].prev = i; 880c45cb8bbSRichard Henderson s->gen_next_op_idx = i + 1; 881c45cb8bbSRichard Henderson s->gen_next_parm_idx = pi; 8822bece2c8SRichard Henderson 88334b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \ 88434b1a49cSRichard Henderson && !defined(CONFIG_TCG_INTERPRETER) 88534b1a49cSRichard Henderson /* Free all of the parts we allocated above. */ 88634b1a49cSRichard Henderson for (i = real_args = 0; i < orig_nargs; ++i) { 88734b1a49cSRichard Henderson int is_64bit = orig_sizemask & (1 << (i+1)*2); 88834b1a49cSRichard Henderson if (is_64bit) { 88934b1a49cSRichard Henderson TCGv_i32 h = MAKE_TCGV_I32(args[real_args++]); 89034b1a49cSRichard Henderson TCGv_i32 l = MAKE_TCGV_I32(args[real_args++]); 89134b1a49cSRichard Henderson tcg_temp_free_i32(h); 89234b1a49cSRichard Henderson tcg_temp_free_i32(l); 89334b1a49cSRichard Henderson } else { 89434b1a49cSRichard Henderson real_args++; 89534b1a49cSRichard Henderson } 89634b1a49cSRichard Henderson } 89734b1a49cSRichard Henderson if (orig_sizemask & 1) { 89834b1a49cSRichard Henderson /* The 32-bit ABI returned two 32-bit pieces. Re-assemble them. 89934b1a49cSRichard Henderson Note that describing these as TCGv_i64 eliminates an unnecessary 90034b1a49cSRichard Henderson zero-extension that tcg_gen_concat_i32_i64 would create. */ 90134b1a49cSRichard Henderson tcg_gen_concat32_i64(MAKE_TCGV_I64(ret), retl, reth); 90234b1a49cSRichard Henderson tcg_temp_free_i64(retl); 90334b1a49cSRichard Henderson tcg_temp_free_i64(reth); 90434b1a49cSRichard Henderson } 90534b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64 9062bece2c8SRichard Henderson for (i = 0; i < nargs; ++i) { 9072bece2c8SRichard Henderson int is_64bit = sizemask & (1 << (i+1)*2); 9082bece2c8SRichard Henderson if (!is_64bit) { 9092bece2c8SRichard Henderson TCGv_i64 temp = MAKE_TCGV_I64(args[i]); 9102bece2c8SRichard Henderson tcg_temp_free_i64(temp); 9112bece2c8SRichard Henderson } 9122bece2c8SRichard Henderson } 9132bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */ 914a7812ae4Spbrook } 915c896fe29Sbellard 9168fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s) 917c896fe29Sbellard { 918c896fe29Sbellard int i; 919c896fe29Sbellard TCGTemp *ts; 920c896fe29Sbellard for(i = 0; i < s->nb_globals; i++) { 921c896fe29Sbellard ts = &s->temps[i]; 922c896fe29Sbellard if (ts->fixed_reg) { 923c896fe29Sbellard ts->val_type = TEMP_VAL_REG; 924c896fe29Sbellard } else { 925c896fe29Sbellard ts->val_type = TEMP_VAL_MEM; 926c896fe29Sbellard } 927c896fe29Sbellard } 928e8996ee0Sbellard for(i = s->nb_globals; i < s->nb_temps; i++) { 929e8996ee0Sbellard ts = &s->temps[i]; 9307dfd8c6aSAurelien Jarno if (ts->temp_local) { 9317dfd8c6aSAurelien Jarno ts->val_type = TEMP_VAL_MEM; 9327dfd8c6aSAurelien Jarno } else { 933e8996ee0Sbellard ts->val_type = TEMP_VAL_DEAD; 9347dfd8c6aSAurelien Jarno } 935e8996ee0Sbellard ts->mem_allocated = 0; 936e8996ee0Sbellard ts->fixed_reg = 0; 937e8996ee0Sbellard } 938f8b2f202SRichard Henderson 939f8b2f202SRichard Henderson memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp)); 940c896fe29Sbellard } 941c896fe29Sbellard 942f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size, 943f8b2f202SRichard Henderson TCGTemp *ts) 944c896fe29Sbellard { 945f8b2f202SRichard Henderson int idx = temp_idx(s, ts); 946ac56dd48Spbrook 947ac56dd48Spbrook if (idx < s->nb_globals) { 948ac56dd48Spbrook pstrcpy(buf, buf_size, ts->name); 949f8b2f202SRichard Henderson } else if (ts->temp_local) { 950641d5fbeSbellard snprintf(buf, buf_size, "loc%d", idx - s->nb_globals); 951f8b2f202SRichard Henderson } else { 952ac56dd48Spbrook snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals); 953c896fe29Sbellard } 954c896fe29Sbellard return buf; 955c896fe29Sbellard } 956c896fe29Sbellard 957f8b2f202SRichard Henderson static char *tcg_get_arg_str_idx(TCGContext *s, char *buf, 958f8b2f202SRichard Henderson int buf_size, int idx) 959f8b2f202SRichard Henderson { 960eabb7b91SAurelien Jarno tcg_debug_assert(idx >= 0 && idx < s->nb_temps); 961f8b2f202SRichard Henderson return tcg_get_arg_str_ptr(s, buf, buf_size, &s->temps[idx]); 962f8b2f202SRichard Henderson } 963f8b2f202SRichard Henderson 9646e085f72SRichard Henderson /* Find helper name. */ 9656e085f72SRichard Henderson static inline const char *tcg_find_helper(TCGContext *s, uintptr_t val) 966e8996ee0Sbellard { 9676e085f72SRichard Henderson const char *ret = NULL; 9686e085f72SRichard Henderson if (s->helpers) { 96972866e82SRichard Henderson TCGHelperInfo *info = g_hash_table_lookup(s->helpers, (gpointer)val); 97072866e82SRichard Henderson if (info) { 97172866e82SRichard Henderson ret = info->name; 97272866e82SRichard Henderson } 973e8996ee0Sbellard } 9746e085f72SRichard Henderson return ret; 9754dc81f28Sbellard } 9764dc81f28Sbellard 977f48f3edeSblueswir1 static const char * const cond_name[] = 978f48f3edeSblueswir1 { 9790aed257fSRichard Henderson [TCG_COND_NEVER] = "never", 9800aed257fSRichard Henderson [TCG_COND_ALWAYS] = "always", 981f48f3edeSblueswir1 [TCG_COND_EQ] = "eq", 982f48f3edeSblueswir1 [TCG_COND_NE] = "ne", 983f48f3edeSblueswir1 [TCG_COND_LT] = "lt", 984f48f3edeSblueswir1 [TCG_COND_GE] = "ge", 985f48f3edeSblueswir1 [TCG_COND_LE] = "le", 986f48f3edeSblueswir1 [TCG_COND_GT] = "gt", 987f48f3edeSblueswir1 [TCG_COND_LTU] = "ltu", 988f48f3edeSblueswir1 [TCG_COND_GEU] = "geu", 989f48f3edeSblueswir1 [TCG_COND_LEU] = "leu", 990f48f3edeSblueswir1 [TCG_COND_GTU] = "gtu" 991f48f3edeSblueswir1 }; 992f48f3edeSblueswir1 993f713d6adSRichard Henderson static const char * const ldst_name[] = 994f713d6adSRichard Henderson { 995f713d6adSRichard Henderson [MO_UB] = "ub", 996f713d6adSRichard Henderson [MO_SB] = "sb", 997f713d6adSRichard Henderson [MO_LEUW] = "leuw", 998f713d6adSRichard Henderson [MO_LESW] = "lesw", 999f713d6adSRichard Henderson [MO_LEUL] = "leul", 1000f713d6adSRichard Henderson [MO_LESL] = "lesl", 1001f713d6adSRichard Henderson [MO_LEQ] = "leq", 1002f713d6adSRichard Henderson [MO_BEUW] = "beuw", 1003f713d6adSRichard Henderson [MO_BESW] = "besw", 1004f713d6adSRichard Henderson [MO_BEUL] = "beul", 1005f713d6adSRichard Henderson [MO_BESL] = "besl", 1006f713d6adSRichard Henderson [MO_BEQ] = "beq", 1007f713d6adSRichard Henderson }; 1008f713d6adSRichard Henderson 10091f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = { 10101f00b27fSSergey Sorokin #ifdef ALIGNED_ONLY 10111f00b27fSSergey Sorokin [MO_UNALN >> MO_ASHIFT] = "un+", 10121f00b27fSSergey Sorokin [MO_ALIGN >> MO_ASHIFT] = "", 10131f00b27fSSergey Sorokin #else 10141f00b27fSSergey Sorokin [MO_UNALN >> MO_ASHIFT] = "", 10151f00b27fSSergey Sorokin [MO_ALIGN >> MO_ASHIFT] = "al+", 10161f00b27fSSergey Sorokin #endif 10171f00b27fSSergey Sorokin [MO_ALIGN_2 >> MO_ASHIFT] = "al2+", 10181f00b27fSSergey Sorokin [MO_ALIGN_4 >> MO_ASHIFT] = "al4+", 10191f00b27fSSergey Sorokin [MO_ALIGN_8 >> MO_ASHIFT] = "al8+", 10201f00b27fSSergey Sorokin [MO_ALIGN_16 >> MO_ASHIFT] = "al16+", 10211f00b27fSSergey Sorokin [MO_ALIGN_32 >> MO_ASHIFT] = "al32+", 10221f00b27fSSergey Sorokin [MO_ALIGN_64 >> MO_ASHIFT] = "al64+", 10231f00b27fSSergey Sorokin }; 10241f00b27fSSergey Sorokin 1025eeacee4dSBlue Swirl void tcg_dump_ops(TCGContext *s) 1026c896fe29Sbellard { 1027c896fe29Sbellard char buf[128]; 1028c45cb8bbSRichard Henderson TCGOp *op; 1029c45cb8bbSRichard Henderson int oi; 1030c896fe29Sbellard 1031dcb8e758SRichard Henderson for (oi = s->gen_op_buf[0].next; oi != 0; oi = op->next) { 1032c45cb8bbSRichard Henderson int i, k, nb_oargs, nb_iargs, nb_cargs; 1033c45cb8bbSRichard Henderson const TCGOpDef *def; 1034c45cb8bbSRichard Henderson const TCGArg *args; 1035c45cb8bbSRichard Henderson TCGOpcode c; 1036bdfb460eSRichard Henderson int col = 0; 1037c45cb8bbSRichard Henderson 1038c45cb8bbSRichard Henderson op = &s->gen_op_buf[oi]; 1039c45cb8bbSRichard Henderson c = op->opc; 1040c896fe29Sbellard def = &tcg_op_defs[c]; 1041c45cb8bbSRichard Henderson args = &s->gen_opparam_buf[op->args]; 1042c45cb8bbSRichard Henderson 1043765b842aSRichard Henderson if (c == INDEX_op_insn_start) { 1044bdfb460eSRichard Henderson col += qemu_log("%s ----", oi != s->gen_op_buf[0].next ? "\n" : ""); 10459aef40edSRichard Henderson 10469aef40edSRichard Henderson for (i = 0; i < TARGET_INSN_START_WORDS; ++i) { 10479aef40edSRichard Henderson target_ulong a; 10487e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS 10499aef40edSRichard Henderson a = ((target_ulong)args[i * 2 + 1] << 32) | args[i * 2]; 10507e4597d7Sbellard #else 10519aef40edSRichard Henderson a = args[i]; 10527e4597d7Sbellard #endif 1053bdfb460eSRichard Henderson col += qemu_log(" " TARGET_FMT_lx, a); 1054eeacee4dSBlue Swirl } 10557e4597d7Sbellard } else if (c == INDEX_op_call) { 1056c896fe29Sbellard /* variable number of arguments */ 1057c45cb8bbSRichard Henderson nb_oargs = op->callo; 1058c45cb8bbSRichard Henderson nb_iargs = op->calli; 1059c896fe29Sbellard nb_cargs = def->nb_cargs; 1060b03cce8eSbellard 1061cf066674SRichard Henderson /* function name, flags, out args */ 1062bdfb460eSRichard Henderson col += qemu_log(" %s %s,$0x%" TCG_PRIlx ",$%d", def->name, 1063cf066674SRichard Henderson tcg_find_helper(s, args[nb_oargs + nb_iargs]), 1064cf066674SRichard Henderson args[nb_oargs + nb_iargs + 1], nb_oargs); 1065b03cce8eSbellard for (i = 0; i < nb_oargs; i++) { 1066bdfb460eSRichard Henderson col += qemu_log(",%s", tcg_get_arg_str_idx(s, buf, sizeof(buf), 1067eeacee4dSBlue Swirl args[i])); 1068b03cce8eSbellard } 1069cf066674SRichard Henderson for (i = 0; i < nb_iargs; i++) { 1070cf066674SRichard Henderson TCGArg arg = args[nb_oargs + i]; 1071cf066674SRichard Henderson const char *t = "<dummy>"; 1072cf066674SRichard Henderson if (arg != TCG_CALL_DUMMY_ARG) { 1073cf066674SRichard Henderson t = tcg_get_arg_str_idx(s, buf, sizeof(buf), arg); 1074b03cce8eSbellard } 1075bdfb460eSRichard Henderson col += qemu_log(",%s", t); 1076e8996ee0Sbellard } 1077b03cce8eSbellard } else { 1078bdfb460eSRichard Henderson col += qemu_log(" %s ", def->name); 1079c45cb8bbSRichard Henderson 1080c896fe29Sbellard nb_oargs = def->nb_oargs; 1081c896fe29Sbellard nb_iargs = def->nb_iargs; 1082c896fe29Sbellard nb_cargs = def->nb_cargs; 1083c896fe29Sbellard 1084c896fe29Sbellard k = 0; 1085c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 1086eeacee4dSBlue Swirl if (k != 0) { 1087bdfb460eSRichard Henderson col += qemu_log(","); 1088eeacee4dSBlue Swirl } 1089bdfb460eSRichard Henderson col += qemu_log("%s", tcg_get_arg_str_idx(s, buf, sizeof(buf), 1090eeacee4dSBlue Swirl args[k++])); 1091c896fe29Sbellard } 1092c896fe29Sbellard for (i = 0; i < nb_iargs; i++) { 1093eeacee4dSBlue Swirl if (k != 0) { 1094bdfb460eSRichard Henderson col += qemu_log(","); 1095eeacee4dSBlue Swirl } 1096bdfb460eSRichard Henderson col += qemu_log("%s", tcg_get_arg_str_idx(s, buf, sizeof(buf), 1097eeacee4dSBlue Swirl args[k++])); 1098c896fe29Sbellard } 1099be210acbSRichard Henderson switch (c) { 1100be210acbSRichard Henderson case INDEX_op_brcond_i32: 1101ffc5ea09SRichard Henderson case INDEX_op_setcond_i32: 1102ffc5ea09SRichard Henderson case INDEX_op_movcond_i32: 1103be210acbSRichard Henderson case INDEX_op_brcond2_i32: 1104be210acbSRichard Henderson case INDEX_op_setcond2_i32: 1105ffc5ea09SRichard Henderson case INDEX_op_brcond_i64: 1106be210acbSRichard Henderson case INDEX_op_setcond_i64: 1107ffc5ea09SRichard Henderson case INDEX_op_movcond_i64: 1108eeacee4dSBlue Swirl if (args[k] < ARRAY_SIZE(cond_name) && cond_name[args[k]]) { 1109bdfb460eSRichard Henderson col += qemu_log(",%s", cond_name[args[k++]]); 1110eeacee4dSBlue Swirl } else { 1111bdfb460eSRichard Henderson col += qemu_log(",$0x%" TCG_PRIlx, args[k++]); 1112eeacee4dSBlue Swirl } 1113f48f3edeSblueswir1 i = 1; 1114be210acbSRichard Henderson break; 1115f713d6adSRichard Henderson case INDEX_op_qemu_ld_i32: 1116f713d6adSRichard Henderson case INDEX_op_qemu_st_i32: 1117f713d6adSRichard Henderson case INDEX_op_qemu_ld_i64: 1118f713d6adSRichard Henderson case INDEX_op_qemu_st_i64: 111959227d5dSRichard Henderson { 112059227d5dSRichard Henderson TCGMemOpIdx oi = args[k++]; 112159227d5dSRichard Henderson TCGMemOp op = get_memop(oi); 112259227d5dSRichard Henderson unsigned ix = get_mmuidx(oi); 112359227d5dSRichard Henderson 112459c4b7e8SRichard Henderson if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) { 1125bdfb460eSRichard Henderson col += qemu_log(",$0x%x,%u", op, ix); 112659c4b7e8SRichard Henderson } else { 11271f00b27fSSergey Sorokin const char *s_al, *s_op; 11281f00b27fSSergey Sorokin s_al = alignment_name[(op & MO_AMASK) >> MO_ASHIFT]; 112959c4b7e8SRichard Henderson s_op = ldst_name[op & (MO_BSWAP | MO_SSIZE)]; 1130bdfb460eSRichard Henderson col += qemu_log(",%s%s,%u", s_al, s_op, ix); 1131f713d6adSRichard Henderson } 1132f713d6adSRichard Henderson i = 1; 113359227d5dSRichard Henderson } 1134f713d6adSRichard Henderson break; 1135be210acbSRichard Henderson default: 1136f48f3edeSblueswir1 i = 0; 1137be210acbSRichard Henderson break; 1138be210acbSRichard Henderson } 113951e3972cSRichard Henderson switch (c) { 114051e3972cSRichard Henderson case INDEX_op_set_label: 114151e3972cSRichard Henderson case INDEX_op_br: 114251e3972cSRichard Henderson case INDEX_op_brcond_i32: 114351e3972cSRichard Henderson case INDEX_op_brcond_i64: 114451e3972cSRichard Henderson case INDEX_op_brcond2_i32: 1145bdfb460eSRichard Henderson col += qemu_log("%s$L%d", k ? "," : "", arg_label(args[k])->id); 114651e3972cSRichard Henderson i++, k++; 114751e3972cSRichard Henderson break; 114851e3972cSRichard Henderson default: 114951e3972cSRichard Henderson break; 1150eeacee4dSBlue Swirl } 115151e3972cSRichard Henderson for (; i < nb_cargs; i++, k++) { 1152bdfb460eSRichard Henderson col += qemu_log("%s$0x%" TCG_PRIlx, k ? "," : "", args[k]); 1153bdfb460eSRichard Henderson } 1154bdfb460eSRichard Henderson } 1155bdfb460eSRichard Henderson if (op->life) { 1156bdfb460eSRichard Henderson unsigned life = op->life; 1157bdfb460eSRichard Henderson 1158bdfb460eSRichard Henderson for (; col < 48; ++col) { 1159bdfb460eSRichard Henderson putc(' ', qemu_logfile); 1160bdfb460eSRichard Henderson } 1161bdfb460eSRichard Henderson 1162bdfb460eSRichard Henderson if (life & (SYNC_ARG * 3)) { 1163bdfb460eSRichard Henderson qemu_log(" sync:"); 1164bdfb460eSRichard Henderson for (i = 0; i < 2; ++i) { 1165bdfb460eSRichard Henderson if (life & (SYNC_ARG << i)) { 1166bdfb460eSRichard Henderson qemu_log(" %d", i); 1167bdfb460eSRichard Henderson } 1168bdfb460eSRichard Henderson } 1169bdfb460eSRichard Henderson } 1170bdfb460eSRichard Henderson life /= DEAD_ARG; 1171bdfb460eSRichard Henderson if (life) { 1172bdfb460eSRichard Henderson qemu_log(" dead:"); 1173bdfb460eSRichard Henderson for (i = 0; life; ++i, life >>= 1) { 1174bdfb460eSRichard Henderson if (life & 1) { 1175bdfb460eSRichard Henderson qemu_log(" %d", i); 1176bdfb460eSRichard Henderson } 1177bdfb460eSRichard Henderson } 1178c896fe29Sbellard } 1179b03cce8eSbellard } 1180eeacee4dSBlue Swirl qemu_log("\n"); 1181c896fe29Sbellard } 1182c896fe29Sbellard } 1183c896fe29Sbellard 1184c896fe29Sbellard /* we give more priority to constraints with less registers */ 1185c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k) 1186c896fe29Sbellard { 1187c896fe29Sbellard const TCGArgConstraint *arg_ct; 1188c896fe29Sbellard 1189c896fe29Sbellard int i, n; 1190c896fe29Sbellard arg_ct = &def->args_ct[k]; 1191c896fe29Sbellard if (arg_ct->ct & TCG_CT_ALIAS) { 1192c896fe29Sbellard /* an alias is equivalent to a single register */ 1193c896fe29Sbellard n = 1; 1194c896fe29Sbellard } else { 1195c896fe29Sbellard if (!(arg_ct->ct & TCG_CT_REG)) 1196c896fe29Sbellard return 0; 1197c896fe29Sbellard n = 0; 1198c896fe29Sbellard for(i = 0; i < TCG_TARGET_NB_REGS; i++) { 1199c896fe29Sbellard if (tcg_regset_test_reg(arg_ct->u.regs, i)) 1200c896fe29Sbellard n++; 1201c896fe29Sbellard } 1202c896fe29Sbellard } 1203c896fe29Sbellard return TCG_TARGET_NB_REGS - n + 1; 1204c896fe29Sbellard } 1205c896fe29Sbellard 1206c896fe29Sbellard /* sort from highest priority to lowest */ 1207c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n) 1208c896fe29Sbellard { 1209c896fe29Sbellard int i, j, p1, p2, tmp; 1210c896fe29Sbellard 1211c896fe29Sbellard for(i = 0; i < n; i++) 1212c896fe29Sbellard def->sorted_args[start + i] = start + i; 1213c896fe29Sbellard if (n <= 1) 1214c896fe29Sbellard return; 1215c896fe29Sbellard for(i = 0; i < n - 1; i++) { 1216c896fe29Sbellard for(j = i + 1; j < n; j++) { 1217c896fe29Sbellard p1 = get_constraint_priority(def, def->sorted_args[start + i]); 1218c896fe29Sbellard p2 = get_constraint_priority(def, def->sorted_args[start + j]); 1219c896fe29Sbellard if (p1 < p2) { 1220c896fe29Sbellard tmp = def->sorted_args[start + i]; 1221c896fe29Sbellard def->sorted_args[start + i] = def->sorted_args[start + j]; 1222c896fe29Sbellard def->sorted_args[start + j] = tmp; 1223c896fe29Sbellard } 1224c896fe29Sbellard } 1225c896fe29Sbellard } 1226c896fe29Sbellard } 1227c896fe29Sbellard 1228f69d277eSRichard Henderson static void process_op_defs(TCGContext *s) 1229c896fe29Sbellard { 1230a9751609SRichard Henderson TCGOpcode op; 1231c896fe29Sbellard 1232f69d277eSRichard Henderson for (op = 0; op < NB_OPS; op++) { 1233f69d277eSRichard Henderson TCGOpDef *def = &tcg_op_defs[op]; 1234f69d277eSRichard Henderson const TCGTargetOpDef *tdefs; 1235*069ea736SRichard Henderson TCGType type; 1236*069ea736SRichard Henderson int i, nb_args; 1237f69d277eSRichard Henderson 1238f69d277eSRichard Henderson if (def->flags & TCG_OPF_NOT_PRESENT) { 1239f69d277eSRichard Henderson continue; 1240f69d277eSRichard Henderson } 1241f69d277eSRichard Henderson 1242c896fe29Sbellard nb_args = def->nb_iargs + def->nb_oargs; 1243f69d277eSRichard Henderson if (nb_args == 0) { 1244f69d277eSRichard Henderson continue; 1245f69d277eSRichard Henderson } 1246f69d277eSRichard Henderson 1247f69d277eSRichard Henderson tdefs = tcg_target_op_def(op); 1248f69d277eSRichard Henderson /* Missing TCGTargetOpDef entry. */ 1249f69d277eSRichard Henderson tcg_debug_assert(tdefs != NULL); 1250f69d277eSRichard Henderson 1251*069ea736SRichard Henderson type = (def->flags & TCG_OPF_64BIT ? TCG_TYPE_I64 : TCG_TYPE_I32); 1252c896fe29Sbellard for (i = 0; i < nb_args; i++) { 1253f69d277eSRichard Henderson const char *ct_str = tdefs->args_ct_str[i]; 1254f69d277eSRichard Henderson /* Incomplete TCGTargetOpDef entry. */ 1255eabb7b91SAurelien Jarno tcg_debug_assert(ct_str != NULL); 1256f69d277eSRichard Henderson 1257c896fe29Sbellard tcg_regset_clear(def->args_ct[i].u.regs); 1258c896fe29Sbellard def->args_ct[i].ct = 0; 1259c896fe29Sbellard if (ct_str[0] >= '0' && ct_str[0] <= '9') { 1260c896fe29Sbellard int oarg; 1261c896fe29Sbellard oarg = ct_str[0] - '0'; 1262eabb7b91SAurelien Jarno tcg_debug_assert(oarg < def->nb_oargs); 1263eabb7b91SAurelien Jarno tcg_debug_assert(def->args_ct[oarg].ct & TCG_CT_REG); 1264c896fe29Sbellard /* TCG_CT_ALIAS is for the output arguments. The input 12655ff9d6a4Sbellard argument is tagged with TCG_CT_IALIAS. */ 1266c896fe29Sbellard def->args_ct[i] = def->args_ct[oarg]; 12675ff9d6a4Sbellard def->args_ct[oarg].ct = TCG_CT_ALIAS; 12685ff9d6a4Sbellard def->args_ct[oarg].alias_index = i; 1269c896fe29Sbellard def->args_ct[i].ct |= TCG_CT_IALIAS; 12705ff9d6a4Sbellard def->args_ct[i].alias_index = oarg; 1271c896fe29Sbellard } else { 1272c896fe29Sbellard for(;;) { 1273c896fe29Sbellard if (*ct_str == '\0') 1274c896fe29Sbellard break; 1275c896fe29Sbellard switch(*ct_str) { 127682790a87SRichard Henderson case '&': 127782790a87SRichard Henderson def->args_ct[i].ct |= TCG_CT_NEWREG; 127882790a87SRichard Henderson ct_str++; 127982790a87SRichard Henderson break; 1280c896fe29Sbellard case 'i': 1281c896fe29Sbellard def->args_ct[i].ct |= TCG_CT_CONST; 1282c896fe29Sbellard ct_str++; 1283c896fe29Sbellard break; 1284c896fe29Sbellard default: 1285*069ea736SRichard Henderson ct_str = target_parse_constraint(&def->args_ct[i], 1286*069ea736SRichard Henderson ct_str, type); 1287f69d277eSRichard Henderson /* Typo in TCGTargetOpDef constraint. */ 1288*069ea736SRichard Henderson tcg_debug_assert(ct_str != NULL); 1289c896fe29Sbellard } 1290c896fe29Sbellard } 1291c896fe29Sbellard } 1292c896fe29Sbellard } 1293c896fe29Sbellard 1294c68aaa18SStefan Weil /* TCGTargetOpDef entry with too much information? */ 1295eabb7b91SAurelien Jarno tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL); 1296c68aaa18SStefan Weil 1297c896fe29Sbellard /* sort the constraints (XXX: this is just an heuristic) */ 1298c896fe29Sbellard sort_constraints(def, 0, def->nb_oargs); 1299c896fe29Sbellard sort_constraints(def, def->nb_oargs, def->nb_iargs); 1300c896fe29Sbellard } 1301c896fe29Sbellard } 1302c896fe29Sbellard 13030c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op) 13040c627cdcSRichard Henderson { 13050c627cdcSRichard Henderson int next = op->next; 13060c627cdcSRichard Henderson int prev = op->prev; 13070c627cdcSRichard Henderson 1308dcb8e758SRichard Henderson /* We should never attempt to remove the list terminator. */ 1309dcb8e758SRichard Henderson tcg_debug_assert(op != &s->gen_op_buf[0]); 13100c627cdcSRichard Henderson 1311dcb8e758SRichard Henderson s->gen_op_buf[next].prev = prev; 1312dcb8e758SRichard Henderson s->gen_op_buf[prev].next = next; 1313dcb8e758SRichard Henderson 1314dcb8e758SRichard Henderson memset(op, 0, sizeof(*op)); 13150c627cdcSRichard Henderson 13160c627cdcSRichard Henderson #ifdef CONFIG_PROFILER 13170c627cdcSRichard Henderson s->del_op_count++; 13180c627cdcSRichard Henderson #endif 13190c627cdcSRichard Henderson } 13200c627cdcSRichard Henderson 13215a18407fSRichard Henderson TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op, 13225a18407fSRichard Henderson TCGOpcode opc, int nargs) 13235a18407fSRichard Henderson { 13245a18407fSRichard Henderson int oi = s->gen_next_op_idx; 13255a18407fSRichard Henderson int pi = s->gen_next_parm_idx; 13265a18407fSRichard Henderson int prev = old_op->prev; 13275a18407fSRichard Henderson int next = old_op - s->gen_op_buf; 13285a18407fSRichard Henderson TCGOp *new_op; 13295a18407fSRichard Henderson 13305a18407fSRichard Henderson tcg_debug_assert(oi < OPC_BUF_SIZE); 13315a18407fSRichard Henderson tcg_debug_assert(pi + nargs <= OPPARAM_BUF_SIZE); 13325a18407fSRichard Henderson s->gen_next_op_idx = oi + 1; 13335a18407fSRichard Henderson s->gen_next_parm_idx = pi + nargs; 13345a18407fSRichard Henderson 13355a18407fSRichard Henderson new_op = &s->gen_op_buf[oi]; 13365a18407fSRichard Henderson *new_op = (TCGOp){ 13375a18407fSRichard Henderson .opc = opc, 13385a18407fSRichard Henderson .args = pi, 13395a18407fSRichard Henderson .prev = prev, 13405a18407fSRichard Henderson .next = next 13415a18407fSRichard Henderson }; 13425a18407fSRichard Henderson s->gen_op_buf[prev].next = oi; 13435a18407fSRichard Henderson old_op->prev = oi; 13445a18407fSRichard Henderson 13455a18407fSRichard Henderson return new_op; 13465a18407fSRichard Henderson } 13475a18407fSRichard Henderson 13485a18407fSRichard Henderson TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, 13495a18407fSRichard Henderson TCGOpcode opc, int nargs) 13505a18407fSRichard Henderson { 13515a18407fSRichard Henderson int oi = s->gen_next_op_idx; 13525a18407fSRichard Henderson int pi = s->gen_next_parm_idx; 13535a18407fSRichard Henderson int prev = old_op - s->gen_op_buf; 13545a18407fSRichard Henderson int next = old_op->next; 13555a18407fSRichard Henderson TCGOp *new_op; 13565a18407fSRichard Henderson 13575a18407fSRichard Henderson tcg_debug_assert(oi < OPC_BUF_SIZE); 13585a18407fSRichard Henderson tcg_debug_assert(pi + nargs <= OPPARAM_BUF_SIZE); 13595a18407fSRichard Henderson s->gen_next_op_idx = oi + 1; 13605a18407fSRichard Henderson s->gen_next_parm_idx = pi + nargs; 13615a18407fSRichard Henderson 13625a18407fSRichard Henderson new_op = &s->gen_op_buf[oi]; 13635a18407fSRichard Henderson *new_op = (TCGOp){ 13645a18407fSRichard Henderson .opc = opc, 13655a18407fSRichard Henderson .args = pi, 13665a18407fSRichard Henderson .prev = prev, 13675a18407fSRichard Henderson .next = next 13685a18407fSRichard Henderson }; 13695a18407fSRichard Henderson s->gen_op_buf[next].prev = oi; 13705a18407fSRichard Henderson old_op->next = oi; 13715a18407fSRichard Henderson 13725a18407fSRichard Henderson return new_op; 13735a18407fSRichard Henderson } 13745a18407fSRichard Henderson 1375c70fbf0aSRichard Henderson #define TS_DEAD 1 1376c70fbf0aSRichard Henderson #define TS_MEM 2 1377c70fbf0aSRichard Henderson 13785a18407fSRichard Henderson #define IS_DEAD_ARG(n) (arg_life & (DEAD_ARG << (n))) 13795a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n))) 13805a18407fSRichard Henderson 13819c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals 13829c43b68dSAurelien Jarno should be in memory. */ 1383c70fbf0aSRichard Henderson static inline void tcg_la_func_end(TCGContext *s, uint8_t *temp_state) 1384c896fe29Sbellard { 1385c70fbf0aSRichard Henderson memset(temp_state, TS_DEAD | TS_MEM, s->nb_globals); 1386c70fbf0aSRichard Henderson memset(temp_state + s->nb_globals, TS_DEAD, s->nb_temps - s->nb_globals); 1387c896fe29Sbellard } 1388c896fe29Sbellard 13899c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals 13909c43b68dSAurelien Jarno and local temps should be in memory. */ 1391c70fbf0aSRichard Henderson static inline void tcg_la_bb_end(TCGContext *s, uint8_t *temp_state) 1392641d5fbeSbellard { 1393c70fbf0aSRichard Henderson int i, n; 1394641d5fbeSbellard 1395c70fbf0aSRichard Henderson tcg_la_func_end(s, temp_state); 1396c70fbf0aSRichard Henderson for (i = s->nb_globals, n = s->nb_temps; i < n; i++) { 1397c70fbf0aSRichard Henderson if (s->temps[i].temp_local) { 1398c70fbf0aSRichard Henderson temp_state[i] |= TS_MEM; 1399c70fbf0aSRichard Henderson } 1400641d5fbeSbellard } 1401641d5fbeSbellard } 1402641d5fbeSbellard 1403a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a 1404c896fe29Sbellard given input arguments is dead. Instructions updating dead 1405c896fe29Sbellard temporaries are removed. */ 14065a18407fSRichard Henderson static void liveness_pass_1(TCGContext *s, uint8_t *temp_state) 1407c896fe29Sbellard { 1408c70fbf0aSRichard Henderson int nb_globals = s->nb_globals; 14095a18407fSRichard Henderson int oi, oi_prev; 1410c896fe29Sbellard 1411c70fbf0aSRichard Henderson tcg_la_func_end(s, temp_state); 1412c896fe29Sbellard 1413dcb8e758SRichard Henderson for (oi = s->gen_op_buf[0].prev; oi != 0; oi = oi_prev) { 1414c45cb8bbSRichard Henderson int i, nb_iargs, nb_oargs; 1415c45cb8bbSRichard Henderson TCGOpcode opc_new, opc_new2; 1416c45cb8bbSRichard Henderson bool have_opc_new2; 1417a1b3c48dSRichard Henderson TCGLifeData arg_life = 0; 1418c45cb8bbSRichard Henderson TCGArg arg; 1419c45cb8bbSRichard Henderson 1420c45cb8bbSRichard Henderson TCGOp * const op = &s->gen_op_buf[oi]; 1421c45cb8bbSRichard Henderson TCGArg * const args = &s->gen_opparam_buf[op->args]; 1422c45cb8bbSRichard Henderson TCGOpcode opc = op->opc; 1423c45cb8bbSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 1424c45cb8bbSRichard Henderson 1425c45cb8bbSRichard Henderson oi_prev = op->prev; 1426c45cb8bbSRichard Henderson 1427c45cb8bbSRichard Henderson switch (opc) { 1428c896fe29Sbellard case INDEX_op_call: 1429c6e113f5Sbellard { 1430c6e113f5Sbellard int call_flags; 1431c6e113f5Sbellard 1432c45cb8bbSRichard Henderson nb_oargs = op->callo; 1433c45cb8bbSRichard Henderson nb_iargs = op->calli; 1434cf066674SRichard Henderson call_flags = args[nb_oargs + nb_iargs + 1]; 1435c6e113f5Sbellard 1436c45cb8bbSRichard Henderson /* pure functions can be removed if their result is unused */ 143778505279SAurelien Jarno if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) { 1438c6e113f5Sbellard for (i = 0; i < nb_oargs; i++) { 1439c6e113f5Sbellard arg = args[i]; 1440c70fbf0aSRichard Henderson if (temp_state[arg] != TS_DEAD) { 1441c6e113f5Sbellard goto do_not_remove_call; 1442c6e113f5Sbellard } 14439c43b68dSAurelien Jarno } 1444c45cb8bbSRichard Henderson goto do_remove; 1445c6e113f5Sbellard } else { 1446c6e113f5Sbellard do_not_remove_call: 1447c896fe29Sbellard 1448c896fe29Sbellard /* output args are dead */ 1449c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 1450c896fe29Sbellard arg = args[i]; 1451c70fbf0aSRichard Henderson if (temp_state[arg] & TS_DEAD) { 1452a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 14536b64b624SAurelien Jarno } 1454c70fbf0aSRichard Henderson if (temp_state[arg] & TS_MEM) { 1455a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i; 14569c43b68dSAurelien Jarno } 1457c70fbf0aSRichard Henderson temp_state[arg] = TS_DEAD; 1458c896fe29Sbellard } 1459c896fe29Sbellard 146078505279SAurelien Jarno if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS | 146178505279SAurelien Jarno TCG_CALL_NO_READ_GLOBALS))) { 14629c43b68dSAurelien Jarno /* globals should go back to memory */ 1463c70fbf0aSRichard Henderson memset(temp_state, TS_DEAD | TS_MEM, nb_globals); 1464c70fbf0aSRichard Henderson } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) { 1465c70fbf0aSRichard Henderson /* globals should be synced to memory */ 1466c70fbf0aSRichard Henderson for (i = 0; i < nb_globals; i++) { 1467c70fbf0aSRichard Henderson temp_state[i] |= TS_MEM; 1468c70fbf0aSRichard Henderson } 1469b9c18f56Saurel32 } 1470c896fe29Sbellard 1471c19f47bfSAurelien Jarno /* record arguments that die in this helper */ 1472866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 1473866cb6cbSAurelien Jarno arg = args[i]; 147439cf05d3Sbellard if (arg != TCG_CALL_DUMMY_ARG) { 1475c70fbf0aSRichard Henderson if (temp_state[arg] & TS_DEAD) { 1476a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 1477c896fe29Sbellard } 1478c896fe29Sbellard } 147939cf05d3Sbellard } 148067cc32ebSVeres Lajos /* input arguments are live for preceding opcodes */ 1481c70fbf0aSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 1482c19f47bfSAurelien Jarno arg = args[i]; 1483c70fbf0aSRichard Henderson if (arg != TCG_CALL_DUMMY_ARG) { 1484c70fbf0aSRichard Henderson temp_state[arg] &= ~TS_DEAD; 1485c70fbf0aSRichard Henderson } 1486c19f47bfSAurelien Jarno } 1487c6e113f5Sbellard } 1488c6e113f5Sbellard } 1489c896fe29Sbellard break; 1490765b842aSRichard Henderson case INDEX_op_insn_start: 1491c896fe29Sbellard break; 14925ff9d6a4Sbellard case INDEX_op_discard: 14935ff9d6a4Sbellard /* mark the temporary as dead */ 1494c70fbf0aSRichard Henderson temp_state[args[0]] = TS_DEAD; 14955ff9d6a4Sbellard break; 14961305c451SRichard Henderson 14971305c451SRichard Henderson case INDEX_op_add2_i32: 1498c45cb8bbSRichard Henderson opc_new = INDEX_op_add_i32; 1499f1fae40cSRichard Henderson goto do_addsub2; 15001305c451SRichard Henderson case INDEX_op_sub2_i32: 1501c45cb8bbSRichard Henderson opc_new = INDEX_op_sub_i32; 1502f1fae40cSRichard Henderson goto do_addsub2; 1503f1fae40cSRichard Henderson case INDEX_op_add2_i64: 1504c45cb8bbSRichard Henderson opc_new = INDEX_op_add_i64; 1505f1fae40cSRichard Henderson goto do_addsub2; 1506f1fae40cSRichard Henderson case INDEX_op_sub2_i64: 1507c45cb8bbSRichard Henderson opc_new = INDEX_op_sub_i64; 1508f1fae40cSRichard Henderson do_addsub2: 15091305c451SRichard Henderson nb_iargs = 4; 15101305c451SRichard Henderson nb_oargs = 2; 15111305c451SRichard Henderson /* Test if the high part of the operation is dead, but not 15121305c451SRichard Henderson the low part. The result can be optimized to a simple 15131305c451SRichard Henderson add or sub. This happens often for x86_64 guest when the 15141305c451SRichard Henderson cpu mode is set to 32 bit. */ 1515c70fbf0aSRichard Henderson if (temp_state[args[1]] == TS_DEAD) { 1516c70fbf0aSRichard Henderson if (temp_state[args[0]] == TS_DEAD) { 15171305c451SRichard Henderson goto do_remove; 15181305c451SRichard Henderson } 1519c45cb8bbSRichard Henderson /* Replace the opcode and adjust the args in place, 1520c45cb8bbSRichard Henderson leaving 3 unused args at the end. */ 1521c45cb8bbSRichard Henderson op->opc = opc = opc_new; 15221305c451SRichard Henderson args[1] = args[2]; 15231305c451SRichard Henderson args[2] = args[4]; 15241305c451SRichard Henderson /* Fall through and mark the single-word operation live. */ 15251305c451SRichard Henderson nb_iargs = 2; 15261305c451SRichard Henderson nb_oargs = 1; 15271305c451SRichard Henderson } 15281305c451SRichard Henderson goto do_not_remove; 15291305c451SRichard Henderson 15301414968aSRichard Henderson case INDEX_op_mulu2_i32: 1531c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i32; 1532c45cb8bbSRichard Henderson opc_new2 = INDEX_op_muluh_i32; 1533c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_muluh_i32; 153403271524SRichard Henderson goto do_mul2; 1535f1fae40cSRichard Henderson case INDEX_op_muls2_i32: 1536c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i32; 1537c45cb8bbSRichard Henderson opc_new2 = INDEX_op_mulsh_i32; 1538c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_mulsh_i32; 1539f1fae40cSRichard Henderson goto do_mul2; 1540f1fae40cSRichard Henderson case INDEX_op_mulu2_i64: 1541c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i64; 1542c45cb8bbSRichard Henderson opc_new2 = INDEX_op_muluh_i64; 1543c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_muluh_i64; 154403271524SRichard Henderson goto do_mul2; 1545f1fae40cSRichard Henderson case INDEX_op_muls2_i64: 1546c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i64; 1547c45cb8bbSRichard Henderson opc_new2 = INDEX_op_mulsh_i64; 1548c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_mulsh_i64; 154903271524SRichard Henderson goto do_mul2; 1550f1fae40cSRichard Henderson do_mul2: 15511414968aSRichard Henderson nb_iargs = 2; 15521414968aSRichard Henderson nb_oargs = 2; 1553c70fbf0aSRichard Henderson if (temp_state[args[1]] == TS_DEAD) { 1554c70fbf0aSRichard Henderson if (temp_state[args[0]] == TS_DEAD) { 155503271524SRichard Henderson /* Both parts of the operation are dead. */ 15561414968aSRichard Henderson goto do_remove; 15571414968aSRichard Henderson } 155803271524SRichard Henderson /* The high part of the operation is dead; generate the low. */ 1559c45cb8bbSRichard Henderson op->opc = opc = opc_new; 15601414968aSRichard Henderson args[1] = args[2]; 15611414968aSRichard Henderson args[2] = args[3]; 1562c70fbf0aSRichard Henderson } else if (temp_state[args[0]] == TS_DEAD && have_opc_new2) { 156303271524SRichard Henderson /* The low part of the operation is dead; generate the high. */ 1564c45cb8bbSRichard Henderson op->opc = opc = opc_new2; 156503271524SRichard Henderson args[0] = args[1]; 156603271524SRichard Henderson args[1] = args[2]; 156703271524SRichard Henderson args[2] = args[3]; 156803271524SRichard Henderson } else { 156903271524SRichard Henderson goto do_not_remove; 157003271524SRichard Henderson } 157103271524SRichard Henderson /* Mark the single-word operation live. */ 15721414968aSRichard Henderson nb_oargs = 1; 15731414968aSRichard Henderson goto do_not_remove; 15741414968aSRichard Henderson 1575c896fe29Sbellard default: 15761305c451SRichard Henderson /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */ 1577c896fe29Sbellard nb_iargs = def->nb_iargs; 1578c896fe29Sbellard nb_oargs = def->nb_oargs; 1579c896fe29Sbellard 1580c896fe29Sbellard /* Test if the operation can be removed because all 15815ff9d6a4Sbellard its outputs are dead. We assume that nb_oargs == 0 15825ff9d6a4Sbellard implies side effects */ 15835ff9d6a4Sbellard if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) { 1584c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 1585c70fbf0aSRichard Henderson if (temp_state[args[i]] != TS_DEAD) { 1586c896fe29Sbellard goto do_not_remove; 1587c896fe29Sbellard } 15889c43b68dSAurelien Jarno } 15891305c451SRichard Henderson do_remove: 15900c627cdcSRichard Henderson tcg_op_remove(s, op); 1591c896fe29Sbellard } else { 1592c896fe29Sbellard do_not_remove: 1593c896fe29Sbellard /* output args are dead */ 1594c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 1595c896fe29Sbellard arg = args[i]; 1596c70fbf0aSRichard Henderson if (temp_state[arg] & TS_DEAD) { 1597a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 15986b64b624SAurelien Jarno } 1599c70fbf0aSRichard Henderson if (temp_state[arg] & TS_MEM) { 1600a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i; 16019c43b68dSAurelien Jarno } 1602c70fbf0aSRichard Henderson temp_state[arg] = TS_DEAD; 1603c896fe29Sbellard } 1604c896fe29Sbellard 1605c896fe29Sbellard /* if end of basic block, update */ 1606c896fe29Sbellard if (def->flags & TCG_OPF_BB_END) { 1607c70fbf0aSRichard Henderson tcg_la_bb_end(s, temp_state); 16083d5c5f87SAurelien Jarno } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { 16093d5c5f87SAurelien Jarno /* globals should be synced to memory */ 1610c70fbf0aSRichard Henderson for (i = 0; i < nb_globals; i++) { 1611c70fbf0aSRichard Henderson temp_state[i] |= TS_MEM; 1612c70fbf0aSRichard Henderson } 1613c896fe29Sbellard } 1614c896fe29Sbellard 1615c19f47bfSAurelien Jarno /* record arguments that die in this opcode */ 1616866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 1617866cb6cbSAurelien Jarno arg = args[i]; 1618c70fbf0aSRichard Henderson if (temp_state[arg] & TS_DEAD) { 1619a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 1620c896fe29Sbellard } 1621c19f47bfSAurelien Jarno } 162267cc32ebSVeres Lajos /* input arguments are live for preceding opcodes */ 1623c19f47bfSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 1624c70fbf0aSRichard Henderson temp_state[args[i]] &= ~TS_DEAD; 1625c896fe29Sbellard } 1626c896fe29Sbellard } 1627c896fe29Sbellard break; 1628c896fe29Sbellard } 1629bee158cbSRichard Henderson op->life = arg_life; 1630c896fe29Sbellard } 16311ff0a2c5SEvgeny Voevodin } 1632c896fe29Sbellard 16335a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries. */ 16345a18407fSRichard Henderson static bool liveness_pass_2(TCGContext *s, uint8_t *temp_state) 16355a18407fSRichard Henderson { 16365a18407fSRichard Henderson int nb_globals = s->nb_globals; 16375a18407fSRichard Henderson int16_t *dir_temps; 16385a18407fSRichard Henderson int i, oi, oi_next; 16395a18407fSRichard Henderson bool changes = false; 16405a18407fSRichard Henderson 16415a18407fSRichard Henderson dir_temps = tcg_malloc(nb_globals * sizeof(int16_t)); 16425a18407fSRichard Henderson memset(dir_temps, 0, nb_globals * sizeof(int16_t)); 16435a18407fSRichard Henderson 16445a18407fSRichard Henderson /* Create a temporary for each indirect global. */ 16455a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 16465a18407fSRichard Henderson TCGTemp *its = &s->temps[i]; 16475a18407fSRichard Henderson if (its->indirect_reg) { 16485a18407fSRichard Henderson TCGTemp *dts = tcg_temp_alloc(s); 16495a18407fSRichard Henderson dts->type = its->type; 16505a18407fSRichard Henderson dts->base_type = its->base_type; 16515a18407fSRichard Henderson dir_temps[i] = temp_idx(s, dts); 16525a18407fSRichard Henderson } 16535a18407fSRichard Henderson } 16545a18407fSRichard Henderson 16555a18407fSRichard Henderson memset(temp_state, TS_DEAD, nb_globals); 16565a18407fSRichard Henderson 16575a18407fSRichard Henderson for (oi = s->gen_op_buf[0].next; oi != 0; oi = oi_next) { 16585a18407fSRichard Henderson TCGOp *op = &s->gen_op_buf[oi]; 16595a18407fSRichard Henderson TCGArg *args = &s->gen_opparam_buf[op->args]; 16605a18407fSRichard Henderson TCGOpcode opc = op->opc; 16615a18407fSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 16625a18407fSRichard Henderson TCGLifeData arg_life = op->life; 16635a18407fSRichard Henderson int nb_iargs, nb_oargs, call_flags; 16645a18407fSRichard Henderson TCGArg arg, dir; 16655a18407fSRichard Henderson 16665a18407fSRichard Henderson oi_next = op->next; 16675a18407fSRichard Henderson 16685a18407fSRichard Henderson if (opc == INDEX_op_call) { 16695a18407fSRichard Henderson nb_oargs = op->callo; 16705a18407fSRichard Henderson nb_iargs = op->calli; 16715a18407fSRichard Henderson call_flags = args[nb_oargs + nb_iargs + 1]; 16725a18407fSRichard Henderson } else { 16735a18407fSRichard Henderson nb_iargs = def->nb_iargs; 16745a18407fSRichard Henderson nb_oargs = def->nb_oargs; 16755a18407fSRichard Henderson 16765a18407fSRichard Henderson /* Set flags similar to how calls require. */ 16775a18407fSRichard Henderson if (def->flags & TCG_OPF_BB_END) { 16785a18407fSRichard Henderson /* Like writing globals: save_globals */ 16795a18407fSRichard Henderson call_flags = 0; 16805a18407fSRichard Henderson } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { 16815a18407fSRichard Henderson /* Like reading globals: sync_globals */ 16825a18407fSRichard Henderson call_flags = TCG_CALL_NO_WRITE_GLOBALS; 16835a18407fSRichard Henderson } else { 16845a18407fSRichard Henderson /* No effect on globals. */ 16855a18407fSRichard Henderson call_flags = (TCG_CALL_NO_READ_GLOBALS | 16865a18407fSRichard Henderson TCG_CALL_NO_WRITE_GLOBALS); 16875a18407fSRichard Henderson } 16885a18407fSRichard Henderson } 16895a18407fSRichard Henderson 16905a18407fSRichard Henderson /* Make sure that input arguments are available. */ 16915a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 16925a18407fSRichard Henderson arg = args[i]; 16935a18407fSRichard Henderson /* Note this unsigned test catches TCG_CALL_ARG_DUMMY too. */ 16945a18407fSRichard Henderson if (arg < nb_globals) { 16955a18407fSRichard Henderson dir = dir_temps[arg]; 16965a18407fSRichard Henderson if (dir != 0 && temp_state[arg] == TS_DEAD) { 16975a18407fSRichard Henderson TCGTemp *its = &s->temps[arg]; 16985a18407fSRichard Henderson TCGOpcode lopc = (its->type == TCG_TYPE_I32 16995a18407fSRichard Henderson ? INDEX_op_ld_i32 17005a18407fSRichard Henderson : INDEX_op_ld_i64); 17015a18407fSRichard Henderson TCGOp *lop = tcg_op_insert_before(s, op, lopc, 3); 17025a18407fSRichard Henderson TCGArg *largs = &s->gen_opparam_buf[lop->args]; 17035a18407fSRichard Henderson 17045a18407fSRichard Henderson largs[0] = dir; 17055a18407fSRichard Henderson largs[1] = temp_idx(s, its->mem_base); 17065a18407fSRichard Henderson largs[2] = its->mem_offset; 17075a18407fSRichard Henderson 17085a18407fSRichard Henderson /* Loaded, but synced with memory. */ 17095a18407fSRichard Henderson temp_state[arg] = TS_MEM; 17105a18407fSRichard Henderson } 17115a18407fSRichard Henderson } 17125a18407fSRichard Henderson } 17135a18407fSRichard Henderson 17145a18407fSRichard Henderson /* Perform input replacement, and mark inputs that became dead. 17155a18407fSRichard Henderson No action is required except keeping temp_state up to date 17165a18407fSRichard Henderson so that we reload when needed. */ 17175a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 17185a18407fSRichard Henderson arg = args[i]; 17195a18407fSRichard Henderson if (arg < nb_globals) { 17205a18407fSRichard Henderson dir = dir_temps[arg]; 17215a18407fSRichard Henderson if (dir != 0) { 17225a18407fSRichard Henderson args[i] = dir; 17235a18407fSRichard Henderson changes = true; 17245a18407fSRichard Henderson if (IS_DEAD_ARG(i)) { 17255a18407fSRichard Henderson temp_state[arg] = TS_DEAD; 17265a18407fSRichard Henderson } 17275a18407fSRichard Henderson } 17285a18407fSRichard Henderson } 17295a18407fSRichard Henderson } 17305a18407fSRichard Henderson 17315a18407fSRichard Henderson /* Liveness analysis should ensure that the following are 17325a18407fSRichard Henderson all correct, for call sites and basic block end points. */ 17335a18407fSRichard Henderson if (call_flags & TCG_CALL_NO_READ_GLOBALS) { 17345a18407fSRichard Henderson /* Nothing to do */ 17355a18407fSRichard Henderson } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) { 17365a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 17375a18407fSRichard Henderson /* Liveness should see that globals are synced back, 17385a18407fSRichard Henderson that is, either TS_DEAD or TS_MEM. */ 17395a18407fSRichard Henderson tcg_debug_assert(dir_temps[i] == 0 17405a18407fSRichard Henderson || temp_state[i] != 0); 17415a18407fSRichard Henderson } 17425a18407fSRichard Henderson } else { 17435a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 17445a18407fSRichard Henderson /* Liveness should see that globals are saved back, 17455a18407fSRichard Henderson that is, TS_DEAD, waiting to be reloaded. */ 17465a18407fSRichard Henderson tcg_debug_assert(dir_temps[i] == 0 17475a18407fSRichard Henderson || temp_state[i] == TS_DEAD); 17485a18407fSRichard Henderson } 17495a18407fSRichard Henderson } 17505a18407fSRichard Henderson 17515a18407fSRichard Henderson /* Outputs become available. */ 17525a18407fSRichard Henderson for (i = 0; i < nb_oargs; i++) { 17535a18407fSRichard Henderson arg = args[i]; 17545a18407fSRichard Henderson if (arg >= nb_globals) { 17555a18407fSRichard Henderson continue; 17565a18407fSRichard Henderson } 17575a18407fSRichard Henderson dir = dir_temps[arg]; 17585a18407fSRichard Henderson if (dir == 0) { 17595a18407fSRichard Henderson continue; 17605a18407fSRichard Henderson } 17615a18407fSRichard Henderson args[i] = dir; 17625a18407fSRichard Henderson changes = true; 17635a18407fSRichard Henderson 17645a18407fSRichard Henderson /* The output is now live and modified. */ 17655a18407fSRichard Henderson temp_state[arg] = 0; 17665a18407fSRichard Henderson 17675a18407fSRichard Henderson /* Sync outputs upon their last write. */ 17685a18407fSRichard Henderson if (NEED_SYNC_ARG(i)) { 17695a18407fSRichard Henderson TCGTemp *its = &s->temps[arg]; 17705a18407fSRichard Henderson TCGOpcode sopc = (its->type == TCG_TYPE_I32 17715a18407fSRichard Henderson ? INDEX_op_st_i32 17725a18407fSRichard Henderson : INDEX_op_st_i64); 17735a18407fSRichard Henderson TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3); 17745a18407fSRichard Henderson TCGArg *sargs = &s->gen_opparam_buf[sop->args]; 17755a18407fSRichard Henderson 17765a18407fSRichard Henderson sargs[0] = dir; 17775a18407fSRichard Henderson sargs[1] = temp_idx(s, its->mem_base); 17785a18407fSRichard Henderson sargs[2] = its->mem_offset; 17795a18407fSRichard Henderson 17805a18407fSRichard Henderson temp_state[arg] = TS_MEM; 17815a18407fSRichard Henderson } 17825a18407fSRichard Henderson /* Drop outputs that are dead. */ 17835a18407fSRichard Henderson if (IS_DEAD_ARG(i)) { 17845a18407fSRichard Henderson temp_state[arg] = TS_DEAD; 17855a18407fSRichard Henderson } 17865a18407fSRichard Henderson } 17875a18407fSRichard Henderson } 17885a18407fSRichard Henderson 17895a18407fSRichard Henderson return changes; 17905a18407fSRichard Henderson } 17915a18407fSRichard Henderson 17928d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG 1793c896fe29Sbellard static void dump_regs(TCGContext *s) 1794c896fe29Sbellard { 1795c896fe29Sbellard TCGTemp *ts; 1796c896fe29Sbellard int i; 1797c896fe29Sbellard char buf[64]; 1798c896fe29Sbellard 1799c896fe29Sbellard for(i = 0; i < s->nb_temps; i++) { 1800c896fe29Sbellard ts = &s->temps[i]; 1801ac56dd48Spbrook printf(" %10s: ", tcg_get_arg_str_idx(s, buf, sizeof(buf), i)); 1802c896fe29Sbellard switch(ts->val_type) { 1803c896fe29Sbellard case TEMP_VAL_REG: 1804c896fe29Sbellard printf("%s", tcg_target_reg_names[ts->reg]); 1805c896fe29Sbellard break; 1806c896fe29Sbellard case TEMP_VAL_MEM: 1807b3a62939SRichard Henderson printf("%d(%s)", (int)ts->mem_offset, 1808b3a62939SRichard Henderson tcg_target_reg_names[ts->mem_base->reg]); 1809c896fe29Sbellard break; 1810c896fe29Sbellard case TEMP_VAL_CONST: 1811c896fe29Sbellard printf("$0x%" TCG_PRIlx, ts->val); 1812c896fe29Sbellard break; 1813c896fe29Sbellard case TEMP_VAL_DEAD: 1814c896fe29Sbellard printf("D"); 1815c896fe29Sbellard break; 1816c896fe29Sbellard default: 1817c896fe29Sbellard printf("???"); 1818c896fe29Sbellard break; 1819c896fe29Sbellard } 1820c896fe29Sbellard printf("\n"); 1821c896fe29Sbellard } 1822c896fe29Sbellard 1823c896fe29Sbellard for(i = 0; i < TCG_TARGET_NB_REGS; i++) { 1824f8b2f202SRichard Henderson if (s->reg_to_temp[i] != NULL) { 1825c896fe29Sbellard printf("%s: %s\n", 1826c896fe29Sbellard tcg_target_reg_names[i], 1827f8b2f202SRichard Henderson tcg_get_arg_str_ptr(s, buf, sizeof(buf), s->reg_to_temp[i])); 1828c896fe29Sbellard } 1829c896fe29Sbellard } 1830c896fe29Sbellard } 1831c896fe29Sbellard 1832c896fe29Sbellard static void check_regs(TCGContext *s) 1833c896fe29Sbellard { 1834869938aeSRichard Henderson int reg; 1835b6638662SRichard Henderson int k; 1836c896fe29Sbellard TCGTemp *ts; 1837c896fe29Sbellard char buf[64]; 1838c896fe29Sbellard 1839c896fe29Sbellard for (reg = 0; reg < TCG_TARGET_NB_REGS; reg++) { 1840f8b2f202SRichard Henderson ts = s->reg_to_temp[reg]; 1841f8b2f202SRichard Henderson if (ts != NULL) { 1842f8b2f202SRichard Henderson if (ts->val_type != TEMP_VAL_REG || ts->reg != reg) { 1843c896fe29Sbellard printf("Inconsistency for register %s:\n", 1844c896fe29Sbellard tcg_target_reg_names[reg]); 1845b03cce8eSbellard goto fail; 1846c896fe29Sbellard } 1847c896fe29Sbellard } 1848c896fe29Sbellard } 1849c896fe29Sbellard for (k = 0; k < s->nb_temps; k++) { 1850c896fe29Sbellard ts = &s->temps[k]; 1851f8b2f202SRichard Henderson if (ts->val_type == TEMP_VAL_REG && !ts->fixed_reg 1852f8b2f202SRichard Henderson && s->reg_to_temp[ts->reg] != ts) { 1853c896fe29Sbellard printf("Inconsistency for temp %s:\n", 1854f8b2f202SRichard Henderson tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts)); 1855b03cce8eSbellard fail: 1856c896fe29Sbellard printf("reg state:\n"); 1857c896fe29Sbellard dump_regs(s); 1858c896fe29Sbellard tcg_abort(); 1859c896fe29Sbellard } 1860c896fe29Sbellard } 1861c896fe29Sbellard } 1862c896fe29Sbellard #endif 1863c896fe29Sbellard 1864c896fe29Sbellard static void temp_allocate_frame(TCGContext *s, int temp) 1865c896fe29Sbellard { 1866c896fe29Sbellard TCGTemp *ts; 1867c896fe29Sbellard ts = &s->temps[temp]; 18689b9c37c3SRichard Henderson #if !(defined(__sparc__) && TCG_TARGET_REG_BITS == 64) 18699b9c37c3SRichard Henderson /* Sparc64 stack is accessed with offset of 2047 */ 1870b591dc59SBlue Swirl s->current_frame_offset = (s->current_frame_offset + 1871b591dc59SBlue Swirl (tcg_target_long)sizeof(tcg_target_long) - 1) & 1872b591dc59SBlue Swirl ~(sizeof(tcg_target_long) - 1); 1873f44c9960SBlue Swirl #endif 1874b591dc59SBlue Swirl if (s->current_frame_offset + (tcg_target_long)sizeof(tcg_target_long) > 1875b591dc59SBlue Swirl s->frame_end) { 18765ff9d6a4Sbellard tcg_abort(); 1877b591dc59SBlue Swirl } 1878c896fe29Sbellard ts->mem_offset = s->current_frame_offset; 1879b3a62939SRichard Henderson ts->mem_base = s->frame_temp; 1880c896fe29Sbellard ts->mem_allocated = 1; 1881e2c6d1b4SRichard Henderson s->current_frame_offset += sizeof(tcg_target_long); 1882c896fe29Sbellard } 1883c896fe29Sbellard 1884b3915dbbSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet); 1885b3915dbbSRichard Henderson 188659d7c14eSRichard Henderson /* Mark a temporary as free or dead. If 'free_or_dead' is negative, 188759d7c14eSRichard Henderson mark it free; otherwise mark it dead. */ 188859d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead) 1889c896fe29Sbellard { 189059d7c14eSRichard Henderson if (ts->fixed_reg) { 189159d7c14eSRichard Henderson return; 189259d7c14eSRichard Henderson } 189359d7c14eSRichard Henderson if (ts->val_type == TEMP_VAL_REG) { 189459d7c14eSRichard Henderson s->reg_to_temp[ts->reg] = NULL; 189559d7c14eSRichard Henderson } 189659d7c14eSRichard Henderson ts->val_type = (free_or_dead < 0 189759d7c14eSRichard Henderson || ts->temp_local 189859d7c14eSRichard Henderson || temp_idx(s, ts) < s->nb_globals 189959d7c14eSRichard Henderson ? TEMP_VAL_MEM : TEMP_VAL_DEAD); 190059d7c14eSRichard Henderson } 1901c896fe29Sbellard 190259d7c14eSRichard Henderson /* Mark a temporary as dead. */ 190359d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts) 190459d7c14eSRichard Henderson { 190559d7c14eSRichard Henderson temp_free_or_dead(s, ts, 1); 190659d7c14eSRichard Henderson } 190759d7c14eSRichard Henderson 190859d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary 190959d7c14eSRichard Henderson registers needs to be allocated to store a constant. If 'free_or_dead' 191059d7c14eSRichard Henderson is non-zero, subsequently release the temporary; if it is positive, the 191159d7c14eSRichard Henderson temp is dead; if it is negative, the temp is free. */ 191259d7c14eSRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, 191359d7c14eSRichard Henderson TCGRegSet allocated_regs, int free_or_dead) 191459d7c14eSRichard Henderson { 191559d7c14eSRichard Henderson if (ts->fixed_reg) { 191659d7c14eSRichard Henderson return; 191759d7c14eSRichard Henderson } 191859d7c14eSRichard Henderson if (!ts->mem_coherent) { 19197f6ceedfSAurelien Jarno if (!ts->mem_allocated) { 1920f8b2f202SRichard Henderson temp_allocate_frame(s, temp_idx(s, ts)); 192159d7c14eSRichard Henderson } 192259d7c14eSRichard Henderson switch (ts->val_type) { 192359d7c14eSRichard Henderson case TEMP_VAL_CONST: 192459d7c14eSRichard Henderson /* If we're going to free the temp immediately, then we won't 192559d7c14eSRichard Henderson require it later in a register, so attempt to store the 192659d7c14eSRichard Henderson constant to memory directly. */ 192759d7c14eSRichard Henderson if (free_or_dead 192859d7c14eSRichard Henderson && tcg_out_sti(s, ts->type, ts->val, 192959d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset)) { 193059d7c14eSRichard Henderson break; 193159d7c14eSRichard Henderson } 193259d7c14eSRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 193359d7c14eSRichard Henderson allocated_regs); 193459d7c14eSRichard Henderson /* fallthrough */ 193559d7c14eSRichard Henderson 193659d7c14eSRichard Henderson case TEMP_VAL_REG: 193759d7c14eSRichard Henderson tcg_out_st(s, ts->type, ts->reg, 193859d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset); 193959d7c14eSRichard Henderson break; 194059d7c14eSRichard Henderson 194159d7c14eSRichard Henderson case TEMP_VAL_MEM: 194259d7c14eSRichard Henderson break; 194359d7c14eSRichard Henderson 194459d7c14eSRichard Henderson case TEMP_VAL_DEAD: 194559d7c14eSRichard Henderson default: 194659d7c14eSRichard Henderson tcg_abort(); 1947c896fe29Sbellard } 19487f6ceedfSAurelien Jarno ts->mem_coherent = 1; 19497f6ceedfSAurelien Jarno } 195059d7c14eSRichard Henderson if (free_or_dead) { 195159d7c14eSRichard Henderson temp_free_or_dead(s, ts, free_or_dead); 195259d7c14eSRichard Henderson } 195359d7c14eSRichard Henderson } 19547f6ceedfSAurelien Jarno 19557f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */ 1956b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs) 19577f6ceedfSAurelien Jarno { 1958f8b2f202SRichard Henderson TCGTemp *ts = s->reg_to_temp[reg]; 1959f8b2f202SRichard Henderson if (ts != NULL) { 196059d7c14eSRichard Henderson temp_sync(s, ts, allocated_regs, -1); 1961c896fe29Sbellard } 1962c896fe29Sbellard } 1963c896fe29Sbellard 1964c896fe29Sbellard /* Allocate a register belonging to reg1 & ~reg2 */ 1965b3915dbbSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet desired_regs, 196691478cefSRichard Henderson TCGRegSet allocated_regs, bool rev) 1967c896fe29Sbellard { 196891478cefSRichard Henderson int i, n = ARRAY_SIZE(tcg_target_reg_alloc_order); 196991478cefSRichard Henderson const int *order; 1970b6638662SRichard Henderson TCGReg reg; 1971c896fe29Sbellard TCGRegSet reg_ct; 1972c896fe29Sbellard 1973b3915dbbSRichard Henderson tcg_regset_andnot(reg_ct, desired_regs, allocated_regs); 197491478cefSRichard Henderson order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order; 1975c896fe29Sbellard 1976c896fe29Sbellard /* first try free registers */ 197791478cefSRichard Henderson for(i = 0; i < n; i++) { 197891478cefSRichard Henderson reg = order[i]; 1979f8b2f202SRichard Henderson if (tcg_regset_test_reg(reg_ct, reg) && s->reg_to_temp[reg] == NULL) 1980c896fe29Sbellard return reg; 1981c896fe29Sbellard } 1982c896fe29Sbellard 1983c896fe29Sbellard /* XXX: do better spill choice */ 198491478cefSRichard Henderson for(i = 0; i < n; i++) { 198591478cefSRichard Henderson reg = order[i]; 1986c896fe29Sbellard if (tcg_regset_test_reg(reg_ct, reg)) { 1987b3915dbbSRichard Henderson tcg_reg_free(s, reg, allocated_regs); 1988c896fe29Sbellard return reg; 1989c896fe29Sbellard } 1990c896fe29Sbellard } 1991c896fe29Sbellard 1992c896fe29Sbellard tcg_abort(); 1993c896fe29Sbellard } 1994c896fe29Sbellard 199540ae5c62SRichard Henderson /* Make sure the temporary is in a register. If needed, allocate the register 199640ae5c62SRichard Henderson from DESIRED while avoiding ALLOCATED. */ 199740ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs, 199840ae5c62SRichard Henderson TCGRegSet allocated_regs) 199940ae5c62SRichard Henderson { 200040ae5c62SRichard Henderson TCGReg reg; 200140ae5c62SRichard Henderson 200240ae5c62SRichard Henderson switch (ts->val_type) { 200340ae5c62SRichard Henderson case TEMP_VAL_REG: 200440ae5c62SRichard Henderson return; 200540ae5c62SRichard Henderson case TEMP_VAL_CONST: 200691478cefSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs, ts->indirect_base); 200740ae5c62SRichard Henderson tcg_out_movi(s, ts->type, reg, ts->val); 200840ae5c62SRichard Henderson ts->mem_coherent = 0; 200940ae5c62SRichard Henderson break; 201040ae5c62SRichard Henderson case TEMP_VAL_MEM: 201191478cefSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs, ts->indirect_base); 201240ae5c62SRichard Henderson tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset); 201340ae5c62SRichard Henderson ts->mem_coherent = 1; 201440ae5c62SRichard Henderson break; 201540ae5c62SRichard Henderson case TEMP_VAL_DEAD: 201640ae5c62SRichard Henderson default: 201740ae5c62SRichard Henderson tcg_abort(); 201840ae5c62SRichard Henderson } 201940ae5c62SRichard Henderson ts->reg = reg; 202040ae5c62SRichard Henderson ts->val_type = TEMP_VAL_REG; 202140ae5c62SRichard Henderson s->reg_to_temp[reg] = ts; 202240ae5c62SRichard Henderson } 202340ae5c62SRichard Henderson 202459d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a 2025e8996ee0Sbellard temporary registers needs to be allocated to store a constant. */ 202659d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs) 20271ad80729SAurelien Jarno { 20282c0366f0SAurelien Jarno /* The liveness analysis already ensures that globals are back 2029eabb7b91SAurelien Jarno in memory. Keep an tcg_debug_assert for safety. */ 2030f8bf00f1SRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || ts->fixed_reg); 20311ad80729SAurelien Jarno } 20321ad80729SAurelien Jarno 20339814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be 2034641d5fbeSbellard modified be the following code. 'allocated_regs' is used in case a 2035641d5fbeSbellard temporary registers needs to be allocated to store a constant. */ 2036641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs) 2037641d5fbeSbellard { 2038641d5fbeSbellard int i; 2039641d5fbeSbellard 2040641d5fbeSbellard for (i = 0; i < s->nb_globals; i++) { 2041b13eb728SRichard Henderson temp_save(s, &s->temps[i], allocated_regs); 2042641d5fbeSbellard } 2043e5097dc8Sbellard } 2044e5097dc8Sbellard 20453d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be 20463d5c5f87SAurelien Jarno read by the following code. 'allocated_regs' is used in case a 20473d5c5f87SAurelien Jarno temporary registers needs to be allocated to store a constant. */ 20483d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs) 20493d5c5f87SAurelien Jarno { 20503d5c5f87SAurelien Jarno int i; 20513d5c5f87SAurelien Jarno 20523d5c5f87SAurelien Jarno for (i = 0; i < s->nb_globals; i++) { 205312b9b11aSRichard Henderson TCGTemp *ts = &s->temps[i]; 205412b9b11aSRichard Henderson tcg_debug_assert(ts->val_type != TEMP_VAL_REG 205512b9b11aSRichard Henderson || ts->fixed_reg 205612b9b11aSRichard Henderson || ts->mem_coherent); 20573d5c5f87SAurelien Jarno } 20583d5c5f87SAurelien Jarno } 20593d5c5f87SAurelien Jarno 2060e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and 2061e8996ee0Sbellard all globals are stored at their canonical location. */ 2062e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs) 2063e5097dc8Sbellard { 2064e5097dc8Sbellard int i; 2065e5097dc8Sbellard 2066c896fe29Sbellard for (i = s->nb_globals; i < s->nb_temps; i++) { 2067b13eb728SRichard Henderson TCGTemp *ts = &s->temps[i]; 2068641d5fbeSbellard if (ts->temp_local) { 2069b13eb728SRichard Henderson temp_save(s, ts, allocated_regs); 2070641d5fbeSbellard } else { 20712c0366f0SAurelien Jarno /* The liveness analysis already ensures that temps are dead. 2072eabb7b91SAurelien Jarno Keep an tcg_debug_assert for safety. */ 2073eabb7b91SAurelien Jarno tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD); 2074c896fe29Sbellard } 2075641d5fbeSbellard } 2076e8996ee0Sbellard 2077e8996ee0Sbellard save_globals(s, allocated_regs); 2078c896fe29Sbellard } 2079c896fe29Sbellard 20800fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots, 20810fe4fca4SPaolo Bonzini tcg_target_ulong val, TCGLifeData arg_life) 2082e8996ee0Sbellard { 2083e8996ee0Sbellard if (ots->fixed_reg) { 208459d7c14eSRichard Henderson /* For fixed registers, we do not do any constant propagation. */ 2085e8996ee0Sbellard tcg_out_movi(s, ots->type, ots->reg, val); 208659d7c14eSRichard Henderson return; 208759d7c14eSRichard Henderson } 208859d7c14eSRichard Henderson 208959d7c14eSRichard Henderson /* The movi is not explicitly generated here. */ 2090f8b2f202SRichard Henderson if (ots->val_type == TEMP_VAL_REG) { 2091f8b2f202SRichard Henderson s->reg_to_temp[ots->reg] = NULL; 2092f8b2f202SRichard Henderson } 2093e8996ee0Sbellard ots->val_type = TEMP_VAL_CONST; 2094e8996ee0Sbellard ots->val = val; 209559d7c14eSRichard Henderson ots->mem_coherent = 0; 2096ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) { 209759d7c14eSRichard Henderson temp_sync(s, ots, s->reserved_regs, IS_DEAD_ARG(0)); 209859d7c14eSRichard Henderson } else if (IS_DEAD_ARG(0)) { 2099f8bf00f1SRichard Henderson temp_dead(s, ots); 21004c4e1ab2SAurelien Jarno } 2101e8996ee0Sbellard } 2102e8996ee0Sbellard 21030fe4fca4SPaolo Bonzini static void tcg_reg_alloc_movi(TCGContext *s, const TCGArg *args, 21040fe4fca4SPaolo Bonzini TCGLifeData arg_life) 21050fe4fca4SPaolo Bonzini { 21060fe4fca4SPaolo Bonzini TCGTemp *ots = &s->temps[args[0]]; 21070fe4fca4SPaolo Bonzini tcg_target_ulong val = args[1]; 21080fe4fca4SPaolo Bonzini 21090fe4fca4SPaolo Bonzini tcg_reg_alloc_do_movi(s, ots, val, arg_life); 21100fe4fca4SPaolo Bonzini } 21110fe4fca4SPaolo Bonzini 2112c896fe29Sbellard static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def, 2113a1b3c48dSRichard Henderson const TCGArg *args, TCGLifeData arg_life) 2114c896fe29Sbellard { 2115c29c1d7eSAurelien Jarno TCGRegSet allocated_regs; 2116c896fe29Sbellard TCGTemp *ts, *ots; 2117450445d5SRichard Henderson TCGType otype, itype; 2118c896fe29Sbellard 2119c29c1d7eSAurelien Jarno tcg_regset_set(allocated_regs, s->reserved_regs); 2120c896fe29Sbellard ots = &s->temps[args[0]]; 2121c896fe29Sbellard ts = &s->temps[args[1]]; 2122450445d5SRichard Henderson 2123450445d5SRichard Henderson /* Note that otype != itype for no-op truncation. */ 2124450445d5SRichard Henderson otype = ots->type; 2125450445d5SRichard Henderson itype = ts->type; 2126c896fe29Sbellard 21270fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_CONST) { 21280fe4fca4SPaolo Bonzini /* propagate constant or generate sti */ 21290fe4fca4SPaolo Bonzini tcg_target_ulong val = ts->val; 21300fe4fca4SPaolo Bonzini if (IS_DEAD_ARG(1)) { 21310fe4fca4SPaolo Bonzini temp_dead(s, ts); 21320fe4fca4SPaolo Bonzini } 21330fe4fca4SPaolo Bonzini tcg_reg_alloc_do_movi(s, ots, val, arg_life); 21340fe4fca4SPaolo Bonzini return; 21350fe4fca4SPaolo Bonzini } 21360fe4fca4SPaolo Bonzini 21370fe4fca4SPaolo Bonzini /* If the source value is in memory we're going to be forced 21380fe4fca4SPaolo Bonzini to have it in a register in order to perform the copy. Copy 21390fe4fca4SPaolo Bonzini the SOURCE value into its own register first, that way we 21400fe4fca4SPaolo Bonzini don't have to reload SOURCE the next time it is used. */ 21410fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_MEM) { 214240ae5c62SRichard Henderson temp_load(s, ts, tcg_target_available_regs[itype], allocated_regs); 2143c29c1d7eSAurelien Jarno } 2144c29c1d7eSAurelien Jarno 21450fe4fca4SPaolo Bonzini tcg_debug_assert(ts->val_type == TEMP_VAL_REG); 2146c29c1d7eSAurelien Jarno if (IS_DEAD_ARG(0) && !ots->fixed_reg) { 2147c29c1d7eSAurelien Jarno /* mov to a non-saved dead register makes no sense (even with 2148c29c1d7eSAurelien Jarno liveness analysis disabled). */ 2149eabb7b91SAurelien Jarno tcg_debug_assert(NEED_SYNC_ARG(0)); 2150c29c1d7eSAurelien Jarno if (!ots->mem_allocated) { 2151c29c1d7eSAurelien Jarno temp_allocate_frame(s, args[0]); 2152c29c1d7eSAurelien Jarno } 2153b3a62939SRichard Henderson tcg_out_st(s, otype, ts->reg, ots->mem_base->reg, ots->mem_offset); 2154c29c1d7eSAurelien Jarno if (IS_DEAD_ARG(1)) { 2155f8bf00f1SRichard Henderson temp_dead(s, ts); 2156c29c1d7eSAurelien Jarno } 2157f8bf00f1SRichard Henderson temp_dead(s, ots); 2158e8996ee0Sbellard } else { 2159c29c1d7eSAurelien Jarno if (IS_DEAD_ARG(1) && !ts->fixed_reg && !ots->fixed_reg) { 2160c29c1d7eSAurelien Jarno /* the mov can be suppressed */ 2161c29c1d7eSAurelien Jarno if (ots->val_type == TEMP_VAL_REG) { 2162f8b2f202SRichard Henderson s->reg_to_temp[ots->reg] = NULL; 2163c896fe29Sbellard } 2164c29c1d7eSAurelien Jarno ots->reg = ts->reg; 2165f8bf00f1SRichard Henderson temp_dead(s, ts); 2166c29c1d7eSAurelien Jarno } else { 2167c29c1d7eSAurelien Jarno if (ots->val_type != TEMP_VAL_REG) { 2168c29c1d7eSAurelien Jarno /* When allocating a new register, make sure to not spill the 2169c29c1d7eSAurelien Jarno input one. */ 2170c29c1d7eSAurelien Jarno tcg_regset_set_reg(allocated_regs, ts->reg); 2171450445d5SRichard Henderson ots->reg = tcg_reg_alloc(s, tcg_target_available_regs[otype], 217291478cefSRichard Henderson allocated_regs, ots->indirect_base); 2173c29c1d7eSAurelien Jarno } 2174450445d5SRichard Henderson tcg_out_mov(s, otype, ots->reg, ts->reg); 2175c29c1d7eSAurelien Jarno } 2176c896fe29Sbellard ots->val_type = TEMP_VAL_REG; 2177c896fe29Sbellard ots->mem_coherent = 0; 2178f8b2f202SRichard Henderson s->reg_to_temp[ots->reg] = ots; 2179ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) { 218059d7c14eSRichard Henderson temp_sync(s, ots, allocated_regs, 0); 2181c29c1d7eSAurelien Jarno } 2182ec7a869dSAurelien Jarno } 2183c896fe29Sbellard } 2184c896fe29Sbellard 2185c896fe29Sbellard static void tcg_reg_alloc_op(TCGContext *s, 2186a9751609SRichard Henderson const TCGOpDef *def, TCGOpcode opc, 2187a1b3c48dSRichard Henderson const TCGArg *args, TCGLifeData arg_life) 2188c896fe29Sbellard { 218982790a87SRichard Henderson TCGRegSet i_allocated_regs; 219082790a87SRichard Henderson TCGRegSet o_allocated_regs; 2191b6638662SRichard Henderson int i, k, nb_iargs, nb_oargs; 2192b6638662SRichard Henderson TCGReg reg; 2193c896fe29Sbellard TCGArg arg; 2194c896fe29Sbellard const TCGArgConstraint *arg_ct; 2195c896fe29Sbellard TCGTemp *ts; 2196c896fe29Sbellard TCGArg new_args[TCG_MAX_OP_ARGS]; 2197c896fe29Sbellard int const_args[TCG_MAX_OP_ARGS]; 2198c896fe29Sbellard 2199c896fe29Sbellard nb_oargs = def->nb_oargs; 2200c896fe29Sbellard nb_iargs = def->nb_iargs; 2201c896fe29Sbellard 2202c896fe29Sbellard /* copy constants */ 2203c896fe29Sbellard memcpy(new_args + nb_oargs + nb_iargs, 2204c896fe29Sbellard args + nb_oargs + nb_iargs, 2205c896fe29Sbellard sizeof(TCGArg) * def->nb_cargs); 2206c896fe29Sbellard 220782790a87SRichard Henderson tcg_regset_set(i_allocated_regs, s->reserved_regs); 220882790a87SRichard Henderson tcg_regset_set(o_allocated_regs, s->reserved_regs); 220982790a87SRichard Henderson 2210c896fe29Sbellard /* satisfy input constraints */ 2211c896fe29Sbellard for(k = 0; k < nb_iargs; k++) { 2212c896fe29Sbellard i = def->sorted_args[nb_oargs + k]; 2213c896fe29Sbellard arg = args[i]; 2214c896fe29Sbellard arg_ct = &def->args_ct[i]; 2215c896fe29Sbellard ts = &s->temps[arg]; 221640ae5c62SRichard Henderson 221740ae5c62SRichard Henderson if (ts->val_type == TEMP_VAL_CONST 221840ae5c62SRichard Henderson && tcg_target_const_match(ts->val, ts->type, arg_ct)) { 2219c896fe29Sbellard /* constant is OK for instruction */ 2220c896fe29Sbellard const_args[i] = 1; 2221c896fe29Sbellard new_args[i] = ts->val; 2222c896fe29Sbellard goto iarg_end; 2223c896fe29Sbellard } 222440ae5c62SRichard Henderson 222582790a87SRichard Henderson temp_load(s, ts, arg_ct->u.regs, i_allocated_regs); 222640ae5c62SRichard Henderson 22275ff9d6a4Sbellard if (arg_ct->ct & TCG_CT_IALIAS) { 22285ff9d6a4Sbellard if (ts->fixed_reg) { 22295ff9d6a4Sbellard /* if fixed register, we must allocate a new register 22305ff9d6a4Sbellard if the alias is not the same register */ 22315ff9d6a4Sbellard if (arg != args[arg_ct->alias_index]) 22325ff9d6a4Sbellard goto allocate_in_reg; 22335ff9d6a4Sbellard } else { 2234c896fe29Sbellard /* if the input is aliased to an output and if it is 2235c896fe29Sbellard not dead after the instruction, we must allocate 2236c896fe29Sbellard a new register and move it */ 2237866cb6cbSAurelien Jarno if (!IS_DEAD_ARG(i)) { 2238c896fe29Sbellard goto allocate_in_reg; 2239c896fe29Sbellard } 22407e1df267SAurelien Jarno /* check if the current register has already been allocated 22417e1df267SAurelien Jarno for another input aliased to an output */ 22427e1df267SAurelien Jarno int k2, i2; 22437e1df267SAurelien Jarno for (k2 = 0 ; k2 < k ; k2++) { 22447e1df267SAurelien Jarno i2 = def->sorted_args[nb_oargs + k2]; 22457e1df267SAurelien Jarno if ((def->args_ct[i2].ct & TCG_CT_IALIAS) && 22467e1df267SAurelien Jarno (new_args[i2] == ts->reg)) { 22477e1df267SAurelien Jarno goto allocate_in_reg; 22487e1df267SAurelien Jarno } 22497e1df267SAurelien Jarno } 22505ff9d6a4Sbellard } 2251866cb6cbSAurelien Jarno } 2252c896fe29Sbellard reg = ts->reg; 2253c896fe29Sbellard if (tcg_regset_test_reg(arg_ct->u.regs, reg)) { 2254c896fe29Sbellard /* nothing to do : the constraint is satisfied */ 2255c896fe29Sbellard } else { 2256c896fe29Sbellard allocate_in_reg: 2257c896fe29Sbellard /* allocate a new register matching the constraint 2258c896fe29Sbellard and move the temporary register into it */ 225982790a87SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->u.regs, i_allocated_regs, 226091478cefSRichard Henderson ts->indirect_base); 22613b6dac34SRichard Henderson tcg_out_mov(s, ts->type, reg, ts->reg); 2262c896fe29Sbellard } 2263c896fe29Sbellard new_args[i] = reg; 2264c896fe29Sbellard const_args[i] = 0; 226582790a87SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg); 2266c896fe29Sbellard iarg_end: ; 2267c896fe29Sbellard } 2268c896fe29Sbellard 2269c896fe29Sbellard /* mark dead temporaries and free the associated registers */ 2270866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 2271866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) { 2272f8bf00f1SRichard Henderson temp_dead(s, &s->temps[args[i]]); 2273c896fe29Sbellard } 2274c896fe29Sbellard } 2275c896fe29Sbellard 2276a52ad07eSAurelien Jarno if (def->flags & TCG_OPF_BB_END) { 227782790a87SRichard Henderson tcg_reg_alloc_bb_end(s, i_allocated_regs); 2278a52ad07eSAurelien Jarno } else { 2279c896fe29Sbellard if (def->flags & TCG_OPF_CALL_CLOBBER) { 2280b03cce8eSbellard /* XXX: permit generic clobber register list ? */ 2281c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) { 2282c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { 228382790a87SRichard Henderson tcg_reg_free(s, i, i_allocated_regs); 2284c896fe29Sbellard } 2285c896fe29Sbellard } 22863d5c5f87SAurelien Jarno } 22873d5c5f87SAurelien Jarno if (def->flags & TCG_OPF_SIDE_EFFECTS) { 22883d5c5f87SAurelien Jarno /* sync globals if the op has side effects and might trigger 22893d5c5f87SAurelien Jarno an exception. */ 229082790a87SRichard Henderson sync_globals(s, i_allocated_regs); 2291c896fe29Sbellard } 2292c896fe29Sbellard 2293c896fe29Sbellard /* satisfy the output constraints */ 2294c896fe29Sbellard for(k = 0; k < nb_oargs; k++) { 2295c896fe29Sbellard i = def->sorted_args[k]; 2296c896fe29Sbellard arg = args[i]; 2297c896fe29Sbellard arg_ct = &def->args_ct[i]; 2298c896fe29Sbellard ts = &s->temps[arg]; 2299c896fe29Sbellard if (arg_ct->ct & TCG_CT_ALIAS) { 23005ff9d6a4Sbellard reg = new_args[arg_ct->alias_index]; 230182790a87SRichard Henderson } else if (arg_ct->ct & TCG_CT_NEWREG) { 230282790a87SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->u.regs, 230382790a87SRichard Henderson i_allocated_regs | o_allocated_regs, 230482790a87SRichard Henderson ts->indirect_base); 2305c896fe29Sbellard } else { 2306c896fe29Sbellard /* if fixed register, we try to use it */ 2307c896fe29Sbellard reg = ts->reg; 2308c896fe29Sbellard if (ts->fixed_reg && 2309c896fe29Sbellard tcg_regset_test_reg(arg_ct->u.regs, reg)) { 2310c896fe29Sbellard goto oarg_end; 2311c896fe29Sbellard } 231282790a87SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->u.regs, o_allocated_regs, 231391478cefSRichard Henderson ts->indirect_base); 2314c896fe29Sbellard } 231582790a87SRichard Henderson tcg_regset_set_reg(o_allocated_regs, reg); 2316c896fe29Sbellard /* if a fixed register is used, then a move will be done afterwards */ 2317c896fe29Sbellard if (!ts->fixed_reg) { 2318639368ddSAurelien Jarno if (ts->val_type == TEMP_VAL_REG) { 2319f8b2f202SRichard Henderson s->reg_to_temp[ts->reg] = NULL; 2320639368ddSAurelien Jarno } 2321c896fe29Sbellard ts->val_type = TEMP_VAL_REG; 2322c896fe29Sbellard ts->reg = reg; 2323c896fe29Sbellard /* temp value is modified, so the value kept in memory is 2324c896fe29Sbellard potentially not the same */ 2325c896fe29Sbellard ts->mem_coherent = 0; 2326f8b2f202SRichard Henderson s->reg_to_temp[reg] = ts; 2327c896fe29Sbellard } 2328c896fe29Sbellard oarg_end: 2329c896fe29Sbellard new_args[i] = reg; 2330c896fe29Sbellard } 2331e8996ee0Sbellard } 2332c896fe29Sbellard 2333c896fe29Sbellard /* emit instruction */ 2334c896fe29Sbellard tcg_out_op(s, opc, new_args, const_args); 2335c896fe29Sbellard 2336c896fe29Sbellard /* move the outputs in the correct register if needed */ 2337c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 2338c896fe29Sbellard ts = &s->temps[args[i]]; 2339c896fe29Sbellard reg = new_args[i]; 2340c896fe29Sbellard if (ts->fixed_reg && ts->reg != reg) { 23413b6dac34SRichard Henderson tcg_out_mov(s, ts->type, ts->reg, reg); 2342c896fe29Sbellard } 2343ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) { 234482790a87SRichard Henderson temp_sync(s, ts, o_allocated_regs, IS_DEAD_ARG(i)); 234559d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) { 2346f8bf00f1SRichard Henderson temp_dead(s, ts); 2347ec7a869dSAurelien Jarno } 2348c896fe29Sbellard } 2349c896fe29Sbellard } 2350c896fe29Sbellard 2351b03cce8eSbellard #ifdef TCG_TARGET_STACK_GROWSUP 2352b03cce8eSbellard #define STACK_DIR(x) (-(x)) 2353b03cce8eSbellard #else 2354b03cce8eSbellard #define STACK_DIR(x) (x) 2355b03cce8eSbellard #endif 2356b03cce8eSbellard 2357c45cb8bbSRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, int nb_oargs, int nb_iargs, 2358a1b3c48dSRichard Henderson const TCGArg * const args, TCGLifeData arg_life) 2359c896fe29Sbellard { 2360b6638662SRichard Henderson int flags, nb_regs, i; 2361b6638662SRichard Henderson TCGReg reg; 2362cf066674SRichard Henderson TCGArg arg; 2363c896fe29Sbellard TCGTemp *ts; 2364d3452f1fSRichard Henderson intptr_t stack_offset; 2365d3452f1fSRichard Henderson size_t call_stack_size; 2366cf066674SRichard Henderson tcg_insn_unit *func_addr; 2367cf066674SRichard Henderson int allocate_args; 2368c896fe29Sbellard TCGRegSet allocated_regs; 2369c896fe29Sbellard 2370cf066674SRichard Henderson func_addr = (tcg_insn_unit *)(intptr_t)args[nb_oargs + nb_iargs]; 2371cf066674SRichard Henderson flags = args[nb_oargs + nb_iargs + 1]; 2372c896fe29Sbellard 23736e17d0c5SStefan Weil nb_regs = ARRAY_SIZE(tcg_target_call_iarg_regs); 2374c45cb8bbSRichard Henderson if (nb_regs > nb_iargs) { 2375c45cb8bbSRichard Henderson nb_regs = nb_iargs; 2376cf066674SRichard Henderson } 2377c896fe29Sbellard 2378c896fe29Sbellard /* assign stack slots first */ 2379c45cb8bbSRichard Henderson call_stack_size = (nb_iargs - nb_regs) * sizeof(tcg_target_long); 2380c896fe29Sbellard call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) & 2381c896fe29Sbellard ~(TCG_TARGET_STACK_ALIGN - 1); 2382b03cce8eSbellard allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE); 2383b03cce8eSbellard if (allocate_args) { 2384345649c0SBlue Swirl /* XXX: if more than TCG_STATIC_CALL_ARGS_SIZE is needed, 2385345649c0SBlue Swirl preallocate call stack */ 2386345649c0SBlue Swirl tcg_abort(); 2387b03cce8eSbellard } 238839cf05d3Sbellard 238939cf05d3Sbellard stack_offset = TCG_TARGET_CALL_STACK_OFFSET; 2390c45cb8bbSRichard Henderson for(i = nb_regs; i < nb_iargs; i++) { 2391c896fe29Sbellard arg = args[nb_oargs + i]; 239239cf05d3Sbellard #ifdef TCG_TARGET_STACK_GROWSUP 239339cf05d3Sbellard stack_offset -= sizeof(tcg_target_long); 239439cf05d3Sbellard #endif 239539cf05d3Sbellard if (arg != TCG_CALL_DUMMY_ARG) { 2396c896fe29Sbellard ts = &s->temps[arg]; 239740ae5c62SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 239840ae5c62SRichard Henderson s->reserved_regs); 2399e4d5434cSblueswir1 tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset); 240039cf05d3Sbellard } 240139cf05d3Sbellard #ifndef TCG_TARGET_STACK_GROWSUP 240239cf05d3Sbellard stack_offset += sizeof(tcg_target_long); 240339cf05d3Sbellard #endif 2404c896fe29Sbellard } 2405c896fe29Sbellard 2406c896fe29Sbellard /* assign input registers */ 2407c896fe29Sbellard tcg_regset_set(allocated_regs, s->reserved_regs); 2408c896fe29Sbellard for(i = 0; i < nb_regs; i++) { 2409c896fe29Sbellard arg = args[nb_oargs + i]; 241039cf05d3Sbellard if (arg != TCG_CALL_DUMMY_ARG) { 2411c896fe29Sbellard ts = &s->temps[arg]; 2412c896fe29Sbellard reg = tcg_target_call_iarg_regs[i]; 2413b3915dbbSRichard Henderson tcg_reg_free(s, reg, allocated_regs); 241440ae5c62SRichard Henderson 2415c896fe29Sbellard if (ts->val_type == TEMP_VAL_REG) { 2416c896fe29Sbellard if (ts->reg != reg) { 24173b6dac34SRichard Henderson tcg_out_mov(s, ts->type, reg, ts->reg); 2418c896fe29Sbellard } 2419c896fe29Sbellard } else { 242040ae5c62SRichard Henderson TCGRegSet arg_set; 242140ae5c62SRichard Henderson 242240ae5c62SRichard Henderson tcg_regset_clear(arg_set); 242340ae5c62SRichard Henderson tcg_regset_set_reg(arg_set, reg); 242440ae5c62SRichard Henderson temp_load(s, ts, arg_set, allocated_regs); 2425c896fe29Sbellard } 242640ae5c62SRichard Henderson 2427c896fe29Sbellard tcg_regset_set_reg(allocated_regs, reg); 2428c896fe29Sbellard } 242939cf05d3Sbellard } 2430c896fe29Sbellard 2431c896fe29Sbellard /* mark dead temporaries and free the associated registers */ 2432866cb6cbSAurelien Jarno for(i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 2433866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) { 2434f8bf00f1SRichard Henderson temp_dead(s, &s->temps[args[i]]); 2435c896fe29Sbellard } 2436c896fe29Sbellard } 2437c896fe29Sbellard 2438c896fe29Sbellard /* clobber call registers */ 2439c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) { 2440c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { 2441b3915dbbSRichard Henderson tcg_reg_free(s, i, allocated_regs); 2442c896fe29Sbellard } 2443c896fe29Sbellard } 2444c896fe29Sbellard 244578505279SAurelien Jarno /* Save globals if they might be written by the helper, sync them if 244678505279SAurelien Jarno they might be read. */ 244778505279SAurelien Jarno if (flags & TCG_CALL_NO_READ_GLOBALS) { 244878505279SAurelien Jarno /* Nothing to do */ 244978505279SAurelien Jarno } else if (flags & TCG_CALL_NO_WRITE_GLOBALS) { 245078505279SAurelien Jarno sync_globals(s, allocated_regs); 245178505279SAurelien Jarno } else { 2452e8996ee0Sbellard save_globals(s, allocated_regs); 2453b9c18f56Saurel32 } 2454c896fe29Sbellard 2455cf066674SRichard Henderson tcg_out_call(s, func_addr); 2456c896fe29Sbellard 2457c896fe29Sbellard /* assign output registers and emit moves if needed */ 2458c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 2459c896fe29Sbellard arg = args[i]; 2460c896fe29Sbellard ts = &s->temps[arg]; 2461c896fe29Sbellard reg = tcg_target_call_oarg_regs[i]; 2462eabb7b91SAurelien Jarno tcg_debug_assert(s->reg_to_temp[reg] == NULL); 246334b1a49cSRichard Henderson 2464c896fe29Sbellard if (ts->fixed_reg) { 2465c896fe29Sbellard if (ts->reg != reg) { 24663b6dac34SRichard Henderson tcg_out_mov(s, ts->type, ts->reg, reg); 2467c896fe29Sbellard } 2468c896fe29Sbellard } else { 2469639368ddSAurelien Jarno if (ts->val_type == TEMP_VAL_REG) { 2470f8b2f202SRichard Henderson s->reg_to_temp[ts->reg] = NULL; 2471639368ddSAurelien Jarno } 2472c896fe29Sbellard ts->val_type = TEMP_VAL_REG; 2473c896fe29Sbellard ts->reg = reg; 2474c896fe29Sbellard ts->mem_coherent = 0; 2475f8b2f202SRichard Henderson s->reg_to_temp[reg] = ts; 2476ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) { 247759d7c14eSRichard Henderson temp_sync(s, ts, allocated_regs, IS_DEAD_ARG(i)); 247859d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) { 2479f8bf00f1SRichard Henderson temp_dead(s, ts); 2480c896fe29Sbellard } 2481c896fe29Sbellard } 24828c11ad25SAurelien Jarno } 2483c896fe29Sbellard } 2484c896fe29Sbellard 2485c896fe29Sbellard #ifdef CONFIG_PROFILER 2486c896fe29Sbellard 248754604f74Saurel32 static int64_t tcg_table_op_count[NB_OPS]; 2488c896fe29Sbellard 2489246ae24dSMax Filippov void tcg_dump_op_count(FILE *f, fprintf_function cpu_fprintf) 2490c896fe29Sbellard { 2491c896fe29Sbellard int i; 2492d70724ceSzhanghailiang 249315fc7daaSRichard Henderson for (i = 0; i < NB_OPS; i++) { 2494246ae24dSMax Filippov cpu_fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name, 2495246ae24dSMax Filippov tcg_table_op_count[i]); 2496c896fe29Sbellard } 2497c896fe29Sbellard } 2498246ae24dSMax Filippov #else 2499246ae24dSMax Filippov void tcg_dump_op_count(FILE *f, fprintf_function cpu_fprintf) 2500246ae24dSMax Filippov { 2501246ae24dSMax Filippov cpu_fprintf(f, "[TCG profiler not compiled]\n"); 2502246ae24dSMax Filippov } 2503c896fe29Sbellard #endif 2504c896fe29Sbellard 2505c896fe29Sbellard 25065bd2ec3dSAlex Bennée int tcg_gen_code(TCGContext *s, TranslationBlock *tb) 2507c896fe29Sbellard { 2508fca8a500SRichard Henderson int i, oi, oi_next, num_insns; 2509c896fe29Sbellard 251004fe6400SRichard Henderson #ifdef CONFIG_PROFILER 251104fe6400SRichard Henderson { 251204fe6400SRichard Henderson int n; 251304fe6400SRichard Henderson 2514dcb8e758SRichard Henderson n = s->gen_op_buf[0].prev + 1; 251504fe6400SRichard Henderson s->op_count += n; 251604fe6400SRichard Henderson if (n > s->op_count_max) { 251704fe6400SRichard Henderson s->op_count_max = n; 251804fe6400SRichard Henderson } 251904fe6400SRichard Henderson 252004fe6400SRichard Henderson n = s->nb_temps; 252104fe6400SRichard Henderson s->temp_count += n; 252204fe6400SRichard Henderson if (n > s->temp_count_max) { 252304fe6400SRichard Henderson s->temp_count_max = n; 252404fe6400SRichard Henderson } 252504fe6400SRichard Henderson } 252604fe6400SRichard Henderson #endif 252704fe6400SRichard Henderson 2528c896fe29Sbellard #ifdef DEBUG_DISAS 2529d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP) 2530d977e1c2SAlex Bennée && qemu_log_in_addr_range(tb->pc))) { 25311ee73216SRichard Henderson qemu_log_lock(); 253293fcfe39Saliguori qemu_log("OP:\n"); 2533eeacee4dSBlue Swirl tcg_dump_ops(s); 253493fcfe39Saliguori qemu_log("\n"); 25351ee73216SRichard Henderson qemu_log_unlock(); 2536c896fe29Sbellard } 2537c896fe29Sbellard #endif 2538c896fe29Sbellard 2539c5cc28ffSAurelien Jarno #ifdef CONFIG_PROFILER 2540c5cc28ffSAurelien Jarno s->opt_time -= profile_getclock(); 2541c5cc28ffSAurelien Jarno #endif 2542c5cc28ffSAurelien Jarno 25438f2e8c07SKirill Batuzov #ifdef USE_TCG_OPTIMIZATIONS 2544c45cb8bbSRichard Henderson tcg_optimize(s); 25458f2e8c07SKirill Batuzov #endif 25468f2e8c07SKirill Batuzov 2547a23a9ec6Sbellard #ifdef CONFIG_PROFILER 2548c5cc28ffSAurelien Jarno s->opt_time += profile_getclock(); 2549a23a9ec6Sbellard s->la_time -= profile_getclock(); 2550a23a9ec6Sbellard #endif 2551c5cc28ffSAurelien Jarno 25525a18407fSRichard Henderson { 25535a18407fSRichard Henderson uint8_t *temp_state = tcg_malloc(s->nb_temps + s->nb_indirects); 25545a18407fSRichard Henderson 25555a18407fSRichard Henderson liveness_pass_1(s, temp_state); 25565a18407fSRichard Henderson 25575a18407fSRichard Henderson if (s->nb_indirects > 0) { 25585a18407fSRichard Henderson #ifdef DEBUG_DISAS 25595a18407fSRichard Henderson if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND) 25605a18407fSRichard Henderson && qemu_log_in_addr_range(tb->pc))) { 25611ee73216SRichard Henderson qemu_log_lock(); 25625a18407fSRichard Henderson qemu_log("OP before indirect lowering:\n"); 25635a18407fSRichard Henderson tcg_dump_ops(s); 25645a18407fSRichard Henderson qemu_log("\n"); 25651ee73216SRichard Henderson qemu_log_unlock(); 25665a18407fSRichard Henderson } 25675a18407fSRichard Henderson #endif 25685a18407fSRichard Henderson /* Replace indirect temps with direct temps. */ 25695a18407fSRichard Henderson if (liveness_pass_2(s, temp_state)) { 25705a18407fSRichard Henderson /* If changes were made, re-run liveness. */ 25715a18407fSRichard Henderson liveness_pass_1(s, temp_state); 25725a18407fSRichard Henderson } 25735a18407fSRichard Henderson } 25745a18407fSRichard Henderson } 2575c5cc28ffSAurelien Jarno 2576a23a9ec6Sbellard #ifdef CONFIG_PROFILER 2577a23a9ec6Sbellard s->la_time += profile_getclock(); 2578a23a9ec6Sbellard #endif 2579c896fe29Sbellard 2580c896fe29Sbellard #ifdef DEBUG_DISAS 2581d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT) 2582d977e1c2SAlex Bennée && qemu_log_in_addr_range(tb->pc))) { 25831ee73216SRichard Henderson qemu_log_lock(); 2584c5cc28ffSAurelien Jarno qemu_log("OP after optimization and liveness analysis:\n"); 2585eeacee4dSBlue Swirl tcg_dump_ops(s); 258693fcfe39Saliguori qemu_log("\n"); 25871ee73216SRichard Henderson qemu_log_unlock(); 2588c896fe29Sbellard } 2589c896fe29Sbellard #endif 2590c896fe29Sbellard 2591c896fe29Sbellard tcg_reg_alloc_start(s); 2592c896fe29Sbellard 25935bd2ec3dSAlex Bennée s->code_buf = tb->tc_ptr; 25945bd2ec3dSAlex Bennée s->code_ptr = tb->tc_ptr; 2595c896fe29Sbellard 25969ecefc84SRichard Henderson tcg_out_tb_init(s); 25979ecefc84SRichard Henderson 2598fca8a500SRichard Henderson num_insns = -1; 2599dcb8e758SRichard Henderson for (oi = s->gen_op_buf[0].next; oi != 0; oi = oi_next) { 2600c45cb8bbSRichard Henderson TCGOp * const op = &s->gen_op_buf[oi]; 2601c45cb8bbSRichard Henderson TCGArg * const args = &s->gen_opparam_buf[op->args]; 2602c45cb8bbSRichard Henderson TCGOpcode opc = op->opc; 2603c45cb8bbSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 2604bee158cbSRichard Henderson TCGLifeData arg_life = op->life; 2605b3db8758Sblueswir1 2606c45cb8bbSRichard Henderson oi_next = op->next; 2607c896fe29Sbellard #ifdef CONFIG_PROFILER 260854604f74Saurel32 tcg_table_op_count[opc]++; 2609c896fe29Sbellard #endif 2610c45cb8bbSRichard Henderson 2611c896fe29Sbellard switch (opc) { 2612c896fe29Sbellard case INDEX_op_mov_i32: 2613c896fe29Sbellard case INDEX_op_mov_i64: 2614a1b3c48dSRichard Henderson tcg_reg_alloc_mov(s, def, args, arg_life); 2615c896fe29Sbellard break; 2616e8996ee0Sbellard case INDEX_op_movi_i32: 2617e8996ee0Sbellard case INDEX_op_movi_i64: 2618a1b3c48dSRichard Henderson tcg_reg_alloc_movi(s, args, arg_life); 2619e8996ee0Sbellard break; 2620765b842aSRichard Henderson case INDEX_op_insn_start: 2621fca8a500SRichard Henderson if (num_insns >= 0) { 2622fca8a500SRichard Henderson s->gen_insn_end_off[num_insns] = tcg_current_code_size(s); 2623fca8a500SRichard Henderson } 2624fca8a500SRichard Henderson num_insns++; 2625bad729e2SRichard Henderson for (i = 0; i < TARGET_INSN_START_WORDS; ++i) { 2626bad729e2SRichard Henderson target_ulong a; 2627bad729e2SRichard Henderson #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS 2628bad729e2SRichard Henderson a = ((target_ulong)args[i * 2 + 1] << 32) | args[i * 2]; 2629bad729e2SRichard Henderson #else 2630bad729e2SRichard Henderson a = args[i]; 2631bad729e2SRichard Henderson #endif 2632fca8a500SRichard Henderson s->gen_insn_data[num_insns][i] = a; 2633bad729e2SRichard Henderson } 2634c896fe29Sbellard break; 26355ff9d6a4Sbellard case INDEX_op_discard: 2636f8bf00f1SRichard Henderson temp_dead(s, &s->temps[args[0]]); 26375ff9d6a4Sbellard break; 2638c896fe29Sbellard case INDEX_op_set_label: 2639e8996ee0Sbellard tcg_reg_alloc_bb_end(s, s->reserved_regs); 2640bec16311SRichard Henderson tcg_out_label(s, arg_label(args[0]), s->code_ptr); 2641c896fe29Sbellard break; 2642c896fe29Sbellard case INDEX_op_call: 2643a1b3c48dSRichard Henderson tcg_reg_alloc_call(s, op->callo, op->calli, args, arg_life); 2644c45cb8bbSRichard Henderson break; 2645c896fe29Sbellard default: 264625c4d9ccSRichard Henderson /* Sanity check that we've not introduced any unhandled opcodes. */ 264725c4d9ccSRichard Henderson if (def->flags & TCG_OPF_NOT_PRESENT) { 264825c4d9ccSRichard Henderson tcg_abort(); 264925c4d9ccSRichard Henderson } 2650c896fe29Sbellard /* Note: in order to speed up the code, it would be much 2651c896fe29Sbellard faster to have specialized register allocator functions for 2652c896fe29Sbellard some common argument patterns */ 2653a1b3c48dSRichard Henderson tcg_reg_alloc_op(s, def, opc, args, arg_life); 2654c896fe29Sbellard break; 2655c896fe29Sbellard } 26568d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG 2657c896fe29Sbellard check_regs(s); 2658c896fe29Sbellard #endif 2659b125f9dcSRichard Henderson /* Test for (pending) buffer overflow. The assumption is that any 2660b125f9dcSRichard Henderson one operation beginning below the high water mark cannot overrun 2661b125f9dcSRichard Henderson the buffer completely. Thus we can test for overflow after 2662b125f9dcSRichard Henderson generating code without having to check during generation. */ 2663644da9b3SJohn Clarke if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) { 2664b125f9dcSRichard Henderson return -1; 2665b125f9dcSRichard Henderson } 2666c896fe29Sbellard } 2667fca8a500SRichard Henderson tcg_debug_assert(num_insns >= 0); 2668fca8a500SRichard Henderson s->gen_insn_end_off[num_insns] = tcg_current_code_size(s); 2669c45cb8bbSRichard Henderson 2670b76f0d8cSYeongkyoon Lee /* Generate TB finalization at the end of block */ 267123dceda6SRichard Henderson if (!tcg_out_tb_finalize(s)) { 267223dceda6SRichard Henderson return -1; 267323dceda6SRichard Henderson } 2674c896fe29Sbellard 2675c896fe29Sbellard /* flush instruction cache */ 26761813e175SRichard Henderson flush_icache_range((uintptr_t)s->code_buf, (uintptr_t)s->code_ptr); 26772aeabc08SStefan Weil 26781813e175SRichard Henderson return tcg_current_code_size(s); 2679c896fe29Sbellard } 2680c896fe29Sbellard 2681a23a9ec6Sbellard #ifdef CONFIG_PROFILER 2682405cf9ffSStefan Weil void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf) 2683a23a9ec6Sbellard { 2684a23a9ec6Sbellard TCGContext *s = &tcg_ctx; 2685fca8a500SRichard Henderson int64_t tb_count = s->tb_count; 2686fca8a500SRichard Henderson int64_t tb_div_count = tb_count ? tb_count : 1; 2687fca8a500SRichard Henderson int64_t tot = s->interm_time + s->code_time; 2688a23a9ec6Sbellard 2689a23a9ec6Sbellard cpu_fprintf(f, "JIT cycles %" PRId64 " (%0.3f s at 2.4 GHz)\n", 2690a23a9ec6Sbellard tot, tot / 2.4e9); 2691a23a9ec6Sbellard cpu_fprintf(f, "translated TBs %" PRId64 " (aborted=%" PRId64 " %0.1f%%)\n", 2692fca8a500SRichard Henderson tb_count, s->tb_count1 - tb_count, 2693fca8a500SRichard Henderson (double)(s->tb_count1 - s->tb_count) 2694fca8a500SRichard Henderson / (s->tb_count1 ? s->tb_count1 : 1) * 100.0); 2695a23a9ec6Sbellard cpu_fprintf(f, "avg ops/TB %0.1f max=%d\n", 2696fca8a500SRichard Henderson (double)s->op_count / tb_div_count, s->op_count_max); 2697a23a9ec6Sbellard cpu_fprintf(f, "deleted ops/TB %0.2f\n", 2698fca8a500SRichard Henderson (double)s->del_op_count / tb_div_count); 2699a23a9ec6Sbellard cpu_fprintf(f, "avg temps/TB %0.2f max=%d\n", 2700fca8a500SRichard Henderson (double)s->temp_count / tb_div_count, s->temp_count_max); 2701fca8a500SRichard Henderson cpu_fprintf(f, "avg host code/TB %0.1f\n", 2702fca8a500SRichard Henderson (double)s->code_out_len / tb_div_count); 2703fca8a500SRichard Henderson cpu_fprintf(f, "avg search data/TB %0.1f\n", 2704fca8a500SRichard Henderson (double)s->search_out_len / tb_div_count); 2705a23a9ec6Sbellard 2706a23a9ec6Sbellard cpu_fprintf(f, "cycles/op %0.1f\n", 2707a23a9ec6Sbellard s->op_count ? (double)tot / s->op_count : 0); 2708a23a9ec6Sbellard cpu_fprintf(f, "cycles/in byte %0.1f\n", 2709a23a9ec6Sbellard s->code_in_len ? (double)tot / s->code_in_len : 0); 2710a23a9ec6Sbellard cpu_fprintf(f, "cycles/out byte %0.1f\n", 2711a23a9ec6Sbellard s->code_out_len ? (double)tot / s->code_out_len : 0); 2712fca8a500SRichard Henderson cpu_fprintf(f, "cycles/search byte %0.1f\n", 2713fca8a500SRichard Henderson s->search_out_len ? (double)tot / s->search_out_len : 0); 2714fca8a500SRichard Henderson if (tot == 0) { 2715a23a9ec6Sbellard tot = 1; 2716fca8a500SRichard Henderson } 2717a23a9ec6Sbellard cpu_fprintf(f, " gen_interm time %0.1f%%\n", 2718a23a9ec6Sbellard (double)s->interm_time / tot * 100.0); 2719a23a9ec6Sbellard cpu_fprintf(f, " gen_code time %0.1f%%\n", 2720a23a9ec6Sbellard (double)s->code_time / tot * 100.0); 2721c5cc28ffSAurelien Jarno cpu_fprintf(f, "optim./code time %0.1f%%\n", 2722c5cc28ffSAurelien Jarno (double)s->opt_time / (s->code_time ? s->code_time : 1) 2723c5cc28ffSAurelien Jarno * 100.0); 2724a23a9ec6Sbellard cpu_fprintf(f, "liveness/code time %0.1f%%\n", 2725a23a9ec6Sbellard (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0); 2726a23a9ec6Sbellard cpu_fprintf(f, "cpu_restore count %" PRId64 "\n", 2727a23a9ec6Sbellard s->restore_count); 2728a23a9ec6Sbellard cpu_fprintf(f, " avg cycles %0.1f\n", 2729a23a9ec6Sbellard s->restore_count ? (double)s->restore_time / s->restore_count : 0); 2730a23a9ec6Sbellard } 2731a23a9ec6Sbellard #else 2732405cf9ffSStefan Weil void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf) 2733a23a9ec6Sbellard { 273424bf7b3aSbellard cpu_fprintf(f, "[TCG profiler not compiled]\n"); 2735a23a9ec6Sbellard } 2736a23a9ec6Sbellard #endif 2737813da627SRichard Henderson 2738813da627SRichard Henderson #ifdef ELF_HOST_MACHINE 27395872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things: 27405872bbf2SRichard Henderson 27415872bbf2SRichard Henderson (1) Define ELF_HOST_MACHINE to indicate both what value to 27425872bbf2SRichard Henderson put into the ELF image and to indicate support for the feature. 27435872bbf2SRichard Henderson 27445872bbf2SRichard Henderson (2) Define tcg_register_jit. This should create a buffer containing 27455872bbf2SRichard Henderson the contents of a .debug_frame section that describes the post- 27465872bbf2SRichard Henderson prologue unwind info for the tcg machine. 27475872bbf2SRichard Henderson 27485872bbf2SRichard Henderson (3) Call tcg_register_jit_int, with the constructed .debug_frame. 27495872bbf2SRichard Henderson */ 2750813da627SRichard Henderson 2751813da627SRichard Henderson /* Begin GDB interface. THE FOLLOWING MUST MATCH GDB DOCS. */ 2752813da627SRichard Henderson typedef enum { 2753813da627SRichard Henderson JIT_NOACTION = 0, 2754813da627SRichard Henderson JIT_REGISTER_FN, 2755813da627SRichard Henderson JIT_UNREGISTER_FN 2756813da627SRichard Henderson } jit_actions_t; 2757813da627SRichard Henderson 2758813da627SRichard Henderson struct jit_code_entry { 2759813da627SRichard Henderson struct jit_code_entry *next_entry; 2760813da627SRichard Henderson struct jit_code_entry *prev_entry; 2761813da627SRichard Henderson const void *symfile_addr; 2762813da627SRichard Henderson uint64_t symfile_size; 2763813da627SRichard Henderson }; 2764813da627SRichard Henderson 2765813da627SRichard Henderson struct jit_descriptor { 2766813da627SRichard Henderson uint32_t version; 2767813da627SRichard Henderson uint32_t action_flag; 2768813da627SRichard Henderson struct jit_code_entry *relevant_entry; 2769813da627SRichard Henderson struct jit_code_entry *first_entry; 2770813da627SRichard Henderson }; 2771813da627SRichard Henderson 2772813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline)); 2773813da627SRichard Henderson void __jit_debug_register_code(void) 2774813da627SRichard Henderson { 2775813da627SRichard Henderson asm(""); 2776813da627SRichard Henderson } 2777813da627SRichard Henderson 2778813da627SRichard Henderson /* Must statically initialize the version, because GDB may check 2779813da627SRichard Henderson the version before we can set it. */ 2780813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 }; 2781813da627SRichard Henderson 2782813da627SRichard Henderson /* End GDB interface. */ 2783813da627SRichard Henderson 2784813da627SRichard Henderson static int find_string(const char *strtab, const char *str) 2785813da627SRichard Henderson { 2786813da627SRichard Henderson const char *p = strtab + 1; 2787813da627SRichard Henderson 2788813da627SRichard Henderson while (1) { 2789813da627SRichard Henderson if (strcmp(p, str) == 0) { 2790813da627SRichard Henderson return p - strtab; 2791813da627SRichard Henderson } 2792813da627SRichard Henderson p += strlen(p) + 1; 2793813da627SRichard Henderson } 2794813da627SRichard Henderson } 2795813da627SRichard Henderson 27965872bbf2SRichard Henderson static void tcg_register_jit_int(void *buf_ptr, size_t buf_size, 27972c90784aSRichard Henderson const void *debug_frame, 27982c90784aSRichard Henderson size_t debug_frame_size) 2799813da627SRichard Henderson { 28005872bbf2SRichard Henderson struct __attribute__((packed)) DebugInfo { 28015872bbf2SRichard Henderson uint32_t len; 28025872bbf2SRichard Henderson uint16_t version; 28035872bbf2SRichard Henderson uint32_t abbrev; 28045872bbf2SRichard Henderson uint8_t ptr_size; 28055872bbf2SRichard Henderson uint8_t cu_die; 28065872bbf2SRichard Henderson uint16_t cu_lang; 28075872bbf2SRichard Henderson uintptr_t cu_low_pc; 28085872bbf2SRichard Henderson uintptr_t cu_high_pc; 28095872bbf2SRichard Henderson uint8_t fn_die; 28105872bbf2SRichard Henderson char fn_name[16]; 28115872bbf2SRichard Henderson uintptr_t fn_low_pc; 28125872bbf2SRichard Henderson uintptr_t fn_high_pc; 28135872bbf2SRichard Henderson uint8_t cu_eoc; 28145872bbf2SRichard Henderson }; 2815813da627SRichard Henderson 2816813da627SRichard Henderson struct ElfImage { 2817813da627SRichard Henderson ElfW(Ehdr) ehdr; 2818813da627SRichard Henderson ElfW(Phdr) phdr; 28195872bbf2SRichard Henderson ElfW(Shdr) shdr[7]; 28205872bbf2SRichard Henderson ElfW(Sym) sym[2]; 28215872bbf2SRichard Henderson struct DebugInfo di; 28225872bbf2SRichard Henderson uint8_t da[24]; 28235872bbf2SRichard Henderson char str[80]; 28245872bbf2SRichard Henderson }; 28255872bbf2SRichard Henderson 28265872bbf2SRichard Henderson struct ElfImage *img; 28275872bbf2SRichard Henderson 28285872bbf2SRichard Henderson static const struct ElfImage img_template = { 28295872bbf2SRichard Henderson .ehdr = { 28305872bbf2SRichard Henderson .e_ident[EI_MAG0] = ELFMAG0, 28315872bbf2SRichard Henderson .e_ident[EI_MAG1] = ELFMAG1, 28325872bbf2SRichard Henderson .e_ident[EI_MAG2] = ELFMAG2, 28335872bbf2SRichard Henderson .e_ident[EI_MAG3] = ELFMAG3, 28345872bbf2SRichard Henderson .e_ident[EI_CLASS] = ELF_CLASS, 28355872bbf2SRichard Henderson .e_ident[EI_DATA] = ELF_DATA, 28365872bbf2SRichard Henderson .e_ident[EI_VERSION] = EV_CURRENT, 28375872bbf2SRichard Henderson .e_type = ET_EXEC, 28385872bbf2SRichard Henderson .e_machine = ELF_HOST_MACHINE, 28395872bbf2SRichard Henderson .e_version = EV_CURRENT, 28405872bbf2SRichard Henderson .e_phoff = offsetof(struct ElfImage, phdr), 28415872bbf2SRichard Henderson .e_shoff = offsetof(struct ElfImage, shdr), 28425872bbf2SRichard Henderson .e_ehsize = sizeof(ElfW(Shdr)), 28435872bbf2SRichard Henderson .e_phentsize = sizeof(ElfW(Phdr)), 28445872bbf2SRichard Henderson .e_phnum = 1, 28455872bbf2SRichard Henderson .e_shentsize = sizeof(ElfW(Shdr)), 28465872bbf2SRichard Henderson .e_shnum = ARRAY_SIZE(img->shdr), 28475872bbf2SRichard Henderson .e_shstrndx = ARRAY_SIZE(img->shdr) - 1, 2848abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS 2849abbb3eaeSRichard Henderson .e_flags = ELF_HOST_FLAGS, 2850abbb3eaeSRichard Henderson #endif 2851abbb3eaeSRichard Henderson #ifdef ELF_OSABI 2852abbb3eaeSRichard Henderson .e_ident[EI_OSABI] = ELF_OSABI, 2853abbb3eaeSRichard Henderson #endif 28545872bbf2SRichard Henderson }, 28555872bbf2SRichard Henderson .phdr = { 28565872bbf2SRichard Henderson .p_type = PT_LOAD, 28575872bbf2SRichard Henderson .p_flags = PF_X, 28585872bbf2SRichard Henderson }, 28595872bbf2SRichard Henderson .shdr = { 28605872bbf2SRichard Henderson [0] = { .sh_type = SHT_NULL }, 28615872bbf2SRichard Henderson /* Trick: The contents of code_gen_buffer are not present in 28625872bbf2SRichard Henderson this fake ELF file; that got allocated elsewhere. Therefore 28635872bbf2SRichard Henderson we mark .text as SHT_NOBITS (similar to .bss) so that readers 28645872bbf2SRichard Henderson will not look for contents. We can record any address. */ 28655872bbf2SRichard Henderson [1] = { /* .text */ 28665872bbf2SRichard Henderson .sh_type = SHT_NOBITS, 28675872bbf2SRichard Henderson .sh_flags = SHF_EXECINSTR | SHF_ALLOC, 28685872bbf2SRichard Henderson }, 28695872bbf2SRichard Henderson [2] = { /* .debug_info */ 28705872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 28715872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, di), 28725872bbf2SRichard Henderson .sh_size = sizeof(struct DebugInfo), 28735872bbf2SRichard Henderson }, 28745872bbf2SRichard Henderson [3] = { /* .debug_abbrev */ 28755872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 28765872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, da), 28775872bbf2SRichard Henderson .sh_size = sizeof(img->da), 28785872bbf2SRichard Henderson }, 28795872bbf2SRichard Henderson [4] = { /* .debug_frame */ 28805872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 28815872bbf2SRichard Henderson .sh_offset = sizeof(struct ElfImage), 28825872bbf2SRichard Henderson }, 28835872bbf2SRichard Henderson [5] = { /* .symtab */ 28845872bbf2SRichard Henderson .sh_type = SHT_SYMTAB, 28855872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, sym), 28865872bbf2SRichard Henderson .sh_size = sizeof(img->sym), 28875872bbf2SRichard Henderson .sh_info = 1, 28885872bbf2SRichard Henderson .sh_link = ARRAY_SIZE(img->shdr) - 1, 28895872bbf2SRichard Henderson .sh_entsize = sizeof(ElfW(Sym)), 28905872bbf2SRichard Henderson }, 28915872bbf2SRichard Henderson [6] = { /* .strtab */ 28925872bbf2SRichard Henderson .sh_type = SHT_STRTAB, 28935872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, str), 28945872bbf2SRichard Henderson .sh_size = sizeof(img->str), 28955872bbf2SRichard Henderson } 28965872bbf2SRichard Henderson }, 28975872bbf2SRichard Henderson .sym = { 28985872bbf2SRichard Henderson [1] = { /* code_gen_buffer */ 28995872bbf2SRichard Henderson .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC), 29005872bbf2SRichard Henderson .st_shndx = 1, 29015872bbf2SRichard Henderson } 29025872bbf2SRichard Henderson }, 29035872bbf2SRichard Henderson .di = { 29045872bbf2SRichard Henderson .len = sizeof(struct DebugInfo) - 4, 29055872bbf2SRichard Henderson .version = 2, 29065872bbf2SRichard Henderson .ptr_size = sizeof(void *), 29075872bbf2SRichard Henderson .cu_die = 1, 29085872bbf2SRichard Henderson .cu_lang = 0x8001, /* DW_LANG_Mips_Assembler */ 29095872bbf2SRichard Henderson .fn_die = 2, 29105872bbf2SRichard Henderson .fn_name = "code_gen_buffer" 29115872bbf2SRichard Henderson }, 29125872bbf2SRichard Henderson .da = { 29135872bbf2SRichard Henderson 1, /* abbrev number (the cu) */ 29145872bbf2SRichard Henderson 0x11, 1, /* DW_TAG_compile_unit, has children */ 29155872bbf2SRichard Henderson 0x13, 0x5, /* DW_AT_language, DW_FORM_data2 */ 29165872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */ 29175872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */ 29185872bbf2SRichard Henderson 0, 0, /* end of abbrev */ 29195872bbf2SRichard Henderson 2, /* abbrev number (the fn) */ 29205872bbf2SRichard Henderson 0x2e, 0, /* DW_TAG_subprogram, no children */ 29215872bbf2SRichard Henderson 0x3, 0x8, /* DW_AT_name, DW_FORM_string */ 29225872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */ 29235872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */ 29245872bbf2SRichard Henderson 0, 0, /* end of abbrev */ 29255872bbf2SRichard Henderson 0 /* no more abbrev */ 29265872bbf2SRichard Henderson }, 29275872bbf2SRichard Henderson .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0" 29285872bbf2SRichard Henderson ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer", 2929813da627SRichard Henderson }; 2930813da627SRichard Henderson 2931813da627SRichard Henderson /* We only need a single jit entry; statically allocate it. */ 2932813da627SRichard Henderson static struct jit_code_entry one_entry; 2933813da627SRichard Henderson 29345872bbf2SRichard Henderson uintptr_t buf = (uintptr_t)buf_ptr; 2935813da627SRichard Henderson size_t img_size = sizeof(struct ElfImage) + debug_frame_size; 29362c90784aSRichard Henderson DebugFrameHeader *dfh; 2937813da627SRichard Henderson 29385872bbf2SRichard Henderson img = g_malloc(img_size); 29395872bbf2SRichard Henderson *img = img_template; 2940813da627SRichard Henderson 29415872bbf2SRichard Henderson img->phdr.p_vaddr = buf; 29425872bbf2SRichard Henderson img->phdr.p_paddr = buf; 29435872bbf2SRichard Henderson img->phdr.p_memsz = buf_size; 2944813da627SRichard Henderson 29455872bbf2SRichard Henderson img->shdr[1].sh_name = find_string(img->str, ".text"); 29465872bbf2SRichard Henderson img->shdr[1].sh_addr = buf; 29475872bbf2SRichard Henderson img->shdr[1].sh_size = buf_size; 2948813da627SRichard Henderson 29495872bbf2SRichard Henderson img->shdr[2].sh_name = find_string(img->str, ".debug_info"); 29505872bbf2SRichard Henderson img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev"); 29515872bbf2SRichard Henderson 29525872bbf2SRichard Henderson img->shdr[4].sh_name = find_string(img->str, ".debug_frame"); 29535872bbf2SRichard Henderson img->shdr[4].sh_size = debug_frame_size; 29545872bbf2SRichard Henderson 29555872bbf2SRichard Henderson img->shdr[5].sh_name = find_string(img->str, ".symtab"); 29565872bbf2SRichard Henderson img->shdr[6].sh_name = find_string(img->str, ".strtab"); 29575872bbf2SRichard Henderson 29585872bbf2SRichard Henderson img->sym[1].st_name = find_string(img->str, "code_gen_buffer"); 29595872bbf2SRichard Henderson img->sym[1].st_value = buf; 29605872bbf2SRichard Henderson img->sym[1].st_size = buf_size; 29615872bbf2SRichard Henderson 29625872bbf2SRichard Henderson img->di.cu_low_pc = buf; 296345aba097SRichard Henderson img->di.cu_high_pc = buf + buf_size; 29645872bbf2SRichard Henderson img->di.fn_low_pc = buf; 296545aba097SRichard Henderson img->di.fn_high_pc = buf + buf_size; 2966813da627SRichard Henderson 29672c90784aSRichard Henderson dfh = (DebugFrameHeader *)(img + 1); 29682c90784aSRichard Henderson memcpy(dfh, debug_frame, debug_frame_size); 29692c90784aSRichard Henderson dfh->fde.func_start = buf; 29702c90784aSRichard Henderson dfh->fde.func_len = buf_size; 29712c90784aSRichard Henderson 2972813da627SRichard Henderson #ifdef DEBUG_JIT 2973813da627SRichard Henderson /* Enable this block to be able to debug the ELF image file creation. 2974813da627SRichard Henderson One can use readelf, objdump, or other inspection utilities. */ 2975813da627SRichard Henderson { 2976813da627SRichard Henderson FILE *f = fopen("/tmp/qemu.jit", "w+b"); 2977813da627SRichard Henderson if (f) { 29785872bbf2SRichard Henderson if (fwrite(img, img_size, 1, f) != img_size) { 2979813da627SRichard Henderson /* Avoid stupid unused return value warning for fwrite. */ 2980813da627SRichard Henderson } 2981813da627SRichard Henderson fclose(f); 2982813da627SRichard Henderson } 2983813da627SRichard Henderson } 2984813da627SRichard Henderson #endif 2985813da627SRichard Henderson 2986813da627SRichard Henderson one_entry.symfile_addr = img; 2987813da627SRichard Henderson one_entry.symfile_size = img_size; 2988813da627SRichard Henderson 2989813da627SRichard Henderson __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; 2990813da627SRichard Henderson __jit_debug_descriptor.relevant_entry = &one_entry; 2991813da627SRichard Henderson __jit_debug_descriptor.first_entry = &one_entry; 2992813da627SRichard Henderson __jit_debug_register_code(); 2993813da627SRichard Henderson } 2994813da627SRichard Henderson #else 29955872bbf2SRichard Henderson /* No support for the feature. Provide the entry point expected by exec.c, 29965872bbf2SRichard Henderson and implement the internal function we declared earlier. */ 2997813da627SRichard Henderson 2998813da627SRichard Henderson static void tcg_register_jit_int(void *buf, size_t size, 29992c90784aSRichard Henderson const void *debug_frame, 30002c90784aSRichard Henderson size_t debug_frame_size) 3001813da627SRichard Henderson { 3002813da627SRichard Henderson } 3003813da627SRichard Henderson 3004813da627SRichard Henderson void tcg_register_jit(void *buf, size_t buf_size) 3005813da627SRichard Henderson { 3006813da627SRichard Henderson } 3007813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */ 3008