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); 65*f69d277eSRichard 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. */ 99c0ad3001SStefan Weil static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str); 1002a534affSRichard Henderson static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1, 101a05b5b9bSRichard Henderson intptr_t arg2); 1022a534affSRichard Henderson static void tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg); 103c0ad3001SStefan Weil static void tcg_out_movi(TCGContext *s, TCGType type, 1042a534affSRichard Henderson TCGReg ret, tcg_target_long arg); 105c0ad3001SStefan Weil static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, 106c0ad3001SStefan Weil const int *const_args); 1072a534affSRichard Henderson static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1, 108a05b5b9bSRichard Henderson intptr_t arg2); 10959d7c14eSRichard Henderson static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val, 11059d7c14eSRichard Henderson TCGReg base, intptr_t ofs); 111cf066674SRichard Henderson static void tcg_out_call(TCGContext *s, tcg_insn_unit *target); 112f6c6afc1SRichard Henderson static int tcg_target_const_match(tcg_target_long val, TCGType type, 113c0ad3001SStefan Weil const TCGArgConstraint *arg_ct); 1149ecefc84SRichard Henderson static void tcg_out_tb_init(TCGContext *s); 11523dceda6SRichard Henderson static bool tcg_out_tb_finalize(TCGContext *s); 1169ecefc84SRichard Henderson 117c0ad3001SStefan Weil 118c896fe29Sbellard 119b1d8e52eSblueswir1 static TCGRegSet tcg_target_available_regs[2]; 120b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs; 121c896fe29Sbellard 1221813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1 1234196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v) 124c896fe29Sbellard { 125c896fe29Sbellard *s->code_ptr++ = v; 126c896fe29Sbellard } 127c896fe29Sbellard 1284196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p, 1294196dca6SPeter Maydell uint8_t v) 1305c53bb81SPeter Maydell { 1311813e175SRichard Henderson *p = v; 1325c53bb81SPeter Maydell } 1331813e175SRichard Henderson #endif 1345c53bb81SPeter Maydell 1351813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2 1364196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v) 137c896fe29Sbellard { 1381813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 2) { 1391813e175SRichard Henderson *s->code_ptr++ = v; 1401813e175SRichard Henderson } else { 1411813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 1424387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 1431813e175SRichard Henderson s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE); 1441813e175SRichard Henderson } 145c896fe29Sbellard } 146c896fe29Sbellard 1474196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p, 1484196dca6SPeter Maydell uint16_t v) 1495c53bb81SPeter Maydell { 1501813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 2) { 1511813e175SRichard Henderson *p = v; 1521813e175SRichard Henderson } else { 1535c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 1545c53bb81SPeter Maydell } 1551813e175SRichard Henderson } 1561813e175SRichard Henderson #endif 1575c53bb81SPeter Maydell 1581813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4 1594196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v) 160c896fe29Sbellard { 1611813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 4) { 1621813e175SRichard Henderson *s->code_ptr++ = v; 1631813e175SRichard Henderson } else { 1641813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 1654387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 1661813e175SRichard Henderson s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE); 1671813e175SRichard Henderson } 168c896fe29Sbellard } 169c896fe29Sbellard 1704196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p, 1714196dca6SPeter Maydell uint32_t v) 1725c53bb81SPeter Maydell { 1731813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 4) { 1741813e175SRichard Henderson *p = v; 1751813e175SRichard Henderson } else { 1765c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 1775c53bb81SPeter Maydell } 1781813e175SRichard Henderson } 1791813e175SRichard Henderson #endif 1805c53bb81SPeter Maydell 1811813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 8 1824196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v) 183ac26eb69SRichard Henderson { 1841813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 8) { 1851813e175SRichard Henderson *s->code_ptr++ = v; 1861813e175SRichard Henderson } else { 1871813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 1884387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 1891813e175SRichard Henderson s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE); 1901813e175SRichard Henderson } 191ac26eb69SRichard Henderson } 192ac26eb69SRichard Henderson 1934196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p, 1944196dca6SPeter Maydell uint64_t v) 1955c53bb81SPeter Maydell { 1961813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 8) { 1971813e175SRichard Henderson *p = v; 1981813e175SRichard Henderson } else { 1995c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 2005c53bb81SPeter Maydell } 2011813e175SRichard Henderson } 2021813e175SRichard Henderson #endif 2035c53bb81SPeter Maydell 204c896fe29Sbellard /* label relocation processing */ 205c896fe29Sbellard 2061813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type, 207bec16311SRichard Henderson TCGLabel *l, intptr_t addend) 208c896fe29Sbellard { 209c896fe29Sbellard TCGRelocation *r; 210c896fe29Sbellard 211c896fe29Sbellard if (l->has_value) { 212623e265cSpbrook /* FIXME: This may break relocations on RISC targets that 213623e265cSpbrook modify instruction fields in place. The caller may not have 214623e265cSpbrook written the initial value. */ 215f54b3f92Saurel32 patch_reloc(code_ptr, type, l->u.value, addend); 216c896fe29Sbellard } else { 217c896fe29Sbellard /* add a new relocation entry */ 218c896fe29Sbellard r = tcg_malloc(sizeof(TCGRelocation)); 219c896fe29Sbellard r->type = type; 220c896fe29Sbellard r->ptr = code_ptr; 221c896fe29Sbellard r->addend = addend; 222c896fe29Sbellard r->next = l->u.first_reloc; 223c896fe29Sbellard l->u.first_reloc = r; 224c896fe29Sbellard } 225c896fe29Sbellard } 226c896fe29Sbellard 227bec16311SRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l, tcg_insn_unit *ptr) 228c896fe29Sbellard { 2292ba7fae2SRichard Henderson intptr_t value = (intptr_t)ptr; 2301813e175SRichard Henderson TCGRelocation *r; 231c896fe29Sbellard 232eabb7b91SAurelien Jarno tcg_debug_assert(!l->has_value); 2331813e175SRichard Henderson 2341813e175SRichard Henderson for (r = l->u.first_reloc; r != NULL; r = r->next) { 235f54b3f92Saurel32 patch_reloc(r->ptr, r->type, value, r->addend); 236c896fe29Sbellard } 2371813e175SRichard Henderson 238c896fe29Sbellard l->has_value = 1; 2391813e175SRichard Henderson l->u.value_ptr = ptr; 240c896fe29Sbellard } 241c896fe29Sbellard 24242a268c2SRichard Henderson TCGLabel *gen_new_label(void) 243c896fe29Sbellard { 244c896fe29Sbellard TCGContext *s = &tcg_ctx; 24551e3972cSRichard Henderson TCGLabel *l = tcg_malloc(sizeof(TCGLabel)); 246c896fe29Sbellard 24751e3972cSRichard Henderson *l = (TCGLabel){ 24851e3972cSRichard Henderson .id = s->nb_labels++ 24951e3972cSRichard Henderson }; 25042a268c2SRichard Henderson 25142a268c2SRichard Henderson return l; 252c896fe29Sbellard } 253c896fe29Sbellard 254ce151109SPeter Maydell #include "tcg-target.inc.c" 255c896fe29Sbellard 256c896fe29Sbellard /* pool based memory allocation */ 257c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size) 258c896fe29Sbellard { 259c896fe29Sbellard TCGPool *p; 260c896fe29Sbellard int pool_size; 261c896fe29Sbellard 262c896fe29Sbellard if (size > TCG_POOL_CHUNK_SIZE) { 263c896fe29Sbellard /* big malloc: insert a new pool (XXX: could optimize) */ 2647267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + size); 265c896fe29Sbellard p->size = size; 2664055299eSKirill Batuzov p->next = s->pool_first_large; 2674055299eSKirill Batuzov s->pool_first_large = p; 2684055299eSKirill Batuzov return p->data; 269c896fe29Sbellard } else { 270c896fe29Sbellard p = s->pool_current; 271c896fe29Sbellard if (!p) { 272c896fe29Sbellard p = s->pool_first; 273c896fe29Sbellard if (!p) 274c896fe29Sbellard goto new_pool; 275c896fe29Sbellard } else { 276c896fe29Sbellard if (!p->next) { 277c896fe29Sbellard new_pool: 278c896fe29Sbellard pool_size = TCG_POOL_CHUNK_SIZE; 2797267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + pool_size); 280c896fe29Sbellard p->size = pool_size; 281c896fe29Sbellard p->next = NULL; 282c896fe29Sbellard if (s->pool_current) 283c896fe29Sbellard s->pool_current->next = p; 284c896fe29Sbellard else 285c896fe29Sbellard s->pool_first = p; 286c896fe29Sbellard } else { 287c896fe29Sbellard p = p->next; 288c896fe29Sbellard } 289c896fe29Sbellard } 290c896fe29Sbellard } 291c896fe29Sbellard s->pool_current = p; 292c896fe29Sbellard s->pool_cur = p->data + size; 293c896fe29Sbellard s->pool_end = p->data + p->size; 294c896fe29Sbellard return p->data; 295c896fe29Sbellard } 296c896fe29Sbellard 297c896fe29Sbellard void tcg_pool_reset(TCGContext *s) 298c896fe29Sbellard { 2994055299eSKirill Batuzov TCGPool *p, *t; 3004055299eSKirill Batuzov for (p = s->pool_first_large; p; p = t) { 3014055299eSKirill Batuzov t = p->next; 3024055299eSKirill Batuzov g_free(p); 3034055299eSKirill Batuzov } 3044055299eSKirill Batuzov s->pool_first_large = NULL; 305c896fe29Sbellard s->pool_cur = s->pool_end = NULL; 306c896fe29Sbellard s->pool_current = NULL; 307c896fe29Sbellard } 308c896fe29Sbellard 309100b5e01SRichard Henderson typedef struct TCGHelperInfo { 310100b5e01SRichard Henderson void *func; 311100b5e01SRichard Henderson const char *name; 312afb49896SRichard Henderson unsigned flags; 313afb49896SRichard Henderson unsigned sizemask; 314100b5e01SRichard Henderson } TCGHelperInfo; 315100b5e01SRichard Henderson 3162ef6175aSRichard Henderson #include "exec/helper-proto.h" 3172ef6175aSRichard Henderson 318100b5e01SRichard Henderson static const TCGHelperInfo all_helpers[] = { 3192ef6175aSRichard Henderson #include "exec/helper-tcg.h" 320100b5e01SRichard Henderson }; 321100b5e01SRichard Henderson 32291478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)]; 323*f69d277eSRichard Henderson static void process_op_defs(TCGContext *s); 32491478cefSRichard Henderson 325c896fe29Sbellard void tcg_context_init(TCGContext *s) 326c896fe29Sbellard { 327100b5e01SRichard Henderson int op, total_args, n, i; 328c896fe29Sbellard TCGOpDef *def; 329c896fe29Sbellard TCGArgConstraint *args_ct; 330c896fe29Sbellard int *sorted_args; 33184fd9dd3SRichard Henderson GHashTable *helper_table; 332c896fe29Sbellard 333c896fe29Sbellard memset(s, 0, sizeof(*s)); 334c896fe29Sbellard s->nb_globals = 0; 335c896fe29Sbellard 336c896fe29Sbellard /* Count total number of arguments and allocate the corresponding 337c896fe29Sbellard space */ 338c896fe29Sbellard total_args = 0; 339c896fe29Sbellard for(op = 0; op < NB_OPS; op++) { 340c896fe29Sbellard def = &tcg_op_defs[op]; 341c896fe29Sbellard n = def->nb_iargs + def->nb_oargs; 342c896fe29Sbellard total_args += n; 343c896fe29Sbellard } 344c896fe29Sbellard 3457267c094SAnthony Liguori args_ct = g_malloc(sizeof(TCGArgConstraint) * total_args); 3467267c094SAnthony Liguori sorted_args = g_malloc(sizeof(int) * total_args); 347c896fe29Sbellard 348c896fe29Sbellard for(op = 0; op < NB_OPS; op++) { 349c896fe29Sbellard def = &tcg_op_defs[op]; 350c896fe29Sbellard def->args_ct = args_ct; 351c896fe29Sbellard def->sorted_args = sorted_args; 352c896fe29Sbellard n = def->nb_iargs + def->nb_oargs; 353c896fe29Sbellard sorted_args += n; 354c896fe29Sbellard args_ct += n; 355c896fe29Sbellard } 356c896fe29Sbellard 3575cd8f621SRichard Henderson /* Register helpers. */ 35884fd9dd3SRichard Henderson /* Use g_direct_hash/equal for direct pointer comparisons on func. */ 35984fd9dd3SRichard Henderson s->helpers = helper_table = g_hash_table_new(NULL, NULL); 36084fd9dd3SRichard Henderson 361100b5e01SRichard Henderson for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) { 36284fd9dd3SRichard Henderson g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func, 36372866e82SRichard Henderson (gpointer)&all_helpers[i]); 364100b5e01SRichard Henderson } 3655cd8f621SRichard Henderson 366c896fe29Sbellard tcg_target_init(s); 367*f69d277eSRichard Henderson process_op_defs(s); 36891478cefSRichard Henderson 36991478cefSRichard Henderson /* Reverse the order of the saved registers, assuming they're all at 37091478cefSRichard Henderson the start of tcg_target_reg_alloc_order. */ 37191478cefSRichard Henderson for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) { 37291478cefSRichard Henderson int r = tcg_target_reg_alloc_order[n]; 37391478cefSRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) { 37491478cefSRichard Henderson break; 37591478cefSRichard Henderson } 37691478cefSRichard Henderson } 37791478cefSRichard Henderson for (i = 0; i < n; ++i) { 37891478cefSRichard Henderson indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i]; 37991478cefSRichard Henderson } 38091478cefSRichard Henderson for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) { 38191478cefSRichard Henderson indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i]; 38291478cefSRichard Henderson } 3839002ec79SRichard Henderson } 384b03cce8eSbellard 3859002ec79SRichard Henderson void tcg_prologue_init(TCGContext *s) 3869002ec79SRichard Henderson { 3878163b749SRichard Henderson size_t prologue_size, total_size; 3888163b749SRichard Henderson void *buf0, *buf1; 3898163b749SRichard Henderson 3908163b749SRichard Henderson /* Put the prologue at the beginning of code_gen_buffer. */ 3918163b749SRichard Henderson buf0 = s->code_gen_buffer; 3928163b749SRichard Henderson s->code_ptr = buf0; 3938163b749SRichard Henderson s->code_buf = buf0; 3948163b749SRichard Henderson s->code_gen_prologue = buf0; 3958163b749SRichard Henderson 3968163b749SRichard Henderson /* Generate the prologue. */ 397b03cce8eSbellard tcg_target_qemu_prologue(s); 3988163b749SRichard Henderson buf1 = s->code_ptr; 3998163b749SRichard Henderson flush_icache_range((uintptr_t)buf0, (uintptr_t)buf1); 4008163b749SRichard Henderson 4018163b749SRichard Henderson /* Deduct the prologue from the buffer. */ 4028163b749SRichard Henderson prologue_size = tcg_current_code_size(s); 4038163b749SRichard Henderson s->code_gen_ptr = buf1; 4048163b749SRichard Henderson s->code_gen_buffer = buf1; 4058163b749SRichard Henderson s->code_buf = buf1; 4068163b749SRichard Henderson total_size = s->code_gen_buffer_size - prologue_size; 4078163b749SRichard Henderson s->code_gen_buffer_size = total_size; 4088163b749SRichard Henderson 409b125f9dcSRichard Henderson /* Compute a high-water mark, at which we voluntarily flush the buffer 410b125f9dcSRichard Henderson and start over. The size here is arbitrary, significantly larger 411b125f9dcSRichard Henderson than we expect the code generation for any one opcode to require. */ 41223dceda6SRichard Henderson s->code_gen_highwater = s->code_gen_buffer + (total_size - 1024); 4138163b749SRichard Henderson 4148163b749SRichard Henderson tcg_register_jit(s->code_gen_buffer, total_size); 415d6b64b2bSRichard Henderson 416d6b64b2bSRichard Henderson #ifdef DEBUG_DISAS 417d6b64b2bSRichard Henderson if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) { 4181ee73216SRichard Henderson qemu_log_lock(); 4198163b749SRichard Henderson qemu_log("PROLOGUE: [size=%zu]\n", prologue_size); 4208163b749SRichard Henderson log_disas(buf0, prologue_size); 421d6b64b2bSRichard Henderson qemu_log("\n"); 422d6b64b2bSRichard Henderson qemu_log_flush(); 4231ee73216SRichard Henderson qemu_log_unlock(); 424d6b64b2bSRichard Henderson } 425d6b64b2bSRichard Henderson #endif 426c896fe29Sbellard } 427c896fe29Sbellard 428c896fe29Sbellard void tcg_func_start(TCGContext *s) 429c896fe29Sbellard { 430c896fe29Sbellard tcg_pool_reset(s); 431c896fe29Sbellard s->nb_temps = s->nb_globals; 4320ec9eabcSRichard Henderson 4330ec9eabcSRichard Henderson /* No temps have been previously allocated for size or locality. */ 4340ec9eabcSRichard Henderson memset(s->free_temps, 0, sizeof(s->free_temps)); 4350ec9eabcSRichard Henderson 436c896fe29Sbellard s->nb_labels = 0; 437c896fe29Sbellard s->current_frame_offset = s->frame_start; 438c896fe29Sbellard 4390a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG 4400a209d4bSRichard Henderson s->goto_tb_issue_mask = 0; 4410a209d4bSRichard Henderson #endif 4420a209d4bSRichard Henderson 443dcb8e758SRichard Henderson s->gen_op_buf[0].next = 1; 444dcb8e758SRichard Henderson s->gen_op_buf[0].prev = 0; 445dcb8e758SRichard Henderson s->gen_next_op_idx = 1; 446c45cb8bbSRichard Henderson s->gen_next_parm_idx = 0; 447b76f0d8cSYeongkyoon Lee 4489ecefc84SRichard Henderson s->be = tcg_malloc(sizeof(TCGBackendData)); 449c896fe29Sbellard } 450c896fe29Sbellard 4517ca4b752SRichard Henderson static inline int temp_idx(TCGContext *s, TCGTemp *ts) 452c896fe29Sbellard { 4537ca4b752SRichard Henderson ptrdiff_t n = ts - s->temps; 4547ca4b752SRichard Henderson tcg_debug_assert(n >= 0 && n < s->nb_temps); 4557ca4b752SRichard Henderson return n; 4567ca4b752SRichard Henderson } 4577ca4b752SRichard Henderson 4587ca4b752SRichard Henderson static inline TCGTemp *tcg_temp_alloc(TCGContext *s) 4597ca4b752SRichard Henderson { 4607ca4b752SRichard Henderson int n = s->nb_temps++; 4617ca4b752SRichard Henderson tcg_debug_assert(n < TCG_MAX_TEMPS); 4627ca4b752SRichard Henderson return memset(&s->temps[n], 0, sizeof(TCGTemp)); 4637ca4b752SRichard Henderson } 4647ca4b752SRichard Henderson 4657ca4b752SRichard Henderson static inline TCGTemp *tcg_global_alloc(TCGContext *s) 4667ca4b752SRichard Henderson { 4677ca4b752SRichard Henderson tcg_debug_assert(s->nb_globals == s->nb_temps); 4687ca4b752SRichard Henderson s->nb_globals++; 4697ca4b752SRichard Henderson return tcg_temp_alloc(s); 470c896fe29Sbellard } 471c896fe29Sbellard 472b3a62939SRichard Henderson static int tcg_global_reg_new_internal(TCGContext *s, TCGType type, 473b6638662SRichard Henderson TCGReg reg, const char *name) 474c896fe29Sbellard { 475c896fe29Sbellard TCGTemp *ts; 476c896fe29Sbellard 477b3a62939SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type != TCG_TYPE_I32) { 478c896fe29Sbellard tcg_abort(); 479b3a62939SRichard Henderson } 4807ca4b752SRichard Henderson 4817ca4b752SRichard Henderson ts = tcg_global_alloc(s); 482c896fe29Sbellard ts->base_type = type; 483c896fe29Sbellard ts->type = type; 484c896fe29Sbellard ts->fixed_reg = 1; 485c896fe29Sbellard ts->reg = reg; 486c896fe29Sbellard ts->name = name; 487c896fe29Sbellard tcg_regset_set_reg(s->reserved_regs, reg); 4887ca4b752SRichard Henderson 4897ca4b752SRichard Henderson return temp_idx(s, ts); 490a7812ae4Spbrook } 491a7812ae4Spbrook 492b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size) 493a7812ae4Spbrook { 494a7812ae4Spbrook int idx; 495b3a62939SRichard Henderson s->frame_start = start; 496b3a62939SRichard Henderson s->frame_end = start + size; 497b3a62939SRichard Henderson idx = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame"); 498b3a62939SRichard Henderson s->frame_temp = &s->temps[idx]; 499b3a62939SRichard Henderson } 500a7812ae4Spbrook 501b6638662SRichard Henderson TCGv_i32 tcg_global_reg_new_i32(TCGReg reg, const char *name) 502b3a62939SRichard Henderson { 503b3a62939SRichard Henderson TCGContext *s = &tcg_ctx; 504b3a62939SRichard Henderson int idx; 505b3a62939SRichard Henderson 506b3a62939SRichard Henderson if (tcg_regset_test_reg(s->reserved_regs, reg)) { 507b3a62939SRichard Henderson tcg_abort(); 508b3a62939SRichard Henderson } 509b3a62939SRichard Henderson idx = tcg_global_reg_new_internal(s, TCG_TYPE_I32, reg, name); 510a7812ae4Spbrook return MAKE_TCGV_I32(idx); 511a7812ae4Spbrook } 512a7812ae4Spbrook 513b6638662SRichard Henderson TCGv_i64 tcg_global_reg_new_i64(TCGReg reg, const char *name) 514a7812ae4Spbrook { 515b3a62939SRichard Henderson TCGContext *s = &tcg_ctx; 516a7812ae4Spbrook int idx; 517a7812ae4Spbrook 518b3a62939SRichard Henderson if (tcg_regset_test_reg(s->reserved_regs, reg)) { 519b3a62939SRichard Henderson tcg_abort(); 520b3a62939SRichard Henderson } 521b3a62939SRichard Henderson idx = tcg_global_reg_new_internal(s, TCG_TYPE_I64, reg, name); 522a7812ae4Spbrook return MAKE_TCGV_I64(idx); 523c896fe29Sbellard } 524c896fe29Sbellard 525e1ccc054SRichard Henderson int tcg_global_mem_new_internal(TCGType type, TCGv_ptr base, 526e1ccc054SRichard Henderson intptr_t offset, const char *name) 527c896fe29Sbellard { 528c896fe29Sbellard TCGContext *s = &tcg_ctx; 5297ca4b752SRichard Henderson TCGTemp *base_ts = &s->temps[GET_TCGV_PTR(base)]; 5307ca4b752SRichard Henderson TCGTemp *ts = tcg_global_alloc(s); 531b3915dbbSRichard Henderson int indirect_reg = 0, bigendian = 0; 5327ca4b752SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 5337ca4b752SRichard Henderson bigendian = 1; 5347ca4b752SRichard Henderson #endif 535c896fe29Sbellard 536b3915dbbSRichard Henderson if (!base_ts->fixed_reg) { 5375a18407fSRichard Henderson /* We do not support double-indirect registers. */ 5385a18407fSRichard Henderson tcg_debug_assert(!base_ts->indirect_reg); 539b3915dbbSRichard Henderson base_ts->indirect_base = 1; 5405a18407fSRichard Henderson s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64 5415a18407fSRichard Henderson ? 2 : 1); 5425a18407fSRichard Henderson indirect_reg = 1; 543b3915dbbSRichard Henderson } 544b3915dbbSRichard Henderson 5457ca4b752SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { 5467ca4b752SRichard Henderson TCGTemp *ts2 = tcg_global_alloc(s); 547c896fe29Sbellard char buf[64]; 5487ca4b752SRichard Henderson 5497ca4b752SRichard Henderson ts->base_type = TCG_TYPE_I64; 550c896fe29Sbellard ts->type = TCG_TYPE_I32; 551b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg; 552c896fe29Sbellard ts->mem_allocated = 1; 553b3a62939SRichard Henderson ts->mem_base = base_ts; 5547ca4b752SRichard Henderson ts->mem_offset = offset + bigendian * 4; 555c896fe29Sbellard pstrcpy(buf, sizeof(buf), name); 556c896fe29Sbellard pstrcat(buf, sizeof(buf), "_0"); 557c896fe29Sbellard ts->name = strdup(buf); 558c896fe29Sbellard 5597ca4b752SRichard Henderson tcg_debug_assert(ts2 == ts + 1); 5607ca4b752SRichard Henderson ts2->base_type = TCG_TYPE_I64; 5617ca4b752SRichard Henderson ts2->type = TCG_TYPE_I32; 562b3915dbbSRichard Henderson ts2->indirect_reg = indirect_reg; 5637ca4b752SRichard Henderson ts2->mem_allocated = 1; 5647ca4b752SRichard Henderson ts2->mem_base = base_ts; 5657ca4b752SRichard Henderson ts2->mem_offset = offset + (1 - bigendian) * 4; 566c896fe29Sbellard pstrcpy(buf, sizeof(buf), name); 567c896fe29Sbellard pstrcat(buf, sizeof(buf), "_1"); 568120c1084SRichard Henderson ts2->name = strdup(buf); 5697ca4b752SRichard Henderson } else { 570c896fe29Sbellard ts->base_type = type; 571c896fe29Sbellard ts->type = type; 572b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg; 573c896fe29Sbellard ts->mem_allocated = 1; 574b3a62939SRichard Henderson ts->mem_base = base_ts; 575c896fe29Sbellard ts->mem_offset = offset; 576c896fe29Sbellard ts->name = name; 577c896fe29Sbellard } 5787ca4b752SRichard Henderson return temp_idx(s, ts); 579c896fe29Sbellard } 580c896fe29Sbellard 5817ca4b752SRichard Henderson static int tcg_temp_new_internal(TCGType type, int temp_local) 582c896fe29Sbellard { 583c896fe29Sbellard TCGContext *s = &tcg_ctx; 584c896fe29Sbellard TCGTemp *ts; 585641d5fbeSbellard int idx, k; 586c896fe29Sbellard 5870ec9eabcSRichard Henderson k = type + (temp_local ? TCG_TYPE_COUNT : 0); 5880ec9eabcSRichard Henderson idx = find_first_bit(s->free_temps[k].l, TCG_MAX_TEMPS); 5890ec9eabcSRichard Henderson if (idx < TCG_MAX_TEMPS) { 5900ec9eabcSRichard Henderson /* There is already an available temp with the right type. */ 5910ec9eabcSRichard Henderson clear_bit(idx, s->free_temps[k].l); 5920ec9eabcSRichard Henderson 593e8996ee0Sbellard ts = &s->temps[idx]; 594e8996ee0Sbellard ts->temp_allocated = 1; 5957ca4b752SRichard Henderson tcg_debug_assert(ts->base_type == type); 5967ca4b752SRichard Henderson tcg_debug_assert(ts->temp_local == temp_local); 597e8996ee0Sbellard } else { 5987ca4b752SRichard Henderson ts = tcg_temp_alloc(s); 5997ca4b752SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { 6007ca4b752SRichard Henderson TCGTemp *ts2 = tcg_temp_alloc(s); 6017ca4b752SRichard Henderson 602c896fe29Sbellard ts->base_type = type; 603c896fe29Sbellard ts->type = TCG_TYPE_I32; 604e8996ee0Sbellard ts->temp_allocated = 1; 605641d5fbeSbellard ts->temp_local = temp_local; 6067ca4b752SRichard Henderson 6077ca4b752SRichard Henderson tcg_debug_assert(ts2 == ts + 1); 6087ca4b752SRichard Henderson ts2->base_type = TCG_TYPE_I64; 6097ca4b752SRichard Henderson ts2->type = TCG_TYPE_I32; 6107ca4b752SRichard Henderson ts2->temp_allocated = 1; 6117ca4b752SRichard Henderson ts2->temp_local = temp_local; 6127ca4b752SRichard Henderson } else { 613c896fe29Sbellard ts->base_type = type; 614c896fe29Sbellard ts->type = type; 615e8996ee0Sbellard ts->temp_allocated = 1; 616641d5fbeSbellard ts->temp_local = temp_local; 617c896fe29Sbellard } 6187ca4b752SRichard Henderson idx = temp_idx(s, ts); 619e8996ee0Sbellard } 62027bfd83cSPeter Maydell 62127bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG) 62227bfd83cSPeter Maydell s->temps_in_use++; 62327bfd83cSPeter Maydell #endif 624a7812ae4Spbrook return idx; 625c896fe29Sbellard } 626c896fe29Sbellard 627a7812ae4Spbrook TCGv_i32 tcg_temp_new_internal_i32(int temp_local) 628a7812ae4Spbrook { 629a7812ae4Spbrook int idx; 630a7812ae4Spbrook 631a7812ae4Spbrook idx = tcg_temp_new_internal(TCG_TYPE_I32, temp_local); 632a7812ae4Spbrook return MAKE_TCGV_I32(idx); 633a7812ae4Spbrook } 634a7812ae4Spbrook 635a7812ae4Spbrook TCGv_i64 tcg_temp_new_internal_i64(int temp_local) 636a7812ae4Spbrook { 637a7812ae4Spbrook int idx; 638a7812ae4Spbrook 639a7812ae4Spbrook idx = tcg_temp_new_internal(TCG_TYPE_I64, temp_local); 640a7812ae4Spbrook return MAKE_TCGV_I64(idx); 641a7812ae4Spbrook } 642a7812ae4Spbrook 6430ec9eabcSRichard Henderson static void tcg_temp_free_internal(int idx) 644c896fe29Sbellard { 645c896fe29Sbellard TCGContext *s = &tcg_ctx; 646c896fe29Sbellard TCGTemp *ts; 647641d5fbeSbellard int k; 648c896fe29Sbellard 64927bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG) 65027bfd83cSPeter Maydell s->temps_in_use--; 65127bfd83cSPeter Maydell if (s->temps_in_use < 0) { 65227bfd83cSPeter Maydell fprintf(stderr, "More temporaries freed than allocated!\n"); 65327bfd83cSPeter Maydell } 65427bfd83cSPeter Maydell #endif 65527bfd83cSPeter Maydell 656eabb7b91SAurelien Jarno tcg_debug_assert(idx >= s->nb_globals && idx < s->nb_temps); 657c896fe29Sbellard ts = &s->temps[idx]; 658eabb7b91SAurelien Jarno tcg_debug_assert(ts->temp_allocated != 0); 659e8996ee0Sbellard ts->temp_allocated = 0; 6600ec9eabcSRichard Henderson 66118d13fa2SAlexander Graf k = ts->base_type + (ts->temp_local ? TCG_TYPE_COUNT : 0); 6620ec9eabcSRichard Henderson set_bit(idx, s->free_temps[k].l); 663e8996ee0Sbellard } 664e8996ee0Sbellard 665a7812ae4Spbrook void tcg_temp_free_i32(TCGv_i32 arg) 666e8996ee0Sbellard { 667a7812ae4Spbrook tcg_temp_free_internal(GET_TCGV_I32(arg)); 668a7812ae4Spbrook } 669a7812ae4Spbrook 670a7812ae4Spbrook void tcg_temp_free_i64(TCGv_i64 arg) 671a7812ae4Spbrook { 672a7812ae4Spbrook tcg_temp_free_internal(GET_TCGV_I64(arg)); 673a7812ae4Spbrook } 674a7812ae4Spbrook 675a7812ae4Spbrook TCGv_i32 tcg_const_i32(int32_t val) 676a7812ae4Spbrook { 677a7812ae4Spbrook TCGv_i32 t0; 678a7812ae4Spbrook t0 = tcg_temp_new_i32(); 679e8996ee0Sbellard tcg_gen_movi_i32(t0, val); 680e8996ee0Sbellard return t0; 681c896fe29Sbellard } 682c896fe29Sbellard 683a7812ae4Spbrook TCGv_i64 tcg_const_i64(int64_t val) 684c896fe29Sbellard { 685a7812ae4Spbrook TCGv_i64 t0; 686a7812ae4Spbrook t0 = tcg_temp_new_i64(); 687e8996ee0Sbellard tcg_gen_movi_i64(t0, val); 688e8996ee0Sbellard return t0; 689c896fe29Sbellard } 690c896fe29Sbellard 691a7812ae4Spbrook TCGv_i32 tcg_const_local_i32(int32_t val) 692bdffd4a9Saurel32 { 693a7812ae4Spbrook TCGv_i32 t0; 694a7812ae4Spbrook t0 = tcg_temp_local_new_i32(); 695bdffd4a9Saurel32 tcg_gen_movi_i32(t0, val); 696bdffd4a9Saurel32 return t0; 697bdffd4a9Saurel32 } 698bdffd4a9Saurel32 699a7812ae4Spbrook TCGv_i64 tcg_const_local_i64(int64_t val) 700bdffd4a9Saurel32 { 701a7812ae4Spbrook TCGv_i64 t0; 702a7812ae4Spbrook t0 = tcg_temp_local_new_i64(); 703bdffd4a9Saurel32 tcg_gen_movi_i64(t0, val); 704bdffd4a9Saurel32 return t0; 705bdffd4a9Saurel32 } 706bdffd4a9Saurel32 70727bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG) 70827bfd83cSPeter Maydell void tcg_clear_temp_count(void) 70927bfd83cSPeter Maydell { 71027bfd83cSPeter Maydell TCGContext *s = &tcg_ctx; 71127bfd83cSPeter Maydell s->temps_in_use = 0; 71227bfd83cSPeter Maydell } 71327bfd83cSPeter Maydell 71427bfd83cSPeter Maydell int tcg_check_temp_count(void) 71527bfd83cSPeter Maydell { 71627bfd83cSPeter Maydell TCGContext *s = &tcg_ctx; 71727bfd83cSPeter Maydell if (s->temps_in_use) { 71827bfd83cSPeter Maydell /* Clear the count so that we don't give another 71927bfd83cSPeter Maydell * warning immediately next time around. 72027bfd83cSPeter Maydell */ 72127bfd83cSPeter Maydell s->temps_in_use = 0; 72227bfd83cSPeter Maydell return 1; 72327bfd83cSPeter Maydell } 72427bfd83cSPeter Maydell return 0; 72527bfd83cSPeter Maydell } 72627bfd83cSPeter Maydell #endif 72727bfd83cSPeter Maydell 72839cf05d3Sbellard /* Note: we convert the 64 bit args to 32 bit and do some alignment 72939cf05d3Sbellard and endian swap. Maybe it would be better to do the alignment 73039cf05d3Sbellard and endian swap in tcg_reg_alloc_call(). */ 731bbb8a1b4SRichard Henderson void tcg_gen_callN(TCGContext *s, void *func, TCGArg ret, 732bbb8a1b4SRichard Henderson int nargs, TCGArg *args) 733c896fe29Sbellard { 734c45cb8bbSRichard Henderson int i, real_args, nb_rets, pi, pi_first; 735bbb8a1b4SRichard Henderson unsigned sizemask, flags; 736afb49896SRichard Henderson TCGHelperInfo *info; 737afb49896SRichard Henderson 738afb49896SRichard Henderson info = g_hash_table_lookup(s->helpers, (gpointer)func); 739bbb8a1b4SRichard Henderson flags = info->flags; 740bbb8a1b4SRichard Henderson sizemask = info->sizemask; 7412bece2c8SRichard Henderson 74234b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \ 74334b1a49cSRichard Henderson && !defined(CONFIG_TCG_INTERPRETER) 74434b1a49cSRichard Henderson /* We have 64-bit values in one register, but need to pass as two 74534b1a49cSRichard Henderson separate parameters. Split them. */ 74634b1a49cSRichard Henderson int orig_sizemask = sizemask; 74734b1a49cSRichard Henderson int orig_nargs = nargs; 74834b1a49cSRichard Henderson TCGv_i64 retl, reth; 74934b1a49cSRichard Henderson 75034b1a49cSRichard Henderson TCGV_UNUSED_I64(retl); 75134b1a49cSRichard Henderson TCGV_UNUSED_I64(reth); 75234b1a49cSRichard Henderson if (sizemask != 0) { 75334b1a49cSRichard Henderson TCGArg *split_args = __builtin_alloca(sizeof(TCGArg) * nargs * 2); 75434b1a49cSRichard Henderson for (i = real_args = 0; i < nargs; ++i) { 75534b1a49cSRichard Henderson int is_64bit = sizemask & (1 << (i+1)*2); 75634b1a49cSRichard Henderson if (is_64bit) { 75734b1a49cSRichard Henderson TCGv_i64 orig = MAKE_TCGV_I64(args[i]); 75834b1a49cSRichard Henderson TCGv_i32 h = tcg_temp_new_i32(); 75934b1a49cSRichard Henderson TCGv_i32 l = tcg_temp_new_i32(); 76034b1a49cSRichard Henderson tcg_gen_extr_i64_i32(l, h, orig); 76134b1a49cSRichard Henderson split_args[real_args++] = GET_TCGV_I32(h); 76234b1a49cSRichard Henderson split_args[real_args++] = GET_TCGV_I32(l); 76334b1a49cSRichard Henderson } else { 76434b1a49cSRichard Henderson split_args[real_args++] = args[i]; 76534b1a49cSRichard Henderson } 76634b1a49cSRichard Henderson } 76734b1a49cSRichard Henderson nargs = real_args; 76834b1a49cSRichard Henderson args = split_args; 76934b1a49cSRichard Henderson sizemask = 0; 77034b1a49cSRichard Henderson } 77134b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64 7722bece2c8SRichard Henderson for (i = 0; i < nargs; ++i) { 7732bece2c8SRichard Henderson int is_64bit = sizemask & (1 << (i+1)*2); 7742bece2c8SRichard Henderson int is_signed = sizemask & (2 << (i+1)*2); 7752bece2c8SRichard Henderson if (!is_64bit) { 7762bece2c8SRichard Henderson TCGv_i64 temp = tcg_temp_new_i64(); 7772bece2c8SRichard Henderson TCGv_i64 orig = MAKE_TCGV_I64(args[i]); 7782bece2c8SRichard Henderson if (is_signed) { 7792bece2c8SRichard Henderson tcg_gen_ext32s_i64(temp, orig); 7802bece2c8SRichard Henderson } else { 7812bece2c8SRichard Henderson tcg_gen_ext32u_i64(temp, orig); 7822bece2c8SRichard Henderson } 7832bece2c8SRichard Henderson args[i] = GET_TCGV_I64(temp); 7842bece2c8SRichard Henderson } 7852bece2c8SRichard Henderson } 7862bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */ 7872bece2c8SRichard Henderson 788c45cb8bbSRichard Henderson pi_first = pi = s->gen_next_parm_idx; 789a7812ae4Spbrook if (ret != TCG_CALL_DUMMY_ARG) { 79034b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \ 79134b1a49cSRichard Henderson && !defined(CONFIG_TCG_INTERPRETER) 79234b1a49cSRichard Henderson if (orig_sizemask & 1) { 79334b1a49cSRichard Henderson /* The 32-bit ABI is going to return the 64-bit value in 79434b1a49cSRichard Henderson the %o0/%o1 register pair. Prepare for this by using 79534b1a49cSRichard Henderson two return temporaries, and reassemble below. */ 79634b1a49cSRichard Henderson retl = tcg_temp_new_i64(); 79734b1a49cSRichard Henderson reth = tcg_temp_new_i64(); 798c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = GET_TCGV_I64(reth); 799c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = GET_TCGV_I64(retl); 80034b1a49cSRichard Henderson nb_rets = 2; 80134b1a49cSRichard Henderson } else { 802c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = ret; 80334b1a49cSRichard Henderson nb_rets = 1; 80434b1a49cSRichard Henderson } 80534b1a49cSRichard Henderson #else 80634b1a49cSRichard Henderson if (TCG_TARGET_REG_BITS < 64 && (sizemask & 1)) { 80702eb19d0SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 808c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = ret + 1; 809c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = ret; 810a7812ae4Spbrook #else 811c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = ret; 812c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = ret + 1; 813a7812ae4Spbrook #endif 814a7812ae4Spbrook nb_rets = 2; 81534b1a49cSRichard Henderson } else { 816c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = ret; 817a7812ae4Spbrook nb_rets = 1; 818a7812ae4Spbrook } 81934b1a49cSRichard Henderson #endif 820a7812ae4Spbrook } else { 821a7812ae4Spbrook nb_rets = 0; 822a7812ae4Spbrook } 823a7812ae4Spbrook real_args = 0; 824a7812ae4Spbrook for (i = 0; i < nargs; i++) { 8252bece2c8SRichard Henderson int is_64bit = sizemask & (1 << (i+1)*2); 826bbb8a1b4SRichard Henderson if (TCG_TARGET_REG_BITS < 64 && is_64bit) { 82739cf05d3Sbellard #ifdef TCG_TARGET_CALL_ALIGN_ARGS 82839cf05d3Sbellard /* some targets want aligned 64 bit args */ 829ebd486d5Smalc if (real_args & 1) { 830c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = TCG_CALL_DUMMY_ARG; 831ebd486d5Smalc real_args++; 83239cf05d3Sbellard } 83339cf05d3Sbellard #endif 8343f90f252SRichard Henderson /* If stack grows up, then we will be placing successive 8353f90f252SRichard Henderson arguments at lower addresses, which means we need to 8363f90f252SRichard Henderson reverse the order compared to how we would normally 8373f90f252SRichard Henderson treat either big or little-endian. For those arguments 8383f90f252SRichard Henderson that will wind up in registers, this still works for 8393f90f252SRichard Henderson HPPA (the only current STACK_GROWSUP target) since the 8403f90f252SRichard Henderson argument registers are *also* allocated in decreasing 8413f90f252SRichard Henderson order. If another such target is added, this logic may 8423f90f252SRichard Henderson have to get more complicated to differentiate between 8433f90f252SRichard Henderson stack arguments and register arguments. */ 84402eb19d0SRichard Henderson #if defined(HOST_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP) 845c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = args[i] + 1; 846c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = args[i]; 847c896fe29Sbellard #else 848c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = args[i]; 849c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = args[i] + 1; 850c896fe29Sbellard #endif 851a7812ae4Spbrook real_args += 2; 8522bece2c8SRichard Henderson continue; 8532bece2c8SRichard Henderson } 8542bece2c8SRichard Henderson 855c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = args[i]; 856a7812ae4Spbrook real_args++; 857c896fe29Sbellard } 858c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = (uintptr_t)func; 859c45cb8bbSRichard Henderson s->gen_opparam_buf[pi++] = flags; 860a7812ae4Spbrook 861c45cb8bbSRichard Henderson i = s->gen_next_op_idx; 862c45cb8bbSRichard Henderson tcg_debug_assert(i < OPC_BUF_SIZE); 863c45cb8bbSRichard Henderson tcg_debug_assert(pi <= OPPARAM_BUF_SIZE); 864a7812ae4Spbrook 865c45cb8bbSRichard Henderson /* Set links for sequential allocation during translation. */ 866c45cb8bbSRichard Henderson s->gen_op_buf[i] = (TCGOp){ 867c45cb8bbSRichard Henderson .opc = INDEX_op_call, 868c45cb8bbSRichard Henderson .callo = nb_rets, 869c45cb8bbSRichard Henderson .calli = real_args, 870c45cb8bbSRichard Henderson .args = pi_first, 871c45cb8bbSRichard Henderson .prev = i - 1, 872c45cb8bbSRichard Henderson .next = i + 1 873c45cb8bbSRichard Henderson }; 874c45cb8bbSRichard Henderson 875c45cb8bbSRichard Henderson /* Make sure the calli field didn't overflow. */ 876c45cb8bbSRichard Henderson tcg_debug_assert(s->gen_op_buf[i].calli == real_args); 877c45cb8bbSRichard Henderson 878dcb8e758SRichard Henderson s->gen_op_buf[0].prev = i; 879c45cb8bbSRichard Henderson s->gen_next_op_idx = i + 1; 880c45cb8bbSRichard Henderson s->gen_next_parm_idx = pi; 8812bece2c8SRichard Henderson 88234b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \ 88334b1a49cSRichard Henderson && !defined(CONFIG_TCG_INTERPRETER) 88434b1a49cSRichard Henderson /* Free all of the parts we allocated above. */ 88534b1a49cSRichard Henderson for (i = real_args = 0; i < orig_nargs; ++i) { 88634b1a49cSRichard Henderson int is_64bit = orig_sizemask & (1 << (i+1)*2); 88734b1a49cSRichard Henderson if (is_64bit) { 88834b1a49cSRichard Henderson TCGv_i32 h = MAKE_TCGV_I32(args[real_args++]); 88934b1a49cSRichard Henderson TCGv_i32 l = MAKE_TCGV_I32(args[real_args++]); 89034b1a49cSRichard Henderson tcg_temp_free_i32(h); 89134b1a49cSRichard Henderson tcg_temp_free_i32(l); 89234b1a49cSRichard Henderson } else { 89334b1a49cSRichard Henderson real_args++; 89434b1a49cSRichard Henderson } 89534b1a49cSRichard Henderson } 89634b1a49cSRichard Henderson if (orig_sizemask & 1) { 89734b1a49cSRichard Henderson /* The 32-bit ABI returned two 32-bit pieces. Re-assemble them. 89834b1a49cSRichard Henderson Note that describing these as TCGv_i64 eliminates an unnecessary 89934b1a49cSRichard Henderson zero-extension that tcg_gen_concat_i32_i64 would create. */ 90034b1a49cSRichard Henderson tcg_gen_concat32_i64(MAKE_TCGV_I64(ret), retl, reth); 90134b1a49cSRichard Henderson tcg_temp_free_i64(retl); 90234b1a49cSRichard Henderson tcg_temp_free_i64(reth); 90334b1a49cSRichard Henderson } 90434b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64 9052bece2c8SRichard Henderson for (i = 0; i < nargs; ++i) { 9062bece2c8SRichard Henderson int is_64bit = sizemask & (1 << (i+1)*2); 9072bece2c8SRichard Henderson if (!is_64bit) { 9082bece2c8SRichard Henderson TCGv_i64 temp = MAKE_TCGV_I64(args[i]); 9092bece2c8SRichard Henderson tcg_temp_free_i64(temp); 9102bece2c8SRichard Henderson } 9112bece2c8SRichard Henderson } 9122bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */ 913a7812ae4Spbrook } 914c896fe29Sbellard 9158fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s) 916c896fe29Sbellard { 917c896fe29Sbellard int i; 918c896fe29Sbellard TCGTemp *ts; 919c896fe29Sbellard for(i = 0; i < s->nb_globals; i++) { 920c896fe29Sbellard ts = &s->temps[i]; 921c896fe29Sbellard if (ts->fixed_reg) { 922c896fe29Sbellard ts->val_type = TEMP_VAL_REG; 923c896fe29Sbellard } else { 924c896fe29Sbellard ts->val_type = TEMP_VAL_MEM; 925c896fe29Sbellard } 926c896fe29Sbellard } 927e8996ee0Sbellard for(i = s->nb_globals; i < s->nb_temps; i++) { 928e8996ee0Sbellard ts = &s->temps[i]; 9297dfd8c6aSAurelien Jarno if (ts->temp_local) { 9307dfd8c6aSAurelien Jarno ts->val_type = TEMP_VAL_MEM; 9317dfd8c6aSAurelien Jarno } else { 932e8996ee0Sbellard ts->val_type = TEMP_VAL_DEAD; 9337dfd8c6aSAurelien Jarno } 934e8996ee0Sbellard ts->mem_allocated = 0; 935e8996ee0Sbellard ts->fixed_reg = 0; 936e8996ee0Sbellard } 937f8b2f202SRichard Henderson 938f8b2f202SRichard Henderson memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp)); 939c896fe29Sbellard } 940c896fe29Sbellard 941f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size, 942f8b2f202SRichard Henderson TCGTemp *ts) 943c896fe29Sbellard { 944f8b2f202SRichard Henderson int idx = temp_idx(s, ts); 945ac56dd48Spbrook 946ac56dd48Spbrook if (idx < s->nb_globals) { 947ac56dd48Spbrook pstrcpy(buf, buf_size, ts->name); 948f8b2f202SRichard Henderson } else if (ts->temp_local) { 949641d5fbeSbellard snprintf(buf, buf_size, "loc%d", idx - s->nb_globals); 950f8b2f202SRichard Henderson } else { 951ac56dd48Spbrook snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals); 952c896fe29Sbellard } 953c896fe29Sbellard return buf; 954c896fe29Sbellard } 955c896fe29Sbellard 956f8b2f202SRichard Henderson static char *tcg_get_arg_str_idx(TCGContext *s, char *buf, 957f8b2f202SRichard Henderson int buf_size, int idx) 958f8b2f202SRichard Henderson { 959eabb7b91SAurelien Jarno tcg_debug_assert(idx >= 0 && idx < s->nb_temps); 960f8b2f202SRichard Henderson return tcg_get_arg_str_ptr(s, buf, buf_size, &s->temps[idx]); 961f8b2f202SRichard Henderson } 962f8b2f202SRichard Henderson 9636e085f72SRichard Henderson /* Find helper name. */ 9646e085f72SRichard Henderson static inline const char *tcg_find_helper(TCGContext *s, uintptr_t val) 965e8996ee0Sbellard { 9666e085f72SRichard Henderson const char *ret = NULL; 9676e085f72SRichard Henderson if (s->helpers) { 96872866e82SRichard Henderson TCGHelperInfo *info = g_hash_table_lookup(s->helpers, (gpointer)val); 96972866e82SRichard Henderson if (info) { 97072866e82SRichard Henderson ret = info->name; 97172866e82SRichard Henderson } 972e8996ee0Sbellard } 9736e085f72SRichard Henderson return ret; 9744dc81f28Sbellard } 9754dc81f28Sbellard 976f48f3edeSblueswir1 static const char * const cond_name[] = 977f48f3edeSblueswir1 { 9780aed257fSRichard Henderson [TCG_COND_NEVER] = "never", 9790aed257fSRichard Henderson [TCG_COND_ALWAYS] = "always", 980f48f3edeSblueswir1 [TCG_COND_EQ] = "eq", 981f48f3edeSblueswir1 [TCG_COND_NE] = "ne", 982f48f3edeSblueswir1 [TCG_COND_LT] = "lt", 983f48f3edeSblueswir1 [TCG_COND_GE] = "ge", 984f48f3edeSblueswir1 [TCG_COND_LE] = "le", 985f48f3edeSblueswir1 [TCG_COND_GT] = "gt", 986f48f3edeSblueswir1 [TCG_COND_LTU] = "ltu", 987f48f3edeSblueswir1 [TCG_COND_GEU] = "geu", 988f48f3edeSblueswir1 [TCG_COND_LEU] = "leu", 989f48f3edeSblueswir1 [TCG_COND_GTU] = "gtu" 990f48f3edeSblueswir1 }; 991f48f3edeSblueswir1 992f713d6adSRichard Henderson static const char * const ldst_name[] = 993f713d6adSRichard Henderson { 994f713d6adSRichard Henderson [MO_UB] = "ub", 995f713d6adSRichard Henderson [MO_SB] = "sb", 996f713d6adSRichard Henderson [MO_LEUW] = "leuw", 997f713d6adSRichard Henderson [MO_LESW] = "lesw", 998f713d6adSRichard Henderson [MO_LEUL] = "leul", 999f713d6adSRichard Henderson [MO_LESL] = "lesl", 1000f713d6adSRichard Henderson [MO_LEQ] = "leq", 1001f713d6adSRichard Henderson [MO_BEUW] = "beuw", 1002f713d6adSRichard Henderson [MO_BESW] = "besw", 1003f713d6adSRichard Henderson [MO_BEUL] = "beul", 1004f713d6adSRichard Henderson [MO_BESL] = "besl", 1005f713d6adSRichard Henderson [MO_BEQ] = "beq", 1006f713d6adSRichard Henderson }; 1007f713d6adSRichard Henderson 10081f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = { 10091f00b27fSSergey Sorokin #ifdef ALIGNED_ONLY 10101f00b27fSSergey Sorokin [MO_UNALN >> MO_ASHIFT] = "un+", 10111f00b27fSSergey Sorokin [MO_ALIGN >> MO_ASHIFT] = "", 10121f00b27fSSergey Sorokin #else 10131f00b27fSSergey Sorokin [MO_UNALN >> MO_ASHIFT] = "", 10141f00b27fSSergey Sorokin [MO_ALIGN >> MO_ASHIFT] = "al+", 10151f00b27fSSergey Sorokin #endif 10161f00b27fSSergey Sorokin [MO_ALIGN_2 >> MO_ASHIFT] = "al2+", 10171f00b27fSSergey Sorokin [MO_ALIGN_4 >> MO_ASHIFT] = "al4+", 10181f00b27fSSergey Sorokin [MO_ALIGN_8 >> MO_ASHIFT] = "al8+", 10191f00b27fSSergey Sorokin [MO_ALIGN_16 >> MO_ASHIFT] = "al16+", 10201f00b27fSSergey Sorokin [MO_ALIGN_32 >> MO_ASHIFT] = "al32+", 10211f00b27fSSergey Sorokin [MO_ALIGN_64 >> MO_ASHIFT] = "al64+", 10221f00b27fSSergey Sorokin }; 10231f00b27fSSergey Sorokin 1024eeacee4dSBlue Swirl void tcg_dump_ops(TCGContext *s) 1025c896fe29Sbellard { 1026c896fe29Sbellard char buf[128]; 1027c45cb8bbSRichard Henderson TCGOp *op; 1028c45cb8bbSRichard Henderson int oi; 1029c896fe29Sbellard 1030dcb8e758SRichard Henderson for (oi = s->gen_op_buf[0].next; oi != 0; oi = op->next) { 1031c45cb8bbSRichard Henderson int i, k, nb_oargs, nb_iargs, nb_cargs; 1032c45cb8bbSRichard Henderson const TCGOpDef *def; 1033c45cb8bbSRichard Henderson const TCGArg *args; 1034c45cb8bbSRichard Henderson TCGOpcode c; 1035bdfb460eSRichard Henderson int col = 0; 1036c45cb8bbSRichard Henderson 1037c45cb8bbSRichard Henderson op = &s->gen_op_buf[oi]; 1038c45cb8bbSRichard Henderson c = op->opc; 1039c896fe29Sbellard def = &tcg_op_defs[c]; 1040c45cb8bbSRichard Henderson args = &s->gen_opparam_buf[op->args]; 1041c45cb8bbSRichard Henderson 1042765b842aSRichard Henderson if (c == INDEX_op_insn_start) { 1043bdfb460eSRichard Henderson col += qemu_log("%s ----", oi != s->gen_op_buf[0].next ? "\n" : ""); 10449aef40edSRichard Henderson 10459aef40edSRichard Henderson for (i = 0; i < TARGET_INSN_START_WORDS; ++i) { 10469aef40edSRichard Henderson target_ulong a; 10477e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS 10489aef40edSRichard Henderson a = ((target_ulong)args[i * 2 + 1] << 32) | args[i * 2]; 10497e4597d7Sbellard #else 10509aef40edSRichard Henderson a = args[i]; 10517e4597d7Sbellard #endif 1052bdfb460eSRichard Henderson col += qemu_log(" " TARGET_FMT_lx, a); 1053eeacee4dSBlue Swirl } 10547e4597d7Sbellard } else if (c == INDEX_op_call) { 1055c896fe29Sbellard /* variable number of arguments */ 1056c45cb8bbSRichard Henderson nb_oargs = op->callo; 1057c45cb8bbSRichard Henderson nb_iargs = op->calli; 1058c896fe29Sbellard nb_cargs = def->nb_cargs; 1059b03cce8eSbellard 1060cf066674SRichard Henderson /* function name, flags, out args */ 1061bdfb460eSRichard Henderson col += qemu_log(" %s %s,$0x%" TCG_PRIlx ",$%d", def->name, 1062cf066674SRichard Henderson tcg_find_helper(s, args[nb_oargs + nb_iargs]), 1063cf066674SRichard Henderson args[nb_oargs + nb_iargs + 1], nb_oargs); 1064b03cce8eSbellard for (i = 0; i < nb_oargs; i++) { 1065bdfb460eSRichard Henderson col += qemu_log(",%s", tcg_get_arg_str_idx(s, buf, sizeof(buf), 1066eeacee4dSBlue Swirl args[i])); 1067b03cce8eSbellard } 1068cf066674SRichard Henderson for (i = 0; i < nb_iargs; i++) { 1069cf066674SRichard Henderson TCGArg arg = args[nb_oargs + i]; 1070cf066674SRichard Henderson const char *t = "<dummy>"; 1071cf066674SRichard Henderson if (arg != TCG_CALL_DUMMY_ARG) { 1072cf066674SRichard Henderson t = tcg_get_arg_str_idx(s, buf, sizeof(buf), arg); 1073b03cce8eSbellard } 1074bdfb460eSRichard Henderson col += qemu_log(",%s", t); 1075e8996ee0Sbellard } 1076b03cce8eSbellard } else { 1077bdfb460eSRichard Henderson col += qemu_log(" %s ", def->name); 1078c45cb8bbSRichard Henderson 1079c896fe29Sbellard nb_oargs = def->nb_oargs; 1080c896fe29Sbellard nb_iargs = def->nb_iargs; 1081c896fe29Sbellard nb_cargs = def->nb_cargs; 1082c896fe29Sbellard 1083c896fe29Sbellard k = 0; 1084c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 1085eeacee4dSBlue Swirl if (k != 0) { 1086bdfb460eSRichard Henderson col += qemu_log(","); 1087eeacee4dSBlue Swirl } 1088bdfb460eSRichard Henderson col += qemu_log("%s", tcg_get_arg_str_idx(s, buf, sizeof(buf), 1089eeacee4dSBlue Swirl args[k++])); 1090c896fe29Sbellard } 1091c896fe29Sbellard for (i = 0; i < nb_iargs; i++) { 1092eeacee4dSBlue Swirl if (k != 0) { 1093bdfb460eSRichard Henderson col += qemu_log(","); 1094eeacee4dSBlue Swirl } 1095bdfb460eSRichard Henderson col += qemu_log("%s", tcg_get_arg_str_idx(s, buf, sizeof(buf), 1096eeacee4dSBlue Swirl args[k++])); 1097c896fe29Sbellard } 1098be210acbSRichard Henderson switch (c) { 1099be210acbSRichard Henderson case INDEX_op_brcond_i32: 1100ffc5ea09SRichard Henderson case INDEX_op_setcond_i32: 1101ffc5ea09SRichard Henderson case INDEX_op_movcond_i32: 1102be210acbSRichard Henderson case INDEX_op_brcond2_i32: 1103be210acbSRichard Henderson case INDEX_op_setcond2_i32: 1104ffc5ea09SRichard Henderson case INDEX_op_brcond_i64: 1105be210acbSRichard Henderson case INDEX_op_setcond_i64: 1106ffc5ea09SRichard Henderson case INDEX_op_movcond_i64: 1107eeacee4dSBlue Swirl if (args[k] < ARRAY_SIZE(cond_name) && cond_name[args[k]]) { 1108bdfb460eSRichard Henderson col += qemu_log(",%s", cond_name[args[k++]]); 1109eeacee4dSBlue Swirl } else { 1110bdfb460eSRichard Henderson col += qemu_log(",$0x%" TCG_PRIlx, args[k++]); 1111eeacee4dSBlue Swirl } 1112f48f3edeSblueswir1 i = 1; 1113be210acbSRichard Henderson break; 1114f713d6adSRichard Henderson case INDEX_op_qemu_ld_i32: 1115f713d6adSRichard Henderson case INDEX_op_qemu_st_i32: 1116f713d6adSRichard Henderson case INDEX_op_qemu_ld_i64: 1117f713d6adSRichard Henderson case INDEX_op_qemu_st_i64: 111859227d5dSRichard Henderson { 111959227d5dSRichard Henderson TCGMemOpIdx oi = args[k++]; 112059227d5dSRichard Henderson TCGMemOp op = get_memop(oi); 112159227d5dSRichard Henderson unsigned ix = get_mmuidx(oi); 112259227d5dSRichard Henderson 112359c4b7e8SRichard Henderson if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) { 1124bdfb460eSRichard Henderson col += qemu_log(",$0x%x,%u", op, ix); 112559c4b7e8SRichard Henderson } else { 11261f00b27fSSergey Sorokin const char *s_al, *s_op; 11271f00b27fSSergey Sorokin s_al = alignment_name[(op & MO_AMASK) >> MO_ASHIFT]; 112859c4b7e8SRichard Henderson s_op = ldst_name[op & (MO_BSWAP | MO_SSIZE)]; 1129bdfb460eSRichard Henderson col += qemu_log(",%s%s,%u", s_al, s_op, ix); 1130f713d6adSRichard Henderson } 1131f713d6adSRichard Henderson i = 1; 113259227d5dSRichard Henderson } 1133f713d6adSRichard Henderson break; 1134be210acbSRichard Henderson default: 1135f48f3edeSblueswir1 i = 0; 1136be210acbSRichard Henderson break; 1137be210acbSRichard Henderson } 113851e3972cSRichard Henderson switch (c) { 113951e3972cSRichard Henderson case INDEX_op_set_label: 114051e3972cSRichard Henderson case INDEX_op_br: 114151e3972cSRichard Henderson case INDEX_op_brcond_i32: 114251e3972cSRichard Henderson case INDEX_op_brcond_i64: 114351e3972cSRichard Henderson case INDEX_op_brcond2_i32: 1144bdfb460eSRichard Henderson col += qemu_log("%s$L%d", k ? "," : "", arg_label(args[k])->id); 114551e3972cSRichard Henderson i++, k++; 114651e3972cSRichard Henderson break; 114751e3972cSRichard Henderson default: 114851e3972cSRichard Henderson break; 1149eeacee4dSBlue Swirl } 115051e3972cSRichard Henderson for (; i < nb_cargs; i++, k++) { 1151bdfb460eSRichard Henderson col += qemu_log("%s$0x%" TCG_PRIlx, k ? "," : "", args[k]); 1152bdfb460eSRichard Henderson } 1153bdfb460eSRichard Henderson } 1154bdfb460eSRichard Henderson if (op->life) { 1155bdfb460eSRichard Henderson unsigned life = op->life; 1156bdfb460eSRichard Henderson 1157bdfb460eSRichard Henderson for (; col < 48; ++col) { 1158bdfb460eSRichard Henderson putc(' ', qemu_logfile); 1159bdfb460eSRichard Henderson } 1160bdfb460eSRichard Henderson 1161bdfb460eSRichard Henderson if (life & (SYNC_ARG * 3)) { 1162bdfb460eSRichard Henderson qemu_log(" sync:"); 1163bdfb460eSRichard Henderson for (i = 0; i < 2; ++i) { 1164bdfb460eSRichard Henderson if (life & (SYNC_ARG << i)) { 1165bdfb460eSRichard Henderson qemu_log(" %d", i); 1166bdfb460eSRichard Henderson } 1167bdfb460eSRichard Henderson } 1168bdfb460eSRichard Henderson } 1169bdfb460eSRichard Henderson life /= DEAD_ARG; 1170bdfb460eSRichard Henderson if (life) { 1171bdfb460eSRichard Henderson qemu_log(" dead:"); 1172bdfb460eSRichard Henderson for (i = 0; life; ++i, life >>= 1) { 1173bdfb460eSRichard Henderson if (life & 1) { 1174bdfb460eSRichard Henderson qemu_log(" %d", i); 1175bdfb460eSRichard Henderson } 1176bdfb460eSRichard Henderson } 1177c896fe29Sbellard } 1178b03cce8eSbellard } 1179eeacee4dSBlue Swirl qemu_log("\n"); 1180c896fe29Sbellard } 1181c896fe29Sbellard } 1182c896fe29Sbellard 1183c896fe29Sbellard /* we give more priority to constraints with less registers */ 1184c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k) 1185c896fe29Sbellard { 1186c896fe29Sbellard const TCGArgConstraint *arg_ct; 1187c896fe29Sbellard 1188c896fe29Sbellard int i, n; 1189c896fe29Sbellard arg_ct = &def->args_ct[k]; 1190c896fe29Sbellard if (arg_ct->ct & TCG_CT_ALIAS) { 1191c896fe29Sbellard /* an alias is equivalent to a single register */ 1192c896fe29Sbellard n = 1; 1193c896fe29Sbellard } else { 1194c896fe29Sbellard if (!(arg_ct->ct & TCG_CT_REG)) 1195c896fe29Sbellard return 0; 1196c896fe29Sbellard n = 0; 1197c896fe29Sbellard for(i = 0; i < TCG_TARGET_NB_REGS; i++) { 1198c896fe29Sbellard if (tcg_regset_test_reg(arg_ct->u.regs, i)) 1199c896fe29Sbellard n++; 1200c896fe29Sbellard } 1201c896fe29Sbellard } 1202c896fe29Sbellard return TCG_TARGET_NB_REGS - n + 1; 1203c896fe29Sbellard } 1204c896fe29Sbellard 1205c896fe29Sbellard /* sort from highest priority to lowest */ 1206c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n) 1207c896fe29Sbellard { 1208c896fe29Sbellard int i, j, p1, p2, tmp; 1209c896fe29Sbellard 1210c896fe29Sbellard for(i = 0; i < n; i++) 1211c896fe29Sbellard def->sorted_args[start + i] = start + i; 1212c896fe29Sbellard if (n <= 1) 1213c896fe29Sbellard return; 1214c896fe29Sbellard for(i = 0; i < n - 1; i++) { 1215c896fe29Sbellard for(j = i + 1; j < n; j++) { 1216c896fe29Sbellard p1 = get_constraint_priority(def, def->sorted_args[start + i]); 1217c896fe29Sbellard p2 = get_constraint_priority(def, def->sorted_args[start + j]); 1218c896fe29Sbellard if (p1 < p2) { 1219c896fe29Sbellard tmp = def->sorted_args[start + i]; 1220c896fe29Sbellard def->sorted_args[start + i] = def->sorted_args[start + j]; 1221c896fe29Sbellard def->sorted_args[start + j] = tmp; 1222c896fe29Sbellard } 1223c896fe29Sbellard } 1224c896fe29Sbellard } 1225c896fe29Sbellard } 1226c896fe29Sbellard 1227*f69d277eSRichard Henderson static void process_op_defs(TCGContext *s) 1228c896fe29Sbellard { 1229a9751609SRichard Henderson TCGOpcode op; 1230c896fe29Sbellard 1231*f69d277eSRichard Henderson for (op = 0; op < NB_OPS; op++) { 1232*f69d277eSRichard Henderson TCGOpDef *def = &tcg_op_defs[op]; 1233*f69d277eSRichard Henderson const TCGTargetOpDef *tdefs; 1234*f69d277eSRichard Henderson int i, nb_args, ok; 1235*f69d277eSRichard Henderson 1236*f69d277eSRichard Henderson if (def->flags & TCG_OPF_NOT_PRESENT) { 1237*f69d277eSRichard Henderson continue; 1238*f69d277eSRichard Henderson } 1239*f69d277eSRichard Henderson 1240c896fe29Sbellard nb_args = def->nb_iargs + def->nb_oargs; 1241*f69d277eSRichard Henderson if (nb_args == 0) { 1242*f69d277eSRichard Henderson continue; 1243*f69d277eSRichard Henderson } 1244*f69d277eSRichard Henderson 1245*f69d277eSRichard Henderson tdefs = tcg_target_op_def(op); 1246*f69d277eSRichard Henderson /* Missing TCGTargetOpDef entry. */ 1247*f69d277eSRichard Henderson tcg_debug_assert(tdefs != NULL); 1248*f69d277eSRichard Henderson 1249c896fe29Sbellard for (i = 0; i < nb_args; i++) { 1250*f69d277eSRichard Henderson const char *ct_str = tdefs->args_ct_str[i]; 1251*f69d277eSRichard Henderson /* Incomplete TCGTargetOpDef entry. */ 1252eabb7b91SAurelien Jarno tcg_debug_assert(ct_str != NULL); 1253*f69d277eSRichard Henderson 1254c896fe29Sbellard tcg_regset_clear(def->args_ct[i].u.regs); 1255c896fe29Sbellard def->args_ct[i].ct = 0; 1256c896fe29Sbellard if (ct_str[0] >= '0' && ct_str[0] <= '9') { 1257c896fe29Sbellard int oarg; 1258c896fe29Sbellard oarg = ct_str[0] - '0'; 1259eabb7b91SAurelien Jarno tcg_debug_assert(oarg < def->nb_oargs); 1260eabb7b91SAurelien Jarno tcg_debug_assert(def->args_ct[oarg].ct & TCG_CT_REG); 1261c896fe29Sbellard /* TCG_CT_ALIAS is for the output arguments. The input 12625ff9d6a4Sbellard argument is tagged with TCG_CT_IALIAS. */ 1263c896fe29Sbellard def->args_ct[i] = def->args_ct[oarg]; 12645ff9d6a4Sbellard def->args_ct[oarg].ct = TCG_CT_ALIAS; 12655ff9d6a4Sbellard def->args_ct[oarg].alias_index = i; 1266c896fe29Sbellard def->args_ct[i].ct |= TCG_CT_IALIAS; 12675ff9d6a4Sbellard def->args_ct[i].alias_index = oarg; 1268c896fe29Sbellard } else { 1269c896fe29Sbellard for(;;) { 1270c896fe29Sbellard if (*ct_str == '\0') 1271c896fe29Sbellard break; 1272c896fe29Sbellard switch(*ct_str) { 127382790a87SRichard Henderson case '&': 127482790a87SRichard Henderson def->args_ct[i].ct |= TCG_CT_NEWREG; 127582790a87SRichard Henderson ct_str++; 127682790a87SRichard Henderson break; 1277c896fe29Sbellard case 'i': 1278c896fe29Sbellard def->args_ct[i].ct |= TCG_CT_CONST; 1279c896fe29Sbellard ct_str++; 1280c896fe29Sbellard break; 1281c896fe29Sbellard default: 1282*f69d277eSRichard Henderson ok = target_parse_constraint(&def->args_ct[i], &ct_str); 1283*f69d277eSRichard Henderson /* Typo in TCGTargetOpDef constraint. */ 1284*f69d277eSRichard Henderson tcg_debug_assert(ok == 0); 1285c896fe29Sbellard } 1286c896fe29Sbellard } 1287c896fe29Sbellard } 1288c896fe29Sbellard } 1289c896fe29Sbellard 1290c68aaa18SStefan Weil /* TCGTargetOpDef entry with too much information? */ 1291eabb7b91SAurelien Jarno tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL); 1292c68aaa18SStefan Weil 1293c896fe29Sbellard /* sort the constraints (XXX: this is just an heuristic) */ 1294c896fe29Sbellard sort_constraints(def, 0, def->nb_oargs); 1295c896fe29Sbellard sort_constraints(def, def->nb_oargs, def->nb_iargs); 1296c896fe29Sbellard } 1297c896fe29Sbellard } 1298c896fe29Sbellard 12990c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op) 13000c627cdcSRichard Henderson { 13010c627cdcSRichard Henderson int next = op->next; 13020c627cdcSRichard Henderson int prev = op->prev; 13030c627cdcSRichard Henderson 1304dcb8e758SRichard Henderson /* We should never attempt to remove the list terminator. */ 1305dcb8e758SRichard Henderson tcg_debug_assert(op != &s->gen_op_buf[0]); 13060c627cdcSRichard Henderson 1307dcb8e758SRichard Henderson s->gen_op_buf[next].prev = prev; 1308dcb8e758SRichard Henderson s->gen_op_buf[prev].next = next; 1309dcb8e758SRichard Henderson 1310dcb8e758SRichard Henderson memset(op, 0, sizeof(*op)); 13110c627cdcSRichard Henderson 13120c627cdcSRichard Henderson #ifdef CONFIG_PROFILER 13130c627cdcSRichard Henderson s->del_op_count++; 13140c627cdcSRichard Henderson #endif 13150c627cdcSRichard Henderson } 13160c627cdcSRichard Henderson 13175a18407fSRichard Henderson TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op, 13185a18407fSRichard Henderson TCGOpcode opc, int nargs) 13195a18407fSRichard Henderson { 13205a18407fSRichard Henderson int oi = s->gen_next_op_idx; 13215a18407fSRichard Henderson int pi = s->gen_next_parm_idx; 13225a18407fSRichard Henderson int prev = old_op->prev; 13235a18407fSRichard Henderson int next = old_op - s->gen_op_buf; 13245a18407fSRichard Henderson TCGOp *new_op; 13255a18407fSRichard Henderson 13265a18407fSRichard Henderson tcg_debug_assert(oi < OPC_BUF_SIZE); 13275a18407fSRichard Henderson tcg_debug_assert(pi + nargs <= OPPARAM_BUF_SIZE); 13285a18407fSRichard Henderson s->gen_next_op_idx = oi + 1; 13295a18407fSRichard Henderson s->gen_next_parm_idx = pi + nargs; 13305a18407fSRichard Henderson 13315a18407fSRichard Henderson new_op = &s->gen_op_buf[oi]; 13325a18407fSRichard Henderson *new_op = (TCGOp){ 13335a18407fSRichard Henderson .opc = opc, 13345a18407fSRichard Henderson .args = pi, 13355a18407fSRichard Henderson .prev = prev, 13365a18407fSRichard Henderson .next = next 13375a18407fSRichard Henderson }; 13385a18407fSRichard Henderson s->gen_op_buf[prev].next = oi; 13395a18407fSRichard Henderson old_op->prev = oi; 13405a18407fSRichard Henderson 13415a18407fSRichard Henderson return new_op; 13425a18407fSRichard Henderson } 13435a18407fSRichard Henderson 13445a18407fSRichard Henderson TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, 13455a18407fSRichard Henderson TCGOpcode opc, int nargs) 13465a18407fSRichard Henderson { 13475a18407fSRichard Henderson int oi = s->gen_next_op_idx; 13485a18407fSRichard Henderson int pi = s->gen_next_parm_idx; 13495a18407fSRichard Henderson int prev = old_op - s->gen_op_buf; 13505a18407fSRichard Henderson int next = old_op->next; 13515a18407fSRichard Henderson TCGOp *new_op; 13525a18407fSRichard Henderson 13535a18407fSRichard Henderson tcg_debug_assert(oi < OPC_BUF_SIZE); 13545a18407fSRichard Henderson tcg_debug_assert(pi + nargs <= OPPARAM_BUF_SIZE); 13555a18407fSRichard Henderson s->gen_next_op_idx = oi + 1; 13565a18407fSRichard Henderson s->gen_next_parm_idx = pi + nargs; 13575a18407fSRichard Henderson 13585a18407fSRichard Henderson new_op = &s->gen_op_buf[oi]; 13595a18407fSRichard Henderson *new_op = (TCGOp){ 13605a18407fSRichard Henderson .opc = opc, 13615a18407fSRichard Henderson .args = pi, 13625a18407fSRichard Henderson .prev = prev, 13635a18407fSRichard Henderson .next = next 13645a18407fSRichard Henderson }; 13655a18407fSRichard Henderson s->gen_op_buf[next].prev = oi; 13665a18407fSRichard Henderson old_op->next = oi; 13675a18407fSRichard Henderson 13685a18407fSRichard Henderson return new_op; 13695a18407fSRichard Henderson } 13705a18407fSRichard Henderson 1371c70fbf0aSRichard Henderson #define TS_DEAD 1 1372c70fbf0aSRichard Henderson #define TS_MEM 2 1373c70fbf0aSRichard Henderson 13745a18407fSRichard Henderson #define IS_DEAD_ARG(n) (arg_life & (DEAD_ARG << (n))) 13755a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n))) 13765a18407fSRichard Henderson 13779c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals 13789c43b68dSAurelien Jarno should be in memory. */ 1379c70fbf0aSRichard Henderson static inline void tcg_la_func_end(TCGContext *s, uint8_t *temp_state) 1380c896fe29Sbellard { 1381c70fbf0aSRichard Henderson memset(temp_state, TS_DEAD | TS_MEM, s->nb_globals); 1382c70fbf0aSRichard Henderson memset(temp_state + s->nb_globals, TS_DEAD, s->nb_temps - s->nb_globals); 1383c896fe29Sbellard } 1384c896fe29Sbellard 13859c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals 13869c43b68dSAurelien Jarno and local temps should be in memory. */ 1387c70fbf0aSRichard Henderson static inline void tcg_la_bb_end(TCGContext *s, uint8_t *temp_state) 1388641d5fbeSbellard { 1389c70fbf0aSRichard Henderson int i, n; 1390641d5fbeSbellard 1391c70fbf0aSRichard Henderson tcg_la_func_end(s, temp_state); 1392c70fbf0aSRichard Henderson for (i = s->nb_globals, n = s->nb_temps; i < n; i++) { 1393c70fbf0aSRichard Henderson if (s->temps[i].temp_local) { 1394c70fbf0aSRichard Henderson temp_state[i] |= TS_MEM; 1395c70fbf0aSRichard Henderson } 1396641d5fbeSbellard } 1397641d5fbeSbellard } 1398641d5fbeSbellard 1399a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a 1400c896fe29Sbellard given input arguments is dead. Instructions updating dead 1401c896fe29Sbellard temporaries are removed. */ 14025a18407fSRichard Henderson static void liveness_pass_1(TCGContext *s, uint8_t *temp_state) 1403c896fe29Sbellard { 1404c70fbf0aSRichard Henderson int nb_globals = s->nb_globals; 14055a18407fSRichard Henderson int oi, oi_prev; 1406c896fe29Sbellard 1407c70fbf0aSRichard Henderson tcg_la_func_end(s, temp_state); 1408c896fe29Sbellard 1409dcb8e758SRichard Henderson for (oi = s->gen_op_buf[0].prev; oi != 0; oi = oi_prev) { 1410c45cb8bbSRichard Henderson int i, nb_iargs, nb_oargs; 1411c45cb8bbSRichard Henderson TCGOpcode opc_new, opc_new2; 1412c45cb8bbSRichard Henderson bool have_opc_new2; 1413a1b3c48dSRichard Henderson TCGLifeData arg_life = 0; 1414c45cb8bbSRichard Henderson TCGArg arg; 1415c45cb8bbSRichard Henderson 1416c45cb8bbSRichard Henderson TCGOp * const op = &s->gen_op_buf[oi]; 1417c45cb8bbSRichard Henderson TCGArg * const args = &s->gen_opparam_buf[op->args]; 1418c45cb8bbSRichard Henderson TCGOpcode opc = op->opc; 1419c45cb8bbSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 1420c45cb8bbSRichard Henderson 1421c45cb8bbSRichard Henderson oi_prev = op->prev; 1422c45cb8bbSRichard Henderson 1423c45cb8bbSRichard Henderson switch (opc) { 1424c896fe29Sbellard case INDEX_op_call: 1425c6e113f5Sbellard { 1426c6e113f5Sbellard int call_flags; 1427c6e113f5Sbellard 1428c45cb8bbSRichard Henderson nb_oargs = op->callo; 1429c45cb8bbSRichard Henderson nb_iargs = op->calli; 1430cf066674SRichard Henderson call_flags = args[nb_oargs + nb_iargs + 1]; 1431c6e113f5Sbellard 1432c45cb8bbSRichard Henderson /* pure functions can be removed if their result is unused */ 143378505279SAurelien Jarno if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) { 1434c6e113f5Sbellard for (i = 0; i < nb_oargs; i++) { 1435c6e113f5Sbellard arg = args[i]; 1436c70fbf0aSRichard Henderson if (temp_state[arg] != TS_DEAD) { 1437c6e113f5Sbellard goto do_not_remove_call; 1438c6e113f5Sbellard } 14399c43b68dSAurelien Jarno } 1440c45cb8bbSRichard Henderson goto do_remove; 1441c6e113f5Sbellard } else { 1442c6e113f5Sbellard do_not_remove_call: 1443c896fe29Sbellard 1444c896fe29Sbellard /* output args are dead */ 1445c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 1446c896fe29Sbellard arg = args[i]; 1447c70fbf0aSRichard Henderson if (temp_state[arg] & TS_DEAD) { 1448a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 14496b64b624SAurelien Jarno } 1450c70fbf0aSRichard Henderson if (temp_state[arg] & TS_MEM) { 1451a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i; 14529c43b68dSAurelien Jarno } 1453c70fbf0aSRichard Henderson temp_state[arg] = TS_DEAD; 1454c896fe29Sbellard } 1455c896fe29Sbellard 145678505279SAurelien Jarno if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS | 145778505279SAurelien Jarno TCG_CALL_NO_READ_GLOBALS))) { 14589c43b68dSAurelien Jarno /* globals should go back to memory */ 1459c70fbf0aSRichard Henderson memset(temp_state, TS_DEAD | TS_MEM, nb_globals); 1460c70fbf0aSRichard Henderson } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) { 1461c70fbf0aSRichard Henderson /* globals should be synced to memory */ 1462c70fbf0aSRichard Henderson for (i = 0; i < nb_globals; i++) { 1463c70fbf0aSRichard Henderson temp_state[i] |= TS_MEM; 1464c70fbf0aSRichard Henderson } 1465b9c18f56Saurel32 } 1466c896fe29Sbellard 1467c19f47bfSAurelien Jarno /* record arguments that die in this helper */ 1468866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 1469866cb6cbSAurelien Jarno arg = args[i]; 147039cf05d3Sbellard if (arg != TCG_CALL_DUMMY_ARG) { 1471c70fbf0aSRichard Henderson if (temp_state[arg] & TS_DEAD) { 1472a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 1473c896fe29Sbellard } 1474c896fe29Sbellard } 147539cf05d3Sbellard } 147667cc32ebSVeres Lajos /* input arguments are live for preceding opcodes */ 1477c70fbf0aSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 1478c19f47bfSAurelien Jarno arg = args[i]; 1479c70fbf0aSRichard Henderson if (arg != TCG_CALL_DUMMY_ARG) { 1480c70fbf0aSRichard Henderson temp_state[arg] &= ~TS_DEAD; 1481c70fbf0aSRichard Henderson } 1482c19f47bfSAurelien Jarno } 1483c6e113f5Sbellard } 1484c6e113f5Sbellard } 1485c896fe29Sbellard break; 1486765b842aSRichard Henderson case INDEX_op_insn_start: 1487c896fe29Sbellard break; 14885ff9d6a4Sbellard case INDEX_op_discard: 14895ff9d6a4Sbellard /* mark the temporary as dead */ 1490c70fbf0aSRichard Henderson temp_state[args[0]] = TS_DEAD; 14915ff9d6a4Sbellard break; 14921305c451SRichard Henderson 14931305c451SRichard Henderson case INDEX_op_add2_i32: 1494c45cb8bbSRichard Henderson opc_new = INDEX_op_add_i32; 1495f1fae40cSRichard Henderson goto do_addsub2; 14961305c451SRichard Henderson case INDEX_op_sub2_i32: 1497c45cb8bbSRichard Henderson opc_new = INDEX_op_sub_i32; 1498f1fae40cSRichard Henderson goto do_addsub2; 1499f1fae40cSRichard Henderson case INDEX_op_add2_i64: 1500c45cb8bbSRichard Henderson opc_new = INDEX_op_add_i64; 1501f1fae40cSRichard Henderson goto do_addsub2; 1502f1fae40cSRichard Henderson case INDEX_op_sub2_i64: 1503c45cb8bbSRichard Henderson opc_new = INDEX_op_sub_i64; 1504f1fae40cSRichard Henderson do_addsub2: 15051305c451SRichard Henderson nb_iargs = 4; 15061305c451SRichard Henderson nb_oargs = 2; 15071305c451SRichard Henderson /* Test if the high part of the operation is dead, but not 15081305c451SRichard Henderson the low part. The result can be optimized to a simple 15091305c451SRichard Henderson add or sub. This happens often for x86_64 guest when the 15101305c451SRichard Henderson cpu mode is set to 32 bit. */ 1511c70fbf0aSRichard Henderson if (temp_state[args[1]] == TS_DEAD) { 1512c70fbf0aSRichard Henderson if (temp_state[args[0]] == TS_DEAD) { 15131305c451SRichard Henderson goto do_remove; 15141305c451SRichard Henderson } 1515c45cb8bbSRichard Henderson /* Replace the opcode and adjust the args in place, 1516c45cb8bbSRichard Henderson leaving 3 unused args at the end. */ 1517c45cb8bbSRichard Henderson op->opc = opc = opc_new; 15181305c451SRichard Henderson args[1] = args[2]; 15191305c451SRichard Henderson args[2] = args[4]; 15201305c451SRichard Henderson /* Fall through and mark the single-word operation live. */ 15211305c451SRichard Henderson nb_iargs = 2; 15221305c451SRichard Henderson nb_oargs = 1; 15231305c451SRichard Henderson } 15241305c451SRichard Henderson goto do_not_remove; 15251305c451SRichard Henderson 15261414968aSRichard Henderson case INDEX_op_mulu2_i32: 1527c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i32; 1528c45cb8bbSRichard Henderson opc_new2 = INDEX_op_muluh_i32; 1529c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_muluh_i32; 153003271524SRichard Henderson goto do_mul2; 1531f1fae40cSRichard Henderson case INDEX_op_muls2_i32: 1532c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i32; 1533c45cb8bbSRichard Henderson opc_new2 = INDEX_op_mulsh_i32; 1534c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_mulsh_i32; 1535f1fae40cSRichard Henderson goto do_mul2; 1536f1fae40cSRichard Henderson case INDEX_op_mulu2_i64: 1537c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i64; 1538c45cb8bbSRichard Henderson opc_new2 = INDEX_op_muluh_i64; 1539c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_muluh_i64; 154003271524SRichard Henderson goto do_mul2; 1541f1fae40cSRichard Henderson case INDEX_op_muls2_i64: 1542c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i64; 1543c45cb8bbSRichard Henderson opc_new2 = INDEX_op_mulsh_i64; 1544c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_mulsh_i64; 154503271524SRichard Henderson goto do_mul2; 1546f1fae40cSRichard Henderson do_mul2: 15471414968aSRichard Henderson nb_iargs = 2; 15481414968aSRichard Henderson nb_oargs = 2; 1549c70fbf0aSRichard Henderson if (temp_state[args[1]] == TS_DEAD) { 1550c70fbf0aSRichard Henderson if (temp_state[args[0]] == TS_DEAD) { 155103271524SRichard Henderson /* Both parts of the operation are dead. */ 15521414968aSRichard Henderson goto do_remove; 15531414968aSRichard Henderson } 155403271524SRichard Henderson /* The high part of the operation is dead; generate the low. */ 1555c45cb8bbSRichard Henderson op->opc = opc = opc_new; 15561414968aSRichard Henderson args[1] = args[2]; 15571414968aSRichard Henderson args[2] = args[3]; 1558c70fbf0aSRichard Henderson } else if (temp_state[args[0]] == TS_DEAD && have_opc_new2) { 155903271524SRichard Henderson /* The low part of the operation is dead; generate the high. */ 1560c45cb8bbSRichard Henderson op->opc = opc = opc_new2; 156103271524SRichard Henderson args[0] = args[1]; 156203271524SRichard Henderson args[1] = args[2]; 156303271524SRichard Henderson args[2] = args[3]; 156403271524SRichard Henderson } else { 156503271524SRichard Henderson goto do_not_remove; 156603271524SRichard Henderson } 156703271524SRichard Henderson /* Mark the single-word operation live. */ 15681414968aSRichard Henderson nb_oargs = 1; 15691414968aSRichard Henderson goto do_not_remove; 15701414968aSRichard Henderson 1571c896fe29Sbellard default: 15721305c451SRichard Henderson /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */ 1573c896fe29Sbellard nb_iargs = def->nb_iargs; 1574c896fe29Sbellard nb_oargs = def->nb_oargs; 1575c896fe29Sbellard 1576c896fe29Sbellard /* Test if the operation can be removed because all 15775ff9d6a4Sbellard its outputs are dead. We assume that nb_oargs == 0 15785ff9d6a4Sbellard implies side effects */ 15795ff9d6a4Sbellard if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) { 1580c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 1581c70fbf0aSRichard Henderson if (temp_state[args[i]] != TS_DEAD) { 1582c896fe29Sbellard goto do_not_remove; 1583c896fe29Sbellard } 15849c43b68dSAurelien Jarno } 15851305c451SRichard Henderson do_remove: 15860c627cdcSRichard Henderson tcg_op_remove(s, op); 1587c896fe29Sbellard } else { 1588c896fe29Sbellard do_not_remove: 1589c896fe29Sbellard /* output args are dead */ 1590c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 1591c896fe29Sbellard arg = args[i]; 1592c70fbf0aSRichard Henderson if (temp_state[arg] & TS_DEAD) { 1593a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 15946b64b624SAurelien Jarno } 1595c70fbf0aSRichard Henderson if (temp_state[arg] & TS_MEM) { 1596a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i; 15979c43b68dSAurelien Jarno } 1598c70fbf0aSRichard Henderson temp_state[arg] = TS_DEAD; 1599c896fe29Sbellard } 1600c896fe29Sbellard 1601c896fe29Sbellard /* if end of basic block, update */ 1602c896fe29Sbellard if (def->flags & TCG_OPF_BB_END) { 1603c70fbf0aSRichard Henderson tcg_la_bb_end(s, temp_state); 16043d5c5f87SAurelien Jarno } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { 16053d5c5f87SAurelien Jarno /* globals should be synced to memory */ 1606c70fbf0aSRichard Henderson for (i = 0; i < nb_globals; i++) { 1607c70fbf0aSRichard Henderson temp_state[i] |= TS_MEM; 1608c70fbf0aSRichard Henderson } 1609c896fe29Sbellard } 1610c896fe29Sbellard 1611c19f47bfSAurelien Jarno /* record arguments that die in this opcode */ 1612866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 1613866cb6cbSAurelien Jarno arg = args[i]; 1614c70fbf0aSRichard Henderson if (temp_state[arg] & TS_DEAD) { 1615a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 1616c896fe29Sbellard } 1617c19f47bfSAurelien Jarno } 161867cc32ebSVeres Lajos /* input arguments are live for preceding opcodes */ 1619c19f47bfSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 1620c70fbf0aSRichard Henderson temp_state[args[i]] &= ~TS_DEAD; 1621c896fe29Sbellard } 1622c896fe29Sbellard } 1623c896fe29Sbellard break; 1624c896fe29Sbellard } 1625bee158cbSRichard Henderson op->life = arg_life; 1626c896fe29Sbellard } 16271ff0a2c5SEvgeny Voevodin } 1628c896fe29Sbellard 16295a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries. */ 16305a18407fSRichard Henderson static bool liveness_pass_2(TCGContext *s, uint8_t *temp_state) 16315a18407fSRichard Henderson { 16325a18407fSRichard Henderson int nb_globals = s->nb_globals; 16335a18407fSRichard Henderson int16_t *dir_temps; 16345a18407fSRichard Henderson int i, oi, oi_next; 16355a18407fSRichard Henderson bool changes = false; 16365a18407fSRichard Henderson 16375a18407fSRichard Henderson dir_temps = tcg_malloc(nb_globals * sizeof(int16_t)); 16385a18407fSRichard Henderson memset(dir_temps, 0, nb_globals * sizeof(int16_t)); 16395a18407fSRichard Henderson 16405a18407fSRichard Henderson /* Create a temporary for each indirect global. */ 16415a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 16425a18407fSRichard Henderson TCGTemp *its = &s->temps[i]; 16435a18407fSRichard Henderson if (its->indirect_reg) { 16445a18407fSRichard Henderson TCGTemp *dts = tcg_temp_alloc(s); 16455a18407fSRichard Henderson dts->type = its->type; 16465a18407fSRichard Henderson dts->base_type = its->base_type; 16475a18407fSRichard Henderson dir_temps[i] = temp_idx(s, dts); 16485a18407fSRichard Henderson } 16495a18407fSRichard Henderson } 16505a18407fSRichard Henderson 16515a18407fSRichard Henderson memset(temp_state, TS_DEAD, nb_globals); 16525a18407fSRichard Henderson 16535a18407fSRichard Henderson for (oi = s->gen_op_buf[0].next; oi != 0; oi = oi_next) { 16545a18407fSRichard Henderson TCGOp *op = &s->gen_op_buf[oi]; 16555a18407fSRichard Henderson TCGArg *args = &s->gen_opparam_buf[op->args]; 16565a18407fSRichard Henderson TCGOpcode opc = op->opc; 16575a18407fSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 16585a18407fSRichard Henderson TCGLifeData arg_life = op->life; 16595a18407fSRichard Henderson int nb_iargs, nb_oargs, call_flags; 16605a18407fSRichard Henderson TCGArg arg, dir; 16615a18407fSRichard Henderson 16625a18407fSRichard Henderson oi_next = op->next; 16635a18407fSRichard Henderson 16645a18407fSRichard Henderson if (opc == INDEX_op_call) { 16655a18407fSRichard Henderson nb_oargs = op->callo; 16665a18407fSRichard Henderson nb_iargs = op->calli; 16675a18407fSRichard Henderson call_flags = args[nb_oargs + nb_iargs + 1]; 16685a18407fSRichard Henderson } else { 16695a18407fSRichard Henderson nb_iargs = def->nb_iargs; 16705a18407fSRichard Henderson nb_oargs = def->nb_oargs; 16715a18407fSRichard Henderson 16725a18407fSRichard Henderson /* Set flags similar to how calls require. */ 16735a18407fSRichard Henderson if (def->flags & TCG_OPF_BB_END) { 16745a18407fSRichard Henderson /* Like writing globals: save_globals */ 16755a18407fSRichard Henderson call_flags = 0; 16765a18407fSRichard Henderson } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { 16775a18407fSRichard Henderson /* Like reading globals: sync_globals */ 16785a18407fSRichard Henderson call_flags = TCG_CALL_NO_WRITE_GLOBALS; 16795a18407fSRichard Henderson } else { 16805a18407fSRichard Henderson /* No effect on globals. */ 16815a18407fSRichard Henderson call_flags = (TCG_CALL_NO_READ_GLOBALS | 16825a18407fSRichard Henderson TCG_CALL_NO_WRITE_GLOBALS); 16835a18407fSRichard Henderson } 16845a18407fSRichard Henderson } 16855a18407fSRichard Henderson 16865a18407fSRichard Henderson /* Make sure that input arguments are available. */ 16875a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 16885a18407fSRichard Henderson arg = args[i]; 16895a18407fSRichard Henderson /* Note this unsigned test catches TCG_CALL_ARG_DUMMY too. */ 16905a18407fSRichard Henderson if (arg < nb_globals) { 16915a18407fSRichard Henderson dir = dir_temps[arg]; 16925a18407fSRichard Henderson if (dir != 0 && temp_state[arg] == TS_DEAD) { 16935a18407fSRichard Henderson TCGTemp *its = &s->temps[arg]; 16945a18407fSRichard Henderson TCGOpcode lopc = (its->type == TCG_TYPE_I32 16955a18407fSRichard Henderson ? INDEX_op_ld_i32 16965a18407fSRichard Henderson : INDEX_op_ld_i64); 16975a18407fSRichard Henderson TCGOp *lop = tcg_op_insert_before(s, op, lopc, 3); 16985a18407fSRichard Henderson TCGArg *largs = &s->gen_opparam_buf[lop->args]; 16995a18407fSRichard Henderson 17005a18407fSRichard Henderson largs[0] = dir; 17015a18407fSRichard Henderson largs[1] = temp_idx(s, its->mem_base); 17025a18407fSRichard Henderson largs[2] = its->mem_offset; 17035a18407fSRichard Henderson 17045a18407fSRichard Henderson /* Loaded, but synced with memory. */ 17055a18407fSRichard Henderson temp_state[arg] = TS_MEM; 17065a18407fSRichard Henderson } 17075a18407fSRichard Henderson } 17085a18407fSRichard Henderson } 17095a18407fSRichard Henderson 17105a18407fSRichard Henderson /* Perform input replacement, and mark inputs that became dead. 17115a18407fSRichard Henderson No action is required except keeping temp_state up to date 17125a18407fSRichard Henderson so that we reload when needed. */ 17135a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 17145a18407fSRichard Henderson arg = args[i]; 17155a18407fSRichard Henderson if (arg < nb_globals) { 17165a18407fSRichard Henderson dir = dir_temps[arg]; 17175a18407fSRichard Henderson if (dir != 0) { 17185a18407fSRichard Henderson args[i] = dir; 17195a18407fSRichard Henderson changes = true; 17205a18407fSRichard Henderson if (IS_DEAD_ARG(i)) { 17215a18407fSRichard Henderson temp_state[arg] = TS_DEAD; 17225a18407fSRichard Henderson } 17235a18407fSRichard Henderson } 17245a18407fSRichard Henderson } 17255a18407fSRichard Henderson } 17265a18407fSRichard Henderson 17275a18407fSRichard Henderson /* Liveness analysis should ensure that the following are 17285a18407fSRichard Henderson all correct, for call sites and basic block end points. */ 17295a18407fSRichard Henderson if (call_flags & TCG_CALL_NO_READ_GLOBALS) { 17305a18407fSRichard Henderson /* Nothing to do */ 17315a18407fSRichard Henderson } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) { 17325a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 17335a18407fSRichard Henderson /* Liveness should see that globals are synced back, 17345a18407fSRichard Henderson that is, either TS_DEAD or TS_MEM. */ 17355a18407fSRichard Henderson tcg_debug_assert(dir_temps[i] == 0 17365a18407fSRichard Henderson || temp_state[i] != 0); 17375a18407fSRichard Henderson } 17385a18407fSRichard Henderson } else { 17395a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 17405a18407fSRichard Henderson /* Liveness should see that globals are saved back, 17415a18407fSRichard Henderson that is, TS_DEAD, waiting to be reloaded. */ 17425a18407fSRichard Henderson tcg_debug_assert(dir_temps[i] == 0 17435a18407fSRichard Henderson || temp_state[i] == TS_DEAD); 17445a18407fSRichard Henderson } 17455a18407fSRichard Henderson } 17465a18407fSRichard Henderson 17475a18407fSRichard Henderson /* Outputs become available. */ 17485a18407fSRichard Henderson for (i = 0; i < nb_oargs; i++) { 17495a18407fSRichard Henderson arg = args[i]; 17505a18407fSRichard Henderson if (arg >= nb_globals) { 17515a18407fSRichard Henderson continue; 17525a18407fSRichard Henderson } 17535a18407fSRichard Henderson dir = dir_temps[arg]; 17545a18407fSRichard Henderson if (dir == 0) { 17555a18407fSRichard Henderson continue; 17565a18407fSRichard Henderson } 17575a18407fSRichard Henderson args[i] = dir; 17585a18407fSRichard Henderson changes = true; 17595a18407fSRichard Henderson 17605a18407fSRichard Henderson /* The output is now live and modified. */ 17615a18407fSRichard Henderson temp_state[arg] = 0; 17625a18407fSRichard Henderson 17635a18407fSRichard Henderson /* Sync outputs upon their last write. */ 17645a18407fSRichard Henderson if (NEED_SYNC_ARG(i)) { 17655a18407fSRichard Henderson TCGTemp *its = &s->temps[arg]; 17665a18407fSRichard Henderson TCGOpcode sopc = (its->type == TCG_TYPE_I32 17675a18407fSRichard Henderson ? INDEX_op_st_i32 17685a18407fSRichard Henderson : INDEX_op_st_i64); 17695a18407fSRichard Henderson TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3); 17705a18407fSRichard Henderson TCGArg *sargs = &s->gen_opparam_buf[sop->args]; 17715a18407fSRichard Henderson 17725a18407fSRichard Henderson sargs[0] = dir; 17735a18407fSRichard Henderson sargs[1] = temp_idx(s, its->mem_base); 17745a18407fSRichard Henderson sargs[2] = its->mem_offset; 17755a18407fSRichard Henderson 17765a18407fSRichard Henderson temp_state[arg] = TS_MEM; 17775a18407fSRichard Henderson } 17785a18407fSRichard Henderson /* Drop outputs that are dead. */ 17795a18407fSRichard Henderson if (IS_DEAD_ARG(i)) { 17805a18407fSRichard Henderson temp_state[arg] = TS_DEAD; 17815a18407fSRichard Henderson } 17825a18407fSRichard Henderson } 17835a18407fSRichard Henderson } 17845a18407fSRichard Henderson 17855a18407fSRichard Henderson return changes; 17865a18407fSRichard Henderson } 17875a18407fSRichard Henderson 17888d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG 1789c896fe29Sbellard static void dump_regs(TCGContext *s) 1790c896fe29Sbellard { 1791c896fe29Sbellard TCGTemp *ts; 1792c896fe29Sbellard int i; 1793c896fe29Sbellard char buf[64]; 1794c896fe29Sbellard 1795c896fe29Sbellard for(i = 0; i < s->nb_temps; i++) { 1796c896fe29Sbellard ts = &s->temps[i]; 1797ac56dd48Spbrook printf(" %10s: ", tcg_get_arg_str_idx(s, buf, sizeof(buf), i)); 1798c896fe29Sbellard switch(ts->val_type) { 1799c896fe29Sbellard case TEMP_VAL_REG: 1800c896fe29Sbellard printf("%s", tcg_target_reg_names[ts->reg]); 1801c896fe29Sbellard break; 1802c896fe29Sbellard case TEMP_VAL_MEM: 1803b3a62939SRichard Henderson printf("%d(%s)", (int)ts->mem_offset, 1804b3a62939SRichard Henderson tcg_target_reg_names[ts->mem_base->reg]); 1805c896fe29Sbellard break; 1806c896fe29Sbellard case TEMP_VAL_CONST: 1807c896fe29Sbellard printf("$0x%" TCG_PRIlx, ts->val); 1808c896fe29Sbellard break; 1809c896fe29Sbellard case TEMP_VAL_DEAD: 1810c896fe29Sbellard printf("D"); 1811c896fe29Sbellard break; 1812c896fe29Sbellard default: 1813c896fe29Sbellard printf("???"); 1814c896fe29Sbellard break; 1815c896fe29Sbellard } 1816c896fe29Sbellard printf("\n"); 1817c896fe29Sbellard } 1818c896fe29Sbellard 1819c896fe29Sbellard for(i = 0; i < TCG_TARGET_NB_REGS; i++) { 1820f8b2f202SRichard Henderson if (s->reg_to_temp[i] != NULL) { 1821c896fe29Sbellard printf("%s: %s\n", 1822c896fe29Sbellard tcg_target_reg_names[i], 1823f8b2f202SRichard Henderson tcg_get_arg_str_ptr(s, buf, sizeof(buf), s->reg_to_temp[i])); 1824c896fe29Sbellard } 1825c896fe29Sbellard } 1826c896fe29Sbellard } 1827c896fe29Sbellard 1828c896fe29Sbellard static void check_regs(TCGContext *s) 1829c896fe29Sbellard { 1830869938aeSRichard Henderson int reg; 1831b6638662SRichard Henderson int k; 1832c896fe29Sbellard TCGTemp *ts; 1833c896fe29Sbellard char buf[64]; 1834c896fe29Sbellard 1835c896fe29Sbellard for (reg = 0; reg < TCG_TARGET_NB_REGS; reg++) { 1836f8b2f202SRichard Henderson ts = s->reg_to_temp[reg]; 1837f8b2f202SRichard Henderson if (ts != NULL) { 1838f8b2f202SRichard Henderson if (ts->val_type != TEMP_VAL_REG || ts->reg != reg) { 1839c896fe29Sbellard printf("Inconsistency for register %s:\n", 1840c896fe29Sbellard tcg_target_reg_names[reg]); 1841b03cce8eSbellard goto fail; 1842c896fe29Sbellard } 1843c896fe29Sbellard } 1844c896fe29Sbellard } 1845c896fe29Sbellard for (k = 0; k < s->nb_temps; k++) { 1846c896fe29Sbellard ts = &s->temps[k]; 1847f8b2f202SRichard Henderson if (ts->val_type == TEMP_VAL_REG && !ts->fixed_reg 1848f8b2f202SRichard Henderson && s->reg_to_temp[ts->reg] != ts) { 1849c896fe29Sbellard printf("Inconsistency for temp %s:\n", 1850f8b2f202SRichard Henderson tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts)); 1851b03cce8eSbellard fail: 1852c896fe29Sbellard printf("reg state:\n"); 1853c896fe29Sbellard dump_regs(s); 1854c896fe29Sbellard tcg_abort(); 1855c896fe29Sbellard } 1856c896fe29Sbellard } 1857c896fe29Sbellard } 1858c896fe29Sbellard #endif 1859c896fe29Sbellard 1860c896fe29Sbellard static void temp_allocate_frame(TCGContext *s, int temp) 1861c896fe29Sbellard { 1862c896fe29Sbellard TCGTemp *ts; 1863c896fe29Sbellard ts = &s->temps[temp]; 18649b9c37c3SRichard Henderson #if !(defined(__sparc__) && TCG_TARGET_REG_BITS == 64) 18659b9c37c3SRichard Henderson /* Sparc64 stack is accessed with offset of 2047 */ 1866b591dc59SBlue Swirl s->current_frame_offset = (s->current_frame_offset + 1867b591dc59SBlue Swirl (tcg_target_long)sizeof(tcg_target_long) - 1) & 1868b591dc59SBlue Swirl ~(sizeof(tcg_target_long) - 1); 1869f44c9960SBlue Swirl #endif 1870b591dc59SBlue Swirl if (s->current_frame_offset + (tcg_target_long)sizeof(tcg_target_long) > 1871b591dc59SBlue Swirl s->frame_end) { 18725ff9d6a4Sbellard tcg_abort(); 1873b591dc59SBlue Swirl } 1874c896fe29Sbellard ts->mem_offset = s->current_frame_offset; 1875b3a62939SRichard Henderson ts->mem_base = s->frame_temp; 1876c896fe29Sbellard ts->mem_allocated = 1; 1877e2c6d1b4SRichard Henderson s->current_frame_offset += sizeof(tcg_target_long); 1878c896fe29Sbellard } 1879c896fe29Sbellard 1880b3915dbbSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet); 1881b3915dbbSRichard Henderson 188259d7c14eSRichard Henderson /* Mark a temporary as free or dead. If 'free_or_dead' is negative, 188359d7c14eSRichard Henderson mark it free; otherwise mark it dead. */ 188459d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead) 1885c896fe29Sbellard { 188659d7c14eSRichard Henderson if (ts->fixed_reg) { 188759d7c14eSRichard Henderson return; 188859d7c14eSRichard Henderson } 188959d7c14eSRichard Henderson if (ts->val_type == TEMP_VAL_REG) { 189059d7c14eSRichard Henderson s->reg_to_temp[ts->reg] = NULL; 189159d7c14eSRichard Henderson } 189259d7c14eSRichard Henderson ts->val_type = (free_or_dead < 0 189359d7c14eSRichard Henderson || ts->temp_local 189459d7c14eSRichard Henderson || temp_idx(s, ts) < s->nb_globals 189559d7c14eSRichard Henderson ? TEMP_VAL_MEM : TEMP_VAL_DEAD); 189659d7c14eSRichard Henderson } 1897c896fe29Sbellard 189859d7c14eSRichard Henderson /* Mark a temporary as dead. */ 189959d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts) 190059d7c14eSRichard Henderson { 190159d7c14eSRichard Henderson temp_free_or_dead(s, ts, 1); 190259d7c14eSRichard Henderson } 190359d7c14eSRichard Henderson 190459d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary 190559d7c14eSRichard Henderson registers needs to be allocated to store a constant. If 'free_or_dead' 190659d7c14eSRichard Henderson is non-zero, subsequently release the temporary; if it is positive, the 190759d7c14eSRichard Henderson temp is dead; if it is negative, the temp is free. */ 190859d7c14eSRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, 190959d7c14eSRichard Henderson TCGRegSet allocated_regs, int free_or_dead) 191059d7c14eSRichard Henderson { 191159d7c14eSRichard Henderson if (ts->fixed_reg) { 191259d7c14eSRichard Henderson return; 191359d7c14eSRichard Henderson } 191459d7c14eSRichard Henderson if (!ts->mem_coherent) { 19157f6ceedfSAurelien Jarno if (!ts->mem_allocated) { 1916f8b2f202SRichard Henderson temp_allocate_frame(s, temp_idx(s, ts)); 191759d7c14eSRichard Henderson } 191859d7c14eSRichard Henderson switch (ts->val_type) { 191959d7c14eSRichard Henderson case TEMP_VAL_CONST: 192059d7c14eSRichard Henderson /* If we're going to free the temp immediately, then we won't 192159d7c14eSRichard Henderson require it later in a register, so attempt to store the 192259d7c14eSRichard Henderson constant to memory directly. */ 192359d7c14eSRichard Henderson if (free_or_dead 192459d7c14eSRichard Henderson && tcg_out_sti(s, ts->type, ts->val, 192559d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset)) { 192659d7c14eSRichard Henderson break; 192759d7c14eSRichard Henderson } 192859d7c14eSRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 192959d7c14eSRichard Henderson allocated_regs); 193059d7c14eSRichard Henderson /* fallthrough */ 193159d7c14eSRichard Henderson 193259d7c14eSRichard Henderson case TEMP_VAL_REG: 193359d7c14eSRichard Henderson tcg_out_st(s, ts->type, ts->reg, 193459d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset); 193559d7c14eSRichard Henderson break; 193659d7c14eSRichard Henderson 193759d7c14eSRichard Henderson case TEMP_VAL_MEM: 193859d7c14eSRichard Henderson break; 193959d7c14eSRichard Henderson 194059d7c14eSRichard Henderson case TEMP_VAL_DEAD: 194159d7c14eSRichard Henderson default: 194259d7c14eSRichard Henderson tcg_abort(); 1943c896fe29Sbellard } 19447f6ceedfSAurelien Jarno ts->mem_coherent = 1; 19457f6ceedfSAurelien Jarno } 194659d7c14eSRichard Henderson if (free_or_dead) { 194759d7c14eSRichard Henderson temp_free_or_dead(s, ts, free_or_dead); 194859d7c14eSRichard Henderson } 194959d7c14eSRichard Henderson } 19507f6ceedfSAurelien Jarno 19517f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */ 1952b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs) 19537f6ceedfSAurelien Jarno { 1954f8b2f202SRichard Henderson TCGTemp *ts = s->reg_to_temp[reg]; 1955f8b2f202SRichard Henderson if (ts != NULL) { 195659d7c14eSRichard Henderson temp_sync(s, ts, allocated_regs, -1); 1957c896fe29Sbellard } 1958c896fe29Sbellard } 1959c896fe29Sbellard 1960c896fe29Sbellard /* Allocate a register belonging to reg1 & ~reg2 */ 1961b3915dbbSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet desired_regs, 196291478cefSRichard Henderson TCGRegSet allocated_regs, bool rev) 1963c896fe29Sbellard { 196491478cefSRichard Henderson int i, n = ARRAY_SIZE(tcg_target_reg_alloc_order); 196591478cefSRichard Henderson const int *order; 1966b6638662SRichard Henderson TCGReg reg; 1967c896fe29Sbellard TCGRegSet reg_ct; 1968c896fe29Sbellard 1969b3915dbbSRichard Henderson tcg_regset_andnot(reg_ct, desired_regs, allocated_regs); 197091478cefSRichard Henderson order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order; 1971c896fe29Sbellard 1972c896fe29Sbellard /* first try free registers */ 197391478cefSRichard Henderson for(i = 0; i < n; i++) { 197491478cefSRichard Henderson reg = order[i]; 1975f8b2f202SRichard Henderson if (tcg_regset_test_reg(reg_ct, reg) && s->reg_to_temp[reg] == NULL) 1976c896fe29Sbellard return reg; 1977c896fe29Sbellard } 1978c896fe29Sbellard 1979c896fe29Sbellard /* XXX: do better spill choice */ 198091478cefSRichard Henderson for(i = 0; i < n; i++) { 198191478cefSRichard Henderson reg = order[i]; 1982c896fe29Sbellard if (tcg_regset_test_reg(reg_ct, reg)) { 1983b3915dbbSRichard Henderson tcg_reg_free(s, reg, allocated_regs); 1984c896fe29Sbellard return reg; 1985c896fe29Sbellard } 1986c896fe29Sbellard } 1987c896fe29Sbellard 1988c896fe29Sbellard tcg_abort(); 1989c896fe29Sbellard } 1990c896fe29Sbellard 199140ae5c62SRichard Henderson /* Make sure the temporary is in a register. If needed, allocate the register 199240ae5c62SRichard Henderson from DESIRED while avoiding ALLOCATED. */ 199340ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs, 199440ae5c62SRichard Henderson TCGRegSet allocated_regs) 199540ae5c62SRichard Henderson { 199640ae5c62SRichard Henderson TCGReg reg; 199740ae5c62SRichard Henderson 199840ae5c62SRichard Henderson switch (ts->val_type) { 199940ae5c62SRichard Henderson case TEMP_VAL_REG: 200040ae5c62SRichard Henderson return; 200140ae5c62SRichard Henderson case TEMP_VAL_CONST: 200291478cefSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs, ts->indirect_base); 200340ae5c62SRichard Henderson tcg_out_movi(s, ts->type, reg, ts->val); 200440ae5c62SRichard Henderson ts->mem_coherent = 0; 200540ae5c62SRichard Henderson break; 200640ae5c62SRichard Henderson case TEMP_VAL_MEM: 200791478cefSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs, ts->indirect_base); 200840ae5c62SRichard Henderson tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset); 200940ae5c62SRichard Henderson ts->mem_coherent = 1; 201040ae5c62SRichard Henderson break; 201140ae5c62SRichard Henderson case TEMP_VAL_DEAD: 201240ae5c62SRichard Henderson default: 201340ae5c62SRichard Henderson tcg_abort(); 201440ae5c62SRichard Henderson } 201540ae5c62SRichard Henderson ts->reg = reg; 201640ae5c62SRichard Henderson ts->val_type = TEMP_VAL_REG; 201740ae5c62SRichard Henderson s->reg_to_temp[reg] = ts; 201840ae5c62SRichard Henderson } 201940ae5c62SRichard Henderson 202059d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a 2021e8996ee0Sbellard temporary registers needs to be allocated to store a constant. */ 202259d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs) 20231ad80729SAurelien Jarno { 20242c0366f0SAurelien Jarno /* The liveness analysis already ensures that globals are back 2025eabb7b91SAurelien Jarno in memory. Keep an tcg_debug_assert for safety. */ 2026f8bf00f1SRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || ts->fixed_reg); 20271ad80729SAurelien Jarno } 20281ad80729SAurelien Jarno 20299814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be 2030641d5fbeSbellard modified be the following code. 'allocated_regs' is used in case a 2031641d5fbeSbellard temporary registers needs to be allocated to store a constant. */ 2032641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs) 2033641d5fbeSbellard { 2034641d5fbeSbellard int i; 2035641d5fbeSbellard 2036641d5fbeSbellard for (i = 0; i < s->nb_globals; i++) { 2037b13eb728SRichard Henderson temp_save(s, &s->temps[i], allocated_regs); 2038641d5fbeSbellard } 2039e5097dc8Sbellard } 2040e5097dc8Sbellard 20413d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be 20423d5c5f87SAurelien Jarno read by the following code. 'allocated_regs' is used in case a 20433d5c5f87SAurelien Jarno temporary registers needs to be allocated to store a constant. */ 20443d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs) 20453d5c5f87SAurelien Jarno { 20463d5c5f87SAurelien Jarno int i; 20473d5c5f87SAurelien Jarno 20483d5c5f87SAurelien Jarno for (i = 0; i < s->nb_globals; i++) { 204912b9b11aSRichard Henderson TCGTemp *ts = &s->temps[i]; 205012b9b11aSRichard Henderson tcg_debug_assert(ts->val_type != TEMP_VAL_REG 205112b9b11aSRichard Henderson || ts->fixed_reg 205212b9b11aSRichard Henderson || ts->mem_coherent); 20533d5c5f87SAurelien Jarno } 20543d5c5f87SAurelien Jarno } 20553d5c5f87SAurelien Jarno 2056e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and 2057e8996ee0Sbellard all globals are stored at their canonical location. */ 2058e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs) 2059e5097dc8Sbellard { 2060e5097dc8Sbellard int i; 2061e5097dc8Sbellard 2062c896fe29Sbellard for (i = s->nb_globals; i < s->nb_temps; i++) { 2063b13eb728SRichard Henderson TCGTemp *ts = &s->temps[i]; 2064641d5fbeSbellard if (ts->temp_local) { 2065b13eb728SRichard Henderson temp_save(s, ts, allocated_regs); 2066641d5fbeSbellard } else { 20672c0366f0SAurelien Jarno /* The liveness analysis already ensures that temps are dead. 2068eabb7b91SAurelien Jarno Keep an tcg_debug_assert for safety. */ 2069eabb7b91SAurelien Jarno tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD); 2070c896fe29Sbellard } 2071641d5fbeSbellard } 2072e8996ee0Sbellard 2073e8996ee0Sbellard save_globals(s, allocated_regs); 2074c896fe29Sbellard } 2075c896fe29Sbellard 20760fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots, 20770fe4fca4SPaolo Bonzini tcg_target_ulong val, TCGLifeData arg_life) 2078e8996ee0Sbellard { 2079e8996ee0Sbellard if (ots->fixed_reg) { 208059d7c14eSRichard Henderson /* For fixed registers, we do not do any constant propagation. */ 2081e8996ee0Sbellard tcg_out_movi(s, ots->type, ots->reg, val); 208259d7c14eSRichard Henderson return; 208359d7c14eSRichard Henderson } 208459d7c14eSRichard Henderson 208559d7c14eSRichard Henderson /* The movi is not explicitly generated here. */ 2086f8b2f202SRichard Henderson if (ots->val_type == TEMP_VAL_REG) { 2087f8b2f202SRichard Henderson s->reg_to_temp[ots->reg] = NULL; 2088f8b2f202SRichard Henderson } 2089e8996ee0Sbellard ots->val_type = TEMP_VAL_CONST; 2090e8996ee0Sbellard ots->val = val; 209159d7c14eSRichard Henderson ots->mem_coherent = 0; 2092ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) { 209359d7c14eSRichard Henderson temp_sync(s, ots, s->reserved_regs, IS_DEAD_ARG(0)); 209459d7c14eSRichard Henderson } else if (IS_DEAD_ARG(0)) { 2095f8bf00f1SRichard Henderson temp_dead(s, ots); 20964c4e1ab2SAurelien Jarno } 2097e8996ee0Sbellard } 2098e8996ee0Sbellard 20990fe4fca4SPaolo Bonzini static void tcg_reg_alloc_movi(TCGContext *s, const TCGArg *args, 21000fe4fca4SPaolo Bonzini TCGLifeData arg_life) 21010fe4fca4SPaolo Bonzini { 21020fe4fca4SPaolo Bonzini TCGTemp *ots = &s->temps[args[0]]; 21030fe4fca4SPaolo Bonzini tcg_target_ulong val = args[1]; 21040fe4fca4SPaolo Bonzini 21050fe4fca4SPaolo Bonzini tcg_reg_alloc_do_movi(s, ots, val, arg_life); 21060fe4fca4SPaolo Bonzini } 21070fe4fca4SPaolo Bonzini 2108c896fe29Sbellard static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def, 2109a1b3c48dSRichard Henderson const TCGArg *args, TCGLifeData arg_life) 2110c896fe29Sbellard { 2111c29c1d7eSAurelien Jarno TCGRegSet allocated_regs; 2112c896fe29Sbellard TCGTemp *ts, *ots; 2113450445d5SRichard Henderson TCGType otype, itype; 2114c896fe29Sbellard 2115c29c1d7eSAurelien Jarno tcg_regset_set(allocated_regs, s->reserved_regs); 2116c896fe29Sbellard ots = &s->temps[args[0]]; 2117c896fe29Sbellard ts = &s->temps[args[1]]; 2118450445d5SRichard Henderson 2119450445d5SRichard Henderson /* Note that otype != itype for no-op truncation. */ 2120450445d5SRichard Henderson otype = ots->type; 2121450445d5SRichard Henderson itype = ts->type; 2122c896fe29Sbellard 21230fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_CONST) { 21240fe4fca4SPaolo Bonzini /* propagate constant or generate sti */ 21250fe4fca4SPaolo Bonzini tcg_target_ulong val = ts->val; 21260fe4fca4SPaolo Bonzini if (IS_DEAD_ARG(1)) { 21270fe4fca4SPaolo Bonzini temp_dead(s, ts); 21280fe4fca4SPaolo Bonzini } 21290fe4fca4SPaolo Bonzini tcg_reg_alloc_do_movi(s, ots, val, arg_life); 21300fe4fca4SPaolo Bonzini return; 21310fe4fca4SPaolo Bonzini } 21320fe4fca4SPaolo Bonzini 21330fe4fca4SPaolo Bonzini /* If the source value is in memory we're going to be forced 21340fe4fca4SPaolo Bonzini to have it in a register in order to perform the copy. Copy 21350fe4fca4SPaolo Bonzini the SOURCE value into its own register first, that way we 21360fe4fca4SPaolo Bonzini don't have to reload SOURCE the next time it is used. */ 21370fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_MEM) { 213840ae5c62SRichard Henderson temp_load(s, ts, tcg_target_available_regs[itype], allocated_regs); 2139c29c1d7eSAurelien Jarno } 2140c29c1d7eSAurelien Jarno 21410fe4fca4SPaolo Bonzini tcg_debug_assert(ts->val_type == TEMP_VAL_REG); 2142c29c1d7eSAurelien Jarno if (IS_DEAD_ARG(0) && !ots->fixed_reg) { 2143c29c1d7eSAurelien Jarno /* mov to a non-saved dead register makes no sense (even with 2144c29c1d7eSAurelien Jarno liveness analysis disabled). */ 2145eabb7b91SAurelien Jarno tcg_debug_assert(NEED_SYNC_ARG(0)); 2146c29c1d7eSAurelien Jarno if (!ots->mem_allocated) { 2147c29c1d7eSAurelien Jarno temp_allocate_frame(s, args[0]); 2148c29c1d7eSAurelien Jarno } 2149b3a62939SRichard Henderson tcg_out_st(s, otype, ts->reg, ots->mem_base->reg, ots->mem_offset); 2150c29c1d7eSAurelien Jarno if (IS_DEAD_ARG(1)) { 2151f8bf00f1SRichard Henderson temp_dead(s, ts); 2152c29c1d7eSAurelien Jarno } 2153f8bf00f1SRichard Henderson temp_dead(s, ots); 2154e8996ee0Sbellard } else { 2155c29c1d7eSAurelien Jarno if (IS_DEAD_ARG(1) && !ts->fixed_reg && !ots->fixed_reg) { 2156c29c1d7eSAurelien Jarno /* the mov can be suppressed */ 2157c29c1d7eSAurelien Jarno if (ots->val_type == TEMP_VAL_REG) { 2158f8b2f202SRichard Henderson s->reg_to_temp[ots->reg] = NULL; 2159c896fe29Sbellard } 2160c29c1d7eSAurelien Jarno ots->reg = ts->reg; 2161f8bf00f1SRichard Henderson temp_dead(s, ts); 2162c29c1d7eSAurelien Jarno } else { 2163c29c1d7eSAurelien Jarno if (ots->val_type != TEMP_VAL_REG) { 2164c29c1d7eSAurelien Jarno /* When allocating a new register, make sure to not spill the 2165c29c1d7eSAurelien Jarno input one. */ 2166c29c1d7eSAurelien Jarno tcg_regset_set_reg(allocated_regs, ts->reg); 2167450445d5SRichard Henderson ots->reg = tcg_reg_alloc(s, tcg_target_available_regs[otype], 216891478cefSRichard Henderson allocated_regs, ots->indirect_base); 2169c29c1d7eSAurelien Jarno } 2170450445d5SRichard Henderson tcg_out_mov(s, otype, ots->reg, ts->reg); 2171c29c1d7eSAurelien Jarno } 2172c896fe29Sbellard ots->val_type = TEMP_VAL_REG; 2173c896fe29Sbellard ots->mem_coherent = 0; 2174f8b2f202SRichard Henderson s->reg_to_temp[ots->reg] = ots; 2175ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) { 217659d7c14eSRichard Henderson temp_sync(s, ots, allocated_regs, 0); 2177c29c1d7eSAurelien Jarno } 2178ec7a869dSAurelien Jarno } 2179c896fe29Sbellard } 2180c896fe29Sbellard 2181c896fe29Sbellard static void tcg_reg_alloc_op(TCGContext *s, 2182a9751609SRichard Henderson const TCGOpDef *def, TCGOpcode opc, 2183a1b3c48dSRichard Henderson const TCGArg *args, TCGLifeData arg_life) 2184c896fe29Sbellard { 218582790a87SRichard Henderson TCGRegSet i_allocated_regs; 218682790a87SRichard Henderson TCGRegSet o_allocated_regs; 2187b6638662SRichard Henderson int i, k, nb_iargs, nb_oargs; 2188b6638662SRichard Henderson TCGReg reg; 2189c896fe29Sbellard TCGArg arg; 2190c896fe29Sbellard const TCGArgConstraint *arg_ct; 2191c896fe29Sbellard TCGTemp *ts; 2192c896fe29Sbellard TCGArg new_args[TCG_MAX_OP_ARGS]; 2193c896fe29Sbellard int const_args[TCG_MAX_OP_ARGS]; 2194c896fe29Sbellard 2195c896fe29Sbellard nb_oargs = def->nb_oargs; 2196c896fe29Sbellard nb_iargs = def->nb_iargs; 2197c896fe29Sbellard 2198c896fe29Sbellard /* copy constants */ 2199c896fe29Sbellard memcpy(new_args + nb_oargs + nb_iargs, 2200c896fe29Sbellard args + nb_oargs + nb_iargs, 2201c896fe29Sbellard sizeof(TCGArg) * def->nb_cargs); 2202c896fe29Sbellard 220382790a87SRichard Henderson tcg_regset_set(i_allocated_regs, s->reserved_regs); 220482790a87SRichard Henderson tcg_regset_set(o_allocated_regs, s->reserved_regs); 220582790a87SRichard Henderson 2206c896fe29Sbellard /* satisfy input constraints */ 2207c896fe29Sbellard for(k = 0; k < nb_iargs; k++) { 2208c896fe29Sbellard i = def->sorted_args[nb_oargs + k]; 2209c896fe29Sbellard arg = args[i]; 2210c896fe29Sbellard arg_ct = &def->args_ct[i]; 2211c896fe29Sbellard ts = &s->temps[arg]; 221240ae5c62SRichard Henderson 221340ae5c62SRichard Henderson if (ts->val_type == TEMP_VAL_CONST 221440ae5c62SRichard Henderson && tcg_target_const_match(ts->val, ts->type, arg_ct)) { 2215c896fe29Sbellard /* constant is OK for instruction */ 2216c896fe29Sbellard const_args[i] = 1; 2217c896fe29Sbellard new_args[i] = ts->val; 2218c896fe29Sbellard goto iarg_end; 2219c896fe29Sbellard } 222040ae5c62SRichard Henderson 222182790a87SRichard Henderson temp_load(s, ts, arg_ct->u.regs, i_allocated_regs); 222240ae5c62SRichard Henderson 22235ff9d6a4Sbellard if (arg_ct->ct & TCG_CT_IALIAS) { 22245ff9d6a4Sbellard if (ts->fixed_reg) { 22255ff9d6a4Sbellard /* if fixed register, we must allocate a new register 22265ff9d6a4Sbellard if the alias is not the same register */ 22275ff9d6a4Sbellard if (arg != args[arg_ct->alias_index]) 22285ff9d6a4Sbellard goto allocate_in_reg; 22295ff9d6a4Sbellard } else { 2230c896fe29Sbellard /* if the input is aliased to an output and if it is 2231c896fe29Sbellard not dead after the instruction, we must allocate 2232c896fe29Sbellard a new register and move it */ 2233866cb6cbSAurelien Jarno if (!IS_DEAD_ARG(i)) { 2234c896fe29Sbellard goto allocate_in_reg; 2235c896fe29Sbellard } 22367e1df267SAurelien Jarno /* check if the current register has already been allocated 22377e1df267SAurelien Jarno for another input aliased to an output */ 22387e1df267SAurelien Jarno int k2, i2; 22397e1df267SAurelien Jarno for (k2 = 0 ; k2 < k ; k2++) { 22407e1df267SAurelien Jarno i2 = def->sorted_args[nb_oargs + k2]; 22417e1df267SAurelien Jarno if ((def->args_ct[i2].ct & TCG_CT_IALIAS) && 22427e1df267SAurelien Jarno (new_args[i2] == ts->reg)) { 22437e1df267SAurelien Jarno goto allocate_in_reg; 22447e1df267SAurelien Jarno } 22457e1df267SAurelien Jarno } 22465ff9d6a4Sbellard } 2247866cb6cbSAurelien Jarno } 2248c896fe29Sbellard reg = ts->reg; 2249c896fe29Sbellard if (tcg_regset_test_reg(arg_ct->u.regs, reg)) { 2250c896fe29Sbellard /* nothing to do : the constraint is satisfied */ 2251c896fe29Sbellard } else { 2252c896fe29Sbellard allocate_in_reg: 2253c896fe29Sbellard /* allocate a new register matching the constraint 2254c896fe29Sbellard and move the temporary register into it */ 225582790a87SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->u.regs, i_allocated_regs, 225691478cefSRichard Henderson ts->indirect_base); 22573b6dac34SRichard Henderson tcg_out_mov(s, ts->type, reg, ts->reg); 2258c896fe29Sbellard } 2259c896fe29Sbellard new_args[i] = reg; 2260c896fe29Sbellard const_args[i] = 0; 226182790a87SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg); 2262c896fe29Sbellard iarg_end: ; 2263c896fe29Sbellard } 2264c896fe29Sbellard 2265c896fe29Sbellard /* mark dead temporaries and free the associated registers */ 2266866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 2267866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) { 2268f8bf00f1SRichard Henderson temp_dead(s, &s->temps[args[i]]); 2269c896fe29Sbellard } 2270c896fe29Sbellard } 2271c896fe29Sbellard 2272a52ad07eSAurelien Jarno if (def->flags & TCG_OPF_BB_END) { 227382790a87SRichard Henderson tcg_reg_alloc_bb_end(s, i_allocated_regs); 2274a52ad07eSAurelien Jarno } else { 2275c896fe29Sbellard if (def->flags & TCG_OPF_CALL_CLOBBER) { 2276b03cce8eSbellard /* XXX: permit generic clobber register list ? */ 2277c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) { 2278c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { 227982790a87SRichard Henderson tcg_reg_free(s, i, i_allocated_regs); 2280c896fe29Sbellard } 2281c896fe29Sbellard } 22823d5c5f87SAurelien Jarno } 22833d5c5f87SAurelien Jarno if (def->flags & TCG_OPF_SIDE_EFFECTS) { 22843d5c5f87SAurelien Jarno /* sync globals if the op has side effects and might trigger 22853d5c5f87SAurelien Jarno an exception. */ 228682790a87SRichard Henderson sync_globals(s, i_allocated_regs); 2287c896fe29Sbellard } 2288c896fe29Sbellard 2289c896fe29Sbellard /* satisfy the output constraints */ 2290c896fe29Sbellard for(k = 0; k < nb_oargs; k++) { 2291c896fe29Sbellard i = def->sorted_args[k]; 2292c896fe29Sbellard arg = args[i]; 2293c896fe29Sbellard arg_ct = &def->args_ct[i]; 2294c896fe29Sbellard ts = &s->temps[arg]; 2295c896fe29Sbellard if (arg_ct->ct & TCG_CT_ALIAS) { 22965ff9d6a4Sbellard reg = new_args[arg_ct->alias_index]; 229782790a87SRichard Henderson } else if (arg_ct->ct & TCG_CT_NEWREG) { 229882790a87SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->u.regs, 229982790a87SRichard Henderson i_allocated_regs | o_allocated_regs, 230082790a87SRichard Henderson ts->indirect_base); 2301c896fe29Sbellard } else { 2302c896fe29Sbellard /* if fixed register, we try to use it */ 2303c896fe29Sbellard reg = ts->reg; 2304c896fe29Sbellard if (ts->fixed_reg && 2305c896fe29Sbellard tcg_regset_test_reg(arg_ct->u.regs, reg)) { 2306c896fe29Sbellard goto oarg_end; 2307c896fe29Sbellard } 230882790a87SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->u.regs, o_allocated_regs, 230991478cefSRichard Henderson ts->indirect_base); 2310c896fe29Sbellard } 231182790a87SRichard Henderson tcg_regset_set_reg(o_allocated_regs, reg); 2312c896fe29Sbellard /* if a fixed register is used, then a move will be done afterwards */ 2313c896fe29Sbellard if (!ts->fixed_reg) { 2314639368ddSAurelien Jarno if (ts->val_type == TEMP_VAL_REG) { 2315f8b2f202SRichard Henderson s->reg_to_temp[ts->reg] = NULL; 2316639368ddSAurelien Jarno } 2317c896fe29Sbellard ts->val_type = TEMP_VAL_REG; 2318c896fe29Sbellard ts->reg = reg; 2319c896fe29Sbellard /* temp value is modified, so the value kept in memory is 2320c896fe29Sbellard potentially not the same */ 2321c896fe29Sbellard ts->mem_coherent = 0; 2322f8b2f202SRichard Henderson s->reg_to_temp[reg] = ts; 2323c896fe29Sbellard } 2324c896fe29Sbellard oarg_end: 2325c896fe29Sbellard new_args[i] = reg; 2326c896fe29Sbellard } 2327e8996ee0Sbellard } 2328c896fe29Sbellard 2329c896fe29Sbellard /* emit instruction */ 2330c896fe29Sbellard tcg_out_op(s, opc, new_args, const_args); 2331c896fe29Sbellard 2332c896fe29Sbellard /* move the outputs in the correct register if needed */ 2333c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 2334c896fe29Sbellard ts = &s->temps[args[i]]; 2335c896fe29Sbellard reg = new_args[i]; 2336c896fe29Sbellard if (ts->fixed_reg && ts->reg != reg) { 23373b6dac34SRichard Henderson tcg_out_mov(s, ts->type, ts->reg, reg); 2338c896fe29Sbellard } 2339ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) { 234082790a87SRichard Henderson temp_sync(s, ts, o_allocated_regs, IS_DEAD_ARG(i)); 234159d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) { 2342f8bf00f1SRichard Henderson temp_dead(s, ts); 2343ec7a869dSAurelien Jarno } 2344c896fe29Sbellard } 2345c896fe29Sbellard } 2346c896fe29Sbellard 2347b03cce8eSbellard #ifdef TCG_TARGET_STACK_GROWSUP 2348b03cce8eSbellard #define STACK_DIR(x) (-(x)) 2349b03cce8eSbellard #else 2350b03cce8eSbellard #define STACK_DIR(x) (x) 2351b03cce8eSbellard #endif 2352b03cce8eSbellard 2353c45cb8bbSRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, int nb_oargs, int nb_iargs, 2354a1b3c48dSRichard Henderson const TCGArg * const args, TCGLifeData arg_life) 2355c896fe29Sbellard { 2356b6638662SRichard Henderson int flags, nb_regs, i; 2357b6638662SRichard Henderson TCGReg reg; 2358cf066674SRichard Henderson TCGArg arg; 2359c896fe29Sbellard TCGTemp *ts; 2360d3452f1fSRichard Henderson intptr_t stack_offset; 2361d3452f1fSRichard Henderson size_t call_stack_size; 2362cf066674SRichard Henderson tcg_insn_unit *func_addr; 2363cf066674SRichard Henderson int allocate_args; 2364c896fe29Sbellard TCGRegSet allocated_regs; 2365c896fe29Sbellard 2366cf066674SRichard Henderson func_addr = (tcg_insn_unit *)(intptr_t)args[nb_oargs + nb_iargs]; 2367cf066674SRichard Henderson flags = args[nb_oargs + nb_iargs + 1]; 2368c896fe29Sbellard 23696e17d0c5SStefan Weil nb_regs = ARRAY_SIZE(tcg_target_call_iarg_regs); 2370c45cb8bbSRichard Henderson if (nb_regs > nb_iargs) { 2371c45cb8bbSRichard Henderson nb_regs = nb_iargs; 2372cf066674SRichard Henderson } 2373c896fe29Sbellard 2374c896fe29Sbellard /* assign stack slots first */ 2375c45cb8bbSRichard Henderson call_stack_size = (nb_iargs - nb_regs) * sizeof(tcg_target_long); 2376c896fe29Sbellard call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) & 2377c896fe29Sbellard ~(TCG_TARGET_STACK_ALIGN - 1); 2378b03cce8eSbellard allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE); 2379b03cce8eSbellard if (allocate_args) { 2380345649c0SBlue Swirl /* XXX: if more than TCG_STATIC_CALL_ARGS_SIZE is needed, 2381345649c0SBlue Swirl preallocate call stack */ 2382345649c0SBlue Swirl tcg_abort(); 2383b03cce8eSbellard } 238439cf05d3Sbellard 238539cf05d3Sbellard stack_offset = TCG_TARGET_CALL_STACK_OFFSET; 2386c45cb8bbSRichard Henderson for(i = nb_regs; i < nb_iargs; i++) { 2387c896fe29Sbellard arg = args[nb_oargs + i]; 238839cf05d3Sbellard #ifdef TCG_TARGET_STACK_GROWSUP 238939cf05d3Sbellard stack_offset -= sizeof(tcg_target_long); 239039cf05d3Sbellard #endif 239139cf05d3Sbellard if (arg != TCG_CALL_DUMMY_ARG) { 2392c896fe29Sbellard ts = &s->temps[arg]; 239340ae5c62SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 239440ae5c62SRichard Henderson s->reserved_regs); 2395e4d5434cSblueswir1 tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset); 239639cf05d3Sbellard } 239739cf05d3Sbellard #ifndef TCG_TARGET_STACK_GROWSUP 239839cf05d3Sbellard stack_offset += sizeof(tcg_target_long); 239939cf05d3Sbellard #endif 2400c896fe29Sbellard } 2401c896fe29Sbellard 2402c896fe29Sbellard /* assign input registers */ 2403c896fe29Sbellard tcg_regset_set(allocated_regs, s->reserved_regs); 2404c896fe29Sbellard for(i = 0; i < nb_regs; i++) { 2405c896fe29Sbellard arg = args[nb_oargs + i]; 240639cf05d3Sbellard if (arg != TCG_CALL_DUMMY_ARG) { 2407c896fe29Sbellard ts = &s->temps[arg]; 2408c896fe29Sbellard reg = tcg_target_call_iarg_regs[i]; 2409b3915dbbSRichard Henderson tcg_reg_free(s, reg, allocated_regs); 241040ae5c62SRichard Henderson 2411c896fe29Sbellard if (ts->val_type == TEMP_VAL_REG) { 2412c896fe29Sbellard if (ts->reg != reg) { 24133b6dac34SRichard Henderson tcg_out_mov(s, ts->type, reg, ts->reg); 2414c896fe29Sbellard } 2415c896fe29Sbellard } else { 241640ae5c62SRichard Henderson TCGRegSet arg_set; 241740ae5c62SRichard Henderson 241840ae5c62SRichard Henderson tcg_regset_clear(arg_set); 241940ae5c62SRichard Henderson tcg_regset_set_reg(arg_set, reg); 242040ae5c62SRichard Henderson temp_load(s, ts, arg_set, allocated_regs); 2421c896fe29Sbellard } 242240ae5c62SRichard Henderson 2423c896fe29Sbellard tcg_regset_set_reg(allocated_regs, reg); 2424c896fe29Sbellard } 242539cf05d3Sbellard } 2426c896fe29Sbellard 2427c896fe29Sbellard /* mark dead temporaries and free the associated registers */ 2428866cb6cbSAurelien Jarno for(i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 2429866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) { 2430f8bf00f1SRichard Henderson temp_dead(s, &s->temps[args[i]]); 2431c896fe29Sbellard } 2432c896fe29Sbellard } 2433c896fe29Sbellard 2434c896fe29Sbellard /* clobber call registers */ 2435c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) { 2436c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { 2437b3915dbbSRichard Henderson tcg_reg_free(s, i, allocated_regs); 2438c896fe29Sbellard } 2439c896fe29Sbellard } 2440c896fe29Sbellard 244178505279SAurelien Jarno /* Save globals if they might be written by the helper, sync them if 244278505279SAurelien Jarno they might be read. */ 244378505279SAurelien Jarno if (flags & TCG_CALL_NO_READ_GLOBALS) { 244478505279SAurelien Jarno /* Nothing to do */ 244578505279SAurelien Jarno } else if (flags & TCG_CALL_NO_WRITE_GLOBALS) { 244678505279SAurelien Jarno sync_globals(s, allocated_regs); 244778505279SAurelien Jarno } else { 2448e8996ee0Sbellard save_globals(s, allocated_regs); 2449b9c18f56Saurel32 } 2450c896fe29Sbellard 2451cf066674SRichard Henderson tcg_out_call(s, func_addr); 2452c896fe29Sbellard 2453c896fe29Sbellard /* assign output registers and emit moves if needed */ 2454c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 2455c896fe29Sbellard arg = args[i]; 2456c896fe29Sbellard ts = &s->temps[arg]; 2457c896fe29Sbellard reg = tcg_target_call_oarg_regs[i]; 2458eabb7b91SAurelien Jarno tcg_debug_assert(s->reg_to_temp[reg] == NULL); 245934b1a49cSRichard Henderson 2460c896fe29Sbellard if (ts->fixed_reg) { 2461c896fe29Sbellard if (ts->reg != reg) { 24623b6dac34SRichard Henderson tcg_out_mov(s, ts->type, ts->reg, reg); 2463c896fe29Sbellard } 2464c896fe29Sbellard } else { 2465639368ddSAurelien Jarno if (ts->val_type == TEMP_VAL_REG) { 2466f8b2f202SRichard Henderson s->reg_to_temp[ts->reg] = NULL; 2467639368ddSAurelien Jarno } 2468c896fe29Sbellard ts->val_type = TEMP_VAL_REG; 2469c896fe29Sbellard ts->reg = reg; 2470c896fe29Sbellard ts->mem_coherent = 0; 2471f8b2f202SRichard Henderson s->reg_to_temp[reg] = ts; 2472ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) { 247359d7c14eSRichard Henderson temp_sync(s, ts, allocated_regs, IS_DEAD_ARG(i)); 247459d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) { 2475f8bf00f1SRichard Henderson temp_dead(s, ts); 2476c896fe29Sbellard } 2477c896fe29Sbellard } 24788c11ad25SAurelien Jarno } 2479c896fe29Sbellard } 2480c896fe29Sbellard 2481c896fe29Sbellard #ifdef CONFIG_PROFILER 2482c896fe29Sbellard 248354604f74Saurel32 static int64_t tcg_table_op_count[NB_OPS]; 2484c896fe29Sbellard 2485246ae24dSMax Filippov void tcg_dump_op_count(FILE *f, fprintf_function cpu_fprintf) 2486c896fe29Sbellard { 2487c896fe29Sbellard int i; 2488d70724ceSzhanghailiang 248915fc7daaSRichard Henderson for (i = 0; i < NB_OPS; i++) { 2490246ae24dSMax Filippov cpu_fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name, 2491246ae24dSMax Filippov tcg_table_op_count[i]); 2492c896fe29Sbellard } 2493c896fe29Sbellard } 2494246ae24dSMax Filippov #else 2495246ae24dSMax Filippov void tcg_dump_op_count(FILE *f, fprintf_function cpu_fprintf) 2496246ae24dSMax Filippov { 2497246ae24dSMax Filippov cpu_fprintf(f, "[TCG profiler not compiled]\n"); 2498246ae24dSMax Filippov } 2499c896fe29Sbellard #endif 2500c896fe29Sbellard 2501c896fe29Sbellard 25025bd2ec3dSAlex Bennée int tcg_gen_code(TCGContext *s, TranslationBlock *tb) 2503c896fe29Sbellard { 2504fca8a500SRichard Henderson int i, oi, oi_next, num_insns; 2505c896fe29Sbellard 250604fe6400SRichard Henderson #ifdef CONFIG_PROFILER 250704fe6400SRichard Henderson { 250804fe6400SRichard Henderson int n; 250904fe6400SRichard Henderson 2510dcb8e758SRichard Henderson n = s->gen_op_buf[0].prev + 1; 251104fe6400SRichard Henderson s->op_count += n; 251204fe6400SRichard Henderson if (n > s->op_count_max) { 251304fe6400SRichard Henderson s->op_count_max = n; 251404fe6400SRichard Henderson } 251504fe6400SRichard Henderson 251604fe6400SRichard Henderson n = s->nb_temps; 251704fe6400SRichard Henderson s->temp_count += n; 251804fe6400SRichard Henderson if (n > s->temp_count_max) { 251904fe6400SRichard Henderson s->temp_count_max = n; 252004fe6400SRichard Henderson } 252104fe6400SRichard Henderson } 252204fe6400SRichard Henderson #endif 252304fe6400SRichard Henderson 2524c896fe29Sbellard #ifdef DEBUG_DISAS 2525d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP) 2526d977e1c2SAlex Bennée && qemu_log_in_addr_range(tb->pc))) { 25271ee73216SRichard Henderson qemu_log_lock(); 252893fcfe39Saliguori qemu_log("OP:\n"); 2529eeacee4dSBlue Swirl tcg_dump_ops(s); 253093fcfe39Saliguori qemu_log("\n"); 25311ee73216SRichard Henderson qemu_log_unlock(); 2532c896fe29Sbellard } 2533c896fe29Sbellard #endif 2534c896fe29Sbellard 2535c5cc28ffSAurelien Jarno #ifdef CONFIG_PROFILER 2536c5cc28ffSAurelien Jarno s->opt_time -= profile_getclock(); 2537c5cc28ffSAurelien Jarno #endif 2538c5cc28ffSAurelien Jarno 25398f2e8c07SKirill Batuzov #ifdef USE_TCG_OPTIMIZATIONS 2540c45cb8bbSRichard Henderson tcg_optimize(s); 25418f2e8c07SKirill Batuzov #endif 25428f2e8c07SKirill Batuzov 2543a23a9ec6Sbellard #ifdef CONFIG_PROFILER 2544c5cc28ffSAurelien Jarno s->opt_time += profile_getclock(); 2545a23a9ec6Sbellard s->la_time -= profile_getclock(); 2546a23a9ec6Sbellard #endif 2547c5cc28ffSAurelien Jarno 25485a18407fSRichard Henderson { 25495a18407fSRichard Henderson uint8_t *temp_state = tcg_malloc(s->nb_temps + s->nb_indirects); 25505a18407fSRichard Henderson 25515a18407fSRichard Henderson liveness_pass_1(s, temp_state); 25525a18407fSRichard Henderson 25535a18407fSRichard Henderson if (s->nb_indirects > 0) { 25545a18407fSRichard Henderson #ifdef DEBUG_DISAS 25555a18407fSRichard Henderson if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND) 25565a18407fSRichard Henderson && qemu_log_in_addr_range(tb->pc))) { 25571ee73216SRichard Henderson qemu_log_lock(); 25585a18407fSRichard Henderson qemu_log("OP before indirect lowering:\n"); 25595a18407fSRichard Henderson tcg_dump_ops(s); 25605a18407fSRichard Henderson qemu_log("\n"); 25611ee73216SRichard Henderson qemu_log_unlock(); 25625a18407fSRichard Henderson } 25635a18407fSRichard Henderson #endif 25645a18407fSRichard Henderson /* Replace indirect temps with direct temps. */ 25655a18407fSRichard Henderson if (liveness_pass_2(s, temp_state)) { 25665a18407fSRichard Henderson /* If changes were made, re-run liveness. */ 25675a18407fSRichard Henderson liveness_pass_1(s, temp_state); 25685a18407fSRichard Henderson } 25695a18407fSRichard Henderson } 25705a18407fSRichard Henderson } 2571c5cc28ffSAurelien Jarno 2572a23a9ec6Sbellard #ifdef CONFIG_PROFILER 2573a23a9ec6Sbellard s->la_time += profile_getclock(); 2574a23a9ec6Sbellard #endif 2575c896fe29Sbellard 2576c896fe29Sbellard #ifdef DEBUG_DISAS 2577d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT) 2578d977e1c2SAlex Bennée && qemu_log_in_addr_range(tb->pc))) { 25791ee73216SRichard Henderson qemu_log_lock(); 2580c5cc28ffSAurelien Jarno qemu_log("OP after optimization and liveness analysis:\n"); 2581eeacee4dSBlue Swirl tcg_dump_ops(s); 258293fcfe39Saliguori qemu_log("\n"); 25831ee73216SRichard Henderson qemu_log_unlock(); 2584c896fe29Sbellard } 2585c896fe29Sbellard #endif 2586c896fe29Sbellard 2587c896fe29Sbellard tcg_reg_alloc_start(s); 2588c896fe29Sbellard 25895bd2ec3dSAlex Bennée s->code_buf = tb->tc_ptr; 25905bd2ec3dSAlex Bennée s->code_ptr = tb->tc_ptr; 2591c896fe29Sbellard 25929ecefc84SRichard Henderson tcg_out_tb_init(s); 25939ecefc84SRichard Henderson 2594fca8a500SRichard Henderson num_insns = -1; 2595dcb8e758SRichard Henderson for (oi = s->gen_op_buf[0].next; oi != 0; oi = oi_next) { 2596c45cb8bbSRichard Henderson TCGOp * const op = &s->gen_op_buf[oi]; 2597c45cb8bbSRichard Henderson TCGArg * const args = &s->gen_opparam_buf[op->args]; 2598c45cb8bbSRichard Henderson TCGOpcode opc = op->opc; 2599c45cb8bbSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 2600bee158cbSRichard Henderson TCGLifeData arg_life = op->life; 2601b3db8758Sblueswir1 2602c45cb8bbSRichard Henderson oi_next = op->next; 2603c896fe29Sbellard #ifdef CONFIG_PROFILER 260454604f74Saurel32 tcg_table_op_count[opc]++; 2605c896fe29Sbellard #endif 2606c45cb8bbSRichard Henderson 2607c896fe29Sbellard switch (opc) { 2608c896fe29Sbellard case INDEX_op_mov_i32: 2609c896fe29Sbellard case INDEX_op_mov_i64: 2610a1b3c48dSRichard Henderson tcg_reg_alloc_mov(s, def, args, arg_life); 2611c896fe29Sbellard break; 2612e8996ee0Sbellard case INDEX_op_movi_i32: 2613e8996ee0Sbellard case INDEX_op_movi_i64: 2614a1b3c48dSRichard Henderson tcg_reg_alloc_movi(s, args, arg_life); 2615e8996ee0Sbellard break; 2616765b842aSRichard Henderson case INDEX_op_insn_start: 2617fca8a500SRichard Henderson if (num_insns >= 0) { 2618fca8a500SRichard Henderson s->gen_insn_end_off[num_insns] = tcg_current_code_size(s); 2619fca8a500SRichard Henderson } 2620fca8a500SRichard Henderson num_insns++; 2621bad729e2SRichard Henderson for (i = 0; i < TARGET_INSN_START_WORDS; ++i) { 2622bad729e2SRichard Henderson target_ulong a; 2623bad729e2SRichard Henderson #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS 2624bad729e2SRichard Henderson a = ((target_ulong)args[i * 2 + 1] << 32) | args[i * 2]; 2625bad729e2SRichard Henderson #else 2626bad729e2SRichard Henderson a = args[i]; 2627bad729e2SRichard Henderson #endif 2628fca8a500SRichard Henderson s->gen_insn_data[num_insns][i] = a; 2629bad729e2SRichard Henderson } 2630c896fe29Sbellard break; 26315ff9d6a4Sbellard case INDEX_op_discard: 2632f8bf00f1SRichard Henderson temp_dead(s, &s->temps[args[0]]); 26335ff9d6a4Sbellard break; 2634c896fe29Sbellard case INDEX_op_set_label: 2635e8996ee0Sbellard tcg_reg_alloc_bb_end(s, s->reserved_regs); 2636bec16311SRichard Henderson tcg_out_label(s, arg_label(args[0]), s->code_ptr); 2637c896fe29Sbellard break; 2638c896fe29Sbellard case INDEX_op_call: 2639a1b3c48dSRichard Henderson tcg_reg_alloc_call(s, op->callo, op->calli, args, arg_life); 2640c45cb8bbSRichard Henderson break; 2641c896fe29Sbellard default: 264225c4d9ccSRichard Henderson /* Sanity check that we've not introduced any unhandled opcodes. */ 264325c4d9ccSRichard Henderson if (def->flags & TCG_OPF_NOT_PRESENT) { 264425c4d9ccSRichard Henderson tcg_abort(); 264525c4d9ccSRichard Henderson } 2646c896fe29Sbellard /* Note: in order to speed up the code, it would be much 2647c896fe29Sbellard faster to have specialized register allocator functions for 2648c896fe29Sbellard some common argument patterns */ 2649a1b3c48dSRichard Henderson tcg_reg_alloc_op(s, def, opc, args, arg_life); 2650c896fe29Sbellard break; 2651c896fe29Sbellard } 26528d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG 2653c896fe29Sbellard check_regs(s); 2654c896fe29Sbellard #endif 2655b125f9dcSRichard Henderson /* Test for (pending) buffer overflow. The assumption is that any 2656b125f9dcSRichard Henderson one operation beginning below the high water mark cannot overrun 2657b125f9dcSRichard Henderson the buffer completely. Thus we can test for overflow after 2658b125f9dcSRichard Henderson generating code without having to check during generation. */ 2659644da9b3SJohn Clarke if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) { 2660b125f9dcSRichard Henderson return -1; 2661b125f9dcSRichard Henderson } 2662c896fe29Sbellard } 2663fca8a500SRichard Henderson tcg_debug_assert(num_insns >= 0); 2664fca8a500SRichard Henderson s->gen_insn_end_off[num_insns] = tcg_current_code_size(s); 2665c45cb8bbSRichard Henderson 2666b76f0d8cSYeongkyoon Lee /* Generate TB finalization at the end of block */ 266723dceda6SRichard Henderson if (!tcg_out_tb_finalize(s)) { 266823dceda6SRichard Henderson return -1; 266923dceda6SRichard Henderson } 2670c896fe29Sbellard 2671c896fe29Sbellard /* flush instruction cache */ 26721813e175SRichard Henderson flush_icache_range((uintptr_t)s->code_buf, (uintptr_t)s->code_ptr); 26732aeabc08SStefan Weil 26741813e175SRichard Henderson return tcg_current_code_size(s); 2675c896fe29Sbellard } 2676c896fe29Sbellard 2677a23a9ec6Sbellard #ifdef CONFIG_PROFILER 2678405cf9ffSStefan Weil void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf) 2679a23a9ec6Sbellard { 2680a23a9ec6Sbellard TCGContext *s = &tcg_ctx; 2681fca8a500SRichard Henderson int64_t tb_count = s->tb_count; 2682fca8a500SRichard Henderson int64_t tb_div_count = tb_count ? tb_count : 1; 2683fca8a500SRichard Henderson int64_t tot = s->interm_time + s->code_time; 2684a23a9ec6Sbellard 2685a23a9ec6Sbellard cpu_fprintf(f, "JIT cycles %" PRId64 " (%0.3f s at 2.4 GHz)\n", 2686a23a9ec6Sbellard tot, tot / 2.4e9); 2687a23a9ec6Sbellard cpu_fprintf(f, "translated TBs %" PRId64 " (aborted=%" PRId64 " %0.1f%%)\n", 2688fca8a500SRichard Henderson tb_count, s->tb_count1 - tb_count, 2689fca8a500SRichard Henderson (double)(s->tb_count1 - s->tb_count) 2690fca8a500SRichard Henderson / (s->tb_count1 ? s->tb_count1 : 1) * 100.0); 2691a23a9ec6Sbellard cpu_fprintf(f, "avg ops/TB %0.1f max=%d\n", 2692fca8a500SRichard Henderson (double)s->op_count / tb_div_count, s->op_count_max); 2693a23a9ec6Sbellard cpu_fprintf(f, "deleted ops/TB %0.2f\n", 2694fca8a500SRichard Henderson (double)s->del_op_count / tb_div_count); 2695a23a9ec6Sbellard cpu_fprintf(f, "avg temps/TB %0.2f max=%d\n", 2696fca8a500SRichard Henderson (double)s->temp_count / tb_div_count, s->temp_count_max); 2697fca8a500SRichard Henderson cpu_fprintf(f, "avg host code/TB %0.1f\n", 2698fca8a500SRichard Henderson (double)s->code_out_len / tb_div_count); 2699fca8a500SRichard Henderson cpu_fprintf(f, "avg search data/TB %0.1f\n", 2700fca8a500SRichard Henderson (double)s->search_out_len / tb_div_count); 2701a23a9ec6Sbellard 2702a23a9ec6Sbellard cpu_fprintf(f, "cycles/op %0.1f\n", 2703a23a9ec6Sbellard s->op_count ? (double)tot / s->op_count : 0); 2704a23a9ec6Sbellard cpu_fprintf(f, "cycles/in byte %0.1f\n", 2705a23a9ec6Sbellard s->code_in_len ? (double)tot / s->code_in_len : 0); 2706a23a9ec6Sbellard cpu_fprintf(f, "cycles/out byte %0.1f\n", 2707a23a9ec6Sbellard s->code_out_len ? (double)tot / s->code_out_len : 0); 2708fca8a500SRichard Henderson cpu_fprintf(f, "cycles/search byte %0.1f\n", 2709fca8a500SRichard Henderson s->search_out_len ? (double)tot / s->search_out_len : 0); 2710fca8a500SRichard Henderson if (tot == 0) { 2711a23a9ec6Sbellard tot = 1; 2712fca8a500SRichard Henderson } 2713a23a9ec6Sbellard cpu_fprintf(f, " gen_interm time %0.1f%%\n", 2714a23a9ec6Sbellard (double)s->interm_time / tot * 100.0); 2715a23a9ec6Sbellard cpu_fprintf(f, " gen_code time %0.1f%%\n", 2716a23a9ec6Sbellard (double)s->code_time / tot * 100.0); 2717c5cc28ffSAurelien Jarno cpu_fprintf(f, "optim./code time %0.1f%%\n", 2718c5cc28ffSAurelien Jarno (double)s->opt_time / (s->code_time ? s->code_time : 1) 2719c5cc28ffSAurelien Jarno * 100.0); 2720a23a9ec6Sbellard cpu_fprintf(f, "liveness/code time %0.1f%%\n", 2721a23a9ec6Sbellard (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0); 2722a23a9ec6Sbellard cpu_fprintf(f, "cpu_restore count %" PRId64 "\n", 2723a23a9ec6Sbellard s->restore_count); 2724a23a9ec6Sbellard cpu_fprintf(f, " avg cycles %0.1f\n", 2725a23a9ec6Sbellard s->restore_count ? (double)s->restore_time / s->restore_count : 0); 2726a23a9ec6Sbellard } 2727a23a9ec6Sbellard #else 2728405cf9ffSStefan Weil void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf) 2729a23a9ec6Sbellard { 273024bf7b3aSbellard cpu_fprintf(f, "[TCG profiler not compiled]\n"); 2731a23a9ec6Sbellard } 2732a23a9ec6Sbellard #endif 2733813da627SRichard Henderson 2734813da627SRichard Henderson #ifdef ELF_HOST_MACHINE 27355872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things: 27365872bbf2SRichard Henderson 27375872bbf2SRichard Henderson (1) Define ELF_HOST_MACHINE to indicate both what value to 27385872bbf2SRichard Henderson put into the ELF image and to indicate support for the feature. 27395872bbf2SRichard Henderson 27405872bbf2SRichard Henderson (2) Define tcg_register_jit. This should create a buffer containing 27415872bbf2SRichard Henderson the contents of a .debug_frame section that describes the post- 27425872bbf2SRichard Henderson prologue unwind info for the tcg machine. 27435872bbf2SRichard Henderson 27445872bbf2SRichard Henderson (3) Call tcg_register_jit_int, with the constructed .debug_frame. 27455872bbf2SRichard Henderson */ 2746813da627SRichard Henderson 2747813da627SRichard Henderson /* Begin GDB interface. THE FOLLOWING MUST MATCH GDB DOCS. */ 2748813da627SRichard Henderson typedef enum { 2749813da627SRichard Henderson JIT_NOACTION = 0, 2750813da627SRichard Henderson JIT_REGISTER_FN, 2751813da627SRichard Henderson JIT_UNREGISTER_FN 2752813da627SRichard Henderson } jit_actions_t; 2753813da627SRichard Henderson 2754813da627SRichard Henderson struct jit_code_entry { 2755813da627SRichard Henderson struct jit_code_entry *next_entry; 2756813da627SRichard Henderson struct jit_code_entry *prev_entry; 2757813da627SRichard Henderson const void *symfile_addr; 2758813da627SRichard Henderson uint64_t symfile_size; 2759813da627SRichard Henderson }; 2760813da627SRichard Henderson 2761813da627SRichard Henderson struct jit_descriptor { 2762813da627SRichard Henderson uint32_t version; 2763813da627SRichard Henderson uint32_t action_flag; 2764813da627SRichard Henderson struct jit_code_entry *relevant_entry; 2765813da627SRichard Henderson struct jit_code_entry *first_entry; 2766813da627SRichard Henderson }; 2767813da627SRichard Henderson 2768813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline)); 2769813da627SRichard Henderson void __jit_debug_register_code(void) 2770813da627SRichard Henderson { 2771813da627SRichard Henderson asm(""); 2772813da627SRichard Henderson } 2773813da627SRichard Henderson 2774813da627SRichard Henderson /* Must statically initialize the version, because GDB may check 2775813da627SRichard Henderson the version before we can set it. */ 2776813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 }; 2777813da627SRichard Henderson 2778813da627SRichard Henderson /* End GDB interface. */ 2779813da627SRichard Henderson 2780813da627SRichard Henderson static int find_string(const char *strtab, const char *str) 2781813da627SRichard Henderson { 2782813da627SRichard Henderson const char *p = strtab + 1; 2783813da627SRichard Henderson 2784813da627SRichard Henderson while (1) { 2785813da627SRichard Henderson if (strcmp(p, str) == 0) { 2786813da627SRichard Henderson return p - strtab; 2787813da627SRichard Henderson } 2788813da627SRichard Henderson p += strlen(p) + 1; 2789813da627SRichard Henderson } 2790813da627SRichard Henderson } 2791813da627SRichard Henderson 27925872bbf2SRichard Henderson static void tcg_register_jit_int(void *buf_ptr, size_t buf_size, 27932c90784aSRichard Henderson const void *debug_frame, 27942c90784aSRichard Henderson size_t debug_frame_size) 2795813da627SRichard Henderson { 27965872bbf2SRichard Henderson struct __attribute__((packed)) DebugInfo { 27975872bbf2SRichard Henderson uint32_t len; 27985872bbf2SRichard Henderson uint16_t version; 27995872bbf2SRichard Henderson uint32_t abbrev; 28005872bbf2SRichard Henderson uint8_t ptr_size; 28015872bbf2SRichard Henderson uint8_t cu_die; 28025872bbf2SRichard Henderson uint16_t cu_lang; 28035872bbf2SRichard Henderson uintptr_t cu_low_pc; 28045872bbf2SRichard Henderson uintptr_t cu_high_pc; 28055872bbf2SRichard Henderson uint8_t fn_die; 28065872bbf2SRichard Henderson char fn_name[16]; 28075872bbf2SRichard Henderson uintptr_t fn_low_pc; 28085872bbf2SRichard Henderson uintptr_t fn_high_pc; 28095872bbf2SRichard Henderson uint8_t cu_eoc; 28105872bbf2SRichard Henderson }; 2811813da627SRichard Henderson 2812813da627SRichard Henderson struct ElfImage { 2813813da627SRichard Henderson ElfW(Ehdr) ehdr; 2814813da627SRichard Henderson ElfW(Phdr) phdr; 28155872bbf2SRichard Henderson ElfW(Shdr) shdr[7]; 28165872bbf2SRichard Henderson ElfW(Sym) sym[2]; 28175872bbf2SRichard Henderson struct DebugInfo di; 28185872bbf2SRichard Henderson uint8_t da[24]; 28195872bbf2SRichard Henderson char str[80]; 28205872bbf2SRichard Henderson }; 28215872bbf2SRichard Henderson 28225872bbf2SRichard Henderson struct ElfImage *img; 28235872bbf2SRichard Henderson 28245872bbf2SRichard Henderson static const struct ElfImage img_template = { 28255872bbf2SRichard Henderson .ehdr = { 28265872bbf2SRichard Henderson .e_ident[EI_MAG0] = ELFMAG0, 28275872bbf2SRichard Henderson .e_ident[EI_MAG1] = ELFMAG1, 28285872bbf2SRichard Henderson .e_ident[EI_MAG2] = ELFMAG2, 28295872bbf2SRichard Henderson .e_ident[EI_MAG3] = ELFMAG3, 28305872bbf2SRichard Henderson .e_ident[EI_CLASS] = ELF_CLASS, 28315872bbf2SRichard Henderson .e_ident[EI_DATA] = ELF_DATA, 28325872bbf2SRichard Henderson .e_ident[EI_VERSION] = EV_CURRENT, 28335872bbf2SRichard Henderson .e_type = ET_EXEC, 28345872bbf2SRichard Henderson .e_machine = ELF_HOST_MACHINE, 28355872bbf2SRichard Henderson .e_version = EV_CURRENT, 28365872bbf2SRichard Henderson .e_phoff = offsetof(struct ElfImage, phdr), 28375872bbf2SRichard Henderson .e_shoff = offsetof(struct ElfImage, shdr), 28385872bbf2SRichard Henderson .e_ehsize = sizeof(ElfW(Shdr)), 28395872bbf2SRichard Henderson .e_phentsize = sizeof(ElfW(Phdr)), 28405872bbf2SRichard Henderson .e_phnum = 1, 28415872bbf2SRichard Henderson .e_shentsize = sizeof(ElfW(Shdr)), 28425872bbf2SRichard Henderson .e_shnum = ARRAY_SIZE(img->shdr), 28435872bbf2SRichard Henderson .e_shstrndx = ARRAY_SIZE(img->shdr) - 1, 2844abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS 2845abbb3eaeSRichard Henderson .e_flags = ELF_HOST_FLAGS, 2846abbb3eaeSRichard Henderson #endif 2847abbb3eaeSRichard Henderson #ifdef ELF_OSABI 2848abbb3eaeSRichard Henderson .e_ident[EI_OSABI] = ELF_OSABI, 2849abbb3eaeSRichard Henderson #endif 28505872bbf2SRichard Henderson }, 28515872bbf2SRichard Henderson .phdr = { 28525872bbf2SRichard Henderson .p_type = PT_LOAD, 28535872bbf2SRichard Henderson .p_flags = PF_X, 28545872bbf2SRichard Henderson }, 28555872bbf2SRichard Henderson .shdr = { 28565872bbf2SRichard Henderson [0] = { .sh_type = SHT_NULL }, 28575872bbf2SRichard Henderson /* Trick: The contents of code_gen_buffer are not present in 28585872bbf2SRichard Henderson this fake ELF file; that got allocated elsewhere. Therefore 28595872bbf2SRichard Henderson we mark .text as SHT_NOBITS (similar to .bss) so that readers 28605872bbf2SRichard Henderson will not look for contents. We can record any address. */ 28615872bbf2SRichard Henderson [1] = { /* .text */ 28625872bbf2SRichard Henderson .sh_type = SHT_NOBITS, 28635872bbf2SRichard Henderson .sh_flags = SHF_EXECINSTR | SHF_ALLOC, 28645872bbf2SRichard Henderson }, 28655872bbf2SRichard Henderson [2] = { /* .debug_info */ 28665872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 28675872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, di), 28685872bbf2SRichard Henderson .sh_size = sizeof(struct DebugInfo), 28695872bbf2SRichard Henderson }, 28705872bbf2SRichard Henderson [3] = { /* .debug_abbrev */ 28715872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 28725872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, da), 28735872bbf2SRichard Henderson .sh_size = sizeof(img->da), 28745872bbf2SRichard Henderson }, 28755872bbf2SRichard Henderson [4] = { /* .debug_frame */ 28765872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 28775872bbf2SRichard Henderson .sh_offset = sizeof(struct ElfImage), 28785872bbf2SRichard Henderson }, 28795872bbf2SRichard Henderson [5] = { /* .symtab */ 28805872bbf2SRichard Henderson .sh_type = SHT_SYMTAB, 28815872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, sym), 28825872bbf2SRichard Henderson .sh_size = sizeof(img->sym), 28835872bbf2SRichard Henderson .sh_info = 1, 28845872bbf2SRichard Henderson .sh_link = ARRAY_SIZE(img->shdr) - 1, 28855872bbf2SRichard Henderson .sh_entsize = sizeof(ElfW(Sym)), 28865872bbf2SRichard Henderson }, 28875872bbf2SRichard Henderson [6] = { /* .strtab */ 28885872bbf2SRichard Henderson .sh_type = SHT_STRTAB, 28895872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, str), 28905872bbf2SRichard Henderson .sh_size = sizeof(img->str), 28915872bbf2SRichard Henderson } 28925872bbf2SRichard Henderson }, 28935872bbf2SRichard Henderson .sym = { 28945872bbf2SRichard Henderson [1] = { /* code_gen_buffer */ 28955872bbf2SRichard Henderson .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC), 28965872bbf2SRichard Henderson .st_shndx = 1, 28975872bbf2SRichard Henderson } 28985872bbf2SRichard Henderson }, 28995872bbf2SRichard Henderson .di = { 29005872bbf2SRichard Henderson .len = sizeof(struct DebugInfo) - 4, 29015872bbf2SRichard Henderson .version = 2, 29025872bbf2SRichard Henderson .ptr_size = sizeof(void *), 29035872bbf2SRichard Henderson .cu_die = 1, 29045872bbf2SRichard Henderson .cu_lang = 0x8001, /* DW_LANG_Mips_Assembler */ 29055872bbf2SRichard Henderson .fn_die = 2, 29065872bbf2SRichard Henderson .fn_name = "code_gen_buffer" 29075872bbf2SRichard Henderson }, 29085872bbf2SRichard Henderson .da = { 29095872bbf2SRichard Henderson 1, /* abbrev number (the cu) */ 29105872bbf2SRichard Henderson 0x11, 1, /* DW_TAG_compile_unit, has children */ 29115872bbf2SRichard Henderson 0x13, 0x5, /* DW_AT_language, DW_FORM_data2 */ 29125872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */ 29135872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */ 29145872bbf2SRichard Henderson 0, 0, /* end of abbrev */ 29155872bbf2SRichard Henderson 2, /* abbrev number (the fn) */ 29165872bbf2SRichard Henderson 0x2e, 0, /* DW_TAG_subprogram, no children */ 29175872bbf2SRichard Henderson 0x3, 0x8, /* DW_AT_name, DW_FORM_string */ 29185872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */ 29195872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */ 29205872bbf2SRichard Henderson 0, 0, /* end of abbrev */ 29215872bbf2SRichard Henderson 0 /* no more abbrev */ 29225872bbf2SRichard Henderson }, 29235872bbf2SRichard Henderson .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0" 29245872bbf2SRichard Henderson ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer", 2925813da627SRichard Henderson }; 2926813da627SRichard Henderson 2927813da627SRichard Henderson /* We only need a single jit entry; statically allocate it. */ 2928813da627SRichard Henderson static struct jit_code_entry one_entry; 2929813da627SRichard Henderson 29305872bbf2SRichard Henderson uintptr_t buf = (uintptr_t)buf_ptr; 2931813da627SRichard Henderson size_t img_size = sizeof(struct ElfImage) + debug_frame_size; 29322c90784aSRichard Henderson DebugFrameHeader *dfh; 2933813da627SRichard Henderson 29345872bbf2SRichard Henderson img = g_malloc(img_size); 29355872bbf2SRichard Henderson *img = img_template; 2936813da627SRichard Henderson 29375872bbf2SRichard Henderson img->phdr.p_vaddr = buf; 29385872bbf2SRichard Henderson img->phdr.p_paddr = buf; 29395872bbf2SRichard Henderson img->phdr.p_memsz = buf_size; 2940813da627SRichard Henderson 29415872bbf2SRichard Henderson img->shdr[1].sh_name = find_string(img->str, ".text"); 29425872bbf2SRichard Henderson img->shdr[1].sh_addr = buf; 29435872bbf2SRichard Henderson img->shdr[1].sh_size = buf_size; 2944813da627SRichard Henderson 29455872bbf2SRichard Henderson img->shdr[2].sh_name = find_string(img->str, ".debug_info"); 29465872bbf2SRichard Henderson img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev"); 29475872bbf2SRichard Henderson 29485872bbf2SRichard Henderson img->shdr[4].sh_name = find_string(img->str, ".debug_frame"); 29495872bbf2SRichard Henderson img->shdr[4].sh_size = debug_frame_size; 29505872bbf2SRichard Henderson 29515872bbf2SRichard Henderson img->shdr[5].sh_name = find_string(img->str, ".symtab"); 29525872bbf2SRichard Henderson img->shdr[6].sh_name = find_string(img->str, ".strtab"); 29535872bbf2SRichard Henderson 29545872bbf2SRichard Henderson img->sym[1].st_name = find_string(img->str, "code_gen_buffer"); 29555872bbf2SRichard Henderson img->sym[1].st_value = buf; 29565872bbf2SRichard Henderson img->sym[1].st_size = buf_size; 29575872bbf2SRichard Henderson 29585872bbf2SRichard Henderson img->di.cu_low_pc = buf; 295945aba097SRichard Henderson img->di.cu_high_pc = buf + buf_size; 29605872bbf2SRichard Henderson img->di.fn_low_pc = buf; 296145aba097SRichard Henderson img->di.fn_high_pc = buf + buf_size; 2962813da627SRichard Henderson 29632c90784aSRichard Henderson dfh = (DebugFrameHeader *)(img + 1); 29642c90784aSRichard Henderson memcpy(dfh, debug_frame, debug_frame_size); 29652c90784aSRichard Henderson dfh->fde.func_start = buf; 29662c90784aSRichard Henderson dfh->fde.func_len = buf_size; 29672c90784aSRichard Henderson 2968813da627SRichard Henderson #ifdef DEBUG_JIT 2969813da627SRichard Henderson /* Enable this block to be able to debug the ELF image file creation. 2970813da627SRichard Henderson One can use readelf, objdump, or other inspection utilities. */ 2971813da627SRichard Henderson { 2972813da627SRichard Henderson FILE *f = fopen("/tmp/qemu.jit", "w+b"); 2973813da627SRichard Henderson if (f) { 29745872bbf2SRichard Henderson if (fwrite(img, img_size, 1, f) != img_size) { 2975813da627SRichard Henderson /* Avoid stupid unused return value warning for fwrite. */ 2976813da627SRichard Henderson } 2977813da627SRichard Henderson fclose(f); 2978813da627SRichard Henderson } 2979813da627SRichard Henderson } 2980813da627SRichard Henderson #endif 2981813da627SRichard Henderson 2982813da627SRichard Henderson one_entry.symfile_addr = img; 2983813da627SRichard Henderson one_entry.symfile_size = img_size; 2984813da627SRichard Henderson 2985813da627SRichard Henderson __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; 2986813da627SRichard Henderson __jit_debug_descriptor.relevant_entry = &one_entry; 2987813da627SRichard Henderson __jit_debug_descriptor.first_entry = &one_entry; 2988813da627SRichard Henderson __jit_debug_register_code(); 2989813da627SRichard Henderson } 2990813da627SRichard Henderson #else 29915872bbf2SRichard Henderson /* No support for the feature. Provide the entry point expected by exec.c, 29925872bbf2SRichard Henderson and implement the internal function we declared earlier. */ 2993813da627SRichard Henderson 2994813da627SRichard Henderson static void tcg_register_jit_int(void *buf, size_t size, 29952c90784aSRichard Henderson const void *debug_frame, 29962c90784aSRichard Henderson size_t debug_frame_size) 2997813da627SRichard Henderson { 2998813da627SRichard Henderson } 2999813da627SRichard Henderson 3000813da627SRichard Henderson void tcg_register_jit(void *buf, size_t buf_size) 3001813da627SRichard Henderson { 3002813da627SRichard Henderson } 3003813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */ 3004