1c896fe29Sbellard /* 2c896fe29Sbellard * Tiny Code Generator for QEMU 3c896fe29Sbellard * 4c896fe29Sbellard * Copyright (c) 2008 Fabrice Bellard 5c896fe29Sbellard * 6c896fe29Sbellard * Permission is hereby granted, free of charge, to any person obtaining a copy 7c896fe29Sbellard * of this software and associated documentation files (the "Software"), to deal 8c896fe29Sbellard * in the Software without restriction, including without limitation the rights 9c896fe29Sbellard * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10c896fe29Sbellard * copies of the Software, and to permit persons to whom the Software is 11c896fe29Sbellard * furnished to do so, subject to the following conditions: 12c896fe29Sbellard * 13c896fe29Sbellard * The above copyright notice and this permission notice shall be included in 14c896fe29Sbellard * all copies or substantial portions of the Software. 15c896fe29Sbellard * 16c896fe29Sbellard * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17c896fe29Sbellard * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18c896fe29Sbellard * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19c896fe29Sbellard * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20c896fe29Sbellard * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21c896fe29Sbellard * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22c896fe29Sbellard * THE SOFTWARE. 23c896fe29Sbellard */ 24c896fe29Sbellard 25c896fe29Sbellard /* define it to use liveness analysis (better code) */ 268f2e8c07SKirill Batuzov #define USE_TCG_OPTIMIZATIONS 27c896fe29Sbellard 28757e725bSPeter Maydell #include "qemu/osdep.h" 29cca82982Saurel32 30813da627SRichard Henderson /* Define to jump the ELF file used to communicate with GDB. */ 31813da627SRichard Henderson #undef DEBUG_JIT 32813da627SRichard Henderson 3372fd2efbSEmilio G. Cota #include "qemu/error-report.h" 34f348b6d1SVeronia Bahaa #include "qemu/cutils.h" 351de7afc9SPaolo Bonzini #include "qemu/host-utils.h" 36d4c51a0aSMarkus Armbruster #include "qemu/qemu-print.h" 371de7afc9SPaolo Bonzini #include "qemu/timer.h" 38084cfca1SRichard Henderson #include "qemu/cacheflush.h" 39ad768e6fSPeter Maydell #include "qemu/cacheinfo.h" 40c896fe29Sbellard 41c5d3c498SStefan Weil /* Note: the long term plan is to reduce the dependencies on the QEMU 42c896fe29Sbellard CPU definitions. Currently they are used for qemu_ld/st 43c896fe29Sbellard instructions */ 44c896fe29Sbellard #define NO_CPU_IO_DEFS 45c896fe29Sbellard 4663c91552SPaolo Bonzini #include "exec/exec-all.h" 47dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h" 48813da627SRichard Henderson 49edee2579SRichard Henderson #if UINTPTR_MAX == UINT32_MAX 50813da627SRichard Henderson # define ELF_CLASS ELFCLASS32 51edee2579SRichard Henderson #else 52edee2579SRichard Henderson # define ELF_CLASS ELFCLASS64 53813da627SRichard Henderson #endif 54e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN 55813da627SRichard Henderson # define ELF_DATA ELFDATA2MSB 56813da627SRichard Henderson #else 57813da627SRichard Henderson # define ELF_DATA ELFDATA2LSB 58813da627SRichard Henderson #endif 59813da627SRichard Henderson 60c896fe29Sbellard #include "elf.h" 61508127e2SPaolo Bonzini #include "exec/log.h" 62d2ba8026SRichard Henderson #include "tcg/tcg-ldst.h" 635ff7258cSRichard Henderson #include "tcg-internal.h" 645584e2dbSIlya Leoshkevich #include "accel/tcg/perf.h" 65c896fe29Sbellard 66139c1837SPaolo Bonzini /* Forward declarations for functions declared in tcg-target.c.inc and 67ce151109SPeter Maydell used here. */ 68e4d58b41SRichard Henderson static void tcg_target_init(TCGContext *s); 69e4d58b41SRichard Henderson static void tcg_target_qemu_prologue(TCGContext *s); 706ac17786SRichard Henderson static bool patch_reloc(tcg_insn_unit *code_ptr, int type, 712ba7fae2SRichard Henderson intptr_t value, intptr_t addend); 72c896fe29Sbellard 73497a22ebSRichard Henderson /* The CIE and FDE header definitions will be common to all hosts. */ 74497a22ebSRichard Henderson typedef struct { 75497a22ebSRichard Henderson uint32_t len __attribute__((aligned((sizeof(void *))))); 76497a22ebSRichard Henderson uint32_t id; 77497a22ebSRichard Henderson uint8_t version; 78497a22ebSRichard Henderson char augmentation[1]; 79497a22ebSRichard Henderson uint8_t code_align; 80497a22ebSRichard Henderson uint8_t data_align; 81497a22ebSRichard Henderson uint8_t return_column; 82497a22ebSRichard Henderson } DebugFrameCIE; 83497a22ebSRichard Henderson 84497a22ebSRichard Henderson typedef struct QEMU_PACKED { 85497a22ebSRichard Henderson uint32_t len __attribute__((aligned((sizeof(void *))))); 86497a22ebSRichard Henderson uint32_t cie_offset; 87edee2579SRichard Henderson uintptr_t func_start; 88edee2579SRichard Henderson uintptr_t func_len; 89497a22ebSRichard Henderson } DebugFrameFDEHeader; 90497a22ebSRichard Henderson 912c90784aSRichard Henderson typedef struct QEMU_PACKED { 922c90784aSRichard Henderson DebugFrameCIE cie; 932c90784aSRichard Henderson DebugFrameFDEHeader fde; 942c90784aSRichard Henderson } DebugFrameHeader; 952c90784aSRichard Henderson 96755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size, 972c90784aSRichard Henderson const void *debug_frame, 982c90784aSRichard Henderson size_t debug_frame_size) 99813da627SRichard Henderson __attribute__((unused)); 100813da627SRichard Henderson 101139c1837SPaolo Bonzini /* Forward declarations for functions declared and used in tcg-target.c.inc. */ 1022a534affSRichard Henderson static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1, 103a05b5b9bSRichard Henderson intptr_t arg2); 10478113e83SRichard Henderson static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg); 105c0ad3001SStefan Weil static void tcg_out_movi(TCGContext *s, TCGType type, 1062a534affSRichard Henderson TCGReg ret, tcg_target_long arg); 107b55a8d9dSRichard Henderson static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg); 1085e8892dbSMiroslav Rezanina static void tcg_out_op(TCGContext *s, TCGOpcode opc, 1095e8892dbSMiroslav Rezanina const TCGArg args[TCG_MAX_OP_ARGS], 1105e8892dbSMiroslav Rezanina const int const_args[TCG_MAX_OP_ARGS]); 111d2fd745fSRichard Henderson #if TCG_TARGET_MAYBE_vec 112e7632cfaSRichard Henderson static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece, 113e7632cfaSRichard Henderson TCGReg dst, TCGReg src); 114d6ecb4a9SRichard Henderson static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece, 115d6ecb4a9SRichard Henderson TCGReg dst, TCGReg base, intptr_t offset); 1164e186175SRichard Henderson static void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece, 1174e186175SRichard Henderson TCGReg dst, int64_t arg); 1185e8892dbSMiroslav Rezanina static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, 1195e8892dbSMiroslav Rezanina unsigned vecl, unsigned vece, 1205e8892dbSMiroslav Rezanina const TCGArg args[TCG_MAX_OP_ARGS], 1215e8892dbSMiroslav Rezanina const int const_args[TCG_MAX_OP_ARGS]); 122d2fd745fSRichard Henderson #else 123e7632cfaSRichard Henderson static inline bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece, 124e7632cfaSRichard Henderson TCGReg dst, TCGReg src) 125e7632cfaSRichard Henderson { 126e7632cfaSRichard Henderson g_assert_not_reached(); 127e7632cfaSRichard Henderson } 128d6ecb4a9SRichard Henderson static inline bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece, 129d6ecb4a9SRichard Henderson TCGReg dst, TCGReg base, intptr_t offset) 130d6ecb4a9SRichard Henderson { 131d6ecb4a9SRichard Henderson g_assert_not_reached(); 132d6ecb4a9SRichard Henderson } 1334e186175SRichard Henderson static inline void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece, 1344e186175SRichard Henderson TCGReg dst, int64_t arg) 135e7632cfaSRichard Henderson { 136e7632cfaSRichard Henderson g_assert_not_reached(); 137e7632cfaSRichard Henderson } 1385e8892dbSMiroslav Rezanina static inline void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, 1395e8892dbSMiroslav Rezanina unsigned vecl, unsigned vece, 1405e8892dbSMiroslav Rezanina const TCGArg args[TCG_MAX_OP_ARGS], 1415e8892dbSMiroslav Rezanina const int const_args[TCG_MAX_OP_ARGS]) 142d2fd745fSRichard Henderson { 143d2fd745fSRichard Henderson g_assert_not_reached(); 144d2fd745fSRichard Henderson } 145d2fd745fSRichard Henderson #endif 1462a534affSRichard Henderson static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1, 147a05b5b9bSRichard Henderson intptr_t arg2); 14859d7c14eSRichard Henderson static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val, 14959d7c14eSRichard Henderson TCGReg base, intptr_t ofs); 1507b7d8b2dSRichard Henderson static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target, 151cee44b03SRichard Henderson const TCGHelperInfo *info); 152a4fbbd77SRichard Henderson static bool tcg_target_const_match(int64_t val, TCGType type, int ct); 153659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS 154aeee05f5SRichard Henderson static int tcg_out_ldst_finalize(TCGContext *s); 155659ef5cbSRichard Henderson #endif 156c896fe29Sbellard 15742eb6dfcSRichard Henderson TCGContext tcg_init_ctx; 15842eb6dfcSRichard Henderson __thread TCGContext *tcg_ctx; 15942eb6dfcSRichard Henderson 1605ff7258cSRichard Henderson TCGContext **tcg_ctxs; 1610e2d61cfSRichard Henderson unsigned int tcg_cur_ctxs; 1620e2d61cfSRichard Henderson unsigned int tcg_max_ctxs; 1631c2adb95SRichard Henderson TCGv_env cpu_env = 0; 164c8bc1168SRichard Henderson const void *tcg_code_gen_epilogue; 165db0c51a3SRichard Henderson uintptr_t tcg_splitwx_diff; 166df2cce29SEmilio G. Cota 167b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 168b91ccb31SRichard Henderson tcg_prologue_fn *tcg_qemu_tb_exec; 169b91ccb31SRichard Henderson #endif 170b91ccb31SRichard Henderson 171d2fd745fSRichard Henderson static TCGRegSet tcg_target_available_regs[TCG_TYPE_COUNT]; 172b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs; 173c896fe29Sbellard 1741813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1 1754196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v) 176c896fe29Sbellard { 177c896fe29Sbellard *s->code_ptr++ = v; 178c896fe29Sbellard } 179c896fe29Sbellard 1804196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p, 1814196dca6SPeter Maydell uint8_t v) 1825c53bb81SPeter Maydell { 1831813e175SRichard Henderson *p = v; 1845c53bb81SPeter Maydell } 1851813e175SRichard Henderson #endif 1865c53bb81SPeter Maydell 1871813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2 1884196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v) 189c896fe29Sbellard { 1901813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 2) { 1911813e175SRichard Henderson *s->code_ptr++ = v; 1921813e175SRichard Henderson } else { 1931813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 1944387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 1951813e175SRichard Henderson s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE); 1961813e175SRichard Henderson } 197c896fe29Sbellard } 198c896fe29Sbellard 1994196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p, 2004196dca6SPeter Maydell uint16_t v) 2015c53bb81SPeter Maydell { 2021813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 2) { 2031813e175SRichard Henderson *p = v; 2041813e175SRichard Henderson } else { 2055c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 2065c53bb81SPeter Maydell } 2071813e175SRichard Henderson } 2081813e175SRichard Henderson #endif 2095c53bb81SPeter Maydell 2101813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4 2114196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v) 212c896fe29Sbellard { 2131813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 4) { 2141813e175SRichard Henderson *s->code_ptr++ = v; 2151813e175SRichard Henderson } else { 2161813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 2174387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 2181813e175SRichard Henderson s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE); 2191813e175SRichard Henderson } 220c896fe29Sbellard } 221c896fe29Sbellard 2224196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p, 2234196dca6SPeter Maydell uint32_t v) 2245c53bb81SPeter Maydell { 2251813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 4) { 2261813e175SRichard Henderson *p = v; 2271813e175SRichard Henderson } else { 2285c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 2295c53bb81SPeter Maydell } 2301813e175SRichard Henderson } 2311813e175SRichard Henderson #endif 2325c53bb81SPeter Maydell 2331813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 8 2344196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v) 235ac26eb69SRichard Henderson { 2361813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 8) { 2371813e175SRichard Henderson *s->code_ptr++ = v; 2381813e175SRichard Henderson } else { 2391813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 2404387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 2411813e175SRichard Henderson s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE); 2421813e175SRichard Henderson } 243ac26eb69SRichard Henderson } 244ac26eb69SRichard Henderson 2454196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p, 2464196dca6SPeter Maydell uint64_t v) 2475c53bb81SPeter Maydell { 2481813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 8) { 2491813e175SRichard Henderson *p = v; 2501813e175SRichard Henderson } else { 2515c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 2525c53bb81SPeter Maydell } 2531813e175SRichard Henderson } 2541813e175SRichard Henderson #endif 2555c53bb81SPeter Maydell 256c896fe29Sbellard /* label relocation processing */ 257c896fe29Sbellard 2581813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type, 259bec16311SRichard Henderson TCGLabel *l, intptr_t addend) 260c896fe29Sbellard { 2617ecd02a0SRichard Henderson TCGRelocation *r = tcg_malloc(sizeof(TCGRelocation)); 262c896fe29Sbellard 263c896fe29Sbellard r->type = type; 264c896fe29Sbellard r->ptr = code_ptr; 265c896fe29Sbellard r->addend = addend; 2667ecd02a0SRichard Henderson QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next); 267c896fe29Sbellard } 268c896fe29Sbellard 26992ab8e7dSRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l) 270c896fe29Sbellard { 271eabb7b91SAurelien Jarno tcg_debug_assert(!l->has_value); 272c896fe29Sbellard l->has_value = 1; 27392ab8e7dSRichard Henderson l->u.value_ptr = tcg_splitwx_to_rx(s->code_ptr); 274c896fe29Sbellard } 275c896fe29Sbellard 27642a268c2SRichard Henderson TCGLabel *gen_new_label(void) 277c896fe29Sbellard { 278b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 27951e3972cSRichard Henderson TCGLabel *l = tcg_malloc(sizeof(TCGLabel)); 280c896fe29Sbellard 2817ecd02a0SRichard Henderson memset(l, 0, sizeof(TCGLabel)); 2827ecd02a0SRichard Henderson l->id = s->nb_labels++; 2837ecd02a0SRichard Henderson QSIMPLEQ_INIT(&l->relocs); 2847ecd02a0SRichard Henderson 285bef16ab4SRichard Henderson QSIMPLEQ_INSERT_TAIL(&s->labels, l, next); 28642a268c2SRichard Henderson 28742a268c2SRichard Henderson return l; 288c896fe29Sbellard } 289c896fe29Sbellard 2907ecd02a0SRichard Henderson static bool tcg_resolve_relocs(TCGContext *s) 2917ecd02a0SRichard Henderson { 2927ecd02a0SRichard Henderson TCGLabel *l; 2937ecd02a0SRichard Henderson 2947ecd02a0SRichard Henderson QSIMPLEQ_FOREACH(l, &s->labels, next) { 2957ecd02a0SRichard Henderson TCGRelocation *r; 2967ecd02a0SRichard Henderson uintptr_t value = l->u.value; 2977ecd02a0SRichard Henderson 2987ecd02a0SRichard Henderson QSIMPLEQ_FOREACH(r, &l->relocs, next) { 2997ecd02a0SRichard Henderson if (!patch_reloc(r->ptr, r->type, value, r->addend)) { 3007ecd02a0SRichard Henderson return false; 3017ecd02a0SRichard Henderson } 3027ecd02a0SRichard Henderson } 3037ecd02a0SRichard Henderson } 3047ecd02a0SRichard Henderson return true; 3057ecd02a0SRichard Henderson } 3067ecd02a0SRichard Henderson 3079f754620SRichard Henderson static void set_jmp_reset_offset(TCGContext *s, int which) 3089f754620SRichard Henderson { 309f14bed3fSRichard Henderson /* 310f14bed3fSRichard Henderson * We will check for overflow at the end of the opcode loop in 311f14bed3fSRichard Henderson * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX. 312f14bed3fSRichard Henderson */ 313f14bed3fSRichard Henderson s->tb_jmp_reset_offset[which] = tcg_current_code_size(s); 3149f754620SRichard Henderson } 3159f754620SRichard Henderson 316b52a2c03SRichard Henderson static void G_GNUC_UNUSED set_jmp_insn_offset(TCGContext *s, int which) 317b52a2c03SRichard Henderson { 318b52a2c03SRichard Henderson /* 319b52a2c03SRichard Henderson * We will check for overflow at the end of the opcode loop in 320b52a2c03SRichard Henderson * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX. 321b52a2c03SRichard Henderson */ 322b52a2c03SRichard Henderson tcg_debug_assert(TCG_TARGET_HAS_direct_jump); 323b52a2c03SRichard Henderson s->tb_jmp_insn_offset[which] = tcg_current_code_size(s); 324b52a2c03SRichard Henderson } 325b52a2c03SRichard Henderson 326*becc452aSRichard Henderson static uintptr_t G_GNUC_UNUSED get_jmp_target_addr(TCGContext *s, int which) 327*becc452aSRichard Henderson { 328*becc452aSRichard Henderson /* 329*becc452aSRichard Henderson * Return the read-execute version of the pointer, for the benefit 330*becc452aSRichard Henderson * of any pc-relative addressing mode. 331*becc452aSRichard Henderson */ 332*becc452aSRichard Henderson return (uintptr_t)tcg_splitwx_to_rx(&s->tb_jmp_target_addr[which]); 333*becc452aSRichard Henderson } 334*becc452aSRichard Henderson 335db6b7d0cSRichard Henderson /* Signal overflow, starting over with fewer guest insns. */ 3368905770bSMarc-André Lureau static G_NORETURN 3378905770bSMarc-André Lureau void tcg_raise_tb_overflow(TCGContext *s) 338db6b7d0cSRichard Henderson { 339db6b7d0cSRichard Henderson siglongjmp(s->jmp_trans, -2); 340db6b7d0cSRichard Henderson } 341db6b7d0cSRichard Henderson 3424c22e840SRichard Henderson #define C_PFX1(P, A) P##A 3434c22e840SRichard Henderson #define C_PFX2(P, A, B) P##A##_##B 3444c22e840SRichard Henderson #define C_PFX3(P, A, B, C) P##A##_##B##_##C 3454c22e840SRichard Henderson #define C_PFX4(P, A, B, C, D) P##A##_##B##_##C##_##D 3464c22e840SRichard Henderson #define C_PFX5(P, A, B, C, D, E) P##A##_##B##_##C##_##D##_##E 3474c22e840SRichard Henderson #define C_PFX6(P, A, B, C, D, E, F) P##A##_##B##_##C##_##D##_##E##_##F 3484c22e840SRichard Henderson 3494c22e840SRichard Henderson /* Define an enumeration for the various combinations. */ 3504c22e840SRichard Henderson 3514c22e840SRichard Henderson #define C_O0_I1(I1) C_PFX1(c_o0_i1_, I1), 3524c22e840SRichard Henderson #define C_O0_I2(I1, I2) C_PFX2(c_o0_i2_, I1, I2), 3534c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3) C_PFX3(c_o0_i3_, I1, I2, I3), 3544c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4) C_PFX4(c_o0_i4_, I1, I2, I3, I4), 3554c22e840SRichard Henderson 3564c22e840SRichard Henderson #define C_O1_I1(O1, I1) C_PFX2(c_o1_i1_, O1, I1), 3574c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2) C_PFX3(c_o1_i2_, O1, I1, I2), 3584c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3) C_PFX4(c_o1_i3_, O1, I1, I2, I3), 3594c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4) C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4), 3604c22e840SRichard Henderson 3614c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2) C_PFX3(c_n1_i2_, O1, I1, I2), 3624c22e840SRichard Henderson 3634c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1) C_PFX3(c_o2_i1_, O1, O2, I1), 3644c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2) C_PFX4(c_o2_i2_, O1, O2, I1, I2), 3654c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3) C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3), 3664c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4), 3674c22e840SRichard Henderson 3684c22e840SRichard Henderson typedef enum { 3694c22e840SRichard Henderson #include "tcg-target-con-set.h" 3704c22e840SRichard Henderson } TCGConstraintSetIndex; 3714c22e840SRichard Henderson 3724c22e840SRichard Henderson static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode); 3734c22e840SRichard Henderson 3744c22e840SRichard Henderson #undef C_O0_I1 3754c22e840SRichard Henderson #undef C_O0_I2 3764c22e840SRichard Henderson #undef C_O0_I3 3774c22e840SRichard Henderson #undef C_O0_I4 3784c22e840SRichard Henderson #undef C_O1_I1 3794c22e840SRichard Henderson #undef C_O1_I2 3804c22e840SRichard Henderson #undef C_O1_I3 3814c22e840SRichard Henderson #undef C_O1_I4 3824c22e840SRichard Henderson #undef C_N1_I2 3834c22e840SRichard Henderson #undef C_O2_I1 3844c22e840SRichard Henderson #undef C_O2_I2 3854c22e840SRichard Henderson #undef C_O2_I3 3864c22e840SRichard Henderson #undef C_O2_I4 3874c22e840SRichard Henderson 3884c22e840SRichard Henderson /* Put all of the constraint sets into an array, indexed by the enum. */ 3894c22e840SRichard Henderson 3904c22e840SRichard Henderson #define C_O0_I1(I1) { .args_ct_str = { #I1 } }, 3914c22e840SRichard Henderson #define C_O0_I2(I1, I2) { .args_ct_str = { #I1, #I2 } }, 3924c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3) { .args_ct_str = { #I1, #I2, #I3 } }, 3934c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4) { .args_ct_str = { #I1, #I2, #I3, #I4 } }, 3944c22e840SRichard Henderson 3954c22e840SRichard Henderson #define C_O1_I1(O1, I1) { .args_ct_str = { #O1, #I1 } }, 3964c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2) { .args_ct_str = { #O1, #I1, #I2 } }, 3974c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3) { .args_ct_str = { #O1, #I1, #I2, #I3 } }, 3984c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4) { .args_ct_str = { #O1, #I1, #I2, #I3, #I4 } }, 3994c22e840SRichard Henderson 4004c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2) { .args_ct_str = { "&" #O1, #I1, #I2 } }, 4014c22e840SRichard Henderson 4024c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1) { .args_ct_str = { #O1, #O2, #I1 } }, 4034c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2) { .args_ct_str = { #O1, #O2, #I1, #I2 } }, 4044c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3) { .args_ct_str = { #O1, #O2, #I1, #I2, #I3 } }, 4054c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) { .args_ct_str = { #O1, #O2, #I1, #I2, #I3, #I4 } }, 4064c22e840SRichard Henderson 4074c22e840SRichard Henderson static const TCGTargetOpDef constraint_sets[] = { 4084c22e840SRichard Henderson #include "tcg-target-con-set.h" 4094c22e840SRichard Henderson }; 4104c22e840SRichard Henderson 4114c22e840SRichard Henderson 4124c22e840SRichard Henderson #undef C_O0_I1 4134c22e840SRichard Henderson #undef C_O0_I2 4144c22e840SRichard Henderson #undef C_O0_I3 4154c22e840SRichard Henderson #undef C_O0_I4 4164c22e840SRichard Henderson #undef C_O1_I1 4174c22e840SRichard Henderson #undef C_O1_I2 4184c22e840SRichard Henderson #undef C_O1_I3 4194c22e840SRichard Henderson #undef C_O1_I4 4204c22e840SRichard Henderson #undef C_N1_I2 4214c22e840SRichard Henderson #undef C_O2_I1 4224c22e840SRichard Henderson #undef C_O2_I2 4234c22e840SRichard Henderson #undef C_O2_I3 4244c22e840SRichard Henderson #undef C_O2_I4 4254c22e840SRichard Henderson 4264c22e840SRichard Henderson /* Expand the enumerator to be returned from tcg_target_op_def(). */ 4274c22e840SRichard Henderson 4284c22e840SRichard Henderson #define C_O0_I1(I1) C_PFX1(c_o0_i1_, I1) 4294c22e840SRichard Henderson #define C_O0_I2(I1, I2) C_PFX2(c_o0_i2_, I1, I2) 4304c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3) C_PFX3(c_o0_i3_, I1, I2, I3) 4314c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4) C_PFX4(c_o0_i4_, I1, I2, I3, I4) 4324c22e840SRichard Henderson 4334c22e840SRichard Henderson #define C_O1_I1(O1, I1) C_PFX2(c_o1_i1_, O1, I1) 4344c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2) C_PFX3(c_o1_i2_, O1, I1, I2) 4354c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3) C_PFX4(c_o1_i3_, O1, I1, I2, I3) 4364c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4) C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4) 4374c22e840SRichard Henderson 4384c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2) C_PFX3(c_n1_i2_, O1, I1, I2) 4394c22e840SRichard Henderson 4404c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1) C_PFX3(c_o2_i1_, O1, O2, I1) 4414c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2) C_PFX4(c_o2_i2_, O1, O2, I1, I2) 4424c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3) C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3) 4434c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4) 4444c22e840SRichard Henderson 445139c1837SPaolo Bonzini #include "tcg-target.c.inc" 446c896fe29Sbellard 44738b47b19SEmilio G. Cota static void alloc_tcg_plugin_context(TCGContext *s) 44838b47b19SEmilio G. Cota { 44938b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN 45038b47b19SEmilio G. Cota s->plugin_tb = g_new0(struct qemu_plugin_tb, 1); 45138b47b19SEmilio G. Cota s->plugin_tb->insns = 45238b47b19SEmilio G. Cota g_ptr_array_new_with_free_func(qemu_plugin_insn_cleanup_fn); 45338b47b19SEmilio G. Cota #endif 45438b47b19SEmilio G. Cota } 45538b47b19SEmilio G. Cota 456e8feb96fSEmilio G. Cota /* 4573468b59eSEmilio G. Cota * All TCG threads except the parent (i.e. the one that called tcg_context_init 4583468b59eSEmilio G. Cota * and registered the target's TCG globals) must register with this function 4593468b59eSEmilio G. Cota * before initiating translation. 4603468b59eSEmilio G. Cota * 4613468b59eSEmilio G. Cota * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation 4623468b59eSEmilio G. Cota * of tcg_region_init() for the reasoning behind this. 4633468b59eSEmilio G. Cota * 4643468b59eSEmilio G. Cota * In softmmu each caller registers its context in tcg_ctxs[]. Note that in 4653468b59eSEmilio G. Cota * softmmu tcg_ctxs[] does not track tcg_ctx_init, since the initial context 4663468b59eSEmilio G. Cota * is not used anymore for translation once this function is called. 4673468b59eSEmilio G. Cota * 4683468b59eSEmilio G. Cota * Not tracking tcg_init_ctx in tcg_ctxs[] in softmmu keeps code that iterates 4693468b59eSEmilio G. Cota * over the array (e.g. tcg_code_size() the same for both softmmu and user-mode. 4703468b59eSEmilio G. Cota */ 4713468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY 4723468b59eSEmilio G. Cota void tcg_register_thread(void) 4733468b59eSEmilio G. Cota { 4743468b59eSEmilio G. Cota tcg_ctx = &tcg_init_ctx; 4753468b59eSEmilio G. Cota } 4763468b59eSEmilio G. Cota #else 4773468b59eSEmilio G. Cota void tcg_register_thread(void) 4783468b59eSEmilio G. Cota { 4793468b59eSEmilio G. Cota TCGContext *s = g_malloc(sizeof(*s)); 4803468b59eSEmilio G. Cota unsigned int i, n; 4813468b59eSEmilio G. Cota 4823468b59eSEmilio G. Cota *s = tcg_init_ctx; 4833468b59eSEmilio G. Cota 4843468b59eSEmilio G. Cota /* Relink mem_base. */ 4853468b59eSEmilio G. Cota for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) { 4863468b59eSEmilio G. Cota if (tcg_init_ctx.temps[i].mem_base) { 4873468b59eSEmilio G. Cota ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps; 4883468b59eSEmilio G. Cota tcg_debug_assert(b >= 0 && b < n); 4893468b59eSEmilio G. Cota s->temps[i].mem_base = &s->temps[b]; 4903468b59eSEmilio G. Cota } 4913468b59eSEmilio G. Cota } 4923468b59eSEmilio G. Cota 4933468b59eSEmilio G. Cota /* Claim an entry in tcg_ctxs */ 4940e2d61cfSRichard Henderson n = qatomic_fetch_inc(&tcg_cur_ctxs); 4950e2d61cfSRichard Henderson g_assert(n < tcg_max_ctxs); 496d73415a3SStefan Hajnoczi qatomic_set(&tcg_ctxs[n], s); 4973468b59eSEmilio G. Cota 49838b47b19SEmilio G. Cota if (n > 0) { 49938b47b19SEmilio G. Cota alloc_tcg_plugin_context(s); 500bf042e8eSRichard Henderson tcg_region_initial_alloc(s); 50138b47b19SEmilio G. Cota } 50238b47b19SEmilio G. Cota 5033468b59eSEmilio G. Cota tcg_ctx = s; 5043468b59eSEmilio G. Cota } 5053468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */ 5063468b59eSEmilio G. Cota 507c896fe29Sbellard /* pool based memory allocation */ 508c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size) 509c896fe29Sbellard { 510c896fe29Sbellard TCGPool *p; 511c896fe29Sbellard int pool_size; 512c896fe29Sbellard 513c896fe29Sbellard if (size > TCG_POOL_CHUNK_SIZE) { 514c896fe29Sbellard /* big malloc: insert a new pool (XXX: could optimize) */ 5157267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + size); 516c896fe29Sbellard p->size = size; 5174055299eSKirill Batuzov p->next = s->pool_first_large; 5184055299eSKirill Batuzov s->pool_first_large = p; 5194055299eSKirill Batuzov return p->data; 520c896fe29Sbellard } else { 521c896fe29Sbellard p = s->pool_current; 522c896fe29Sbellard if (!p) { 523c896fe29Sbellard p = s->pool_first; 524c896fe29Sbellard if (!p) 525c896fe29Sbellard goto new_pool; 526c896fe29Sbellard } else { 527c896fe29Sbellard if (!p->next) { 528c896fe29Sbellard new_pool: 529c896fe29Sbellard pool_size = TCG_POOL_CHUNK_SIZE; 5307267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + pool_size); 531c896fe29Sbellard p->size = pool_size; 532c896fe29Sbellard p->next = NULL; 533a813e36fSRichard Henderson if (s->pool_current) { 534c896fe29Sbellard s->pool_current->next = p; 535a813e36fSRichard Henderson } else { 536c896fe29Sbellard s->pool_first = p; 537a813e36fSRichard Henderson } 538c896fe29Sbellard } else { 539c896fe29Sbellard p = p->next; 540c896fe29Sbellard } 541c896fe29Sbellard } 542c896fe29Sbellard } 543c896fe29Sbellard s->pool_current = p; 544c896fe29Sbellard s->pool_cur = p->data + size; 545c896fe29Sbellard s->pool_end = p->data + p->size; 546c896fe29Sbellard return p->data; 547c896fe29Sbellard } 548c896fe29Sbellard 549c896fe29Sbellard void tcg_pool_reset(TCGContext *s) 550c896fe29Sbellard { 5514055299eSKirill Batuzov TCGPool *p, *t; 5524055299eSKirill Batuzov for (p = s->pool_first_large; p; p = t) { 5534055299eSKirill Batuzov t = p->next; 5544055299eSKirill Batuzov g_free(p); 5554055299eSKirill Batuzov } 5564055299eSKirill Batuzov s->pool_first_large = NULL; 557c896fe29Sbellard s->pool_cur = s->pool_end = NULL; 558c896fe29Sbellard s->pool_current = NULL; 559c896fe29Sbellard } 560c896fe29Sbellard 5612ef6175aSRichard Henderson #include "exec/helper-proto.h" 5622ef6175aSRichard Henderson 56339004a71SRichard Henderson static TCGHelperInfo all_helpers[] = { 5642ef6175aSRichard Henderson #include "exec/helper-tcg.h" 565100b5e01SRichard Henderson }; 566619205fdSEmilio G. Cota static GHashTable *helper_table; 567100b5e01SRichard Henderson 56822f15579SRichard Henderson #ifdef CONFIG_TCG_INTERPRETER 569c6ef8c7bSPhilippe Mathieu-Daudé static ffi_type *typecode_to_ffi(int argmask) 570c6ef8c7bSPhilippe Mathieu-Daudé { 571c6ef8c7bSPhilippe Mathieu-Daudé switch (argmask) { 572c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_void: 573c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_void; 574c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_i32: 575c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_uint32; 576c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_s32: 577c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_sint32; 578c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_i64: 579c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_uint64; 580c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_s64: 581c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_sint64; 582c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_ptr: 583c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_pointer; 584c6ef8c7bSPhilippe Mathieu-Daudé } 585c6ef8c7bSPhilippe Mathieu-Daudé g_assert_not_reached(); 586c6ef8c7bSPhilippe Mathieu-Daudé } 5870c22e176SPhilippe Mathieu-Daudé 5880c22e176SPhilippe Mathieu-Daudé static void init_ffi_layouts(void) 5890c22e176SPhilippe Mathieu-Daudé { 5900c22e176SPhilippe Mathieu-Daudé /* g_direct_hash/equal for direct comparisons on uint32_t. */ 591f9c4bb80SRichard Henderson GHashTable *ffi_table = g_hash_table_new(NULL, NULL); 592f9c4bb80SRichard Henderson 5930c22e176SPhilippe Mathieu-Daudé for (int i = 0; i < ARRAY_SIZE(all_helpers); ++i) { 594f9c4bb80SRichard Henderson TCGHelperInfo *info = &all_helpers[i]; 595f9c4bb80SRichard Henderson unsigned typemask = info->typemask; 5960c22e176SPhilippe Mathieu-Daudé gpointer hash = (gpointer)(uintptr_t)typemask; 5970c22e176SPhilippe Mathieu-Daudé struct { 5980c22e176SPhilippe Mathieu-Daudé ffi_cif cif; 5990c22e176SPhilippe Mathieu-Daudé ffi_type *args[]; 6000c22e176SPhilippe Mathieu-Daudé } *ca; 6010c22e176SPhilippe Mathieu-Daudé ffi_status status; 6020c22e176SPhilippe Mathieu-Daudé int nargs; 603f9c4bb80SRichard Henderson ffi_cif *cif; 6040c22e176SPhilippe Mathieu-Daudé 605f9c4bb80SRichard Henderson cif = g_hash_table_lookup(ffi_table, hash); 606f9c4bb80SRichard Henderson if (cif) { 607f9c4bb80SRichard Henderson info->cif = cif; 6080c22e176SPhilippe Mathieu-Daudé continue; 6090c22e176SPhilippe Mathieu-Daudé } 6100c22e176SPhilippe Mathieu-Daudé 6110c22e176SPhilippe Mathieu-Daudé /* Ignoring the return type, find the last non-zero field. */ 6120c22e176SPhilippe Mathieu-Daudé nargs = 32 - clz32(typemask >> 3); 6130c22e176SPhilippe Mathieu-Daudé nargs = DIV_ROUND_UP(nargs, 3); 6140c22e176SPhilippe Mathieu-Daudé 6150c22e176SPhilippe Mathieu-Daudé ca = g_malloc0(sizeof(*ca) + nargs * sizeof(ffi_type *)); 6160c22e176SPhilippe Mathieu-Daudé ca->cif.rtype = typecode_to_ffi(typemask & 7); 6170c22e176SPhilippe Mathieu-Daudé ca->cif.nargs = nargs; 6180c22e176SPhilippe Mathieu-Daudé 6190c22e176SPhilippe Mathieu-Daudé if (nargs != 0) { 6200c22e176SPhilippe Mathieu-Daudé ca->cif.arg_types = ca->args; 6210c22e176SPhilippe Mathieu-Daudé for (int j = 0; j < nargs; ++j) { 6220c22e176SPhilippe Mathieu-Daudé int typecode = extract32(typemask, (j + 1) * 3, 3); 6230c22e176SPhilippe Mathieu-Daudé ca->args[j] = typecode_to_ffi(typecode); 6240c22e176SPhilippe Mathieu-Daudé } 6250c22e176SPhilippe Mathieu-Daudé } 6260c22e176SPhilippe Mathieu-Daudé 6270c22e176SPhilippe Mathieu-Daudé status = ffi_prep_cif(&ca->cif, FFI_DEFAULT_ABI, nargs, 6280c22e176SPhilippe Mathieu-Daudé ca->cif.rtype, ca->cif.arg_types); 6290c22e176SPhilippe Mathieu-Daudé assert(status == FFI_OK); 6300c22e176SPhilippe Mathieu-Daudé 631f9c4bb80SRichard Henderson cif = &ca->cif; 632f9c4bb80SRichard Henderson info->cif = cif; 633f9c4bb80SRichard Henderson g_hash_table_insert(ffi_table, hash, (gpointer)cif); 6340c22e176SPhilippe Mathieu-Daudé } 635f9c4bb80SRichard Henderson 636f9c4bb80SRichard Henderson g_hash_table_destroy(ffi_table); 6370c22e176SPhilippe Mathieu-Daudé } 6380c22e176SPhilippe Mathieu-Daudé #endif /* CONFIG_TCG_INTERPRETER */ 63922f15579SRichard Henderson 64039004a71SRichard Henderson typedef struct TCGCumulativeArgs { 64139004a71SRichard Henderson int arg_idx; /* tcg_gen_callN args[] */ 64239004a71SRichard Henderson int info_in_idx; /* TCGHelperInfo in[] */ 64339004a71SRichard Henderson int arg_slot; /* regs+stack slot */ 64439004a71SRichard Henderson int ref_slot; /* stack slots for references */ 64539004a71SRichard Henderson } TCGCumulativeArgs; 64639004a71SRichard Henderson 64739004a71SRichard Henderson static void layout_arg_even(TCGCumulativeArgs *cum) 64839004a71SRichard Henderson { 64939004a71SRichard Henderson cum->arg_slot += cum->arg_slot & 1; 65039004a71SRichard Henderson } 65139004a71SRichard Henderson 65239004a71SRichard Henderson static void layout_arg_1(TCGCumulativeArgs *cum, TCGHelperInfo *info, 65339004a71SRichard Henderson TCGCallArgumentKind kind) 65439004a71SRichard Henderson { 65539004a71SRichard Henderson TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx]; 65639004a71SRichard Henderson 65739004a71SRichard Henderson *loc = (TCGCallArgumentLoc){ 65839004a71SRichard Henderson .kind = kind, 65939004a71SRichard Henderson .arg_idx = cum->arg_idx, 66039004a71SRichard Henderson .arg_slot = cum->arg_slot, 66139004a71SRichard Henderson }; 66239004a71SRichard Henderson cum->info_in_idx++; 66339004a71SRichard Henderson cum->arg_slot++; 66439004a71SRichard Henderson } 66539004a71SRichard Henderson 66639004a71SRichard Henderson static void layout_arg_normal_n(TCGCumulativeArgs *cum, 66739004a71SRichard Henderson TCGHelperInfo *info, int n) 66839004a71SRichard Henderson { 66939004a71SRichard Henderson TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx]; 67039004a71SRichard Henderson 67139004a71SRichard Henderson for (int i = 0; i < n; ++i) { 67239004a71SRichard Henderson /* Layout all using the same arg_idx, adjusting the subindex. */ 67339004a71SRichard Henderson loc[i] = (TCGCallArgumentLoc){ 67439004a71SRichard Henderson .kind = TCG_CALL_ARG_NORMAL, 67539004a71SRichard Henderson .arg_idx = cum->arg_idx, 67639004a71SRichard Henderson .tmp_subindex = i, 67739004a71SRichard Henderson .arg_slot = cum->arg_slot + i, 67839004a71SRichard Henderson }; 67939004a71SRichard Henderson } 68039004a71SRichard Henderson cum->info_in_idx += n; 68139004a71SRichard Henderson cum->arg_slot += n; 68239004a71SRichard Henderson } 68339004a71SRichard Henderson 68439004a71SRichard Henderson static void init_call_layout(TCGHelperInfo *info) 68539004a71SRichard Henderson { 68639004a71SRichard Henderson int max_reg_slots = ARRAY_SIZE(tcg_target_call_iarg_regs); 68739004a71SRichard Henderson int max_stk_slots = TCG_STATIC_CALL_ARGS_SIZE / sizeof(tcg_target_long); 68839004a71SRichard Henderson unsigned typemask = info->typemask; 68939004a71SRichard Henderson unsigned typecode; 69039004a71SRichard Henderson TCGCumulativeArgs cum = { }; 69139004a71SRichard Henderson 69239004a71SRichard Henderson /* 69339004a71SRichard Henderson * Parse and place any function return value. 69439004a71SRichard Henderson */ 69539004a71SRichard Henderson typecode = typemask & 7; 69639004a71SRichard Henderson switch (typecode) { 69739004a71SRichard Henderson case dh_typecode_void: 69839004a71SRichard Henderson info->nr_out = 0; 69939004a71SRichard Henderson break; 70039004a71SRichard Henderson case dh_typecode_i32: 70139004a71SRichard Henderson case dh_typecode_s32: 70239004a71SRichard Henderson case dh_typecode_ptr: 70339004a71SRichard Henderson info->nr_out = 1; 70439004a71SRichard Henderson info->out_kind = TCG_CALL_RET_NORMAL; 70539004a71SRichard Henderson break; 70639004a71SRichard Henderson case dh_typecode_i64: 70739004a71SRichard Henderson case dh_typecode_s64: 70839004a71SRichard Henderson info->nr_out = 64 / TCG_TARGET_REG_BITS; 70939004a71SRichard Henderson info->out_kind = TCG_CALL_RET_NORMAL; 71039004a71SRichard Henderson break; 71139004a71SRichard Henderson default: 71239004a71SRichard Henderson g_assert_not_reached(); 71339004a71SRichard Henderson } 71439004a71SRichard Henderson assert(info->nr_out <= ARRAY_SIZE(tcg_target_call_oarg_regs)); 71539004a71SRichard Henderson 71639004a71SRichard Henderson /* 71739004a71SRichard Henderson * Parse and place function arguments. 71839004a71SRichard Henderson */ 71939004a71SRichard Henderson for (typemask >>= 3; typemask; typemask >>= 3, cum.arg_idx++) { 72039004a71SRichard Henderson TCGCallArgumentKind kind; 72139004a71SRichard Henderson TCGType type; 72239004a71SRichard Henderson 72339004a71SRichard Henderson typecode = typemask & 7; 72439004a71SRichard Henderson switch (typecode) { 72539004a71SRichard Henderson case dh_typecode_i32: 72639004a71SRichard Henderson case dh_typecode_s32: 72739004a71SRichard Henderson type = TCG_TYPE_I32; 72839004a71SRichard Henderson break; 72939004a71SRichard Henderson case dh_typecode_i64: 73039004a71SRichard Henderson case dh_typecode_s64: 73139004a71SRichard Henderson type = TCG_TYPE_I64; 73239004a71SRichard Henderson break; 73339004a71SRichard Henderson case dh_typecode_ptr: 73439004a71SRichard Henderson type = TCG_TYPE_PTR; 73539004a71SRichard Henderson break; 73639004a71SRichard Henderson default: 73739004a71SRichard Henderson g_assert_not_reached(); 73839004a71SRichard Henderson } 73939004a71SRichard Henderson 74039004a71SRichard Henderson switch (type) { 74139004a71SRichard Henderson case TCG_TYPE_I32: 74239004a71SRichard Henderson switch (TCG_TARGET_CALL_ARG_I32) { 74339004a71SRichard Henderson case TCG_CALL_ARG_EVEN: 74439004a71SRichard Henderson layout_arg_even(&cum); 74539004a71SRichard Henderson /* fall through */ 74639004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 74739004a71SRichard Henderson layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL); 74839004a71SRichard Henderson break; 74939004a71SRichard Henderson case TCG_CALL_ARG_EXTEND: 75039004a71SRichard Henderson kind = TCG_CALL_ARG_EXTEND_U + (typecode & 1); 75139004a71SRichard Henderson layout_arg_1(&cum, info, kind); 75239004a71SRichard Henderson break; 75339004a71SRichard Henderson default: 75439004a71SRichard Henderson qemu_build_not_reached(); 75539004a71SRichard Henderson } 75639004a71SRichard Henderson break; 75739004a71SRichard Henderson 75839004a71SRichard Henderson case TCG_TYPE_I64: 75939004a71SRichard Henderson switch (TCG_TARGET_CALL_ARG_I64) { 76039004a71SRichard Henderson case TCG_CALL_ARG_EVEN: 76139004a71SRichard Henderson layout_arg_even(&cum); 76239004a71SRichard Henderson /* fall through */ 76339004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 76439004a71SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 76539004a71SRichard Henderson layout_arg_normal_n(&cum, info, 2); 76639004a71SRichard Henderson } else { 76739004a71SRichard Henderson layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL); 76839004a71SRichard Henderson } 76939004a71SRichard Henderson break; 77039004a71SRichard Henderson default: 77139004a71SRichard Henderson qemu_build_not_reached(); 77239004a71SRichard Henderson } 77339004a71SRichard Henderson break; 77439004a71SRichard Henderson 77539004a71SRichard Henderson default: 77639004a71SRichard Henderson g_assert_not_reached(); 77739004a71SRichard Henderson } 77839004a71SRichard Henderson } 77939004a71SRichard Henderson info->nr_in = cum.info_in_idx; 78039004a71SRichard Henderson 78139004a71SRichard Henderson /* Validate that we didn't overrun the input array. */ 78239004a71SRichard Henderson assert(cum.info_in_idx <= ARRAY_SIZE(info->in)); 78339004a71SRichard Henderson /* Validate the backend has enough argument space. */ 78439004a71SRichard Henderson assert(cum.arg_slot <= max_reg_slots + max_stk_slots); 78539004a71SRichard Henderson assert(cum.ref_slot <= max_stk_slots); 78639004a71SRichard Henderson } 78739004a71SRichard Henderson 78891478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)]; 789f69d277eSRichard Henderson static void process_op_defs(TCGContext *s); 7901c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type, 7911c2adb95SRichard Henderson TCGReg reg, const char *name); 79291478cefSRichard Henderson 79343b972b7SRichard Henderson static void tcg_context_init(unsigned max_cpus) 794c896fe29Sbellard { 795a76aabd3SRichard Henderson TCGContext *s = &tcg_init_ctx; 796100b5e01SRichard Henderson int op, total_args, n, i; 797c896fe29Sbellard TCGOpDef *def; 798c896fe29Sbellard TCGArgConstraint *args_ct; 7991c2adb95SRichard Henderson TCGTemp *ts; 800c896fe29Sbellard 801c896fe29Sbellard memset(s, 0, sizeof(*s)); 802c896fe29Sbellard s->nb_globals = 0; 803c896fe29Sbellard 804c896fe29Sbellard /* Count total number of arguments and allocate the corresponding 805c896fe29Sbellard space */ 806c896fe29Sbellard total_args = 0; 807c896fe29Sbellard for(op = 0; op < NB_OPS; op++) { 808c896fe29Sbellard def = &tcg_op_defs[op]; 809c896fe29Sbellard n = def->nb_iargs + def->nb_oargs; 810c896fe29Sbellard total_args += n; 811c896fe29Sbellard } 812c896fe29Sbellard 813bc2b17e6SRichard Henderson args_ct = g_new0(TCGArgConstraint, total_args); 814c896fe29Sbellard 815c896fe29Sbellard for(op = 0; op < NB_OPS; op++) { 816c896fe29Sbellard def = &tcg_op_defs[op]; 817c896fe29Sbellard def->args_ct = args_ct; 818c896fe29Sbellard n = def->nb_iargs + def->nb_oargs; 819c896fe29Sbellard args_ct += n; 820c896fe29Sbellard } 821c896fe29Sbellard 8225cd8f621SRichard Henderson /* Register helpers. */ 82384fd9dd3SRichard Henderson /* Use g_direct_hash/equal for direct pointer comparisons on func. */ 824619205fdSEmilio G. Cota helper_table = g_hash_table_new(NULL, NULL); 82584fd9dd3SRichard Henderson 826100b5e01SRichard Henderson for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) { 82739004a71SRichard Henderson init_call_layout(&all_helpers[i]); 82884fd9dd3SRichard Henderson g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func, 82972866e82SRichard Henderson (gpointer)&all_helpers[i]); 830100b5e01SRichard Henderson } 8315cd8f621SRichard Henderson 83222f15579SRichard Henderson #ifdef CONFIG_TCG_INTERPRETER 8330c22e176SPhilippe Mathieu-Daudé init_ffi_layouts(); 83422f15579SRichard Henderson #endif 83522f15579SRichard Henderson 836c896fe29Sbellard tcg_target_init(s); 837f69d277eSRichard Henderson process_op_defs(s); 83891478cefSRichard Henderson 83991478cefSRichard Henderson /* Reverse the order of the saved registers, assuming they're all at 84091478cefSRichard Henderson the start of tcg_target_reg_alloc_order. */ 84191478cefSRichard Henderson for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) { 84291478cefSRichard Henderson int r = tcg_target_reg_alloc_order[n]; 84391478cefSRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) { 84491478cefSRichard Henderson break; 84591478cefSRichard Henderson } 84691478cefSRichard Henderson } 84791478cefSRichard Henderson for (i = 0; i < n; ++i) { 84891478cefSRichard Henderson indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i]; 84991478cefSRichard Henderson } 85091478cefSRichard Henderson for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) { 85191478cefSRichard Henderson indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i]; 85291478cefSRichard Henderson } 853b1311c4aSEmilio G. Cota 85438b47b19SEmilio G. Cota alloc_tcg_plugin_context(s); 85538b47b19SEmilio G. Cota 856b1311c4aSEmilio G. Cota tcg_ctx = s; 8573468b59eSEmilio G. Cota /* 8583468b59eSEmilio G. Cota * In user-mode we simply share the init context among threads, since we 8593468b59eSEmilio G. Cota * use a single region. See the documentation tcg_region_init() for the 8603468b59eSEmilio G. Cota * reasoning behind this. 8613468b59eSEmilio G. Cota * In softmmu we will have at most max_cpus TCG threads. 8623468b59eSEmilio G. Cota */ 8633468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY 864df2cce29SEmilio G. Cota tcg_ctxs = &tcg_ctx; 8650e2d61cfSRichard Henderson tcg_cur_ctxs = 1; 8660e2d61cfSRichard Henderson tcg_max_ctxs = 1; 8673468b59eSEmilio G. Cota #else 8680e2d61cfSRichard Henderson tcg_max_ctxs = max_cpus; 8690e2d61cfSRichard Henderson tcg_ctxs = g_new0(TCGContext *, max_cpus); 8703468b59eSEmilio G. Cota #endif 8711c2adb95SRichard Henderson 8721c2adb95SRichard Henderson tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0)); 8731c2adb95SRichard Henderson ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env"); 8741c2adb95SRichard Henderson cpu_env = temp_tcgv_ptr(ts); 8759002ec79SRichard Henderson } 876b03cce8eSbellard 87743b972b7SRichard Henderson void tcg_init(size_t tb_size, int splitwx, unsigned max_cpus) 878a76aabd3SRichard Henderson { 87943b972b7SRichard Henderson tcg_context_init(max_cpus); 88043b972b7SRichard Henderson tcg_region_init(tb_size, splitwx, max_cpus); 881a76aabd3SRichard Henderson } 882a76aabd3SRichard Henderson 8836e3b2bfdSEmilio G. Cota /* 8846e3b2bfdSEmilio G. Cota * Allocate TBs right before their corresponding translated code, making 8856e3b2bfdSEmilio G. Cota * sure that TBs and code are on different cache lines. 8866e3b2bfdSEmilio G. Cota */ 8876e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s) 8886e3b2bfdSEmilio G. Cota { 8896e3b2bfdSEmilio G. Cota uintptr_t align = qemu_icache_linesize; 8906e3b2bfdSEmilio G. Cota TranslationBlock *tb; 8916e3b2bfdSEmilio G. Cota void *next; 8926e3b2bfdSEmilio G. Cota 893e8feb96fSEmilio G. Cota retry: 8946e3b2bfdSEmilio G. Cota tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align); 8956e3b2bfdSEmilio G. Cota next = (void *)ROUND_UP((uintptr_t)(tb + 1), align); 8966e3b2bfdSEmilio G. Cota 8976e3b2bfdSEmilio G. Cota if (unlikely(next > s->code_gen_highwater)) { 898e8feb96fSEmilio G. Cota if (tcg_region_alloc(s)) { 8996e3b2bfdSEmilio G. Cota return NULL; 9006e3b2bfdSEmilio G. Cota } 901e8feb96fSEmilio G. Cota goto retry; 902e8feb96fSEmilio G. Cota } 903d73415a3SStefan Hajnoczi qatomic_set(&s->code_gen_ptr, next); 90457a26946SRichard Henderson s->data_gen_ptr = NULL; 9056e3b2bfdSEmilio G. Cota return tb; 9066e3b2bfdSEmilio G. Cota } 9076e3b2bfdSEmilio G. Cota 9089002ec79SRichard Henderson void tcg_prologue_init(TCGContext *s) 9099002ec79SRichard Henderson { 910b0a0794aSRichard Henderson size_t prologue_size; 9118163b749SRichard Henderson 912b0a0794aSRichard Henderson s->code_ptr = s->code_gen_ptr; 913b0a0794aSRichard Henderson s->code_buf = s->code_gen_ptr; 9145b38ee31SRichard Henderson s->data_gen_ptr = NULL; 915b91ccb31SRichard Henderson 916b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 917b0a0794aSRichard Henderson tcg_qemu_tb_exec = (tcg_prologue_fn *)tcg_splitwx_to_rx(s->code_ptr); 918b91ccb31SRichard Henderson #endif 9198163b749SRichard Henderson 9205b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 9215b38ee31SRichard Henderson s->pool_labels = NULL; 9225b38ee31SRichard Henderson #endif 9235b38ee31SRichard Henderson 924653b87ebSRoman Bolshakov qemu_thread_jit_write(); 9258163b749SRichard Henderson /* Generate the prologue. */ 926b03cce8eSbellard tcg_target_qemu_prologue(s); 9275b38ee31SRichard Henderson 9285b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 9295b38ee31SRichard Henderson /* Allow the prologue to put e.g. guest_base into a pool entry. */ 9305b38ee31SRichard Henderson { 9311768987bSRichard Henderson int result = tcg_out_pool_finalize(s); 9321768987bSRichard Henderson tcg_debug_assert(result == 0); 9335b38ee31SRichard Henderson } 9345b38ee31SRichard Henderson #endif 9355b38ee31SRichard Henderson 936b0a0794aSRichard Henderson prologue_size = tcg_current_code_size(s); 9375584e2dbSIlya Leoshkevich perf_report_prologue(s->code_gen_ptr, prologue_size); 938b0a0794aSRichard Henderson 939df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 940b0a0794aSRichard Henderson flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf), 941b0a0794aSRichard Henderson (uintptr_t)s->code_buf, prologue_size); 942df5d2b16SRichard Henderson #endif 9438163b749SRichard Henderson 944d6b64b2bSRichard Henderson #ifdef DEBUG_DISAS 945d6b64b2bSRichard Henderson if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) { 946c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock(); 94778b54858SRichard Henderson if (logfile) { 94878b54858SRichard Henderson fprintf(logfile, "PROLOGUE: [size=%zu]\n", prologue_size); 9495b38ee31SRichard Henderson if (s->data_gen_ptr) { 950b0a0794aSRichard Henderson size_t code_size = s->data_gen_ptr - s->code_gen_ptr; 9515b38ee31SRichard Henderson size_t data_size = prologue_size - code_size; 9525b38ee31SRichard Henderson size_t i; 9535b38ee31SRichard Henderson 95478b54858SRichard Henderson disas(logfile, s->code_gen_ptr, code_size); 9555b38ee31SRichard Henderson 9565b38ee31SRichard Henderson for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) { 9575b38ee31SRichard Henderson if (sizeof(tcg_target_ulong) == 8) { 95878b54858SRichard Henderson fprintf(logfile, 95978b54858SRichard Henderson "0x%08" PRIxPTR ": .quad 0x%016" PRIx64 "\n", 9605b38ee31SRichard Henderson (uintptr_t)s->data_gen_ptr + i, 9615b38ee31SRichard Henderson *(uint64_t *)(s->data_gen_ptr + i)); 9625b38ee31SRichard Henderson } else { 96378b54858SRichard Henderson fprintf(logfile, 96478b54858SRichard Henderson "0x%08" PRIxPTR ": .long 0x%08x\n", 9655b38ee31SRichard Henderson (uintptr_t)s->data_gen_ptr + i, 9665b38ee31SRichard Henderson *(uint32_t *)(s->data_gen_ptr + i)); 9675b38ee31SRichard Henderson } 9685b38ee31SRichard Henderson } 9695b38ee31SRichard Henderson } else { 97078b54858SRichard Henderson disas(logfile, s->code_gen_ptr, prologue_size); 9715b38ee31SRichard Henderson } 97278b54858SRichard Henderson fprintf(logfile, "\n"); 973fc59d2d8SRobert Foley qemu_log_unlock(logfile); 974d6b64b2bSRichard Henderson } 97578b54858SRichard Henderson } 976d6b64b2bSRichard Henderson #endif 977cedbcb01SEmilio G. Cota 9786eea0434SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 9796eea0434SRichard Henderson /* 9806eea0434SRichard Henderson * Assert that goto_ptr is implemented completely, setting an epilogue. 9816eea0434SRichard Henderson * For tci, we use NULL as the signal to return from the interpreter, 9826eea0434SRichard Henderson * so skip this check. 9836eea0434SRichard Henderson */ 9848b5c2b62SRichard Henderson tcg_debug_assert(tcg_code_gen_epilogue != NULL); 9856eea0434SRichard Henderson #endif 986d1c74ab3SRichard Henderson 987d1c74ab3SRichard Henderson tcg_region_prologue_set(s); 988c896fe29Sbellard } 989c896fe29Sbellard 990c896fe29Sbellard void tcg_func_start(TCGContext *s) 991c896fe29Sbellard { 992c896fe29Sbellard tcg_pool_reset(s); 993c896fe29Sbellard s->nb_temps = s->nb_globals; 9940ec9eabcSRichard Henderson 9950ec9eabcSRichard Henderson /* No temps have been previously allocated for size or locality. */ 9960ec9eabcSRichard Henderson memset(s->free_temps, 0, sizeof(s->free_temps)); 9970ec9eabcSRichard Henderson 998c0522136SRichard Henderson /* No constant temps have been previously allocated. */ 999c0522136SRichard Henderson for (int i = 0; i < TCG_TYPE_COUNT; ++i) { 1000c0522136SRichard Henderson if (s->const_table[i]) { 1001c0522136SRichard Henderson g_hash_table_remove_all(s->const_table[i]); 1002c0522136SRichard Henderson } 1003c0522136SRichard Henderson } 1004c0522136SRichard Henderson 1005abebf925SRichard Henderson s->nb_ops = 0; 1006c896fe29Sbellard s->nb_labels = 0; 1007c896fe29Sbellard s->current_frame_offset = s->frame_start; 1008c896fe29Sbellard 10090a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG 10100a209d4bSRichard Henderson s->goto_tb_issue_mask = 0; 10110a209d4bSRichard Henderson #endif 10120a209d4bSRichard Henderson 101315fa08f8SRichard Henderson QTAILQ_INIT(&s->ops); 101415fa08f8SRichard Henderson QTAILQ_INIT(&s->free_ops); 1015bef16ab4SRichard Henderson QSIMPLEQ_INIT(&s->labels); 1016c896fe29Sbellard } 1017c896fe29Sbellard 1018ae30e866SRichard Henderson static TCGTemp *tcg_temp_alloc(TCGContext *s) 10197ca4b752SRichard Henderson { 10207ca4b752SRichard Henderson int n = s->nb_temps++; 1021ae30e866SRichard Henderson 1022ae30e866SRichard Henderson if (n >= TCG_MAX_TEMPS) { 1023db6b7d0cSRichard Henderson tcg_raise_tb_overflow(s); 1024ae30e866SRichard Henderson } 10257ca4b752SRichard Henderson return memset(&s->temps[n], 0, sizeof(TCGTemp)); 10267ca4b752SRichard Henderson } 10277ca4b752SRichard Henderson 1028ae30e866SRichard Henderson static TCGTemp *tcg_global_alloc(TCGContext *s) 10297ca4b752SRichard Henderson { 1030fa477d25SRichard Henderson TCGTemp *ts; 1031fa477d25SRichard Henderson 10327ca4b752SRichard Henderson tcg_debug_assert(s->nb_globals == s->nb_temps); 1033ae30e866SRichard Henderson tcg_debug_assert(s->nb_globals < TCG_MAX_TEMPS); 10347ca4b752SRichard Henderson s->nb_globals++; 1035fa477d25SRichard Henderson ts = tcg_temp_alloc(s); 1036ee17db83SRichard Henderson ts->kind = TEMP_GLOBAL; 1037fa477d25SRichard Henderson 1038fa477d25SRichard Henderson return ts; 1039c896fe29Sbellard } 1040c896fe29Sbellard 1041085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type, 1042b6638662SRichard Henderson TCGReg reg, const char *name) 1043c896fe29Sbellard { 1044c896fe29Sbellard TCGTemp *ts; 1045c896fe29Sbellard 1046b3a62939SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type != TCG_TYPE_I32) { 1047c896fe29Sbellard tcg_abort(); 1048b3a62939SRichard Henderson } 10497ca4b752SRichard Henderson 10507ca4b752SRichard Henderson ts = tcg_global_alloc(s); 1051c896fe29Sbellard ts->base_type = type; 1052c896fe29Sbellard ts->type = type; 1053ee17db83SRichard Henderson ts->kind = TEMP_FIXED; 1054c896fe29Sbellard ts->reg = reg; 1055c896fe29Sbellard ts->name = name; 1056c896fe29Sbellard tcg_regset_set_reg(s->reserved_regs, reg); 10577ca4b752SRichard Henderson 1058085272b3SRichard Henderson return ts; 1059a7812ae4Spbrook } 1060a7812ae4Spbrook 1061b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size) 1062a7812ae4Spbrook { 1063b3a62939SRichard Henderson s->frame_start = start; 1064b3a62939SRichard Henderson s->frame_end = start + size; 1065085272b3SRichard Henderson s->frame_temp 1066085272b3SRichard Henderson = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame"); 1067b3a62939SRichard Henderson } 1068a7812ae4Spbrook 1069085272b3SRichard Henderson TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base, 1070e1ccc054SRichard Henderson intptr_t offset, const char *name) 1071c896fe29Sbellard { 1072b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1073dc41aa7dSRichard Henderson TCGTemp *base_ts = tcgv_ptr_temp(base); 10747ca4b752SRichard Henderson TCGTemp *ts = tcg_global_alloc(s); 1075aef85402SRichard Henderson int indirect_reg = 0; 1076c896fe29Sbellard 1077c0522136SRichard Henderson switch (base_ts->kind) { 1078c0522136SRichard Henderson case TEMP_FIXED: 1079c0522136SRichard Henderson break; 1080c0522136SRichard Henderson case TEMP_GLOBAL: 10815a18407fSRichard Henderson /* We do not support double-indirect registers. */ 10825a18407fSRichard Henderson tcg_debug_assert(!base_ts->indirect_reg); 1083b3915dbbSRichard Henderson base_ts->indirect_base = 1; 10845a18407fSRichard Henderson s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64 10855a18407fSRichard Henderson ? 2 : 1); 10865a18407fSRichard Henderson indirect_reg = 1; 1087c0522136SRichard Henderson break; 1088c0522136SRichard Henderson default: 1089c0522136SRichard Henderson g_assert_not_reached(); 1090b3915dbbSRichard Henderson } 1091b3915dbbSRichard Henderson 10927ca4b752SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { 10937ca4b752SRichard Henderson TCGTemp *ts2 = tcg_global_alloc(s); 1094c896fe29Sbellard char buf[64]; 10957ca4b752SRichard Henderson 10967ca4b752SRichard Henderson ts->base_type = TCG_TYPE_I64; 1097c896fe29Sbellard ts->type = TCG_TYPE_I32; 1098b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg; 1099c896fe29Sbellard ts->mem_allocated = 1; 1100b3a62939SRichard Henderson ts->mem_base = base_ts; 1101aef85402SRichard Henderson ts->mem_offset = offset; 1102c896fe29Sbellard pstrcpy(buf, sizeof(buf), name); 1103c896fe29Sbellard pstrcat(buf, sizeof(buf), "_0"); 1104c896fe29Sbellard ts->name = strdup(buf); 1105c896fe29Sbellard 11067ca4b752SRichard Henderson tcg_debug_assert(ts2 == ts + 1); 11077ca4b752SRichard Henderson ts2->base_type = TCG_TYPE_I64; 11087ca4b752SRichard Henderson ts2->type = TCG_TYPE_I32; 1109b3915dbbSRichard Henderson ts2->indirect_reg = indirect_reg; 11107ca4b752SRichard Henderson ts2->mem_allocated = 1; 11117ca4b752SRichard Henderson ts2->mem_base = base_ts; 1112aef85402SRichard Henderson ts2->mem_offset = offset + 4; 1113fac87bd2SRichard Henderson ts2->temp_subindex = 1; 1114c896fe29Sbellard pstrcpy(buf, sizeof(buf), name); 1115c896fe29Sbellard pstrcat(buf, sizeof(buf), "_1"); 1116120c1084SRichard Henderson ts2->name = strdup(buf); 11177ca4b752SRichard Henderson } else { 1118c896fe29Sbellard ts->base_type = type; 1119c896fe29Sbellard ts->type = type; 1120b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg; 1121c896fe29Sbellard ts->mem_allocated = 1; 1122b3a62939SRichard Henderson ts->mem_base = base_ts; 1123c896fe29Sbellard ts->mem_offset = offset; 1124c896fe29Sbellard ts->name = name; 1125c896fe29Sbellard } 1126085272b3SRichard Henderson return ts; 1127c896fe29Sbellard } 1128c896fe29Sbellard 11295bfa8034SRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, bool temp_local) 1130c896fe29Sbellard { 1131b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1132ee17db83SRichard Henderson TCGTempKind kind = temp_local ? TEMP_LOCAL : TEMP_NORMAL; 1133c896fe29Sbellard TCGTemp *ts; 1134641d5fbeSbellard int idx, k; 1135c896fe29Sbellard 11360ec9eabcSRichard Henderson k = type + (temp_local ? TCG_TYPE_COUNT : 0); 11370ec9eabcSRichard Henderson idx = find_first_bit(s->free_temps[k].l, TCG_MAX_TEMPS); 11380ec9eabcSRichard Henderson if (idx < TCG_MAX_TEMPS) { 11390ec9eabcSRichard Henderson /* There is already an available temp with the right type. */ 11400ec9eabcSRichard Henderson clear_bit(idx, s->free_temps[k].l); 11410ec9eabcSRichard Henderson 1142e8996ee0Sbellard ts = &s->temps[idx]; 1143e8996ee0Sbellard ts->temp_allocated = 1; 11447ca4b752SRichard Henderson tcg_debug_assert(ts->base_type == type); 1145ee17db83SRichard Henderson tcg_debug_assert(ts->kind == kind); 1146e8996ee0Sbellard } else { 11477ca4b752SRichard Henderson ts = tcg_temp_alloc(s); 11487ca4b752SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { 11497ca4b752SRichard Henderson TCGTemp *ts2 = tcg_temp_alloc(s); 11507ca4b752SRichard Henderson 1151c896fe29Sbellard ts->base_type = type; 1152c896fe29Sbellard ts->type = TCG_TYPE_I32; 1153e8996ee0Sbellard ts->temp_allocated = 1; 1154ee17db83SRichard Henderson ts->kind = kind; 11557ca4b752SRichard Henderson 11567ca4b752SRichard Henderson tcg_debug_assert(ts2 == ts + 1); 11577ca4b752SRichard Henderson ts2->base_type = TCG_TYPE_I64; 11587ca4b752SRichard Henderson ts2->type = TCG_TYPE_I32; 11597ca4b752SRichard Henderson ts2->temp_allocated = 1; 1160fac87bd2SRichard Henderson ts2->temp_subindex = 1; 1161ee17db83SRichard Henderson ts2->kind = kind; 11627ca4b752SRichard Henderson } else { 1163c896fe29Sbellard ts->base_type = type; 1164c896fe29Sbellard ts->type = type; 1165e8996ee0Sbellard ts->temp_allocated = 1; 1166ee17db83SRichard Henderson ts->kind = kind; 1167c896fe29Sbellard } 1168e8996ee0Sbellard } 116927bfd83cSPeter Maydell 117027bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG) 117127bfd83cSPeter Maydell s->temps_in_use++; 117227bfd83cSPeter Maydell #endif 1173085272b3SRichard Henderson return ts; 1174c896fe29Sbellard } 1175c896fe29Sbellard 1176d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type) 1177d2fd745fSRichard Henderson { 1178d2fd745fSRichard Henderson TCGTemp *t; 1179d2fd745fSRichard Henderson 1180d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG 1181d2fd745fSRichard Henderson switch (type) { 1182d2fd745fSRichard Henderson case TCG_TYPE_V64: 1183d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v64); 1184d2fd745fSRichard Henderson break; 1185d2fd745fSRichard Henderson case TCG_TYPE_V128: 1186d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v128); 1187d2fd745fSRichard Henderson break; 1188d2fd745fSRichard Henderson case TCG_TYPE_V256: 1189d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v256); 1190d2fd745fSRichard Henderson break; 1191d2fd745fSRichard Henderson default: 1192d2fd745fSRichard Henderson g_assert_not_reached(); 1193d2fd745fSRichard Henderson } 1194d2fd745fSRichard Henderson #endif 1195d2fd745fSRichard Henderson 1196d2fd745fSRichard Henderson t = tcg_temp_new_internal(type, 0); 1197d2fd745fSRichard Henderson return temp_tcgv_vec(t); 1198d2fd745fSRichard Henderson } 1199d2fd745fSRichard Henderson 1200d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp. */ 1201d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match) 1202d2fd745fSRichard Henderson { 1203d2fd745fSRichard Henderson TCGTemp *t = tcgv_vec_temp(match); 1204d2fd745fSRichard Henderson 1205d2fd745fSRichard Henderson tcg_debug_assert(t->temp_allocated != 0); 1206d2fd745fSRichard Henderson 1207d2fd745fSRichard Henderson t = tcg_temp_new_internal(t->base_type, 0); 1208d2fd745fSRichard Henderson return temp_tcgv_vec(t); 1209d2fd745fSRichard Henderson } 1210d2fd745fSRichard Henderson 12115bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts) 1212c896fe29Sbellard { 1213b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1214085272b3SRichard Henderson int k, idx; 1215c896fe29Sbellard 1216c7482438SRichard Henderson switch (ts->kind) { 1217c7482438SRichard Henderson case TEMP_CONST: 1218c7482438SRichard Henderson /* 1219c7482438SRichard Henderson * In order to simplify users of tcg_constant_*, 1220c7482438SRichard Henderson * silently ignore free. 1221c7482438SRichard Henderson */ 1222c0522136SRichard Henderson return; 1223c7482438SRichard Henderson case TEMP_NORMAL: 1224c7482438SRichard Henderson case TEMP_LOCAL: 1225c7482438SRichard Henderson break; 1226c7482438SRichard Henderson default: 1227c7482438SRichard Henderson g_assert_not_reached(); 1228c0522136SRichard Henderson } 1229c0522136SRichard Henderson 123027bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG) 123127bfd83cSPeter Maydell s->temps_in_use--; 123227bfd83cSPeter Maydell if (s->temps_in_use < 0) { 123327bfd83cSPeter Maydell fprintf(stderr, "More temporaries freed than allocated!\n"); 123427bfd83cSPeter Maydell } 123527bfd83cSPeter Maydell #endif 123627bfd83cSPeter Maydell 1237eabb7b91SAurelien Jarno tcg_debug_assert(ts->temp_allocated != 0); 1238e8996ee0Sbellard ts->temp_allocated = 0; 12390ec9eabcSRichard Henderson 1240085272b3SRichard Henderson idx = temp_idx(ts); 1241ee17db83SRichard Henderson k = ts->base_type + (ts->kind == TEMP_NORMAL ? 0 : TCG_TYPE_COUNT); 12420ec9eabcSRichard Henderson set_bit(idx, s->free_temps[k].l); 1243e8996ee0Sbellard } 1244e8996ee0Sbellard 1245c0522136SRichard Henderson TCGTemp *tcg_constant_internal(TCGType type, int64_t val) 1246c0522136SRichard Henderson { 1247c0522136SRichard Henderson TCGContext *s = tcg_ctx; 1248c0522136SRichard Henderson GHashTable *h = s->const_table[type]; 1249c0522136SRichard Henderson TCGTemp *ts; 1250c0522136SRichard Henderson 1251c0522136SRichard Henderson if (h == NULL) { 1252c0522136SRichard Henderson h = g_hash_table_new(g_int64_hash, g_int64_equal); 1253c0522136SRichard Henderson s->const_table[type] = h; 1254c0522136SRichard Henderson } 1255c0522136SRichard Henderson 1256c0522136SRichard Henderson ts = g_hash_table_lookup(h, &val); 1257c0522136SRichard Henderson if (ts == NULL) { 1258aef85402SRichard Henderson int64_t *val_ptr; 1259aef85402SRichard Henderson 1260c0522136SRichard Henderson ts = tcg_temp_alloc(s); 1261c0522136SRichard Henderson 1262c0522136SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { 1263c0522136SRichard Henderson TCGTemp *ts2 = tcg_temp_alloc(s); 1264c0522136SRichard Henderson 1265aef85402SRichard Henderson tcg_debug_assert(ts2 == ts + 1); 1266aef85402SRichard Henderson 1267c0522136SRichard Henderson ts->base_type = TCG_TYPE_I64; 1268c0522136SRichard Henderson ts->type = TCG_TYPE_I32; 1269c0522136SRichard Henderson ts->kind = TEMP_CONST; 1270c0522136SRichard Henderson ts->temp_allocated = 1; 1271c0522136SRichard Henderson 1272c0522136SRichard Henderson ts2->base_type = TCG_TYPE_I64; 1273c0522136SRichard Henderson ts2->type = TCG_TYPE_I32; 1274c0522136SRichard Henderson ts2->kind = TEMP_CONST; 1275c0522136SRichard Henderson ts2->temp_allocated = 1; 1276fac87bd2SRichard Henderson ts2->temp_subindex = 1; 1277aef85402SRichard Henderson 1278aef85402SRichard Henderson /* 1279aef85402SRichard Henderson * Retain the full value of the 64-bit constant in the low 1280aef85402SRichard Henderson * part, so that the hash table works. Actual uses will 1281aef85402SRichard Henderson * truncate the value to the low part. 1282aef85402SRichard Henderson */ 1283aef85402SRichard Henderson ts[HOST_BIG_ENDIAN].val = val; 1284aef85402SRichard Henderson ts[!HOST_BIG_ENDIAN].val = val >> 32; 1285aef85402SRichard Henderson val_ptr = &ts[HOST_BIG_ENDIAN].val; 1286c0522136SRichard Henderson } else { 1287c0522136SRichard Henderson ts->base_type = type; 1288c0522136SRichard Henderson ts->type = type; 1289c0522136SRichard Henderson ts->kind = TEMP_CONST; 1290c0522136SRichard Henderson ts->temp_allocated = 1; 1291c0522136SRichard Henderson ts->val = val; 1292aef85402SRichard Henderson val_ptr = &ts->val; 1293c0522136SRichard Henderson } 1294aef85402SRichard Henderson g_hash_table_insert(h, val_ptr, ts); 1295c0522136SRichard Henderson } 1296c0522136SRichard Henderson 1297c0522136SRichard Henderson return ts; 1298c0522136SRichard Henderson } 1299c0522136SRichard Henderson 1300c0522136SRichard Henderson TCGv_vec tcg_constant_vec(TCGType type, unsigned vece, int64_t val) 1301c0522136SRichard Henderson { 1302c0522136SRichard Henderson val = dup_const(vece, val); 1303c0522136SRichard Henderson return temp_tcgv_vec(tcg_constant_internal(type, val)); 1304c0522136SRichard Henderson } 1305c0522136SRichard Henderson 130688d4005bSRichard Henderson TCGv_vec tcg_constant_vec_matching(TCGv_vec match, unsigned vece, int64_t val) 130788d4005bSRichard Henderson { 130888d4005bSRichard Henderson TCGTemp *t = tcgv_vec_temp(match); 130988d4005bSRichard Henderson 131088d4005bSRichard Henderson tcg_debug_assert(t->temp_allocated != 0); 131188d4005bSRichard Henderson return tcg_constant_vec(t->base_type, vece, val); 131288d4005bSRichard Henderson } 131388d4005bSRichard Henderson 1314a7812ae4Spbrook TCGv_i32 tcg_const_i32(int32_t val) 1315a7812ae4Spbrook { 1316a7812ae4Spbrook TCGv_i32 t0; 1317a7812ae4Spbrook t0 = tcg_temp_new_i32(); 1318e8996ee0Sbellard tcg_gen_movi_i32(t0, val); 1319e8996ee0Sbellard return t0; 1320c896fe29Sbellard } 1321c896fe29Sbellard 1322a7812ae4Spbrook TCGv_i64 tcg_const_i64(int64_t val) 1323c896fe29Sbellard { 1324a7812ae4Spbrook TCGv_i64 t0; 1325a7812ae4Spbrook t0 = tcg_temp_new_i64(); 1326e8996ee0Sbellard tcg_gen_movi_i64(t0, val); 1327e8996ee0Sbellard return t0; 1328c896fe29Sbellard } 1329c896fe29Sbellard 1330a7812ae4Spbrook TCGv_i32 tcg_const_local_i32(int32_t val) 1331bdffd4a9Saurel32 { 1332a7812ae4Spbrook TCGv_i32 t0; 1333a7812ae4Spbrook t0 = tcg_temp_local_new_i32(); 1334bdffd4a9Saurel32 tcg_gen_movi_i32(t0, val); 1335bdffd4a9Saurel32 return t0; 1336bdffd4a9Saurel32 } 1337bdffd4a9Saurel32 1338a7812ae4Spbrook TCGv_i64 tcg_const_local_i64(int64_t val) 1339bdffd4a9Saurel32 { 1340a7812ae4Spbrook TCGv_i64 t0; 1341a7812ae4Spbrook t0 = tcg_temp_local_new_i64(); 1342bdffd4a9Saurel32 tcg_gen_movi_i64(t0, val); 1343bdffd4a9Saurel32 return t0; 1344bdffd4a9Saurel32 } 1345bdffd4a9Saurel32 134627bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG) 134727bfd83cSPeter Maydell void tcg_clear_temp_count(void) 134827bfd83cSPeter Maydell { 1349b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 135027bfd83cSPeter Maydell s->temps_in_use = 0; 135127bfd83cSPeter Maydell } 135227bfd83cSPeter Maydell 135327bfd83cSPeter Maydell int tcg_check_temp_count(void) 135427bfd83cSPeter Maydell { 1355b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 135627bfd83cSPeter Maydell if (s->temps_in_use) { 135727bfd83cSPeter Maydell /* Clear the count so that we don't give another 135827bfd83cSPeter Maydell * warning immediately next time around. 135927bfd83cSPeter Maydell */ 136027bfd83cSPeter Maydell s->temps_in_use = 0; 136127bfd83cSPeter Maydell return 1; 136227bfd83cSPeter Maydell } 136327bfd83cSPeter Maydell return 0; 136427bfd83cSPeter Maydell } 136527bfd83cSPeter Maydell #endif 136627bfd83cSPeter Maydell 1367be0f34b5SRichard Henderson /* Return true if OP may appear in the opcode stream. 1368be0f34b5SRichard Henderson Test the runtime variable that controls each opcode. */ 1369be0f34b5SRichard Henderson bool tcg_op_supported(TCGOpcode op) 1370be0f34b5SRichard Henderson { 1371d2fd745fSRichard Henderson const bool have_vec 1372d2fd745fSRichard Henderson = TCG_TARGET_HAS_v64 | TCG_TARGET_HAS_v128 | TCG_TARGET_HAS_v256; 1373d2fd745fSRichard Henderson 1374be0f34b5SRichard Henderson switch (op) { 1375be0f34b5SRichard Henderson case INDEX_op_discard: 1376be0f34b5SRichard Henderson case INDEX_op_set_label: 1377be0f34b5SRichard Henderson case INDEX_op_call: 1378be0f34b5SRichard Henderson case INDEX_op_br: 1379be0f34b5SRichard Henderson case INDEX_op_mb: 1380be0f34b5SRichard Henderson case INDEX_op_insn_start: 1381be0f34b5SRichard Henderson case INDEX_op_exit_tb: 1382be0f34b5SRichard Henderson case INDEX_op_goto_tb: 1383f4e01e30SRichard Henderson case INDEX_op_goto_ptr: 1384be0f34b5SRichard Henderson case INDEX_op_qemu_ld_i32: 1385be0f34b5SRichard Henderson case INDEX_op_qemu_st_i32: 1386be0f34b5SRichard Henderson case INDEX_op_qemu_ld_i64: 1387be0f34b5SRichard Henderson case INDEX_op_qemu_st_i64: 1388be0f34b5SRichard Henderson return true; 1389be0f34b5SRichard Henderson 139007ce0b05SRichard Henderson case INDEX_op_qemu_st8_i32: 139107ce0b05SRichard Henderson return TCG_TARGET_HAS_qemu_st8_i32; 139207ce0b05SRichard Henderson 1393be0f34b5SRichard Henderson case INDEX_op_mov_i32: 1394be0f34b5SRichard Henderson case INDEX_op_setcond_i32: 1395be0f34b5SRichard Henderson case INDEX_op_brcond_i32: 1396be0f34b5SRichard Henderson case INDEX_op_ld8u_i32: 1397be0f34b5SRichard Henderson case INDEX_op_ld8s_i32: 1398be0f34b5SRichard Henderson case INDEX_op_ld16u_i32: 1399be0f34b5SRichard Henderson case INDEX_op_ld16s_i32: 1400be0f34b5SRichard Henderson case INDEX_op_ld_i32: 1401be0f34b5SRichard Henderson case INDEX_op_st8_i32: 1402be0f34b5SRichard Henderson case INDEX_op_st16_i32: 1403be0f34b5SRichard Henderson case INDEX_op_st_i32: 1404be0f34b5SRichard Henderson case INDEX_op_add_i32: 1405be0f34b5SRichard Henderson case INDEX_op_sub_i32: 1406be0f34b5SRichard Henderson case INDEX_op_mul_i32: 1407be0f34b5SRichard Henderson case INDEX_op_and_i32: 1408be0f34b5SRichard Henderson case INDEX_op_or_i32: 1409be0f34b5SRichard Henderson case INDEX_op_xor_i32: 1410be0f34b5SRichard Henderson case INDEX_op_shl_i32: 1411be0f34b5SRichard Henderson case INDEX_op_shr_i32: 1412be0f34b5SRichard Henderson case INDEX_op_sar_i32: 1413be0f34b5SRichard Henderson return true; 1414be0f34b5SRichard Henderson 1415be0f34b5SRichard Henderson case INDEX_op_movcond_i32: 1416be0f34b5SRichard Henderson return TCG_TARGET_HAS_movcond_i32; 1417be0f34b5SRichard Henderson case INDEX_op_div_i32: 1418be0f34b5SRichard Henderson case INDEX_op_divu_i32: 1419be0f34b5SRichard Henderson return TCG_TARGET_HAS_div_i32; 1420be0f34b5SRichard Henderson case INDEX_op_rem_i32: 1421be0f34b5SRichard Henderson case INDEX_op_remu_i32: 1422be0f34b5SRichard Henderson return TCG_TARGET_HAS_rem_i32; 1423be0f34b5SRichard Henderson case INDEX_op_div2_i32: 1424be0f34b5SRichard Henderson case INDEX_op_divu2_i32: 1425be0f34b5SRichard Henderson return TCG_TARGET_HAS_div2_i32; 1426be0f34b5SRichard Henderson case INDEX_op_rotl_i32: 1427be0f34b5SRichard Henderson case INDEX_op_rotr_i32: 1428be0f34b5SRichard Henderson return TCG_TARGET_HAS_rot_i32; 1429be0f34b5SRichard Henderson case INDEX_op_deposit_i32: 1430be0f34b5SRichard Henderson return TCG_TARGET_HAS_deposit_i32; 1431be0f34b5SRichard Henderson case INDEX_op_extract_i32: 1432be0f34b5SRichard Henderson return TCG_TARGET_HAS_extract_i32; 1433be0f34b5SRichard Henderson case INDEX_op_sextract_i32: 1434be0f34b5SRichard Henderson return TCG_TARGET_HAS_sextract_i32; 1435fce1296fSRichard Henderson case INDEX_op_extract2_i32: 1436fce1296fSRichard Henderson return TCG_TARGET_HAS_extract2_i32; 1437be0f34b5SRichard Henderson case INDEX_op_add2_i32: 1438be0f34b5SRichard Henderson return TCG_TARGET_HAS_add2_i32; 1439be0f34b5SRichard Henderson case INDEX_op_sub2_i32: 1440be0f34b5SRichard Henderson return TCG_TARGET_HAS_sub2_i32; 1441be0f34b5SRichard Henderson case INDEX_op_mulu2_i32: 1442be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulu2_i32; 1443be0f34b5SRichard Henderson case INDEX_op_muls2_i32: 1444be0f34b5SRichard Henderson return TCG_TARGET_HAS_muls2_i32; 1445be0f34b5SRichard Henderson case INDEX_op_muluh_i32: 1446be0f34b5SRichard Henderson return TCG_TARGET_HAS_muluh_i32; 1447be0f34b5SRichard Henderson case INDEX_op_mulsh_i32: 1448be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulsh_i32; 1449be0f34b5SRichard Henderson case INDEX_op_ext8s_i32: 1450be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8s_i32; 1451be0f34b5SRichard Henderson case INDEX_op_ext16s_i32: 1452be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16s_i32; 1453be0f34b5SRichard Henderson case INDEX_op_ext8u_i32: 1454be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8u_i32; 1455be0f34b5SRichard Henderson case INDEX_op_ext16u_i32: 1456be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16u_i32; 1457be0f34b5SRichard Henderson case INDEX_op_bswap16_i32: 1458be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap16_i32; 1459be0f34b5SRichard Henderson case INDEX_op_bswap32_i32: 1460be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap32_i32; 1461be0f34b5SRichard Henderson case INDEX_op_not_i32: 1462be0f34b5SRichard Henderson return TCG_TARGET_HAS_not_i32; 1463be0f34b5SRichard Henderson case INDEX_op_neg_i32: 1464be0f34b5SRichard Henderson return TCG_TARGET_HAS_neg_i32; 1465be0f34b5SRichard Henderson case INDEX_op_andc_i32: 1466be0f34b5SRichard Henderson return TCG_TARGET_HAS_andc_i32; 1467be0f34b5SRichard Henderson case INDEX_op_orc_i32: 1468be0f34b5SRichard Henderson return TCG_TARGET_HAS_orc_i32; 1469be0f34b5SRichard Henderson case INDEX_op_eqv_i32: 1470be0f34b5SRichard Henderson return TCG_TARGET_HAS_eqv_i32; 1471be0f34b5SRichard Henderson case INDEX_op_nand_i32: 1472be0f34b5SRichard Henderson return TCG_TARGET_HAS_nand_i32; 1473be0f34b5SRichard Henderson case INDEX_op_nor_i32: 1474be0f34b5SRichard Henderson return TCG_TARGET_HAS_nor_i32; 1475be0f34b5SRichard Henderson case INDEX_op_clz_i32: 1476be0f34b5SRichard Henderson return TCG_TARGET_HAS_clz_i32; 1477be0f34b5SRichard Henderson case INDEX_op_ctz_i32: 1478be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctz_i32; 1479be0f34b5SRichard Henderson case INDEX_op_ctpop_i32: 1480be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctpop_i32; 1481be0f34b5SRichard Henderson 1482be0f34b5SRichard Henderson case INDEX_op_brcond2_i32: 1483be0f34b5SRichard Henderson case INDEX_op_setcond2_i32: 1484be0f34b5SRichard Henderson return TCG_TARGET_REG_BITS == 32; 1485be0f34b5SRichard Henderson 1486be0f34b5SRichard Henderson case INDEX_op_mov_i64: 1487be0f34b5SRichard Henderson case INDEX_op_setcond_i64: 1488be0f34b5SRichard Henderson case INDEX_op_brcond_i64: 1489be0f34b5SRichard Henderson case INDEX_op_ld8u_i64: 1490be0f34b5SRichard Henderson case INDEX_op_ld8s_i64: 1491be0f34b5SRichard Henderson case INDEX_op_ld16u_i64: 1492be0f34b5SRichard Henderson case INDEX_op_ld16s_i64: 1493be0f34b5SRichard Henderson case INDEX_op_ld32u_i64: 1494be0f34b5SRichard Henderson case INDEX_op_ld32s_i64: 1495be0f34b5SRichard Henderson case INDEX_op_ld_i64: 1496be0f34b5SRichard Henderson case INDEX_op_st8_i64: 1497be0f34b5SRichard Henderson case INDEX_op_st16_i64: 1498be0f34b5SRichard Henderson case INDEX_op_st32_i64: 1499be0f34b5SRichard Henderson case INDEX_op_st_i64: 1500be0f34b5SRichard Henderson case INDEX_op_add_i64: 1501be0f34b5SRichard Henderson case INDEX_op_sub_i64: 1502be0f34b5SRichard Henderson case INDEX_op_mul_i64: 1503be0f34b5SRichard Henderson case INDEX_op_and_i64: 1504be0f34b5SRichard Henderson case INDEX_op_or_i64: 1505be0f34b5SRichard Henderson case INDEX_op_xor_i64: 1506be0f34b5SRichard Henderson case INDEX_op_shl_i64: 1507be0f34b5SRichard Henderson case INDEX_op_shr_i64: 1508be0f34b5SRichard Henderson case INDEX_op_sar_i64: 1509be0f34b5SRichard Henderson case INDEX_op_ext_i32_i64: 1510be0f34b5SRichard Henderson case INDEX_op_extu_i32_i64: 1511be0f34b5SRichard Henderson return TCG_TARGET_REG_BITS == 64; 1512be0f34b5SRichard Henderson 1513be0f34b5SRichard Henderson case INDEX_op_movcond_i64: 1514be0f34b5SRichard Henderson return TCG_TARGET_HAS_movcond_i64; 1515be0f34b5SRichard Henderson case INDEX_op_div_i64: 1516be0f34b5SRichard Henderson case INDEX_op_divu_i64: 1517be0f34b5SRichard Henderson return TCG_TARGET_HAS_div_i64; 1518be0f34b5SRichard Henderson case INDEX_op_rem_i64: 1519be0f34b5SRichard Henderson case INDEX_op_remu_i64: 1520be0f34b5SRichard Henderson return TCG_TARGET_HAS_rem_i64; 1521be0f34b5SRichard Henderson case INDEX_op_div2_i64: 1522be0f34b5SRichard Henderson case INDEX_op_divu2_i64: 1523be0f34b5SRichard Henderson return TCG_TARGET_HAS_div2_i64; 1524be0f34b5SRichard Henderson case INDEX_op_rotl_i64: 1525be0f34b5SRichard Henderson case INDEX_op_rotr_i64: 1526be0f34b5SRichard Henderson return TCG_TARGET_HAS_rot_i64; 1527be0f34b5SRichard Henderson case INDEX_op_deposit_i64: 1528be0f34b5SRichard Henderson return TCG_TARGET_HAS_deposit_i64; 1529be0f34b5SRichard Henderson case INDEX_op_extract_i64: 1530be0f34b5SRichard Henderson return TCG_TARGET_HAS_extract_i64; 1531be0f34b5SRichard Henderson case INDEX_op_sextract_i64: 1532be0f34b5SRichard Henderson return TCG_TARGET_HAS_sextract_i64; 1533fce1296fSRichard Henderson case INDEX_op_extract2_i64: 1534fce1296fSRichard Henderson return TCG_TARGET_HAS_extract2_i64; 1535be0f34b5SRichard Henderson case INDEX_op_extrl_i64_i32: 1536be0f34b5SRichard Henderson return TCG_TARGET_HAS_extrl_i64_i32; 1537be0f34b5SRichard Henderson case INDEX_op_extrh_i64_i32: 1538be0f34b5SRichard Henderson return TCG_TARGET_HAS_extrh_i64_i32; 1539be0f34b5SRichard Henderson case INDEX_op_ext8s_i64: 1540be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8s_i64; 1541be0f34b5SRichard Henderson case INDEX_op_ext16s_i64: 1542be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16s_i64; 1543be0f34b5SRichard Henderson case INDEX_op_ext32s_i64: 1544be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext32s_i64; 1545be0f34b5SRichard Henderson case INDEX_op_ext8u_i64: 1546be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8u_i64; 1547be0f34b5SRichard Henderson case INDEX_op_ext16u_i64: 1548be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16u_i64; 1549be0f34b5SRichard Henderson case INDEX_op_ext32u_i64: 1550be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext32u_i64; 1551be0f34b5SRichard Henderson case INDEX_op_bswap16_i64: 1552be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap16_i64; 1553be0f34b5SRichard Henderson case INDEX_op_bswap32_i64: 1554be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap32_i64; 1555be0f34b5SRichard Henderson case INDEX_op_bswap64_i64: 1556be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap64_i64; 1557be0f34b5SRichard Henderson case INDEX_op_not_i64: 1558be0f34b5SRichard Henderson return TCG_TARGET_HAS_not_i64; 1559be0f34b5SRichard Henderson case INDEX_op_neg_i64: 1560be0f34b5SRichard Henderson return TCG_TARGET_HAS_neg_i64; 1561be0f34b5SRichard Henderson case INDEX_op_andc_i64: 1562be0f34b5SRichard Henderson return TCG_TARGET_HAS_andc_i64; 1563be0f34b5SRichard Henderson case INDEX_op_orc_i64: 1564be0f34b5SRichard Henderson return TCG_TARGET_HAS_orc_i64; 1565be0f34b5SRichard Henderson case INDEX_op_eqv_i64: 1566be0f34b5SRichard Henderson return TCG_TARGET_HAS_eqv_i64; 1567be0f34b5SRichard Henderson case INDEX_op_nand_i64: 1568be0f34b5SRichard Henderson return TCG_TARGET_HAS_nand_i64; 1569be0f34b5SRichard Henderson case INDEX_op_nor_i64: 1570be0f34b5SRichard Henderson return TCG_TARGET_HAS_nor_i64; 1571be0f34b5SRichard Henderson case INDEX_op_clz_i64: 1572be0f34b5SRichard Henderson return TCG_TARGET_HAS_clz_i64; 1573be0f34b5SRichard Henderson case INDEX_op_ctz_i64: 1574be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctz_i64; 1575be0f34b5SRichard Henderson case INDEX_op_ctpop_i64: 1576be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctpop_i64; 1577be0f34b5SRichard Henderson case INDEX_op_add2_i64: 1578be0f34b5SRichard Henderson return TCG_TARGET_HAS_add2_i64; 1579be0f34b5SRichard Henderson case INDEX_op_sub2_i64: 1580be0f34b5SRichard Henderson return TCG_TARGET_HAS_sub2_i64; 1581be0f34b5SRichard Henderson case INDEX_op_mulu2_i64: 1582be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulu2_i64; 1583be0f34b5SRichard Henderson case INDEX_op_muls2_i64: 1584be0f34b5SRichard Henderson return TCG_TARGET_HAS_muls2_i64; 1585be0f34b5SRichard Henderson case INDEX_op_muluh_i64: 1586be0f34b5SRichard Henderson return TCG_TARGET_HAS_muluh_i64; 1587be0f34b5SRichard Henderson case INDEX_op_mulsh_i64: 1588be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulsh_i64; 1589be0f34b5SRichard Henderson 1590d2fd745fSRichard Henderson case INDEX_op_mov_vec: 1591d2fd745fSRichard Henderson case INDEX_op_dup_vec: 159237ee55a0SRichard Henderson case INDEX_op_dupm_vec: 1593d2fd745fSRichard Henderson case INDEX_op_ld_vec: 1594d2fd745fSRichard Henderson case INDEX_op_st_vec: 1595d2fd745fSRichard Henderson case INDEX_op_add_vec: 1596d2fd745fSRichard Henderson case INDEX_op_sub_vec: 1597d2fd745fSRichard Henderson case INDEX_op_and_vec: 1598d2fd745fSRichard Henderson case INDEX_op_or_vec: 1599d2fd745fSRichard Henderson case INDEX_op_xor_vec: 1600212be173SRichard Henderson case INDEX_op_cmp_vec: 1601d2fd745fSRichard Henderson return have_vec; 1602d2fd745fSRichard Henderson case INDEX_op_dup2_vec: 1603d2fd745fSRichard Henderson return have_vec && TCG_TARGET_REG_BITS == 32; 1604d2fd745fSRichard Henderson case INDEX_op_not_vec: 1605d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_not_vec; 1606d2fd745fSRichard Henderson case INDEX_op_neg_vec: 1607d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_neg_vec; 1608bcefc902SRichard Henderson case INDEX_op_abs_vec: 1609bcefc902SRichard Henderson return have_vec && TCG_TARGET_HAS_abs_vec; 1610d2fd745fSRichard Henderson case INDEX_op_andc_vec: 1611d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_andc_vec; 1612d2fd745fSRichard Henderson case INDEX_op_orc_vec: 1613d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_orc_vec; 1614ed523473SRichard Henderson case INDEX_op_nand_vec: 1615ed523473SRichard Henderson return have_vec && TCG_TARGET_HAS_nand_vec; 1616ed523473SRichard Henderson case INDEX_op_nor_vec: 1617ed523473SRichard Henderson return have_vec && TCG_TARGET_HAS_nor_vec; 1618ed523473SRichard Henderson case INDEX_op_eqv_vec: 1619ed523473SRichard Henderson return have_vec && TCG_TARGET_HAS_eqv_vec; 16203774030aSRichard Henderson case INDEX_op_mul_vec: 16213774030aSRichard Henderson return have_vec && TCG_TARGET_HAS_mul_vec; 1622d0ec9796SRichard Henderson case INDEX_op_shli_vec: 1623d0ec9796SRichard Henderson case INDEX_op_shri_vec: 1624d0ec9796SRichard Henderson case INDEX_op_sari_vec: 1625d0ec9796SRichard Henderson return have_vec && TCG_TARGET_HAS_shi_vec; 1626d0ec9796SRichard Henderson case INDEX_op_shls_vec: 1627d0ec9796SRichard Henderson case INDEX_op_shrs_vec: 1628d0ec9796SRichard Henderson case INDEX_op_sars_vec: 1629d0ec9796SRichard Henderson return have_vec && TCG_TARGET_HAS_shs_vec; 1630d0ec9796SRichard Henderson case INDEX_op_shlv_vec: 1631d0ec9796SRichard Henderson case INDEX_op_shrv_vec: 1632d0ec9796SRichard Henderson case INDEX_op_sarv_vec: 1633d0ec9796SRichard Henderson return have_vec && TCG_TARGET_HAS_shv_vec; 1634b0f7e744SRichard Henderson case INDEX_op_rotli_vec: 1635b0f7e744SRichard Henderson return have_vec && TCG_TARGET_HAS_roti_vec; 163623850a74SRichard Henderson case INDEX_op_rotls_vec: 163723850a74SRichard Henderson return have_vec && TCG_TARGET_HAS_rots_vec; 16385d0ceda9SRichard Henderson case INDEX_op_rotlv_vec: 16395d0ceda9SRichard Henderson case INDEX_op_rotrv_vec: 16405d0ceda9SRichard Henderson return have_vec && TCG_TARGET_HAS_rotv_vec; 16418afaf050SRichard Henderson case INDEX_op_ssadd_vec: 16428afaf050SRichard Henderson case INDEX_op_usadd_vec: 16438afaf050SRichard Henderson case INDEX_op_sssub_vec: 16448afaf050SRichard Henderson case INDEX_op_ussub_vec: 16458afaf050SRichard Henderson return have_vec && TCG_TARGET_HAS_sat_vec; 1646dd0a0fcdSRichard Henderson case INDEX_op_smin_vec: 1647dd0a0fcdSRichard Henderson case INDEX_op_umin_vec: 1648dd0a0fcdSRichard Henderson case INDEX_op_smax_vec: 1649dd0a0fcdSRichard Henderson case INDEX_op_umax_vec: 1650dd0a0fcdSRichard Henderson return have_vec && TCG_TARGET_HAS_minmax_vec; 165138dc1294SRichard Henderson case INDEX_op_bitsel_vec: 165238dc1294SRichard Henderson return have_vec && TCG_TARGET_HAS_bitsel_vec; 1653f75da298SRichard Henderson case INDEX_op_cmpsel_vec: 1654f75da298SRichard Henderson return have_vec && TCG_TARGET_HAS_cmpsel_vec; 1655d2fd745fSRichard Henderson 1656db432672SRichard Henderson default: 1657db432672SRichard Henderson tcg_debug_assert(op > INDEX_op_last_generic && op < NB_OPS); 1658db432672SRichard Henderson return true; 1659be0f34b5SRichard Henderson } 1660be0f34b5SRichard Henderson } 1661be0f34b5SRichard Henderson 166239004a71SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs); 166339004a71SRichard Henderson 1664ae8b75dcSRichard Henderson void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args) 1665c896fe29Sbellard { 16663e92aa34SRichard Henderson const TCGHelperInfo *info; 166739004a71SRichard Henderson TCGv_i64 extend_free[MAX_CALL_IARGS]; 166839004a71SRichard Henderson int n_extend = 0; 166975e8b9b7SRichard Henderson TCGOp *op; 167039004a71SRichard Henderson int i, n, pi = 0, total_args; 1671afb49896SRichard Henderson 1672619205fdSEmilio G. Cota info = g_hash_table_lookup(helper_table, (gpointer)func); 167339004a71SRichard Henderson total_args = info->nr_out + info->nr_in + 2; 167439004a71SRichard Henderson op = tcg_op_alloc(INDEX_op_call, total_args); 16752bece2c8SRichard Henderson 167638b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN 167738b47b19SEmilio G. Cota /* detect non-plugin helpers */ 167838b47b19SEmilio G. Cota if (tcg_ctx->plugin_insn && unlikely(strncmp(info->name, "plugin_", 7))) { 167938b47b19SEmilio G. Cota tcg_ctx->plugin_insn->calls_helpers = true; 168038b47b19SEmilio G. Cota } 168138b47b19SEmilio G. Cota #endif 168238b47b19SEmilio G. Cota 168339004a71SRichard Henderson TCGOP_CALLO(op) = n = info->nr_out; 168439004a71SRichard Henderson switch (n) { 168539004a71SRichard Henderson case 0: 168639004a71SRichard Henderson tcg_debug_assert(ret == NULL); 168739004a71SRichard Henderson break; 168839004a71SRichard Henderson case 1: 168939004a71SRichard Henderson tcg_debug_assert(ret != NULL); 169039004a71SRichard Henderson op->args[pi++] = temp_arg(ret); 169139004a71SRichard Henderson break; 169239004a71SRichard Henderson case 2: 169339004a71SRichard Henderson tcg_debug_assert(ret != NULL); 169439004a71SRichard Henderson tcg_debug_assert(ret->base_type == ret->type + 1); 169539004a71SRichard Henderson tcg_debug_assert(ret->temp_subindex == 0); 169639004a71SRichard Henderson op->args[pi++] = temp_arg(ret); 169739004a71SRichard Henderson op->args[pi++] = temp_arg(ret + 1); 169839004a71SRichard Henderson break; 169939004a71SRichard Henderson default: 170039004a71SRichard Henderson g_assert_not_reached(); 170139004a71SRichard Henderson } 17027319d83aSRichard Henderson 170339004a71SRichard Henderson TCGOP_CALLI(op) = n = info->nr_in; 170439004a71SRichard Henderson for (i = 0; i < n; i++) { 170539004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i]; 170639004a71SRichard Henderson TCGTemp *ts = args[loc->arg_idx] + loc->tmp_subindex; 170739004a71SRichard Henderson 170839004a71SRichard Henderson switch (loc->kind) { 170939004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 171039004a71SRichard Henderson op->args[pi++] = temp_arg(ts); 171139004a71SRichard Henderson break; 171239004a71SRichard Henderson 171339004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 171439004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 171539004a71SRichard Henderson { 17162bece2c8SRichard Henderson TCGv_i64 temp = tcg_temp_new_i64(); 171739004a71SRichard Henderson TCGv_i32 orig = temp_tcgv_i32(ts); 171839004a71SRichard Henderson 171939004a71SRichard Henderson if (loc->kind == TCG_CALL_ARG_EXTEND_S) { 172018cf3d07SRichard Henderson tcg_gen_ext_i32_i64(temp, orig); 17212bece2c8SRichard Henderson } else { 172218cf3d07SRichard Henderson tcg_gen_extu_i32_i64(temp, orig); 17232bece2c8SRichard Henderson } 172439004a71SRichard Henderson op->args[pi++] = tcgv_i64_arg(temp); 172539004a71SRichard Henderson extend_free[n_extend++] = temp; 17262bece2c8SRichard Henderson } 172739004a71SRichard Henderson break; 17282bece2c8SRichard Henderson 1729e2a9dd6bSRichard Henderson default: 1730e2a9dd6bSRichard Henderson g_assert_not_reached(); 1731e2a9dd6bSRichard Henderson } 1732c896fe29Sbellard } 173375e8b9b7SRichard Henderson op->args[pi++] = (uintptr_t)func; 17343e92aa34SRichard Henderson op->args[pi++] = (uintptr_t)info; 173539004a71SRichard Henderson tcg_debug_assert(pi == total_args); 1736a7812ae4Spbrook 173739004a71SRichard Henderson QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link); 17382bece2c8SRichard Henderson 173939004a71SRichard Henderson tcg_debug_assert(n_extend < ARRAY_SIZE(extend_free)); 174039004a71SRichard Henderson for (i = 0; i < n_extend; ++i) { 174139004a71SRichard Henderson tcg_temp_free_i64(extend_free[i]); 1742eb8b0224SRichard Henderson } 1743a7812ae4Spbrook } 1744c896fe29Sbellard 17458fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s) 1746c896fe29Sbellard { 1747ac3b8891SRichard Henderson int i, n; 1748ac3b8891SRichard Henderson 1749ee17db83SRichard Henderson for (i = 0, n = s->nb_temps; i < n; i++) { 1750ee17db83SRichard Henderson TCGTemp *ts = &s->temps[i]; 1751ee17db83SRichard Henderson TCGTempVal val = TEMP_VAL_MEM; 1752ee17db83SRichard Henderson 1753ee17db83SRichard Henderson switch (ts->kind) { 1754c0522136SRichard Henderson case TEMP_CONST: 1755c0522136SRichard Henderson val = TEMP_VAL_CONST; 1756c0522136SRichard Henderson break; 1757ee17db83SRichard Henderson case TEMP_FIXED: 1758ee17db83SRichard Henderson val = TEMP_VAL_REG; 1759ee17db83SRichard Henderson break; 1760ee17db83SRichard Henderson case TEMP_GLOBAL: 1761ee17db83SRichard Henderson break; 1762ee17db83SRichard Henderson case TEMP_NORMAL: 1763c7482438SRichard Henderson case TEMP_EBB: 1764ee17db83SRichard Henderson val = TEMP_VAL_DEAD; 1765ee17db83SRichard Henderson /* fall through */ 1766ee17db83SRichard Henderson case TEMP_LOCAL: 1767e8996ee0Sbellard ts->mem_allocated = 0; 1768ee17db83SRichard Henderson break; 1769ee17db83SRichard Henderson default: 1770ee17db83SRichard Henderson g_assert_not_reached(); 1771ee17db83SRichard Henderson } 1772ee17db83SRichard Henderson ts->val_type = val; 1773e8996ee0Sbellard } 1774f8b2f202SRichard Henderson 1775f8b2f202SRichard Henderson memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp)); 1776c896fe29Sbellard } 1777c896fe29Sbellard 1778f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size, 1779f8b2f202SRichard Henderson TCGTemp *ts) 1780c896fe29Sbellard { 17811807f4c4SRichard Henderson int idx = temp_idx(ts); 1782ac56dd48Spbrook 1783ee17db83SRichard Henderson switch (ts->kind) { 1784ee17db83SRichard Henderson case TEMP_FIXED: 1785ee17db83SRichard Henderson case TEMP_GLOBAL: 1786ac56dd48Spbrook pstrcpy(buf, buf_size, ts->name); 1787ee17db83SRichard Henderson break; 1788ee17db83SRichard Henderson case TEMP_LOCAL: 1789641d5fbeSbellard snprintf(buf, buf_size, "loc%d", idx - s->nb_globals); 1790ee17db83SRichard Henderson break; 1791c7482438SRichard Henderson case TEMP_EBB: 1792c7482438SRichard Henderson snprintf(buf, buf_size, "ebb%d", idx - s->nb_globals); 1793c7482438SRichard Henderson break; 1794ee17db83SRichard Henderson case TEMP_NORMAL: 1795ac56dd48Spbrook snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals); 1796ee17db83SRichard Henderson break; 1797c0522136SRichard Henderson case TEMP_CONST: 1798c0522136SRichard Henderson switch (ts->type) { 1799c0522136SRichard Henderson case TCG_TYPE_I32: 1800c0522136SRichard Henderson snprintf(buf, buf_size, "$0x%x", (int32_t)ts->val); 1801c0522136SRichard Henderson break; 1802c0522136SRichard Henderson #if TCG_TARGET_REG_BITS > 32 1803c0522136SRichard Henderson case TCG_TYPE_I64: 1804c0522136SRichard Henderson snprintf(buf, buf_size, "$0x%" PRIx64, ts->val); 1805c0522136SRichard Henderson break; 1806c0522136SRichard Henderson #endif 1807c0522136SRichard Henderson case TCG_TYPE_V64: 1808c0522136SRichard Henderson case TCG_TYPE_V128: 1809c0522136SRichard Henderson case TCG_TYPE_V256: 1810c0522136SRichard Henderson snprintf(buf, buf_size, "v%d$0x%" PRIx64, 1811c0522136SRichard Henderson 64 << (ts->type - TCG_TYPE_V64), ts->val); 1812c0522136SRichard Henderson break; 1813c0522136SRichard Henderson default: 1814c0522136SRichard Henderson g_assert_not_reached(); 1815c0522136SRichard Henderson } 1816c0522136SRichard Henderson break; 1817c896fe29Sbellard } 1818c896fe29Sbellard return buf; 1819c896fe29Sbellard } 1820c896fe29Sbellard 182143439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf, 182243439139SRichard Henderson int buf_size, TCGArg arg) 1823f8b2f202SRichard Henderson { 182443439139SRichard Henderson return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg)); 1825f8b2f202SRichard Henderson } 1826f8b2f202SRichard Henderson 1827f48f3edeSblueswir1 static const char * const cond_name[] = 1828f48f3edeSblueswir1 { 18290aed257fSRichard Henderson [TCG_COND_NEVER] = "never", 18300aed257fSRichard Henderson [TCG_COND_ALWAYS] = "always", 1831f48f3edeSblueswir1 [TCG_COND_EQ] = "eq", 1832f48f3edeSblueswir1 [TCG_COND_NE] = "ne", 1833f48f3edeSblueswir1 [TCG_COND_LT] = "lt", 1834f48f3edeSblueswir1 [TCG_COND_GE] = "ge", 1835f48f3edeSblueswir1 [TCG_COND_LE] = "le", 1836f48f3edeSblueswir1 [TCG_COND_GT] = "gt", 1837f48f3edeSblueswir1 [TCG_COND_LTU] = "ltu", 1838f48f3edeSblueswir1 [TCG_COND_GEU] = "geu", 1839f48f3edeSblueswir1 [TCG_COND_LEU] = "leu", 1840f48f3edeSblueswir1 [TCG_COND_GTU] = "gtu" 1841f48f3edeSblueswir1 }; 1842f48f3edeSblueswir1 1843f713d6adSRichard Henderson static const char * const ldst_name[] = 1844f713d6adSRichard Henderson { 1845f713d6adSRichard Henderson [MO_UB] = "ub", 1846f713d6adSRichard Henderson [MO_SB] = "sb", 1847f713d6adSRichard Henderson [MO_LEUW] = "leuw", 1848f713d6adSRichard Henderson [MO_LESW] = "lesw", 1849f713d6adSRichard Henderson [MO_LEUL] = "leul", 1850f713d6adSRichard Henderson [MO_LESL] = "lesl", 1851fc313c64SFrédéric Pétrot [MO_LEUQ] = "leq", 1852f713d6adSRichard Henderson [MO_BEUW] = "beuw", 1853f713d6adSRichard Henderson [MO_BESW] = "besw", 1854f713d6adSRichard Henderson [MO_BEUL] = "beul", 1855f713d6adSRichard Henderson [MO_BESL] = "besl", 1856fc313c64SFrédéric Pétrot [MO_BEUQ] = "beq", 1857f713d6adSRichard Henderson }; 1858f713d6adSRichard Henderson 18591f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = { 186052bf9771Stony.nguyen@bt.com #ifdef TARGET_ALIGNED_ONLY 18611f00b27fSSergey Sorokin [MO_UNALN >> MO_ASHIFT] = "un+", 18621f00b27fSSergey Sorokin [MO_ALIGN >> MO_ASHIFT] = "", 18631f00b27fSSergey Sorokin #else 18641f00b27fSSergey Sorokin [MO_UNALN >> MO_ASHIFT] = "", 18651f00b27fSSergey Sorokin [MO_ALIGN >> MO_ASHIFT] = "al+", 18661f00b27fSSergey Sorokin #endif 18671f00b27fSSergey Sorokin [MO_ALIGN_2 >> MO_ASHIFT] = "al2+", 18681f00b27fSSergey Sorokin [MO_ALIGN_4 >> MO_ASHIFT] = "al4+", 18691f00b27fSSergey Sorokin [MO_ALIGN_8 >> MO_ASHIFT] = "al8+", 18701f00b27fSSergey Sorokin [MO_ALIGN_16 >> MO_ASHIFT] = "al16+", 18711f00b27fSSergey Sorokin [MO_ALIGN_32 >> MO_ASHIFT] = "al32+", 18721f00b27fSSergey Sorokin [MO_ALIGN_64 >> MO_ASHIFT] = "al64+", 18731f00b27fSSergey Sorokin }; 18741f00b27fSSergey Sorokin 1875587195bdSRichard Henderson static const char bswap_flag_name[][6] = { 1876587195bdSRichard Henderson [TCG_BSWAP_IZ] = "iz", 1877587195bdSRichard Henderson [TCG_BSWAP_OZ] = "oz", 1878587195bdSRichard Henderson [TCG_BSWAP_OS] = "os", 1879587195bdSRichard Henderson [TCG_BSWAP_IZ | TCG_BSWAP_OZ] = "iz,oz", 1880587195bdSRichard Henderson [TCG_BSWAP_IZ | TCG_BSWAP_OS] = "iz,os", 1881587195bdSRichard Henderson }; 1882587195bdSRichard Henderson 1883b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d) 1884b016486eSRichard Henderson { 1885b016486eSRichard Henderson return (d & (d - 1)) == 0; 1886b016486eSRichard Henderson } 1887b016486eSRichard Henderson 1888b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d) 1889b016486eSRichard Henderson { 1890b016486eSRichard Henderson if (TCG_TARGET_NB_REGS <= 32) { 1891b016486eSRichard Henderson return ctz32(d); 1892b016486eSRichard Henderson } else { 1893b016486eSRichard Henderson return ctz64(d); 1894b016486eSRichard Henderson } 1895b016486eSRichard Henderson } 1896b016486eSRichard Henderson 1897b7a83ff8SRichard Henderson /* Return only the number of characters output -- no error return. */ 1898b7a83ff8SRichard Henderson #define ne_fprintf(...) \ 1899b7a83ff8SRichard Henderson ({ int ret_ = fprintf(__VA_ARGS__); ret_ >= 0 ? ret_ : 0; }) 1900b7a83ff8SRichard Henderson 1901b7a83ff8SRichard Henderson static void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs) 1902c896fe29Sbellard { 1903c896fe29Sbellard char buf[128]; 1904c45cb8bbSRichard Henderson TCGOp *op; 1905c896fe29Sbellard 190615fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 1907c45cb8bbSRichard Henderson int i, k, nb_oargs, nb_iargs, nb_cargs; 1908c45cb8bbSRichard Henderson const TCGOpDef *def; 1909c45cb8bbSRichard Henderson TCGOpcode c; 1910bdfb460eSRichard Henderson int col = 0; 1911c45cb8bbSRichard Henderson 1912c45cb8bbSRichard Henderson c = op->opc; 1913c896fe29Sbellard def = &tcg_op_defs[c]; 1914c45cb8bbSRichard Henderson 1915765b842aSRichard Henderson if (c == INDEX_op_insn_start) { 1916b016486eSRichard Henderson nb_oargs = 0; 1917b7a83ff8SRichard Henderson col += ne_fprintf(f, "\n ----"); 19189aef40edSRichard Henderson 19199aef40edSRichard Henderson for (i = 0; i < TARGET_INSN_START_WORDS; ++i) { 19209aef40edSRichard Henderson target_ulong a; 19217e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS 1922efee3746SRichard Henderson a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]); 19237e4597d7Sbellard #else 1924efee3746SRichard Henderson a = op->args[i]; 19257e4597d7Sbellard #endif 1926b7a83ff8SRichard Henderson col += ne_fprintf(f, " " TARGET_FMT_lx, a); 1927eeacee4dSBlue Swirl } 19287e4597d7Sbellard } else if (c == INDEX_op_call) { 19293e92aa34SRichard Henderson const TCGHelperInfo *info = tcg_call_info(op); 1930fa52e660SRichard Henderson void *func = tcg_call_func(op); 19313e92aa34SRichard Henderson 1932c896fe29Sbellard /* variable number of arguments */ 1933cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 1934cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 1935c896fe29Sbellard nb_cargs = def->nb_cargs; 1936b03cce8eSbellard 1937b7a83ff8SRichard Henderson col += ne_fprintf(f, " %s ", def->name); 19383e92aa34SRichard Henderson 19393e92aa34SRichard Henderson /* 19403e92aa34SRichard Henderson * Print the function name from TCGHelperInfo, if available. 19413e92aa34SRichard Henderson * Note that plugins have a template function for the info, 19423e92aa34SRichard Henderson * but the actual function pointer comes from the plugin. 19433e92aa34SRichard Henderson */ 19443e92aa34SRichard Henderson if (func == info->func) { 1945b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s", info->name); 19463e92aa34SRichard Henderson } else { 1947b7a83ff8SRichard Henderson col += ne_fprintf(f, "plugin(%p)", func); 19483e92aa34SRichard Henderson } 19493e92aa34SRichard Henderson 1950b7a83ff8SRichard Henderson col += ne_fprintf(f, ",$0x%x,$%d", info->flags, nb_oargs); 1951b03cce8eSbellard for (i = 0; i < nb_oargs; i++) { 1952b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", tcg_get_arg_str(s, buf, sizeof(buf), 1953efee3746SRichard Henderson op->args[i])); 1954b03cce8eSbellard } 1955cf066674SRichard Henderson for (i = 0; i < nb_iargs; i++) { 1956efee3746SRichard Henderson TCGArg arg = op->args[nb_oargs + i]; 195739004a71SRichard Henderson const char *t = tcg_get_arg_str(s, buf, sizeof(buf), arg); 1958b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", t); 1959e8996ee0Sbellard } 1960b03cce8eSbellard } else { 1961b7a83ff8SRichard Henderson col += ne_fprintf(f, " %s ", def->name); 1962c45cb8bbSRichard Henderson 1963c896fe29Sbellard nb_oargs = def->nb_oargs; 1964c896fe29Sbellard nb_iargs = def->nb_iargs; 1965c896fe29Sbellard nb_cargs = def->nb_cargs; 1966c896fe29Sbellard 1967d2fd745fSRichard Henderson if (def->flags & TCG_OPF_VECTOR) { 1968b7a83ff8SRichard Henderson col += ne_fprintf(f, "v%d,e%d,", 64 << TCGOP_VECL(op), 1969d2fd745fSRichard Henderson 8 << TCGOP_VECE(op)); 1970d2fd745fSRichard Henderson } 1971d2fd745fSRichard Henderson 1972c896fe29Sbellard k = 0; 1973c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 1974b7a83ff8SRichard Henderson const char *sep = k ? "," : ""; 1975b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s%s", sep, 1976b7a83ff8SRichard Henderson tcg_get_arg_str(s, buf, sizeof(buf), 1977efee3746SRichard Henderson op->args[k++])); 1978c896fe29Sbellard } 1979c896fe29Sbellard for (i = 0; i < nb_iargs; i++) { 1980b7a83ff8SRichard Henderson const char *sep = k ? "," : ""; 1981b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s%s", sep, 1982b7a83ff8SRichard Henderson tcg_get_arg_str(s, buf, sizeof(buf), 1983efee3746SRichard Henderson op->args[k++])); 1984c896fe29Sbellard } 1985be210acbSRichard Henderson switch (c) { 1986be210acbSRichard Henderson case INDEX_op_brcond_i32: 1987ffc5ea09SRichard Henderson case INDEX_op_setcond_i32: 1988ffc5ea09SRichard Henderson case INDEX_op_movcond_i32: 1989be210acbSRichard Henderson case INDEX_op_brcond2_i32: 1990be210acbSRichard Henderson case INDEX_op_setcond2_i32: 1991ffc5ea09SRichard Henderson case INDEX_op_brcond_i64: 1992be210acbSRichard Henderson case INDEX_op_setcond_i64: 1993ffc5ea09SRichard Henderson case INDEX_op_movcond_i64: 1994212be173SRichard Henderson case INDEX_op_cmp_vec: 1995f75da298SRichard Henderson case INDEX_op_cmpsel_vec: 1996efee3746SRichard Henderson if (op->args[k] < ARRAY_SIZE(cond_name) 1997efee3746SRichard Henderson && cond_name[op->args[k]]) { 1998b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", cond_name[op->args[k++]]); 1999eeacee4dSBlue Swirl } else { 2000b7a83ff8SRichard Henderson col += ne_fprintf(f, ",$0x%" TCG_PRIlx, op->args[k++]); 2001eeacee4dSBlue Swirl } 2002f48f3edeSblueswir1 i = 1; 2003be210acbSRichard Henderson break; 2004f713d6adSRichard Henderson case INDEX_op_qemu_ld_i32: 2005f713d6adSRichard Henderson case INDEX_op_qemu_st_i32: 200607ce0b05SRichard Henderson case INDEX_op_qemu_st8_i32: 2007f713d6adSRichard Henderson case INDEX_op_qemu_ld_i64: 2008f713d6adSRichard Henderson case INDEX_op_qemu_st_i64: 200959227d5dSRichard Henderson { 20109002ffcbSRichard Henderson MemOpIdx oi = op->args[k++]; 201114776ab5STony Nguyen MemOp op = get_memop(oi); 201259227d5dSRichard Henderson unsigned ix = get_mmuidx(oi); 201359227d5dSRichard Henderson 201459c4b7e8SRichard Henderson if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) { 2015b7a83ff8SRichard Henderson col += ne_fprintf(f, ",$0x%x,%u", op, ix); 201659c4b7e8SRichard Henderson } else { 20171f00b27fSSergey Sorokin const char *s_al, *s_op; 20181f00b27fSSergey Sorokin s_al = alignment_name[(op & MO_AMASK) >> MO_ASHIFT]; 201959c4b7e8SRichard Henderson s_op = ldst_name[op & (MO_BSWAP | MO_SSIZE)]; 2020b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s%s,%u", s_al, s_op, ix); 2021f713d6adSRichard Henderson } 2022f713d6adSRichard Henderson i = 1; 202359227d5dSRichard Henderson } 2024f713d6adSRichard Henderson break; 2025587195bdSRichard Henderson case INDEX_op_bswap16_i32: 2026587195bdSRichard Henderson case INDEX_op_bswap16_i64: 2027587195bdSRichard Henderson case INDEX_op_bswap32_i32: 2028587195bdSRichard Henderson case INDEX_op_bswap32_i64: 2029587195bdSRichard Henderson case INDEX_op_bswap64_i64: 2030587195bdSRichard Henderson { 2031587195bdSRichard Henderson TCGArg flags = op->args[k]; 2032587195bdSRichard Henderson const char *name = NULL; 2033587195bdSRichard Henderson 2034587195bdSRichard Henderson if (flags < ARRAY_SIZE(bswap_flag_name)) { 2035587195bdSRichard Henderson name = bswap_flag_name[flags]; 2036587195bdSRichard Henderson } 2037587195bdSRichard Henderson if (name) { 2038b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", name); 2039587195bdSRichard Henderson } else { 2040b7a83ff8SRichard Henderson col += ne_fprintf(f, ",$0x%" TCG_PRIlx, flags); 2041587195bdSRichard Henderson } 2042587195bdSRichard Henderson i = k = 1; 2043587195bdSRichard Henderson } 2044587195bdSRichard Henderson break; 2045be210acbSRichard Henderson default: 2046f48f3edeSblueswir1 i = 0; 2047be210acbSRichard Henderson break; 2048be210acbSRichard Henderson } 204951e3972cSRichard Henderson switch (c) { 205051e3972cSRichard Henderson case INDEX_op_set_label: 205151e3972cSRichard Henderson case INDEX_op_br: 205251e3972cSRichard Henderson case INDEX_op_brcond_i32: 205351e3972cSRichard Henderson case INDEX_op_brcond_i64: 205451e3972cSRichard Henderson case INDEX_op_brcond2_i32: 2055b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s$L%d", k ? "," : "", 2056efee3746SRichard Henderson arg_label(op->args[k])->id); 205751e3972cSRichard Henderson i++, k++; 205851e3972cSRichard Henderson break; 205951e3972cSRichard Henderson default: 206051e3972cSRichard Henderson break; 2061eeacee4dSBlue Swirl } 206251e3972cSRichard Henderson for (; i < nb_cargs; i++, k++) { 2063b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s$0x%" TCG_PRIlx, k ? "," : "", 2064b7a83ff8SRichard Henderson op->args[k]); 2065bdfb460eSRichard Henderson } 2066bdfb460eSRichard Henderson } 2067bdfb460eSRichard Henderson 20681894f69aSRichard Henderson if (have_prefs || op->life) { 20691894f69aSRichard Henderson for (; col < 40; ++col) { 2070b7a83ff8SRichard Henderson putc(' ', f); 2071bdfb460eSRichard Henderson } 20721894f69aSRichard Henderson } 20731894f69aSRichard Henderson 20741894f69aSRichard Henderson if (op->life) { 20751894f69aSRichard Henderson unsigned life = op->life; 2076bdfb460eSRichard Henderson 2077bdfb460eSRichard Henderson if (life & (SYNC_ARG * 3)) { 2078b7a83ff8SRichard Henderson ne_fprintf(f, " sync:"); 2079bdfb460eSRichard Henderson for (i = 0; i < 2; ++i) { 2080bdfb460eSRichard Henderson if (life & (SYNC_ARG << i)) { 2081b7a83ff8SRichard Henderson ne_fprintf(f, " %d", i); 2082bdfb460eSRichard Henderson } 2083bdfb460eSRichard Henderson } 2084bdfb460eSRichard Henderson } 2085bdfb460eSRichard Henderson life /= DEAD_ARG; 2086bdfb460eSRichard Henderson if (life) { 2087b7a83ff8SRichard Henderson ne_fprintf(f, " dead:"); 2088bdfb460eSRichard Henderson for (i = 0; life; ++i, life >>= 1) { 2089bdfb460eSRichard Henderson if (life & 1) { 2090b7a83ff8SRichard Henderson ne_fprintf(f, " %d", i); 2091bdfb460eSRichard Henderson } 2092bdfb460eSRichard Henderson } 2093c896fe29Sbellard } 2094b03cce8eSbellard } 20951894f69aSRichard Henderson 20961894f69aSRichard Henderson if (have_prefs) { 20971894f69aSRichard Henderson for (i = 0; i < nb_oargs; ++i) { 209831fd884bSRichard Henderson TCGRegSet set = output_pref(op, i); 20991894f69aSRichard Henderson 21001894f69aSRichard Henderson if (i == 0) { 2101b7a83ff8SRichard Henderson ne_fprintf(f, " pref="); 21021894f69aSRichard Henderson } else { 2103b7a83ff8SRichard Henderson ne_fprintf(f, ","); 21041894f69aSRichard Henderson } 21051894f69aSRichard Henderson if (set == 0) { 2106b7a83ff8SRichard Henderson ne_fprintf(f, "none"); 21071894f69aSRichard Henderson } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) { 2108b7a83ff8SRichard Henderson ne_fprintf(f, "all"); 21091894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG 21101894f69aSRichard Henderson } else if (tcg_regset_single(set)) { 21111894f69aSRichard Henderson TCGReg reg = tcg_regset_first(set); 2112b7a83ff8SRichard Henderson ne_fprintf(f, "%s", tcg_target_reg_names[reg]); 21131894f69aSRichard Henderson #endif 21141894f69aSRichard Henderson } else if (TCG_TARGET_NB_REGS <= 32) { 2115b7a83ff8SRichard Henderson ne_fprintf(f, "0x%x", (uint32_t)set); 21161894f69aSRichard Henderson } else { 2117b7a83ff8SRichard Henderson ne_fprintf(f, "0x%" PRIx64, (uint64_t)set); 21181894f69aSRichard Henderson } 21191894f69aSRichard Henderson } 21201894f69aSRichard Henderson } 21211894f69aSRichard Henderson 2122b7a83ff8SRichard Henderson putc('\n', f); 2123c896fe29Sbellard } 2124c896fe29Sbellard } 2125c896fe29Sbellard 2126c896fe29Sbellard /* we give more priority to constraints with less registers */ 2127c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k) 2128c896fe29Sbellard { 212974a11790SRichard Henderson const TCGArgConstraint *arg_ct = &def->args_ct[k]; 213029f5e925SRichard Henderson int n = ctpop64(arg_ct->regs); 2131c896fe29Sbellard 213229f5e925SRichard Henderson /* 213329f5e925SRichard Henderson * Sort constraints of a single register first, which includes output 213429f5e925SRichard Henderson * aliases (which must exactly match the input already allocated). 213529f5e925SRichard Henderson */ 213629f5e925SRichard Henderson if (n == 1 || arg_ct->oalias) { 213729f5e925SRichard Henderson return INT_MAX; 2138c896fe29Sbellard } 213929f5e925SRichard Henderson 214029f5e925SRichard Henderson /* 214129f5e925SRichard Henderson * Sort register pairs next, first then second immediately after. 214229f5e925SRichard Henderson * Arbitrarily sort multiple pairs by the index of the first reg; 214329f5e925SRichard Henderson * there shouldn't be many pairs. 214429f5e925SRichard Henderson */ 214529f5e925SRichard Henderson switch (arg_ct->pair) { 214629f5e925SRichard Henderson case 1: 214729f5e925SRichard Henderson case 3: 214829f5e925SRichard Henderson return (k + 1) * 2; 214929f5e925SRichard Henderson case 2: 215029f5e925SRichard Henderson return (arg_ct->pair_index + 1) * 2 - 1; 215129f5e925SRichard Henderson } 215229f5e925SRichard Henderson 215329f5e925SRichard Henderson /* Finally, sort by decreasing register count. */ 215429f5e925SRichard Henderson assert(n > 1); 215529f5e925SRichard Henderson return -n; 2156c896fe29Sbellard } 2157c896fe29Sbellard 2158c896fe29Sbellard /* sort from highest priority to lowest */ 2159c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n) 2160c896fe29Sbellard { 216166792f90SRichard Henderson int i, j; 216266792f90SRichard Henderson TCGArgConstraint *a = def->args_ct; 2163c896fe29Sbellard 216466792f90SRichard Henderson for (i = 0; i < n; i++) { 216566792f90SRichard Henderson a[start + i].sort_index = start + i; 216666792f90SRichard Henderson } 216766792f90SRichard Henderson if (n <= 1) { 2168c896fe29Sbellard return; 216966792f90SRichard Henderson } 2170c896fe29Sbellard for (i = 0; i < n - 1; i++) { 2171c896fe29Sbellard for (j = i + 1; j < n; j++) { 217266792f90SRichard Henderson int p1 = get_constraint_priority(def, a[start + i].sort_index); 217366792f90SRichard Henderson int p2 = get_constraint_priority(def, a[start + j].sort_index); 2174c896fe29Sbellard if (p1 < p2) { 217566792f90SRichard Henderson int tmp = a[start + i].sort_index; 217666792f90SRichard Henderson a[start + i].sort_index = a[start + j].sort_index; 217766792f90SRichard Henderson a[start + j].sort_index = tmp; 2178c896fe29Sbellard } 2179c896fe29Sbellard } 2180c896fe29Sbellard } 2181c896fe29Sbellard } 2182c896fe29Sbellard 2183f69d277eSRichard Henderson static void process_op_defs(TCGContext *s) 2184c896fe29Sbellard { 2185a9751609SRichard Henderson TCGOpcode op; 2186c896fe29Sbellard 2187f69d277eSRichard Henderson for (op = 0; op < NB_OPS; op++) { 2188f69d277eSRichard Henderson TCGOpDef *def = &tcg_op_defs[op]; 2189f69d277eSRichard Henderson const TCGTargetOpDef *tdefs; 219029f5e925SRichard Henderson bool saw_alias_pair = false; 219129f5e925SRichard Henderson int i, o, i2, o2, nb_args; 2192f69d277eSRichard Henderson 2193f69d277eSRichard Henderson if (def->flags & TCG_OPF_NOT_PRESENT) { 2194f69d277eSRichard Henderson continue; 2195f69d277eSRichard Henderson } 2196f69d277eSRichard Henderson 2197c896fe29Sbellard nb_args = def->nb_iargs + def->nb_oargs; 2198f69d277eSRichard Henderson if (nb_args == 0) { 2199f69d277eSRichard Henderson continue; 2200f69d277eSRichard Henderson } 2201f69d277eSRichard Henderson 22024c22e840SRichard Henderson /* 22034c22e840SRichard Henderson * Macro magic should make it impossible, but double-check that 22044c22e840SRichard Henderson * the array index is in range. Since the signness of an enum 22054c22e840SRichard Henderson * is implementation defined, force the result to unsigned. 22064c22e840SRichard Henderson */ 22074c22e840SRichard Henderson unsigned con_set = tcg_target_op_def(op); 22084c22e840SRichard Henderson tcg_debug_assert(con_set < ARRAY_SIZE(constraint_sets)); 22094c22e840SRichard Henderson tdefs = &constraint_sets[con_set]; 2210f69d277eSRichard Henderson 2211c896fe29Sbellard for (i = 0; i < nb_args; i++) { 2212f69d277eSRichard Henderson const char *ct_str = tdefs->args_ct_str[i]; 22138940ea0dSPhilippe Mathieu-Daudé bool input_p = i >= def->nb_oargs; 22148940ea0dSPhilippe Mathieu-Daudé 2215f69d277eSRichard Henderson /* Incomplete TCGTargetOpDef entry. */ 2216eabb7b91SAurelien Jarno tcg_debug_assert(ct_str != NULL); 2217f69d277eSRichard Henderson 221817280ff4SRichard Henderson switch (*ct_str) { 221917280ff4SRichard Henderson case '0' ... '9': 22208940ea0dSPhilippe Mathieu-Daudé o = *ct_str - '0'; 22218940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(input_p); 22228940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(o < def->nb_oargs); 22238940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(def->args_ct[o].regs != 0); 22248940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(!def->args_ct[o].oalias); 22258940ea0dSPhilippe Mathieu-Daudé def->args_ct[i] = def->args_ct[o]; 2226bc2b17e6SRichard Henderson /* The output sets oalias. */ 22278940ea0dSPhilippe Mathieu-Daudé def->args_ct[o].oalias = 1; 22288940ea0dSPhilippe Mathieu-Daudé def->args_ct[o].alias_index = i; 2229bc2b17e6SRichard Henderson /* The input sets ialias. */ 22308940ea0dSPhilippe Mathieu-Daudé def->args_ct[i].ialias = 1; 22318940ea0dSPhilippe Mathieu-Daudé def->args_ct[i].alias_index = o; 223229f5e925SRichard Henderson if (def->args_ct[i].pair) { 223329f5e925SRichard Henderson saw_alias_pair = true; 223429f5e925SRichard Henderson } 22358940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(ct_str[1] == '\0'); 22368940ea0dSPhilippe Mathieu-Daudé continue; 22378940ea0dSPhilippe Mathieu-Daudé 223882790a87SRichard Henderson case '&': 22398940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(!input_p); 2240bc2b17e6SRichard Henderson def->args_ct[i].newreg = true; 224182790a87SRichard Henderson ct_str++; 224282790a87SRichard Henderson break; 224329f5e925SRichard Henderson 224429f5e925SRichard Henderson case 'p': /* plus */ 224529f5e925SRichard Henderson /* Allocate to the register after the previous. */ 224629f5e925SRichard Henderson tcg_debug_assert(i > (input_p ? def->nb_oargs : 0)); 224729f5e925SRichard Henderson o = i - 1; 224829f5e925SRichard Henderson tcg_debug_assert(!def->args_ct[o].pair); 224929f5e925SRichard Henderson tcg_debug_assert(!def->args_ct[o].ct); 225029f5e925SRichard Henderson def->args_ct[i] = (TCGArgConstraint){ 225129f5e925SRichard Henderson .pair = 2, 225229f5e925SRichard Henderson .pair_index = o, 225329f5e925SRichard Henderson .regs = def->args_ct[o].regs << 1, 225429f5e925SRichard Henderson }; 225529f5e925SRichard Henderson def->args_ct[o].pair = 1; 225629f5e925SRichard Henderson def->args_ct[o].pair_index = i; 225729f5e925SRichard Henderson tcg_debug_assert(ct_str[1] == '\0'); 225829f5e925SRichard Henderson continue; 225929f5e925SRichard Henderson 226029f5e925SRichard Henderson case 'm': /* minus */ 226129f5e925SRichard Henderson /* Allocate to the register before the previous. */ 226229f5e925SRichard Henderson tcg_debug_assert(i > (input_p ? def->nb_oargs : 0)); 226329f5e925SRichard Henderson o = i - 1; 226429f5e925SRichard Henderson tcg_debug_assert(!def->args_ct[o].pair); 226529f5e925SRichard Henderson tcg_debug_assert(!def->args_ct[o].ct); 226629f5e925SRichard Henderson def->args_ct[i] = (TCGArgConstraint){ 226729f5e925SRichard Henderson .pair = 1, 226829f5e925SRichard Henderson .pair_index = o, 226929f5e925SRichard Henderson .regs = def->args_ct[o].regs >> 1, 227029f5e925SRichard Henderson }; 227129f5e925SRichard Henderson def->args_ct[o].pair = 2; 227229f5e925SRichard Henderson def->args_ct[o].pair_index = i; 227329f5e925SRichard Henderson tcg_debug_assert(ct_str[1] == '\0'); 227429f5e925SRichard Henderson continue; 22758940ea0dSPhilippe Mathieu-Daudé } 22768940ea0dSPhilippe Mathieu-Daudé 22778940ea0dSPhilippe Mathieu-Daudé do { 22788940ea0dSPhilippe Mathieu-Daudé switch (*ct_str) { 2279c896fe29Sbellard case 'i': 2280c896fe29Sbellard def->args_ct[i].ct |= TCG_CT_CONST; 2281c896fe29Sbellard break; 2282358b4923SRichard Henderson 2283358b4923SRichard Henderson /* Include all of the target-specific constraints. */ 2284358b4923SRichard Henderson 2285358b4923SRichard Henderson #undef CONST 2286358b4923SRichard Henderson #define CONST(CASE, MASK) \ 22878940ea0dSPhilippe Mathieu-Daudé case CASE: def->args_ct[i].ct |= MASK; break; 2288358b4923SRichard Henderson #define REGS(CASE, MASK) \ 22898940ea0dSPhilippe Mathieu-Daudé case CASE: def->args_ct[i].regs |= MASK; break; 2290358b4923SRichard Henderson 2291358b4923SRichard Henderson #include "tcg-target-con-str.h" 2292358b4923SRichard Henderson 2293358b4923SRichard Henderson #undef REGS 2294358b4923SRichard Henderson #undef CONST 2295c896fe29Sbellard default: 22968940ea0dSPhilippe Mathieu-Daudé case '0' ... '9': 22978940ea0dSPhilippe Mathieu-Daudé case '&': 229829f5e925SRichard Henderson case 'p': 229929f5e925SRichard Henderson case 'm': 2300358b4923SRichard Henderson /* Typo in TCGTargetOpDef constraint. */ 2301358b4923SRichard Henderson g_assert_not_reached(); 2302358b4923SRichard Henderson } 23038940ea0dSPhilippe Mathieu-Daudé } while (*++ct_str != '\0'); 2304c896fe29Sbellard } 2305c896fe29Sbellard 2306c68aaa18SStefan Weil /* TCGTargetOpDef entry with too much information? */ 2307eabb7b91SAurelien Jarno tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL); 2308c68aaa18SStefan Weil 230929f5e925SRichard Henderson /* 231029f5e925SRichard Henderson * Fix up output pairs that are aliased with inputs. 231129f5e925SRichard Henderson * When we created the alias, we copied pair from the output. 231229f5e925SRichard Henderson * There are three cases: 231329f5e925SRichard Henderson * (1a) Pairs of inputs alias pairs of outputs. 231429f5e925SRichard Henderson * (1b) One input aliases the first of a pair of outputs. 231529f5e925SRichard Henderson * (2) One input aliases the second of a pair of outputs. 231629f5e925SRichard Henderson * 231729f5e925SRichard Henderson * Case 1a is handled by making sure that the pair_index'es are 231829f5e925SRichard Henderson * properly updated so that they appear the same as a pair of inputs. 231929f5e925SRichard Henderson * 232029f5e925SRichard Henderson * Case 1b is handled by setting the pair_index of the input to 232129f5e925SRichard Henderson * itself, simply so it doesn't point to an unrelated argument. 232229f5e925SRichard Henderson * Since we don't encounter the "second" during the input allocation 232329f5e925SRichard Henderson * phase, nothing happens with the second half of the input pair. 232429f5e925SRichard Henderson * 232529f5e925SRichard Henderson * Case 2 is handled by setting the second input to pair=3, the 232629f5e925SRichard Henderson * first output to pair=3, and the pair_index'es to match. 232729f5e925SRichard Henderson */ 232829f5e925SRichard Henderson if (saw_alias_pair) { 232929f5e925SRichard Henderson for (i = def->nb_oargs; i < nb_args; i++) { 233029f5e925SRichard Henderson /* 233129f5e925SRichard Henderson * Since [0-9pm] must be alone in the constraint string, 233229f5e925SRichard Henderson * the only way they can both be set is if the pair comes 233329f5e925SRichard Henderson * from the output alias. 233429f5e925SRichard Henderson */ 233529f5e925SRichard Henderson if (!def->args_ct[i].ialias) { 233629f5e925SRichard Henderson continue; 233729f5e925SRichard Henderson } 233829f5e925SRichard Henderson switch (def->args_ct[i].pair) { 233929f5e925SRichard Henderson case 0: 234029f5e925SRichard Henderson break; 234129f5e925SRichard Henderson case 1: 234229f5e925SRichard Henderson o = def->args_ct[i].alias_index; 234329f5e925SRichard Henderson o2 = def->args_ct[o].pair_index; 234429f5e925SRichard Henderson tcg_debug_assert(def->args_ct[o].pair == 1); 234529f5e925SRichard Henderson tcg_debug_assert(def->args_ct[o2].pair == 2); 234629f5e925SRichard Henderson if (def->args_ct[o2].oalias) { 234729f5e925SRichard Henderson /* Case 1a */ 234829f5e925SRichard Henderson i2 = def->args_ct[o2].alias_index; 234929f5e925SRichard Henderson tcg_debug_assert(def->args_ct[i2].pair == 2); 235029f5e925SRichard Henderson def->args_ct[i2].pair_index = i; 235129f5e925SRichard Henderson def->args_ct[i].pair_index = i2; 235229f5e925SRichard Henderson } else { 235329f5e925SRichard Henderson /* Case 1b */ 235429f5e925SRichard Henderson def->args_ct[i].pair_index = i; 235529f5e925SRichard Henderson } 235629f5e925SRichard Henderson break; 235729f5e925SRichard Henderson case 2: 235829f5e925SRichard Henderson o = def->args_ct[i].alias_index; 235929f5e925SRichard Henderson o2 = def->args_ct[o].pair_index; 236029f5e925SRichard Henderson tcg_debug_assert(def->args_ct[o].pair == 2); 236129f5e925SRichard Henderson tcg_debug_assert(def->args_ct[o2].pair == 1); 236229f5e925SRichard Henderson if (def->args_ct[o2].oalias) { 236329f5e925SRichard Henderson /* Case 1a */ 236429f5e925SRichard Henderson i2 = def->args_ct[o2].alias_index; 236529f5e925SRichard Henderson tcg_debug_assert(def->args_ct[i2].pair == 1); 236629f5e925SRichard Henderson def->args_ct[i2].pair_index = i; 236729f5e925SRichard Henderson def->args_ct[i].pair_index = i2; 236829f5e925SRichard Henderson } else { 236929f5e925SRichard Henderson /* Case 2 */ 237029f5e925SRichard Henderson def->args_ct[i].pair = 3; 237129f5e925SRichard Henderson def->args_ct[o2].pair = 3; 237229f5e925SRichard Henderson def->args_ct[i].pair_index = o2; 237329f5e925SRichard Henderson def->args_ct[o2].pair_index = i; 237429f5e925SRichard Henderson } 237529f5e925SRichard Henderson break; 237629f5e925SRichard Henderson default: 237729f5e925SRichard Henderson g_assert_not_reached(); 237829f5e925SRichard Henderson } 237929f5e925SRichard Henderson } 238029f5e925SRichard Henderson } 238129f5e925SRichard Henderson 2382c896fe29Sbellard /* sort the constraints (XXX: this is just an heuristic) */ 2383c896fe29Sbellard sort_constraints(def, 0, def->nb_oargs); 2384c896fe29Sbellard sort_constraints(def, def->nb_oargs, def->nb_iargs); 2385c896fe29Sbellard } 2386c896fe29Sbellard } 2387c896fe29Sbellard 23880c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op) 23890c627cdcSRichard Henderson { 2390d88a117eSRichard Henderson TCGLabel *label; 2391d88a117eSRichard Henderson 2392d88a117eSRichard Henderson switch (op->opc) { 2393d88a117eSRichard Henderson case INDEX_op_br: 2394d88a117eSRichard Henderson label = arg_label(op->args[0]); 2395d88a117eSRichard Henderson label->refs--; 2396d88a117eSRichard Henderson break; 2397d88a117eSRichard Henderson case INDEX_op_brcond_i32: 2398d88a117eSRichard Henderson case INDEX_op_brcond_i64: 2399d88a117eSRichard Henderson label = arg_label(op->args[3]); 2400d88a117eSRichard Henderson label->refs--; 2401d88a117eSRichard Henderson break; 2402d88a117eSRichard Henderson case INDEX_op_brcond2_i32: 2403d88a117eSRichard Henderson label = arg_label(op->args[5]); 2404d88a117eSRichard Henderson label->refs--; 2405d88a117eSRichard Henderson break; 2406d88a117eSRichard Henderson default: 2407d88a117eSRichard Henderson break; 2408d88a117eSRichard Henderson } 2409d88a117eSRichard Henderson 241015fa08f8SRichard Henderson QTAILQ_REMOVE(&s->ops, op, link); 241115fa08f8SRichard Henderson QTAILQ_INSERT_TAIL(&s->free_ops, op, link); 2412abebf925SRichard Henderson s->nb_ops--; 24130c627cdcSRichard Henderson 24140c627cdcSRichard Henderson #ifdef CONFIG_PROFILER 2415d73415a3SStefan Hajnoczi qatomic_set(&s->prof.del_op_count, s->prof.del_op_count + 1); 24160c627cdcSRichard Henderson #endif 24170c627cdcSRichard Henderson } 24180c627cdcSRichard Henderson 2419a80cdd31SRichard Henderson void tcg_remove_ops_after(TCGOp *op) 2420a80cdd31SRichard Henderson { 2421a80cdd31SRichard Henderson TCGContext *s = tcg_ctx; 2422a80cdd31SRichard Henderson 2423a80cdd31SRichard Henderson while (true) { 2424a80cdd31SRichard Henderson TCGOp *last = tcg_last_op(); 2425a80cdd31SRichard Henderson if (last == op) { 2426a80cdd31SRichard Henderson return; 2427a80cdd31SRichard Henderson } 2428a80cdd31SRichard Henderson tcg_op_remove(s, last); 2429a80cdd31SRichard Henderson } 2430a80cdd31SRichard Henderson } 2431a80cdd31SRichard Henderson 2432d4478943SPhilippe Mathieu-Daudé static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs) 243315fa08f8SRichard Henderson { 243415fa08f8SRichard Henderson TCGContext *s = tcg_ctx; 2435cb10bc63SRichard Henderson TCGOp *op = NULL; 243615fa08f8SRichard Henderson 2437cb10bc63SRichard Henderson if (unlikely(!QTAILQ_EMPTY(&s->free_ops))) { 2438cb10bc63SRichard Henderson QTAILQ_FOREACH(op, &s->free_ops, link) { 2439cb10bc63SRichard Henderson if (nargs <= op->nargs) { 244015fa08f8SRichard Henderson QTAILQ_REMOVE(&s->free_ops, op, link); 2441cb10bc63SRichard Henderson nargs = op->nargs; 2442cb10bc63SRichard Henderson goto found; 244315fa08f8SRichard Henderson } 2444cb10bc63SRichard Henderson } 2445cb10bc63SRichard Henderson } 2446cb10bc63SRichard Henderson 2447cb10bc63SRichard Henderson /* Most opcodes have 3 or 4 operands: reduce fragmentation. */ 2448cb10bc63SRichard Henderson nargs = MAX(4, nargs); 2449cb10bc63SRichard Henderson op = tcg_malloc(sizeof(TCGOp) + sizeof(TCGArg) * nargs); 2450cb10bc63SRichard Henderson 2451cb10bc63SRichard Henderson found: 245215fa08f8SRichard Henderson memset(op, 0, offsetof(TCGOp, link)); 245315fa08f8SRichard Henderson op->opc = opc; 2454cb10bc63SRichard Henderson op->nargs = nargs; 245515fa08f8SRichard Henderson 2456cb10bc63SRichard Henderson /* Check for bitfield overflow. */ 2457cb10bc63SRichard Henderson tcg_debug_assert(op->nargs == nargs); 2458cb10bc63SRichard Henderson 2459cb10bc63SRichard Henderson s->nb_ops++; 246015fa08f8SRichard Henderson return op; 246115fa08f8SRichard Henderson } 246215fa08f8SRichard Henderson 2463d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_emit_op(TCGOpcode opc, unsigned nargs) 246415fa08f8SRichard Henderson { 2465d4478943SPhilippe Mathieu-Daudé TCGOp *op = tcg_op_alloc(opc, nargs); 246615fa08f8SRichard Henderson QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link); 246715fa08f8SRichard Henderson return op; 246815fa08f8SRichard Henderson } 246915fa08f8SRichard Henderson 2470d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op, 2471d4478943SPhilippe Mathieu-Daudé TCGOpcode opc, unsigned nargs) 24725a18407fSRichard Henderson { 2473d4478943SPhilippe Mathieu-Daudé TCGOp *new_op = tcg_op_alloc(opc, nargs); 247415fa08f8SRichard Henderson QTAILQ_INSERT_BEFORE(old_op, new_op, link); 24755a18407fSRichard Henderson return new_op; 24765a18407fSRichard Henderson } 24775a18407fSRichard Henderson 2478d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, 2479d4478943SPhilippe Mathieu-Daudé TCGOpcode opc, unsigned nargs) 24805a18407fSRichard Henderson { 2481d4478943SPhilippe Mathieu-Daudé TCGOp *new_op = tcg_op_alloc(opc, nargs); 248215fa08f8SRichard Henderson QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link); 24835a18407fSRichard Henderson return new_op; 24845a18407fSRichard Henderson } 24855a18407fSRichard Henderson 2486b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code. */ 2487b4fc67c7SRichard Henderson static void reachable_code_pass(TCGContext *s) 2488b4fc67c7SRichard Henderson { 2489b4fc67c7SRichard Henderson TCGOp *op, *op_next; 2490b4fc67c7SRichard Henderson bool dead = false; 2491b4fc67c7SRichard Henderson 2492b4fc67c7SRichard Henderson QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) { 2493b4fc67c7SRichard Henderson bool remove = dead; 2494b4fc67c7SRichard Henderson TCGLabel *label; 2495b4fc67c7SRichard Henderson 2496b4fc67c7SRichard Henderson switch (op->opc) { 2497b4fc67c7SRichard Henderson case INDEX_op_set_label: 2498b4fc67c7SRichard Henderson label = arg_label(op->args[0]); 2499b4fc67c7SRichard Henderson if (label->refs == 0) { 2500b4fc67c7SRichard Henderson /* 2501b4fc67c7SRichard Henderson * While there is an occasional backward branch, virtually 2502b4fc67c7SRichard Henderson * all branches generated by the translators are forward. 2503b4fc67c7SRichard Henderson * Which means that generally we will have already removed 2504b4fc67c7SRichard Henderson * all references to the label that will be, and there is 2505b4fc67c7SRichard Henderson * little to be gained by iterating. 2506b4fc67c7SRichard Henderson */ 2507b4fc67c7SRichard Henderson remove = true; 2508b4fc67c7SRichard Henderson } else { 2509b4fc67c7SRichard Henderson /* Once we see a label, insns become live again. */ 2510b4fc67c7SRichard Henderson dead = false; 2511b4fc67c7SRichard Henderson remove = false; 2512b4fc67c7SRichard Henderson 2513b4fc67c7SRichard Henderson /* 2514b4fc67c7SRichard Henderson * Optimization can fold conditional branches to unconditional. 2515b4fc67c7SRichard Henderson * If we find a label with one reference which is preceded by 2516b4fc67c7SRichard Henderson * an unconditional branch to it, remove both. This needed to 2517b4fc67c7SRichard Henderson * wait until the dead code in between them was removed. 2518b4fc67c7SRichard Henderson */ 2519b4fc67c7SRichard Henderson if (label->refs == 1) { 2520eae3eb3eSPaolo Bonzini TCGOp *op_prev = QTAILQ_PREV(op, link); 2521b4fc67c7SRichard Henderson if (op_prev->opc == INDEX_op_br && 2522b4fc67c7SRichard Henderson label == arg_label(op_prev->args[0])) { 2523b4fc67c7SRichard Henderson tcg_op_remove(s, op_prev); 2524b4fc67c7SRichard Henderson remove = true; 2525b4fc67c7SRichard Henderson } 2526b4fc67c7SRichard Henderson } 2527b4fc67c7SRichard Henderson } 2528b4fc67c7SRichard Henderson break; 2529b4fc67c7SRichard Henderson 2530b4fc67c7SRichard Henderson case INDEX_op_br: 2531b4fc67c7SRichard Henderson case INDEX_op_exit_tb: 2532b4fc67c7SRichard Henderson case INDEX_op_goto_ptr: 2533b4fc67c7SRichard Henderson /* Unconditional branches; everything following is dead. */ 2534b4fc67c7SRichard Henderson dead = true; 2535b4fc67c7SRichard Henderson break; 2536b4fc67c7SRichard Henderson 2537b4fc67c7SRichard Henderson case INDEX_op_call: 2538b4fc67c7SRichard Henderson /* Notice noreturn helper calls, raising exceptions. */ 253990163900SRichard Henderson if (tcg_call_flags(op) & TCG_CALL_NO_RETURN) { 2540b4fc67c7SRichard Henderson dead = true; 2541b4fc67c7SRichard Henderson } 2542b4fc67c7SRichard Henderson break; 2543b4fc67c7SRichard Henderson 2544b4fc67c7SRichard Henderson case INDEX_op_insn_start: 2545b4fc67c7SRichard Henderson /* Never remove -- we need to keep these for unwind. */ 2546b4fc67c7SRichard Henderson remove = false; 2547b4fc67c7SRichard Henderson break; 2548b4fc67c7SRichard Henderson 2549b4fc67c7SRichard Henderson default: 2550b4fc67c7SRichard Henderson break; 2551b4fc67c7SRichard Henderson } 2552b4fc67c7SRichard Henderson 2553b4fc67c7SRichard Henderson if (remove) { 2554b4fc67c7SRichard Henderson tcg_op_remove(s, op); 2555b4fc67c7SRichard Henderson } 2556b4fc67c7SRichard Henderson } 2557b4fc67c7SRichard Henderson } 2558b4fc67c7SRichard Henderson 2559c70fbf0aSRichard Henderson #define TS_DEAD 1 2560c70fbf0aSRichard Henderson #define TS_MEM 2 2561c70fbf0aSRichard Henderson 25625a18407fSRichard Henderson #define IS_DEAD_ARG(n) (arg_life & (DEAD_ARG << (n))) 25635a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n))) 25645a18407fSRichard Henderson 256525f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp. */ 256625f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts) 256725f49c5fSRichard Henderson { 256825f49c5fSRichard Henderson return ts->state_ptr; 256925f49c5fSRichard Henderson } 257025f49c5fSRichard Henderson 257125f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the 257225f49c5fSRichard Henderson * maximal regset for its type. 257325f49c5fSRichard Henderson */ 257425f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts) 257525f49c5fSRichard Henderson { 257625f49c5fSRichard Henderson *la_temp_pref(ts) 257725f49c5fSRichard Henderson = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]); 257825f49c5fSRichard Henderson } 257925f49c5fSRichard Henderson 25809c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals 25819c43b68dSAurelien Jarno should be in memory. */ 25822616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt) 2583c896fe29Sbellard { 2584b83eabeaSRichard Henderson int i; 2585b83eabeaSRichard Henderson 2586b83eabeaSRichard Henderson for (i = 0; i < ng; ++i) { 2587b83eabeaSRichard Henderson s->temps[i].state = TS_DEAD | TS_MEM; 258825f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 2589b83eabeaSRichard Henderson } 2590b83eabeaSRichard Henderson for (i = ng; i < nt; ++i) { 2591b83eabeaSRichard Henderson s->temps[i].state = TS_DEAD; 259225f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 2593b83eabeaSRichard Henderson } 2594c896fe29Sbellard } 2595c896fe29Sbellard 25969c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals 25979c43b68dSAurelien Jarno and local temps should be in memory. */ 25982616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt) 2599641d5fbeSbellard { 2600b83eabeaSRichard Henderson int i; 2601641d5fbeSbellard 2602ee17db83SRichard Henderson for (i = 0; i < nt; ++i) { 2603ee17db83SRichard Henderson TCGTemp *ts = &s->temps[i]; 2604ee17db83SRichard Henderson int state; 2605ee17db83SRichard Henderson 2606ee17db83SRichard Henderson switch (ts->kind) { 2607ee17db83SRichard Henderson case TEMP_FIXED: 2608ee17db83SRichard Henderson case TEMP_GLOBAL: 2609ee17db83SRichard Henderson case TEMP_LOCAL: 2610ee17db83SRichard Henderson state = TS_DEAD | TS_MEM; 2611ee17db83SRichard Henderson break; 2612ee17db83SRichard Henderson case TEMP_NORMAL: 2613c7482438SRichard Henderson case TEMP_EBB: 2614c0522136SRichard Henderson case TEMP_CONST: 2615ee17db83SRichard Henderson state = TS_DEAD; 2616ee17db83SRichard Henderson break; 2617ee17db83SRichard Henderson default: 2618ee17db83SRichard Henderson g_assert_not_reached(); 2619c70fbf0aSRichard Henderson } 2620ee17db83SRichard Henderson ts->state = state; 2621ee17db83SRichard Henderson la_reset_pref(ts); 2622641d5fbeSbellard } 2623641d5fbeSbellard } 2624641d5fbeSbellard 2625f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory. */ 2626f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng) 2627f65a061cSRichard Henderson { 2628f65a061cSRichard Henderson int i; 2629f65a061cSRichard Henderson 2630f65a061cSRichard Henderson for (i = 0; i < ng; ++i) { 263125f49c5fSRichard Henderson int state = s->temps[i].state; 263225f49c5fSRichard Henderson s->temps[i].state = state | TS_MEM; 263325f49c5fSRichard Henderson if (state == TS_DEAD) { 263425f49c5fSRichard Henderson /* If the global was previously dead, reset prefs. */ 263525f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 263625f49c5fSRichard Henderson } 2637f65a061cSRichard Henderson } 2638f65a061cSRichard Henderson } 2639f65a061cSRichard Henderson 2640b4cb76e6SRichard Henderson /* 2641c7482438SRichard Henderson * liveness analysis: conditional branch: all temps are dead unless 2642c7482438SRichard Henderson * explicitly live-across-conditional-branch, globals and local temps 2643c7482438SRichard Henderson * should be synced. 2644b4cb76e6SRichard Henderson */ 2645b4cb76e6SRichard Henderson static void la_bb_sync(TCGContext *s, int ng, int nt) 2646b4cb76e6SRichard Henderson { 2647b4cb76e6SRichard Henderson la_global_sync(s, ng); 2648b4cb76e6SRichard Henderson 2649b4cb76e6SRichard Henderson for (int i = ng; i < nt; ++i) { 2650c0522136SRichard Henderson TCGTemp *ts = &s->temps[i]; 2651c0522136SRichard Henderson int state; 2652c0522136SRichard Henderson 2653c0522136SRichard Henderson switch (ts->kind) { 2654c0522136SRichard Henderson case TEMP_LOCAL: 2655c0522136SRichard Henderson state = ts->state; 2656c0522136SRichard Henderson ts->state = state | TS_MEM; 2657b4cb76e6SRichard Henderson if (state != TS_DEAD) { 2658b4cb76e6SRichard Henderson continue; 2659b4cb76e6SRichard Henderson } 2660c0522136SRichard Henderson break; 2661c0522136SRichard Henderson case TEMP_NORMAL: 2662b4cb76e6SRichard Henderson s->temps[i].state = TS_DEAD; 2663c0522136SRichard Henderson break; 2664c7482438SRichard Henderson case TEMP_EBB: 2665c0522136SRichard Henderson case TEMP_CONST: 2666c0522136SRichard Henderson continue; 2667c0522136SRichard Henderson default: 2668c0522136SRichard Henderson g_assert_not_reached(); 2669b4cb76e6SRichard Henderson } 2670b4cb76e6SRichard Henderson la_reset_pref(&s->temps[i]); 2671b4cb76e6SRichard Henderson } 2672b4cb76e6SRichard Henderson } 2673b4cb76e6SRichard Henderson 2674f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill. */ 2675f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng) 2676f65a061cSRichard Henderson { 2677f65a061cSRichard Henderson int i; 2678f65a061cSRichard Henderson 2679f65a061cSRichard Henderson for (i = 0; i < ng; i++) { 2680f65a061cSRichard Henderson s->temps[i].state = TS_DEAD | TS_MEM; 268125f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 268225f49c5fSRichard Henderson } 268325f49c5fSRichard Henderson } 268425f49c5fSRichard Henderson 268525f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls. */ 268625f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt) 268725f49c5fSRichard Henderson { 268825f49c5fSRichard Henderson TCGRegSet mask = ~tcg_target_call_clobber_regs; 268925f49c5fSRichard Henderson int i; 269025f49c5fSRichard Henderson 269125f49c5fSRichard Henderson for (i = 0; i < nt; i++) { 269225f49c5fSRichard Henderson TCGTemp *ts = &s->temps[i]; 269325f49c5fSRichard Henderson if (!(ts->state & TS_DEAD)) { 269425f49c5fSRichard Henderson TCGRegSet *pset = la_temp_pref(ts); 269525f49c5fSRichard Henderson TCGRegSet set = *pset; 269625f49c5fSRichard Henderson 269725f49c5fSRichard Henderson set &= mask; 269825f49c5fSRichard Henderson /* If the combination is not possible, restart. */ 269925f49c5fSRichard Henderson if (set == 0) { 270025f49c5fSRichard Henderson set = tcg_target_available_regs[ts->type] & mask; 270125f49c5fSRichard Henderson } 270225f49c5fSRichard Henderson *pset = set; 270325f49c5fSRichard Henderson } 2704f65a061cSRichard Henderson } 2705f65a061cSRichard Henderson } 2706f65a061cSRichard Henderson 2707a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a 2708c896fe29Sbellard given input arguments is dead. Instructions updating dead 2709c896fe29Sbellard temporaries are removed. */ 2710b83eabeaSRichard Henderson static void liveness_pass_1(TCGContext *s) 2711c896fe29Sbellard { 2712c70fbf0aSRichard Henderson int nb_globals = s->nb_globals; 27132616c808SRichard Henderson int nb_temps = s->nb_temps; 271415fa08f8SRichard Henderson TCGOp *op, *op_prev; 271525f49c5fSRichard Henderson TCGRegSet *prefs; 271625f49c5fSRichard Henderson int i; 271725f49c5fSRichard Henderson 271825f49c5fSRichard Henderson prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps); 271925f49c5fSRichard Henderson for (i = 0; i < nb_temps; ++i) { 272025f49c5fSRichard Henderson s->temps[i].state_ptr = prefs + i; 272125f49c5fSRichard Henderson } 2722c896fe29Sbellard 2723ae36a246SRichard Henderson /* ??? Should be redundant with the exit_tb that ends the TB. */ 27242616c808SRichard Henderson la_func_end(s, nb_globals, nb_temps); 2725c896fe29Sbellard 2726eae3eb3eSPaolo Bonzini QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) { 272725f49c5fSRichard Henderson int nb_iargs, nb_oargs; 2728c45cb8bbSRichard Henderson TCGOpcode opc_new, opc_new2; 2729c45cb8bbSRichard Henderson bool have_opc_new2; 2730a1b3c48dSRichard Henderson TCGLifeData arg_life = 0; 273125f49c5fSRichard Henderson TCGTemp *ts; 2732c45cb8bbSRichard Henderson TCGOpcode opc = op->opc; 2733c45cb8bbSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 2734c45cb8bbSRichard Henderson 2735c45cb8bbSRichard Henderson switch (opc) { 2736c896fe29Sbellard case INDEX_op_call: 2737c6e113f5Sbellard { 273839004a71SRichard Henderson const TCGHelperInfo *info = tcg_call_info(op); 273939004a71SRichard Henderson int call_flags = tcg_call_flags(op); 2740c6e113f5Sbellard 2741cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 2742cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 2743c6e113f5Sbellard 2744c45cb8bbSRichard Henderson /* pure functions can be removed if their result is unused */ 274578505279SAurelien Jarno if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) { 2746c6e113f5Sbellard for (i = 0; i < nb_oargs; i++) { 274725f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 274825f49c5fSRichard Henderson if (ts->state != TS_DEAD) { 2749c6e113f5Sbellard goto do_not_remove_call; 2750c6e113f5Sbellard } 27519c43b68dSAurelien Jarno } 2752c45cb8bbSRichard Henderson goto do_remove; 2753152c35aaSRichard Henderson } 2754c6e113f5Sbellard do_not_remove_call: 2755c896fe29Sbellard 275625f49c5fSRichard Henderson /* Output args are dead. */ 2757c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 275825f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 275925f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 2760a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 27616b64b624SAurelien Jarno } 276225f49c5fSRichard Henderson if (ts->state & TS_MEM) { 2763a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i; 27649c43b68dSAurelien Jarno } 276525f49c5fSRichard Henderson ts->state = TS_DEAD; 276625f49c5fSRichard Henderson la_reset_pref(ts); 2767c896fe29Sbellard } 2768c896fe29Sbellard 276931fd884bSRichard Henderson /* Not used -- it will be tcg_target_call_oarg_reg(). */ 277031fd884bSRichard Henderson memset(op->output_pref, 0, sizeof(op->output_pref)); 277131fd884bSRichard Henderson 277278505279SAurelien Jarno if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS | 277378505279SAurelien Jarno TCG_CALL_NO_READ_GLOBALS))) { 2774f65a061cSRichard Henderson la_global_kill(s, nb_globals); 2775c70fbf0aSRichard Henderson } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) { 2776f65a061cSRichard Henderson la_global_sync(s, nb_globals); 2777b9c18f56Saurel32 } 2778c896fe29Sbellard 277925f49c5fSRichard Henderson /* Record arguments that die in this helper. */ 2780866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 278125f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 278239004a71SRichard Henderson if (ts->state & TS_DEAD) { 2783a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 2784c896fe29Sbellard } 2785c896fe29Sbellard } 278625f49c5fSRichard Henderson 278725f49c5fSRichard Henderson /* For all live registers, remove call-clobbered prefs. */ 278825f49c5fSRichard Henderson la_cross_call(s, nb_temps); 278925f49c5fSRichard Henderson 279039004a71SRichard Henderson /* 279139004a71SRichard Henderson * Input arguments are live for preceding opcodes. 279239004a71SRichard Henderson * 279339004a71SRichard Henderson * For those arguments that die, and will be allocated in 279439004a71SRichard Henderson * registers, clear the register set for that arg, to be 279539004a71SRichard Henderson * filled in below. For args that will be on the stack, 279639004a71SRichard Henderson * reset to any available reg. Process arguments in reverse 279739004a71SRichard Henderson * order so that if a temp is used more than once, the stack 279839004a71SRichard Henderson * reset to max happens before the register reset to 0. 279925f49c5fSRichard Henderson */ 280039004a71SRichard Henderson for (i = nb_iargs - 1; i >= 0; i--) { 280139004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i]; 280239004a71SRichard Henderson ts = arg_temp(op->args[nb_oargs + i]); 280339004a71SRichard Henderson 280439004a71SRichard Henderson if (ts->state & TS_DEAD) { 280539004a71SRichard Henderson switch (loc->kind) { 280639004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 280739004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 280839004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 280939004a71SRichard Henderson if (REG_P(loc)) { 281039004a71SRichard Henderson *la_temp_pref(ts) = 0; 281139004a71SRichard Henderson break; 281239004a71SRichard Henderson } 281339004a71SRichard Henderson /* fall through */ 281439004a71SRichard Henderson default: 281539004a71SRichard Henderson *la_temp_pref(ts) = 281639004a71SRichard Henderson tcg_target_available_regs[ts->type]; 281739004a71SRichard Henderson break; 281839004a71SRichard Henderson } 281925f49c5fSRichard Henderson ts->state &= ~TS_DEAD; 282025f49c5fSRichard Henderson } 282125f49c5fSRichard Henderson } 282225f49c5fSRichard Henderson 282339004a71SRichard Henderson /* 282439004a71SRichard Henderson * For each input argument, add its input register to prefs. 282539004a71SRichard Henderson * If a temp is used once, this produces a single set bit; 282639004a71SRichard Henderson * if a temp is used multiple times, this produces a set. 282739004a71SRichard Henderson */ 282839004a71SRichard Henderson for (i = 0; i < nb_iargs; i++) { 282939004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i]; 283039004a71SRichard Henderson ts = arg_temp(op->args[nb_oargs + i]); 283139004a71SRichard Henderson 283239004a71SRichard Henderson switch (loc->kind) { 283339004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 283439004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 283539004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 283639004a71SRichard Henderson if (REG_P(loc)) { 283725f49c5fSRichard Henderson tcg_regset_set_reg(*la_temp_pref(ts), 283839004a71SRichard Henderson tcg_target_call_iarg_regs[loc->arg_slot]); 283939004a71SRichard Henderson } 284039004a71SRichard Henderson break; 284139004a71SRichard Henderson default: 284239004a71SRichard Henderson break; 2843c70fbf0aSRichard Henderson } 2844c19f47bfSAurelien Jarno } 2845c6e113f5Sbellard } 2846c896fe29Sbellard break; 2847765b842aSRichard Henderson case INDEX_op_insn_start: 2848c896fe29Sbellard break; 28495ff9d6a4Sbellard case INDEX_op_discard: 28505ff9d6a4Sbellard /* mark the temporary as dead */ 285125f49c5fSRichard Henderson ts = arg_temp(op->args[0]); 285225f49c5fSRichard Henderson ts->state = TS_DEAD; 285325f49c5fSRichard Henderson la_reset_pref(ts); 28545ff9d6a4Sbellard break; 28551305c451SRichard Henderson 28561305c451SRichard Henderson case INDEX_op_add2_i32: 2857c45cb8bbSRichard Henderson opc_new = INDEX_op_add_i32; 2858f1fae40cSRichard Henderson goto do_addsub2; 28591305c451SRichard Henderson case INDEX_op_sub2_i32: 2860c45cb8bbSRichard Henderson opc_new = INDEX_op_sub_i32; 2861f1fae40cSRichard Henderson goto do_addsub2; 2862f1fae40cSRichard Henderson case INDEX_op_add2_i64: 2863c45cb8bbSRichard Henderson opc_new = INDEX_op_add_i64; 2864f1fae40cSRichard Henderson goto do_addsub2; 2865f1fae40cSRichard Henderson case INDEX_op_sub2_i64: 2866c45cb8bbSRichard Henderson opc_new = INDEX_op_sub_i64; 2867f1fae40cSRichard Henderson do_addsub2: 28681305c451SRichard Henderson nb_iargs = 4; 28691305c451SRichard Henderson nb_oargs = 2; 28701305c451SRichard Henderson /* Test if the high part of the operation is dead, but not 28711305c451SRichard Henderson the low part. The result can be optimized to a simple 28721305c451SRichard Henderson add or sub. This happens often for x86_64 guest when the 28731305c451SRichard Henderson cpu mode is set to 32 bit. */ 2874b83eabeaSRichard Henderson if (arg_temp(op->args[1])->state == TS_DEAD) { 2875b83eabeaSRichard Henderson if (arg_temp(op->args[0])->state == TS_DEAD) { 28761305c451SRichard Henderson goto do_remove; 28771305c451SRichard Henderson } 2878c45cb8bbSRichard Henderson /* Replace the opcode and adjust the args in place, 2879c45cb8bbSRichard Henderson leaving 3 unused args at the end. */ 2880c45cb8bbSRichard Henderson op->opc = opc = opc_new; 2881efee3746SRichard Henderson op->args[1] = op->args[2]; 2882efee3746SRichard Henderson op->args[2] = op->args[4]; 28831305c451SRichard Henderson /* Fall through and mark the single-word operation live. */ 28841305c451SRichard Henderson nb_iargs = 2; 28851305c451SRichard Henderson nb_oargs = 1; 28861305c451SRichard Henderson } 28871305c451SRichard Henderson goto do_not_remove; 28881305c451SRichard Henderson 28891414968aSRichard Henderson case INDEX_op_mulu2_i32: 2890c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i32; 2891c45cb8bbSRichard Henderson opc_new2 = INDEX_op_muluh_i32; 2892c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_muluh_i32; 289303271524SRichard Henderson goto do_mul2; 2894f1fae40cSRichard Henderson case INDEX_op_muls2_i32: 2895c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i32; 2896c45cb8bbSRichard Henderson opc_new2 = INDEX_op_mulsh_i32; 2897c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_mulsh_i32; 2898f1fae40cSRichard Henderson goto do_mul2; 2899f1fae40cSRichard Henderson case INDEX_op_mulu2_i64: 2900c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i64; 2901c45cb8bbSRichard Henderson opc_new2 = INDEX_op_muluh_i64; 2902c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_muluh_i64; 290303271524SRichard Henderson goto do_mul2; 2904f1fae40cSRichard Henderson case INDEX_op_muls2_i64: 2905c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i64; 2906c45cb8bbSRichard Henderson opc_new2 = INDEX_op_mulsh_i64; 2907c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_mulsh_i64; 290803271524SRichard Henderson goto do_mul2; 2909f1fae40cSRichard Henderson do_mul2: 29101414968aSRichard Henderson nb_iargs = 2; 29111414968aSRichard Henderson nb_oargs = 2; 2912b83eabeaSRichard Henderson if (arg_temp(op->args[1])->state == TS_DEAD) { 2913b83eabeaSRichard Henderson if (arg_temp(op->args[0])->state == TS_DEAD) { 291403271524SRichard Henderson /* Both parts of the operation are dead. */ 29151414968aSRichard Henderson goto do_remove; 29161414968aSRichard Henderson } 291703271524SRichard Henderson /* The high part of the operation is dead; generate the low. */ 2918c45cb8bbSRichard Henderson op->opc = opc = opc_new; 2919efee3746SRichard Henderson op->args[1] = op->args[2]; 2920efee3746SRichard Henderson op->args[2] = op->args[3]; 2921b83eabeaSRichard Henderson } else if (arg_temp(op->args[0])->state == TS_DEAD && have_opc_new2) { 292203271524SRichard Henderson /* The low part of the operation is dead; generate the high. */ 2923c45cb8bbSRichard Henderson op->opc = opc = opc_new2; 2924efee3746SRichard Henderson op->args[0] = op->args[1]; 2925efee3746SRichard Henderson op->args[1] = op->args[2]; 2926efee3746SRichard Henderson op->args[2] = op->args[3]; 292703271524SRichard Henderson } else { 292803271524SRichard Henderson goto do_not_remove; 292903271524SRichard Henderson } 293003271524SRichard Henderson /* Mark the single-word operation live. */ 29311414968aSRichard Henderson nb_oargs = 1; 29321414968aSRichard Henderson goto do_not_remove; 29331414968aSRichard Henderson 2934c896fe29Sbellard default: 29351305c451SRichard Henderson /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */ 2936c896fe29Sbellard nb_iargs = def->nb_iargs; 2937c896fe29Sbellard nb_oargs = def->nb_oargs; 2938c896fe29Sbellard 2939c896fe29Sbellard /* Test if the operation can be removed because all 29405ff9d6a4Sbellard its outputs are dead. We assume that nb_oargs == 0 29415ff9d6a4Sbellard implies side effects */ 29425ff9d6a4Sbellard if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) { 2943c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 2944b83eabeaSRichard Henderson if (arg_temp(op->args[i])->state != TS_DEAD) { 2945c896fe29Sbellard goto do_not_remove; 2946c896fe29Sbellard } 29479c43b68dSAurelien Jarno } 2948152c35aaSRichard Henderson goto do_remove; 2949152c35aaSRichard Henderson } 2950152c35aaSRichard Henderson goto do_not_remove; 2951152c35aaSRichard Henderson 29521305c451SRichard Henderson do_remove: 29530c627cdcSRichard Henderson tcg_op_remove(s, op); 2954152c35aaSRichard Henderson break; 2955152c35aaSRichard Henderson 2956c896fe29Sbellard do_not_remove: 2957c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 295825f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 295925f49c5fSRichard Henderson 296025f49c5fSRichard Henderson /* Remember the preference of the uses that followed. */ 296131fd884bSRichard Henderson if (i < ARRAY_SIZE(op->output_pref)) { 296225f49c5fSRichard Henderson op->output_pref[i] = *la_temp_pref(ts); 296331fd884bSRichard Henderson } 296425f49c5fSRichard Henderson 296525f49c5fSRichard Henderson /* Output args are dead. */ 296625f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 2967a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 29686b64b624SAurelien Jarno } 296925f49c5fSRichard Henderson if (ts->state & TS_MEM) { 2970a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i; 29719c43b68dSAurelien Jarno } 297225f49c5fSRichard Henderson ts->state = TS_DEAD; 297325f49c5fSRichard Henderson la_reset_pref(ts); 2974c896fe29Sbellard } 2975c896fe29Sbellard 297625f49c5fSRichard Henderson /* If end of basic block, update. */ 2977ae36a246SRichard Henderson if (def->flags & TCG_OPF_BB_EXIT) { 2978ae36a246SRichard Henderson la_func_end(s, nb_globals, nb_temps); 2979b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_COND_BRANCH) { 2980b4cb76e6SRichard Henderson la_bb_sync(s, nb_globals, nb_temps); 2981ae36a246SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 29822616c808SRichard Henderson la_bb_end(s, nb_globals, nb_temps); 29833d5c5f87SAurelien Jarno } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { 2984f65a061cSRichard Henderson la_global_sync(s, nb_globals); 298525f49c5fSRichard Henderson if (def->flags & TCG_OPF_CALL_CLOBBER) { 298625f49c5fSRichard Henderson la_cross_call(s, nb_temps); 298725f49c5fSRichard Henderson } 2988c896fe29Sbellard } 2989c896fe29Sbellard 299025f49c5fSRichard Henderson /* Record arguments that die in this opcode. */ 2991866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 299225f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 299325f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 2994a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 2995c896fe29Sbellard } 2996c19f47bfSAurelien Jarno } 299725f49c5fSRichard Henderson 299825f49c5fSRichard Henderson /* Input arguments are live for preceding opcodes. */ 2999c19f47bfSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 300025f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 300125f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 300225f49c5fSRichard Henderson /* For operands that were dead, initially allow 300325f49c5fSRichard Henderson all regs for the type. */ 300425f49c5fSRichard Henderson *la_temp_pref(ts) = tcg_target_available_regs[ts->type]; 300525f49c5fSRichard Henderson ts->state &= ~TS_DEAD; 300625f49c5fSRichard Henderson } 300725f49c5fSRichard Henderson } 300825f49c5fSRichard Henderson 300925f49c5fSRichard Henderson /* Incorporate constraints for this operand. */ 301025f49c5fSRichard Henderson switch (opc) { 301125f49c5fSRichard Henderson case INDEX_op_mov_i32: 301225f49c5fSRichard Henderson case INDEX_op_mov_i64: 301325f49c5fSRichard Henderson /* Note that these are TCG_OPF_NOT_PRESENT and do not 301425f49c5fSRichard Henderson have proper constraints. That said, special case 301525f49c5fSRichard Henderson moves to propagate preferences backward. */ 301625f49c5fSRichard Henderson if (IS_DEAD_ARG(1)) { 301725f49c5fSRichard Henderson *la_temp_pref(arg_temp(op->args[0])) 301825f49c5fSRichard Henderson = *la_temp_pref(arg_temp(op->args[1])); 301925f49c5fSRichard Henderson } 302025f49c5fSRichard Henderson break; 302125f49c5fSRichard Henderson 302225f49c5fSRichard Henderson default: 302325f49c5fSRichard Henderson for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 302425f49c5fSRichard Henderson const TCGArgConstraint *ct = &def->args_ct[i]; 302525f49c5fSRichard Henderson TCGRegSet set, *pset; 302625f49c5fSRichard Henderson 302725f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 302825f49c5fSRichard Henderson pset = la_temp_pref(ts); 302925f49c5fSRichard Henderson set = *pset; 303025f49c5fSRichard Henderson 30319be0d080SRichard Henderson set &= ct->regs; 3032bc2b17e6SRichard Henderson if (ct->ialias) { 303331fd884bSRichard Henderson set &= output_pref(op, ct->alias_index); 303425f49c5fSRichard Henderson } 303525f49c5fSRichard Henderson /* If the combination is not possible, restart. */ 303625f49c5fSRichard Henderson if (set == 0) { 30379be0d080SRichard Henderson set = ct->regs; 303825f49c5fSRichard Henderson } 303925f49c5fSRichard Henderson *pset = set; 304025f49c5fSRichard Henderson } 304125f49c5fSRichard Henderson break; 3042c896fe29Sbellard } 3043c896fe29Sbellard break; 3044c896fe29Sbellard } 3045bee158cbSRichard Henderson op->life = arg_life; 3046c896fe29Sbellard } 30471ff0a2c5SEvgeny Voevodin } 3048c896fe29Sbellard 30495a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries. */ 3050b83eabeaSRichard Henderson static bool liveness_pass_2(TCGContext *s) 30515a18407fSRichard Henderson { 30525a18407fSRichard Henderson int nb_globals = s->nb_globals; 305315fa08f8SRichard Henderson int nb_temps, i; 30545a18407fSRichard Henderson bool changes = false; 305515fa08f8SRichard Henderson TCGOp *op, *op_next; 30565a18407fSRichard Henderson 30575a18407fSRichard Henderson /* Create a temporary for each indirect global. */ 30585a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 30595a18407fSRichard Henderson TCGTemp *its = &s->temps[i]; 30605a18407fSRichard Henderson if (its->indirect_reg) { 30615a18407fSRichard Henderson TCGTemp *dts = tcg_temp_alloc(s); 30625a18407fSRichard Henderson dts->type = its->type; 30635a18407fSRichard Henderson dts->base_type = its->base_type; 3064c7482438SRichard Henderson dts->kind = TEMP_EBB; 3065b83eabeaSRichard Henderson its->state_ptr = dts; 3066b83eabeaSRichard Henderson } else { 3067b83eabeaSRichard Henderson its->state_ptr = NULL; 30685a18407fSRichard Henderson } 3069b83eabeaSRichard Henderson /* All globals begin dead. */ 3070b83eabeaSRichard Henderson its->state = TS_DEAD; 30715a18407fSRichard Henderson } 3072b83eabeaSRichard Henderson for (nb_temps = s->nb_temps; i < nb_temps; ++i) { 3073b83eabeaSRichard Henderson TCGTemp *its = &s->temps[i]; 3074b83eabeaSRichard Henderson its->state_ptr = NULL; 3075b83eabeaSRichard Henderson its->state = TS_DEAD; 3076b83eabeaSRichard Henderson } 30775a18407fSRichard Henderson 307815fa08f8SRichard Henderson QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) { 30795a18407fSRichard Henderson TCGOpcode opc = op->opc; 30805a18407fSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 30815a18407fSRichard Henderson TCGLifeData arg_life = op->life; 30825a18407fSRichard Henderson int nb_iargs, nb_oargs, call_flags; 3083b83eabeaSRichard Henderson TCGTemp *arg_ts, *dir_ts; 30845a18407fSRichard Henderson 30855a18407fSRichard Henderson if (opc == INDEX_op_call) { 3086cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 3087cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 308890163900SRichard Henderson call_flags = tcg_call_flags(op); 30895a18407fSRichard Henderson } else { 30905a18407fSRichard Henderson nb_iargs = def->nb_iargs; 30915a18407fSRichard Henderson nb_oargs = def->nb_oargs; 30925a18407fSRichard Henderson 30935a18407fSRichard Henderson /* Set flags similar to how calls require. */ 3094b4cb76e6SRichard Henderson if (def->flags & TCG_OPF_COND_BRANCH) { 3095b4cb76e6SRichard Henderson /* Like reading globals: sync_globals */ 3096b4cb76e6SRichard Henderson call_flags = TCG_CALL_NO_WRITE_GLOBALS; 3097b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 30985a18407fSRichard Henderson /* Like writing globals: save_globals */ 30995a18407fSRichard Henderson call_flags = 0; 31005a18407fSRichard Henderson } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { 31015a18407fSRichard Henderson /* Like reading globals: sync_globals */ 31025a18407fSRichard Henderson call_flags = TCG_CALL_NO_WRITE_GLOBALS; 31035a18407fSRichard Henderson } else { 31045a18407fSRichard Henderson /* No effect on globals. */ 31055a18407fSRichard Henderson call_flags = (TCG_CALL_NO_READ_GLOBALS | 31065a18407fSRichard Henderson TCG_CALL_NO_WRITE_GLOBALS); 31075a18407fSRichard Henderson } 31085a18407fSRichard Henderson } 31095a18407fSRichard Henderson 31105a18407fSRichard Henderson /* Make sure that input arguments are available. */ 31115a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 3112b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 3113b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 3114b83eabeaSRichard Henderson if (dir_ts && arg_ts->state == TS_DEAD) { 3115b83eabeaSRichard Henderson TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32 31165a18407fSRichard Henderson ? INDEX_op_ld_i32 31175a18407fSRichard Henderson : INDEX_op_ld_i64); 3118d4478943SPhilippe Mathieu-Daudé TCGOp *lop = tcg_op_insert_before(s, op, lopc, 3); 31195a18407fSRichard Henderson 3120b83eabeaSRichard Henderson lop->args[0] = temp_arg(dir_ts); 3121b83eabeaSRichard Henderson lop->args[1] = temp_arg(arg_ts->mem_base); 3122b83eabeaSRichard Henderson lop->args[2] = arg_ts->mem_offset; 31235a18407fSRichard Henderson 31245a18407fSRichard Henderson /* Loaded, but synced with memory. */ 3125b83eabeaSRichard Henderson arg_ts->state = TS_MEM; 31265a18407fSRichard Henderson } 31275a18407fSRichard Henderson } 31285a18407fSRichard Henderson 31295a18407fSRichard Henderson /* Perform input replacement, and mark inputs that became dead. 31305a18407fSRichard Henderson No action is required except keeping temp_state up to date 31315a18407fSRichard Henderson so that we reload when needed. */ 31325a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 3133b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 3134b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 3135b83eabeaSRichard Henderson if (dir_ts) { 3136b83eabeaSRichard Henderson op->args[i] = temp_arg(dir_ts); 31375a18407fSRichard Henderson changes = true; 31385a18407fSRichard Henderson if (IS_DEAD_ARG(i)) { 3139b83eabeaSRichard Henderson arg_ts->state = TS_DEAD; 31405a18407fSRichard Henderson } 31415a18407fSRichard Henderson } 31425a18407fSRichard Henderson } 31435a18407fSRichard Henderson 31445a18407fSRichard Henderson /* Liveness analysis should ensure that the following are 31455a18407fSRichard Henderson all correct, for call sites and basic block end points. */ 31465a18407fSRichard Henderson if (call_flags & TCG_CALL_NO_READ_GLOBALS) { 31475a18407fSRichard Henderson /* Nothing to do */ 31485a18407fSRichard Henderson } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) { 31495a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 31505a18407fSRichard Henderson /* Liveness should see that globals are synced back, 31515a18407fSRichard Henderson that is, either TS_DEAD or TS_MEM. */ 3152b83eabeaSRichard Henderson arg_ts = &s->temps[i]; 3153b83eabeaSRichard Henderson tcg_debug_assert(arg_ts->state_ptr == 0 3154b83eabeaSRichard Henderson || arg_ts->state != 0); 31555a18407fSRichard Henderson } 31565a18407fSRichard Henderson } else { 31575a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 31585a18407fSRichard Henderson /* Liveness should see that globals are saved back, 31595a18407fSRichard Henderson that is, TS_DEAD, waiting to be reloaded. */ 3160b83eabeaSRichard Henderson arg_ts = &s->temps[i]; 3161b83eabeaSRichard Henderson tcg_debug_assert(arg_ts->state_ptr == 0 3162b83eabeaSRichard Henderson || arg_ts->state == TS_DEAD); 31635a18407fSRichard Henderson } 31645a18407fSRichard Henderson } 31655a18407fSRichard Henderson 31665a18407fSRichard Henderson /* Outputs become available. */ 316761f15c48SRichard Henderson if (opc == INDEX_op_mov_i32 || opc == INDEX_op_mov_i64) { 316861f15c48SRichard Henderson arg_ts = arg_temp(op->args[0]); 316961f15c48SRichard Henderson dir_ts = arg_ts->state_ptr; 317061f15c48SRichard Henderson if (dir_ts) { 317161f15c48SRichard Henderson op->args[0] = temp_arg(dir_ts); 317261f15c48SRichard Henderson changes = true; 317361f15c48SRichard Henderson 317461f15c48SRichard Henderson /* The output is now live and modified. */ 317561f15c48SRichard Henderson arg_ts->state = 0; 317661f15c48SRichard Henderson 317761f15c48SRichard Henderson if (NEED_SYNC_ARG(0)) { 317861f15c48SRichard Henderson TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 317961f15c48SRichard Henderson ? INDEX_op_st_i32 318061f15c48SRichard Henderson : INDEX_op_st_i64); 3181d4478943SPhilippe Mathieu-Daudé TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3); 318261f15c48SRichard Henderson TCGTemp *out_ts = dir_ts; 318361f15c48SRichard Henderson 318461f15c48SRichard Henderson if (IS_DEAD_ARG(0)) { 318561f15c48SRichard Henderson out_ts = arg_temp(op->args[1]); 318661f15c48SRichard Henderson arg_ts->state = TS_DEAD; 318761f15c48SRichard Henderson tcg_op_remove(s, op); 318861f15c48SRichard Henderson } else { 318961f15c48SRichard Henderson arg_ts->state = TS_MEM; 319061f15c48SRichard Henderson } 319161f15c48SRichard Henderson 319261f15c48SRichard Henderson sop->args[0] = temp_arg(out_ts); 319361f15c48SRichard Henderson sop->args[1] = temp_arg(arg_ts->mem_base); 319461f15c48SRichard Henderson sop->args[2] = arg_ts->mem_offset; 319561f15c48SRichard Henderson } else { 319661f15c48SRichard Henderson tcg_debug_assert(!IS_DEAD_ARG(0)); 319761f15c48SRichard Henderson } 319861f15c48SRichard Henderson } 319961f15c48SRichard Henderson } else { 32005a18407fSRichard Henderson for (i = 0; i < nb_oargs; i++) { 3201b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 3202b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 3203b83eabeaSRichard Henderson if (!dir_ts) { 32045a18407fSRichard Henderson continue; 32055a18407fSRichard Henderson } 3206b83eabeaSRichard Henderson op->args[i] = temp_arg(dir_ts); 32075a18407fSRichard Henderson changes = true; 32085a18407fSRichard Henderson 32095a18407fSRichard Henderson /* The output is now live and modified. */ 3210b83eabeaSRichard Henderson arg_ts->state = 0; 32115a18407fSRichard Henderson 32125a18407fSRichard Henderson /* Sync outputs upon their last write. */ 32135a18407fSRichard Henderson if (NEED_SYNC_ARG(i)) { 3214b83eabeaSRichard Henderson TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 32155a18407fSRichard Henderson ? INDEX_op_st_i32 32165a18407fSRichard Henderson : INDEX_op_st_i64); 3217d4478943SPhilippe Mathieu-Daudé TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3); 32185a18407fSRichard Henderson 3219b83eabeaSRichard Henderson sop->args[0] = temp_arg(dir_ts); 3220b83eabeaSRichard Henderson sop->args[1] = temp_arg(arg_ts->mem_base); 3221b83eabeaSRichard Henderson sop->args[2] = arg_ts->mem_offset; 32225a18407fSRichard Henderson 3223b83eabeaSRichard Henderson arg_ts->state = TS_MEM; 32245a18407fSRichard Henderson } 32255a18407fSRichard Henderson /* Drop outputs that are dead. */ 32265a18407fSRichard Henderson if (IS_DEAD_ARG(i)) { 3227b83eabeaSRichard Henderson arg_ts->state = TS_DEAD; 32285a18407fSRichard Henderson } 32295a18407fSRichard Henderson } 32305a18407fSRichard Henderson } 323161f15c48SRichard Henderson } 32325a18407fSRichard Henderson 32335a18407fSRichard Henderson return changes; 32345a18407fSRichard Henderson } 32355a18407fSRichard Henderson 32362272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts) 3237c896fe29Sbellard { 323831c96417SRichard Henderson int size = tcg_type_size(ts->type); 323931c96417SRichard Henderson int align; 324031c96417SRichard Henderson intptr_t off; 3241c1c09194SRichard Henderson 3242c1c09194SRichard Henderson switch (ts->type) { 3243c1c09194SRichard Henderson case TCG_TYPE_I32: 324431c96417SRichard Henderson align = 4; 3245c1c09194SRichard Henderson break; 3246c1c09194SRichard Henderson case TCG_TYPE_I64: 3247c1c09194SRichard Henderson case TCG_TYPE_V64: 324831c96417SRichard Henderson align = 8; 3249c1c09194SRichard Henderson break; 3250c1c09194SRichard Henderson case TCG_TYPE_V128: 3251c1c09194SRichard Henderson case TCG_TYPE_V256: 3252c1c09194SRichard Henderson /* Note that we do not require aligned storage for V256. */ 325331c96417SRichard Henderson align = 16; 3254c1c09194SRichard Henderson break; 3255c1c09194SRichard Henderson default: 3256c1c09194SRichard Henderson g_assert_not_reached(); 3257b591dc59SBlue Swirl } 3258c1c09194SRichard Henderson 3259b9537d59SRichard Henderson /* 3260b9537d59SRichard Henderson * Assume the stack is sufficiently aligned. 3261b9537d59SRichard Henderson * This affects e.g. ARM NEON, where we have 8 byte stack alignment 3262b9537d59SRichard Henderson * and do not require 16 byte vector alignment. This seems slightly 3263b9537d59SRichard Henderson * easier than fully parameterizing the above switch statement. 3264b9537d59SRichard Henderson */ 3265b9537d59SRichard Henderson align = MIN(TCG_TARGET_STACK_ALIGN, align); 3266c1c09194SRichard Henderson off = ROUND_UP(s->current_frame_offset, align); 3267732d5897SRichard Henderson 3268732d5897SRichard Henderson /* If we've exhausted the stack frame, restart with a smaller TB. */ 3269732d5897SRichard Henderson if (off + size > s->frame_end) { 3270732d5897SRichard Henderson tcg_raise_tb_overflow(s); 3271732d5897SRichard Henderson } 3272c1c09194SRichard Henderson s->current_frame_offset = off + size; 3273c1c09194SRichard Henderson 3274c1c09194SRichard Henderson ts->mem_offset = off; 32759defd1bdSRichard Henderson #if defined(__sparc__) 32769defd1bdSRichard Henderson ts->mem_offset += TCG_TARGET_STACK_BIAS; 32779defd1bdSRichard Henderson #endif 3278b3a62939SRichard Henderson ts->mem_base = s->frame_temp; 3279c896fe29Sbellard ts->mem_allocated = 1; 3280c896fe29Sbellard } 3281c896fe29Sbellard 3282098859f1SRichard Henderson /* Assign @reg to @ts, and update reg_to_temp[]. */ 3283098859f1SRichard Henderson static void set_temp_val_reg(TCGContext *s, TCGTemp *ts, TCGReg reg) 3284098859f1SRichard Henderson { 3285098859f1SRichard Henderson if (ts->val_type == TEMP_VAL_REG) { 3286098859f1SRichard Henderson TCGReg old = ts->reg; 3287098859f1SRichard Henderson tcg_debug_assert(s->reg_to_temp[old] == ts); 3288098859f1SRichard Henderson if (old == reg) { 3289098859f1SRichard Henderson return; 3290098859f1SRichard Henderson } 3291098859f1SRichard Henderson s->reg_to_temp[old] = NULL; 3292098859f1SRichard Henderson } 3293098859f1SRichard Henderson tcg_debug_assert(s->reg_to_temp[reg] == NULL); 3294098859f1SRichard Henderson s->reg_to_temp[reg] = ts; 3295098859f1SRichard Henderson ts->val_type = TEMP_VAL_REG; 3296098859f1SRichard Henderson ts->reg = reg; 3297098859f1SRichard Henderson } 3298098859f1SRichard Henderson 3299098859f1SRichard Henderson /* Assign a non-register value type to @ts, and update reg_to_temp[]. */ 3300098859f1SRichard Henderson static void set_temp_val_nonreg(TCGContext *s, TCGTemp *ts, TCGTempVal type) 3301098859f1SRichard Henderson { 3302098859f1SRichard Henderson tcg_debug_assert(type != TEMP_VAL_REG); 3303098859f1SRichard Henderson if (ts->val_type == TEMP_VAL_REG) { 3304098859f1SRichard Henderson TCGReg reg = ts->reg; 3305098859f1SRichard Henderson tcg_debug_assert(s->reg_to_temp[reg] == ts); 3306098859f1SRichard Henderson s->reg_to_temp[reg] = NULL; 3307098859f1SRichard Henderson } 3308098859f1SRichard Henderson ts->val_type = type; 3309098859f1SRichard Henderson } 3310098859f1SRichard Henderson 3311b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet); 3312b3915dbbSRichard Henderson 331359d7c14eSRichard Henderson /* Mark a temporary as free or dead. If 'free_or_dead' is negative, 331459d7c14eSRichard Henderson mark it free; otherwise mark it dead. */ 331559d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead) 3316c896fe29Sbellard { 3317c0522136SRichard Henderson TCGTempVal new_type; 3318c0522136SRichard Henderson 3319c0522136SRichard Henderson switch (ts->kind) { 3320c0522136SRichard Henderson case TEMP_FIXED: 332159d7c14eSRichard Henderson return; 3322c0522136SRichard Henderson case TEMP_GLOBAL: 3323c0522136SRichard Henderson case TEMP_LOCAL: 3324c0522136SRichard Henderson new_type = TEMP_VAL_MEM; 3325c0522136SRichard Henderson break; 3326c0522136SRichard Henderson case TEMP_NORMAL: 3327c7482438SRichard Henderson case TEMP_EBB: 3328c0522136SRichard Henderson new_type = free_or_dead < 0 ? TEMP_VAL_MEM : TEMP_VAL_DEAD; 3329c0522136SRichard Henderson break; 3330c0522136SRichard Henderson case TEMP_CONST: 3331c0522136SRichard Henderson new_type = TEMP_VAL_CONST; 3332c0522136SRichard Henderson break; 3333c0522136SRichard Henderson default: 3334c0522136SRichard Henderson g_assert_not_reached(); 333559d7c14eSRichard Henderson } 3336098859f1SRichard Henderson set_temp_val_nonreg(s, ts, new_type); 333759d7c14eSRichard Henderson } 3338c896fe29Sbellard 333959d7c14eSRichard Henderson /* Mark a temporary as dead. */ 334059d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts) 334159d7c14eSRichard Henderson { 334259d7c14eSRichard Henderson temp_free_or_dead(s, ts, 1); 334359d7c14eSRichard Henderson } 334459d7c14eSRichard Henderson 334559d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary 334659d7c14eSRichard Henderson registers needs to be allocated to store a constant. If 'free_or_dead' 334759d7c14eSRichard Henderson is non-zero, subsequently release the temporary; if it is positive, the 334859d7c14eSRichard Henderson temp is dead; if it is negative, the temp is free. */ 334998b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs, 335098b4e186SRichard Henderson TCGRegSet preferred_regs, int free_or_dead) 335159d7c14eSRichard Henderson { 3352c0522136SRichard Henderson if (!temp_readonly(ts) && !ts->mem_coherent) { 33537f6ceedfSAurelien Jarno if (!ts->mem_allocated) { 33542272e4a7SRichard Henderson temp_allocate_frame(s, ts); 335559d7c14eSRichard Henderson } 335659d7c14eSRichard Henderson switch (ts->val_type) { 335759d7c14eSRichard Henderson case TEMP_VAL_CONST: 335859d7c14eSRichard Henderson /* If we're going to free the temp immediately, then we won't 335959d7c14eSRichard Henderson require it later in a register, so attempt to store the 336059d7c14eSRichard Henderson constant to memory directly. */ 336159d7c14eSRichard Henderson if (free_or_dead 336259d7c14eSRichard Henderson && tcg_out_sti(s, ts->type, ts->val, 336359d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset)) { 336459d7c14eSRichard Henderson break; 336559d7c14eSRichard Henderson } 336659d7c14eSRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 336798b4e186SRichard Henderson allocated_regs, preferred_regs); 336859d7c14eSRichard Henderson /* fallthrough */ 336959d7c14eSRichard Henderson 337059d7c14eSRichard Henderson case TEMP_VAL_REG: 337159d7c14eSRichard Henderson tcg_out_st(s, ts->type, ts->reg, 337259d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset); 337359d7c14eSRichard Henderson break; 337459d7c14eSRichard Henderson 337559d7c14eSRichard Henderson case TEMP_VAL_MEM: 337659d7c14eSRichard Henderson break; 337759d7c14eSRichard Henderson 337859d7c14eSRichard Henderson case TEMP_VAL_DEAD: 337959d7c14eSRichard Henderson default: 338059d7c14eSRichard Henderson tcg_abort(); 3381c896fe29Sbellard } 33827f6ceedfSAurelien Jarno ts->mem_coherent = 1; 33837f6ceedfSAurelien Jarno } 338459d7c14eSRichard Henderson if (free_or_dead) { 338559d7c14eSRichard Henderson temp_free_or_dead(s, ts, free_or_dead); 338659d7c14eSRichard Henderson } 338759d7c14eSRichard Henderson } 33887f6ceedfSAurelien Jarno 33897f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */ 3390b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs) 33917f6ceedfSAurelien Jarno { 3392f8b2f202SRichard Henderson TCGTemp *ts = s->reg_to_temp[reg]; 3393f8b2f202SRichard Henderson if (ts != NULL) { 339498b4e186SRichard Henderson temp_sync(s, ts, allocated_regs, 0, -1); 3395c896fe29Sbellard } 3396c896fe29Sbellard } 3397c896fe29Sbellard 3398b016486eSRichard Henderson /** 3399b016486eSRichard Henderson * tcg_reg_alloc: 3400b016486eSRichard Henderson * @required_regs: Set of registers in which we must allocate. 3401b016486eSRichard Henderson * @allocated_regs: Set of registers which must be avoided. 3402b016486eSRichard Henderson * @preferred_regs: Set of registers we should prefer. 3403b016486eSRichard Henderson * @rev: True if we search the registers in "indirect" order. 3404b016486eSRichard Henderson * 3405b016486eSRichard Henderson * The allocated register must be in @required_regs & ~@allocated_regs, 3406b016486eSRichard Henderson * but if we can put it in @preferred_regs we may save a move later. 3407b016486eSRichard Henderson */ 3408b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs, 3409b016486eSRichard Henderson TCGRegSet allocated_regs, 3410b016486eSRichard Henderson TCGRegSet preferred_regs, bool rev) 3411c896fe29Sbellard { 3412b016486eSRichard Henderson int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order); 3413b016486eSRichard Henderson TCGRegSet reg_ct[2]; 341491478cefSRichard Henderson const int *order; 3415c896fe29Sbellard 3416b016486eSRichard Henderson reg_ct[1] = required_regs & ~allocated_regs; 3417b016486eSRichard Henderson tcg_debug_assert(reg_ct[1] != 0); 3418b016486eSRichard Henderson reg_ct[0] = reg_ct[1] & preferred_regs; 3419b016486eSRichard Henderson 3420b016486eSRichard Henderson /* Skip the preferred_regs option if it cannot be satisfied, 3421b016486eSRichard Henderson or if the preference made no difference. */ 3422b016486eSRichard Henderson f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1]; 3423b016486eSRichard Henderson 342491478cefSRichard Henderson order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order; 3425c896fe29Sbellard 3426b016486eSRichard Henderson /* Try free registers, preferences first. */ 3427b016486eSRichard Henderson for (j = f; j < 2; j++) { 3428b016486eSRichard Henderson TCGRegSet set = reg_ct[j]; 3429b016486eSRichard Henderson 3430b016486eSRichard Henderson if (tcg_regset_single(set)) { 3431b016486eSRichard Henderson /* One register in the set. */ 3432b016486eSRichard Henderson TCGReg reg = tcg_regset_first(set); 3433b016486eSRichard Henderson if (s->reg_to_temp[reg] == NULL) { 3434c896fe29Sbellard return reg; 3435c896fe29Sbellard } 3436b016486eSRichard Henderson } else { 343791478cefSRichard Henderson for (i = 0; i < n; i++) { 3438b016486eSRichard Henderson TCGReg reg = order[i]; 3439b016486eSRichard Henderson if (s->reg_to_temp[reg] == NULL && 3440b016486eSRichard Henderson tcg_regset_test_reg(set, reg)) { 3441b016486eSRichard Henderson return reg; 3442b016486eSRichard Henderson } 3443b016486eSRichard Henderson } 3444b016486eSRichard Henderson } 3445b016486eSRichard Henderson } 3446b016486eSRichard Henderson 3447b016486eSRichard Henderson /* We must spill something. */ 3448b016486eSRichard Henderson for (j = f; j < 2; j++) { 3449b016486eSRichard Henderson TCGRegSet set = reg_ct[j]; 3450b016486eSRichard Henderson 3451b016486eSRichard Henderson if (tcg_regset_single(set)) { 3452b016486eSRichard Henderson /* One register in the set. */ 3453b016486eSRichard Henderson TCGReg reg = tcg_regset_first(set); 3454b3915dbbSRichard Henderson tcg_reg_free(s, reg, allocated_regs); 3455c896fe29Sbellard return reg; 3456b016486eSRichard Henderson } else { 3457b016486eSRichard Henderson for (i = 0; i < n; i++) { 3458b016486eSRichard Henderson TCGReg reg = order[i]; 3459b016486eSRichard Henderson if (tcg_regset_test_reg(set, reg)) { 3460b016486eSRichard Henderson tcg_reg_free(s, reg, allocated_regs); 3461b016486eSRichard Henderson return reg; 3462b016486eSRichard Henderson } 3463b016486eSRichard Henderson } 3464c896fe29Sbellard } 3465c896fe29Sbellard } 3466c896fe29Sbellard 3467c896fe29Sbellard tcg_abort(); 3468c896fe29Sbellard } 3469c896fe29Sbellard 347029f5e925SRichard Henderson static TCGReg tcg_reg_alloc_pair(TCGContext *s, TCGRegSet required_regs, 347129f5e925SRichard Henderson TCGRegSet allocated_regs, 347229f5e925SRichard Henderson TCGRegSet preferred_regs, bool rev) 347329f5e925SRichard Henderson { 347429f5e925SRichard Henderson int i, j, k, fmin, n = ARRAY_SIZE(tcg_target_reg_alloc_order); 347529f5e925SRichard Henderson TCGRegSet reg_ct[2]; 347629f5e925SRichard Henderson const int *order; 347729f5e925SRichard Henderson 347829f5e925SRichard Henderson /* Ensure that if I is not in allocated_regs, I+1 is not either. */ 347929f5e925SRichard Henderson reg_ct[1] = required_regs & ~(allocated_regs | (allocated_regs >> 1)); 348029f5e925SRichard Henderson tcg_debug_assert(reg_ct[1] != 0); 348129f5e925SRichard Henderson reg_ct[0] = reg_ct[1] & preferred_regs; 348229f5e925SRichard Henderson 348329f5e925SRichard Henderson order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order; 348429f5e925SRichard Henderson 348529f5e925SRichard Henderson /* 348629f5e925SRichard Henderson * Skip the preferred_regs option if it cannot be satisfied, 348729f5e925SRichard Henderson * or if the preference made no difference. 348829f5e925SRichard Henderson */ 348929f5e925SRichard Henderson k = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1]; 349029f5e925SRichard Henderson 349129f5e925SRichard Henderson /* 349229f5e925SRichard Henderson * Minimize the number of flushes by looking for 2 free registers first, 349329f5e925SRichard Henderson * then a single flush, then two flushes. 349429f5e925SRichard Henderson */ 349529f5e925SRichard Henderson for (fmin = 2; fmin >= 0; fmin--) { 349629f5e925SRichard Henderson for (j = k; j < 2; j++) { 349729f5e925SRichard Henderson TCGRegSet set = reg_ct[j]; 349829f5e925SRichard Henderson 349929f5e925SRichard Henderson for (i = 0; i < n; i++) { 350029f5e925SRichard Henderson TCGReg reg = order[i]; 350129f5e925SRichard Henderson 350229f5e925SRichard Henderson if (tcg_regset_test_reg(set, reg)) { 350329f5e925SRichard Henderson int f = !s->reg_to_temp[reg] + !s->reg_to_temp[reg + 1]; 350429f5e925SRichard Henderson if (f >= fmin) { 350529f5e925SRichard Henderson tcg_reg_free(s, reg, allocated_regs); 350629f5e925SRichard Henderson tcg_reg_free(s, reg + 1, allocated_regs); 350729f5e925SRichard Henderson return reg; 350829f5e925SRichard Henderson } 350929f5e925SRichard Henderson } 351029f5e925SRichard Henderson } 351129f5e925SRichard Henderson } 351229f5e925SRichard Henderson } 351329f5e925SRichard Henderson tcg_abort(); 351429f5e925SRichard Henderson } 351529f5e925SRichard Henderson 351640ae5c62SRichard Henderson /* Make sure the temporary is in a register. If needed, allocate the register 351740ae5c62SRichard Henderson from DESIRED while avoiding ALLOCATED. */ 351840ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs, 3519b722452aSRichard Henderson TCGRegSet allocated_regs, TCGRegSet preferred_regs) 352040ae5c62SRichard Henderson { 352140ae5c62SRichard Henderson TCGReg reg; 352240ae5c62SRichard Henderson 352340ae5c62SRichard Henderson switch (ts->val_type) { 352440ae5c62SRichard Henderson case TEMP_VAL_REG: 352540ae5c62SRichard Henderson return; 352640ae5c62SRichard Henderson case TEMP_VAL_CONST: 3527b016486eSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs, 3528b722452aSRichard Henderson preferred_regs, ts->indirect_base); 35290a6a8bc8SRichard Henderson if (ts->type <= TCG_TYPE_I64) { 353040ae5c62SRichard Henderson tcg_out_movi(s, ts->type, reg, ts->val); 35310a6a8bc8SRichard Henderson } else { 35324e186175SRichard Henderson uint64_t val = ts->val; 35334e186175SRichard Henderson MemOp vece = MO_64; 35344e186175SRichard Henderson 35354e186175SRichard Henderson /* 35364e186175SRichard Henderson * Find the minimal vector element that matches the constant. 35374e186175SRichard Henderson * The targets will, in general, have to do this search anyway, 35384e186175SRichard Henderson * do this generically. 35394e186175SRichard Henderson */ 35404e186175SRichard Henderson if (val == dup_const(MO_8, val)) { 35414e186175SRichard Henderson vece = MO_8; 35424e186175SRichard Henderson } else if (val == dup_const(MO_16, val)) { 35434e186175SRichard Henderson vece = MO_16; 35440b4286ddSRichard Henderson } else if (val == dup_const(MO_32, val)) { 35454e186175SRichard Henderson vece = MO_32; 35464e186175SRichard Henderson } 35474e186175SRichard Henderson 35484e186175SRichard Henderson tcg_out_dupi_vec(s, ts->type, vece, reg, ts->val); 35490a6a8bc8SRichard Henderson } 355040ae5c62SRichard Henderson ts->mem_coherent = 0; 355140ae5c62SRichard Henderson break; 355240ae5c62SRichard Henderson case TEMP_VAL_MEM: 3553b016486eSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs, 3554b722452aSRichard Henderson preferred_regs, ts->indirect_base); 355540ae5c62SRichard Henderson tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset); 355640ae5c62SRichard Henderson ts->mem_coherent = 1; 355740ae5c62SRichard Henderson break; 355840ae5c62SRichard Henderson case TEMP_VAL_DEAD: 355940ae5c62SRichard Henderson default: 356040ae5c62SRichard Henderson tcg_abort(); 356140ae5c62SRichard Henderson } 3562098859f1SRichard Henderson set_temp_val_reg(s, ts, reg); 356340ae5c62SRichard Henderson } 356440ae5c62SRichard Henderson 356559d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a 3566e8996ee0Sbellard temporary registers needs to be allocated to store a constant. */ 356759d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs) 35681ad80729SAurelien Jarno { 35692c0366f0SAurelien Jarno /* The liveness analysis already ensures that globals are back 3570eabb7b91SAurelien Jarno in memory. Keep an tcg_debug_assert for safety. */ 3571e01fa97dSRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || temp_readonly(ts)); 35721ad80729SAurelien Jarno } 35731ad80729SAurelien Jarno 35749814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be 3575641d5fbeSbellard modified be the following code. 'allocated_regs' is used in case a 3576641d5fbeSbellard temporary registers needs to be allocated to store a constant. */ 3577641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs) 3578641d5fbeSbellard { 3579ac3b8891SRichard Henderson int i, n; 3580641d5fbeSbellard 3581ac3b8891SRichard Henderson for (i = 0, n = s->nb_globals; i < n; i++) { 3582b13eb728SRichard Henderson temp_save(s, &s->temps[i], allocated_regs); 3583641d5fbeSbellard } 3584e5097dc8Sbellard } 3585e5097dc8Sbellard 35863d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be 35873d5c5f87SAurelien Jarno read by the following code. 'allocated_regs' is used in case a 35883d5c5f87SAurelien Jarno temporary registers needs to be allocated to store a constant. */ 35893d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs) 35903d5c5f87SAurelien Jarno { 3591ac3b8891SRichard Henderson int i, n; 35923d5c5f87SAurelien Jarno 3593ac3b8891SRichard Henderson for (i = 0, n = s->nb_globals; i < n; i++) { 359412b9b11aSRichard Henderson TCGTemp *ts = &s->temps[i]; 359512b9b11aSRichard Henderson tcg_debug_assert(ts->val_type != TEMP_VAL_REG 3596ee17db83SRichard Henderson || ts->kind == TEMP_FIXED 359712b9b11aSRichard Henderson || ts->mem_coherent); 35983d5c5f87SAurelien Jarno } 35993d5c5f87SAurelien Jarno } 36003d5c5f87SAurelien Jarno 3601e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and 3602e8996ee0Sbellard all globals are stored at their canonical location. */ 3603e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs) 3604e5097dc8Sbellard { 3605e5097dc8Sbellard int i; 3606e5097dc8Sbellard 3607c896fe29Sbellard for (i = s->nb_globals; i < s->nb_temps; i++) { 3608b13eb728SRichard Henderson TCGTemp *ts = &s->temps[i]; 3609c0522136SRichard Henderson 3610c0522136SRichard Henderson switch (ts->kind) { 3611c0522136SRichard Henderson case TEMP_LOCAL: 3612b13eb728SRichard Henderson temp_save(s, ts, allocated_regs); 3613c0522136SRichard Henderson break; 3614c0522136SRichard Henderson case TEMP_NORMAL: 3615c7482438SRichard Henderson case TEMP_EBB: 36162c0366f0SAurelien Jarno /* The liveness analysis already ensures that temps are dead. 3617eabb7b91SAurelien Jarno Keep an tcg_debug_assert for safety. */ 3618eabb7b91SAurelien Jarno tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD); 3619c0522136SRichard Henderson break; 3620c0522136SRichard Henderson case TEMP_CONST: 3621c0522136SRichard Henderson /* Similarly, we should have freed any allocated register. */ 3622c0522136SRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_CONST); 3623c0522136SRichard Henderson break; 3624c0522136SRichard Henderson default: 3625c0522136SRichard Henderson g_assert_not_reached(); 3626c896fe29Sbellard } 3627641d5fbeSbellard } 3628e8996ee0Sbellard 3629e8996ee0Sbellard save_globals(s, allocated_regs); 3630c896fe29Sbellard } 3631c896fe29Sbellard 3632bab1671fSRichard Henderson /* 3633c7482438SRichard Henderson * At a conditional branch, we assume all temporaries are dead unless 3634c7482438SRichard Henderson * explicitly live-across-conditional-branch; all globals and local 3635c7482438SRichard Henderson * temps are synced to their location. 3636b4cb76e6SRichard Henderson */ 3637b4cb76e6SRichard Henderson static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs) 3638b4cb76e6SRichard Henderson { 3639b4cb76e6SRichard Henderson sync_globals(s, allocated_regs); 3640b4cb76e6SRichard Henderson 3641b4cb76e6SRichard Henderson for (int i = s->nb_globals; i < s->nb_temps; i++) { 3642b4cb76e6SRichard Henderson TCGTemp *ts = &s->temps[i]; 3643b4cb76e6SRichard Henderson /* 3644b4cb76e6SRichard Henderson * The liveness analysis already ensures that temps are dead. 3645b4cb76e6SRichard Henderson * Keep tcg_debug_asserts for safety. 3646b4cb76e6SRichard Henderson */ 3647c0522136SRichard Henderson switch (ts->kind) { 3648c0522136SRichard Henderson case TEMP_LOCAL: 3649b4cb76e6SRichard Henderson tcg_debug_assert(ts->val_type != TEMP_VAL_REG || ts->mem_coherent); 3650c0522136SRichard Henderson break; 3651c0522136SRichard Henderson case TEMP_NORMAL: 3652b4cb76e6SRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD); 3653c0522136SRichard Henderson break; 3654c7482438SRichard Henderson case TEMP_EBB: 3655c0522136SRichard Henderson case TEMP_CONST: 3656c0522136SRichard Henderson break; 3657c0522136SRichard Henderson default: 3658c0522136SRichard Henderson g_assert_not_reached(); 3659b4cb76e6SRichard Henderson } 3660b4cb76e6SRichard Henderson } 3661b4cb76e6SRichard Henderson } 3662b4cb76e6SRichard Henderson 3663b4cb76e6SRichard Henderson /* 3664c58f4c97SRichard Henderson * Specialized code generation for INDEX_op_mov_* with a constant. 3665bab1671fSRichard Henderson */ 36660fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots, 3667ba87719cSRichard Henderson tcg_target_ulong val, TCGLifeData arg_life, 3668ba87719cSRichard Henderson TCGRegSet preferred_regs) 3669e8996ee0Sbellard { 3670d63e3b6eSRichard Henderson /* ENV should not be modified. */ 3671e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 367259d7c14eSRichard Henderson 367359d7c14eSRichard Henderson /* The movi is not explicitly generated here. */ 3674098859f1SRichard Henderson set_temp_val_nonreg(s, ots, TEMP_VAL_CONST); 3675e8996ee0Sbellard ots->val = val; 367659d7c14eSRichard Henderson ots->mem_coherent = 0; 3677ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) { 3678ba87719cSRichard Henderson temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0)); 367959d7c14eSRichard Henderson } else if (IS_DEAD_ARG(0)) { 3680f8bf00f1SRichard Henderson temp_dead(s, ots); 36814c4e1ab2SAurelien Jarno } 3682e8996ee0Sbellard } 3683e8996ee0Sbellard 3684bab1671fSRichard Henderson /* 3685bab1671fSRichard Henderson * Specialized code generation for INDEX_op_mov_*. 3686bab1671fSRichard Henderson */ 3687dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op) 3688c896fe29Sbellard { 3689dd186292SRichard Henderson const TCGLifeData arg_life = op->life; 369069e3706dSRichard Henderson TCGRegSet allocated_regs, preferred_regs; 3691c896fe29Sbellard TCGTemp *ts, *ots; 3692450445d5SRichard Henderson TCGType otype, itype; 3693098859f1SRichard Henderson TCGReg oreg, ireg; 3694c896fe29Sbellard 3695d21369f5SRichard Henderson allocated_regs = s->reserved_regs; 369631fd884bSRichard Henderson preferred_regs = output_pref(op, 0); 369743439139SRichard Henderson ots = arg_temp(op->args[0]); 369843439139SRichard Henderson ts = arg_temp(op->args[1]); 3699450445d5SRichard Henderson 3700d63e3b6eSRichard Henderson /* ENV should not be modified. */ 3701e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 3702d63e3b6eSRichard Henderson 3703450445d5SRichard Henderson /* Note that otype != itype for no-op truncation. */ 3704450445d5SRichard Henderson otype = ots->type; 3705450445d5SRichard Henderson itype = ts->type; 3706c896fe29Sbellard 37070fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_CONST) { 37080fe4fca4SPaolo Bonzini /* propagate constant or generate sti */ 37090fe4fca4SPaolo Bonzini tcg_target_ulong val = ts->val; 37100fe4fca4SPaolo Bonzini if (IS_DEAD_ARG(1)) { 37110fe4fca4SPaolo Bonzini temp_dead(s, ts); 37120fe4fca4SPaolo Bonzini } 371369e3706dSRichard Henderson tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs); 37140fe4fca4SPaolo Bonzini return; 37150fe4fca4SPaolo Bonzini } 37160fe4fca4SPaolo Bonzini 37170fe4fca4SPaolo Bonzini /* If the source value is in memory we're going to be forced 37180fe4fca4SPaolo Bonzini to have it in a register in order to perform the copy. Copy 37190fe4fca4SPaolo Bonzini the SOURCE value into its own register first, that way we 37200fe4fca4SPaolo Bonzini don't have to reload SOURCE the next time it is used. */ 37210fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_MEM) { 372269e3706dSRichard Henderson temp_load(s, ts, tcg_target_available_regs[itype], 372369e3706dSRichard Henderson allocated_regs, preferred_regs); 3724c29c1d7eSAurelien Jarno } 37250fe4fca4SPaolo Bonzini tcg_debug_assert(ts->val_type == TEMP_VAL_REG); 3726098859f1SRichard Henderson ireg = ts->reg; 3727098859f1SRichard Henderson 3728d63e3b6eSRichard Henderson if (IS_DEAD_ARG(0)) { 3729c29c1d7eSAurelien Jarno /* mov to a non-saved dead register makes no sense (even with 3730c29c1d7eSAurelien Jarno liveness analysis disabled). */ 3731eabb7b91SAurelien Jarno tcg_debug_assert(NEED_SYNC_ARG(0)); 3732c29c1d7eSAurelien Jarno if (!ots->mem_allocated) { 37332272e4a7SRichard Henderson temp_allocate_frame(s, ots); 3734c29c1d7eSAurelien Jarno } 3735098859f1SRichard Henderson tcg_out_st(s, otype, ireg, ots->mem_base->reg, ots->mem_offset); 3736c29c1d7eSAurelien Jarno if (IS_DEAD_ARG(1)) { 3737f8bf00f1SRichard Henderson temp_dead(s, ts); 3738c29c1d7eSAurelien Jarno } 3739f8bf00f1SRichard Henderson temp_dead(s, ots); 3740098859f1SRichard Henderson return; 3741098859f1SRichard Henderson } 3742098859f1SRichard Henderson 3743ee17db83SRichard Henderson if (IS_DEAD_ARG(1) && ts->kind != TEMP_FIXED) { 3744098859f1SRichard Henderson /* 3745098859f1SRichard Henderson * The mov can be suppressed. Kill input first, so that it 3746098859f1SRichard Henderson * is unlinked from reg_to_temp, then set the output to the 3747098859f1SRichard Henderson * reg that we saved from the input. 3748098859f1SRichard Henderson */ 3749f8bf00f1SRichard Henderson temp_dead(s, ts); 3750098859f1SRichard Henderson oreg = ireg; 3751c29c1d7eSAurelien Jarno } else { 3752098859f1SRichard Henderson if (ots->val_type == TEMP_VAL_REG) { 3753098859f1SRichard Henderson oreg = ots->reg; 3754098859f1SRichard Henderson } else { 3755098859f1SRichard Henderson /* Make sure to not spill the input register during allocation. */ 3756098859f1SRichard Henderson oreg = tcg_reg_alloc(s, tcg_target_available_regs[otype], 3757098859f1SRichard Henderson allocated_regs | ((TCGRegSet)1 << ireg), 3758098859f1SRichard Henderson preferred_regs, ots->indirect_base); 3759c29c1d7eSAurelien Jarno } 3760098859f1SRichard Henderson if (!tcg_out_mov(s, otype, oreg, ireg)) { 3761240c08d0SRichard Henderson /* 3762240c08d0SRichard Henderson * Cross register class move not supported. 3763240c08d0SRichard Henderson * Store the source register into the destination slot 3764240c08d0SRichard Henderson * and leave the destination temp as TEMP_VAL_MEM. 3765240c08d0SRichard Henderson */ 3766e01fa97dSRichard Henderson assert(!temp_readonly(ots)); 3767240c08d0SRichard Henderson if (!ts->mem_allocated) { 3768240c08d0SRichard Henderson temp_allocate_frame(s, ots); 3769240c08d0SRichard Henderson } 3770098859f1SRichard Henderson tcg_out_st(s, ts->type, ireg, ots->mem_base->reg, ots->mem_offset); 3771098859f1SRichard Henderson set_temp_val_nonreg(s, ts, TEMP_VAL_MEM); 3772240c08d0SRichard Henderson ots->mem_coherent = 1; 3773240c08d0SRichard Henderson return; 377478113e83SRichard Henderson } 3775c29c1d7eSAurelien Jarno } 3776098859f1SRichard Henderson set_temp_val_reg(s, ots, oreg); 3777c896fe29Sbellard ots->mem_coherent = 0; 3778098859f1SRichard Henderson 3779ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) { 378098b4e186SRichard Henderson temp_sync(s, ots, allocated_regs, 0, 0); 3781c29c1d7eSAurelien Jarno } 3782ec7a869dSAurelien Jarno } 3783c896fe29Sbellard 3784bab1671fSRichard Henderson /* 3785bab1671fSRichard Henderson * Specialized code generation for INDEX_op_dup_vec. 3786bab1671fSRichard Henderson */ 3787bab1671fSRichard Henderson static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op) 3788bab1671fSRichard Henderson { 3789bab1671fSRichard Henderson const TCGLifeData arg_life = op->life; 3790bab1671fSRichard Henderson TCGRegSet dup_out_regs, dup_in_regs; 3791bab1671fSRichard Henderson TCGTemp *its, *ots; 3792bab1671fSRichard Henderson TCGType itype, vtype; 3793bab1671fSRichard Henderson unsigned vece; 379431c96417SRichard Henderson int lowpart_ofs; 3795bab1671fSRichard Henderson bool ok; 3796bab1671fSRichard Henderson 3797bab1671fSRichard Henderson ots = arg_temp(op->args[0]); 3798bab1671fSRichard Henderson its = arg_temp(op->args[1]); 3799bab1671fSRichard Henderson 3800bab1671fSRichard Henderson /* ENV should not be modified. */ 3801e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 3802bab1671fSRichard Henderson 3803bab1671fSRichard Henderson itype = its->type; 3804bab1671fSRichard Henderson vece = TCGOP_VECE(op); 3805bab1671fSRichard Henderson vtype = TCGOP_VECL(op) + TCG_TYPE_V64; 3806bab1671fSRichard Henderson 3807bab1671fSRichard Henderson if (its->val_type == TEMP_VAL_CONST) { 3808bab1671fSRichard Henderson /* Propagate constant via movi -> dupi. */ 3809bab1671fSRichard Henderson tcg_target_ulong val = its->val; 3810bab1671fSRichard Henderson if (IS_DEAD_ARG(1)) { 3811bab1671fSRichard Henderson temp_dead(s, its); 3812bab1671fSRichard Henderson } 381331fd884bSRichard Henderson tcg_reg_alloc_do_movi(s, ots, val, arg_life, output_pref(op, 0)); 3814bab1671fSRichard Henderson return; 3815bab1671fSRichard Henderson } 3816bab1671fSRichard Henderson 38179be0d080SRichard Henderson dup_out_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs; 38189be0d080SRichard Henderson dup_in_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[1].regs; 3819bab1671fSRichard Henderson 3820bab1671fSRichard Henderson /* Allocate the output register now. */ 3821bab1671fSRichard Henderson if (ots->val_type != TEMP_VAL_REG) { 3822bab1671fSRichard Henderson TCGRegSet allocated_regs = s->reserved_regs; 3823098859f1SRichard Henderson TCGReg oreg; 3824bab1671fSRichard Henderson 3825bab1671fSRichard Henderson if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) { 3826bab1671fSRichard Henderson /* Make sure to not spill the input register. */ 3827bab1671fSRichard Henderson tcg_regset_set_reg(allocated_regs, its->reg); 3828bab1671fSRichard Henderson } 3829098859f1SRichard Henderson oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs, 383031fd884bSRichard Henderson output_pref(op, 0), ots->indirect_base); 3831098859f1SRichard Henderson set_temp_val_reg(s, ots, oreg); 3832bab1671fSRichard Henderson } 3833bab1671fSRichard Henderson 3834bab1671fSRichard Henderson switch (its->val_type) { 3835bab1671fSRichard Henderson case TEMP_VAL_REG: 3836bab1671fSRichard Henderson /* 3837bab1671fSRichard Henderson * The dup constriaints must be broad, covering all possible VECE. 3838bab1671fSRichard Henderson * However, tcg_op_dup_vec() gets to see the VECE and we allow it 3839bab1671fSRichard Henderson * to fail, indicating that extra moves are required for that case. 3840bab1671fSRichard Henderson */ 3841bab1671fSRichard Henderson if (tcg_regset_test_reg(dup_in_regs, its->reg)) { 3842bab1671fSRichard Henderson if (tcg_out_dup_vec(s, vtype, vece, ots->reg, its->reg)) { 3843bab1671fSRichard Henderson goto done; 3844bab1671fSRichard Henderson } 3845bab1671fSRichard Henderson /* Try again from memory or a vector input register. */ 3846bab1671fSRichard Henderson } 3847bab1671fSRichard Henderson if (!its->mem_coherent) { 3848bab1671fSRichard Henderson /* 3849bab1671fSRichard Henderson * The input register is not synced, and so an extra store 3850bab1671fSRichard Henderson * would be required to use memory. Attempt an integer-vector 3851bab1671fSRichard Henderson * register move first. We do not have a TCGRegSet for this. 3852bab1671fSRichard Henderson */ 3853bab1671fSRichard Henderson if (tcg_out_mov(s, itype, ots->reg, its->reg)) { 3854bab1671fSRichard Henderson break; 3855bab1671fSRichard Henderson } 3856bab1671fSRichard Henderson /* Sync the temp back to its slot and load from there. */ 3857bab1671fSRichard Henderson temp_sync(s, its, s->reserved_regs, 0, 0); 3858bab1671fSRichard Henderson } 3859bab1671fSRichard Henderson /* fall through */ 3860bab1671fSRichard Henderson 3861bab1671fSRichard Henderson case TEMP_VAL_MEM: 386231c96417SRichard Henderson lowpart_ofs = 0; 386331c96417SRichard Henderson if (HOST_BIG_ENDIAN) { 386431c96417SRichard Henderson lowpart_ofs = tcg_type_size(itype) - (1 << vece); 386531c96417SRichard Henderson } 3866d6ecb4a9SRichard Henderson if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg, 386731c96417SRichard Henderson its->mem_offset + lowpart_ofs)) { 3868d6ecb4a9SRichard Henderson goto done; 3869d6ecb4a9SRichard Henderson } 3870098859f1SRichard Henderson /* Load the input into the destination vector register. */ 3871bab1671fSRichard Henderson tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset); 3872bab1671fSRichard Henderson break; 3873bab1671fSRichard Henderson 3874bab1671fSRichard Henderson default: 3875bab1671fSRichard Henderson g_assert_not_reached(); 3876bab1671fSRichard Henderson } 3877bab1671fSRichard Henderson 3878bab1671fSRichard Henderson /* We now have a vector input register, so dup must succeed. */ 3879bab1671fSRichard Henderson ok = tcg_out_dup_vec(s, vtype, vece, ots->reg, ots->reg); 3880bab1671fSRichard Henderson tcg_debug_assert(ok); 3881bab1671fSRichard Henderson 3882bab1671fSRichard Henderson done: 388336f5539cSRichard Henderson ots->mem_coherent = 0; 3884bab1671fSRichard Henderson if (IS_DEAD_ARG(1)) { 3885bab1671fSRichard Henderson temp_dead(s, its); 3886bab1671fSRichard Henderson } 3887bab1671fSRichard Henderson if (NEED_SYNC_ARG(0)) { 3888bab1671fSRichard Henderson temp_sync(s, ots, s->reserved_regs, 0, 0); 3889bab1671fSRichard Henderson } 3890bab1671fSRichard Henderson if (IS_DEAD_ARG(0)) { 3891bab1671fSRichard Henderson temp_dead(s, ots); 3892bab1671fSRichard Henderson } 3893bab1671fSRichard Henderson } 3894bab1671fSRichard Henderson 3895dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) 3896c896fe29Sbellard { 3897dd186292SRichard Henderson const TCGLifeData arg_life = op->life; 3898dd186292SRichard Henderson const TCGOpDef * const def = &tcg_op_defs[op->opc]; 389982790a87SRichard Henderson TCGRegSet i_allocated_regs; 390082790a87SRichard Henderson TCGRegSet o_allocated_regs; 3901b6638662SRichard Henderson int i, k, nb_iargs, nb_oargs; 3902b6638662SRichard Henderson TCGReg reg; 3903c896fe29Sbellard TCGArg arg; 3904c896fe29Sbellard const TCGArgConstraint *arg_ct; 3905c896fe29Sbellard TCGTemp *ts; 3906c896fe29Sbellard TCGArg new_args[TCG_MAX_OP_ARGS]; 3907c896fe29Sbellard int const_args[TCG_MAX_OP_ARGS]; 3908c896fe29Sbellard 3909c896fe29Sbellard nb_oargs = def->nb_oargs; 3910c896fe29Sbellard nb_iargs = def->nb_iargs; 3911c896fe29Sbellard 3912c896fe29Sbellard /* copy constants */ 3913c896fe29Sbellard memcpy(new_args + nb_oargs + nb_iargs, 3914dd186292SRichard Henderson op->args + nb_oargs + nb_iargs, 3915c896fe29Sbellard sizeof(TCGArg) * def->nb_cargs); 3916c896fe29Sbellard 3917d21369f5SRichard Henderson i_allocated_regs = s->reserved_regs; 3918d21369f5SRichard Henderson o_allocated_regs = s->reserved_regs; 391982790a87SRichard Henderson 3920c896fe29Sbellard /* satisfy input constraints */ 3921c896fe29Sbellard for (k = 0; k < nb_iargs; k++) { 392229f5e925SRichard Henderson TCGRegSet i_preferred_regs, i_required_regs; 392329f5e925SRichard Henderson bool allocate_new_reg, copyto_new_reg; 392429f5e925SRichard Henderson TCGTemp *ts2; 392529f5e925SRichard Henderson int i1, i2; 3926d62816f2SRichard Henderson 392766792f90SRichard Henderson i = def->args_ct[nb_oargs + k].sort_index; 3928dd186292SRichard Henderson arg = op->args[i]; 3929c896fe29Sbellard arg_ct = &def->args_ct[i]; 393043439139SRichard Henderson ts = arg_temp(arg); 393140ae5c62SRichard Henderson 393240ae5c62SRichard Henderson if (ts->val_type == TEMP_VAL_CONST 3933a4fbbd77SRichard Henderson && tcg_target_const_match(ts->val, ts->type, arg_ct->ct)) { 3934c896fe29Sbellard /* constant is OK for instruction */ 3935c896fe29Sbellard const_args[i] = 1; 3936c896fe29Sbellard new_args[i] = ts->val; 3937d62816f2SRichard Henderson continue; 3938c896fe29Sbellard } 393940ae5c62SRichard Henderson 39401c1824dcSRichard Henderson reg = ts->reg; 39411c1824dcSRichard Henderson i_preferred_regs = 0; 394229f5e925SRichard Henderson i_required_regs = arg_ct->regs; 39431c1824dcSRichard Henderson allocate_new_reg = false; 394429f5e925SRichard Henderson copyto_new_reg = false; 39451c1824dcSRichard Henderson 394629f5e925SRichard Henderson switch (arg_ct->pair) { 394729f5e925SRichard Henderson case 0: /* not paired */ 3948bc2b17e6SRichard Henderson if (arg_ct->ialias) { 394931fd884bSRichard Henderson i_preferred_regs = output_pref(op, arg_ct->alias_index); 3950c0522136SRichard Henderson 3951c0522136SRichard Henderson /* 3952c0522136SRichard Henderson * If the input is readonly, then it cannot also be an 3953c0522136SRichard Henderson * output and aliased to itself. If the input is not 3954c0522136SRichard Henderson * dead after the instruction, we must allocate a new 3955c0522136SRichard Henderson * register and move it. 3956c0522136SRichard Henderson */ 3957c0522136SRichard Henderson if (temp_readonly(ts) || !IS_DEAD_ARG(i)) { 39581c1824dcSRichard Henderson allocate_new_reg = true; 39591c1824dcSRichard Henderson } else if (ts->val_type == TEMP_VAL_REG) { 3960c0522136SRichard Henderson /* 39611c1824dcSRichard Henderson * Check if the current register has already been 39621c1824dcSRichard Henderson * allocated for another input. 3963c0522136SRichard Henderson */ 396429f5e925SRichard Henderson allocate_new_reg = 396529f5e925SRichard Henderson tcg_regset_test_reg(i_allocated_regs, reg); 39667e1df267SAurelien Jarno } 39677e1df267SAurelien Jarno } 39681c1824dcSRichard Henderson if (!allocate_new_reg) { 396929f5e925SRichard Henderson temp_load(s, ts, i_required_regs, i_allocated_regs, 397029f5e925SRichard Henderson i_preferred_regs); 3971c896fe29Sbellard reg = ts->reg; 397229f5e925SRichard Henderson allocate_new_reg = !tcg_regset_test_reg(i_required_regs, reg); 39731c1824dcSRichard Henderson } 39741c1824dcSRichard Henderson if (allocate_new_reg) { 3975c0522136SRichard Henderson /* 3976c0522136SRichard Henderson * Allocate a new register matching the constraint 3977c0522136SRichard Henderson * and move the temporary register into it. 3978c0522136SRichard Henderson */ 3979d62816f2SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 3980d62816f2SRichard Henderson i_allocated_regs, 0); 398129f5e925SRichard Henderson reg = tcg_reg_alloc(s, i_required_regs, i_allocated_regs, 39821c1824dcSRichard Henderson i_preferred_regs, ts->indirect_base); 398329f5e925SRichard Henderson copyto_new_reg = true; 398429f5e925SRichard Henderson } 398529f5e925SRichard Henderson break; 398629f5e925SRichard Henderson 398729f5e925SRichard Henderson case 1: 398829f5e925SRichard Henderson /* First of an input pair; if i1 == i2, the second is an output. */ 398929f5e925SRichard Henderson i1 = i; 399029f5e925SRichard Henderson i2 = arg_ct->pair_index; 399129f5e925SRichard Henderson ts2 = i1 != i2 ? arg_temp(op->args[i2]) : NULL; 399229f5e925SRichard Henderson 399329f5e925SRichard Henderson /* 399429f5e925SRichard Henderson * It is easier to default to allocating a new pair 399529f5e925SRichard Henderson * and to identify a few cases where it's not required. 399629f5e925SRichard Henderson */ 399729f5e925SRichard Henderson if (arg_ct->ialias) { 399831fd884bSRichard Henderson i_preferred_regs = output_pref(op, arg_ct->alias_index); 399929f5e925SRichard Henderson if (IS_DEAD_ARG(i1) && 400029f5e925SRichard Henderson IS_DEAD_ARG(i2) && 400129f5e925SRichard Henderson !temp_readonly(ts) && 400229f5e925SRichard Henderson ts->val_type == TEMP_VAL_REG && 400329f5e925SRichard Henderson ts->reg < TCG_TARGET_NB_REGS - 1 && 400429f5e925SRichard Henderson tcg_regset_test_reg(i_required_regs, reg) && 400529f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg) && 400629f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg + 1) && 400729f5e925SRichard Henderson (ts2 400829f5e925SRichard Henderson ? ts2->val_type == TEMP_VAL_REG && 400929f5e925SRichard Henderson ts2->reg == reg + 1 && 401029f5e925SRichard Henderson !temp_readonly(ts2) 401129f5e925SRichard Henderson : s->reg_to_temp[reg + 1] == NULL)) { 401229f5e925SRichard Henderson break; 401329f5e925SRichard Henderson } 401429f5e925SRichard Henderson } else { 401529f5e925SRichard Henderson /* Without aliasing, the pair must also be an input. */ 401629f5e925SRichard Henderson tcg_debug_assert(ts2); 401729f5e925SRichard Henderson if (ts->val_type == TEMP_VAL_REG && 401829f5e925SRichard Henderson ts2->val_type == TEMP_VAL_REG && 401929f5e925SRichard Henderson ts2->reg == reg + 1 && 402029f5e925SRichard Henderson tcg_regset_test_reg(i_required_regs, reg)) { 402129f5e925SRichard Henderson break; 402229f5e925SRichard Henderson } 402329f5e925SRichard Henderson } 402429f5e925SRichard Henderson reg = tcg_reg_alloc_pair(s, i_required_regs, i_allocated_regs, 402529f5e925SRichard Henderson 0, ts->indirect_base); 402629f5e925SRichard Henderson goto do_pair; 402729f5e925SRichard Henderson 402829f5e925SRichard Henderson case 2: /* pair second */ 402929f5e925SRichard Henderson reg = new_args[arg_ct->pair_index] + 1; 403029f5e925SRichard Henderson goto do_pair; 403129f5e925SRichard Henderson 403229f5e925SRichard Henderson case 3: /* ialias with second output, no first input */ 403329f5e925SRichard Henderson tcg_debug_assert(arg_ct->ialias); 403431fd884bSRichard Henderson i_preferred_regs = output_pref(op, arg_ct->alias_index); 403529f5e925SRichard Henderson 403629f5e925SRichard Henderson if (IS_DEAD_ARG(i) && 403729f5e925SRichard Henderson !temp_readonly(ts) && 403829f5e925SRichard Henderson ts->val_type == TEMP_VAL_REG && 403929f5e925SRichard Henderson reg > 0 && 404029f5e925SRichard Henderson s->reg_to_temp[reg - 1] == NULL && 404129f5e925SRichard Henderson tcg_regset_test_reg(i_required_regs, reg) && 404229f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg) && 404329f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg - 1)) { 404429f5e925SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg - 1); 404529f5e925SRichard Henderson break; 404629f5e925SRichard Henderson } 404729f5e925SRichard Henderson reg = tcg_reg_alloc_pair(s, i_required_regs >> 1, 404829f5e925SRichard Henderson i_allocated_regs, 0, 404929f5e925SRichard Henderson ts->indirect_base); 405029f5e925SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg); 405129f5e925SRichard Henderson reg += 1; 405229f5e925SRichard Henderson goto do_pair; 405329f5e925SRichard Henderson 405429f5e925SRichard Henderson do_pair: 405529f5e925SRichard Henderson /* 405629f5e925SRichard Henderson * If an aliased input is not dead after the instruction, 405729f5e925SRichard Henderson * we must allocate a new register and move it. 405829f5e925SRichard Henderson */ 405929f5e925SRichard Henderson if (arg_ct->ialias && (!IS_DEAD_ARG(i) || temp_readonly(ts))) { 406029f5e925SRichard Henderson TCGRegSet t_allocated_regs = i_allocated_regs; 406129f5e925SRichard Henderson 406229f5e925SRichard Henderson /* 406329f5e925SRichard Henderson * Because of the alias, and the continued life, make sure 406429f5e925SRichard Henderson * that the temp is somewhere *other* than the reg pair, 406529f5e925SRichard Henderson * and we get a copy in reg. 406629f5e925SRichard Henderson */ 406729f5e925SRichard Henderson tcg_regset_set_reg(t_allocated_regs, reg); 406829f5e925SRichard Henderson tcg_regset_set_reg(t_allocated_regs, reg + 1); 406929f5e925SRichard Henderson if (ts->val_type == TEMP_VAL_REG && ts->reg == reg) { 407029f5e925SRichard Henderson /* If ts was already in reg, copy it somewhere else. */ 407129f5e925SRichard Henderson TCGReg nr; 407229f5e925SRichard Henderson bool ok; 407329f5e925SRichard Henderson 407429f5e925SRichard Henderson tcg_debug_assert(ts->kind != TEMP_FIXED); 407529f5e925SRichard Henderson nr = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], 407629f5e925SRichard Henderson t_allocated_regs, 0, ts->indirect_base); 407729f5e925SRichard Henderson ok = tcg_out_mov(s, ts->type, nr, reg); 407829f5e925SRichard Henderson tcg_debug_assert(ok); 407929f5e925SRichard Henderson 408029f5e925SRichard Henderson set_temp_val_reg(s, ts, nr); 408129f5e925SRichard Henderson } else { 408229f5e925SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 408329f5e925SRichard Henderson t_allocated_regs, 0); 408429f5e925SRichard Henderson copyto_new_reg = true; 408529f5e925SRichard Henderson } 408629f5e925SRichard Henderson } else { 408729f5e925SRichard Henderson /* Preferably allocate to reg, otherwise copy. */ 408829f5e925SRichard Henderson i_required_regs = (TCGRegSet)1 << reg; 408929f5e925SRichard Henderson temp_load(s, ts, i_required_regs, i_allocated_regs, 409029f5e925SRichard Henderson i_preferred_regs); 409129f5e925SRichard Henderson copyto_new_reg = ts->reg != reg; 409229f5e925SRichard Henderson } 409329f5e925SRichard Henderson break; 409429f5e925SRichard Henderson 409529f5e925SRichard Henderson default: 409629f5e925SRichard Henderson g_assert_not_reached(); 409729f5e925SRichard Henderson } 409829f5e925SRichard Henderson 409929f5e925SRichard Henderson if (copyto_new_reg) { 410078113e83SRichard Henderson if (!tcg_out_mov(s, ts->type, reg, ts->reg)) { 4101240c08d0SRichard Henderson /* 4102240c08d0SRichard Henderson * Cross register class move not supported. Sync the 4103240c08d0SRichard Henderson * temp back to its slot and load from there. 4104240c08d0SRichard Henderson */ 4105240c08d0SRichard Henderson temp_sync(s, ts, i_allocated_regs, 0, 0); 4106240c08d0SRichard Henderson tcg_out_ld(s, ts->type, reg, 4107240c08d0SRichard Henderson ts->mem_base->reg, ts->mem_offset); 410878113e83SRichard Henderson } 4109c896fe29Sbellard } 4110c896fe29Sbellard new_args[i] = reg; 4111c896fe29Sbellard const_args[i] = 0; 411282790a87SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg); 4113c896fe29Sbellard } 4114c896fe29Sbellard 4115c896fe29Sbellard /* mark dead temporaries and free the associated registers */ 4116866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 4117866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) { 411843439139SRichard Henderson temp_dead(s, arg_temp(op->args[i])); 4119c896fe29Sbellard } 4120c896fe29Sbellard } 4121c896fe29Sbellard 4122b4cb76e6SRichard Henderson if (def->flags & TCG_OPF_COND_BRANCH) { 4123b4cb76e6SRichard Henderson tcg_reg_alloc_cbranch(s, i_allocated_regs); 4124b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 412582790a87SRichard Henderson tcg_reg_alloc_bb_end(s, i_allocated_regs); 4126a52ad07eSAurelien Jarno } else { 4127c896fe29Sbellard if (def->flags & TCG_OPF_CALL_CLOBBER) { 4128b03cce8eSbellard /* XXX: permit generic clobber register list ? */ 4129c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) { 4130c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { 413182790a87SRichard Henderson tcg_reg_free(s, i, i_allocated_regs); 4132c896fe29Sbellard } 4133c896fe29Sbellard } 41343d5c5f87SAurelien Jarno } 41353d5c5f87SAurelien Jarno if (def->flags & TCG_OPF_SIDE_EFFECTS) { 41363d5c5f87SAurelien Jarno /* sync globals if the op has side effects and might trigger 41373d5c5f87SAurelien Jarno an exception. */ 413882790a87SRichard Henderson sync_globals(s, i_allocated_regs); 4139c896fe29Sbellard } 4140c896fe29Sbellard 4141c896fe29Sbellard /* satisfy the output constraints */ 4142c896fe29Sbellard for(k = 0; k < nb_oargs; k++) { 414366792f90SRichard Henderson i = def->args_ct[k].sort_index; 4144dd186292SRichard Henderson arg = op->args[i]; 4145c896fe29Sbellard arg_ct = &def->args_ct[i]; 414643439139SRichard Henderson ts = arg_temp(arg); 4147d63e3b6eSRichard Henderson 4148d63e3b6eSRichard Henderson /* ENV should not be modified. */ 4149e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ts)); 4150d63e3b6eSRichard Henderson 415129f5e925SRichard Henderson switch (arg_ct->pair) { 415229f5e925SRichard Henderson case 0: /* not paired */ 4153bc2b17e6SRichard Henderson if (arg_ct->oalias && !const_args[arg_ct->alias_index]) { 41545ff9d6a4Sbellard reg = new_args[arg_ct->alias_index]; 4155bc2b17e6SRichard Henderson } else if (arg_ct->newreg) { 41569be0d080SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->regs, 415782790a87SRichard Henderson i_allocated_regs | o_allocated_regs, 415831fd884bSRichard Henderson output_pref(op, k), ts->indirect_base); 4159c896fe29Sbellard } else { 41609be0d080SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs, 416131fd884bSRichard Henderson output_pref(op, k), ts->indirect_base); 4162c896fe29Sbellard } 416329f5e925SRichard Henderson break; 416429f5e925SRichard Henderson 416529f5e925SRichard Henderson case 1: /* first of pair */ 416629f5e925SRichard Henderson tcg_debug_assert(!arg_ct->newreg); 416729f5e925SRichard Henderson if (arg_ct->oalias) { 416829f5e925SRichard Henderson reg = new_args[arg_ct->alias_index]; 416929f5e925SRichard Henderson break; 417029f5e925SRichard Henderson } 417129f5e925SRichard Henderson reg = tcg_reg_alloc_pair(s, arg_ct->regs, o_allocated_regs, 417231fd884bSRichard Henderson output_pref(op, k), ts->indirect_base); 417329f5e925SRichard Henderson break; 417429f5e925SRichard Henderson 417529f5e925SRichard Henderson case 2: /* second of pair */ 417629f5e925SRichard Henderson tcg_debug_assert(!arg_ct->newreg); 417729f5e925SRichard Henderson if (arg_ct->oalias) { 417829f5e925SRichard Henderson reg = new_args[arg_ct->alias_index]; 417929f5e925SRichard Henderson } else { 418029f5e925SRichard Henderson reg = new_args[arg_ct->pair_index] + 1; 418129f5e925SRichard Henderson } 418229f5e925SRichard Henderson break; 418329f5e925SRichard Henderson 418429f5e925SRichard Henderson case 3: /* first of pair, aliasing with a second input */ 418529f5e925SRichard Henderson tcg_debug_assert(!arg_ct->newreg); 418629f5e925SRichard Henderson reg = new_args[arg_ct->pair_index] - 1; 418729f5e925SRichard Henderson break; 418829f5e925SRichard Henderson 418929f5e925SRichard Henderson default: 419029f5e925SRichard Henderson g_assert_not_reached(); 419129f5e925SRichard Henderson } 419282790a87SRichard Henderson tcg_regset_set_reg(o_allocated_regs, reg); 4193098859f1SRichard Henderson set_temp_val_reg(s, ts, reg); 4194c896fe29Sbellard ts->mem_coherent = 0; 4195c896fe29Sbellard new_args[i] = reg; 4196c896fe29Sbellard } 4197e8996ee0Sbellard } 4198c896fe29Sbellard 4199c896fe29Sbellard /* emit instruction */ 4200d2fd745fSRichard Henderson if (def->flags & TCG_OPF_VECTOR) { 4201d2fd745fSRichard Henderson tcg_out_vec_op(s, op->opc, TCGOP_VECL(op), TCGOP_VECE(op), 4202d2fd745fSRichard Henderson new_args, const_args); 4203d2fd745fSRichard Henderson } else { 4204dd186292SRichard Henderson tcg_out_op(s, op->opc, new_args, const_args); 4205d2fd745fSRichard Henderson } 4206c896fe29Sbellard 4207c896fe29Sbellard /* move the outputs in the correct register if needed */ 4208c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 420943439139SRichard Henderson ts = arg_temp(op->args[i]); 4210d63e3b6eSRichard Henderson 4211d63e3b6eSRichard Henderson /* ENV should not be modified. */ 4212e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ts)); 4213d63e3b6eSRichard Henderson 4214ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) { 421598b4e186SRichard Henderson temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i)); 421659d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) { 4217f8bf00f1SRichard Henderson temp_dead(s, ts); 4218ec7a869dSAurelien Jarno } 4219c896fe29Sbellard } 4220c896fe29Sbellard } 4221c896fe29Sbellard 4222efe86b21SRichard Henderson static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op) 4223efe86b21SRichard Henderson { 4224efe86b21SRichard Henderson const TCGLifeData arg_life = op->life; 4225efe86b21SRichard Henderson TCGTemp *ots, *itsl, *itsh; 4226efe86b21SRichard Henderson TCGType vtype = TCGOP_VECL(op) + TCG_TYPE_V64; 4227efe86b21SRichard Henderson 4228efe86b21SRichard Henderson /* This opcode is only valid for 32-bit hosts, for 64-bit elements. */ 4229efe86b21SRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 32); 4230efe86b21SRichard Henderson tcg_debug_assert(TCGOP_VECE(op) == MO_64); 4231efe86b21SRichard Henderson 4232efe86b21SRichard Henderson ots = arg_temp(op->args[0]); 4233efe86b21SRichard Henderson itsl = arg_temp(op->args[1]); 4234efe86b21SRichard Henderson itsh = arg_temp(op->args[2]); 4235efe86b21SRichard Henderson 4236efe86b21SRichard Henderson /* ENV should not be modified. */ 4237efe86b21SRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 4238efe86b21SRichard Henderson 4239efe86b21SRichard Henderson /* Allocate the output register now. */ 4240efe86b21SRichard Henderson if (ots->val_type != TEMP_VAL_REG) { 4241efe86b21SRichard Henderson TCGRegSet allocated_regs = s->reserved_regs; 4242efe86b21SRichard Henderson TCGRegSet dup_out_regs = 4243efe86b21SRichard Henderson tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs; 4244098859f1SRichard Henderson TCGReg oreg; 4245efe86b21SRichard Henderson 4246efe86b21SRichard Henderson /* Make sure to not spill the input registers. */ 4247efe86b21SRichard Henderson if (!IS_DEAD_ARG(1) && itsl->val_type == TEMP_VAL_REG) { 4248efe86b21SRichard Henderson tcg_regset_set_reg(allocated_regs, itsl->reg); 4249efe86b21SRichard Henderson } 4250efe86b21SRichard Henderson if (!IS_DEAD_ARG(2) && itsh->val_type == TEMP_VAL_REG) { 4251efe86b21SRichard Henderson tcg_regset_set_reg(allocated_regs, itsh->reg); 4252efe86b21SRichard Henderson } 4253efe86b21SRichard Henderson 4254098859f1SRichard Henderson oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs, 425531fd884bSRichard Henderson output_pref(op, 0), ots->indirect_base); 4256098859f1SRichard Henderson set_temp_val_reg(s, ots, oreg); 4257efe86b21SRichard Henderson } 4258efe86b21SRichard Henderson 4259efe86b21SRichard Henderson /* Promote dup2 of immediates to dupi_vec. */ 4260efe86b21SRichard Henderson if (itsl->val_type == TEMP_VAL_CONST && itsh->val_type == TEMP_VAL_CONST) { 4261efe86b21SRichard Henderson uint64_t val = deposit64(itsl->val, 32, 32, itsh->val); 4262efe86b21SRichard Henderson MemOp vece = MO_64; 4263efe86b21SRichard Henderson 4264efe86b21SRichard Henderson if (val == dup_const(MO_8, val)) { 4265efe86b21SRichard Henderson vece = MO_8; 4266efe86b21SRichard Henderson } else if (val == dup_const(MO_16, val)) { 4267efe86b21SRichard Henderson vece = MO_16; 4268efe86b21SRichard Henderson } else if (val == dup_const(MO_32, val)) { 4269efe86b21SRichard Henderson vece = MO_32; 4270efe86b21SRichard Henderson } 4271efe86b21SRichard Henderson 4272efe86b21SRichard Henderson tcg_out_dupi_vec(s, vtype, vece, ots->reg, val); 4273efe86b21SRichard Henderson goto done; 4274efe86b21SRichard Henderson } 4275efe86b21SRichard Henderson 4276efe86b21SRichard Henderson /* If the two inputs form one 64-bit value, try dupm_vec. */ 4277aef85402SRichard Henderson if (itsl->temp_subindex == HOST_BIG_ENDIAN && 4278aef85402SRichard Henderson itsh->temp_subindex == !HOST_BIG_ENDIAN && 4279aef85402SRichard Henderson itsl == itsh + (HOST_BIG_ENDIAN ? 1 : -1)) { 4280aef85402SRichard Henderson TCGTemp *its = itsl - HOST_BIG_ENDIAN; 4281aef85402SRichard Henderson 4282aef85402SRichard Henderson temp_sync(s, its + 0, s->reserved_regs, 0, 0); 4283aef85402SRichard Henderson temp_sync(s, its + 1, s->reserved_regs, 0, 0); 4284aef85402SRichard Henderson 4285efe86b21SRichard Henderson if (tcg_out_dupm_vec(s, vtype, MO_64, ots->reg, 4286efe86b21SRichard Henderson its->mem_base->reg, its->mem_offset)) { 4287efe86b21SRichard Henderson goto done; 4288efe86b21SRichard Henderson } 4289efe86b21SRichard Henderson } 4290efe86b21SRichard Henderson 4291efe86b21SRichard Henderson /* Fall back to generic expansion. */ 4292efe86b21SRichard Henderson return false; 4293efe86b21SRichard Henderson 4294efe86b21SRichard Henderson done: 429536f5539cSRichard Henderson ots->mem_coherent = 0; 4296efe86b21SRichard Henderson if (IS_DEAD_ARG(1)) { 4297efe86b21SRichard Henderson temp_dead(s, itsl); 4298efe86b21SRichard Henderson } 4299efe86b21SRichard Henderson if (IS_DEAD_ARG(2)) { 4300efe86b21SRichard Henderson temp_dead(s, itsh); 4301efe86b21SRichard Henderson } 4302efe86b21SRichard Henderson if (NEED_SYNC_ARG(0)) { 4303efe86b21SRichard Henderson temp_sync(s, ots, s->reserved_regs, 0, IS_DEAD_ARG(0)); 4304efe86b21SRichard Henderson } else if (IS_DEAD_ARG(0)) { 4305efe86b21SRichard Henderson temp_dead(s, ots); 4306efe86b21SRichard Henderson } 4307efe86b21SRichard Henderson return true; 4308efe86b21SRichard Henderson } 4309efe86b21SRichard Henderson 431039004a71SRichard Henderson static void load_arg_reg(TCGContext *s, TCGReg reg, TCGTemp *ts, 431139004a71SRichard Henderson TCGRegSet allocated_regs) 4312c896fe29Sbellard { 4313c896fe29Sbellard if (ts->val_type == TEMP_VAL_REG) { 4314c896fe29Sbellard if (ts->reg != reg) { 43154250da10SRichard Henderson tcg_reg_free(s, reg, allocated_regs); 431678113e83SRichard Henderson if (!tcg_out_mov(s, ts->type, reg, ts->reg)) { 4317240c08d0SRichard Henderson /* 4318240c08d0SRichard Henderson * Cross register class move not supported. Sync the 4319240c08d0SRichard Henderson * temp back to its slot and load from there. 4320240c08d0SRichard Henderson */ 4321240c08d0SRichard Henderson temp_sync(s, ts, allocated_regs, 0, 0); 4322240c08d0SRichard Henderson tcg_out_ld(s, ts->type, reg, 4323240c08d0SRichard Henderson ts->mem_base->reg, ts->mem_offset); 432478113e83SRichard Henderson } 4325c896fe29Sbellard } 4326c896fe29Sbellard } else { 4327ccb1bb66SRichard Henderson TCGRegSet arg_set = 0; 432840ae5c62SRichard Henderson 43294250da10SRichard Henderson tcg_reg_free(s, reg, allocated_regs); 433040ae5c62SRichard Henderson tcg_regset_set_reg(arg_set, reg); 4331b722452aSRichard Henderson temp_load(s, ts, arg_set, allocated_regs, 0); 4332c896fe29Sbellard } 433339004a71SRichard Henderson } 433440ae5c62SRichard Henderson 433539004a71SRichard Henderson static void load_arg_stk(TCGContext *s, int stk_slot, TCGTemp *ts, 433639004a71SRichard Henderson TCGRegSet allocated_regs) 433739004a71SRichard Henderson { 433839004a71SRichard Henderson /* 433939004a71SRichard Henderson * When the destination is on the stack, load up the temp and store. 434039004a71SRichard Henderson * If there are many call-saved registers, the temp might live to 434139004a71SRichard Henderson * see another use; otherwise it'll be discarded. 434239004a71SRichard Henderson */ 434339004a71SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], allocated_regs, 0); 434439004a71SRichard Henderson tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, 434539004a71SRichard Henderson TCG_TARGET_CALL_STACK_OFFSET + 434639004a71SRichard Henderson stk_slot * sizeof(tcg_target_long)); 434739004a71SRichard Henderson } 434839004a71SRichard Henderson 434939004a71SRichard Henderson static void load_arg_normal(TCGContext *s, const TCGCallArgumentLoc *l, 435039004a71SRichard Henderson TCGTemp *ts, TCGRegSet *allocated_regs) 435139004a71SRichard Henderson { 435239004a71SRichard Henderson if (REG_P(l)) { 435339004a71SRichard Henderson TCGReg reg = tcg_target_call_iarg_regs[l->arg_slot]; 435439004a71SRichard Henderson load_arg_reg(s, reg, ts, *allocated_regs); 435539004a71SRichard Henderson tcg_regset_set_reg(*allocated_regs, reg); 435639004a71SRichard Henderson } else { 435739004a71SRichard Henderson load_arg_stk(s, l->arg_slot - ARRAY_SIZE(tcg_target_call_iarg_regs), 435839004a71SRichard Henderson ts, *allocated_regs); 4359c896fe29Sbellard } 436039cf05d3Sbellard } 4361c896fe29Sbellard 436239004a71SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op) 436339004a71SRichard Henderson { 436439004a71SRichard Henderson const int nb_oargs = TCGOP_CALLO(op); 436539004a71SRichard Henderson const int nb_iargs = TCGOP_CALLI(op); 436639004a71SRichard Henderson const TCGLifeData arg_life = op->life; 436739004a71SRichard Henderson const TCGHelperInfo *info = tcg_call_info(op); 436839004a71SRichard Henderson TCGRegSet allocated_regs = s->reserved_regs; 436939004a71SRichard Henderson int i; 437039004a71SRichard Henderson 437139004a71SRichard Henderson /* 437239004a71SRichard Henderson * Move inputs into place in reverse order, 437339004a71SRichard Henderson * so that we place stacked arguments first. 437439004a71SRichard Henderson */ 437539004a71SRichard Henderson for (i = nb_iargs - 1; i >= 0; --i) { 437639004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i]; 437739004a71SRichard Henderson TCGTemp *ts = arg_temp(op->args[nb_oargs + i]); 437839004a71SRichard Henderson 437939004a71SRichard Henderson switch (loc->kind) { 438039004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 438139004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 438239004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 438339004a71SRichard Henderson load_arg_normal(s, loc, ts, &allocated_regs); 438439004a71SRichard Henderson break; 438539004a71SRichard Henderson default: 438639004a71SRichard Henderson g_assert_not_reached(); 438739004a71SRichard Henderson } 438839004a71SRichard Henderson } 438939004a71SRichard Henderson 439039004a71SRichard Henderson /* Mark dead temporaries and free the associated registers. */ 4391866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 4392866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) { 439343439139SRichard Henderson temp_dead(s, arg_temp(op->args[i])); 4394c896fe29Sbellard } 4395c896fe29Sbellard } 4396c896fe29Sbellard 439739004a71SRichard Henderson /* Clobber call registers. */ 4398c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) { 4399c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { 4400b3915dbbSRichard Henderson tcg_reg_free(s, i, allocated_regs); 4401c896fe29Sbellard } 4402c896fe29Sbellard } 4403c896fe29Sbellard 440439004a71SRichard Henderson /* 440539004a71SRichard Henderson * Save globals if they might be written by the helper, 440639004a71SRichard Henderson * sync them if they might be read. 440739004a71SRichard Henderson */ 440839004a71SRichard Henderson if (info->flags & TCG_CALL_NO_READ_GLOBALS) { 440978505279SAurelien Jarno /* Nothing to do */ 441039004a71SRichard Henderson } else if (info->flags & TCG_CALL_NO_WRITE_GLOBALS) { 441178505279SAurelien Jarno sync_globals(s, allocated_regs); 441278505279SAurelien Jarno } else { 4413e8996ee0Sbellard save_globals(s, allocated_regs); 4414b9c18f56Saurel32 } 4415c896fe29Sbellard 4416cee44b03SRichard Henderson tcg_out_call(s, tcg_call_func(op), info); 4417c896fe29Sbellard 441839004a71SRichard Henderson /* Assign output registers and emit moves if needed. */ 441939004a71SRichard Henderson switch (info->out_kind) { 442039004a71SRichard Henderson case TCG_CALL_RET_NORMAL: 4421c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 442239004a71SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]); 442339004a71SRichard Henderson TCGReg reg = tcg_target_call_oarg_regs[i]; 4424d63e3b6eSRichard Henderson 4425d63e3b6eSRichard Henderson /* ENV should not be modified. */ 4426e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ts)); 4427d63e3b6eSRichard Henderson 4428098859f1SRichard Henderson set_temp_val_reg(s, ts, reg); 4429c896fe29Sbellard ts->mem_coherent = 0; 443039004a71SRichard Henderson } 443139004a71SRichard Henderson break; 443239004a71SRichard Henderson default: 443339004a71SRichard Henderson g_assert_not_reached(); 443439004a71SRichard Henderson } 443539004a71SRichard Henderson 443639004a71SRichard Henderson /* Flush or discard output registers as needed. */ 443739004a71SRichard Henderson for (i = 0; i < nb_oargs; i++) { 443839004a71SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]); 4439ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) { 444039004a71SRichard Henderson temp_sync(s, ts, s->reserved_regs, 0, IS_DEAD_ARG(i)); 444159d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) { 4442f8bf00f1SRichard Henderson temp_dead(s, ts); 4443c896fe29Sbellard } 4444c896fe29Sbellard } 44458c11ad25SAurelien Jarno } 4446c896fe29Sbellard 4447c896fe29Sbellard #ifdef CONFIG_PROFILER 4448c896fe29Sbellard 4449c3fac113SEmilio G. Cota /* avoid copy/paste errors */ 4450c3fac113SEmilio G. Cota #define PROF_ADD(to, from, field) \ 4451c3fac113SEmilio G. Cota do { \ 4452d73415a3SStefan Hajnoczi (to)->field += qatomic_read(&((from)->field)); \ 4453c3fac113SEmilio G. Cota } while (0) 4454c896fe29Sbellard 4455c3fac113SEmilio G. Cota #define PROF_MAX(to, from, field) \ 4456c3fac113SEmilio G. Cota do { \ 4457d73415a3SStefan Hajnoczi typeof((from)->field) val__ = qatomic_read(&((from)->field)); \ 4458c3fac113SEmilio G. Cota if (val__ > (to)->field) { \ 4459c3fac113SEmilio G. Cota (to)->field = val__; \ 4460c3fac113SEmilio G. Cota } \ 4461c3fac113SEmilio G. Cota } while (0) 4462c3fac113SEmilio G. Cota 4463c3fac113SEmilio G. Cota /* Pass in a zero'ed @prof */ 4464c3fac113SEmilio G. Cota static inline 4465c3fac113SEmilio G. Cota void tcg_profile_snapshot(TCGProfile *prof, bool counters, bool table) 4466c896fe29Sbellard { 44670e2d61cfSRichard Henderson unsigned int n_ctxs = qatomic_read(&tcg_cur_ctxs); 4468c3fac113SEmilio G. Cota unsigned int i; 4469c3fac113SEmilio G. Cota 44703468b59eSEmilio G. Cota for (i = 0; i < n_ctxs; i++) { 4471d73415a3SStefan Hajnoczi TCGContext *s = qatomic_read(&tcg_ctxs[i]); 44723468b59eSEmilio G. Cota const TCGProfile *orig = &s->prof; 4473c3fac113SEmilio G. Cota 4474c3fac113SEmilio G. Cota if (counters) { 447572fd2efbSEmilio G. Cota PROF_ADD(prof, orig, cpu_exec_time); 4476c3fac113SEmilio G. Cota PROF_ADD(prof, orig, tb_count1); 4477c3fac113SEmilio G. Cota PROF_ADD(prof, orig, tb_count); 4478c3fac113SEmilio G. Cota PROF_ADD(prof, orig, op_count); 4479c3fac113SEmilio G. Cota PROF_MAX(prof, orig, op_count_max); 4480c3fac113SEmilio G. Cota PROF_ADD(prof, orig, temp_count); 4481c3fac113SEmilio G. Cota PROF_MAX(prof, orig, temp_count_max); 4482c3fac113SEmilio G. Cota PROF_ADD(prof, orig, del_op_count); 4483c3fac113SEmilio G. Cota PROF_ADD(prof, orig, code_in_len); 4484c3fac113SEmilio G. Cota PROF_ADD(prof, orig, code_out_len); 4485c3fac113SEmilio G. Cota PROF_ADD(prof, orig, search_out_len); 4486c3fac113SEmilio G. Cota PROF_ADD(prof, orig, interm_time); 4487c3fac113SEmilio G. Cota PROF_ADD(prof, orig, code_time); 4488c3fac113SEmilio G. Cota PROF_ADD(prof, orig, la_time); 4489c3fac113SEmilio G. Cota PROF_ADD(prof, orig, opt_time); 4490c3fac113SEmilio G. Cota PROF_ADD(prof, orig, restore_count); 4491c3fac113SEmilio G. Cota PROF_ADD(prof, orig, restore_time); 4492c3fac113SEmilio G. Cota } 4493c3fac113SEmilio G. Cota if (table) { 4494c896fe29Sbellard int i; 4495d70724ceSzhanghailiang 449615fc7daaSRichard Henderson for (i = 0; i < NB_OPS; i++) { 4497c3fac113SEmilio G. Cota PROF_ADD(prof, orig, table_op_count[i]); 4498c3fac113SEmilio G. Cota } 4499c3fac113SEmilio G. Cota } 4500c3fac113SEmilio G. Cota } 4501c3fac113SEmilio G. Cota } 4502c3fac113SEmilio G. Cota 4503c3fac113SEmilio G. Cota #undef PROF_ADD 4504c3fac113SEmilio G. Cota #undef PROF_MAX 4505c3fac113SEmilio G. Cota 4506c3fac113SEmilio G. Cota static void tcg_profile_snapshot_counters(TCGProfile *prof) 4507c3fac113SEmilio G. Cota { 4508c3fac113SEmilio G. Cota tcg_profile_snapshot(prof, true, false); 4509c3fac113SEmilio G. Cota } 4510c3fac113SEmilio G. Cota 4511c3fac113SEmilio G. Cota static void tcg_profile_snapshot_table(TCGProfile *prof) 4512c3fac113SEmilio G. Cota { 4513c3fac113SEmilio G. Cota tcg_profile_snapshot(prof, false, true); 4514c3fac113SEmilio G. Cota } 4515c3fac113SEmilio G. Cota 4516b6a7f3e0SDaniel P. Berrangé void tcg_dump_op_count(GString *buf) 4517c3fac113SEmilio G. Cota { 4518c3fac113SEmilio G. Cota TCGProfile prof = {}; 4519c3fac113SEmilio G. Cota int i; 4520c3fac113SEmilio G. Cota 4521c3fac113SEmilio G. Cota tcg_profile_snapshot_table(&prof); 4522c3fac113SEmilio G. Cota for (i = 0; i < NB_OPS; i++) { 4523b6a7f3e0SDaniel P. Berrangé g_string_append_printf(buf, "%s %" PRId64 "\n", tcg_op_defs[i].name, 4524c3fac113SEmilio G. Cota prof.table_op_count[i]); 4525c896fe29Sbellard } 4526c896fe29Sbellard } 452772fd2efbSEmilio G. Cota 452872fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void) 452972fd2efbSEmilio G. Cota { 45300e2d61cfSRichard Henderson unsigned int n_ctxs = qatomic_read(&tcg_cur_ctxs); 453172fd2efbSEmilio G. Cota unsigned int i; 453272fd2efbSEmilio G. Cota int64_t ret = 0; 453372fd2efbSEmilio G. Cota 453472fd2efbSEmilio G. Cota for (i = 0; i < n_ctxs; i++) { 4535d73415a3SStefan Hajnoczi const TCGContext *s = qatomic_read(&tcg_ctxs[i]); 453672fd2efbSEmilio G. Cota const TCGProfile *prof = &s->prof; 453772fd2efbSEmilio G. Cota 4538d73415a3SStefan Hajnoczi ret += qatomic_read(&prof->cpu_exec_time); 453972fd2efbSEmilio G. Cota } 454072fd2efbSEmilio G. Cota return ret; 454172fd2efbSEmilio G. Cota } 4542246ae24dSMax Filippov #else 4543b6a7f3e0SDaniel P. Berrangé void tcg_dump_op_count(GString *buf) 4544246ae24dSMax Filippov { 4545b6a7f3e0SDaniel P. Berrangé g_string_append_printf(buf, "[TCG profiler not compiled]\n"); 4546246ae24dSMax Filippov } 454772fd2efbSEmilio G. Cota 454872fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void) 454972fd2efbSEmilio G. Cota { 455072fd2efbSEmilio G. Cota error_report("%s: TCG profiler not compiled", __func__); 455172fd2efbSEmilio G. Cota exit(EXIT_FAILURE); 455272fd2efbSEmilio G. Cota } 4553c896fe29Sbellard #endif 4554c896fe29Sbellard 4555c896fe29Sbellard 4556fbf59aadSRichard Henderson int tcg_gen_code(TCGContext *s, TranslationBlock *tb, target_ulong pc_start) 4557c896fe29Sbellard { 4558c3fac113SEmilio G. Cota #ifdef CONFIG_PROFILER 4559c3fac113SEmilio G. Cota TCGProfile *prof = &s->prof; 4560c3fac113SEmilio G. Cota #endif 456115fa08f8SRichard Henderson int i, num_insns; 456215fa08f8SRichard Henderson TCGOp *op; 4563c896fe29Sbellard 456404fe6400SRichard Henderson #ifdef CONFIG_PROFILER 456504fe6400SRichard Henderson { 4566c1f543b7SEmilio G. Cota int n = 0; 456704fe6400SRichard Henderson 456815fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 456915fa08f8SRichard Henderson n++; 457015fa08f8SRichard Henderson } 4571d73415a3SStefan Hajnoczi qatomic_set(&prof->op_count, prof->op_count + n); 4572c3fac113SEmilio G. Cota if (n > prof->op_count_max) { 4573d73415a3SStefan Hajnoczi qatomic_set(&prof->op_count_max, n); 457404fe6400SRichard Henderson } 457504fe6400SRichard Henderson 457604fe6400SRichard Henderson n = s->nb_temps; 4577d73415a3SStefan Hajnoczi qatomic_set(&prof->temp_count, prof->temp_count + n); 4578c3fac113SEmilio G. Cota if (n > prof->temp_count_max) { 4579d73415a3SStefan Hajnoczi qatomic_set(&prof->temp_count_max, n); 458004fe6400SRichard Henderson } 458104fe6400SRichard Henderson } 458204fe6400SRichard Henderson #endif 458304fe6400SRichard Henderson 4584c896fe29Sbellard #ifdef DEBUG_DISAS 4585d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP) 4586fbf59aadSRichard Henderson && qemu_log_in_addr_range(pc_start))) { 4587c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock(); 458878b54858SRichard Henderson if (logfile) { 458978b54858SRichard Henderson fprintf(logfile, "OP:\n"); 4590b7a83ff8SRichard Henderson tcg_dump_ops(s, logfile, false); 459178b54858SRichard Henderson fprintf(logfile, "\n"); 4592fc59d2d8SRobert Foley qemu_log_unlock(logfile); 4593c896fe29Sbellard } 459478b54858SRichard Henderson } 4595c896fe29Sbellard #endif 4596c896fe29Sbellard 4597bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG 4598bef16ab4SRichard Henderson /* Ensure all labels referenced have been emitted. */ 4599bef16ab4SRichard Henderson { 4600bef16ab4SRichard Henderson TCGLabel *l; 4601bef16ab4SRichard Henderson bool error = false; 4602bef16ab4SRichard Henderson 4603bef16ab4SRichard Henderson QSIMPLEQ_FOREACH(l, &s->labels, next) { 4604bef16ab4SRichard Henderson if (unlikely(!l->present) && l->refs) { 4605bef16ab4SRichard Henderson qemu_log_mask(CPU_LOG_TB_OP, 4606bef16ab4SRichard Henderson "$L%d referenced but not present.\n", l->id); 4607bef16ab4SRichard Henderson error = true; 4608bef16ab4SRichard Henderson } 4609bef16ab4SRichard Henderson } 4610bef16ab4SRichard Henderson assert(!error); 4611bef16ab4SRichard Henderson } 4612bef16ab4SRichard Henderson #endif 4613bef16ab4SRichard Henderson 4614c5cc28ffSAurelien Jarno #ifdef CONFIG_PROFILER 4615d73415a3SStefan Hajnoczi qatomic_set(&prof->opt_time, prof->opt_time - profile_getclock()); 4616c5cc28ffSAurelien Jarno #endif 4617c5cc28ffSAurelien Jarno 46188f2e8c07SKirill Batuzov #ifdef USE_TCG_OPTIMIZATIONS 4619c45cb8bbSRichard Henderson tcg_optimize(s); 46208f2e8c07SKirill Batuzov #endif 46218f2e8c07SKirill Batuzov 4622a23a9ec6Sbellard #ifdef CONFIG_PROFILER 4623d73415a3SStefan Hajnoczi qatomic_set(&prof->opt_time, prof->opt_time + profile_getclock()); 4624d73415a3SStefan Hajnoczi qatomic_set(&prof->la_time, prof->la_time - profile_getclock()); 4625a23a9ec6Sbellard #endif 4626c5cc28ffSAurelien Jarno 4627b4fc67c7SRichard Henderson reachable_code_pass(s); 4628b83eabeaSRichard Henderson liveness_pass_1(s); 46295a18407fSRichard Henderson 46305a18407fSRichard Henderson if (s->nb_indirects > 0) { 46315a18407fSRichard Henderson #ifdef DEBUG_DISAS 46325a18407fSRichard Henderson if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND) 4633fbf59aadSRichard Henderson && qemu_log_in_addr_range(pc_start))) { 4634c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock(); 463578b54858SRichard Henderson if (logfile) { 463678b54858SRichard Henderson fprintf(logfile, "OP before indirect lowering:\n"); 4637b7a83ff8SRichard Henderson tcg_dump_ops(s, logfile, false); 463878b54858SRichard Henderson fprintf(logfile, "\n"); 4639fc59d2d8SRobert Foley qemu_log_unlock(logfile); 46405a18407fSRichard Henderson } 464178b54858SRichard Henderson } 46425a18407fSRichard Henderson #endif 46435a18407fSRichard Henderson /* Replace indirect temps with direct temps. */ 4644b83eabeaSRichard Henderson if (liveness_pass_2(s)) { 46455a18407fSRichard Henderson /* If changes were made, re-run liveness. */ 4646b83eabeaSRichard Henderson liveness_pass_1(s); 46475a18407fSRichard Henderson } 46485a18407fSRichard Henderson } 4649c5cc28ffSAurelien Jarno 4650a23a9ec6Sbellard #ifdef CONFIG_PROFILER 4651d73415a3SStefan Hajnoczi qatomic_set(&prof->la_time, prof->la_time + profile_getclock()); 4652a23a9ec6Sbellard #endif 4653c896fe29Sbellard 4654c896fe29Sbellard #ifdef DEBUG_DISAS 4655d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT) 4656fbf59aadSRichard Henderson && qemu_log_in_addr_range(pc_start))) { 4657c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock(); 465878b54858SRichard Henderson if (logfile) { 465978b54858SRichard Henderson fprintf(logfile, "OP after optimization and liveness analysis:\n"); 4660b7a83ff8SRichard Henderson tcg_dump_ops(s, logfile, true); 466178b54858SRichard Henderson fprintf(logfile, "\n"); 4662fc59d2d8SRobert Foley qemu_log_unlock(logfile); 4663c896fe29Sbellard } 466478b54858SRichard Henderson } 4665c896fe29Sbellard #endif 4666c896fe29Sbellard 466735abb009SRichard Henderson /* Initialize goto_tb jump offsets. */ 466835abb009SRichard Henderson tb->jmp_reset_offset[0] = TB_JMP_RESET_OFFSET_INVALID; 466935abb009SRichard Henderson tb->jmp_reset_offset[1] = TB_JMP_RESET_OFFSET_INVALID; 467035abb009SRichard Henderson tcg_ctx->tb_jmp_reset_offset = tb->jmp_reset_offset; 467135abb009SRichard Henderson if (TCG_TARGET_HAS_direct_jump) { 467235abb009SRichard Henderson tcg_ctx->tb_jmp_insn_offset = tb->jmp_target_arg; 467335abb009SRichard Henderson tcg_ctx->tb_jmp_target_addr = NULL; 467435abb009SRichard Henderson } else { 467535abb009SRichard Henderson tcg_ctx->tb_jmp_insn_offset = NULL; 467635abb009SRichard Henderson tcg_ctx->tb_jmp_target_addr = tb->jmp_target_arg; 467735abb009SRichard Henderson } 467835abb009SRichard Henderson 4679c896fe29Sbellard tcg_reg_alloc_start(s); 4680c896fe29Sbellard 4681db0c51a3SRichard Henderson /* 4682db0c51a3SRichard Henderson * Reset the buffer pointers when restarting after overflow. 4683db0c51a3SRichard Henderson * TODO: Move this into translate-all.c with the rest of the 4684db0c51a3SRichard Henderson * buffer management. Having only this done here is confusing. 4685db0c51a3SRichard Henderson */ 4686db0c51a3SRichard Henderson s->code_buf = tcg_splitwx_to_rw(tb->tc.ptr); 4687db0c51a3SRichard Henderson s->code_ptr = s->code_buf; 4688c896fe29Sbellard 4689659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS 46906001f772SLaurent Vivier QSIMPLEQ_INIT(&s->ldst_labels); 4691659ef5cbSRichard Henderson #endif 469257a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 469357a26946SRichard Henderson s->pool_labels = NULL; 469457a26946SRichard Henderson #endif 46959ecefc84SRichard Henderson 4696fca8a500SRichard Henderson num_insns = -1; 469715fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 4698c45cb8bbSRichard Henderson TCGOpcode opc = op->opc; 4699b3db8758Sblueswir1 4700c896fe29Sbellard #ifdef CONFIG_PROFILER 4701d73415a3SStefan Hajnoczi qatomic_set(&prof->table_op_count[opc], prof->table_op_count[opc] + 1); 4702c896fe29Sbellard #endif 4703c45cb8bbSRichard Henderson 4704c896fe29Sbellard switch (opc) { 4705c896fe29Sbellard case INDEX_op_mov_i32: 4706c896fe29Sbellard case INDEX_op_mov_i64: 4707d2fd745fSRichard Henderson case INDEX_op_mov_vec: 4708dd186292SRichard Henderson tcg_reg_alloc_mov(s, op); 4709c896fe29Sbellard break; 4710bab1671fSRichard Henderson case INDEX_op_dup_vec: 4711bab1671fSRichard Henderson tcg_reg_alloc_dup(s, op); 4712bab1671fSRichard Henderson break; 4713765b842aSRichard Henderson case INDEX_op_insn_start: 4714fca8a500SRichard Henderson if (num_insns >= 0) { 47159f754620SRichard Henderson size_t off = tcg_current_code_size(s); 47169f754620SRichard Henderson s->gen_insn_end_off[num_insns] = off; 47179f754620SRichard Henderson /* Assert that we do not overflow our stored offset. */ 47189f754620SRichard Henderson assert(s->gen_insn_end_off[num_insns] == off); 4719fca8a500SRichard Henderson } 4720fca8a500SRichard Henderson num_insns++; 4721bad729e2SRichard Henderson for (i = 0; i < TARGET_INSN_START_WORDS; ++i) { 4722bad729e2SRichard Henderson target_ulong a; 4723bad729e2SRichard Henderson #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS 4724efee3746SRichard Henderson a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]); 4725bad729e2SRichard Henderson #else 4726efee3746SRichard Henderson a = op->args[i]; 4727bad729e2SRichard Henderson #endif 4728fca8a500SRichard Henderson s->gen_insn_data[num_insns][i] = a; 4729bad729e2SRichard Henderson } 4730c896fe29Sbellard break; 47315ff9d6a4Sbellard case INDEX_op_discard: 473243439139SRichard Henderson temp_dead(s, arg_temp(op->args[0])); 47335ff9d6a4Sbellard break; 4734c896fe29Sbellard case INDEX_op_set_label: 4735e8996ee0Sbellard tcg_reg_alloc_bb_end(s, s->reserved_regs); 473692ab8e7dSRichard Henderson tcg_out_label(s, arg_label(op->args[0])); 4737c896fe29Sbellard break; 4738c896fe29Sbellard case INDEX_op_call: 4739dd186292SRichard Henderson tcg_reg_alloc_call(s, op); 4740c45cb8bbSRichard Henderson break; 4741b55a8d9dSRichard Henderson case INDEX_op_exit_tb: 4742b55a8d9dSRichard Henderson tcg_out_exit_tb(s, op->args[0]); 4743b55a8d9dSRichard Henderson break; 4744efe86b21SRichard Henderson case INDEX_op_dup2_vec: 4745efe86b21SRichard Henderson if (tcg_reg_alloc_dup2(s, op)) { 4746efe86b21SRichard Henderson break; 4747efe86b21SRichard Henderson } 4748efe86b21SRichard Henderson /* fall through */ 4749c896fe29Sbellard default: 475025c4d9ccSRichard Henderson /* Sanity check that we've not introduced any unhandled opcodes. */ 4751be0f34b5SRichard Henderson tcg_debug_assert(tcg_op_supported(opc)); 4752c896fe29Sbellard /* Note: in order to speed up the code, it would be much 4753c896fe29Sbellard faster to have specialized register allocator functions for 4754c896fe29Sbellard some common argument patterns */ 4755dd186292SRichard Henderson tcg_reg_alloc_op(s, op); 4756c896fe29Sbellard break; 4757c896fe29Sbellard } 4758b125f9dcSRichard Henderson /* Test for (pending) buffer overflow. The assumption is that any 4759b125f9dcSRichard Henderson one operation beginning below the high water mark cannot overrun 4760b125f9dcSRichard Henderson the buffer completely. Thus we can test for overflow after 4761b125f9dcSRichard Henderson generating code without having to check during generation. */ 4762644da9b3SJohn Clarke if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) { 4763b125f9dcSRichard Henderson return -1; 4764b125f9dcSRichard Henderson } 47656e6c4efeSRichard Henderson /* Test for TB overflow, as seen by gen_insn_end_off. */ 47666e6c4efeSRichard Henderson if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) { 47676e6c4efeSRichard Henderson return -2; 47686e6c4efeSRichard Henderson } 4769c896fe29Sbellard } 4770fca8a500SRichard Henderson tcg_debug_assert(num_insns >= 0); 4771fca8a500SRichard Henderson s->gen_insn_end_off[num_insns] = tcg_current_code_size(s); 4772c45cb8bbSRichard Henderson 4773b76f0d8cSYeongkyoon Lee /* Generate TB finalization at the end of block */ 4774659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS 4775aeee05f5SRichard Henderson i = tcg_out_ldst_finalize(s); 4776aeee05f5SRichard Henderson if (i < 0) { 4777aeee05f5SRichard Henderson return i; 477823dceda6SRichard Henderson } 4779659ef5cbSRichard Henderson #endif 478057a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 47811768987bSRichard Henderson i = tcg_out_pool_finalize(s); 47821768987bSRichard Henderson if (i < 0) { 47831768987bSRichard Henderson return i; 478457a26946SRichard Henderson } 478557a26946SRichard Henderson #endif 47867ecd02a0SRichard Henderson if (!tcg_resolve_relocs(s)) { 47877ecd02a0SRichard Henderson return -2; 47887ecd02a0SRichard Henderson } 4789c896fe29Sbellard 4790df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 4791c896fe29Sbellard /* flush instruction cache */ 4792db0c51a3SRichard Henderson flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf), 4793db0c51a3SRichard Henderson (uintptr_t)s->code_buf, 47941da8de39SRichard Henderson tcg_ptr_byte_diff(s->code_ptr, s->code_buf)); 4795df5d2b16SRichard Henderson #endif 47962aeabc08SStefan Weil 47971813e175SRichard Henderson return tcg_current_code_size(s); 4798c896fe29Sbellard } 4799c896fe29Sbellard 4800a23a9ec6Sbellard #ifdef CONFIG_PROFILER 48013a841ab5SDaniel P. Berrangé void tcg_dump_info(GString *buf) 4802a23a9ec6Sbellard { 4803c3fac113SEmilio G. Cota TCGProfile prof = {}; 4804c3fac113SEmilio G. Cota const TCGProfile *s; 4805c3fac113SEmilio G. Cota int64_t tb_count; 4806c3fac113SEmilio G. Cota int64_t tb_div_count; 4807c3fac113SEmilio G. Cota int64_t tot; 4808c3fac113SEmilio G. Cota 4809c3fac113SEmilio G. Cota tcg_profile_snapshot_counters(&prof); 4810c3fac113SEmilio G. Cota s = &prof; 4811c3fac113SEmilio G. Cota tb_count = s->tb_count; 4812c3fac113SEmilio G. Cota tb_div_count = tb_count ? tb_count : 1; 4813c3fac113SEmilio G. Cota tot = s->interm_time + s->code_time; 4814a23a9ec6Sbellard 48153a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "JIT cycles %" PRId64 48163a841ab5SDaniel P. Berrangé " (%0.3f s at 2.4 GHz)\n", 4817a23a9ec6Sbellard tot, tot / 2.4e9); 48183a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "translated TBs %" PRId64 48193a841ab5SDaniel P. Berrangé " (aborted=%" PRId64 " %0.1f%%)\n", 4820fca8a500SRichard Henderson tb_count, s->tb_count1 - tb_count, 4821fca8a500SRichard Henderson (double)(s->tb_count1 - s->tb_count) 4822fca8a500SRichard Henderson / (s->tb_count1 ? s->tb_count1 : 1) * 100.0); 48233a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "avg ops/TB %0.1f max=%d\n", 4824fca8a500SRichard Henderson (double)s->op_count / tb_div_count, s->op_count_max); 48253a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "deleted ops/TB %0.2f\n", 4826fca8a500SRichard Henderson (double)s->del_op_count / tb_div_count); 48273a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "avg temps/TB %0.2f max=%d\n", 48283a841ab5SDaniel P. Berrangé (double)s->temp_count / tb_div_count, 48293a841ab5SDaniel P. Berrangé s->temp_count_max); 48303a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "avg host code/TB %0.1f\n", 4831fca8a500SRichard Henderson (double)s->code_out_len / tb_div_count); 48323a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "avg search data/TB %0.1f\n", 4833fca8a500SRichard Henderson (double)s->search_out_len / tb_div_count); 4834a23a9ec6Sbellard 48353a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "cycles/op %0.1f\n", 4836a23a9ec6Sbellard s->op_count ? (double)tot / s->op_count : 0); 48373a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "cycles/in byte %0.1f\n", 4838a23a9ec6Sbellard s->code_in_len ? (double)tot / s->code_in_len : 0); 48393a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "cycles/out byte %0.1f\n", 4840a23a9ec6Sbellard s->code_out_len ? (double)tot / s->code_out_len : 0); 48413a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "cycles/search byte %0.1f\n", 48423a841ab5SDaniel P. Berrangé s->search_out_len ? 48433a841ab5SDaniel P. Berrangé (double)tot / s->search_out_len : 0); 4844fca8a500SRichard Henderson if (tot == 0) { 4845a23a9ec6Sbellard tot = 1; 4846fca8a500SRichard Henderson } 48473a841ab5SDaniel P. Berrangé g_string_append_printf(buf, " gen_interm time %0.1f%%\n", 4848a23a9ec6Sbellard (double)s->interm_time / tot * 100.0); 48493a841ab5SDaniel P. Berrangé g_string_append_printf(buf, " gen_code time %0.1f%%\n", 4850a23a9ec6Sbellard (double)s->code_time / tot * 100.0); 48513a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "optim./code time %0.1f%%\n", 48523a841ab5SDaniel P. Berrangé (double)s->opt_time / (s->code_time ? 48533a841ab5SDaniel P. Berrangé s->code_time : 1) 4854c5cc28ffSAurelien Jarno * 100.0); 48553a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "liveness/code time %0.1f%%\n", 48563a841ab5SDaniel P. Berrangé (double)s->la_time / (s->code_time ? 48573a841ab5SDaniel P. Berrangé s->code_time : 1) * 100.0); 48583a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "cpu_restore count %" PRId64 "\n", 4859a23a9ec6Sbellard s->restore_count); 48603a841ab5SDaniel P. Berrangé g_string_append_printf(buf, " avg cycles %0.1f\n", 48613a841ab5SDaniel P. Berrangé s->restore_count ? 48623a841ab5SDaniel P. Berrangé (double)s->restore_time / s->restore_count : 0); 4863a23a9ec6Sbellard } 4864a23a9ec6Sbellard #else 48653a841ab5SDaniel P. Berrangé void tcg_dump_info(GString *buf) 4866a23a9ec6Sbellard { 48673a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "[TCG profiler not compiled]\n"); 4868a23a9ec6Sbellard } 4869a23a9ec6Sbellard #endif 4870813da627SRichard Henderson 4871813da627SRichard Henderson #ifdef ELF_HOST_MACHINE 48725872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things: 48735872bbf2SRichard Henderson 48745872bbf2SRichard Henderson (1) Define ELF_HOST_MACHINE to indicate both what value to 48755872bbf2SRichard Henderson put into the ELF image and to indicate support for the feature. 48765872bbf2SRichard Henderson 48775872bbf2SRichard Henderson (2) Define tcg_register_jit. This should create a buffer containing 48785872bbf2SRichard Henderson the contents of a .debug_frame section that describes the post- 48795872bbf2SRichard Henderson prologue unwind info for the tcg machine. 48805872bbf2SRichard Henderson 48815872bbf2SRichard Henderson (3) Call tcg_register_jit_int, with the constructed .debug_frame. 48825872bbf2SRichard Henderson */ 4883813da627SRichard Henderson 4884813da627SRichard Henderson /* Begin GDB interface. THE FOLLOWING MUST MATCH GDB DOCS. */ 4885813da627SRichard Henderson typedef enum { 4886813da627SRichard Henderson JIT_NOACTION = 0, 4887813da627SRichard Henderson JIT_REGISTER_FN, 4888813da627SRichard Henderson JIT_UNREGISTER_FN 4889813da627SRichard Henderson } jit_actions_t; 4890813da627SRichard Henderson 4891813da627SRichard Henderson struct jit_code_entry { 4892813da627SRichard Henderson struct jit_code_entry *next_entry; 4893813da627SRichard Henderson struct jit_code_entry *prev_entry; 4894813da627SRichard Henderson const void *symfile_addr; 4895813da627SRichard Henderson uint64_t symfile_size; 4896813da627SRichard Henderson }; 4897813da627SRichard Henderson 4898813da627SRichard Henderson struct jit_descriptor { 4899813da627SRichard Henderson uint32_t version; 4900813da627SRichard Henderson uint32_t action_flag; 4901813da627SRichard Henderson struct jit_code_entry *relevant_entry; 4902813da627SRichard Henderson struct jit_code_entry *first_entry; 4903813da627SRichard Henderson }; 4904813da627SRichard Henderson 4905813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline)); 4906813da627SRichard Henderson void __jit_debug_register_code(void) 4907813da627SRichard Henderson { 4908813da627SRichard Henderson asm(""); 4909813da627SRichard Henderson } 4910813da627SRichard Henderson 4911813da627SRichard Henderson /* Must statically initialize the version, because GDB may check 4912813da627SRichard Henderson the version before we can set it. */ 4913813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 }; 4914813da627SRichard Henderson 4915813da627SRichard Henderson /* End GDB interface. */ 4916813da627SRichard Henderson 4917813da627SRichard Henderson static int find_string(const char *strtab, const char *str) 4918813da627SRichard Henderson { 4919813da627SRichard Henderson const char *p = strtab + 1; 4920813da627SRichard Henderson 4921813da627SRichard Henderson while (1) { 4922813da627SRichard Henderson if (strcmp(p, str) == 0) { 4923813da627SRichard Henderson return p - strtab; 4924813da627SRichard Henderson } 4925813da627SRichard Henderson p += strlen(p) + 1; 4926813da627SRichard Henderson } 4927813da627SRichard Henderson } 4928813da627SRichard Henderson 4929755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf_ptr, size_t buf_size, 49302c90784aSRichard Henderson const void *debug_frame, 49312c90784aSRichard Henderson size_t debug_frame_size) 4932813da627SRichard Henderson { 49335872bbf2SRichard Henderson struct __attribute__((packed)) DebugInfo { 49345872bbf2SRichard Henderson uint32_t len; 49355872bbf2SRichard Henderson uint16_t version; 49365872bbf2SRichard Henderson uint32_t abbrev; 49375872bbf2SRichard Henderson uint8_t ptr_size; 49385872bbf2SRichard Henderson uint8_t cu_die; 49395872bbf2SRichard Henderson uint16_t cu_lang; 49405872bbf2SRichard Henderson uintptr_t cu_low_pc; 49415872bbf2SRichard Henderson uintptr_t cu_high_pc; 49425872bbf2SRichard Henderson uint8_t fn_die; 49435872bbf2SRichard Henderson char fn_name[16]; 49445872bbf2SRichard Henderson uintptr_t fn_low_pc; 49455872bbf2SRichard Henderson uintptr_t fn_high_pc; 49465872bbf2SRichard Henderson uint8_t cu_eoc; 49475872bbf2SRichard Henderson }; 4948813da627SRichard Henderson 4949813da627SRichard Henderson struct ElfImage { 4950813da627SRichard Henderson ElfW(Ehdr) ehdr; 4951813da627SRichard Henderson ElfW(Phdr) phdr; 49525872bbf2SRichard Henderson ElfW(Shdr) shdr[7]; 49535872bbf2SRichard Henderson ElfW(Sym) sym[2]; 49545872bbf2SRichard Henderson struct DebugInfo di; 49555872bbf2SRichard Henderson uint8_t da[24]; 49565872bbf2SRichard Henderson char str[80]; 49575872bbf2SRichard Henderson }; 49585872bbf2SRichard Henderson 49595872bbf2SRichard Henderson struct ElfImage *img; 49605872bbf2SRichard Henderson 49615872bbf2SRichard Henderson static const struct ElfImage img_template = { 49625872bbf2SRichard Henderson .ehdr = { 49635872bbf2SRichard Henderson .e_ident[EI_MAG0] = ELFMAG0, 49645872bbf2SRichard Henderson .e_ident[EI_MAG1] = ELFMAG1, 49655872bbf2SRichard Henderson .e_ident[EI_MAG2] = ELFMAG2, 49665872bbf2SRichard Henderson .e_ident[EI_MAG3] = ELFMAG3, 49675872bbf2SRichard Henderson .e_ident[EI_CLASS] = ELF_CLASS, 49685872bbf2SRichard Henderson .e_ident[EI_DATA] = ELF_DATA, 49695872bbf2SRichard Henderson .e_ident[EI_VERSION] = EV_CURRENT, 49705872bbf2SRichard Henderson .e_type = ET_EXEC, 49715872bbf2SRichard Henderson .e_machine = ELF_HOST_MACHINE, 49725872bbf2SRichard Henderson .e_version = EV_CURRENT, 49735872bbf2SRichard Henderson .e_phoff = offsetof(struct ElfImage, phdr), 49745872bbf2SRichard Henderson .e_shoff = offsetof(struct ElfImage, shdr), 49755872bbf2SRichard Henderson .e_ehsize = sizeof(ElfW(Shdr)), 49765872bbf2SRichard Henderson .e_phentsize = sizeof(ElfW(Phdr)), 49775872bbf2SRichard Henderson .e_phnum = 1, 49785872bbf2SRichard Henderson .e_shentsize = sizeof(ElfW(Shdr)), 49795872bbf2SRichard Henderson .e_shnum = ARRAY_SIZE(img->shdr), 49805872bbf2SRichard Henderson .e_shstrndx = ARRAY_SIZE(img->shdr) - 1, 4981abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS 4982abbb3eaeSRichard Henderson .e_flags = ELF_HOST_FLAGS, 4983abbb3eaeSRichard Henderson #endif 4984abbb3eaeSRichard Henderson #ifdef ELF_OSABI 4985abbb3eaeSRichard Henderson .e_ident[EI_OSABI] = ELF_OSABI, 4986abbb3eaeSRichard Henderson #endif 49875872bbf2SRichard Henderson }, 49885872bbf2SRichard Henderson .phdr = { 49895872bbf2SRichard Henderson .p_type = PT_LOAD, 49905872bbf2SRichard Henderson .p_flags = PF_X, 49915872bbf2SRichard Henderson }, 49925872bbf2SRichard Henderson .shdr = { 49935872bbf2SRichard Henderson [0] = { .sh_type = SHT_NULL }, 49945872bbf2SRichard Henderson /* Trick: The contents of code_gen_buffer are not present in 49955872bbf2SRichard Henderson this fake ELF file; that got allocated elsewhere. Therefore 49965872bbf2SRichard Henderson we mark .text as SHT_NOBITS (similar to .bss) so that readers 49975872bbf2SRichard Henderson will not look for contents. We can record any address. */ 49985872bbf2SRichard Henderson [1] = { /* .text */ 49995872bbf2SRichard Henderson .sh_type = SHT_NOBITS, 50005872bbf2SRichard Henderson .sh_flags = SHF_EXECINSTR | SHF_ALLOC, 50015872bbf2SRichard Henderson }, 50025872bbf2SRichard Henderson [2] = { /* .debug_info */ 50035872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 50045872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, di), 50055872bbf2SRichard Henderson .sh_size = sizeof(struct DebugInfo), 50065872bbf2SRichard Henderson }, 50075872bbf2SRichard Henderson [3] = { /* .debug_abbrev */ 50085872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 50095872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, da), 50105872bbf2SRichard Henderson .sh_size = sizeof(img->da), 50115872bbf2SRichard Henderson }, 50125872bbf2SRichard Henderson [4] = { /* .debug_frame */ 50135872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 50145872bbf2SRichard Henderson .sh_offset = sizeof(struct ElfImage), 50155872bbf2SRichard Henderson }, 50165872bbf2SRichard Henderson [5] = { /* .symtab */ 50175872bbf2SRichard Henderson .sh_type = SHT_SYMTAB, 50185872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, sym), 50195872bbf2SRichard Henderson .sh_size = sizeof(img->sym), 50205872bbf2SRichard Henderson .sh_info = 1, 50215872bbf2SRichard Henderson .sh_link = ARRAY_SIZE(img->shdr) - 1, 50225872bbf2SRichard Henderson .sh_entsize = sizeof(ElfW(Sym)), 50235872bbf2SRichard Henderson }, 50245872bbf2SRichard Henderson [6] = { /* .strtab */ 50255872bbf2SRichard Henderson .sh_type = SHT_STRTAB, 50265872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, str), 50275872bbf2SRichard Henderson .sh_size = sizeof(img->str), 50285872bbf2SRichard Henderson } 50295872bbf2SRichard Henderson }, 50305872bbf2SRichard Henderson .sym = { 50315872bbf2SRichard Henderson [1] = { /* code_gen_buffer */ 50325872bbf2SRichard Henderson .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC), 50335872bbf2SRichard Henderson .st_shndx = 1, 50345872bbf2SRichard Henderson } 50355872bbf2SRichard Henderson }, 50365872bbf2SRichard Henderson .di = { 50375872bbf2SRichard Henderson .len = sizeof(struct DebugInfo) - 4, 50385872bbf2SRichard Henderson .version = 2, 50395872bbf2SRichard Henderson .ptr_size = sizeof(void *), 50405872bbf2SRichard Henderson .cu_die = 1, 50415872bbf2SRichard Henderson .cu_lang = 0x8001, /* DW_LANG_Mips_Assembler */ 50425872bbf2SRichard Henderson .fn_die = 2, 50435872bbf2SRichard Henderson .fn_name = "code_gen_buffer" 50445872bbf2SRichard Henderson }, 50455872bbf2SRichard Henderson .da = { 50465872bbf2SRichard Henderson 1, /* abbrev number (the cu) */ 50475872bbf2SRichard Henderson 0x11, 1, /* DW_TAG_compile_unit, has children */ 50485872bbf2SRichard Henderson 0x13, 0x5, /* DW_AT_language, DW_FORM_data2 */ 50495872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */ 50505872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */ 50515872bbf2SRichard Henderson 0, 0, /* end of abbrev */ 50525872bbf2SRichard Henderson 2, /* abbrev number (the fn) */ 50535872bbf2SRichard Henderson 0x2e, 0, /* DW_TAG_subprogram, no children */ 50545872bbf2SRichard Henderson 0x3, 0x8, /* DW_AT_name, DW_FORM_string */ 50555872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */ 50565872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */ 50575872bbf2SRichard Henderson 0, 0, /* end of abbrev */ 50585872bbf2SRichard Henderson 0 /* no more abbrev */ 50595872bbf2SRichard Henderson }, 50605872bbf2SRichard Henderson .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0" 50615872bbf2SRichard Henderson ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer", 5062813da627SRichard Henderson }; 5063813da627SRichard Henderson 5064813da627SRichard Henderson /* We only need a single jit entry; statically allocate it. */ 5065813da627SRichard Henderson static struct jit_code_entry one_entry; 5066813da627SRichard Henderson 50675872bbf2SRichard Henderson uintptr_t buf = (uintptr_t)buf_ptr; 5068813da627SRichard Henderson size_t img_size = sizeof(struct ElfImage) + debug_frame_size; 50692c90784aSRichard Henderson DebugFrameHeader *dfh; 5070813da627SRichard Henderson 50715872bbf2SRichard Henderson img = g_malloc(img_size); 50725872bbf2SRichard Henderson *img = img_template; 5073813da627SRichard Henderson 50745872bbf2SRichard Henderson img->phdr.p_vaddr = buf; 50755872bbf2SRichard Henderson img->phdr.p_paddr = buf; 50765872bbf2SRichard Henderson img->phdr.p_memsz = buf_size; 5077813da627SRichard Henderson 50785872bbf2SRichard Henderson img->shdr[1].sh_name = find_string(img->str, ".text"); 50795872bbf2SRichard Henderson img->shdr[1].sh_addr = buf; 50805872bbf2SRichard Henderson img->shdr[1].sh_size = buf_size; 5081813da627SRichard Henderson 50825872bbf2SRichard Henderson img->shdr[2].sh_name = find_string(img->str, ".debug_info"); 50835872bbf2SRichard Henderson img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev"); 50845872bbf2SRichard Henderson 50855872bbf2SRichard Henderson img->shdr[4].sh_name = find_string(img->str, ".debug_frame"); 50865872bbf2SRichard Henderson img->shdr[4].sh_size = debug_frame_size; 50875872bbf2SRichard Henderson 50885872bbf2SRichard Henderson img->shdr[5].sh_name = find_string(img->str, ".symtab"); 50895872bbf2SRichard Henderson img->shdr[6].sh_name = find_string(img->str, ".strtab"); 50905872bbf2SRichard Henderson 50915872bbf2SRichard Henderson img->sym[1].st_name = find_string(img->str, "code_gen_buffer"); 50925872bbf2SRichard Henderson img->sym[1].st_value = buf; 50935872bbf2SRichard Henderson img->sym[1].st_size = buf_size; 50945872bbf2SRichard Henderson 50955872bbf2SRichard Henderson img->di.cu_low_pc = buf; 509645aba097SRichard Henderson img->di.cu_high_pc = buf + buf_size; 50975872bbf2SRichard Henderson img->di.fn_low_pc = buf; 509845aba097SRichard Henderson img->di.fn_high_pc = buf + buf_size; 5099813da627SRichard Henderson 51002c90784aSRichard Henderson dfh = (DebugFrameHeader *)(img + 1); 51012c90784aSRichard Henderson memcpy(dfh, debug_frame, debug_frame_size); 51022c90784aSRichard Henderson dfh->fde.func_start = buf; 51032c90784aSRichard Henderson dfh->fde.func_len = buf_size; 51042c90784aSRichard Henderson 5105813da627SRichard Henderson #ifdef DEBUG_JIT 5106813da627SRichard Henderson /* Enable this block to be able to debug the ELF image file creation. 5107813da627SRichard Henderson One can use readelf, objdump, or other inspection utilities. */ 5108813da627SRichard Henderson { 5109eb6b2edfSBin Meng g_autofree char *jit = g_strdup_printf("%s/qemu.jit", g_get_tmp_dir()); 5110eb6b2edfSBin Meng FILE *f = fopen(jit, "w+b"); 5111813da627SRichard Henderson if (f) { 51125872bbf2SRichard Henderson if (fwrite(img, img_size, 1, f) != img_size) { 5113813da627SRichard Henderson /* Avoid stupid unused return value warning for fwrite. */ 5114813da627SRichard Henderson } 5115813da627SRichard Henderson fclose(f); 5116813da627SRichard Henderson } 5117813da627SRichard Henderson } 5118813da627SRichard Henderson #endif 5119813da627SRichard Henderson 5120813da627SRichard Henderson one_entry.symfile_addr = img; 5121813da627SRichard Henderson one_entry.symfile_size = img_size; 5122813da627SRichard Henderson 5123813da627SRichard Henderson __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; 5124813da627SRichard Henderson __jit_debug_descriptor.relevant_entry = &one_entry; 5125813da627SRichard Henderson __jit_debug_descriptor.first_entry = &one_entry; 5126813da627SRichard Henderson __jit_debug_register_code(); 5127813da627SRichard Henderson } 5128813da627SRichard Henderson #else 51295872bbf2SRichard Henderson /* No support for the feature. Provide the entry point expected by exec.c, 51305872bbf2SRichard Henderson and implement the internal function we declared earlier. */ 5131813da627SRichard Henderson 5132755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size, 51332c90784aSRichard Henderson const void *debug_frame, 51342c90784aSRichard Henderson size_t debug_frame_size) 5135813da627SRichard Henderson { 5136813da627SRichard Henderson } 5137813da627SRichard Henderson 5138755bf9e5SRichard Henderson void tcg_register_jit(const void *buf, size_t buf_size) 5139813da627SRichard Henderson { 5140813da627SRichard Henderson } 5141813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */ 5142db432672SRichard Henderson 5143db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec 5144db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...) 5145db432672SRichard Henderson { 5146db432672SRichard Henderson g_assert_not_reached(); 5147db432672SRichard Henderson } 5148db432672SRichard Henderson #endif 5149