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 25757e725bSPeter Maydell #include "qemu/osdep.h" 26cca82982Saurel32 27813da627SRichard Henderson /* Define to jump the ELF file used to communicate with GDB. */ 28813da627SRichard Henderson #undef DEBUG_JIT 29813da627SRichard Henderson 3072fd2efbSEmilio G. Cota #include "qemu/error-report.h" 31f348b6d1SVeronia Bahaa #include "qemu/cutils.h" 321de7afc9SPaolo Bonzini #include "qemu/host-utils.h" 33d4c51a0aSMarkus Armbruster #include "qemu/qemu-print.h" 34084cfca1SRichard Henderson #include "qemu/cacheflush.h" 35ad768e6fSPeter Maydell #include "qemu/cacheinfo.h" 36533206f0SRichard W.M. Jones #include "qemu/timer.h" 37cac9b0fdSRichard Henderson #include "exec/translation-block.h" 38d0a9bb5eSRichard Henderson #include "exec/tlb-common.h" 39d7ec12f8SRichard Henderson #include "tcg/startup.h" 40ad3d0e4dSRichard Henderson #include "tcg/tcg-op-common.h" 41813da627SRichard Henderson 42edee2579SRichard Henderson #if UINTPTR_MAX == UINT32_MAX 43813da627SRichard Henderson # define ELF_CLASS ELFCLASS32 44edee2579SRichard Henderson #else 45edee2579SRichard Henderson # define ELF_CLASS ELFCLASS64 46813da627SRichard Henderson #endif 47e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN 48813da627SRichard Henderson # define ELF_DATA ELFDATA2MSB 49813da627SRichard Henderson #else 50813da627SRichard Henderson # define ELF_DATA ELFDATA2LSB 51813da627SRichard Henderson #endif 52813da627SRichard Henderson 53c896fe29Sbellard #include "elf.h" 54508127e2SPaolo Bonzini #include "exec/log.h" 55d2ba8026SRichard Henderson #include "tcg/tcg-ldst.h" 5647f7313dSRichard Henderson #include "tcg/tcg-temp-internal.h" 575ff7258cSRichard Henderson #include "tcg-internal.h" 58327b75a4SIlya Leoshkevich #include "tcg/perf.h" 5993280b67SRichard Henderson #include "tcg-has.h" 607d478306SRichard Henderson #ifdef CONFIG_USER_ONLY 61d3cbde74SPhilippe Mathieu-Daudé #include "user/guest-base.h" 627d478306SRichard Henderson #endif 63c896fe29Sbellard 64139c1837SPaolo Bonzini /* Forward declarations for functions declared in tcg-target.c.inc and 65ce151109SPeter Maydell used here. */ 66e4d58b41SRichard Henderson static void tcg_target_init(TCGContext *s); 67e4d58b41SRichard Henderson static void tcg_target_qemu_prologue(TCGContext *s); 686ac17786SRichard Henderson static bool patch_reloc(tcg_insn_unit *code_ptr, int type, 692ba7fae2SRichard Henderson intptr_t value, intptr_t addend); 70a417ef83SRichard Henderson static void tcg_out_nop_fill(tcg_insn_unit *p, int count); 71a417ef83SRichard Henderson 72a417ef83SRichard Henderson typedef struct TCGLabelQemuLdst TCGLabelQemuLdst; 73a417ef83SRichard Henderson static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l); 74a417ef83SRichard Henderson static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l); 75c896fe29Sbellard 76497a22ebSRichard Henderson /* The CIE and FDE header definitions will be common to all hosts. */ 77497a22ebSRichard Henderson typedef struct { 78497a22ebSRichard Henderson uint32_t len __attribute__((aligned((sizeof(void *))))); 79497a22ebSRichard Henderson uint32_t id; 80497a22ebSRichard Henderson uint8_t version; 81497a22ebSRichard Henderson char augmentation[1]; 82497a22ebSRichard Henderson uint8_t code_align; 83497a22ebSRichard Henderson uint8_t data_align; 84497a22ebSRichard Henderson uint8_t return_column; 85497a22ebSRichard Henderson } DebugFrameCIE; 86497a22ebSRichard Henderson 87497a22ebSRichard Henderson typedef struct QEMU_PACKED { 88497a22ebSRichard Henderson uint32_t len __attribute__((aligned((sizeof(void *))))); 89497a22ebSRichard Henderson uint32_t cie_offset; 90edee2579SRichard Henderson uintptr_t func_start; 91edee2579SRichard Henderson uintptr_t func_len; 92497a22ebSRichard Henderson } DebugFrameFDEHeader; 93497a22ebSRichard Henderson 942c90784aSRichard Henderson typedef struct QEMU_PACKED { 952c90784aSRichard Henderson DebugFrameCIE cie; 962c90784aSRichard Henderson DebugFrameFDEHeader fde; 972c90784aSRichard Henderson } DebugFrameHeader; 982c90784aSRichard Henderson 99a417ef83SRichard Henderson struct TCGLabelQemuLdst { 1002528f771SRichard Henderson bool is_ld; /* qemu_ld: true, qemu_st: false */ 1012528f771SRichard Henderson MemOpIdx oi; 1022528f771SRichard Henderson TCGType type; /* result type of a load */ 1032528f771SRichard Henderson TCGReg addrlo_reg; /* reg index for low word of guest virtual addr */ 1042528f771SRichard Henderson TCGReg addrhi_reg; /* reg index for high word of guest virtual addr */ 1052528f771SRichard Henderson TCGReg datalo_reg; /* reg index for low word to be loaded or stored */ 1062528f771SRichard Henderson TCGReg datahi_reg; /* reg index for high word to be loaded or stored */ 1072528f771SRichard Henderson const tcg_insn_unit *raddr; /* addr of the next IR of qemu_ld/st IR */ 1082528f771SRichard Henderson tcg_insn_unit *label_ptr[2]; /* label pointers to be updated */ 1092528f771SRichard Henderson QSIMPLEQ_ENTRY(TCGLabelQemuLdst) next; 110a417ef83SRichard Henderson }; 1112528f771SRichard Henderson 112755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size, 1132c90784aSRichard Henderson const void *debug_frame, 1142c90784aSRichard Henderson size_t debug_frame_size) 115813da627SRichard Henderson __attribute__((unused)); 116813da627SRichard Henderson 117139c1837SPaolo Bonzini /* Forward declarations for functions declared and used in tcg-target.c.inc. */ 1189358fbbfSRichard Henderson static void tcg_out_tb_start(TCGContext *s); 1192a534affSRichard Henderson static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1, 120a05b5b9bSRichard Henderson intptr_t arg2); 12178113e83SRichard Henderson static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg); 122c0ad3001SStefan Weil static void tcg_out_movi(TCGContext *s, TCGType type, 1232a534affSRichard Henderson TCGReg ret, tcg_target_long arg); 124678155b2SRichard Henderson static void tcg_out_ext8s(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg); 125753e42eaSRichard Henderson static void tcg_out_ext16s(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg); 126d0e66c89SRichard Henderson static void tcg_out_ext8u(TCGContext *s, TCGReg ret, TCGReg arg); 127379afdffSRichard Henderson static void tcg_out_ext16u(TCGContext *s, TCGReg ret, TCGReg arg); 12852bf3398SRichard Henderson static void tcg_out_ext32s(TCGContext *s, TCGReg ret, TCGReg arg); 1299ecf5f61SRichard Henderson static void tcg_out_ext32u(TCGContext *s, TCGReg ret, TCGReg arg); 1309c6aa274SRichard Henderson static void tcg_out_exts_i32_i64(TCGContext *s, TCGReg ret, TCGReg arg); 131b9bfe000SRichard Henderson static void tcg_out_extu_i32_i64(TCGContext *s, TCGReg ret, TCGReg arg); 132b8b94ac6SRichard Henderson static void tcg_out_extrl_i64_i32(TCGContext *s, TCGReg ret, TCGReg arg); 133313bdea8SRichard Henderson static void tcg_out_addi_ptr(TCGContext *s, TCGReg, TCGReg, tcg_target_long); 134129f1f9eSRichard Henderson static bool tcg_out_xchg(TCGContext *s, TCGType type, TCGReg r1, TCGReg r2); 135b55a8d9dSRichard Henderson static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg); 136cf7d6b8eSRichard Henderson static void tcg_out_goto_tb(TCGContext *s, int which); 137*4e350091SRichard Henderson static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, 1385e8892dbSMiroslav Rezanina const TCGArg args[TCG_MAX_OP_ARGS], 1395e8892dbSMiroslav Rezanina const int const_args[TCG_MAX_OP_ARGS]); 140d2fd745fSRichard Henderson #if TCG_TARGET_MAYBE_vec 141e7632cfaSRichard Henderson static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece, 142e7632cfaSRichard Henderson TCGReg dst, TCGReg src); 143d6ecb4a9SRichard Henderson static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece, 144d6ecb4a9SRichard Henderson TCGReg dst, TCGReg base, intptr_t offset); 1454e186175SRichard Henderson static void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece, 1464e186175SRichard Henderson TCGReg dst, int64_t arg); 1475e8892dbSMiroslav Rezanina static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, 1485e8892dbSMiroslav Rezanina unsigned vecl, unsigned vece, 1495e8892dbSMiroslav Rezanina const TCGArg args[TCG_MAX_OP_ARGS], 1505e8892dbSMiroslav Rezanina const int const_args[TCG_MAX_OP_ARGS]); 151d2fd745fSRichard Henderson #else 152e7632cfaSRichard Henderson static inline bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece, 153e7632cfaSRichard Henderson TCGReg dst, TCGReg src) 154e7632cfaSRichard Henderson { 155e7632cfaSRichard Henderson g_assert_not_reached(); 156e7632cfaSRichard Henderson } 157d6ecb4a9SRichard Henderson static inline bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece, 158d6ecb4a9SRichard Henderson TCGReg dst, TCGReg base, intptr_t offset) 159d6ecb4a9SRichard Henderson { 160d6ecb4a9SRichard Henderson g_assert_not_reached(); 161d6ecb4a9SRichard Henderson } 1624e186175SRichard Henderson static inline void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece, 1634e186175SRichard Henderson TCGReg dst, int64_t arg) 164e7632cfaSRichard Henderson { 165e7632cfaSRichard Henderson g_assert_not_reached(); 166e7632cfaSRichard Henderson } 1675e8892dbSMiroslav Rezanina static inline void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, 1685e8892dbSMiroslav Rezanina unsigned vecl, unsigned vece, 1695e8892dbSMiroslav Rezanina const TCGArg args[TCG_MAX_OP_ARGS], 1705e8892dbSMiroslav Rezanina const int const_args[TCG_MAX_OP_ARGS]) 171d2fd745fSRichard Henderson { 172d2fd745fSRichard Henderson g_assert_not_reached(); 173d2fd745fSRichard Henderson } 1747d3e705aSRichard Henderson int tcg_can_emit_vec_op(TCGOpcode o, TCGType t, unsigned ve) 1757d3e705aSRichard Henderson { 1767d3e705aSRichard Henderson return 0; 1777d3e705aSRichard Henderson } 178d2fd745fSRichard Henderson #endif 1792a534affSRichard Henderson static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1, 180a05b5b9bSRichard Henderson intptr_t arg2); 18159d7c14eSRichard Henderson static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val, 18259d7c14eSRichard Henderson TCGReg base, intptr_t ofs); 1837b7d8b2dSRichard Henderson static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target, 184cee44b03SRichard Henderson const TCGHelperInfo *info); 1855e3d0c19SRichard Henderson static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot); 18621e9a8aeSRichard Henderson static bool tcg_target_const_match(int64_t val, int ct, 18721e9a8aeSRichard Henderson TCGType type, TCGCond cond, int vece); 188c896fe29Sbellard 18923088ca0SRichard Henderson #ifndef CONFIG_USER_ONLY 19023088ca0SRichard Henderson #define guest_base ({ qemu_build_not_reached(); (uintptr_t)0; }) 19123088ca0SRichard Henderson #endif 19223088ca0SRichard Henderson 1938429a1caSRichard Henderson typedef struct TCGLdstHelperParam { 1948429a1caSRichard Henderson TCGReg (*ra_gen)(TCGContext *s, const TCGLabelQemuLdst *l, int arg_reg); 1958429a1caSRichard Henderson unsigned ntmp; 1968429a1caSRichard Henderson int tmp[3]; 1978429a1caSRichard Henderson } TCGLdstHelperParam; 1988429a1caSRichard Henderson 1998429a1caSRichard Henderson static void tcg_out_ld_helper_args(TCGContext *s, const TCGLabelQemuLdst *l, 2008429a1caSRichard Henderson const TCGLdstHelperParam *p) 2018429a1caSRichard Henderson __attribute__((unused)); 2028429a1caSRichard Henderson static void tcg_out_ld_helper_ret(TCGContext *s, const TCGLabelQemuLdst *l, 2038429a1caSRichard Henderson bool load_sign, const TCGLdstHelperParam *p) 2048429a1caSRichard Henderson __attribute__((unused)); 2058429a1caSRichard Henderson static void tcg_out_st_helper_args(TCGContext *s, const TCGLabelQemuLdst *l, 2068429a1caSRichard Henderson const TCGLdstHelperParam *p) 2078429a1caSRichard Henderson __attribute__((unused)); 2088429a1caSRichard Henderson 209de95016dSRichard Henderson static void * const qemu_ld_helpers[MO_SSIZE + 1] __attribute__((unused)) = { 2100cadc1edSRichard Henderson [MO_UB] = helper_ldub_mmu, 2110cadc1edSRichard Henderson [MO_SB] = helper_ldsb_mmu, 2120cadc1edSRichard Henderson [MO_UW] = helper_lduw_mmu, 2130cadc1edSRichard Henderson [MO_SW] = helper_ldsw_mmu, 2140cadc1edSRichard Henderson [MO_UL] = helper_ldul_mmu, 2150cadc1edSRichard Henderson [MO_UQ] = helper_ldq_mmu, 2160cadc1edSRichard Henderson #if TCG_TARGET_REG_BITS == 64 2170cadc1edSRichard Henderson [MO_SL] = helper_ldsl_mmu, 218ebebea53SRichard Henderson [MO_128] = helper_ld16_mmu, 2190cadc1edSRichard Henderson #endif 2200cadc1edSRichard Henderson }; 2210cadc1edSRichard Henderson 222de95016dSRichard Henderson static void * const qemu_st_helpers[MO_SIZE + 1] __attribute__((unused)) = { 2230cadc1edSRichard Henderson [MO_8] = helper_stb_mmu, 2240cadc1edSRichard Henderson [MO_16] = helper_stw_mmu, 2250cadc1edSRichard Henderson [MO_32] = helper_stl_mmu, 2260cadc1edSRichard Henderson [MO_64] = helper_stq_mmu, 227ebebea53SRichard Henderson #if TCG_TARGET_REG_BITS == 64 228ebebea53SRichard Henderson [MO_128] = helper_st16_mmu, 229ebebea53SRichard Henderson #endif 2300cadc1edSRichard Henderson }; 2310cadc1edSRichard Henderson 232e63b8a29SRichard Henderson typedef struct { 233e63b8a29SRichard Henderson MemOp atom; /* lg2 bits of atomicity required */ 234e63b8a29SRichard Henderson MemOp align; /* lg2 bits of alignment to use */ 235e63b8a29SRichard Henderson } TCGAtomAlign; 236e63b8a29SRichard Henderson 237e63b8a29SRichard Henderson static TCGAtomAlign atom_and_align_for_opc(TCGContext *s, MemOp opc, 238e63b8a29SRichard Henderson MemOp host_atom, bool allow_two_ops) 239e63b8a29SRichard Henderson __attribute__((unused)); 240e63b8a29SRichard Henderson 241397cabaaSRichard Henderson #ifdef CONFIG_USER_ONLY 242397cabaaSRichard Henderson bool tcg_use_softmmu; 243397cabaaSRichard Henderson #endif 244397cabaaSRichard Henderson 24542eb6dfcSRichard Henderson TCGContext tcg_init_ctx; 24642eb6dfcSRichard Henderson __thread TCGContext *tcg_ctx; 24742eb6dfcSRichard Henderson 2485ff7258cSRichard Henderson TCGContext **tcg_ctxs; 2490e2d61cfSRichard Henderson unsigned int tcg_cur_ctxs; 2500e2d61cfSRichard Henderson unsigned int tcg_max_ctxs; 251ad75a51eSRichard Henderson TCGv_env tcg_env; 252c8bc1168SRichard Henderson const void *tcg_code_gen_epilogue; 253db0c51a3SRichard Henderson uintptr_t tcg_splitwx_diff; 254df2cce29SEmilio G. Cota 255b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 256b91ccb31SRichard Henderson tcg_prologue_fn *tcg_qemu_tb_exec; 257b91ccb31SRichard Henderson #endif 258b91ccb31SRichard Henderson 259d2fd745fSRichard Henderson static TCGRegSet tcg_target_available_regs[TCG_TYPE_COUNT]; 260b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs; 261c896fe29Sbellard 2621813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1 2634196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v) 264c896fe29Sbellard { 265c896fe29Sbellard *s->code_ptr++ = v; 266c896fe29Sbellard } 267c896fe29Sbellard 2684196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p, 2694196dca6SPeter Maydell uint8_t v) 2705c53bb81SPeter Maydell { 2711813e175SRichard Henderson *p = v; 2725c53bb81SPeter Maydell } 2731813e175SRichard Henderson #endif 2745c53bb81SPeter Maydell 2751813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2 2764196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v) 277c896fe29Sbellard { 2781813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 2) { 2791813e175SRichard Henderson *s->code_ptr++ = v; 2801813e175SRichard Henderson } else { 2811813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 2824387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 2831813e175SRichard Henderson s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE); 2841813e175SRichard Henderson } 285c896fe29Sbellard } 286c896fe29Sbellard 2874196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p, 2884196dca6SPeter Maydell uint16_t v) 2895c53bb81SPeter Maydell { 2901813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 2) { 2911813e175SRichard Henderson *p = v; 2921813e175SRichard Henderson } else { 2935c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 2945c53bb81SPeter Maydell } 2951813e175SRichard Henderson } 2961813e175SRichard Henderson #endif 2975c53bb81SPeter Maydell 2981813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4 2994196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v) 300c896fe29Sbellard { 3011813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 4) { 3021813e175SRichard Henderson *s->code_ptr++ = v; 3031813e175SRichard Henderson } else { 3041813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 3054387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 3061813e175SRichard Henderson s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE); 3071813e175SRichard Henderson } 308c896fe29Sbellard } 309c896fe29Sbellard 3104196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p, 3114196dca6SPeter Maydell uint32_t v) 3125c53bb81SPeter Maydell { 3131813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 4) { 3141813e175SRichard Henderson *p = v; 3151813e175SRichard Henderson } else { 3165c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 3175c53bb81SPeter Maydell } 3181813e175SRichard Henderson } 3191813e175SRichard Henderson #endif 3205c53bb81SPeter Maydell 3211813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 8 3224196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v) 323ac26eb69SRichard Henderson { 3241813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 8) { 3251813e175SRichard Henderson *s->code_ptr++ = v; 3261813e175SRichard Henderson } else { 3271813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 3284387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 3291813e175SRichard Henderson s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE); 3301813e175SRichard Henderson } 331ac26eb69SRichard Henderson } 332ac26eb69SRichard Henderson 3334196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p, 3344196dca6SPeter Maydell uint64_t v) 3355c53bb81SPeter Maydell { 3361813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 8) { 3371813e175SRichard Henderson *p = v; 3381813e175SRichard Henderson } else { 3395c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 3405c53bb81SPeter Maydell } 3411813e175SRichard Henderson } 3421813e175SRichard Henderson #endif 3435c53bb81SPeter Maydell 344c896fe29Sbellard /* label relocation processing */ 345c896fe29Sbellard 3461813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type, 347bec16311SRichard Henderson TCGLabel *l, intptr_t addend) 348c896fe29Sbellard { 3497ecd02a0SRichard Henderson TCGRelocation *r = tcg_malloc(sizeof(TCGRelocation)); 350c896fe29Sbellard 351c896fe29Sbellard r->type = type; 352c896fe29Sbellard r->ptr = code_ptr; 353c896fe29Sbellard r->addend = addend; 3547ecd02a0SRichard Henderson QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next); 355c896fe29Sbellard } 356c896fe29Sbellard 35792ab8e7dSRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l) 358c896fe29Sbellard { 359eabb7b91SAurelien Jarno tcg_debug_assert(!l->has_value); 360c896fe29Sbellard l->has_value = 1; 36192ab8e7dSRichard Henderson l->u.value_ptr = tcg_splitwx_to_rx(s->code_ptr); 362c896fe29Sbellard } 363c896fe29Sbellard 36442a268c2SRichard Henderson TCGLabel *gen_new_label(void) 365c896fe29Sbellard { 366b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 36751e3972cSRichard Henderson TCGLabel *l = tcg_malloc(sizeof(TCGLabel)); 368c896fe29Sbellard 3697ecd02a0SRichard Henderson memset(l, 0, sizeof(TCGLabel)); 3707ecd02a0SRichard Henderson l->id = s->nb_labels++; 371f85b1fc4SRichard Henderson QSIMPLEQ_INIT(&l->branches); 3727ecd02a0SRichard Henderson QSIMPLEQ_INIT(&l->relocs); 3737ecd02a0SRichard Henderson 374bef16ab4SRichard Henderson QSIMPLEQ_INSERT_TAIL(&s->labels, l, next); 37542a268c2SRichard Henderson 37642a268c2SRichard Henderson return l; 377c896fe29Sbellard } 378c896fe29Sbellard 3797ecd02a0SRichard Henderson static bool tcg_resolve_relocs(TCGContext *s) 3807ecd02a0SRichard Henderson { 3817ecd02a0SRichard Henderson TCGLabel *l; 3827ecd02a0SRichard Henderson 3837ecd02a0SRichard Henderson QSIMPLEQ_FOREACH(l, &s->labels, next) { 3847ecd02a0SRichard Henderson TCGRelocation *r; 3857ecd02a0SRichard Henderson uintptr_t value = l->u.value; 3867ecd02a0SRichard Henderson 3877ecd02a0SRichard Henderson QSIMPLEQ_FOREACH(r, &l->relocs, next) { 3887ecd02a0SRichard Henderson if (!patch_reloc(r->ptr, r->type, value, r->addend)) { 3897ecd02a0SRichard Henderson return false; 3907ecd02a0SRichard Henderson } 3917ecd02a0SRichard Henderson } 3927ecd02a0SRichard Henderson } 3937ecd02a0SRichard Henderson return true; 3947ecd02a0SRichard Henderson } 3957ecd02a0SRichard Henderson 3969f754620SRichard Henderson static void set_jmp_reset_offset(TCGContext *s, int which) 3979f754620SRichard Henderson { 398f14bed3fSRichard Henderson /* 399f14bed3fSRichard Henderson * We will check for overflow at the end of the opcode loop in 400f14bed3fSRichard Henderson * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX. 401f14bed3fSRichard Henderson */ 402b7e4afbdSRichard Henderson s->gen_tb->jmp_reset_offset[which] = tcg_current_code_size(s); 4039f754620SRichard Henderson } 4049f754620SRichard Henderson 405b52a2c03SRichard Henderson static void G_GNUC_UNUSED set_jmp_insn_offset(TCGContext *s, int which) 406b52a2c03SRichard Henderson { 407b52a2c03SRichard Henderson /* 408b52a2c03SRichard Henderson * We will check for overflow at the end of the opcode loop in 409b52a2c03SRichard Henderson * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX. 410b52a2c03SRichard Henderson */ 4119da6079bSRichard Henderson s->gen_tb->jmp_insn_offset[which] = tcg_current_code_size(s); 412b52a2c03SRichard Henderson } 413b52a2c03SRichard Henderson 414becc452aSRichard Henderson static uintptr_t G_GNUC_UNUSED get_jmp_target_addr(TCGContext *s, int which) 415becc452aSRichard Henderson { 416becc452aSRichard Henderson /* 417becc452aSRichard Henderson * Return the read-execute version of the pointer, for the benefit 418becc452aSRichard Henderson * of any pc-relative addressing mode. 419becc452aSRichard Henderson */ 4209da6079bSRichard Henderson return (uintptr_t)tcg_splitwx_to_rx(&s->gen_tb->jmp_target_addr[which]); 421becc452aSRichard Henderson } 422becc452aSRichard Henderson 423397cabaaSRichard Henderson static int __attribute__((unused)) 424397cabaaSRichard Henderson tlb_mask_table_ofs(TCGContext *s, int which) 425d0a9bb5eSRichard Henderson { 4267857ee11SRichard Henderson return (offsetof(CPUNegativeOffsetState, tlb.f[which]) - 4277857ee11SRichard Henderson sizeof(CPUNegativeOffsetState)); 428d0a9bb5eSRichard Henderson } 429d0a9bb5eSRichard Henderson 430db6b7d0cSRichard Henderson /* Signal overflow, starting over with fewer guest insns. */ 4318905770bSMarc-André Lureau static G_NORETURN 4328905770bSMarc-André Lureau void tcg_raise_tb_overflow(TCGContext *s) 433db6b7d0cSRichard Henderson { 434db6b7d0cSRichard Henderson siglongjmp(s->jmp_trans, -2); 435db6b7d0cSRichard Henderson } 436db6b7d0cSRichard Henderson 4378429a1caSRichard Henderson /* 4388429a1caSRichard Henderson * Used by tcg_out_movext{1,2} to hold the arguments for tcg_out_movext. 4398429a1caSRichard Henderson * By the time we arrive at tcg_out_movext1, @dst is always a TCGReg. 4408429a1caSRichard Henderson * 4418429a1caSRichard Henderson * However, tcg_out_helper_load_slots reuses this field to hold an 4428429a1caSRichard Henderson * argument slot number (which may designate a argument register or an 4438429a1caSRichard Henderson * argument stack slot), converting to TCGReg once all arguments that 4448429a1caSRichard Henderson * are destined for the stack are processed. 4458429a1caSRichard Henderson */ 446129f1f9eSRichard Henderson typedef struct TCGMovExtend { 4478429a1caSRichard Henderson unsigned dst; 448129f1f9eSRichard Henderson TCGReg src; 449129f1f9eSRichard Henderson TCGType dst_type; 450129f1f9eSRichard Henderson TCGType src_type; 451129f1f9eSRichard Henderson MemOp src_ext; 452129f1f9eSRichard Henderson } TCGMovExtend; 453129f1f9eSRichard Henderson 454b3dfd5fcSRichard Henderson /** 455b3dfd5fcSRichard Henderson * tcg_out_movext -- move and extend 456b3dfd5fcSRichard Henderson * @s: tcg context 457b3dfd5fcSRichard Henderson * @dst_type: integral type for destination 458b3dfd5fcSRichard Henderson * @dst: destination register 459b3dfd5fcSRichard Henderson * @src_type: integral type for source 460b3dfd5fcSRichard Henderson * @src_ext: extension to apply to source 461b3dfd5fcSRichard Henderson * @src: source register 462b3dfd5fcSRichard Henderson * 463b3dfd5fcSRichard Henderson * Move or extend @src into @dst, depending on @src_ext and the types. 464b3dfd5fcSRichard Henderson */ 465129f1f9eSRichard Henderson static void tcg_out_movext(TCGContext *s, TCGType dst_type, TCGReg dst, 466b3dfd5fcSRichard Henderson TCGType src_type, MemOp src_ext, TCGReg src) 467b3dfd5fcSRichard Henderson { 468b3dfd5fcSRichard Henderson switch (src_ext) { 469b3dfd5fcSRichard Henderson case MO_UB: 470b3dfd5fcSRichard Henderson tcg_out_ext8u(s, dst, src); 471b3dfd5fcSRichard Henderson break; 472b3dfd5fcSRichard Henderson case MO_SB: 473b3dfd5fcSRichard Henderson tcg_out_ext8s(s, dst_type, dst, src); 474b3dfd5fcSRichard Henderson break; 475b3dfd5fcSRichard Henderson case MO_UW: 476b3dfd5fcSRichard Henderson tcg_out_ext16u(s, dst, src); 477b3dfd5fcSRichard Henderson break; 478b3dfd5fcSRichard Henderson case MO_SW: 479b3dfd5fcSRichard Henderson tcg_out_ext16s(s, dst_type, dst, src); 480b3dfd5fcSRichard Henderson break; 481b3dfd5fcSRichard Henderson case MO_UL: 482b3dfd5fcSRichard Henderson case MO_SL: 483b3dfd5fcSRichard Henderson if (dst_type == TCG_TYPE_I32) { 484b3dfd5fcSRichard Henderson if (src_type == TCG_TYPE_I32) { 485b3dfd5fcSRichard Henderson tcg_out_mov(s, TCG_TYPE_I32, dst, src); 486b3dfd5fcSRichard Henderson } else { 487b3dfd5fcSRichard Henderson tcg_out_extrl_i64_i32(s, dst, src); 488b3dfd5fcSRichard Henderson } 489b3dfd5fcSRichard Henderson } else if (src_type == TCG_TYPE_I32) { 490b3dfd5fcSRichard Henderson if (src_ext & MO_SIGN) { 491b3dfd5fcSRichard Henderson tcg_out_exts_i32_i64(s, dst, src); 492b3dfd5fcSRichard Henderson } else { 493b3dfd5fcSRichard Henderson tcg_out_extu_i32_i64(s, dst, src); 494b3dfd5fcSRichard Henderson } 495b3dfd5fcSRichard Henderson } else { 496b3dfd5fcSRichard Henderson if (src_ext & MO_SIGN) { 497b3dfd5fcSRichard Henderson tcg_out_ext32s(s, dst, src); 498b3dfd5fcSRichard Henderson } else { 499b3dfd5fcSRichard Henderson tcg_out_ext32u(s, dst, src); 500b3dfd5fcSRichard Henderson } 501b3dfd5fcSRichard Henderson } 502b3dfd5fcSRichard Henderson break; 503b3dfd5fcSRichard Henderson case MO_UQ: 504b3dfd5fcSRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 64); 505b3dfd5fcSRichard Henderson if (dst_type == TCG_TYPE_I32) { 506b3dfd5fcSRichard Henderson tcg_out_extrl_i64_i32(s, dst, src); 507b3dfd5fcSRichard Henderson } else { 508b3dfd5fcSRichard Henderson tcg_out_mov(s, TCG_TYPE_I64, dst, src); 509b3dfd5fcSRichard Henderson } 510b3dfd5fcSRichard Henderson break; 511b3dfd5fcSRichard Henderson default: 512b3dfd5fcSRichard Henderson g_assert_not_reached(); 513b3dfd5fcSRichard Henderson } 514b3dfd5fcSRichard Henderson } 515b3dfd5fcSRichard Henderson 516129f1f9eSRichard Henderson /* Minor variations on a theme, using a structure. */ 517129f1f9eSRichard Henderson static void tcg_out_movext1_new_src(TCGContext *s, const TCGMovExtend *i, 518129f1f9eSRichard Henderson TCGReg src) 519129f1f9eSRichard Henderson { 520129f1f9eSRichard Henderson tcg_out_movext(s, i->dst_type, i->dst, i->src_type, i->src_ext, src); 521129f1f9eSRichard Henderson } 522129f1f9eSRichard Henderson 523129f1f9eSRichard Henderson static void tcg_out_movext1(TCGContext *s, const TCGMovExtend *i) 524129f1f9eSRichard Henderson { 525129f1f9eSRichard Henderson tcg_out_movext1_new_src(s, i, i->src); 526129f1f9eSRichard Henderson } 527129f1f9eSRichard Henderson 528129f1f9eSRichard Henderson /** 529129f1f9eSRichard Henderson * tcg_out_movext2 -- move and extend two pair 530129f1f9eSRichard Henderson * @s: tcg context 531129f1f9eSRichard Henderson * @i1: first move description 532129f1f9eSRichard Henderson * @i2: second move description 533129f1f9eSRichard Henderson * @scratch: temporary register, or -1 for none 534129f1f9eSRichard Henderson * 535129f1f9eSRichard Henderson * As tcg_out_movext, for both @i1 and @i2, caring for overlap 536129f1f9eSRichard Henderson * between the sources and destinations. 537129f1f9eSRichard Henderson */ 538129f1f9eSRichard Henderson 5398429a1caSRichard Henderson static void tcg_out_movext2(TCGContext *s, const TCGMovExtend *i1, 540129f1f9eSRichard Henderson const TCGMovExtend *i2, int scratch) 541129f1f9eSRichard Henderson { 542129f1f9eSRichard Henderson TCGReg src1 = i1->src; 543129f1f9eSRichard Henderson TCGReg src2 = i2->src; 544129f1f9eSRichard Henderson 545129f1f9eSRichard Henderson if (i1->dst != src2) { 546129f1f9eSRichard Henderson tcg_out_movext1(s, i1); 547129f1f9eSRichard Henderson tcg_out_movext1(s, i2); 548129f1f9eSRichard Henderson return; 549129f1f9eSRichard Henderson } 550129f1f9eSRichard Henderson if (i2->dst == src1) { 551129f1f9eSRichard Henderson TCGType src1_type = i1->src_type; 552129f1f9eSRichard Henderson TCGType src2_type = i2->src_type; 553129f1f9eSRichard Henderson 554129f1f9eSRichard Henderson if (tcg_out_xchg(s, MAX(src1_type, src2_type), src1, src2)) { 555129f1f9eSRichard Henderson /* The data is now in the correct registers, now extend. */ 556129f1f9eSRichard Henderson src1 = i2->src; 557129f1f9eSRichard Henderson src2 = i1->src; 558129f1f9eSRichard Henderson } else { 559129f1f9eSRichard Henderson tcg_debug_assert(scratch >= 0); 560129f1f9eSRichard Henderson tcg_out_mov(s, src1_type, scratch, src1); 561129f1f9eSRichard Henderson src1 = scratch; 562129f1f9eSRichard Henderson } 563129f1f9eSRichard Henderson } 564129f1f9eSRichard Henderson tcg_out_movext1_new_src(s, i2, src2); 565129f1f9eSRichard Henderson tcg_out_movext1_new_src(s, i1, src1); 566129f1f9eSRichard Henderson } 567129f1f9eSRichard Henderson 5682462e30eSRichard Henderson /** 5692462e30eSRichard Henderson * tcg_out_movext3 -- move and extend three pair 5702462e30eSRichard Henderson * @s: tcg context 5712462e30eSRichard Henderson * @i1: first move description 5722462e30eSRichard Henderson * @i2: second move description 5732462e30eSRichard Henderson * @i3: third move description 5742462e30eSRichard Henderson * @scratch: temporary register, or -1 for none 5752462e30eSRichard Henderson * 5762462e30eSRichard Henderson * As tcg_out_movext, for all of @i1, @i2 and @i3, caring for overlap 5772462e30eSRichard Henderson * between the sources and destinations. 5782462e30eSRichard Henderson */ 5792462e30eSRichard Henderson 5802462e30eSRichard Henderson static void tcg_out_movext3(TCGContext *s, const TCGMovExtend *i1, 5812462e30eSRichard Henderson const TCGMovExtend *i2, const TCGMovExtend *i3, 5822462e30eSRichard Henderson int scratch) 5832462e30eSRichard Henderson { 5842462e30eSRichard Henderson TCGReg src1 = i1->src; 5852462e30eSRichard Henderson TCGReg src2 = i2->src; 5862462e30eSRichard Henderson TCGReg src3 = i3->src; 5872462e30eSRichard Henderson 5882462e30eSRichard Henderson if (i1->dst != src2 && i1->dst != src3) { 5892462e30eSRichard Henderson tcg_out_movext1(s, i1); 5902462e30eSRichard Henderson tcg_out_movext2(s, i2, i3, scratch); 5912462e30eSRichard Henderson return; 5922462e30eSRichard Henderson } 5932462e30eSRichard Henderson if (i2->dst != src1 && i2->dst != src3) { 5942462e30eSRichard Henderson tcg_out_movext1(s, i2); 5952462e30eSRichard Henderson tcg_out_movext2(s, i1, i3, scratch); 5962462e30eSRichard Henderson return; 5972462e30eSRichard Henderson } 5982462e30eSRichard Henderson if (i3->dst != src1 && i3->dst != src2) { 5992462e30eSRichard Henderson tcg_out_movext1(s, i3); 6002462e30eSRichard Henderson tcg_out_movext2(s, i1, i2, scratch); 6012462e30eSRichard Henderson return; 6022462e30eSRichard Henderson } 6032462e30eSRichard Henderson 6042462e30eSRichard Henderson /* 6052462e30eSRichard Henderson * There is a cycle. Since there are only 3 nodes, the cycle is 6062462e30eSRichard Henderson * either "clockwise" or "anti-clockwise", and can be solved with 6072462e30eSRichard Henderson * a single scratch or two xchg. 6082462e30eSRichard Henderson */ 6092462e30eSRichard Henderson if (i1->dst == src2 && i2->dst == src3 && i3->dst == src1) { 6102462e30eSRichard Henderson /* "Clockwise" */ 6112462e30eSRichard Henderson if (tcg_out_xchg(s, MAX(i1->src_type, i2->src_type), src1, src2)) { 6122462e30eSRichard Henderson tcg_out_xchg(s, MAX(i2->src_type, i3->src_type), src2, src3); 6132462e30eSRichard Henderson /* The data is now in the correct registers, now extend. */ 6142462e30eSRichard Henderson tcg_out_movext1_new_src(s, i1, i1->dst); 6152462e30eSRichard Henderson tcg_out_movext1_new_src(s, i2, i2->dst); 6162462e30eSRichard Henderson tcg_out_movext1_new_src(s, i3, i3->dst); 6172462e30eSRichard Henderson } else { 6182462e30eSRichard Henderson tcg_debug_assert(scratch >= 0); 6192462e30eSRichard Henderson tcg_out_mov(s, i1->src_type, scratch, src1); 6202462e30eSRichard Henderson tcg_out_movext1(s, i3); 6212462e30eSRichard Henderson tcg_out_movext1(s, i2); 6222462e30eSRichard Henderson tcg_out_movext1_new_src(s, i1, scratch); 6232462e30eSRichard Henderson } 6242462e30eSRichard Henderson } else if (i1->dst == src3 && i2->dst == src1 && i3->dst == src2) { 6252462e30eSRichard Henderson /* "Anti-clockwise" */ 6262462e30eSRichard Henderson if (tcg_out_xchg(s, MAX(i2->src_type, i3->src_type), src2, src3)) { 6272462e30eSRichard Henderson tcg_out_xchg(s, MAX(i1->src_type, i2->src_type), src1, src2); 6282462e30eSRichard Henderson /* The data is now in the correct registers, now extend. */ 6292462e30eSRichard Henderson tcg_out_movext1_new_src(s, i1, i1->dst); 6302462e30eSRichard Henderson tcg_out_movext1_new_src(s, i2, i2->dst); 6312462e30eSRichard Henderson tcg_out_movext1_new_src(s, i3, i3->dst); 6322462e30eSRichard Henderson } else { 6332462e30eSRichard Henderson tcg_debug_assert(scratch >= 0); 6342462e30eSRichard Henderson tcg_out_mov(s, i1->src_type, scratch, src1); 6352462e30eSRichard Henderson tcg_out_movext1(s, i2); 6362462e30eSRichard Henderson tcg_out_movext1(s, i3); 6372462e30eSRichard Henderson tcg_out_movext1_new_src(s, i1, scratch); 6382462e30eSRichard Henderson } 6392462e30eSRichard Henderson } else { 6402462e30eSRichard Henderson g_assert_not_reached(); 6412462e30eSRichard Henderson } 6422462e30eSRichard Henderson } 6432462e30eSRichard Henderson 644a417ef83SRichard Henderson /* 645a417ef83SRichard Henderson * Allocate a new TCGLabelQemuLdst entry. 646a417ef83SRichard Henderson */ 647a417ef83SRichard Henderson 648a417ef83SRichard Henderson __attribute__((unused)) 649a417ef83SRichard Henderson static TCGLabelQemuLdst *new_ldst_label(TCGContext *s) 650a417ef83SRichard Henderson { 651a417ef83SRichard Henderson TCGLabelQemuLdst *l = tcg_malloc(sizeof(*l)); 652a417ef83SRichard Henderson 653a417ef83SRichard Henderson memset(l, 0, sizeof(*l)); 654a417ef83SRichard Henderson QSIMPLEQ_INSERT_TAIL(&s->ldst_labels, l, next); 655a417ef83SRichard Henderson 656a417ef83SRichard Henderson return l; 657a417ef83SRichard Henderson } 658a417ef83SRichard Henderson 659a417ef83SRichard Henderson /* 660a417ef83SRichard Henderson * Allocate new constant pool entries. 661a417ef83SRichard Henderson */ 662a417ef83SRichard Henderson 663a417ef83SRichard Henderson typedef struct TCGLabelPoolData { 664a417ef83SRichard Henderson struct TCGLabelPoolData *next; 665a417ef83SRichard Henderson tcg_insn_unit *label; 666a417ef83SRichard Henderson intptr_t addend; 667a417ef83SRichard Henderson int rtype; 668a417ef83SRichard Henderson unsigned nlong; 669a417ef83SRichard Henderson tcg_target_ulong data[]; 670a417ef83SRichard Henderson } TCGLabelPoolData; 671a417ef83SRichard Henderson 672a417ef83SRichard Henderson static TCGLabelPoolData *new_pool_alloc(TCGContext *s, int nlong, int rtype, 673a417ef83SRichard Henderson tcg_insn_unit *label, intptr_t addend) 674a417ef83SRichard Henderson { 675a417ef83SRichard Henderson TCGLabelPoolData *n = tcg_malloc(sizeof(TCGLabelPoolData) 676a417ef83SRichard Henderson + sizeof(tcg_target_ulong) * nlong); 677a417ef83SRichard Henderson 678a417ef83SRichard Henderson n->label = label; 679a417ef83SRichard Henderson n->addend = addend; 680a417ef83SRichard Henderson n->rtype = rtype; 681a417ef83SRichard Henderson n->nlong = nlong; 682a417ef83SRichard Henderson return n; 683a417ef83SRichard Henderson } 684a417ef83SRichard Henderson 685a417ef83SRichard Henderson static void new_pool_insert(TCGContext *s, TCGLabelPoolData *n) 686a417ef83SRichard Henderson { 687a417ef83SRichard Henderson TCGLabelPoolData *i, **pp; 688a417ef83SRichard Henderson int nlong = n->nlong; 689a417ef83SRichard Henderson 690a417ef83SRichard Henderson /* Insertion sort on the pool. */ 691a417ef83SRichard Henderson for (pp = &s->pool_labels; (i = *pp) != NULL; pp = &i->next) { 692a417ef83SRichard Henderson if (nlong > i->nlong) { 693a417ef83SRichard Henderson break; 694a417ef83SRichard Henderson } 695a417ef83SRichard Henderson if (nlong < i->nlong) { 696a417ef83SRichard Henderson continue; 697a417ef83SRichard Henderson } 698a417ef83SRichard Henderson if (memcmp(n->data, i->data, sizeof(tcg_target_ulong) * nlong) >= 0) { 699a417ef83SRichard Henderson break; 700a417ef83SRichard Henderson } 701a417ef83SRichard Henderson } 702a417ef83SRichard Henderson n->next = *pp; 703a417ef83SRichard Henderson *pp = n; 704a417ef83SRichard Henderson } 705a417ef83SRichard Henderson 706a417ef83SRichard Henderson /* The "usual" for generic integer code. */ 707a417ef83SRichard Henderson __attribute__((unused)) 708a417ef83SRichard Henderson static void new_pool_label(TCGContext *s, tcg_target_ulong d, int rtype, 709a417ef83SRichard Henderson tcg_insn_unit *label, intptr_t addend) 710a417ef83SRichard Henderson { 711a417ef83SRichard Henderson TCGLabelPoolData *n = new_pool_alloc(s, 1, rtype, label, addend); 712a417ef83SRichard Henderson n->data[0] = d; 713a417ef83SRichard Henderson new_pool_insert(s, n); 714a417ef83SRichard Henderson } 715a417ef83SRichard Henderson 716a417ef83SRichard Henderson /* For v64 or v128, depending on the host. */ 717a417ef83SRichard Henderson __attribute__((unused)) 718a417ef83SRichard Henderson static void new_pool_l2(TCGContext *s, int rtype, tcg_insn_unit *label, 719a417ef83SRichard Henderson intptr_t addend, tcg_target_ulong d0, 720a417ef83SRichard Henderson tcg_target_ulong d1) 721a417ef83SRichard Henderson { 722a417ef83SRichard Henderson TCGLabelPoolData *n = new_pool_alloc(s, 2, rtype, label, addend); 723a417ef83SRichard Henderson n->data[0] = d0; 724a417ef83SRichard Henderson n->data[1] = d1; 725a417ef83SRichard Henderson new_pool_insert(s, n); 726a417ef83SRichard Henderson } 727a417ef83SRichard Henderson 728a417ef83SRichard Henderson /* For v128 or v256, depending on the host. */ 729a417ef83SRichard Henderson __attribute__((unused)) 730a417ef83SRichard Henderson static void new_pool_l4(TCGContext *s, int rtype, tcg_insn_unit *label, 731a417ef83SRichard Henderson intptr_t addend, tcg_target_ulong d0, 732a417ef83SRichard Henderson tcg_target_ulong d1, tcg_target_ulong d2, 733a417ef83SRichard Henderson tcg_target_ulong d3) 734a417ef83SRichard Henderson { 735a417ef83SRichard Henderson TCGLabelPoolData *n = new_pool_alloc(s, 4, rtype, label, addend); 736a417ef83SRichard Henderson n->data[0] = d0; 737a417ef83SRichard Henderson n->data[1] = d1; 738a417ef83SRichard Henderson n->data[2] = d2; 739a417ef83SRichard Henderson n->data[3] = d3; 740a417ef83SRichard Henderson new_pool_insert(s, n); 741a417ef83SRichard Henderson } 742a417ef83SRichard Henderson 743a417ef83SRichard Henderson /* For v256, for 32-bit host. */ 744a417ef83SRichard Henderson __attribute__((unused)) 745a417ef83SRichard Henderson static void new_pool_l8(TCGContext *s, int rtype, tcg_insn_unit *label, 746a417ef83SRichard Henderson intptr_t addend, tcg_target_ulong d0, 747a417ef83SRichard Henderson tcg_target_ulong d1, tcg_target_ulong d2, 748a417ef83SRichard Henderson tcg_target_ulong d3, tcg_target_ulong d4, 749a417ef83SRichard Henderson tcg_target_ulong d5, tcg_target_ulong d6, 750a417ef83SRichard Henderson tcg_target_ulong d7) 751a417ef83SRichard Henderson { 752a417ef83SRichard Henderson TCGLabelPoolData *n = new_pool_alloc(s, 8, rtype, label, addend); 753a417ef83SRichard Henderson n->data[0] = d0; 754a417ef83SRichard Henderson n->data[1] = d1; 755a417ef83SRichard Henderson n->data[2] = d2; 756a417ef83SRichard Henderson n->data[3] = d3; 757a417ef83SRichard Henderson n->data[4] = d4; 758a417ef83SRichard Henderson n->data[5] = d5; 759a417ef83SRichard Henderson n->data[6] = d6; 760a417ef83SRichard Henderson n->data[7] = d7; 761a417ef83SRichard Henderson new_pool_insert(s, n); 762a417ef83SRichard Henderson } 763a417ef83SRichard Henderson 764a417ef83SRichard Henderson /* 765a417ef83SRichard Henderson * Generate TB finalization at the end of block 766a417ef83SRichard Henderson */ 767a417ef83SRichard Henderson 768a417ef83SRichard Henderson static int tcg_out_ldst_finalize(TCGContext *s) 769a417ef83SRichard Henderson { 770a417ef83SRichard Henderson TCGLabelQemuLdst *lb; 771a417ef83SRichard Henderson 772a417ef83SRichard Henderson /* qemu_ld/st slow paths */ 773a417ef83SRichard Henderson QSIMPLEQ_FOREACH(lb, &s->ldst_labels, next) { 774a417ef83SRichard Henderson if (lb->is_ld 775a417ef83SRichard Henderson ? !tcg_out_qemu_ld_slow_path(s, lb) 776a417ef83SRichard Henderson : !tcg_out_qemu_st_slow_path(s, lb)) { 777a417ef83SRichard Henderson return -2; 778a417ef83SRichard Henderson } 779a417ef83SRichard Henderson 780a417ef83SRichard Henderson /* 781a417ef83SRichard Henderson * Test for (pending) buffer overflow. The assumption is that any 782a417ef83SRichard Henderson * one operation beginning below the high water mark cannot overrun 783a417ef83SRichard Henderson * the buffer completely. Thus we can test for overflow after 784a417ef83SRichard Henderson * generating code without having to check during generation. 785a417ef83SRichard Henderson */ 786a417ef83SRichard Henderson if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) { 787a417ef83SRichard Henderson return -1; 788a417ef83SRichard Henderson } 789a417ef83SRichard Henderson } 790a417ef83SRichard Henderson return 0; 791a417ef83SRichard Henderson } 792a417ef83SRichard Henderson 793a417ef83SRichard Henderson static int tcg_out_pool_finalize(TCGContext *s) 794a417ef83SRichard Henderson { 795a417ef83SRichard Henderson TCGLabelPoolData *p = s->pool_labels; 796a417ef83SRichard Henderson TCGLabelPoolData *l = NULL; 797a417ef83SRichard Henderson void *a; 798a417ef83SRichard Henderson 799a417ef83SRichard Henderson if (p == NULL) { 800a417ef83SRichard Henderson return 0; 801a417ef83SRichard Henderson } 802a417ef83SRichard Henderson 803a417ef83SRichard Henderson /* 804a417ef83SRichard Henderson * ??? Round up to qemu_icache_linesize, but then do not round 805a417ef83SRichard Henderson * again when allocating the next TranslationBlock structure. 806a417ef83SRichard Henderson */ 807a417ef83SRichard Henderson a = (void *)ROUND_UP((uintptr_t)s->code_ptr, 808a417ef83SRichard Henderson sizeof(tcg_target_ulong) * p->nlong); 809a417ef83SRichard Henderson tcg_out_nop_fill(s->code_ptr, (tcg_insn_unit *)a - s->code_ptr); 810a417ef83SRichard Henderson s->data_gen_ptr = a; 811a417ef83SRichard Henderson 812a417ef83SRichard Henderson for (; p != NULL; p = p->next) { 813a417ef83SRichard Henderson size_t size = sizeof(tcg_target_ulong) * p->nlong; 814a417ef83SRichard Henderson uintptr_t value; 815a417ef83SRichard Henderson 816a417ef83SRichard Henderson if (!l || l->nlong != p->nlong || memcmp(l->data, p->data, size)) { 817a417ef83SRichard Henderson if (unlikely(a > s->code_gen_highwater)) { 818a417ef83SRichard Henderson return -1; 819a417ef83SRichard Henderson } 820a417ef83SRichard Henderson memcpy(a, p->data, size); 821a417ef83SRichard Henderson a += size; 822a417ef83SRichard Henderson l = p; 823a417ef83SRichard Henderson } 824a417ef83SRichard Henderson 825a417ef83SRichard Henderson value = (uintptr_t)tcg_splitwx_to_rx(a) - size; 826a417ef83SRichard Henderson if (!patch_reloc(p->label, p->rtype, value, p->addend)) { 827a417ef83SRichard Henderson return -2; 828a417ef83SRichard Henderson } 829a417ef83SRichard Henderson } 830a417ef83SRichard Henderson 831a417ef83SRichard Henderson s->code_ptr = a; 832a417ef83SRichard Henderson return 0; 833a417ef83SRichard Henderson } 834a417ef83SRichard Henderson 8354c22e840SRichard Henderson #define C_PFX1(P, A) P##A 8364c22e840SRichard Henderson #define C_PFX2(P, A, B) P##A##_##B 8374c22e840SRichard Henderson #define C_PFX3(P, A, B, C) P##A##_##B##_##C 8384c22e840SRichard Henderson #define C_PFX4(P, A, B, C, D) P##A##_##B##_##C##_##D 8394c22e840SRichard Henderson #define C_PFX5(P, A, B, C, D, E) P##A##_##B##_##C##_##D##_##E 8404c22e840SRichard Henderson #define C_PFX6(P, A, B, C, D, E, F) P##A##_##B##_##C##_##D##_##E##_##F 8414c22e840SRichard Henderson 8424c22e840SRichard Henderson /* Define an enumeration for the various combinations. */ 8434c22e840SRichard Henderson 8444c22e840SRichard Henderson #define C_O0_I1(I1) C_PFX1(c_o0_i1_, I1), 8454c22e840SRichard Henderson #define C_O0_I2(I1, I2) C_PFX2(c_o0_i2_, I1, I2), 8464c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3) C_PFX3(c_o0_i3_, I1, I2, I3), 8474c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4) C_PFX4(c_o0_i4_, I1, I2, I3, I4), 8484c22e840SRichard Henderson 8494c22e840SRichard Henderson #define C_O1_I1(O1, I1) C_PFX2(c_o1_i1_, O1, I1), 8504c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2) C_PFX3(c_o1_i2_, O1, I1, I2), 8514c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3) C_PFX4(c_o1_i3_, O1, I1, I2, I3), 8524c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4) C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4), 8534c22e840SRichard Henderson 8544c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2) C_PFX3(c_n1_i2_, O1, I1, I2), 855ca5bed07SRichard Henderson #define C_N1O1_I1(O1, O2, I1) C_PFX3(c_n1o1_i1_, O1, O2, I1), 856fa645b48SRichard Henderson #define C_N2_I1(O1, O2, I1) C_PFX3(c_n2_i1_, O1, O2, I1), 8574c22e840SRichard Henderson 8584c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1) C_PFX3(c_o2_i1_, O1, O2, I1), 8594c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2) C_PFX4(c_o2_i2_, O1, O2, I1, I2), 8604c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3) C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3), 8614c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4), 86222d2e535SIlya Leoshkevich #define C_N1_O1_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_n1_o1_i4_, O1, O2, I1, I2, I3, I4), 8634c22e840SRichard Henderson 8644c22e840SRichard Henderson typedef enum { 865da43e5e6SRichard Henderson C_NotImplemented = -1, 8664c22e840SRichard Henderson #include "tcg-target-con-set.h" 8674c22e840SRichard Henderson } TCGConstraintSetIndex; 8684c22e840SRichard Henderson 8696323b363SRichard Henderson static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode, TCGType, unsigned); 8704c22e840SRichard Henderson 8714c22e840SRichard Henderson #undef C_O0_I1 8724c22e840SRichard Henderson #undef C_O0_I2 8734c22e840SRichard Henderson #undef C_O0_I3 8744c22e840SRichard Henderson #undef C_O0_I4 8754c22e840SRichard Henderson #undef C_O1_I1 8764c22e840SRichard Henderson #undef C_O1_I2 8774c22e840SRichard Henderson #undef C_O1_I3 8784c22e840SRichard Henderson #undef C_O1_I4 8794c22e840SRichard Henderson #undef C_N1_I2 880ca5bed07SRichard Henderson #undef C_N1O1_I1 881fa645b48SRichard Henderson #undef C_N2_I1 8824c22e840SRichard Henderson #undef C_O2_I1 8834c22e840SRichard Henderson #undef C_O2_I2 8844c22e840SRichard Henderson #undef C_O2_I3 8854c22e840SRichard Henderson #undef C_O2_I4 88622d2e535SIlya Leoshkevich #undef C_N1_O1_I4 8874c22e840SRichard Henderson 8884c22e840SRichard Henderson /* Put all of the constraint sets into an array, indexed by the enum. */ 8894c22e840SRichard Henderson 8903e80824eSRichard Henderson typedef struct TCGConstraintSet { 8913e80824eSRichard Henderson uint8_t nb_oargs, nb_iargs; 8923e80824eSRichard Henderson const char *args_ct_str[TCG_MAX_OP_ARGS]; 8933e80824eSRichard Henderson } TCGConstraintSet; 8944c22e840SRichard Henderson 8953e80824eSRichard Henderson #define C_O0_I1(I1) { 0, 1, { #I1 } }, 8963e80824eSRichard Henderson #define C_O0_I2(I1, I2) { 0, 2, { #I1, #I2 } }, 8973e80824eSRichard Henderson #define C_O0_I3(I1, I2, I3) { 0, 3, { #I1, #I2, #I3 } }, 8983e80824eSRichard Henderson #define C_O0_I4(I1, I2, I3, I4) { 0, 4, { #I1, #I2, #I3, #I4 } }, 8994c22e840SRichard Henderson 9003e80824eSRichard Henderson #define C_O1_I1(O1, I1) { 1, 1, { #O1, #I1 } }, 9013e80824eSRichard Henderson #define C_O1_I2(O1, I1, I2) { 1, 2, { #O1, #I1, #I2 } }, 9023e80824eSRichard Henderson #define C_O1_I3(O1, I1, I2, I3) { 1, 3, { #O1, #I1, #I2, #I3 } }, 9033e80824eSRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4) { 1, 4, { #O1, #I1, #I2, #I3, #I4 } }, 9044c22e840SRichard Henderson 9053e80824eSRichard Henderson #define C_N1_I2(O1, I1, I2) { 1, 2, { "&" #O1, #I1, #I2 } }, 9063e80824eSRichard Henderson #define C_N1O1_I1(O1, O2, I1) { 2, 1, { "&" #O1, #O2, #I1 } }, 9073e80824eSRichard Henderson #define C_N2_I1(O1, O2, I1) { 2, 1, { "&" #O1, "&" #O2, #I1 } }, 9084c22e840SRichard Henderson 9093e80824eSRichard Henderson #define C_O2_I1(O1, O2, I1) { 2, 1, { #O1, #O2, #I1 } }, 9103e80824eSRichard Henderson #define C_O2_I2(O1, O2, I1, I2) { 2, 2, { #O1, #O2, #I1, #I2 } }, 9113e80824eSRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3) { 2, 3, { #O1, #O2, #I1, #I2, #I3 } }, 9123e80824eSRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) { 2, 4, { #O1, #O2, #I1, #I2, #I3, #I4 } }, 9133e80824eSRichard Henderson #define C_N1_O1_I4(O1, O2, I1, I2, I3, I4) { 2, 4, { "&" #O1, #O2, #I1, #I2, #I3, #I4 } }, 9143e80824eSRichard Henderson 9153e80824eSRichard Henderson static const TCGConstraintSet constraint_sets[] = { 9164c22e840SRichard Henderson #include "tcg-target-con-set.h" 9174c22e840SRichard Henderson }; 9184c22e840SRichard Henderson 9194c22e840SRichard Henderson #undef C_O0_I1 9204c22e840SRichard Henderson #undef C_O0_I2 9214c22e840SRichard Henderson #undef C_O0_I3 9224c22e840SRichard Henderson #undef C_O0_I4 9234c22e840SRichard Henderson #undef C_O1_I1 9244c22e840SRichard Henderson #undef C_O1_I2 9254c22e840SRichard Henderson #undef C_O1_I3 9264c22e840SRichard Henderson #undef C_O1_I4 9274c22e840SRichard Henderson #undef C_N1_I2 928ca5bed07SRichard Henderson #undef C_N1O1_I1 929fa645b48SRichard Henderson #undef C_N2_I1 9304c22e840SRichard Henderson #undef C_O2_I1 9314c22e840SRichard Henderson #undef C_O2_I2 9324c22e840SRichard Henderson #undef C_O2_I3 9334c22e840SRichard Henderson #undef C_O2_I4 93422d2e535SIlya Leoshkevich #undef C_N1_O1_I4 9354c22e840SRichard Henderson 9364c22e840SRichard Henderson /* Expand the enumerator to be returned from tcg_target_op_def(). */ 9374c22e840SRichard Henderson 9384c22e840SRichard Henderson #define C_O0_I1(I1) C_PFX1(c_o0_i1_, I1) 9394c22e840SRichard Henderson #define C_O0_I2(I1, I2) C_PFX2(c_o0_i2_, I1, I2) 9404c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3) C_PFX3(c_o0_i3_, I1, I2, I3) 9414c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4) C_PFX4(c_o0_i4_, I1, I2, I3, I4) 9424c22e840SRichard Henderson 9434c22e840SRichard Henderson #define C_O1_I1(O1, I1) C_PFX2(c_o1_i1_, O1, I1) 9444c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2) C_PFX3(c_o1_i2_, O1, I1, I2) 9454c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3) C_PFX4(c_o1_i3_, O1, I1, I2, I3) 9464c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4) C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4) 9474c22e840SRichard Henderson 9484c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2) C_PFX3(c_n1_i2_, O1, I1, I2) 949ca5bed07SRichard Henderson #define C_N1O1_I1(O1, O2, I1) C_PFX3(c_n1o1_i1_, O1, O2, I1) 950fa645b48SRichard Henderson #define C_N2_I1(O1, O2, I1) C_PFX3(c_n2_i1_, O1, O2, I1) 9514c22e840SRichard Henderson 9524c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1) C_PFX3(c_o2_i1_, O1, O2, I1) 9534c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2) C_PFX4(c_o2_i2_, O1, O2, I1, I2) 9544c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3) C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3) 9554c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4) 95622d2e535SIlya Leoshkevich #define C_N1_O1_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_n1_o1_i4_, O1, O2, I1, I2, I3, I4) 9574c22e840SRichard Henderson 958139c1837SPaolo Bonzini #include "tcg-target.c.inc" 959c896fe29Sbellard 9607857ee11SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 9617857ee11SRichard Henderson /* Validate CPUTLBDescFast placement. */ 9627857ee11SRichard Henderson QEMU_BUILD_BUG_ON((int)(offsetof(CPUNegativeOffsetState, tlb.f[0]) - 9637857ee11SRichard Henderson sizeof(CPUNegativeOffsetState)) 9647857ee11SRichard Henderson < MIN_TLB_MASK_TABLE_OFS); 9657857ee11SRichard Henderson #endif 9667857ee11SRichard Henderson 967e8feb96fSEmilio G. Cota /* 9683468b59eSEmilio G. Cota * All TCG threads except the parent (i.e. the one that called tcg_context_init 9693468b59eSEmilio G. Cota * and registered the target's TCG globals) must register with this function 9703468b59eSEmilio G. Cota * before initiating translation. 9713468b59eSEmilio G. Cota * 9723468b59eSEmilio G. Cota * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation 9733468b59eSEmilio G. Cota * of tcg_region_init() for the reasoning behind this. 9743468b59eSEmilio G. Cota * 9757893e42dSPhilippe Mathieu-Daudé * In system-mode each caller registers its context in tcg_ctxs[]. Note that in 9767893e42dSPhilippe Mathieu-Daudé * system-mode tcg_ctxs[] does not track tcg_ctx_init, since the initial context 9773468b59eSEmilio G. Cota * is not used anymore for translation once this function is called. 9783468b59eSEmilio G. Cota * 9797893e42dSPhilippe Mathieu-Daudé * Not tracking tcg_init_ctx in tcg_ctxs[] in system-mode keeps code that 9807893e42dSPhilippe Mathieu-Daudé * iterates over the array (e.g. tcg_code_size() the same for both system/user 9817893e42dSPhilippe Mathieu-Daudé * modes. 9823468b59eSEmilio G. Cota */ 9833468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY 9843468b59eSEmilio G. Cota void tcg_register_thread(void) 9853468b59eSEmilio G. Cota { 9863468b59eSEmilio G. Cota tcg_ctx = &tcg_init_ctx; 9873468b59eSEmilio G. Cota } 9883468b59eSEmilio G. Cota #else 9893468b59eSEmilio G. Cota void tcg_register_thread(void) 9903468b59eSEmilio G. Cota { 9913468b59eSEmilio G. Cota TCGContext *s = g_malloc(sizeof(*s)); 9923468b59eSEmilio G. Cota unsigned int i, n; 9933468b59eSEmilio G. Cota 9943468b59eSEmilio G. Cota *s = tcg_init_ctx; 9953468b59eSEmilio G. Cota 9963468b59eSEmilio G. Cota /* Relink mem_base. */ 9973468b59eSEmilio G. Cota for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) { 9983468b59eSEmilio G. Cota if (tcg_init_ctx.temps[i].mem_base) { 9993468b59eSEmilio G. Cota ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps; 10003468b59eSEmilio G. Cota tcg_debug_assert(b >= 0 && b < n); 10013468b59eSEmilio G. Cota s->temps[i].mem_base = &s->temps[b]; 10023468b59eSEmilio G. Cota } 10033468b59eSEmilio G. Cota } 10043468b59eSEmilio G. Cota 10053468b59eSEmilio G. Cota /* Claim an entry in tcg_ctxs */ 10060e2d61cfSRichard Henderson n = qatomic_fetch_inc(&tcg_cur_ctxs); 10070e2d61cfSRichard Henderson g_assert(n < tcg_max_ctxs); 1008d73415a3SStefan Hajnoczi qatomic_set(&tcg_ctxs[n], s); 10093468b59eSEmilio G. Cota 101038b47b19SEmilio G. Cota if (n > 0) { 1011bf042e8eSRichard Henderson tcg_region_initial_alloc(s); 101238b47b19SEmilio G. Cota } 101338b47b19SEmilio G. Cota 10143468b59eSEmilio G. Cota tcg_ctx = s; 10153468b59eSEmilio G. Cota } 10163468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */ 10173468b59eSEmilio G. Cota 1018c896fe29Sbellard /* pool based memory allocation */ 1019c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size) 1020c896fe29Sbellard { 1021c896fe29Sbellard TCGPool *p; 1022c896fe29Sbellard int pool_size; 1023c896fe29Sbellard 1024c896fe29Sbellard if (size > TCG_POOL_CHUNK_SIZE) { 1025c896fe29Sbellard /* big malloc: insert a new pool (XXX: could optimize) */ 10267267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + size); 1027c896fe29Sbellard p->size = size; 10284055299eSKirill Batuzov p->next = s->pool_first_large; 10294055299eSKirill Batuzov s->pool_first_large = p; 10304055299eSKirill Batuzov return p->data; 1031c896fe29Sbellard } else { 1032c896fe29Sbellard p = s->pool_current; 1033c896fe29Sbellard if (!p) { 1034c896fe29Sbellard p = s->pool_first; 1035c896fe29Sbellard if (!p) 1036c896fe29Sbellard goto new_pool; 1037c896fe29Sbellard } else { 1038c896fe29Sbellard if (!p->next) { 1039c896fe29Sbellard new_pool: 1040c896fe29Sbellard pool_size = TCG_POOL_CHUNK_SIZE; 10417267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + pool_size); 1042c896fe29Sbellard p->size = pool_size; 1043c896fe29Sbellard p->next = NULL; 1044a813e36fSRichard Henderson if (s->pool_current) { 1045c896fe29Sbellard s->pool_current->next = p; 1046a813e36fSRichard Henderson } else { 1047c896fe29Sbellard s->pool_first = p; 1048a813e36fSRichard Henderson } 1049c896fe29Sbellard } else { 1050c896fe29Sbellard p = p->next; 1051c896fe29Sbellard } 1052c896fe29Sbellard } 1053c896fe29Sbellard } 1054c896fe29Sbellard s->pool_current = p; 1055c896fe29Sbellard s->pool_cur = p->data + size; 1056c896fe29Sbellard s->pool_end = p->data + p->size; 1057c896fe29Sbellard return p->data; 1058c896fe29Sbellard } 1059c896fe29Sbellard 1060c896fe29Sbellard void tcg_pool_reset(TCGContext *s) 1061c896fe29Sbellard { 10624055299eSKirill Batuzov TCGPool *p, *t; 10634055299eSKirill Batuzov for (p = s->pool_first_large; p; p = t) { 10644055299eSKirill Batuzov t = p->next; 10654055299eSKirill Batuzov g_free(p); 10664055299eSKirill Batuzov } 10674055299eSKirill Batuzov s->pool_first_large = NULL; 1068c896fe29Sbellard s->pool_cur = s->pool_end = NULL; 1069c896fe29Sbellard s->pool_current = NULL; 1070c896fe29Sbellard } 1071c896fe29Sbellard 10728429a1caSRichard Henderson /* 10738429a1caSRichard Henderson * Create TCGHelperInfo structures for "tcg/tcg-ldst.h" functions, 10748429a1caSRichard Henderson * akin to what "exec/helper-tcg.h" does with DEF_HELPER_FLAGS_N. 10758429a1caSRichard Henderson * We only use these for layout in tcg_out_ld_helper_ret and 10768429a1caSRichard Henderson * tcg_out_st_helper_args, and share them between several of 10778429a1caSRichard Henderson * the helpers, with the end result that it's easier to build manually. 10788429a1caSRichard Henderson */ 10798429a1caSRichard Henderson 10808429a1caSRichard Henderson #if TCG_TARGET_REG_BITS == 32 10818429a1caSRichard Henderson # define dh_typecode_ttl dh_typecode_i32 10828429a1caSRichard Henderson #else 10838429a1caSRichard Henderson # define dh_typecode_ttl dh_typecode_i64 10848429a1caSRichard Henderson #endif 10858429a1caSRichard Henderson 10868429a1caSRichard Henderson static TCGHelperInfo info_helper_ld32_mmu = { 10878429a1caSRichard Henderson .flags = TCG_CALL_NO_WG, 10888429a1caSRichard Henderson .typemask = dh_typemask(ttl, 0) /* return tcg_target_ulong */ 10898429a1caSRichard Henderson | dh_typemask(env, 1) 109024e46e6cSRichard Henderson | dh_typemask(i64, 2) /* uint64_t addr */ 10918429a1caSRichard Henderson | dh_typemask(i32, 3) /* unsigned oi */ 10928429a1caSRichard Henderson | dh_typemask(ptr, 4) /* uintptr_t ra */ 10938429a1caSRichard Henderson }; 10948429a1caSRichard Henderson 10958429a1caSRichard Henderson static TCGHelperInfo info_helper_ld64_mmu = { 10968429a1caSRichard Henderson .flags = TCG_CALL_NO_WG, 10978429a1caSRichard Henderson .typemask = dh_typemask(i64, 0) /* return uint64_t */ 10988429a1caSRichard Henderson | dh_typemask(env, 1) 109924e46e6cSRichard Henderson | dh_typemask(i64, 2) /* uint64_t addr */ 11008429a1caSRichard Henderson | dh_typemask(i32, 3) /* unsigned oi */ 11018429a1caSRichard Henderson | dh_typemask(ptr, 4) /* uintptr_t ra */ 11028429a1caSRichard Henderson }; 11038429a1caSRichard Henderson 1104ebebea53SRichard Henderson static TCGHelperInfo info_helper_ld128_mmu = { 1105ebebea53SRichard Henderson .flags = TCG_CALL_NO_WG, 1106ebebea53SRichard Henderson .typemask = dh_typemask(i128, 0) /* return Int128 */ 1107ebebea53SRichard Henderson | dh_typemask(env, 1) 110824e46e6cSRichard Henderson | dh_typemask(i64, 2) /* uint64_t addr */ 1109ebebea53SRichard Henderson | dh_typemask(i32, 3) /* unsigned oi */ 1110ebebea53SRichard Henderson | dh_typemask(ptr, 4) /* uintptr_t ra */ 1111ebebea53SRichard Henderson }; 1112ebebea53SRichard Henderson 11138429a1caSRichard Henderson static TCGHelperInfo info_helper_st32_mmu = { 11148429a1caSRichard Henderson .flags = TCG_CALL_NO_WG, 11158429a1caSRichard Henderson .typemask = dh_typemask(void, 0) 11168429a1caSRichard Henderson | dh_typemask(env, 1) 111724e46e6cSRichard Henderson | dh_typemask(i64, 2) /* uint64_t addr */ 11188429a1caSRichard Henderson | dh_typemask(i32, 3) /* uint32_t data */ 11198429a1caSRichard Henderson | dh_typemask(i32, 4) /* unsigned oi */ 11208429a1caSRichard Henderson | dh_typemask(ptr, 5) /* uintptr_t ra */ 11218429a1caSRichard Henderson }; 11228429a1caSRichard Henderson 11238429a1caSRichard Henderson static TCGHelperInfo info_helper_st64_mmu = { 11248429a1caSRichard Henderson .flags = TCG_CALL_NO_WG, 11258429a1caSRichard Henderson .typemask = dh_typemask(void, 0) 11268429a1caSRichard Henderson | dh_typemask(env, 1) 112724e46e6cSRichard Henderson | dh_typemask(i64, 2) /* uint64_t addr */ 11288429a1caSRichard Henderson | dh_typemask(i64, 3) /* uint64_t data */ 11298429a1caSRichard Henderson | dh_typemask(i32, 4) /* unsigned oi */ 11308429a1caSRichard Henderson | dh_typemask(ptr, 5) /* uintptr_t ra */ 11318429a1caSRichard Henderson }; 11328429a1caSRichard Henderson 1133ebebea53SRichard Henderson static TCGHelperInfo info_helper_st128_mmu = { 1134ebebea53SRichard Henderson .flags = TCG_CALL_NO_WG, 1135ebebea53SRichard Henderson .typemask = dh_typemask(void, 0) 1136ebebea53SRichard Henderson | dh_typemask(env, 1) 113724e46e6cSRichard Henderson | dh_typemask(i64, 2) /* uint64_t addr */ 1138ebebea53SRichard Henderson | dh_typemask(i128, 3) /* Int128 data */ 1139ebebea53SRichard Henderson | dh_typemask(i32, 4) /* unsigned oi */ 1140ebebea53SRichard Henderson | dh_typemask(ptr, 5) /* uintptr_t ra */ 1141ebebea53SRichard Henderson }; 1142ebebea53SRichard Henderson 114322f15579SRichard Henderson #ifdef CONFIG_TCG_INTERPRETER 1144c6ef8c7bSPhilippe Mathieu-Daudé static ffi_type *typecode_to_ffi(int argmask) 1145c6ef8c7bSPhilippe Mathieu-Daudé { 1146e9709e17SRichard Henderson /* 1147e9709e17SRichard Henderson * libffi does not support __int128_t, so we have forced Int128 1148e9709e17SRichard Henderson * to use the structure definition instead of the builtin type. 1149e9709e17SRichard Henderson */ 1150e9709e17SRichard Henderson static ffi_type *ffi_type_i128_elements[3] = { 1151e9709e17SRichard Henderson &ffi_type_uint64, 1152e9709e17SRichard Henderson &ffi_type_uint64, 1153e9709e17SRichard Henderson NULL 1154e9709e17SRichard Henderson }; 1155e9709e17SRichard Henderson static ffi_type ffi_type_i128 = { 1156e9709e17SRichard Henderson .size = 16, 1157e9709e17SRichard Henderson .alignment = __alignof__(Int128), 1158e9709e17SRichard Henderson .type = FFI_TYPE_STRUCT, 1159e9709e17SRichard Henderson .elements = ffi_type_i128_elements, 1160e9709e17SRichard Henderson }; 1161e9709e17SRichard Henderson 1162c6ef8c7bSPhilippe Mathieu-Daudé switch (argmask) { 1163c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_void: 1164c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_void; 1165c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_i32: 1166c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_uint32; 1167c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_s32: 1168c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_sint32; 1169c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_i64: 1170c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_uint64; 1171c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_s64: 1172c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_sint64; 1173c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_ptr: 1174c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_pointer; 1175e9709e17SRichard Henderson case dh_typecode_i128: 1176e9709e17SRichard Henderson return &ffi_type_i128; 1177c6ef8c7bSPhilippe Mathieu-Daudé } 1178c6ef8c7bSPhilippe Mathieu-Daudé g_assert_not_reached(); 1179c6ef8c7bSPhilippe Mathieu-Daudé } 11800c22e176SPhilippe Mathieu-Daudé 1181d53106c9SRichard Henderson static ffi_cif *init_ffi_layout(TCGHelperInfo *info) 11820c22e176SPhilippe Mathieu-Daudé { 1183f9c4bb80SRichard Henderson unsigned typemask = info->typemask; 11840c22e176SPhilippe Mathieu-Daudé struct { 11850c22e176SPhilippe Mathieu-Daudé ffi_cif cif; 11860c22e176SPhilippe Mathieu-Daudé ffi_type *args[]; 11870c22e176SPhilippe Mathieu-Daudé } *ca; 11880c22e176SPhilippe Mathieu-Daudé ffi_status status; 11890c22e176SPhilippe Mathieu-Daudé int nargs; 11900c22e176SPhilippe Mathieu-Daudé 11910c22e176SPhilippe Mathieu-Daudé /* Ignoring the return type, find the last non-zero field. */ 11920c22e176SPhilippe Mathieu-Daudé nargs = 32 - clz32(typemask >> 3); 11930c22e176SPhilippe Mathieu-Daudé nargs = DIV_ROUND_UP(nargs, 3); 1194e9709e17SRichard Henderson assert(nargs <= MAX_CALL_IARGS); 11950c22e176SPhilippe Mathieu-Daudé 11960c22e176SPhilippe Mathieu-Daudé ca = g_malloc0(sizeof(*ca) + nargs * sizeof(ffi_type *)); 11970c22e176SPhilippe Mathieu-Daudé ca->cif.rtype = typecode_to_ffi(typemask & 7); 11980c22e176SPhilippe Mathieu-Daudé ca->cif.nargs = nargs; 11990c22e176SPhilippe Mathieu-Daudé 12000c22e176SPhilippe Mathieu-Daudé if (nargs != 0) { 12010c22e176SPhilippe Mathieu-Daudé ca->cif.arg_types = ca->args; 12020c22e176SPhilippe Mathieu-Daudé for (int j = 0; j < nargs; ++j) { 12030c22e176SPhilippe Mathieu-Daudé int typecode = extract32(typemask, (j + 1) * 3, 3); 12040c22e176SPhilippe Mathieu-Daudé ca->args[j] = typecode_to_ffi(typecode); 12050c22e176SPhilippe Mathieu-Daudé } 12060c22e176SPhilippe Mathieu-Daudé } 12070c22e176SPhilippe Mathieu-Daudé 12080c22e176SPhilippe Mathieu-Daudé status = ffi_prep_cif(&ca->cif, FFI_DEFAULT_ABI, nargs, 12090c22e176SPhilippe Mathieu-Daudé ca->cif.rtype, ca->cif.arg_types); 12100c22e176SPhilippe Mathieu-Daudé assert(status == FFI_OK); 12110c22e176SPhilippe Mathieu-Daudé 1212d53106c9SRichard Henderson return &ca->cif; 12130c22e176SPhilippe Mathieu-Daudé } 1214f9c4bb80SRichard Henderson 1215d53106c9SRichard Henderson #define HELPER_INFO_INIT(I) (&(I)->cif) 1216d53106c9SRichard Henderson #define HELPER_INFO_INIT_VAL(I) init_ffi_layout(I) 1217d53106c9SRichard Henderson #else 1218d53106c9SRichard Henderson #define HELPER_INFO_INIT(I) (&(I)->init) 1219d53106c9SRichard Henderson #define HELPER_INFO_INIT_VAL(I) 1 12200c22e176SPhilippe Mathieu-Daudé #endif /* CONFIG_TCG_INTERPRETER */ 122122f15579SRichard Henderson 1222338b61e9SRichard Henderson static inline bool arg_slot_reg_p(unsigned arg_slot) 1223338b61e9SRichard Henderson { 1224338b61e9SRichard Henderson /* 1225338b61e9SRichard Henderson * Split the sizeof away from the comparison to avoid Werror from 1226338b61e9SRichard Henderson * "unsigned < 0 is always false", when iarg_regs is empty. 1227338b61e9SRichard Henderson */ 1228338b61e9SRichard Henderson unsigned nreg = ARRAY_SIZE(tcg_target_call_iarg_regs); 1229338b61e9SRichard Henderson return arg_slot < nreg; 1230338b61e9SRichard Henderson } 1231338b61e9SRichard Henderson 1232d78e4a4fSRichard Henderson static inline int arg_slot_stk_ofs(unsigned arg_slot) 1233d78e4a4fSRichard Henderson { 1234d78e4a4fSRichard Henderson unsigned max = TCG_STATIC_CALL_ARGS_SIZE / sizeof(tcg_target_long); 1235d78e4a4fSRichard Henderson unsigned stk_slot = arg_slot - ARRAY_SIZE(tcg_target_call_iarg_regs); 1236d78e4a4fSRichard Henderson 1237d78e4a4fSRichard Henderson tcg_debug_assert(stk_slot < max); 1238d78e4a4fSRichard Henderson return TCG_TARGET_CALL_STACK_OFFSET + stk_slot * sizeof(tcg_target_long); 1239d78e4a4fSRichard Henderson } 1240d78e4a4fSRichard Henderson 124139004a71SRichard Henderson typedef struct TCGCumulativeArgs { 124239004a71SRichard Henderson int arg_idx; /* tcg_gen_callN args[] */ 124339004a71SRichard Henderson int info_in_idx; /* TCGHelperInfo in[] */ 124439004a71SRichard Henderson int arg_slot; /* regs+stack slot */ 124539004a71SRichard Henderson int ref_slot; /* stack slots for references */ 124639004a71SRichard Henderson } TCGCumulativeArgs; 124739004a71SRichard Henderson 124839004a71SRichard Henderson static void layout_arg_even(TCGCumulativeArgs *cum) 124939004a71SRichard Henderson { 125039004a71SRichard Henderson cum->arg_slot += cum->arg_slot & 1; 125139004a71SRichard Henderson } 125239004a71SRichard Henderson 125339004a71SRichard Henderson static void layout_arg_1(TCGCumulativeArgs *cum, TCGHelperInfo *info, 125439004a71SRichard Henderson TCGCallArgumentKind kind) 125539004a71SRichard Henderson { 125639004a71SRichard Henderson TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx]; 125739004a71SRichard Henderson 125839004a71SRichard Henderson *loc = (TCGCallArgumentLoc){ 125939004a71SRichard Henderson .kind = kind, 126039004a71SRichard Henderson .arg_idx = cum->arg_idx, 126139004a71SRichard Henderson .arg_slot = cum->arg_slot, 126239004a71SRichard Henderson }; 126339004a71SRichard Henderson cum->info_in_idx++; 126439004a71SRichard Henderson cum->arg_slot++; 126539004a71SRichard Henderson } 126639004a71SRichard Henderson 126739004a71SRichard Henderson static void layout_arg_normal_n(TCGCumulativeArgs *cum, 126839004a71SRichard Henderson TCGHelperInfo *info, int n) 126939004a71SRichard Henderson { 127039004a71SRichard Henderson TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx]; 127139004a71SRichard Henderson 127239004a71SRichard Henderson for (int i = 0; i < n; ++i) { 127339004a71SRichard Henderson /* Layout all using the same arg_idx, adjusting the subindex. */ 127439004a71SRichard Henderson loc[i] = (TCGCallArgumentLoc){ 127539004a71SRichard Henderson .kind = TCG_CALL_ARG_NORMAL, 127639004a71SRichard Henderson .arg_idx = cum->arg_idx, 127739004a71SRichard Henderson .tmp_subindex = i, 127839004a71SRichard Henderson .arg_slot = cum->arg_slot + i, 127939004a71SRichard Henderson }; 128039004a71SRichard Henderson } 128139004a71SRichard Henderson cum->info_in_idx += n; 128239004a71SRichard Henderson cum->arg_slot += n; 128339004a71SRichard Henderson } 128439004a71SRichard Henderson 1285313bdea8SRichard Henderson static void layout_arg_by_ref(TCGCumulativeArgs *cum, TCGHelperInfo *info) 1286313bdea8SRichard Henderson { 1287313bdea8SRichard Henderson TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx]; 1288313bdea8SRichard Henderson int n = 128 / TCG_TARGET_REG_BITS; 1289313bdea8SRichard Henderson 1290313bdea8SRichard Henderson /* The first subindex carries the pointer. */ 1291313bdea8SRichard Henderson layout_arg_1(cum, info, TCG_CALL_ARG_BY_REF); 1292313bdea8SRichard Henderson 1293313bdea8SRichard Henderson /* 1294313bdea8SRichard Henderson * The callee is allowed to clobber memory associated with 1295313bdea8SRichard Henderson * structure pass by-reference. Therefore we must make copies. 1296313bdea8SRichard Henderson * Allocate space from "ref_slot", which will be adjusted to 1297313bdea8SRichard Henderson * follow the parameters on the stack. 1298313bdea8SRichard Henderson */ 1299313bdea8SRichard Henderson loc[0].ref_slot = cum->ref_slot; 1300313bdea8SRichard Henderson 1301313bdea8SRichard Henderson /* 1302313bdea8SRichard Henderson * Subsequent words also go into the reference slot, but 1303313bdea8SRichard Henderson * do not accumulate into the regular arguments. 1304313bdea8SRichard Henderson */ 1305313bdea8SRichard Henderson for (int i = 1; i < n; ++i) { 1306313bdea8SRichard Henderson loc[i] = (TCGCallArgumentLoc){ 1307313bdea8SRichard Henderson .kind = TCG_CALL_ARG_BY_REF_N, 1308313bdea8SRichard Henderson .arg_idx = cum->arg_idx, 1309313bdea8SRichard Henderson .tmp_subindex = i, 1310313bdea8SRichard Henderson .ref_slot = cum->ref_slot + i, 1311313bdea8SRichard Henderson }; 1312313bdea8SRichard Henderson } 1313e18ed26cSRichard Henderson cum->info_in_idx += n - 1; /* i=0 accounted for in layout_arg_1 */ 1314313bdea8SRichard Henderson cum->ref_slot += n; 1315313bdea8SRichard Henderson } 1316313bdea8SRichard Henderson 131739004a71SRichard Henderson static void init_call_layout(TCGHelperInfo *info) 131839004a71SRichard Henderson { 131939004a71SRichard Henderson int max_reg_slots = ARRAY_SIZE(tcg_target_call_iarg_regs); 132039004a71SRichard Henderson int max_stk_slots = TCG_STATIC_CALL_ARGS_SIZE / sizeof(tcg_target_long); 132139004a71SRichard Henderson unsigned typemask = info->typemask; 132239004a71SRichard Henderson unsigned typecode; 132339004a71SRichard Henderson TCGCumulativeArgs cum = { }; 132439004a71SRichard Henderson 132539004a71SRichard Henderson /* 132639004a71SRichard Henderson * Parse and place any function return value. 132739004a71SRichard Henderson */ 132839004a71SRichard Henderson typecode = typemask & 7; 132939004a71SRichard Henderson switch (typecode) { 133039004a71SRichard Henderson case dh_typecode_void: 133139004a71SRichard Henderson info->nr_out = 0; 133239004a71SRichard Henderson break; 133339004a71SRichard Henderson case dh_typecode_i32: 133439004a71SRichard Henderson case dh_typecode_s32: 133539004a71SRichard Henderson case dh_typecode_ptr: 133639004a71SRichard Henderson info->nr_out = 1; 133739004a71SRichard Henderson info->out_kind = TCG_CALL_RET_NORMAL; 133839004a71SRichard Henderson break; 133939004a71SRichard Henderson case dh_typecode_i64: 134039004a71SRichard Henderson case dh_typecode_s64: 134139004a71SRichard Henderson info->nr_out = 64 / TCG_TARGET_REG_BITS; 134239004a71SRichard Henderson info->out_kind = TCG_CALL_RET_NORMAL; 13435e3d0c19SRichard Henderson /* Query the last register now to trigger any assert early. */ 13445e3d0c19SRichard Henderson tcg_target_call_oarg_reg(info->out_kind, info->nr_out - 1); 1345466d3759SRichard Henderson break; 1346466d3759SRichard Henderson case dh_typecode_i128: 1347466d3759SRichard Henderson info->nr_out = 128 / TCG_TARGET_REG_BITS; 13485427a9a7SRichard Henderson info->out_kind = TCG_TARGET_CALL_RET_I128; 13495427a9a7SRichard Henderson switch (TCG_TARGET_CALL_RET_I128) { 1350466d3759SRichard Henderson case TCG_CALL_RET_NORMAL: 13515e3d0c19SRichard Henderson /* Query the last register now to trigger any assert early. */ 13525e3d0c19SRichard Henderson tcg_target_call_oarg_reg(info->out_kind, info->nr_out - 1); 1353466d3759SRichard Henderson break; 1354c6556aa0SRichard Henderson case TCG_CALL_RET_BY_VEC: 1355c6556aa0SRichard Henderson /* Query the single register now to trigger any assert early. */ 1356c6556aa0SRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0); 1357c6556aa0SRichard Henderson break; 1358313bdea8SRichard Henderson case TCG_CALL_RET_BY_REF: 1359313bdea8SRichard Henderson /* 1360313bdea8SRichard Henderson * Allocate the first argument to the output. 1361313bdea8SRichard Henderson * We don't need to store this anywhere, just make it 1362313bdea8SRichard Henderson * unavailable for use in the input loop below. 1363313bdea8SRichard Henderson */ 1364313bdea8SRichard Henderson cum.arg_slot = 1; 1365313bdea8SRichard Henderson break; 1366466d3759SRichard Henderson default: 1367466d3759SRichard Henderson qemu_build_not_reached(); 1368466d3759SRichard Henderson } 136939004a71SRichard Henderson break; 137039004a71SRichard Henderson default: 137139004a71SRichard Henderson g_assert_not_reached(); 137239004a71SRichard Henderson } 137339004a71SRichard Henderson 137439004a71SRichard Henderson /* 137539004a71SRichard Henderson * Parse and place function arguments. 137639004a71SRichard Henderson */ 137739004a71SRichard Henderson for (typemask >>= 3; typemask; typemask >>= 3, cum.arg_idx++) { 137839004a71SRichard Henderson TCGCallArgumentKind kind; 137939004a71SRichard Henderson TCGType type; 138039004a71SRichard Henderson 138139004a71SRichard Henderson typecode = typemask & 7; 138239004a71SRichard Henderson switch (typecode) { 138339004a71SRichard Henderson case dh_typecode_i32: 138439004a71SRichard Henderson case dh_typecode_s32: 138539004a71SRichard Henderson type = TCG_TYPE_I32; 138639004a71SRichard Henderson break; 138739004a71SRichard Henderson case dh_typecode_i64: 138839004a71SRichard Henderson case dh_typecode_s64: 138939004a71SRichard Henderson type = TCG_TYPE_I64; 139039004a71SRichard Henderson break; 139139004a71SRichard Henderson case dh_typecode_ptr: 139239004a71SRichard Henderson type = TCG_TYPE_PTR; 139339004a71SRichard Henderson break; 1394466d3759SRichard Henderson case dh_typecode_i128: 1395466d3759SRichard Henderson type = TCG_TYPE_I128; 1396466d3759SRichard Henderson break; 139739004a71SRichard Henderson default: 139839004a71SRichard Henderson g_assert_not_reached(); 139939004a71SRichard Henderson } 140039004a71SRichard Henderson 140139004a71SRichard Henderson switch (type) { 140239004a71SRichard Henderson case TCG_TYPE_I32: 140339004a71SRichard Henderson switch (TCG_TARGET_CALL_ARG_I32) { 140439004a71SRichard Henderson case TCG_CALL_ARG_EVEN: 140539004a71SRichard Henderson layout_arg_even(&cum); 140639004a71SRichard Henderson /* fall through */ 140739004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 140839004a71SRichard Henderson layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL); 140939004a71SRichard Henderson break; 141039004a71SRichard Henderson case TCG_CALL_ARG_EXTEND: 141139004a71SRichard Henderson kind = TCG_CALL_ARG_EXTEND_U + (typecode & 1); 141239004a71SRichard Henderson layout_arg_1(&cum, info, kind); 141339004a71SRichard Henderson break; 141439004a71SRichard Henderson default: 141539004a71SRichard Henderson qemu_build_not_reached(); 141639004a71SRichard Henderson } 141739004a71SRichard Henderson break; 141839004a71SRichard Henderson 141939004a71SRichard Henderson case TCG_TYPE_I64: 142039004a71SRichard Henderson switch (TCG_TARGET_CALL_ARG_I64) { 142139004a71SRichard Henderson case TCG_CALL_ARG_EVEN: 142239004a71SRichard Henderson layout_arg_even(&cum); 142339004a71SRichard Henderson /* fall through */ 142439004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 142539004a71SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 142639004a71SRichard Henderson layout_arg_normal_n(&cum, info, 2); 142739004a71SRichard Henderson } else { 142839004a71SRichard Henderson layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL); 142939004a71SRichard Henderson } 143039004a71SRichard Henderson break; 143139004a71SRichard Henderson default: 143239004a71SRichard Henderson qemu_build_not_reached(); 143339004a71SRichard Henderson } 143439004a71SRichard Henderson break; 143539004a71SRichard Henderson 1436466d3759SRichard Henderson case TCG_TYPE_I128: 14375427a9a7SRichard Henderson switch (TCG_TARGET_CALL_ARG_I128) { 1438466d3759SRichard Henderson case TCG_CALL_ARG_EVEN: 1439466d3759SRichard Henderson layout_arg_even(&cum); 1440466d3759SRichard Henderson /* fall through */ 1441466d3759SRichard Henderson case TCG_CALL_ARG_NORMAL: 1442466d3759SRichard Henderson layout_arg_normal_n(&cum, info, 128 / TCG_TARGET_REG_BITS); 1443466d3759SRichard Henderson break; 1444313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF: 1445313bdea8SRichard Henderson layout_arg_by_ref(&cum, info); 1446313bdea8SRichard Henderson break; 1447466d3759SRichard Henderson default: 1448466d3759SRichard Henderson qemu_build_not_reached(); 1449466d3759SRichard Henderson } 1450466d3759SRichard Henderson break; 1451466d3759SRichard Henderson 145239004a71SRichard Henderson default: 145339004a71SRichard Henderson g_assert_not_reached(); 145439004a71SRichard Henderson } 145539004a71SRichard Henderson } 145639004a71SRichard Henderson info->nr_in = cum.info_in_idx; 145739004a71SRichard Henderson 145839004a71SRichard Henderson /* Validate that we didn't overrun the input array. */ 145939004a71SRichard Henderson assert(cum.info_in_idx <= ARRAY_SIZE(info->in)); 146039004a71SRichard Henderson /* Validate the backend has enough argument space. */ 146139004a71SRichard Henderson assert(cum.arg_slot <= max_reg_slots + max_stk_slots); 1462313bdea8SRichard Henderson 1463313bdea8SRichard Henderson /* 1464313bdea8SRichard Henderson * Relocate the "ref_slot" area to the end of the parameters. 1465313bdea8SRichard Henderson * Minimizing this stack offset helps code size for x86, 1466313bdea8SRichard Henderson * which has a signed 8-bit offset encoding. 1467313bdea8SRichard Henderson */ 1468313bdea8SRichard Henderson if (cum.ref_slot != 0) { 1469313bdea8SRichard Henderson int ref_base = 0; 1470313bdea8SRichard Henderson 1471313bdea8SRichard Henderson if (cum.arg_slot > max_reg_slots) { 1472313bdea8SRichard Henderson int align = __alignof(Int128) / sizeof(tcg_target_long); 1473313bdea8SRichard Henderson 1474313bdea8SRichard Henderson ref_base = cum.arg_slot - max_reg_slots; 1475313bdea8SRichard Henderson if (align > 1) { 1476313bdea8SRichard Henderson ref_base = ROUND_UP(ref_base, align); 1477313bdea8SRichard Henderson } 1478313bdea8SRichard Henderson } 1479313bdea8SRichard Henderson assert(ref_base + cum.ref_slot <= max_stk_slots); 1480d78e4a4fSRichard Henderson ref_base += max_reg_slots; 1481313bdea8SRichard Henderson 1482313bdea8SRichard Henderson if (ref_base != 0) { 1483313bdea8SRichard Henderson for (int i = cum.info_in_idx - 1; i >= 0; --i) { 1484313bdea8SRichard Henderson TCGCallArgumentLoc *loc = &info->in[i]; 1485313bdea8SRichard Henderson switch (loc->kind) { 1486313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF: 1487313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF_N: 1488313bdea8SRichard Henderson loc->ref_slot += ref_base; 1489313bdea8SRichard Henderson break; 1490313bdea8SRichard Henderson default: 1491313bdea8SRichard Henderson break; 1492313bdea8SRichard Henderson } 1493313bdea8SRichard Henderson } 1494313bdea8SRichard Henderson } 1495313bdea8SRichard Henderson } 149639004a71SRichard Henderson } 149739004a71SRichard Henderson 149891478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)]; 1499501fb3daSRichard Henderson static void process_constraint_sets(void); 15001c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type, 15011c2adb95SRichard Henderson TCGReg reg, const char *name); 150291478cefSRichard Henderson 150343b972b7SRichard Henderson static void tcg_context_init(unsigned max_cpus) 1504c896fe29Sbellard { 1505a76aabd3SRichard Henderson TCGContext *s = &tcg_init_ctx; 15063e80824eSRichard Henderson int n, i; 15071c2adb95SRichard Henderson TCGTemp *ts; 1508c896fe29Sbellard 1509c896fe29Sbellard memset(s, 0, sizeof(*s)); 1510c896fe29Sbellard s->nb_globals = 0; 1511c896fe29Sbellard 15128429a1caSRichard Henderson init_call_layout(&info_helper_ld32_mmu); 15138429a1caSRichard Henderson init_call_layout(&info_helper_ld64_mmu); 1514ebebea53SRichard Henderson init_call_layout(&info_helper_ld128_mmu); 15158429a1caSRichard Henderson init_call_layout(&info_helper_st32_mmu); 15168429a1caSRichard Henderson init_call_layout(&info_helper_st64_mmu); 1517ebebea53SRichard Henderson init_call_layout(&info_helper_st128_mmu); 15188429a1caSRichard Henderson 1519c896fe29Sbellard tcg_target_init(s); 1520501fb3daSRichard Henderson process_constraint_sets(); 152191478cefSRichard Henderson 152291478cefSRichard Henderson /* Reverse the order of the saved registers, assuming they're all at 152391478cefSRichard Henderson the start of tcg_target_reg_alloc_order. */ 152491478cefSRichard Henderson for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) { 152591478cefSRichard Henderson int r = tcg_target_reg_alloc_order[n]; 152691478cefSRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) { 152791478cefSRichard Henderson break; 152891478cefSRichard Henderson } 152991478cefSRichard Henderson } 153091478cefSRichard Henderson for (i = 0; i < n; ++i) { 153191478cefSRichard Henderson indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i]; 153291478cefSRichard Henderson } 153391478cefSRichard Henderson for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) { 153491478cefSRichard Henderson indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i]; 153591478cefSRichard Henderson } 1536b1311c4aSEmilio G. Cota 1537b1311c4aSEmilio G. Cota tcg_ctx = s; 15383468b59eSEmilio G. Cota /* 15393468b59eSEmilio G. Cota * In user-mode we simply share the init context among threads, since we 15403468b59eSEmilio G. Cota * use a single region. See the documentation tcg_region_init() for the 15413468b59eSEmilio G. Cota * reasoning behind this. 15427893e42dSPhilippe Mathieu-Daudé * In system-mode we will have at most max_cpus TCG threads. 15433468b59eSEmilio G. Cota */ 15443468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY 1545df2cce29SEmilio G. Cota tcg_ctxs = &tcg_ctx; 15460e2d61cfSRichard Henderson tcg_cur_ctxs = 1; 15470e2d61cfSRichard Henderson tcg_max_ctxs = 1; 15483468b59eSEmilio G. Cota #else 15490e2d61cfSRichard Henderson tcg_max_ctxs = max_cpus; 15500e2d61cfSRichard Henderson tcg_ctxs = g_new0(TCGContext *, max_cpus); 15513468b59eSEmilio G. Cota #endif 15521c2adb95SRichard Henderson 15531c2adb95SRichard Henderson tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0)); 15541c2adb95SRichard Henderson ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env"); 1555ad75a51eSRichard Henderson tcg_env = temp_tcgv_ptr(ts); 15569002ec79SRichard Henderson } 1557b03cce8eSbellard 155843b972b7SRichard Henderson void tcg_init(size_t tb_size, int splitwx, unsigned max_cpus) 1559a76aabd3SRichard Henderson { 156043b972b7SRichard Henderson tcg_context_init(max_cpus); 156143b972b7SRichard Henderson tcg_region_init(tb_size, splitwx, max_cpus); 1562a76aabd3SRichard Henderson } 1563a76aabd3SRichard Henderson 15646e3b2bfdSEmilio G. Cota /* 15656e3b2bfdSEmilio G. Cota * Allocate TBs right before their corresponding translated code, making 15666e3b2bfdSEmilio G. Cota * sure that TBs and code are on different cache lines. 15676e3b2bfdSEmilio G. Cota */ 15686e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s) 15696e3b2bfdSEmilio G. Cota { 15706e3b2bfdSEmilio G. Cota uintptr_t align = qemu_icache_linesize; 15716e3b2bfdSEmilio G. Cota TranslationBlock *tb; 15726e3b2bfdSEmilio G. Cota void *next; 15736e3b2bfdSEmilio G. Cota 1574e8feb96fSEmilio G. Cota retry: 15756e3b2bfdSEmilio G. Cota tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align); 15766e3b2bfdSEmilio G. Cota next = (void *)ROUND_UP((uintptr_t)(tb + 1), align); 15776e3b2bfdSEmilio G. Cota 15786e3b2bfdSEmilio G. Cota if (unlikely(next > s->code_gen_highwater)) { 1579e8feb96fSEmilio G. Cota if (tcg_region_alloc(s)) { 15806e3b2bfdSEmilio G. Cota return NULL; 15816e3b2bfdSEmilio G. Cota } 1582e8feb96fSEmilio G. Cota goto retry; 1583e8feb96fSEmilio G. Cota } 1584d73415a3SStefan Hajnoczi qatomic_set(&s->code_gen_ptr, next); 15856e3b2bfdSEmilio G. Cota return tb; 15866e3b2bfdSEmilio G. Cota } 15876e3b2bfdSEmilio G. Cota 1588935f75aeSRichard Henderson void tcg_prologue_init(void) 15899002ec79SRichard Henderson { 1590935f75aeSRichard Henderson TCGContext *s = tcg_ctx; 1591b0a0794aSRichard Henderson size_t prologue_size; 15928163b749SRichard Henderson 1593b0a0794aSRichard Henderson s->code_ptr = s->code_gen_ptr; 1594b0a0794aSRichard Henderson s->code_buf = s->code_gen_ptr; 15955b38ee31SRichard Henderson s->data_gen_ptr = NULL; 1596b91ccb31SRichard Henderson 1597b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 1598b0a0794aSRichard Henderson tcg_qemu_tb_exec = (tcg_prologue_fn *)tcg_splitwx_to_rx(s->code_ptr); 1599b91ccb31SRichard Henderson #endif 16008163b749SRichard Henderson 16015b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 16025b38ee31SRichard Henderson s->pool_labels = NULL; 16035b38ee31SRichard Henderson #endif 16045b38ee31SRichard Henderson 1605653b87ebSRoman Bolshakov qemu_thread_jit_write(); 16068163b749SRichard Henderson /* Generate the prologue. */ 1607b03cce8eSbellard tcg_target_qemu_prologue(s); 16085b38ee31SRichard Henderson 16095b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 16105b38ee31SRichard Henderson /* Allow the prologue to put e.g. guest_base into a pool entry. */ 16115b38ee31SRichard Henderson { 16121768987bSRichard Henderson int result = tcg_out_pool_finalize(s); 16131768987bSRichard Henderson tcg_debug_assert(result == 0); 16145b38ee31SRichard Henderson } 16155b38ee31SRichard Henderson #endif 16165b38ee31SRichard Henderson 1617b0a0794aSRichard Henderson prologue_size = tcg_current_code_size(s); 16185584e2dbSIlya Leoshkevich perf_report_prologue(s->code_gen_ptr, prologue_size); 1619b0a0794aSRichard Henderson 1620df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 1621b0a0794aSRichard Henderson flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf), 1622b0a0794aSRichard Henderson (uintptr_t)s->code_buf, prologue_size); 1623df5d2b16SRichard Henderson #endif 16248163b749SRichard Henderson 1625d6b64b2bSRichard Henderson if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) { 1626c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock(); 162778b54858SRichard Henderson if (logfile) { 162878b54858SRichard Henderson fprintf(logfile, "PROLOGUE: [size=%zu]\n", prologue_size); 16295b38ee31SRichard Henderson if (s->data_gen_ptr) { 1630b0a0794aSRichard Henderson size_t code_size = s->data_gen_ptr - s->code_gen_ptr; 16315b38ee31SRichard Henderson size_t data_size = prologue_size - code_size; 16325b38ee31SRichard Henderson size_t i; 16335b38ee31SRichard Henderson 163478b54858SRichard Henderson disas(logfile, s->code_gen_ptr, code_size); 16355b38ee31SRichard Henderson 16365b38ee31SRichard Henderson for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) { 16375b38ee31SRichard Henderson if (sizeof(tcg_target_ulong) == 8) { 163878b54858SRichard Henderson fprintf(logfile, 163978b54858SRichard Henderson "0x%08" PRIxPTR ": .quad 0x%016" PRIx64 "\n", 16405b38ee31SRichard Henderson (uintptr_t)s->data_gen_ptr + i, 16415b38ee31SRichard Henderson *(uint64_t *)(s->data_gen_ptr + i)); 16425b38ee31SRichard Henderson } else { 164378b54858SRichard Henderson fprintf(logfile, 164478b54858SRichard Henderson "0x%08" PRIxPTR ": .long 0x%08x\n", 16455b38ee31SRichard Henderson (uintptr_t)s->data_gen_ptr + i, 16465b38ee31SRichard Henderson *(uint32_t *)(s->data_gen_ptr + i)); 16475b38ee31SRichard Henderson } 16485b38ee31SRichard Henderson } 16495b38ee31SRichard Henderson } else { 165078b54858SRichard Henderson disas(logfile, s->code_gen_ptr, prologue_size); 16515b38ee31SRichard Henderson } 165278b54858SRichard Henderson fprintf(logfile, "\n"); 1653fc59d2d8SRobert Foley qemu_log_unlock(logfile); 1654d6b64b2bSRichard Henderson } 165578b54858SRichard Henderson } 1656cedbcb01SEmilio G. Cota 16576eea0434SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 16586eea0434SRichard Henderson /* 16596eea0434SRichard Henderson * Assert that goto_ptr is implemented completely, setting an epilogue. 16606eea0434SRichard Henderson * For tci, we use NULL as the signal to return from the interpreter, 16616eea0434SRichard Henderson * so skip this check. 16626eea0434SRichard Henderson */ 16638b5c2b62SRichard Henderson tcg_debug_assert(tcg_code_gen_epilogue != NULL); 16646eea0434SRichard Henderson #endif 1665d1c74ab3SRichard Henderson 1666d1c74ab3SRichard Henderson tcg_region_prologue_set(s); 1667c896fe29Sbellard } 1668c896fe29Sbellard 1669c896fe29Sbellard void tcg_func_start(TCGContext *s) 1670c896fe29Sbellard { 1671c896fe29Sbellard tcg_pool_reset(s); 1672c896fe29Sbellard s->nb_temps = s->nb_globals; 16730ec9eabcSRichard Henderson 16740ec9eabcSRichard Henderson /* No temps have been previously allocated for size or locality. */ 167504e006abSRichard Henderson tcg_temp_ebb_reset_freed(s); 16760ec9eabcSRichard Henderson 1677c0522136SRichard Henderson /* No constant temps have been previously allocated. */ 1678c0522136SRichard Henderson for (int i = 0; i < TCG_TYPE_COUNT; ++i) { 1679c0522136SRichard Henderson if (s->const_table[i]) { 1680c0522136SRichard Henderson g_hash_table_remove_all(s->const_table[i]); 1681c0522136SRichard Henderson } 1682c0522136SRichard Henderson } 1683c0522136SRichard Henderson 1684abebf925SRichard Henderson s->nb_ops = 0; 1685c896fe29Sbellard s->nb_labels = 0; 1686c896fe29Sbellard s->current_frame_offset = s->frame_start; 1687c896fe29Sbellard 16880a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG 16890a209d4bSRichard Henderson s->goto_tb_issue_mask = 0; 16900a209d4bSRichard Henderson #endif 16910a209d4bSRichard Henderson 169215fa08f8SRichard Henderson QTAILQ_INIT(&s->ops); 169315fa08f8SRichard Henderson QTAILQ_INIT(&s->free_ops); 169407843f75SRichard Henderson s->emit_before_op = NULL; 1695bef16ab4SRichard Henderson QSIMPLEQ_INIT(&s->labels); 16964baf3978SRichard Henderson 16974baf3978SRichard Henderson tcg_debug_assert(s->addr_type == TCG_TYPE_I32 || 16984baf3978SRichard Henderson s->addr_type == TCG_TYPE_I64); 1699d0a9bb5eSRichard Henderson 1700747bd69dSRichard Henderson tcg_debug_assert(s->insn_start_words > 0); 1701c896fe29Sbellard } 1702c896fe29Sbellard 1703ae30e866SRichard Henderson static TCGTemp *tcg_temp_alloc(TCGContext *s) 17047ca4b752SRichard Henderson { 17057ca4b752SRichard Henderson int n = s->nb_temps++; 1706ae30e866SRichard Henderson 1707ae30e866SRichard Henderson if (n >= TCG_MAX_TEMPS) { 1708db6b7d0cSRichard Henderson tcg_raise_tb_overflow(s); 1709ae30e866SRichard Henderson } 17107ca4b752SRichard Henderson return memset(&s->temps[n], 0, sizeof(TCGTemp)); 17117ca4b752SRichard Henderson } 17127ca4b752SRichard Henderson 1713ae30e866SRichard Henderson static TCGTemp *tcg_global_alloc(TCGContext *s) 17147ca4b752SRichard Henderson { 1715fa477d25SRichard Henderson TCGTemp *ts; 1716fa477d25SRichard Henderson 17177ca4b752SRichard Henderson tcg_debug_assert(s->nb_globals == s->nb_temps); 1718ae30e866SRichard Henderson tcg_debug_assert(s->nb_globals < TCG_MAX_TEMPS); 17197ca4b752SRichard Henderson s->nb_globals++; 1720fa477d25SRichard Henderson ts = tcg_temp_alloc(s); 1721ee17db83SRichard Henderson ts->kind = TEMP_GLOBAL; 1722fa477d25SRichard Henderson 1723fa477d25SRichard Henderson return ts; 1724c896fe29Sbellard } 1725c896fe29Sbellard 1726085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type, 1727b6638662SRichard Henderson TCGReg reg, const char *name) 1728c896fe29Sbellard { 1729c896fe29Sbellard TCGTemp *ts; 1730c896fe29Sbellard 17311a057554SRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 64 || type == TCG_TYPE_I32); 17327ca4b752SRichard Henderson 17337ca4b752SRichard Henderson ts = tcg_global_alloc(s); 1734c896fe29Sbellard ts->base_type = type; 1735c896fe29Sbellard ts->type = type; 1736ee17db83SRichard Henderson ts->kind = TEMP_FIXED; 1737c896fe29Sbellard ts->reg = reg; 1738c896fe29Sbellard ts->name = name; 1739c896fe29Sbellard tcg_regset_set_reg(s->reserved_regs, reg); 17407ca4b752SRichard Henderson 1741085272b3SRichard Henderson return ts; 1742a7812ae4Spbrook } 1743a7812ae4Spbrook 1744b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size) 1745a7812ae4Spbrook { 1746b3a62939SRichard Henderson s->frame_start = start; 1747b3a62939SRichard Henderson s->frame_end = start + size; 1748085272b3SRichard Henderson s->frame_temp 1749085272b3SRichard Henderson = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame"); 1750b3a62939SRichard Henderson } 1751a7812ae4Spbrook 17524643f3e0SRichard Henderson static TCGTemp *tcg_global_mem_new_internal(TCGv_ptr base, intptr_t offset, 17534643f3e0SRichard Henderson const char *name, TCGType type) 1754c896fe29Sbellard { 1755b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1756dc41aa7dSRichard Henderson TCGTemp *base_ts = tcgv_ptr_temp(base); 17577ca4b752SRichard Henderson TCGTemp *ts = tcg_global_alloc(s); 1758aef85402SRichard Henderson int indirect_reg = 0; 1759c896fe29Sbellard 1760c0522136SRichard Henderson switch (base_ts->kind) { 1761c0522136SRichard Henderson case TEMP_FIXED: 1762c0522136SRichard Henderson break; 1763c0522136SRichard Henderson case TEMP_GLOBAL: 17645a18407fSRichard Henderson /* We do not support double-indirect registers. */ 17655a18407fSRichard Henderson tcg_debug_assert(!base_ts->indirect_reg); 1766b3915dbbSRichard Henderson base_ts->indirect_base = 1; 17675a18407fSRichard Henderson s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64 17685a18407fSRichard Henderson ? 2 : 1); 17695a18407fSRichard Henderson indirect_reg = 1; 1770c0522136SRichard Henderson break; 1771c0522136SRichard Henderson default: 1772c0522136SRichard Henderson g_assert_not_reached(); 1773b3915dbbSRichard Henderson } 1774b3915dbbSRichard Henderson 17757ca4b752SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { 17767ca4b752SRichard Henderson TCGTemp *ts2 = tcg_global_alloc(s); 1777c896fe29Sbellard char buf[64]; 17787ca4b752SRichard Henderson 17797ca4b752SRichard Henderson ts->base_type = TCG_TYPE_I64; 1780c896fe29Sbellard ts->type = TCG_TYPE_I32; 1781b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg; 1782c896fe29Sbellard ts->mem_allocated = 1; 1783b3a62939SRichard Henderson ts->mem_base = base_ts; 1784aef85402SRichard Henderson ts->mem_offset = offset; 1785c896fe29Sbellard pstrcpy(buf, sizeof(buf), name); 1786c896fe29Sbellard pstrcat(buf, sizeof(buf), "_0"); 1787c896fe29Sbellard ts->name = strdup(buf); 1788c896fe29Sbellard 17897ca4b752SRichard Henderson tcg_debug_assert(ts2 == ts + 1); 17907ca4b752SRichard Henderson ts2->base_type = TCG_TYPE_I64; 17917ca4b752SRichard Henderson ts2->type = TCG_TYPE_I32; 1792b3915dbbSRichard Henderson ts2->indirect_reg = indirect_reg; 17937ca4b752SRichard Henderson ts2->mem_allocated = 1; 17947ca4b752SRichard Henderson ts2->mem_base = base_ts; 1795aef85402SRichard Henderson ts2->mem_offset = offset + 4; 1796fac87bd2SRichard Henderson ts2->temp_subindex = 1; 1797c896fe29Sbellard pstrcpy(buf, sizeof(buf), name); 1798c896fe29Sbellard pstrcat(buf, sizeof(buf), "_1"); 1799120c1084SRichard Henderson ts2->name = strdup(buf); 18007ca4b752SRichard Henderson } else { 1801c896fe29Sbellard ts->base_type = type; 1802c896fe29Sbellard ts->type = type; 1803b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg; 1804c896fe29Sbellard ts->mem_allocated = 1; 1805b3a62939SRichard Henderson ts->mem_base = base_ts; 1806c896fe29Sbellard ts->mem_offset = offset; 1807c896fe29Sbellard ts->name = name; 1808c896fe29Sbellard } 1809085272b3SRichard Henderson return ts; 1810c896fe29Sbellard } 1811c896fe29Sbellard 18124643f3e0SRichard Henderson TCGv_i32 tcg_global_mem_new_i32(TCGv_ptr reg, intptr_t off, const char *name) 18134643f3e0SRichard Henderson { 18144643f3e0SRichard Henderson TCGTemp *ts = tcg_global_mem_new_internal(reg, off, name, TCG_TYPE_I32); 18154643f3e0SRichard Henderson return temp_tcgv_i32(ts); 18164643f3e0SRichard Henderson } 18174643f3e0SRichard Henderson 18184643f3e0SRichard Henderson TCGv_i64 tcg_global_mem_new_i64(TCGv_ptr reg, intptr_t off, const char *name) 18194643f3e0SRichard Henderson { 18204643f3e0SRichard Henderson TCGTemp *ts = tcg_global_mem_new_internal(reg, off, name, TCG_TYPE_I64); 18214643f3e0SRichard Henderson return temp_tcgv_i64(ts); 18224643f3e0SRichard Henderson } 18234643f3e0SRichard Henderson 18244643f3e0SRichard Henderson TCGv_ptr tcg_global_mem_new_ptr(TCGv_ptr reg, intptr_t off, const char *name) 18254643f3e0SRichard Henderson { 18264643f3e0SRichard Henderson TCGTemp *ts = tcg_global_mem_new_internal(reg, off, name, TCG_TYPE_PTR); 18274643f3e0SRichard Henderson return temp_tcgv_ptr(ts); 18284643f3e0SRichard Henderson } 18294643f3e0SRichard Henderson 1830fb04ab7dSRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, TCGTempKind kind) 1831c896fe29Sbellard { 1832b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1833c896fe29Sbellard TCGTemp *ts; 1834e1c08b00SRichard Henderson int n; 1835c896fe29Sbellard 1836e1c08b00SRichard Henderson if (kind == TEMP_EBB) { 1837e1c08b00SRichard Henderson int idx = find_first_bit(s->free_temps[type].l, TCG_MAX_TEMPS); 1838e1c08b00SRichard Henderson 18390ec9eabcSRichard Henderson if (idx < TCG_MAX_TEMPS) { 18400ec9eabcSRichard Henderson /* There is already an available temp with the right type. */ 1841e1c08b00SRichard Henderson clear_bit(idx, s->free_temps[type].l); 18420ec9eabcSRichard Henderson 1843e8996ee0Sbellard ts = &s->temps[idx]; 1844e8996ee0Sbellard ts->temp_allocated = 1; 18457ca4b752SRichard Henderson tcg_debug_assert(ts->base_type == type); 1846ee17db83SRichard Henderson tcg_debug_assert(ts->kind == kind); 18472f2e911dSRichard Henderson return ts; 1848e1c08b00SRichard Henderson } 1849e8996ee0Sbellard } else { 1850e1c08b00SRichard Henderson tcg_debug_assert(kind == TEMP_TB); 1851e1c08b00SRichard Henderson } 185243eef72fSRichard Henderson 185343eef72fSRichard Henderson switch (type) { 185443eef72fSRichard Henderson case TCG_TYPE_I32: 185543eef72fSRichard Henderson case TCG_TYPE_V64: 185643eef72fSRichard Henderson case TCG_TYPE_V128: 185743eef72fSRichard Henderson case TCG_TYPE_V256: 185843eef72fSRichard Henderson n = 1; 185943eef72fSRichard Henderson break; 186043eef72fSRichard Henderson case TCG_TYPE_I64: 186143eef72fSRichard Henderson n = 64 / TCG_TARGET_REG_BITS; 186243eef72fSRichard Henderson break; 186343eef72fSRichard Henderson case TCG_TYPE_I128: 186443eef72fSRichard Henderson n = 128 / TCG_TARGET_REG_BITS; 186543eef72fSRichard Henderson break; 186643eef72fSRichard Henderson default: 186743eef72fSRichard Henderson g_assert_not_reached(); 186843eef72fSRichard Henderson } 186943eef72fSRichard Henderson 18707ca4b752SRichard Henderson ts = tcg_temp_alloc(s); 187143eef72fSRichard Henderson ts->base_type = type; 187243eef72fSRichard Henderson ts->temp_allocated = 1; 187343eef72fSRichard Henderson ts->kind = kind; 187443eef72fSRichard Henderson 187543eef72fSRichard Henderson if (n == 1) { 187643eef72fSRichard Henderson ts->type = type; 187743eef72fSRichard Henderson } else { 187843eef72fSRichard Henderson ts->type = TCG_TYPE_REG; 187943eef72fSRichard Henderson 1880e1c08b00SRichard Henderson for (int i = 1; i < n; ++i) { 18817ca4b752SRichard Henderson TCGTemp *ts2 = tcg_temp_alloc(s); 18827ca4b752SRichard Henderson 188343eef72fSRichard Henderson tcg_debug_assert(ts2 == ts + i); 188443eef72fSRichard Henderson ts2->base_type = type; 188543eef72fSRichard Henderson ts2->type = TCG_TYPE_REG; 18867ca4b752SRichard Henderson ts2->temp_allocated = 1; 188743eef72fSRichard Henderson ts2->temp_subindex = i; 1888ee17db83SRichard Henderson ts2->kind = kind; 188943eef72fSRichard Henderson } 1890c896fe29Sbellard } 1891085272b3SRichard Henderson return ts; 1892c896fe29Sbellard } 1893c896fe29Sbellard 18944643f3e0SRichard Henderson TCGv_i32 tcg_temp_new_i32(void) 18954643f3e0SRichard Henderson { 18964643f3e0SRichard Henderson return temp_tcgv_i32(tcg_temp_new_internal(TCG_TYPE_I32, TEMP_TB)); 18974643f3e0SRichard Henderson } 18984643f3e0SRichard Henderson 18994643f3e0SRichard Henderson TCGv_i32 tcg_temp_ebb_new_i32(void) 19004643f3e0SRichard Henderson { 19014643f3e0SRichard Henderson return temp_tcgv_i32(tcg_temp_new_internal(TCG_TYPE_I32, TEMP_EBB)); 19024643f3e0SRichard Henderson } 19034643f3e0SRichard Henderson 19044643f3e0SRichard Henderson TCGv_i64 tcg_temp_new_i64(void) 19054643f3e0SRichard Henderson { 19064643f3e0SRichard Henderson return temp_tcgv_i64(tcg_temp_new_internal(TCG_TYPE_I64, TEMP_TB)); 19074643f3e0SRichard Henderson } 19084643f3e0SRichard Henderson 19094643f3e0SRichard Henderson TCGv_i64 tcg_temp_ebb_new_i64(void) 19104643f3e0SRichard Henderson { 19114643f3e0SRichard Henderson return temp_tcgv_i64(tcg_temp_new_internal(TCG_TYPE_I64, TEMP_EBB)); 19124643f3e0SRichard Henderson } 19134643f3e0SRichard Henderson 19144643f3e0SRichard Henderson TCGv_ptr tcg_temp_new_ptr(void) 19154643f3e0SRichard Henderson { 19164643f3e0SRichard Henderson return temp_tcgv_ptr(tcg_temp_new_internal(TCG_TYPE_PTR, TEMP_TB)); 19174643f3e0SRichard Henderson } 19184643f3e0SRichard Henderson 19194643f3e0SRichard Henderson TCGv_ptr tcg_temp_ebb_new_ptr(void) 19204643f3e0SRichard Henderson { 19214643f3e0SRichard Henderson return temp_tcgv_ptr(tcg_temp_new_internal(TCG_TYPE_PTR, TEMP_EBB)); 19224643f3e0SRichard Henderson } 19234643f3e0SRichard Henderson 19244643f3e0SRichard Henderson TCGv_i128 tcg_temp_new_i128(void) 19254643f3e0SRichard Henderson { 19264643f3e0SRichard Henderson return temp_tcgv_i128(tcg_temp_new_internal(TCG_TYPE_I128, TEMP_TB)); 19274643f3e0SRichard Henderson } 19284643f3e0SRichard Henderson 19294643f3e0SRichard Henderson TCGv_i128 tcg_temp_ebb_new_i128(void) 19304643f3e0SRichard Henderson { 19314643f3e0SRichard Henderson return temp_tcgv_i128(tcg_temp_new_internal(TCG_TYPE_I128, TEMP_EBB)); 19324643f3e0SRichard Henderson } 19334643f3e0SRichard Henderson 1934d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type) 1935d2fd745fSRichard Henderson { 1936d2fd745fSRichard Henderson TCGTemp *t; 1937d2fd745fSRichard Henderson 1938d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG 1939d2fd745fSRichard Henderson switch (type) { 1940d2fd745fSRichard Henderson case TCG_TYPE_V64: 1941d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v64); 1942d2fd745fSRichard Henderson break; 1943d2fd745fSRichard Henderson case TCG_TYPE_V128: 1944d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v128); 1945d2fd745fSRichard Henderson break; 1946d2fd745fSRichard Henderson case TCG_TYPE_V256: 1947d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v256); 1948d2fd745fSRichard Henderson break; 1949d2fd745fSRichard Henderson default: 1950d2fd745fSRichard Henderson g_assert_not_reached(); 1951d2fd745fSRichard Henderson } 1952d2fd745fSRichard Henderson #endif 1953d2fd745fSRichard Henderson 1954bbf989bfSRichard Henderson t = tcg_temp_new_internal(type, TEMP_EBB); 1955d2fd745fSRichard Henderson return temp_tcgv_vec(t); 1956d2fd745fSRichard Henderson } 1957d2fd745fSRichard Henderson 1958d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp. */ 1959d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match) 1960d2fd745fSRichard Henderson { 1961d2fd745fSRichard Henderson TCGTemp *t = tcgv_vec_temp(match); 1962d2fd745fSRichard Henderson 1963d2fd745fSRichard Henderson tcg_debug_assert(t->temp_allocated != 0); 1964d2fd745fSRichard Henderson 1965bbf989bfSRichard Henderson t = tcg_temp_new_internal(t->base_type, TEMP_EBB); 1966d2fd745fSRichard Henderson return temp_tcgv_vec(t); 1967d2fd745fSRichard Henderson } 1968d2fd745fSRichard Henderson 19695bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts) 1970c896fe29Sbellard { 1971b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1972c896fe29Sbellard 1973c7482438SRichard Henderson switch (ts->kind) { 1974c7482438SRichard Henderson case TEMP_CONST: 1975f57c6915SRichard Henderson case TEMP_TB: 19762f2e911dSRichard Henderson /* Silently ignore free. */ 1977c7482438SRichard Henderson break; 19782f2e911dSRichard Henderson case TEMP_EBB: 1979eabb7b91SAurelien Jarno tcg_debug_assert(ts->temp_allocated != 0); 1980e8996ee0Sbellard ts->temp_allocated = 0; 19812f2e911dSRichard Henderson set_bit(temp_idx(ts), s->free_temps[ts->base_type].l); 19822f2e911dSRichard Henderson break; 19832f2e911dSRichard Henderson default: 19842f2e911dSRichard Henderson /* It never made sense to free TEMP_FIXED or TEMP_GLOBAL. */ 19852f2e911dSRichard Henderson g_assert_not_reached(); 1986e1c08b00SRichard Henderson } 1987e8996ee0Sbellard } 1988e8996ee0Sbellard 198958b79713SRichard Henderson void tcg_temp_free_i32(TCGv_i32 arg) 199058b79713SRichard Henderson { 199158b79713SRichard Henderson tcg_temp_free_internal(tcgv_i32_temp(arg)); 199258b79713SRichard Henderson } 199358b79713SRichard Henderson 199458b79713SRichard Henderson void tcg_temp_free_i64(TCGv_i64 arg) 199558b79713SRichard Henderson { 199658b79713SRichard Henderson tcg_temp_free_internal(tcgv_i64_temp(arg)); 199758b79713SRichard Henderson } 199858b79713SRichard Henderson 199958b79713SRichard Henderson void tcg_temp_free_i128(TCGv_i128 arg) 200058b79713SRichard Henderson { 200158b79713SRichard Henderson tcg_temp_free_internal(tcgv_i128_temp(arg)); 200258b79713SRichard Henderson } 200358b79713SRichard Henderson 200458b79713SRichard Henderson void tcg_temp_free_ptr(TCGv_ptr arg) 200558b79713SRichard Henderson { 200658b79713SRichard Henderson tcg_temp_free_internal(tcgv_ptr_temp(arg)); 200758b79713SRichard Henderson } 200858b79713SRichard Henderson 200958b79713SRichard Henderson void tcg_temp_free_vec(TCGv_vec arg) 201058b79713SRichard Henderson { 201158b79713SRichard Henderson tcg_temp_free_internal(tcgv_vec_temp(arg)); 201258b79713SRichard Henderson } 201358b79713SRichard Henderson 2014c0522136SRichard Henderson TCGTemp *tcg_constant_internal(TCGType type, int64_t val) 2015c0522136SRichard Henderson { 2016c0522136SRichard Henderson TCGContext *s = tcg_ctx; 2017c0522136SRichard Henderson GHashTable *h = s->const_table[type]; 2018c0522136SRichard Henderson TCGTemp *ts; 2019c0522136SRichard Henderson 2020c0522136SRichard Henderson if (h == NULL) { 2021c0522136SRichard Henderson h = g_hash_table_new(g_int64_hash, g_int64_equal); 2022c0522136SRichard Henderson s->const_table[type] = h; 2023c0522136SRichard Henderson } 2024c0522136SRichard Henderson 2025c0522136SRichard Henderson ts = g_hash_table_lookup(h, &val); 2026c0522136SRichard Henderson if (ts == NULL) { 2027aef85402SRichard Henderson int64_t *val_ptr; 2028aef85402SRichard Henderson 2029c0522136SRichard Henderson ts = tcg_temp_alloc(s); 2030c0522136SRichard Henderson 2031c0522136SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { 2032c0522136SRichard Henderson TCGTemp *ts2 = tcg_temp_alloc(s); 2033c0522136SRichard Henderson 2034aef85402SRichard Henderson tcg_debug_assert(ts2 == ts + 1); 2035aef85402SRichard Henderson 2036c0522136SRichard Henderson ts->base_type = TCG_TYPE_I64; 2037c0522136SRichard Henderson ts->type = TCG_TYPE_I32; 2038c0522136SRichard Henderson ts->kind = TEMP_CONST; 2039c0522136SRichard Henderson ts->temp_allocated = 1; 2040c0522136SRichard Henderson 2041c0522136SRichard Henderson ts2->base_type = TCG_TYPE_I64; 2042c0522136SRichard Henderson ts2->type = TCG_TYPE_I32; 2043c0522136SRichard Henderson ts2->kind = TEMP_CONST; 2044c0522136SRichard Henderson ts2->temp_allocated = 1; 2045fac87bd2SRichard Henderson ts2->temp_subindex = 1; 2046aef85402SRichard Henderson 2047aef85402SRichard Henderson /* 2048aef85402SRichard Henderson * Retain the full value of the 64-bit constant in the low 2049aef85402SRichard Henderson * part, so that the hash table works. Actual uses will 2050aef85402SRichard Henderson * truncate the value to the low part. 2051aef85402SRichard Henderson */ 2052aef85402SRichard Henderson ts[HOST_BIG_ENDIAN].val = val; 2053aef85402SRichard Henderson ts[!HOST_BIG_ENDIAN].val = val >> 32; 2054aef85402SRichard Henderson val_ptr = &ts[HOST_BIG_ENDIAN].val; 2055c0522136SRichard Henderson } else { 2056c0522136SRichard Henderson ts->base_type = type; 2057c0522136SRichard Henderson ts->type = type; 2058c0522136SRichard Henderson ts->kind = TEMP_CONST; 2059c0522136SRichard Henderson ts->temp_allocated = 1; 2060c0522136SRichard Henderson ts->val = val; 2061aef85402SRichard Henderson val_ptr = &ts->val; 2062c0522136SRichard Henderson } 2063aef85402SRichard Henderson g_hash_table_insert(h, val_ptr, ts); 2064c0522136SRichard Henderson } 2065c0522136SRichard Henderson 2066c0522136SRichard Henderson return ts; 2067c0522136SRichard Henderson } 2068c0522136SRichard Henderson 206916edaee7SRichard Henderson TCGv_i32 tcg_constant_i32(int32_t val) 207016edaee7SRichard Henderson { 207116edaee7SRichard Henderson return temp_tcgv_i32(tcg_constant_internal(TCG_TYPE_I32, val)); 207216edaee7SRichard Henderson } 207316edaee7SRichard Henderson 207416edaee7SRichard Henderson TCGv_i64 tcg_constant_i64(int64_t val) 207516edaee7SRichard Henderson { 207616edaee7SRichard Henderson return temp_tcgv_i64(tcg_constant_internal(TCG_TYPE_I64, val)); 207716edaee7SRichard Henderson } 207816edaee7SRichard Henderson 207916edaee7SRichard Henderson TCGv_ptr tcg_constant_ptr_int(intptr_t val) 208016edaee7SRichard Henderson { 208116edaee7SRichard Henderson return temp_tcgv_ptr(tcg_constant_internal(TCG_TYPE_PTR, val)); 208216edaee7SRichard Henderson } 208316edaee7SRichard Henderson 2084c0522136SRichard Henderson TCGv_vec tcg_constant_vec(TCGType type, unsigned vece, int64_t val) 2085c0522136SRichard Henderson { 2086c0522136SRichard Henderson val = dup_const(vece, val); 2087c0522136SRichard Henderson return temp_tcgv_vec(tcg_constant_internal(type, val)); 2088c0522136SRichard Henderson } 2089c0522136SRichard Henderson 209088d4005bSRichard Henderson TCGv_vec tcg_constant_vec_matching(TCGv_vec match, unsigned vece, int64_t val) 209188d4005bSRichard Henderson { 209288d4005bSRichard Henderson TCGTemp *t = tcgv_vec_temp(match); 209388d4005bSRichard Henderson 209488d4005bSRichard Henderson tcg_debug_assert(t->temp_allocated != 0); 209588d4005bSRichard Henderson return tcg_constant_vec(t->base_type, vece, val); 209688d4005bSRichard Henderson } 209788d4005bSRichard Henderson 2098177f648fSRichard Henderson #ifdef CONFIG_DEBUG_TCG 2099177f648fSRichard Henderson size_t temp_idx(TCGTemp *ts) 2100177f648fSRichard Henderson { 2101177f648fSRichard Henderson ptrdiff_t n = ts - tcg_ctx->temps; 2102177f648fSRichard Henderson assert(n >= 0 && n < tcg_ctx->nb_temps); 2103177f648fSRichard Henderson return n; 2104177f648fSRichard Henderson } 2105177f648fSRichard Henderson 2106177f648fSRichard Henderson TCGTemp *tcgv_i32_temp(TCGv_i32 v) 2107177f648fSRichard Henderson { 2108177f648fSRichard Henderson uintptr_t o = (uintptr_t)v - offsetof(TCGContext, temps); 2109177f648fSRichard Henderson 2110177f648fSRichard Henderson assert(o < sizeof(TCGTemp) * tcg_ctx->nb_temps); 2111177f648fSRichard Henderson assert(o % sizeof(TCGTemp) == 0); 2112177f648fSRichard Henderson 2113177f648fSRichard Henderson return (void *)tcg_ctx + (uintptr_t)v; 2114177f648fSRichard Henderson } 2115177f648fSRichard Henderson #endif /* CONFIG_DEBUG_TCG */ 2116177f648fSRichard Henderson 2117771a5925SRichard Henderson /* 2118771a5925SRichard Henderson * Return true if OP may appear in the opcode stream with TYPE. 2119771a5925SRichard Henderson * Test the runtime variable that controls each opcode. 2120771a5925SRichard Henderson */ 2121771a5925SRichard Henderson bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) 2122be0f34b5SRichard Henderson { 2123f44824ccSRichard Henderson bool has_type; 2124f44824ccSRichard Henderson 2125f44824ccSRichard Henderson switch (type) { 2126f44824ccSRichard Henderson case TCG_TYPE_I32: 2127f44824ccSRichard Henderson has_type = true; 2128f44824ccSRichard Henderson break; 2129f44824ccSRichard Henderson case TCG_TYPE_I64: 2130f44824ccSRichard Henderson has_type = TCG_TARGET_REG_BITS == 64; 2131f44824ccSRichard Henderson break; 2132f44824ccSRichard Henderson case TCG_TYPE_V64: 2133f44824ccSRichard Henderson has_type = TCG_TARGET_HAS_v64; 2134f44824ccSRichard Henderson break; 2135f44824ccSRichard Henderson case TCG_TYPE_V128: 2136f44824ccSRichard Henderson has_type = TCG_TARGET_HAS_v128; 2137f44824ccSRichard Henderson break; 2138f44824ccSRichard Henderson case TCG_TYPE_V256: 2139f44824ccSRichard Henderson has_type = TCG_TARGET_HAS_v256; 2140f44824ccSRichard Henderson break; 2141f44824ccSRichard Henderson default: 2142f44824ccSRichard Henderson has_type = false; 2143f44824ccSRichard Henderson break; 2144f44824ccSRichard Henderson } 2145d2fd745fSRichard Henderson 2146be0f34b5SRichard Henderson switch (op) { 2147be0f34b5SRichard Henderson case INDEX_op_discard: 2148be0f34b5SRichard Henderson case INDEX_op_set_label: 2149be0f34b5SRichard Henderson case INDEX_op_call: 2150be0f34b5SRichard Henderson case INDEX_op_br: 2151be0f34b5SRichard Henderson case INDEX_op_mb: 2152be0f34b5SRichard Henderson case INDEX_op_insn_start: 2153be0f34b5SRichard Henderson case INDEX_op_exit_tb: 2154be0f34b5SRichard Henderson case INDEX_op_goto_tb: 2155f4e01e30SRichard Henderson case INDEX_op_goto_ptr: 2156fecccfccSRichard Henderson case INDEX_op_qemu_ld_a32_i32: 2157fecccfccSRichard Henderson case INDEX_op_qemu_ld_a64_i32: 2158fecccfccSRichard Henderson case INDEX_op_qemu_st_a32_i32: 2159fecccfccSRichard Henderson case INDEX_op_qemu_st_a64_i32: 2160fecccfccSRichard Henderson case INDEX_op_qemu_ld_a32_i64: 2161fecccfccSRichard Henderson case INDEX_op_qemu_ld_a64_i64: 2162fecccfccSRichard Henderson case INDEX_op_qemu_st_a32_i64: 2163fecccfccSRichard Henderson case INDEX_op_qemu_st_a64_i64: 2164be0f34b5SRichard Henderson return true; 2165be0f34b5SRichard Henderson 2166fecccfccSRichard Henderson case INDEX_op_qemu_st8_a32_i32: 2167fecccfccSRichard Henderson case INDEX_op_qemu_st8_a64_i32: 216807ce0b05SRichard Henderson return TCG_TARGET_HAS_qemu_st8_i32; 216907ce0b05SRichard Henderson 2170fecccfccSRichard Henderson case INDEX_op_qemu_ld_a32_i128: 2171fecccfccSRichard Henderson case INDEX_op_qemu_ld_a64_i128: 2172fecccfccSRichard Henderson case INDEX_op_qemu_st_a32_i128: 2173fecccfccSRichard Henderson case INDEX_op_qemu_st_a64_i128: 217412fde9bcSRichard Henderson return TCG_TARGET_HAS_qemu_ldst_i128; 217512fde9bcSRichard Henderson 2176be0f34b5SRichard Henderson case INDEX_op_mov_i32: 2177be0f34b5SRichard Henderson case INDEX_op_setcond_i32: 2178be0f34b5SRichard Henderson case INDEX_op_brcond_i32: 21793871be75SRichard Henderson case INDEX_op_movcond_i32: 2180be0f34b5SRichard Henderson case INDEX_op_ld8u_i32: 2181be0f34b5SRichard Henderson case INDEX_op_ld8s_i32: 2182be0f34b5SRichard Henderson case INDEX_op_ld16u_i32: 2183be0f34b5SRichard Henderson case INDEX_op_ld16s_i32: 2184be0f34b5SRichard Henderson case INDEX_op_ld_i32: 2185be0f34b5SRichard Henderson case INDEX_op_st8_i32: 2186be0f34b5SRichard Henderson case INDEX_op_st16_i32: 2187be0f34b5SRichard Henderson case INDEX_op_st_i32: 2188be0f34b5SRichard Henderson case INDEX_op_add_i32: 2189be0f34b5SRichard Henderson case INDEX_op_sub_i32: 2190b701f195SRichard Henderson case INDEX_op_neg_i32: 2191be0f34b5SRichard Henderson case INDEX_op_mul_i32: 2192be0f34b5SRichard Henderson case INDEX_op_and_i32: 2193be0f34b5SRichard Henderson case INDEX_op_or_i32: 2194be0f34b5SRichard Henderson case INDEX_op_xor_i32: 2195be0f34b5SRichard Henderson case INDEX_op_shl_i32: 2196be0f34b5SRichard Henderson case INDEX_op_shr_i32: 2197be0f34b5SRichard Henderson case INDEX_op_sar_i32: 2198be0f34b5SRichard Henderson return true; 2199be0f34b5SRichard Henderson 22003635502dSRichard Henderson case INDEX_op_negsetcond_i32: 22013635502dSRichard Henderson return TCG_TARGET_HAS_negsetcond_i32; 2202be0f34b5SRichard Henderson case INDEX_op_div_i32: 2203be0f34b5SRichard Henderson case INDEX_op_divu_i32: 2204be0f34b5SRichard Henderson return TCG_TARGET_HAS_div_i32; 2205be0f34b5SRichard Henderson case INDEX_op_rem_i32: 2206be0f34b5SRichard Henderson case INDEX_op_remu_i32: 2207be0f34b5SRichard Henderson return TCG_TARGET_HAS_rem_i32; 2208be0f34b5SRichard Henderson case INDEX_op_div2_i32: 2209be0f34b5SRichard Henderson case INDEX_op_divu2_i32: 2210be0f34b5SRichard Henderson return TCG_TARGET_HAS_div2_i32; 2211be0f34b5SRichard Henderson case INDEX_op_rotl_i32: 2212be0f34b5SRichard Henderson case INDEX_op_rotr_i32: 2213be0f34b5SRichard Henderson return TCG_TARGET_HAS_rot_i32; 2214be0f34b5SRichard Henderson case INDEX_op_deposit_i32: 2215be0f34b5SRichard Henderson return TCG_TARGET_HAS_deposit_i32; 2216be0f34b5SRichard Henderson case INDEX_op_extract_i32: 2217be0f34b5SRichard Henderson return TCG_TARGET_HAS_extract_i32; 2218be0f34b5SRichard Henderson case INDEX_op_sextract_i32: 2219be0f34b5SRichard Henderson return TCG_TARGET_HAS_sextract_i32; 2220fce1296fSRichard Henderson case INDEX_op_extract2_i32: 2221fce1296fSRichard Henderson return TCG_TARGET_HAS_extract2_i32; 2222be0f34b5SRichard Henderson case INDEX_op_add2_i32: 2223be0f34b5SRichard Henderson return TCG_TARGET_HAS_add2_i32; 2224be0f34b5SRichard Henderson case INDEX_op_sub2_i32: 2225be0f34b5SRichard Henderson return TCG_TARGET_HAS_sub2_i32; 2226be0f34b5SRichard Henderson case INDEX_op_mulu2_i32: 2227be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulu2_i32; 2228be0f34b5SRichard Henderson case INDEX_op_muls2_i32: 2229be0f34b5SRichard Henderson return TCG_TARGET_HAS_muls2_i32; 2230be0f34b5SRichard Henderson case INDEX_op_muluh_i32: 2231be0f34b5SRichard Henderson return TCG_TARGET_HAS_muluh_i32; 2232be0f34b5SRichard Henderson case INDEX_op_mulsh_i32: 2233be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulsh_i32; 2234be0f34b5SRichard Henderson case INDEX_op_ext8s_i32: 2235be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8s_i32; 2236be0f34b5SRichard Henderson case INDEX_op_ext16s_i32: 2237be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16s_i32; 2238be0f34b5SRichard Henderson case INDEX_op_ext8u_i32: 2239be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8u_i32; 2240be0f34b5SRichard Henderson case INDEX_op_ext16u_i32: 2241be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16u_i32; 2242be0f34b5SRichard Henderson case INDEX_op_bswap16_i32: 2243be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap16_i32; 2244be0f34b5SRichard Henderson case INDEX_op_bswap32_i32: 2245be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap32_i32; 2246be0f34b5SRichard Henderson case INDEX_op_not_i32: 2247be0f34b5SRichard Henderson return TCG_TARGET_HAS_not_i32; 2248be0f34b5SRichard Henderson case INDEX_op_andc_i32: 2249be0f34b5SRichard Henderson return TCG_TARGET_HAS_andc_i32; 2250be0f34b5SRichard Henderson case INDEX_op_orc_i32: 2251be0f34b5SRichard Henderson return TCG_TARGET_HAS_orc_i32; 2252be0f34b5SRichard Henderson case INDEX_op_eqv_i32: 2253be0f34b5SRichard Henderson return TCG_TARGET_HAS_eqv_i32; 2254be0f34b5SRichard Henderson case INDEX_op_nand_i32: 2255be0f34b5SRichard Henderson return TCG_TARGET_HAS_nand_i32; 2256be0f34b5SRichard Henderson case INDEX_op_nor_i32: 2257be0f34b5SRichard Henderson return TCG_TARGET_HAS_nor_i32; 2258be0f34b5SRichard Henderson case INDEX_op_clz_i32: 2259be0f34b5SRichard Henderson return TCG_TARGET_HAS_clz_i32; 2260be0f34b5SRichard Henderson case INDEX_op_ctz_i32: 2261be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctz_i32; 2262be0f34b5SRichard Henderson case INDEX_op_ctpop_i32: 2263be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctpop_i32; 2264be0f34b5SRichard Henderson 2265be0f34b5SRichard Henderson case INDEX_op_brcond2_i32: 2266be0f34b5SRichard Henderson case INDEX_op_setcond2_i32: 2267be0f34b5SRichard Henderson return TCG_TARGET_REG_BITS == 32; 2268be0f34b5SRichard Henderson 2269be0f34b5SRichard Henderson case INDEX_op_mov_i64: 2270be0f34b5SRichard Henderson case INDEX_op_setcond_i64: 2271be0f34b5SRichard Henderson case INDEX_op_brcond_i64: 22723871be75SRichard Henderson case INDEX_op_movcond_i64: 2273be0f34b5SRichard Henderson case INDEX_op_ld8u_i64: 2274be0f34b5SRichard Henderson case INDEX_op_ld8s_i64: 2275be0f34b5SRichard Henderson case INDEX_op_ld16u_i64: 2276be0f34b5SRichard Henderson case INDEX_op_ld16s_i64: 2277be0f34b5SRichard Henderson case INDEX_op_ld32u_i64: 2278be0f34b5SRichard Henderson case INDEX_op_ld32s_i64: 2279be0f34b5SRichard Henderson case INDEX_op_ld_i64: 2280be0f34b5SRichard Henderson case INDEX_op_st8_i64: 2281be0f34b5SRichard Henderson case INDEX_op_st16_i64: 2282be0f34b5SRichard Henderson case INDEX_op_st32_i64: 2283be0f34b5SRichard Henderson case INDEX_op_st_i64: 2284be0f34b5SRichard Henderson case INDEX_op_add_i64: 2285be0f34b5SRichard Henderson case INDEX_op_sub_i64: 2286b701f195SRichard Henderson case INDEX_op_neg_i64: 2287be0f34b5SRichard Henderson case INDEX_op_mul_i64: 2288be0f34b5SRichard Henderson case INDEX_op_and_i64: 2289be0f34b5SRichard Henderson case INDEX_op_or_i64: 2290be0f34b5SRichard Henderson case INDEX_op_xor_i64: 2291be0f34b5SRichard Henderson case INDEX_op_shl_i64: 2292be0f34b5SRichard Henderson case INDEX_op_shr_i64: 2293be0f34b5SRichard Henderson case INDEX_op_sar_i64: 2294be0f34b5SRichard Henderson case INDEX_op_ext_i32_i64: 2295be0f34b5SRichard Henderson case INDEX_op_extu_i32_i64: 2296be0f34b5SRichard Henderson return TCG_TARGET_REG_BITS == 64; 2297be0f34b5SRichard Henderson 22983635502dSRichard Henderson case INDEX_op_negsetcond_i64: 22993635502dSRichard Henderson return TCG_TARGET_HAS_negsetcond_i64; 2300be0f34b5SRichard Henderson case INDEX_op_div_i64: 2301be0f34b5SRichard Henderson case INDEX_op_divu_i64: 2302be0f34b5SRichard Henderson return TCG_TARGET_HAS_div_i64; 2303be0f34b5SRichard Henderson case INDEX_op_rem_i64: 2304be0f34b5SRichard Henderson case INDEX_op_remu_i64: 2305be0f34b5SRichard Henderson return TCG_TARGET_HAS_rem_i64; 2306be0f34b5SRichard Henderson case INDEX_op_div2_i64: 2307be0f34b5SRichard Henderson case INDEX_op_divu2_i64: 2308be0f34b5SRichard Henderson return TCG_TARGET_HAS_div2_i64; 2309be0f34b5SRichard Henderson case INDEX_op_rotl_i64: 2310be0f34b5SRichard Henderson case INDEX_op_rotr_i64: 2311be0f34b5SRichard Henderson return TCG_TARGET_HAS_rot_i64; 2312be0f34b5SRichard Henderson case INDEX_op_deposit_i64: 2313be0f34b5SRichard Henderson return TCG_TARGET_HAS_deposit_i64; 2314be0f34b5SRichard Henderson case INDEX_op_extract_i64: 2315be0f34b5SRichard Henderson return TCG_TARGET_HAS_extract_i64; 2316be0f34b5SRichard Henderson case INDEX_op_sextract_i64: 2317be0f34b5SRichard Henderson return TCG_TARGET_HAS_sextract_i64; 2318fce1296fSRichard Henderson case INDEX_op_extract2_i64: 2319fce1296fSRichard Henderson return TCG_TARGET_HAS_extract2_i64; 2320be0f34b5SRichard Henderson case INDEX_op_extrl_i64_i32: 2321be0f34b5SRichard Henderson case INDEX_op_extrh_i64_i32: 232213d885b0SRichard Henderson return TCG_TARGET_HAS_extr_i64_i32; 2323be0f34b5SRichard Henderson case INDEX_op_ext8s_i64: 2324be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8s_i64; 2325be0f34b5SRichard Henderson case INDEX_op_ext16s_i64: 2326be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16s_i64; 2327be0f34b5SRichard Henderson case INDEX_op_ext32s_i64: 2328be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext32s_i64; 2329be0f34b5SRichard Henderson case INDEX_op_ext8u_i64: 2330be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8u_i64; 2331be0f34b5SRichard Henderson case INDEX_op_ext16u_i64: 2332be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16u_i64; 2333be0f34b5SRichard Henderson case INDEX_op_ext32u_i64: 2334be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext32u_i64; 2335be0f34b5SRichard Henderson case INDEX_op_bswap16_i64: 2336be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap16_i64; 2337be0f34b5SRichard Henderson case INDEX_op_bswap32_i64: 2338be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap32_i64; 2339be0f34b5SRichard Henderson case INDEX_op_bswap64_i64: 2340be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap64_i64; 2341be0f34b5SRichard Henderson case INDEX_op_not_i64: 2342be0f34b5SRichard Henderson return TCG_TARGET_HAS_not_i64; 2343be0f34b5SRichard Henderson case INDEX_op_andc_i64: 2344be0f34b5SRichard Henderson return TCG_TARGET_HAS_andc_i64; 2345be0f34b5SRichard Henderson case INDEX_op_orc_i64: 2346be0f34b5SRichard Henderson return TCG_TARGET_HAS_orc_i64; 2347be0f34b5SRichard Henderson case INDEX_op_eqv_i64: 2348be0f34b5SRichard Henderson return TCG_TARGET_HAS_eqv_i64; 2349be0f34b5SRichard Henderson case INDEX_op_nand_i64: 2350be0f34b5SRichard Henderson return TCG_TARGET_HAS_nand_i64; 2351be0f34b5SRichard Henderson case INDEX_op_nor_i64: 2352be0f34b5SRichard Henderson return TCG_TARGET_HAS_nor_i64; 2353be0f34b5SRichard Henderson case INDEX_op_clz_i64: 2354be0f34b5SRichard Henderson return TCG_TARGET_HAS_clz_i64; 2355be0f34b5SRichard Henderson case INDEX_op_ctz_i64: 2356be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctz_i64; 2357be0f34b5SRichard Henderson case INDEX_op_ctpop_i64: 2358be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctpop_i64; 2359be0f34b5SRichard Henderson case INDEX_op_add2_i64: 2360be0f34b5SRichard Henderson return TCG_TARGET_HAS_add2_i64; 2361be0f34b5SRichard Henderson case INDEX_op_sub2_i64: 2362be0f34b5SRichard Henderson return TCG_TARGET_HAS_sub2_i64; 2363be0f34b5SRichard Henderson case INDEX_op_mulu2_i64: 2364be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulu2_i64; 2365be0f34b5SRichard Henderson case INDEX_op_muls2_i64: 2366be0f34b5SRichard Henderson return TCG_TARGET_HAS_muls2_i64; 2367be0f34b5SRichard Henderson case INDEX_op_muluh_i64: 2368be0f34b5SRichard Henderson return TCG_TARGET_HAS_muluh_i64; 2369be0f34b5SRichard Henderson case INDEX_op_mulsh_i64: 2370be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulsh_i64; 2371be0f34b5SRichard Henderson 2372d2fd745fSRichard Henderson case INDEX_op_mov_vec: 2373d2fd745fSRichard Henderson case INDEX_op_dup_vec: 237437ee55a0SRichard Henderson case INDEX_op_dupm_vec: 2375d2fd745fSRichard Henderson case INDEX_op_ld_vec: 2376d2fd745fSRichard Henderson case INDEX_op_st_vec: 2377d2fd745fSRichard Henderson case INDEX_op_add_vec: 2378d2fd745fSRichard Henderson case INDEX_op_sub_vec: 2379d2fd745fSRichard Henderson case INDEX_op_and_vec: 2380d2fd745fSRichard Henderson case INDEX_op_or_vec: 2381d2fd745fSRichard Henderson case INDEX_op_xor_vec: 2382212be173SRichard Henderson case INDEX_op_cmp_vec: 2383f44824ccSRichard Henderson return has_type; 2384d2fd745fSRichard Henderson case INDEX_op_dup2_vec: 2385f44824ccSRichard Henderson return has_type && TCG_TARGET_REG_BITS == 32; 2386d2fd745fSRichard Henderson case INDEX_op_not_vec: 2387f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_not_vec; 2388d2fd745fSRichard Henderson case INDEX_op_neg_vec: 2389f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_neg_vec; 2390bcefc902SRichard Henderson case INDEX_op_abs_vec: 2391f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_abs_vec; 2392d2fd745fSRichard Henderson case INDEX_op_andc_vec: 2393f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_andc_vec; 2394d2fd745fSRichard Henderson case INDEX_op_orc_vec: 2395f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_orc_vec; 2396ed523473SRichard Henderson case INDEX_op_nand_vec: 2397f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_nand_vec; 2398ed523473SRichard Henderson case INDEX_op_nor_vec: 2399f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_nor_vec; 2400ed523473SRichard Henderson case INDEX_op_eqv_vec: 2401f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_eqv_vec; 24023774030aSRichard Henderson case INDEX_op_mul_vec: 2403f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_mul_vec; 2404d0ec9796SRichard Henderson case INDEX_op_shli_vec: 2405d0ec9796SRichard Henderson case INDEX_op_shri_vec: 2406d0ec9796SRichard Henderson case INDEX_op_sari_vec: 2407f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_shi_vec; 2408d0ec9796SRichard Henderson case INDEX_op_shls_vec: 2409d0ec9796SRichard Henderson case INDEX_op_shrs_vec: 2410d0ec9796SRichard Henderson case INDEX_op_sars_vec: 2411f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_shs_vec; 2412d0ec9796SRichard Henderson case INDEX_op_shlv_vec: 2413d0ec9796SRichard Henderson case INDEX_op_shrv_vec: 2414d0ec9796SRichard Henderson case INDEX_op_sarv_vec: 2415f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_shv_vec; 2416b0f7e744SRichard Henderson case INDEX_op_rotli_vec: 2417f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_roti_vec; 241823850a74SRichard Henderson case INDEX_op_rotls_vec: 2419f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_rots_vec; 24205d0ceda9SRichard Henderson case INDEX_op_rotlv_vec: 24215d0ceda9SRichard Henderson case INDEX_op_rotrv_vec: 2422f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_rotv_vec; 24238afaf050SRichard Henderson case INDEX_op_ssadd_vec: 24248afaf050SRichard Henderson case INDEX_op_usadd_vec: 24258afaf050SRichard Henderson case INDEX_op_sssub_vec: 24268afaf050SRichard Henderson case INDEX_op_ussub_vec: 2427f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_sat_vec; 2428dd0a0fcdSRichard Henderson case INDEX_op_smin_vec: 2429dd0a0fcdSRichard Henderson case INDEX_op_umin_vec: 2430dd0a0fcdSRichard Henderson case INDEX_op_smax_vec: 2431dd0a0fcdSRichard Henderson case INDEX_op_umax_vec: 2432f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_minmax_vec; 243338dc1294SRichard Henderson case INDEX_op_bitsel_vec: 2434f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_bitsel_vec; 2435f75da298SRichard Henderson case INDEX_op_cmpsel_vec: 2436f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_cmpsel_vec; 2437d2fd745fSRichard Henderson 2438db432672SRichard Henderson default: 2439db432672SRichard Henderson tcg_debug_assert(op > INDEX_op_last_generic && op < NB_OPS); 2440db432672SRichard Henderson return true; 2441be0f34b5SRichard Henderson } 2442be0f34b5SRichard Henderson } 2443be0f34b5SRichard Henderson 24440e4c6424SRichard Henderson bool tcg_op_deposit_valid(TCGType type, unsigned ofs, unsigned len) 24450e4c6424SRichard Henderson { 24460e4c6424SRichard Henderson tcg_debug_assert(len > 0); 24470e4c6424SRichard Henderson switch (type) { 24480e4c6424SRichard Henderson case TCG_TYPE_I32: 24490e4c6424SRichard Henderson tcg_debug_assert(ofs < 32); 24500e4c6424SRichard Henderson tcg_debug_assert(len <= 32); 24510e4c6424SRichard Henderson tcg_debug_assert(ofs + len <= 32); 24520e4c6424SRichard Henderson return TCG_TARGET_HAS_deposit_i32 && 24530e4c6424SRichard Henderson TCG_TARGET_deposit_i32_valid(ofs, len); 24540e4c6424SRichard Henderson case TCG_TYPE_I64: 24550e4c6424SRichard Henderson tcg_debug_assert(ofs < 64); 24560e4c6424SRichard Henderson tcg_debug_assert(len <= 64); 24570e4c6424SRichard Henderson tcg_debug_assert(ofs + len <= 64); 24580e4c6424SRichard Henderson return TCG_TARGET_HAS_deposit_i64 && 24590e4c6424SRichard Henderson TCG_TARGET_deposit_i64_valid(ofs, len); 24600e4c6424SRichard Henderson default: 24610e4c6424SRichard Henderson g_assert_not_reached(); 24620e4c6424SRichard Henderson } 24630e4c6424SRichard Henderson } 24640e4c6424SRichard Henderson 246539004a71SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs); 246639004a71SRichard Henderson 246783a0ad26SRichard Henderson static void tcg_gen_callN(void *func, TCGHelperInfo *info, 246883a0ad26SRichard Henderson TCGTemp *ret, TCGTemp **args) 2469c896fe29Sbellard { 247039004a71SRichard Henderson TCGv_i64 extend_free[MAX_CALL_IARGS]; 247139004a71SRichard Henderson int n_extend = 0; 247275e8b9b7SRichard Henderson TCGOp *op; 247339004a71SRichard Henderson int i, n, pi = 0, total_args; 2474afb49896SRichard Henderson 2475d53106c9SRichard Henderson if (unlikely(g_once_init_enter(HELPER_INFO_INIT(info)))) { 2476d53106c9SRichard Henderson init_call_layout(info); 2477d53106c9SRichard Henderson g_once_init_leave(HELPER_INFO_INIT(info), HELPER_INFO_INIT_VAL(info)); 2478d53106c9SRichard Henderson } 2479d53106c9SRichard Henderson 248039004a71SRichard Henderson total_args = info->nr_out + info->nr_in + 2; 248139004a71SRichard Henderson op = tcg_op_alloc(INDEX_op_call, total_args); 24822bece2c8SRichard Henderson 248338b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN 248417083f6fSEmilio Cota /* Flag helpers that may affect guest state */ 2485b0748975SRichard Henderson if (tcg_ctx->plugin_insn && !(info->flags & TCG_CALL_NO_SIDE_EFFECTS)) { 248638b47b19SEmilio G. Cota tcg_ctx->plugin_insn->calls_helpers = true; 248738b47b19SEmilio G. Cota } 248838b47b19SEmilio G. Cota #endif 248938b47b19SEmilio G. Cota 249039004a71SRichard Henderson TCGOP_CALLO(op) = n = info->nr_out; 249139004a71SRichard Henderson switch (n) { 249239004a71SRichard Henderson case 0: 249339004a71SRichard Henderson tcg_debug_assert(ret == NULL); 249439004a71SRichard Henderson break; 249539004a71SRichard Henderson case 1: 249639004a71SRichard Henderson tcg_debug_assert(ret != NULL); 249739004a71SRichard Henderson op->args[pi++] = temp_arg(ret); 249839004a71SRichard Henderson break; 249939004a71SRichard Henderson case 2: 2500466d3759SRichard Henderson case 4: 250139004a71SRichard Henderson tcg_debug_assert(ret != NULL); 2502466d3759SRichard Henderson tcg_debug_assert(ret->base_type == ret->type + ctz32(n)); 250339004a71SRichard Henderson tcg_debug_assert(ret->temp_subindex == 0); 2504466d3759SRichard Henderson for (i = 0; i < n; ++i) { 2505466d3759SRichard Henderson op->args[pi++] = temp_arg(ret + i); 2506466d3759SRichard Henderson } 250739004a71SRichard Henderson break; 250839004a71SRichard Henderson default: 250939004a71SRichard Henderson g_assert_not_reached(); 251039004a71SRichard Henderson } 25117319d83aSRichard Henderson 251239004a71SRichard Henderson TCGOP_CALLI(op) = n = info->nr_in; 251339004a71SRichard Henderson for (i = 0; i < n; i++) { 251439004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i]; 251539004a71SRichard Henderson TCGTemp *ts = args[loc->arg_idx] + loc->tmp_subindex; 251639004a71SRichard Henderson 251739004a71SRichard Henderson switch (loc->kind) { 251839004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 2519313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF: 2520313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF_N: 252139004a71SRichard Henderson op->args[pi++] = temp_arg(ts); 252239004a71SRichard Henderson break; 252339004a71SRichard Henderson 252439004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 252539004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 252639004a71SRichard Henderson { 25275dd48602SRichard Henderson TCGv_i64 temp = tcg_temp_ebb_new_i64(); 252839004a71SRichard Henderson TCGv_i32 orig = temp_tcgv_i32(ts); 252939004a71SRichard Henderson 253039004a71SRichard Henderson if (loc->kind == TCG_CALL_ARG_EXTEND_S) { 253118cf3d07SRichard Henderson tcg_gen_ext_i32_i64(temp, orig); 25322bece2c8SRichard Henderson } else { 253318cf3d07SRichard Henderson tcg_gen_extu_i32_i64(temp, orig); 25342bece2c8SRichard Henderson } 253539004a71SRichard Henderson op->args[pi++] = tcgv_i64_arg(temp); 253639004a71SRichard Henderson extend_free[n_extend++] = temp; 25372bece2c8SRichard Henderson } 253839004a71SRichard Henderson break; 25392bece2c8SRichard Henderson 2540e2a9dd6bSRichard Henderson default: 2541e2a9dd6bSRichard Henderson g_assert_not_reached(); 2542e2a9dd6bSRichard Henderson } 2543c896fe29Sbellard } 254483a0ad26SRichard Henderson op->args[pi++] = (uintptr_t)func; 25453e92aa34SRichard Henderson op->args[pi++] = (uintptr_t)info; 254639004a71SRichard Henderson tcg_debug_assert(pi == total_args); 2547a7812ae4Spbrook 254807843f75SRichard Henderson if (tcg_ctx->emit_before_op) { 254907843f75SRichard Henderson QTAILQ_INSERT_BEFORE(tcg_ctx->emit_before_op, op, link); 255007843f75SRichard Henderson } else { 255139004a71SRichard Henderson QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link); 255207843f75SRichard Henderson } 25532bece2c8SRichard Henderson 255439004a71SRichard Henderson tcg_debug_assert(n_extend < ARRAY_SIZE(extend_free)); 255539004a71SRichard Henderson for (i = 0; i < n_extend; ++i) { 255639004a71SRichard Henderson tcg_temp_free_i64(extend_free[i]); 2557eb8b0224SRichard Henderson } 2558a7812ae4Spbrook } 2559c896fe29Sbellard 256083a0ad26SRichard Henderson void tcg_gen_call0(void *func, TCGHelperInfo *info, TCGTemp *ret) 2561a3a692b8SRichard Henderson { 256283a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, NULL); 2563a3a692b8SRichard Henderson } 2564a3a692b8SRichard Henderson 256583a0ad26SRichard Henderson void tcg_gen_call1(void *func, TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1) 2566a3a692b8SRichard Henderson { 256783a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, &t1); 2568a3a692b8SRichard Henderson } 2569a3a692b8SRichard Henderson 257083a0ad26SRichard Henderson void tcg_gen_call2(void *func, TCGHelperInfo *info, TCGTemp *ret, 257183a0ad26SRichard Henderson TCGTemp *t1, TCGTemp *t2) 2572a3a692b8SRichard Henderson { 2573a3a692b8SRichard Henderson TCGTemp *args[2] = { t1, t2 }; 257483a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, args); 2575a3a692b8SRichard Henderson } 2576a3a692b8SRichard Henderson 257783a0ad26SRichard Henderson void tcg_gen_call3(void *func, TCGHelperInfo *info, TCGTemp *ret, 257883a0ad26SRichard Henderson TCGTemp *t1, TCGTemp *t2, TCGTemp *t3) 2579a3a692b8SRichard Henderson { 2580a3a692b8SRichard Henderson TCGTemp *args[3] = { t1, t2, t3 }; 258183a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, args); 2582a3a692b8SRichard Henderson } 2583a3a692b8SRichard Henderson 258483a0ad26SRichard Henderson void tcg_gen_call4(void *func, TCGHelperInfo *info, TCGTemp *ret, 258583a0ad26SRichard Henderson TCGTemp *t1, TCGTemp *t2, TCGTemp *t3, TCGTemp *t4) 2586a3a692b8SRichard Henderson { 2587a3a692b8SRichard Henderson TCGTemp *args[4] = { t1, t2, t3, t4 }; 258883a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, args); 2589a3a692b8SRichard Henderson } 2590a3a692b8SRichard Henderson 259183a0ad26SRichard Henderson void tcg_gen_call5(void *func, TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1, 2592a3a692b8SRichard Henderson TCGTemp *t2, TCGTemp *t3, TCGTemp *t4, TCGTemp *t5) 2593a3a692b8SRichard Henderson { 2594a3a692b8SRichard Henderson TCGTemp *args[5] = { t1, t2, t3, t4, t5 }; 259583a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, args); 2596a3a692b8SRichard Henderson } 2597a3a692b8SRichard Henderson 259883a0ad26SRichard Henderson void tcg_gen_call6(void *func, TCGHelperInfo *info, TCGTemp *ret, 259983a0ad26SRichard Henderson TCGTemp *t1, TCGTemp *t2, TCGTemp *t3, 260083a0ad26SRichard Henderson TCGTemp *t4, TCGTemp *t5, TCGTemp *t6) 2601a3a692b8SRichard Henderson { 2602a3a692b8SRichard Henderson TCGTemp *args[6] = { t1, t2, t3, t4, t5, t6 }; 260383a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, args); 2604a3a692b8SRichard Henderson } 2605a3a692b8SRichard Henderson 260683a0ad26SRichard Henderson void tcg_gen_call7(void *func, TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1, 2607a3a692b8SRichard Henderson TCGTemp *t2, TCGTemp *t3, TCGTemp *t4, 2608a3a692b8SRichard Henderson TCGTemp *t5, TCGTemp *t6, TCGTemp *t7) 2609a3a692b8SRichard Henderson { 2610a3a692b8SRichard Henderson TCGTemp *args[7] = { t1, t2, t3, t4, t5, t6, t7 }; 261183a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, args); 2612a3a692b8SRichard Henderson } 2613a3a692b8SRichard Henderson 26148fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s) 2615c896fe29Sbellard { 2616ac3b8891SRichard Henderson int i, n; 2617ac3b8891SRichard Henderson 2618ee17db83SRichard Henderson for (i = 0, n = s->nb_temps; i < n; i++) { 2619ee17db83SRichard Henderson TCGTemp *ts = &s->temps[i]; 2620ee17db83SRichard Henderson TCGTempVal val = TEMP_VAL_MEM; 2621ee17db83SRichard Henderson 2622ee17db83SRichard Henderson switch (ts->kind) { 2623c0522136SRichard Henderson case TEMP_CONST: 2624c0522136SRichard Henderson val = TEMP_VAL_CONST; 2625c0522136SRichard Henderson break; 2626ee17db83SRichard Henderson case TEMP_FIXED: 2627ee17db83SRichard Henderson val = TEMP_VAL_REG; 2628ee17db83SRichard Henderson break; 2629ee17db83SRichard Henderson case TEMP_GLOBAL: 2630ee17db83SRichard Henderson break; 2631c7482438SRichard Henderson case TEMP_EBB: 2632ee17db83SRichard Henderson val = TEMP_VAL_DEAD; 2633ee17db83SRichard Henderson /* fall through */ 2634f57c6915SRichard Henderson case TEMP_TB: 2635e8996ee0Sbellard ts->mem_allocated = 0; 2636ee17db83SRichard Henderson break; 2637ee17db83SRichard Henderson default: 2638ee17db83SRichard Henderson g_assert_not_reached(); 2639ee17db83SRichard Henderson } 2640ee17db83SRichard Henderson ts->val_type = val; 2641e8996ee0Sbellard } 2642f8b2f202SRichard Henderson 2643f8b2f202SRichard Henderson memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp)); 2644c896fe29Sbellard } 2645c896fe29Sbellard 2646f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size, 2647f8b2f202SRichard Henderson TCGTemp *ts) 2648c896fe29Sbellard { 26491807f4c4SRichard Henderson int idx = temp_idx(ts); 2650ac56dd48Spbrook 2651ee17db83SRichard Henderson switch (ts->kind) { 2652ee17db83SRichard Henderson case TEMP_FIXED: 2653ee17db83SRichard Henderson case TEMP_GLOBAL: 2654ac56dd48Spbrook pstrcpy(buf, buf_size, ts->name); 2655ee17db83SRichard Henderson break; 2656f57c6915SRichard Henderson case TEMP_TB: 2657641d5fbeSbellard snprintf(buf, buf_size, "loc%d", idx - s->nb_globals); 2658ee17db83SRichard Henderson break; 2659c7482438SRichard Henderson case TEMP_EBB: 2660ac56dd48Spbrook snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals); 2661ee17db83SRichard Henderson break; 2662c0522136SRichard Henderson case TEMP_CONST: 2663c0522136SRichard Henderson switch (ts->type) { 2664c0522136SRichard Henderson case TCG_TYPE_I32: 2665c0522136SRichard Henderson snprintf(buf, buf_size, "$0x%x", (int32_t)ts->val); 2666c0522136SRichard Henderson break; 2667c0522136SRichard Henderson #if TCG_TARGET_REG_BITS > 32 2668c0522136SRichard Henderson case TCG_TYPE_I64: 2669c0522136SRichard Henderson snprintf(buf, buf_size, "$0x%" PRIx64, ts->val); 2670c0522136SRichard Henderson break; 2671c0522136SRichard Henderson #endif 2672c0522136SRichard Henderson case TCG_TYPE_V64: 2673c0522136SRichard Henderson case TCG_TYPE_V128: 2674c0522136SRichard Henderson case TCG_TYPE_V256: 2675c0522136SRichard Henderson snprintf(buf, buf_size, "v%d$0x%" PRIx64, 2676c0522136SRichard Henderson 64 << (ts->type - TCG_TYPE_V64), ts->val); 2677c0522136SRichard Henderson break; 2678c0522136SRichard Henderson default: 2679c0522136SRichard Henderson g_assert_not_reached(); 2680c0522136SRichard Henderson } 2681c0522136SRichard Henderson break; 2682c896fe29Sbellard } 2683c896fe29Sbellard return buf; 2684c896fe29Sbellard } 2685c896fe29Sbellard 268643439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf, 268743439139SRichard Henderson int buf_size, TCGArg arg) 2688f8b2f202SRichard Henderson { 268943439139SRichard Henderson return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg)); 2690f8b2f202SRichard Henderson } 2691f8b2f202SRichard Henderson 2692f48f3edeSblueswir1 static const char * const cond_name[] = 2693f48f3edeSblueswir1 { 26940aed257fSRichard Henderson [TCG_COND_NEVER] = "never", 26950aed257fSRichard Henderson [TCG_COND_ALWAYS] = "always", 2696f48f3edeSblueswir1 [TCG_COND_EQ] = "eq", 2697f48f3edeSblueswir1 [TCG_COND_NE] = "ne", 2698f48f3edeSblueswir1 [TCG_COND_LT] = "lt", 2699f48f3edeSblueswir1 [TCG_COND_GE] = "ge", 2700f48f3edeSblueswir1 [TCG_COND_LE] = "le", 2701f48f3edeSblueswir1 [TCG_COND_GT] = "gt", 2702f48f3edeSblueswir1 [TCG_COND_LTU] = "ltu", 2703f48f3edeSblueswir1 [TCG_COND_GEU] = "geu", 2704f48f3edeSblueswir1 [TCG_COND_LEU] = "leu", 2705d48097d0SRichard Henderson [TCG_COND_GTU] = "gtu", 2706d48097d0SRichard Henderson [TCG_COND_TSTEQ] = "tsteq", 2707d48097d0SRichard Henderson [TCG_COND_TSTNE] = "tstne", 2708f48f3edeSblueswir1 }; 2709f48f3edeSblueswir1 271012fde9bcSRichard Henderson static const char * const ldst_name[(MO_BSWAP | MO_SSIZE) + 1] = 2711f713d6adSRichard Henderson { 2712f713d6adSRichard Henderson [MO_UB] = "ub", 2713f713d6adSRichard Henderson [MO_SB] = "sb", 2714f713d6adSRichard Henderson [MO_LEUW] = "leuw", 2715f713d6adSRichard Henderson [MO_LESW] = "lesw", 2716f713d6adSRichard Henderson [MO_LEUL] = "leul", 2717f713d6adSRichard Henderson [MO_LESL] = "lesl", 2718fc313c64SFrédéric Pétrot [MO_LEUQ] = "leq", 2719f713d6adSRichard Henderson [MO_BEUW] = "beuw", 2720f713d6adSRichard Henderson [MO_BESW] = "besw", 2721f713d6adSRichard Henderson [MO_BEUL] = "beul", 2722f713d6adSRichard Henderson [MO_BESL] = "besl", 2723fc313c64SFrédéric Pétrot [MO_BEUQ] = "beq", 272412fde9bcSRichard Henderson [MO_128 + MO_BE] = "beo", 272512fde9bcSRichard Henderson [MO_128 + MO_LE] = "leo", 2726f713d6adSRichard Henderson }; 2727f713d6adSRichard Henderson 27281f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = { 27291f00b27fSSergey Sorokin [MO_UNALN >> MO_ASHIFT] = "un+", 27301f00b27fSSergey Sorokin [MO_ALIGN >> MO_ASHIFT] = "al+", 27311f00b27fSSergey Sorokin [MO_ALIGN_2 >> MO_ASHIFT] = "al2+", 27321f00b27fSSergey Sorokin [MO_ALIGN_4 >> MO_ASHIFT] = "al4+", 27331f00b27fSSergey Sorokin [MO_ALIGN_8 >> MO_ASHIFT] = "al8+", 27341f00b27fSSergey Sorokin [MO_ALIGN_16 >> MO_ASHIFT] = "al16+", 27351f00b27fSSergey Sorokin [MO_ALIGN_32 >> MO_ASHIFT] = "al32+", 27361f00b27fSSergey Sorokin [MO_ALIGN_64 >> MO_ASHIFT] = "al64+", 27371f00b27fSSergey Sorokin }; 27381f00b27fSSergey Sorokin 273937031fefSRichard Henderson static const char * const atom_name[(MO_ATOM_MASK >> MO_ATOM_SHIFT) + 1] = { 274037031fefSRichard Henderson [MO_ATOM_IFALIGN >> MO_ATOM_SHIFT] = "", 274137031fefSRichard Henderson [MO_ATOM_IFALIGN_PAIR >> MO_ATOM_SHIFT] = "pair+", 274237031fefSRichard Henderson [MO_ATOM_WITHIN16 >> MO_ATOM_SHIFT] = "w16+", 274337031fefSRichard Henderson [MO_ATOM_WITHIN16_PAIR >> MO_ATOM_SHIFT] = "w16p+", 274437031fefSRichard Henderson [MO_ATOM_SUBALIGN >> MO_ATOM_SHIFT] = "sub+", 274537031fefSRichard Henderson [MO_ATOM_NONE >> MO_ATOM_SHIFT] = "noat+", 274637031fefSRichard Henderson }; 274737031fefSRichard Henderson 2748587195bdSRichard Henderson static const char bswap_flag_name[][6] = { 2749587195bdSRichard Henderson [TCG_BSWAP_IZ] = "iz", 2750587195bdSRichard Henderson [TCG_BSWAP_OZ] = "oz", 2751587195bdSRichard Henderson [TCG_BSWAP_OS] = "os", 2752587195bdSRichard Henderson [TCG_BSWAP_IZ | TCG_BSWAP_OZ] = "iz,oz", 2753587195bdSRichard Henderson [TCG_BSWAP_IZ | TCG_BSWAP_OS] = "iz,os", 2754587195bdSRichard Henderson }; 2755587195bdSRichard Henderson 2756b384c734SRichard Henderson #ifdef CONFIG_PLUGIN 2757b384c734SRichard Henderson static const char * const plugin_from_name[] = { 2758b384c734SRichard Henderson "from-tb", 2759b384c734SRichard Henderson "from-insn", 2760b384c734SRichard Henderson "after-insn", 2761b384c734SRichard Henderson "after-tb", 2762b384c734SRichard Henderson }; 2763b384c734SRichard Henderson #endif 2764b384c734SRichard Henderson 2765b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d) 2766b016486eSRichard Henderson { 2767b016486eSRichard Henderson return (d & (d - 1)) == 0; 2768b016486eSRichard Henderson } 2769b016486eSRichard Henderson 2770b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d) 2771b016486eSRichard Henderson { 2772b016486eSRichard Henderson if (TCG_TARGET_NB_REGS <= 32) { 2773b016486eSRichard Henderson return ctz32(d); 2774b016486eSRichard Henderson } else { 2775b016486eSRichard Henderson return ctz64(d); 2776b016486eSRichard Henderson } 2777b016486eSRichard Henderson } 2778b016486eSRichard Henderson 2779b7a83ff8SRichard Henderson /* Return only the number of characters output -- no error return. */ 2780b7a83ff8SRichard Henderson #define ne_fprintf(...) \ 2781b7a83ff8SRichard Henderson ({ int ret_ = fprintf(__VA_ARGS__); ret_ >= 0 ? ret_ : 0; }) 2782b7a83ff8SRichard Henderson 2783b384c734SRichard Henderson void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs) 2784c896fe29Sbellard { 2785c896fe29Sbellard char buf[128]; 2786c45cb8bbSRichard Henderson TCGOp *op; 2787c896fe29Sbellard 278815fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 2789c45cb8bbSRichard Henderson int i, k, nb_oargs, nb_iargs, nb_cargs; 2790c45cb8bbSRichard Henderson const TCGOpDef *def; 2791c45cb8bbSRichard Henderson TCGOpcode c; 2792bdfb460eSRichard Henderson int col = 0; 2793c45cb8bbSRichard Henderson 2794c45cb8bbSRichard Henderson c = op->opc; 2795c896fe29Sbellard def = &tcg_op_defs[c]; 2796c45cb8bbSRichard Henderson 2797765b842aSRichard Henderson if (c == INDEX_op_insn_start) { 2798b016486eSRichard Henderson nb_oargs = 0; 2799b7a83ff8SRichard Henderson col += ne_fprintf(f, "\n ----"); 28009aef40edSRichard Henderson 2801747bd69dSRichard Henderson for (i = 0, k = s->insn_start_words; i < k; ++i) { 2802c9ad8d27SRichard Henderson col += ne_fprintf(f, " %016" PRIx64, 2803c9ad8d27SRichard Henderson tcg_get_insn_start_param(op, i)); 2804eeacee4dSBlue Swirl } 28057e4597d7Sbellard } else if (c == INDEX_op_call) { 28063e92aa34SRichard Henderson const TCGHelperInfo *info = tcg_call_info(op); 2807fa52e660SRichard Henderson void *func = tcg_call_func(op); 28083e92aa34SRichard Henderson 2809c896fe29Sbellard /* variable number of arguments */ 2810cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 2811cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 2812c896fe29Sbellard nb_cargs = def->nb_cargs; 2813b03cce8eSbellard 2814b7a83ff8SRichard Henderson col += ne_fprintf(f, " %s ", def->name); 28153e92aa34SRichard Henderson 28163e92aa34SRichard Henderson /* 28173e92aa34SRichard Henderson * Print the function name from TCGHelperInfo, if available. 28183e92aa34SRichard Henderson * Note that plugins have a template function for the info, 28193e92aa34SRichard Henderson * but the actual function pointer comes from the plugin. 28203e92aa34SRichard Henderson */ 28213e92aa34SRichard Henderson if (func == info->func) { 2822b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s", info->name); 28233e92aa34SRichard Henderson } else { 2824b7a83ff8SRichard Henderson col += ne_fprintf(f, "plugin(%p)", func); 28253e92aa34SRichard Henderson } 28263e92aa34SRichard Henderson 2827b7a83ff8SRichard Henderson col += ne_fprintf(f, ",$0x%x,$%d", info->flags, nb_oargs); 2828b03cce8eSbellard for (i = 0; i < nb_oargs; i++) { 2829b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", tcg_get_arg_str(s, buf, sizeof(buf), 2830efee3746SRichard Henderson op->args[i])); 2831b03cce8eSbellard } 2832cf066674SRichard Henderson for (i = 0; i < nb_iargs; i++) { 2833efee3746SRichard Henderson TCGArg arg = op->args[nb_oargs + i]; 283439004a71SRichard Henderson const char *t = tcg_get_arg_str(s, buf, sizeof(buf), arg); 2835b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", t); 2836e8996ee0Sbellard } 2837b03cce8eSbellard } else { 2838b7a83ff8SRichard Henderson col += ne_fprintf(f, " %s ", def->name); 2839c45cb8bbSRichard Henderson 2840c896fe29Sbellard nb_oargs = def->nb_oargs; 2841c896fe29Sbellard nb_iargs = def->nb_iargs; 2842c896fe29Sbellard nb_cargs = def->nb_cargs; 2843c896fe29Sbellard 2844d2fd745fSRichard Henderson if (def->flags & TCG_OPF_VECTOR) { 28454d872218SRichard Henderson col += ne_fprintf(f, "v%d,e%d,", 28464d872218SRichard Henderson 8 * tcg_type_size(TCGOP_TYPE(op)), 2847d2fd745fSRichard Henderson 8 << TCGOP_VECE(op)); 2848d2fd745fSRichard Henderson } 2849d2fd745fSRichard Henderson 2850c896fe29Sbellard k = 0; 2851c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 2852b7a83ff8SRichard Henderson const char *sep = k ? "," : ""; 2853b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s%s", sep, 2854b7a83ff8SRichard Henderson tcg_get_arg_str(s, buf, sizeof(buf), 2855efee3746SRichard Henderson op->args[k++])); 2856c896fe29Sbellard } 2857c896fe29Sbellard for (i = 0; i < nb_iargs; i++) { 2858b7a83ff8SRichard Henderson const char *sep = k ? "," : ""; 2859b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s%s", sep, 2860b7a83ff8SRichard Henderson tcg_get_arg_str(s, buf, sizeof(buf), 2861efee3746SRichard Henderson op->args[k++])); 2862c896fe29Sbellard } 2863be210acbSRichard Henderson switch (c) { 2864be210acbSRichard Henderson case INDEX_op_brcond_i32: 2865ffc5ea09SRichard Henderson case INDEX_op_setcond_i32: 28663635502dSRichard Henderson case INDEX_op_negsetcond_i32: 2867ffc5ea09SRichard Henderson case INDEX_op_movcond_i32: 2868be210acbSRichard Henderson case INDEX_op_brcond2_i32: 2869be210acbSRichard Henderson case INDEX_op_setcond2_i32: 2870ffc5ea09SRichard Henderson case INDEX_op_brcond_i64: 2871be210acbSRichard Henderson case INDEX_op_setcond_i64: 28723635502dSRichard Henderson case INDEX_op_negsetcond_i64: 2873ffc5ea09SRichard Henderson case INDEX_op_movcond_i64: 2874212be173SRichard Henderson case INDEX_op_cmp_vec: 2875f75da298SRichard Henderson case INDEX_op_cmpsel_vec: 2876efee3746SRichard Henderson if (op->args[k] < ARRAY_SIZE(cond_name) 2877efee3746SRichard Henderson && cond_name[op->args[k]]) { 2878b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", cond_name[op->args[k++]]); 2879eeacee4dSBlue Swirl } else { 2880b7a83ff8SRichard Henderson col += ne_fprintf(f, ",$0x%" TCG_PRIlx, op->args[k++]); 2881eeacee4dSBlue Swirl } 2882f48f3edeSblueswir1 i = 1; 2883be210acbSRichard Henderson break; 2884fecccfccSRichard Henderson case INDEX_op_qemu_ld_a32_i32: 2885fecccfccSRichard Henderson case INDEX_op_qemu_ld_a64_i32: 2886fecccfccSRichard Henderson case INDEX_op_qemu_st_a32_i32: 2887fecccfccSRichard Henderson case INDEX_op_qemu_st_a64_i32: 2888fecccfccSRichard Henderson case INDEX_op_qemu_st8_a32_i32: 2889fecccfccSRichard Henderson case INDEX_op_qemu_st8_a64_i32: 2890fecccfccSRichard Henderson case INDEX_op_qemu_ld_a32_i64: 2891fecccfccSRichard Henderson case INDEX_op_qemu_ld_a64_i64: 2892fecccfccSRichard Henderson case INDEX_op_qemu_st_a32_i64: 2893fecccfccSRichard Henderson case INDEX_op_qemu_st_a64_i64: 2894fecccfccSRichard Henderson case INDEX_op_qemu_ld_a32_i128: 2895fecccfccSRichard Henderson case INDEX_op_qemu_ld_a64_i128: 2896fecccfccSRichard Henderson case INDEX_op_qemu_st_a32_i128: 2897fecccfccSRichard Henderson case INDEX_op_qemu_st_a64_i128: 289859227d5dSRichard Henderson { 289937031fefSRichard Henderson const char *s_al, *s_op, *s_at; 29009002ffcbSRichard Henderson MemOpIdx oi = op->args[k++]; 29019a239c6eSPhilippe Mathieu-Daudé MemOp mop = get_memop(oi); 290259227d5dSRichard Henderson unsigned ix = get_mmuidx(oi); 290359227d5dSRichard Henderson 29049a239c6eSPhilippe Mathieu-Daudé s_al = alignment_name[(mop & MO_AMASK) >> MO_ASHIFT]; 29059a239c6eSPhilippe Mathieu-Daudé s_op = ldst_name[mop & (MO_BSWAP | MO_SSIZE)]; 29069a239c6eSPhilippe Mathieu-Daudé s_at = atom_name[(mop & MO_ATOM_MASK) >> MO_ATOM_SHIFT]; 29079a239c6eSPhilippe Mathieu-Daudé mop &= ~(MO_AMASK | MO_BSWAP | MO_SSIZE | MO_ATOM_MASK); 290837031fefSRichard Henderson 290937031fefSRichard Henderson /* If all fields are accounted for, print symbolically. */ 29109a239c6eSPhilippe Mathieu-Daudé if (!mop && s_al && s_op && s_at) { 291137031fefSRichard Henderson col += ne_fprintf(f, ",%s%s%s,%u", 291237031fefSRichard Henderson s_at, s_al, s_op, ix); 291337031fefSRichard Henderson } else { 29149a239c6eSPhilippe Mathieu-Daudé mop = get_memop(oi); 29159a239c6eSPhilippe Mathieu-Daudé col += ne_fprintf(f, ",$0x%x,%u", mop, ix); 2916f713d6adSRichard Henderson } 2917f713d6adSRichard Henderson i = 1; 291859227d5dSRichard Henderson } 2919f713d6adSRichard Henderson break; 2920587195bdSRichard Henderson case INDEX_op_bswap16_i32: 2921587195bdSRichard Henderson case INDEX_op_bswap16_i64: 2922587195bdSRichard Henderson case INDEX_op_bswap32_i32: 2923587195bdSRichard Henderson case INDEX_op_bswap32_i64: 2924587195bdSRichard Henderson case INDEX_op_bswap64_i64: 2925587195bdSRichard Henderson { 2926587195bdSRichard Henderson TCGArg flags = op->args[k]; 2927587195bdSRichard Henderson const char *name = NULL; 2928587195bdSRichard Henderson 2929587195bdSRichard Henderson if (flags < ARRAY_SIZE(bswap_flag_name)) { 2930587195bdSRichard Henderson name = bswap_flag_name[flags]; 2931587195bdSRichard Henderson } 2932587195bdSRichard Henderson if (name) { 2933b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", name); 2934587195bdSRichard Henderson } else { 2935b7a83ff8SRichard Henderson col += ne_fprintf(f, ",$0x%" TCG_PRIlx, flags); 2936587195bdSRichard Henderson } 2937587195bdSRichard Henderson i = k = 1; 2938587195bdSRichard Henderson } 2939587195bdSRichard Henderson break; 2940b384c734SRichard Henderson #ifdef CONFIG_PLUGIN 2941b384c734SRichard Henderson case INDEX_op_plugin_cb: 2942b384c734SRichard Henderson { 2943b384c734SRichard Henderson TCGArg from = op->args[k++]; 2944b384c734SRichard Henderson const char *name = NULL; 2945b384c734SRichard Henderson 2946b384c734SRichard Henderson if (from < ARRAY_SIZE(plugin_from_name)) { 2947b384c734SRichard Henderson name = plugin_from_name[from]; 2948b384c734SRichard Henderson } 2949b384c734SRichard Henderson if (name) { 2950b384c734SRichard Henderson col += ne_fprintf(f, "%s", name); 2951b384c734SRichard Henderson } else { 2952b384c734SRichard Henderson col += ne_fprintf(f, "$0x%" TCG_PRIlx, from); 2953b384c734SRichard Henderson } 2954b384c734SRichard Henderson i = 1; 2955b384c734SRichard Henderson } 2956b384c734SRichard Henderson break; 2957b384c734SRichard Henderson #endif 2958be210acbSRichard Henderson default: 2959f48f3edeSblueswir1 i = 0; 2960be210acbSRichard Henderson break; 2961be210acbSRichard Henderson } 296251e3972cSRichard Henderson switch (c) { 296351e3972cSRichard Henderson case INDEX_op_set_label: 296451e3972cSRichard Henderson case INDEX_op_br: 296551e3972cSRichard Henderson case INDEX_op_brcond_i32: 296651e3972cSRichard Henderson case INDEX_op_brcond_i64: 296751e3972cSRichard Henderson case INDEX_op_brcond2_i32: 2968b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s$L%d", k ? "," : "", 2969efee3746SRichard Henderson arg_label(op->args[k])->id); 297051e3972cSRichard Henderson i++, k++; 297151e3972cSRichard Henderson break; 29723470867bSRichard Henderson case INDEX_op_mb: 29733470867bSRichard Henderson { 29743470867bSRichard Henderson TCGBar membar = op->args[k]; 29753470867bSRichard Henderson const char *b_op, *m_op; 29763470867bSRichard Henderson 29773470867bSRichard Henderson switch (membar & TCG_BAR_SC) { 29783470867bSRichard Henderson case 0: 29793470867bSRichard Henderson b_op = "none"; 29803470867bSRichard Henderson break; 29813470867bSRichard Henderson case TCG_BAR_LDAQ: 29823470867bSRichard Henderson b_op = "acq"; 29833470867bSRichard Henderson break; 29843470867bSRichard Henderson case TCG_BAR_STRL: 29853470867bSRichard Henderson b_op = "rel"; 29863470867bSRichard Henderson break; 29873470867bSRichard Henderson case TCG_BAR_SC: 29883470867bSRichard Henderson b_op = "seq"; 29893470867bSRichard Henderson break; 29903470867bSRichard Henderson default: 29913470867bSRichard Henderson g_assert_not_reached(); 29923470867bSRichard Henderson } 29933470867bSRichard Henderson 29943470867bSRichard Henderson switch (membar & TCG_MO_ALL) { 29953470867bSRichard Henderson case 0: 29963470867bSRichard Henderson m_op = "none"; 29973470867bSRichard Henderson break; 29983470867bSRichard Henderson case TCG_MO_LD_LD: 29993470867bSRichard Henderson m_op = "rr"; 30003470867bSRichard Henderson break; 30013470867bSRichard Henderson case TCG_MO_LD_ST: 30023470867bSRichard Henderson m_op = "rw"; 30033470867bSRichard Henderson break; 30043470867bSRichard Henderson case TCG_MO_ST_LD: 30053470867bSRichard Henderson m_op = "wr"; 30063470867bSRichard Henderson break; 30073470867bSRichard Henderson case TCG_MO_ST_ST: 30083470867bSRichard Henderson m_op = "ww"; 30093470867bSRichard Henderson break; 30103470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_LD_ST: 30113470867bSRichard Henderson m_op = "rr+rw"; 30123470867bSRichard Henderson break; 30133470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_ST_LD: 30143470867bSRichard Henderson m_op = "rr+wr"; 30153470867bSRichard Henderson break; 30163470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_ST_ST: 30173470867bSRichard Henderson m_op = "rr+ww"; 30183470867bSRichard Henderson break; 30193470867bSRichard Henderson case TCG_MO_LD_ST | TCG_MO_ST_LD: 30203470867bSRichard Henderson m_op = "rw+wr"; 30213470867bSRichard Henderson break; 30223470867bSRichard Henderson case TCG_MO_LD_ST | TCG_MO_ST_ST: 30233470867bSRichard Henderson m_op = "rw+ww"; 30243470867bSRichard Henderson break; 30253470867bSRichard Henderson case TCG_MO_ST_LD | TCG_MO_ST_ST: 30263470867bSRichard Henderson m_op = "wr+ww"; 30273470867bSRichard Henderson break; 30283470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_MO_ST_LD: 30293470867bSRichard Henderson m_op = "rr+rw+wr"; 30303470867bSRichard Henderson break; 30313470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_MO_ST_ST: 30323470867bSRichard Henderson m_op = "rr+rw+ww"; 30333470867bSRichard Henderson break; 30343470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_ST_LD | TCG_MO_ST_ST: 30353470867bSRichard Henderson m_op = "rr+wr+ww"; 30363470867bSRichard Henderson break; 30373470867bSRichard Henderson case TCG_MO_LD_ST | TCG_MO_ST_LD | TCG_MO_ST_ST: 30383470867bSRichard Henderson m_op = "rw+wr+ww"; 30393470867bSRichard Henderson break; 30403470867bSRichard Henderson case TCG_MO_ALL: 30413470867bSRichard Henderson m_op = "all"; 30423470867bSRichard Henderson break; 30433470867bSRichard Henderson default: 30443470867bSRichard Henderson g_assert_not_reached(); 30453470867bSRichard Henderson } 30463470867bSRichard Henderson 30473470867bSRichard Henderson col += ne_fprintf(f, "%s%s:%s", (k ? "," : ""), b_op, m_op); 30483470867bSRichard Henderson i++, k++; 30493470867bSRichard Henderson } 30503470867bSRichard Henderson break; 305151e3972cSRichard Henderson default: 305251e3972cSRichard Henderson break; 3053eeacee4dSBlue Swirl } 305451e3972cSRichard Henderson for (; i < nb_cargs; i++, k++) { 3055b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s$0x%" TCG_PRIlx, k ? "," : "", 3056b7a83ff8SRichard Henderson op->args[k]); 3057bdfb460eSRichard Henderson } 3058bdfb460eSRichard Henderson } 3059bdfb460eSRichard Henderson 30601894f69aSRichard Henderson if (have_prefs || op->life) { 30611894f69aSRichard Henderson for (; col < 40; ++col) { 3062b7a83ff8SRichard Henderson putc(' ', f); 3063bdfb460eSRichard Henderson } 30641894f69aSRichard Henderson } 30651894f69aSRichard Henderson 30661894f69aSRichard Henderson if (op->life) { 30671894f69aSRichard Henderson unsigned life = op->life; 3068bdfb460eSRichard Henderson 3069bdfb460eSRichard Henderson if (life & (SYNC_ARG * 3)) { 3070b7a83ff8SRichard Henderson ne_fprintf(f, " sync:"); 3071bdfb460eSRichard Henderson for (i = 0; i < 2; ++i) { 3072bdfb460eSRichard Henderson if (life & (SYNC_ARG << i)) { 3073b7a83ff8SRichard Henderson ne_fprintf(f, " %d", i); 3074bdfb460eSRichard Henderson } 3075bdfb460eSRichard Henderson } 3076bdfb460eSRichard Henderson } 3077bdfb460eSRichard Henderson life /= DEAD_ARG; 3078bdfb460eSRichard Henderson if (life) { 3079b7a83ff8SRichard Henderson ne_fprintf(f, " dead:"); 3080bdfb460eSRichard Henderson for (i = 0; life; ++i, life >>= 1) { 3081bdfb460eSRichard Henderson if (life & 1) { 3082b7a83ff8SRichard Henderson ne_fprintf(f, " %d", i); 3083bdfb460eSRichard Henderson } 3084bdfb460eSRichard Henderson } 3085c896fe29Sbellard } 3086b03cce8eSbellard } 30871894f69aSRichard Henderson 30881894f69aSRichard Henderson if (have_prefs) { 30891894f69aSRichard Henderson for (i = 0; i < nb_oargs; ++i) { 309031fd884bSRichard Henderson TCGRegSet set = output_pref(op, i); 30911894f69aSRichard Henderson 30921894f69aSRichard Henderson if (i == 0) { 3093b7a83ff8SRichard Henderson ne_fprintf(f, " pref="); 30941894f69aSRichard Henderson } else { 3095b7a83ff8SRichard Henderson ne_fprintf(f, ","); 30961894f69aSRichard Henderson } 30971894f69aSRichard Henderson if (set == 0) { 3098b7a83ff8SRichard Henderson ne_fprintf(f, "none"); 30991894f69aSRichard Henderson } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) { 3100b7a83ff8SRichard Henderson ne_fprintf(f, "all"); 31011894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG 31021894f69aSRichard Henderson } else if (tcg_regset_single(set)) { 31031894f69aSRichard Henderson TCGReg reg = tcg_regset_first(set); 3104b7a83ff8SRichard Henderson ne_fprintf(f, "%s", tcg_target_reg_names[reg]); 31051894f69aSRichard Henderson #endif 31061894f69aSRichard Henderson } else if (TCG_TARGET_NB_REGS <= 32) { 3107b7a83ff8SRichard Henderson ne_fprintf(f, "0x%x", (uint32_t)set); 31081894f69aSRichard Henderson } else { 3109b7a83ff8SRichard Henderson ne_fprintf(f, "0x%" PRIx64, (uint64_t)set); 31101894f69aSRichard Henderson } 31111894f69aSRichard Henderson } 31121894f69aSRichard Henderson } 31131894f69aSRichard Henderson 3114b7a83ff8SRichard Henderson putc('\n', f); 3115c896fe29Sbellard } 3116c896fe29Sbellard } 3117c896fe29Sbellard 3118c896fe29Sbellard /* we give more priority to constraints with less registers */ 31193e80824eSRichard Henderson static int get_constraint_priority(const TCGArgConstraint *arg_ct, int k) 3120c896fe29Sbellard { 31213e80824eSRichard Henderson int n; 31223e80824eSRichard Henderson 31233e80824eSRichard Henderson arg_ct += k; 31243e80824eSRichard Henderson n = ctpop64(arg_ct->regs); 3125c896fe29Sbellard 312629f5e925SRichard Henderson /* 312729f5e925SRichard Henderson * Sort constraints of a single register first, which includes output 312829f5e925SRichard Henderson * aliases (which must exactly match the input already allocated). 312929f5e925SRichard Henderson */ 313029f5e925SRichard Henderson if (n == 1 || arg_ct->oalias) { 313129f5e925SRichard Henderson return INT_MAX; 3132c896fe29Sbellard } 313329f5e925SRichard Henderson 313429f5e925SRichard Henderson /* 313529f5e925SRichard Henderson * Sort register pairs next, first then second immediately after. 313629f5e925SRichard Henderson * Arbitrarily sort multiple pairs by the index of the first reg; 313729f5e925SRichard Henderson * there shouldn't be many pairs. 313829f5e925SRichard Henderson */ 313929f5e925SRichard Henderson switch (arg_ct->pair) { 314029f5e925SRichard Henderson case 1: 314129f5e925SRichard Henderson case 3: 314229f5e925SRichard Henderson return (k + 1) * 2; 314329f5e925SRichard Henderson case 2: 314429f5e925SRichard Henderson return (arg_ct->pair_index + 1) * 2 - 1; 314529f5e925SRichard Henderson } 314629f5e925SRichard Henderson 314729f5e925SRichard Henderson /* Finally, sort by decreasing register count. */ 314829f5e925SRichard Henderson assert(n > 1); 314929f5e925SRichard Henderson return -n; 3150c896fe29Sbellard } 3151c896fe29Sbellard 3152c896fe29Sbellard /* sort from highest priority to lowest */ 31533e80824eSRichard Henderson static void sort_constraints(TCGArgConstraint *a, int start, int n) 3154c896fe29Sbellard { 315566792f90SRichard Henderson int i, j; 3156c896fe29Sbellard 315766792f90SRichard Henderson for (i = 0; i < n; i++) { 315866792f90SRichard Henderson a[start + i].sort_index = start + i; 315966792f90SRichard Henderson } 316066792f90SRichard Henderson if (n <= 1) { 3161c896fe29Sbellard return; 316266792f90SRichard Henderson } 3163c896fe29Sbellard for (i = 0; i < n - 1; i++) { 3164c896fe29Sbellard for (j = i + 1; j < n; j++) { 31653e80824eSRichard Henderson int p1 = get_constraint_priority(a, a[start + i].sort_index); 31663e80824eSRichard Henderson int p2 = get_constraint_priority(a, a[start + j].sort_index); 3167c896fe29Sbellard if (p1 < p2) { 316866792f90SRichard Henderson int tmp = a[start + i].sort_index; 316966792f90SRichard Henderson a[start + i].sort_index = a[start + j].sort_index; 317066792f90SRichard Henderson a[start + j].sort_index = tmp; 3171c896fe29Sbellard } 3172c896fe29Sbellard } 3173c896fe29Sbellard } 3174c896fe29Sbellard } 3175c896fe29Sbellard 31763e80824eSRichard Henderson static const TCGArgConstraint empty_cts[TCG_MAX_OP_ARGS]; 31773e80824eSRichard Henderson static TCGArgConstraint all_cts[ARRAY_SIZE(constraint_sets)][TCG_MAX_OP_ARGS]; 31783e80824eSRichard Henderson 3179501fb3daSRichard Henderson static void process_constraint_sets(void) 3180c896fe29Sbellard { 31813e80824eSRichard Henderson for (size_t c = 0; c < ARRAY_SIZE(constraint_sets); ++c) { 31823e80824eSRichard Henderson const TCGConstraintSet *tdefs = &constraint_sets[c]; 31833e80824eSRichard Henderson TCGArgConstraint *args_ct = all_cts[c]; 31843e80824eSRichard Henderson int nb_oargs = tdefs->nb_oargs; 31853e80824eSRichard Henderson int nb_iargs = tdefs->nb_iargs; 31863e80824eSRichard Henderson int nb_args = nb_oargs + nb_iargs; 318729f5e925SRichard Henderson bool saw_alias_pair = false; 3188f69d277eSRichard Henderson 31893e80824eSRichard Henderson for (int i = 0; i < nb_args; i++) { 3190f69d277eSRichard Henderson const char *ct_str = tdefs->args_ct_str[i]; 31913e80824eSRichard Henderson bool input_p = i >= nb_oargs; 31923e80824eSRichard Henderson int o; 3193f69d277eSRichard Henderson 319417280ff4SRichard Henderson switch (*ct_str) { 319517280ff4SRichard Henderson case '0' ... '9': 31968940ea0dSPhilippe Mathieu-Daudé o = *ct_str - '0'; 31978940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(input_p); 31983e80824eSRichard Henderson tcg_debug_assert(o < nb_oargs); 31993e80824eSRichard Henderson tcg_debug_assert(args_ct[o].regs != 0); 32003e80824eSRichard Henderson tcg_debug_assert(!args_ct[o].oalias); 32013e80824eSRichard Henderson args_ct[i] = args_ct[o]; 3202bc2b17e6SRichard Henderson /* The output sets oalias. */ 32033e80824eSRichard Henderson args_ct[o].oalias = 1; 32043e80824eSRichard Henderson args_ct[o].alias_index = i; 3205bc2b17e6SRichard Henderson /* The input sets ialias. */ 32063e80824eSRichard Henderson args_ct[i].ialias = 1; 32073e80824eSRichard Henderson args_ct[i].alias_index = o; 32083e80824eSRichard Henderson if (args_ct[i].pair) { 320929f5e925SRichard Henderson saw_alias_pair = true; 321029f5e925SRichard Henderson } 32118940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(ct_str[1] == '\0'); 32128940ea0dSPhilippe Mathieu-Daudé continue; 32138940ea0dSPhilippe Mathieu-Daudé 321482790a87SRichard Henderson case '&': 32158940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(!input_p); 32163e80824eSRichard Henderson args_ct[i].newreg = true; 321782790a87SRichard Henderson ct_str++; 321882790a87SRichard Henderson break; 321929f5e925SRichard Henderson 322029f5e925SRichard Henderson case 'p': /* plus */ 322129f5e925SRichard Henderson /* Allocate to the register after the previous. */ 32223e80824eSRichard Henderson tcg_debug_assert(i > (input_p ? nb_oargs : 0)); 322329f5e925SRichard Henderson o = i - 1; 32243e80824eSRichard Henderson tcg_debug_assert(!args_ct[o].pair); 32253e80824eSRichard Henderson tcg_debug_assert(!args_ct[o].ct); 32263e80824eSRichard Henderson args_ct[i] = (TCGArgConstraint){ 322729f5e925SRichard Henderson .pair = 2, 322829f5e925SRichard Henderson .pair_index = o, 32293e80824eSRichard Henderson .regs = args_ct[o].regs << 1, 32303e80824eSRichard Henderson .newreg = args_ct[o].newreg, 323129f5e925SRichard Henderson }; 32323e80824eSRichard Henderson args_ct[o].pair = 1; 32333e80824eSRichard Henderson args_ct[o].pair_index = i; 323429f5e925SRichard Henderson tcg_debug_assert(ct_str[1] == '\0'); 323529f5e925SRichard Henderson continue; 323629f5e925SRichard Henderson 323729f5e925SRichard Henderson case 'm': /* minus */ 323829f5e925SRichard Henderson /* Allocate to the register before the previous. */ 32393e80824eSRichard Henderson tcg_debug_assert(i > (input_p ? nb_oargs : 0)); 324029f5e925SRichard Henderson o = i - 1; 32413e80824eSRichard Henderson tcg_debug_assert(!args_ct[o].pair); 32423e80824eSRichard Henderson tcg_debug_assert(!args_ct[o].ct); 32433e80824eSRichard Henderson args_ct[i] = (TCGArgConstraint){ 324429f5e925SRichard Henderson .pair = 1, 324529f5e925SRichard Henderson .pair_index = o, 32463e80824eSRichard Henderson .regs = args_ct[o].regs >> 1, 32473e80824eSRichard Henderson .newreg = args_ct[o].newreg, 324829f5e925SRichard Henderson }; 32493e80824eSRichard Henderson args_ct[o].pair = 2; 32503e80824eSRichard Henderson args_ct[o].pair_index = i; 325129f5e925SRichard Henderson tcg_debug_assert(ct_str[1] == '\0'); 325229f5e925SRichard Henderson continue; 32538940ea0dSPhilippe Mathieu-Daudé } 32548940ea0dSPhilippe Mathieu-Daudé 32558940ea0dSPhilippe Mathieu-Daudé do { 32568940ea0dSPhilippe Mathieu-Daudé switch (*ct_str) { 3257c896fe29Sbellard case 'i': 32583e80824eSRichard Henderson args_ct[i].ct |= TCG_CT_CONST; 3259c896fe29Sbellard break; 3260358b4923SRichard Henderson 3261358b4923SRichard Henderson /* Include all of the target-specific constraints. */ 3262358b4923SRichard Henderson 3263358b4923SRichard Henderson #undef CONST 3264358b4923SRichard Henderson #define CONST(CASE, MASK) \ 32653e80824eSRichard Henderson case CASE: args_ct[i].ct |= MASK; break; 3266358b4923SRichard Henderson #define REGS(CASE, MASK) \ 32673e80824eSRichard Henderson case CASE: args_ct[i].regs |= MASK; break; 3268358b4923SRichard Henderson 3269358b4923SRichard Henderson #include "tcg-target-con-str.h" 3270358b4923SRichard Henderson 3271358b4923SRichard Henderson #undef REGS 3272358b4923SRichard Henderson #undef CONST 3273c896fe29Sbellard default: 32748940ea0dSPhilippe Mathieu-Daudé case '0' ... '9': 32758940ea0dSPhilippe Mathieu-Daudé case '&': 327629f5e925SRichard Henderson case 'p': 327729f5e925SRichard Henderson case 'm': 32783e80824eSRichard Henderson /* Typo in TCGConstraintSet constraint. */ 3279358b4923SRichard Henderson g_assert_not_reached(); 3280358b4923SRichard Henderson } 32818940ea0dSPhilippe Mathieu-Daudé } while (*++ct_str != '\0'); 3282c896fe29Sbellard } 3283c896fe29Sbellard 328429f5e925SRichard Henderson /* 328529f5e925SRichard Henderson * Fix up output pairs that are aliased with inputs. 328629f5e925SRichard Henderson * When we created the alias, we copied pair from the output. 328729f5e925SRichard Henderson * There are three cases: 328829f5e925SRichard Henderson * (1a) Pairs of inputs alias pairs of outputs. 328929f5e925SRichard Henderson * (1b) One input aliases the first of a pair of outputs. 329029f5e925SRichard Henderson * (2) One input aliases the second of a pair of outputs. 329129f5e925SRichard Henderson * 329229f5e925SRichard Henderson * Case 1a is handled by making sure that the pair_index'es are 329329f5e925SRichard Henderson * properly updated so that they appear the same as a pair of inputs. 329429f5e925SRichard Henderson * 329529f5e925SRichard Henderson * Case 1b is handled by setting the pair_index of the input to 329629f5e925SRichard Henderson * itself, simply so it doesn't point to an unrelated argument. 329729f5e925SRichard Henderson * Since we don't encounter the "second" during the input allocation 329829f5e925SRichard Henderson * phase, nothing happens with the second half of the input pair. 329929f5e925SRichard Henderson * 330029f5e925SRichard Henderson * Case 2 is handled by setting the second input to pair=3, the 330129f5e925SRichard Henderson * first output to pair=3, and the pair_index'es to match. 330229f5e925SRichard Henderson */ 330329f5e925SRichard Henderson if (saw_alias_pair) { 33043e80824eSRichard Henderson for (int i = nb_oargs; i < nb_args; i++) { 33053e80824eSRichard Henderson int o, o2, i2; 33063e80824eSRichard Henderson 330729f5e925SRichard Henderson /* 330829f5e925SRichard Henderson * Since [0-9pm] must be alone in the constraint string, 330929f5e925SRichard Henderson * the only way they can both be set is if the pair comes 331029f5e925SRichard Henderson * from the output alias. 331129f5e925SRichard Henderson */ 33123e80824eSRichard Henderson if (!args_ct[i].ialias) { 331329f5e925SRichard Henderson continue; 331429f5e925SRichard Henderson } 33153e80824eSRichard Henderson switch (args_ct[i].pair) { 331629f5e925SRichard Henderson case 0: 331729f5e925SRichard Henderson break; 331829f5e925SRichard Henderson case 1: 33193e80824eSRichard Henderson o = args_ct[i].alias_index; 33203e80824eSRichard Henderson o2 = args_ct[o].pair_index; 33213e80824eSRichard Henderson tcg_debug_assert(args_ct[o].pair == 1); 33223e80824eSRichard Henderson tcg_debug_assert(args_ct[o2].pair == 2); 33233e80824eSRichard Henderson if (args_ct[o2].oalias) { 332429f5e925SRichard Henderson /* Case 1a */ 33253e80824eSRichard Henderson i2 = args_ct[o2].alias_index; 33263e80824eSRichard Henderson tcg_debug_assert(args_ct[i2].pair == 2); 33273e80824eSRichard Henderson args_ct[i2].pair_index = i; 33283e80824eSRichard Henderson args_ct[i].pair_index = i2; 332929f5e925SRichard Henderson } else { 333029f5e925SRichard Henderson /* Case 1b */ 33313e80824eSRichard Henderson args_ct[i].pair_index = i; 333229f5e925SRichard Henderson } 333329f5e925SRichard Henderson break; 333429f5e925SRichard Henderson case 2: 33353e80824eSRichard Henderson o = args_ct[i].alias_index; 33363e80824eSRichard Henderson o2 = args_ct[o].pair_index; 33373e80824eSRichard Henderson tcg_debug_assert(args_ct[o].pair == 2); 33383e80824eSRichard Henderson tcg_debug_assert(args_ct[o2].pair == 1); 33393e80824eSRichard Henderson if (args_ct[o2].oalias) { 334029f5e925SRichard Henderson /* Case 1a */ 33413e80824eSRichard Henderson i2 = args_ct[o2].alias_index; 33423e80824eSRichard Henderson tcg_debug_assert(args_ct[i2].pair == 1); 33433e80824eSRichard Henderson args_ct[i2].pair_index = i; 33443e80824eSRichard Henderson args_ct[i].pair_index = i2; 334529f5e925SRichard Henderson } else { 334629f5e925SRichard Henderson /* Case 2 */ 33473e80824eSRichard Henderson args_ct[i].pair = 3; 33483e80824eSRichard Henderson args_ct[o2].pair = 3; 33493e80824eSRichard Henderson args_ct[i].pair_index = o2; 33503e80824eSRichard Henderson args_ct[o2].pair_index = i; 335129f5e925SRichard Henderson } 335229f5e925SRichard Henderson break; 335329f5e925SRichard Henderson default: 335429f5e925SRichard Henderson g_assert_not_reached(); 335529f5e925SRichard Henderson } 335629f5e925SRichard Henderson } 335729f5e925SRichard Henderson } 335829f5e925SRichard Henderson 3359c896fe29Sbellard /* sort the constraints (XXX: this is just an heuristic) */ 33603e80824eSRichard Henderson sort_constraints(args_ct, 0, nb_oargs); 33613e80824eSRichard Henderson sort_constraints(args_ct, nb_oargs, nb_iargs); 33623e80824eSRichard Henderson } 3363501fb3daSRichard Henderson } 33643e80824eSRichard Henderson 3365501fb3daSRichard Henderson static const TCGArgConstraint *opcode_args_ct(const TCGOp *op) 3366501fb3daSRichard Henderson { 3367ed1a653bSRichard Henderson const TCGOpDef *def = &tcg_op_defs[op->opc]; 33683e80824eSRichard Henderson TCGConstraintSetIndex con_set; 33693e80824eSRichard Henderson 3370b277cdd2SRichard Henderson #ifdef CONFIG_DEBUG_TCG 3371b277cdd2SRichard Henderson assert(tcg_op_supported(op->opc, TCGOP_TYPE(op), TCGOP_FLAGS(op))); 3372b277cdd2SRichard Henderson #endif 3373b277cdd2SRichard Henderson 33743e80824eSRichard Henderson if (def->flags & TCG_OPF_NOT_PRESENT) { 3375501fb3daSRichard Henderson return empty_cts; 33763e80824eSRichard Henderson } 33773e80824eSRichard Henderson 33786323b363SRichard Henderson con_set = tcg_target_op_def(op->opc, TCGOP_TYPE(op), TCGOP_FLAGS(op)); 33793e80824eSRichard Henderson tcg_debug_assert(con_set >= 0 && con_set < ARRAY_SIZE(constraint_sets)); 33803e80824eSRichard Henderson 33813e80824eSRichard Henderson /* The constraint arguments must match TCGOpcode arguments. */ 3382501fb3daSRichard Henderson tcg_debug_assert(constraint_sets[con_set].nb_oargs == def->nb_oargs); 3383501fb3daSRichard Henderson tcg_debug_assert(constraint_sets[con_set].nb_iargs == def->nb_iargs); 33843e80824eSRichard Henderson 3385501fb3daSRichard Henderson return all_cts[con_set]; 3386c896fe29Sbellard } 3387c896fe29Sbellard 3388f85b1fc4SRichard Henderson static void remove_label_use(TCGOp *op, int idx) 3389f85b1fc4SRichard Henderson { 3390f85b1fc4SRichard Henderson TCGLabel *label = arg_label(op->args[idx]); 3391f85b1fc4SRichard Henderson TCGLabelUse *use; 3392f85b1fc4SRichard Henderson 3393f85b1fc4SRichard Henderson QSIMPLEQ_FOREACH(use, &label->branches, next) { 3394f85b1fc4SRichard Henderson if (use->op == op) { 3395f85b1fc4SRichard Henderson QSIMPLEQ_REMOVE(&label->branches, use, TCGLabelUse, next); 3396f85b1fc4SRichard Henderson return; 3397f85b1fc4SRichard Henderson } 3398f85b1fc4SRichard Henderson } 3399f85b1fc4SRichard Henderson g_assert_not_reached(); 3400f85b1fc4SRichard Henderson } 3401f85b1fc4SRichard Henderson 34020c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op) 34030c627cdcSRichard Henderson { 3404d88a117eSRichard Henderson switch (op->opc) { 3405d88a117eSRichard Henderson case INDEX_op_br: 3406f85b1fc4SRichard Henderson remove_label_use(op, 0); 3407d88a117eSRichard Henderson break; 3408d88a117eSRichard Henderson case INDEX_op_brcond_i32: 3409d88a117eSRichard Henderson case INDEX_op_brcond_i64: 3410f85b1fc4SRichard Henderson remove_label_use(op, 3); 3411d88a117eSRichard Henderson break; 3412d88a117eSRichard Henderson case INDEX_op_brcond2_i32: 3413f85b1fc4SRichard Henderson remove_label_use(op, 5); 3414d88a117eSRichard Henderson break; 3415d88a117eSRichard Henderson default: 3416d88a117eSRichard Henderson break; 3417d88a117eSRichard Henderson } 3418d88a117eSRichard Henderson 341915fa08f8SRichard Henderson QTAILQ_REMOVE(&s->ops, op, link); 342015fa08f8SRichard Henderson QTAILQ_INSERT_TAIL(&s->free_ops, op, link); 3421abebf925SRichard Henderson s->nb_ops--; 34220c627cdcSRichard Henderson } 34230c627cdcSRichard Henderson 3424a80cdd31SRichard Henderson void tcg_remove_ops_after(TCGOp *op) 3425a80cdd31SRichard Henderson { 3426a80cdd31SRichard Henderson TCGContext *s = tcg_ctx; 3427a80cdd31SRichard Henderson 3428a80cdd31SRichard Henderson while (true) { 3429a80cdd31SRichard Henderson TCGOp *last = tcg_last_op(); 3430a80cdd31SRichard Henderson if (last == op) { 3431a80cdd31SRichard Henderson return; 3432a80cdd31SRichard Henderson } 3433a80cdd31SRichard Henderson tcg_op_remove(s, last); 3434a80cdd31SRichard Henderson } 3435a80cdd31SRichard Henderson } 3436a80cdd31SRichard Henderson 3437d4478943SPhilippe Mathieu-Daudé static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs) 343815fa08f8SRichard Henderson { 343915fa08f8SRichard Henderson TCGContext *s = tcg_ctx; 3440cb10bc63SRichard Henderson TCGOp *op = NULL; 344115fa08f8SRichard Henderson 3442cb10bc63SRichard Henderson if (unlikely(!QTAILQ_EMPTY(&s->free_ops))) { 3443cb10bc63SRichard Henderson QTAILQ_FOREACH(op, &s->free_ops, link) { 3444cb10bc63SRichard Henderson if (nargs <= op->nargs) { 344515fa08f8SRichard Henderson QTAILQ_REMOVE(&s->free_ops, op, link); 3446cb10bc63SRichard Henderson nargs = op->nargs; 3447cb10bc63SRichard Henderson goto found; 344815fa08f8SRichard Henderson } 3449cb10bc63SRichard Henderson } 3450cb10bc63SRichard Henderson } 3451cb10bc63SRichard Henderson 3452cb10bc63SRichard Henderson /* Most opcodes have 3 or 4 operands: reduce fragmentation. */ 3453cb10bc63SRichard Henderson nargs = MAX(4, nargs); 3454cb10bc63SRichard Henderson op = tcg_malloc(sizeof(TCGOp) + sizeof(TCGArg) * nargs); 3455cb10bc63SRichard Henderson 3456cb10bc63SRichard Henderson found: 345715fa08f8SRichard Henderson memset(op, 0, offsetof(TCGOp, link)); 345815fa08f8SRichard Henderson op->opc = opc; 3459cb10bc63SRichard Henderson op->nargs = nargs; 346015fa08f8SRichard Henderson 3461cb10bc63SRichard Henderson /* Check for bitfield overflow. */ 3462cb10bc63SRichard Henderson tcg_debug_assert(op->nargs == nargs); 3463cb10bc63SRichard Henderson 3464cb10bc63SRichard Henderson s->nb_ops++; 346515fa08f8SRichard Henderson return op; 346615fa08f8SRichard Henderson } 346715fa08f8SRichard Henderson 3468d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_emit_op(TCGOpcode opc, unsigned nargs) 346915fa08f8SRichard Henderson { 3470d4478943SPhilippe Mathieu-Daudé TCGOp *op = tcg_op_alloc(opc, nargs); 347107843f75SRichard Henderson 347207843f75SRichard Henderson if (tcg_ctx->emit_before_op) { 347307843f75SRichard Henderson QTAILQ_INSERT_BEFORE(tcg_ctx->emit_before_op, op, link); 347407843f75SRichard Henderson } else { 347515fa08f8SRichard Henderson QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link); 347607843f75SRichard Henderson } 347715fa08f8SRichard Henderson return op; 347815fa08f8SRichard Henderson } 347915fa08f8SRichard Henderson 3480d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op, 3481d4478943SPhilippe Mathieu-Daudé TCGOpcode opc, unsigned nargs) 34825a18407fSRichard Henderson { 3483d4478943SPhilippe Mathieu-Daudé TCGOp *new_op = tcg_op_alloc(opc, nargs); 3484fb744eceSRichard Henderson 3485fb744eceSRichard Henderson TCGOP_TYPE(new_op) = TCGOP_TYPE(old_op); 348615fa08f8SRichard Henderson QTAILQ_INSERT_BEFORE(old_op, new_op, link); 34875a18407fSRichard Henderson return new_op; 34885a18407fSRichard Henderson } 34895a18407fSRichard Henderson 3490d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, 3491d4478943SPhilippe Mathieu-Daudé TCGOpcode opc, unsigned nargs) 34925a18407fSRichard Henderson { 3493d4478943SPhilippe Mathieu-Daudé TCGOp *new_op = tcg_op_alloc(opc, nargs); 3494fb744eceSRichard Henderson 3495fb744eceSRichard Henderson TCGOP_TYPE(new_op) = TCGOP_TYPE(old_op); 349615fa08f8SRichard Henderson QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link); 34975a18407fSRichard Henderson return new_op; 34985a18407fSRichard Henderson } 34995a18407fSRichard Henderson 3500968f305eSRichard Henderson static void move_label_uses(TCGLabel *to, TCGLabel *from) 3501968f305eSRichard Henderson { 3502968f305eSRichard Henderson TCGLabelUse *u; 3503968f305eSRichard Henderson 3504968f305eSRichard Henderson QSIMPLEQ_FOREACH(u, &from->branches, next) { 3505968f305eSRichard Henderson TCGOp *op = u->op; 3506968f305eSRichard Henderson switch (op->opc) { 3507968f305eSRichard Henderson case INDEX_op_br: 3508968f305eSRichard Henderson op->args[0] = label_arg(to); 3509968f305eSRichard Henderson break; 3510968f305eSRichard Henderson case INDEX_op_brcond_i32: 3511968f305eSRichard Henderson case INDEX_op_brcond_i64: 3512968f305eSRichard Henderson op->args[3] = label_arg(to); 3513968f305eSRichard Henderson break; 3514968f305eSRichard Henderson case INDEX_op_brcond2_i32: 3515968f305eSRichard Henderson op->args[5] = label_arg(to); 3516968f305eSRichard Henderson break; 3517968f305eSRichard Henderson default: 3518968f305eSRichard Henderson g_assert_not_reached(); 3519968f305eSRichard Henderson } 3520968f305eSRichard Henderson } 3521968f305eSRichard Henderson 3522968f305eSRichard Henderson QSIMPLEQ_CONCAT(&to->branches, &from->branches); 3523968f305eSRichard Henderson } 3524968f305eSRichard Henderson 3525b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code. */ 35269bbee4c0SRichard Henderson static void __attribute__((noinline)) 35279bbee4c0SRichard Henderson reachable_code_pass(TCGContext *s) 3528b4fc67c7SRichard Henderson { 35294d89d0bbSRichard Henderson TCGOp *op, *op_next, *op_prev; 3530b4fc67c7SRichard Henderson bool dead = false; 3531b4fc67c7SRichard Henderson 3532b4fc67c7SRichard Henderson QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) { 3533b4fc67c7SRichard Henderson bool remove = dead; 3534b4fc67c7SRichard Henderson TCGLabel *label; 3535b4fc67c7SRichard Henderson 3536b4fc67c7SRichard Henderson switch (op->opc) { 3537b4fc67c7SRichard Henderson case INDEX_op_set_label: 3538b4fc67c7SRichard Henderson label = arg_label(op->args[0]); 35394d89d0bbSRichard Henderson 35404d89d0bbSRichard Henderson /* 3541968f305eSRichard Henderson * Note that the first op in the TB is always a load, 3542968f305eSRichard Henderson * so there is always something before a label. 3543968f305eSRichard Henderson */ 3544968f305eSRichard Henderson op_prev = QTAILQ_PREV(op, link); 3545968f305eSRichard Henderson 3546968f305eSRichard Henderson /* 3547968f305eSRichard Henderson * If we find two sequential labels, move all branches to 3548968f305eSRichard Henderson * reference the second label and remove the first label. 3549968f305eSRichard Henderson * Do this before branch to next optimization, so that the 3550968f305eSRichard Henderson * middle label is out of the way. 3551968f305eSRichard Henderson */ 3552968f305eSRichard Henderson if (op_prev->opc == INDEX_op_set_label) { 3553968f305eSRichard Henderson move_label_uses(label, arg_label(op_prev->args[0])); 3554968f305eSRichard Henderson tcg_op_remove(s, op_prev); 3555968f305eSRichard Henderson op_prev = QTAILQ_PREV(op, link); 3556968f305eSRichard Henderson } 3557968f305eSRichard Henderson 3558968f305eSRichard Henderson /* 35594d89d0bbSRichard Henderson * Optimization can fold conditional branches to unconditional. 35604d89d0bbSRichard Henderson * If we find a label which is preceded by an unconditional 35614d89d0bbSRichard Henderson * branch to next, remove the branch. We couldn't do this when 35624d89d0bbSRichard Henderson * processing the branch because any dead code between the branch 35634d89d0bbSRichard Henderson * and label had not yet been removed. 35644d89d0bbSRichard Henderson */ 35654d89d0bbSRichard Henderson if (op_prev->opc == INDEX_op_br && 35664d89d0bbSRichard Henderson label == arg_label(op_prev->args[0])) { 35674d89d0bbSRichard Henderson tcg_op_remove(s, op_prev); 35684d89d0bbSRichard Henderson /* Fall through means insns become live again. */ 35694d89d0bbSRichard Henderson dead = false; 35704d89d0bbSRichard Henderson } 35714d89d0bbSRichard Henderson 3572f85b1fc4SRichard Henderson if (QSIMPLEQ_EMPTY(&label->branches)) { 3573b4fc67c7SRichard Henderson /* 3574b4fc67c7SRichard Henderson * While there is an occasional backward branch, virtually 3575b4fc67c7SRichard Henderson * all branches generated by the translators are forward. 3576b4fc67c7SRichard Henderson * Which means that generally we will have already removed 3577b4fc67c7SRichard Henderson * all references to the label that will be, and there is 3578b4fc67c7SRichard Henderson * little to be gained by iterating. 3579b4fc67c7SRichard Henderson */ 3580b4fc67c7SRichard Henderson remove = true; 3581b4fc67c7SRichard Henderson } else { 3582b4fc67c7SRichard Henderson /* Once we see a label, insns become live again. */ 3583b4fc67c7SRichard Henderson dead = false; 3584b4fc67c7SRichard Henderson remove = false; 3585b4fc67c7SRichard Henderson } 3586b4fc67c7SRichard Henderson break; 3587b4fc67c7SRichard Henderson 3588b4fc67c7SRichard Henderson case INDEX_op_br: 3589b4fc67c7SRichard Henderson case INDEX_op_exit_tb: 3590b4fc67c7SRichard Henderson case INDEX_op_goto_ptr: 3591b4fc67c7SRichard Henderson /* Unconditional branches; everything following is dead. */ 3592b4fc67c7SRichard Henderson dead = true; 3593b4fc67c7SRichard Henderson break; 3594b4fc67c7SRichard Henderson 3595b4fc67c7SRichard Henderson case INDEX_op_call: 3596b4fc67c7SRichard Henderson /* Notice noreturn helper calls, raising exceptions. */ 359790163900SRichard Henderson if (tcg_call_flags(op) & TCG_CALL_NO_RETURN) { 3598b4fc67c7SRichard Henderson dead = true; 3599b4fc67c7SRichard Henderson } 3600b4fc67c7SRichard Henderson break; 3601b4fc67c7SRichard Henderson 3602b4fc67c7SRichard Henderson case INDEX_op_insn_start: 3603b4fc67c7SRichard Henderson /* Never remove -- we need to keep these for unwind. */ 3604b4fc67c7SRichard Henderson remove = false; 3605b4fc67c7SRichard Henderson break; 3606b4fc67c7SRichard Henderson 3607b4fc67c7SRichard Henderson default: 3608b4fc67c7SRichard Henderson break; 3609b4fc67c7SRichard Henderson } 3610b4fc67c7SRichard Henderson 3611b4fc67c7SRichard Henderson if (remove) { 3612b4fc67c7SRichard Henderson tcg_op_remove(s, op); 3613b4fc67c7SRichard Henderson } 3614b4fc67c7SRichard Henderson } 3615b4fc67c7SRichard Henderson } 3616b4fc67c7SRichard Henderson 3617c70fbf0aSRichard Henderson #define TS_DEAD 1 3618c70fbf0aSRichard Henderson #define TS_MEM 2 3619c70fbf0aSRichard Henderson 36205a18407fSRichard Henderson #define IS_DEAD_ARG(n) (arg_life & (DEAD_ARG << (n))) 36215a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n))) 36225a18407fSRichard Henderson 362325f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp. */ 362425f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts) 362525f49c5fSRichard Henderson { 362625f49c5fSRichard Henderson return ts->state_ptr; 362725f49c5fSRichard Henderson } 362825f49c5fSRichard Henderson 362925f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the 363025f49c5fSRichard Henderson * maximal regset for its type. 363125f49c5fSRichard Henderson */ 363225f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts) 363325f49c5fSRichard Henderson { 363425f49c5fSRichard Henderson *la_temp_pref(ts) 363525f49c5fSRichard Henderson = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]); 363625f49c5fSRichard Henderson } 363725f49c5fSRichard Henderson 36389c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals 36399c43b68dSAurelien Jarno should be in memory. */ 36402616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt) 3641c896fe29Sbellard { 3642b83eabeaSRichard Henderson int i; 3643b83eabeaSRichard Henderson 3644b83eabeaSRichard Henderson for (i = 0; i < ng; ++i) { 3645b83eabeaSRichard Henderson s->temps[i].state = TS_DEAD | TS_MEM; 364625f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 3647b83eabeaSRichard Henderson } 3648b83eabeaSRichard Henderson for (i = ng; i < nt; ++i) { 3649b83eabeaSRichard Henderson s->temps[i].state = TS_DEAD; 365025f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 3651b83eabeaSRichard Henderson } 3652c896fe29Sbellard } 3653c896fe29Sbellard 36549c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals 36559c43b68dSAurelien Jarno and local temps should be in memory. */ 36562616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt) 3657641d5fbeSbellard { 3658b83eabeaSRichard Henderson int i; 3659641d5fbeSbellard 3660ee17db83SRichard Henderson for (i = 0; i < nt; ++i) { 3661ee17db83SRichard Henderson TCGTemp *ts = &s->temps[i]; 3662ee17db83SRichard Henderson int state; 3663ee17db83SRichard Henderson 3664ee17db83SRichard Henderson switch (ts->kind) { 3665ee17db83SRichard Henderson case TEMP_FIXED: 3666ee17db83SRichard Henderson case TEMP_GLOBAL: 3667f57c6915SRichard Henderson case TEMP_TB: 3668ee17db83SRichard Henderson state = TS_DEAD | TS_MEM; 3669ee17db83SRichard Henderson break; 3670c7482438SRichard Henderson case TEMP_EBB: 3671c0522136SRichard Henderson case TEMP_CONST: 3672ee17db83SRichard Henderson state = TS_DEAD; 3673ee17db83SRichard Henderson break; 3674ee17db83SRichard Henderson default: 3675ee17db83SRichard Henderson g_assert_not_reached(); 3676c70fbf0aSRichard Henderson } 3677ee17db83SRichard Henderson ts->state = state; 3678ee17db83SRichard Henderson la_reset_pref(ts); 3679641d5fbeSbellard } 3680641d5fbeSbellard } 3681641d5fbeSbellard 3682f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory. */ 3683f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng) 3684f65a061cSRichard Henderson { 3685f65a061cSRichard Henderson int i; 3686f65a061cSRichard Henderson 3687f65a061cSRichard Henderson for (i = 0; i < ng; ++i) { 368825f49c5fSRichard Henderson int state = s->temps[i].state; 368925f49c5fSRichard Henderson s->temps[i].state = state | TS_MEM; 369025f49c5fSRichard Henderson if (state == TS_DEAD) { 369125f49c5fSRichard Henderson /* If the global was previously dead, reset prefs. */ 369225f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 369325f49c5fSRichard Henderson } 3694f65a061cSRichard Henderson } 3695f65a061cSRichard Henderson } 3696f65a061cSRichard Henderson 3697b4cb76e6SRichard Henderson /* 3698c7482438SRichard Henderson * liveness analysis: conditional branch: all temps are dead unless 3699c7482438SRichard Henderson * explicitly live-across-conditional-branch, globals and local temps 3700c7482438SRichard Henderson * should be synced. 3701b4cb76e6SRichard Henderson */ 3702b4cb76e6SRichard Henderson static void la_bb_sync(TCGContext *s, int ng, int nt) 3703b4cb76e6SRichard Henderson { 3704b4cb76e6SRichard Henderson la_global_sync(s, ng); 3705b4cb76e6SRichard Henderson 3706b4cb76e6SRichard Henderson for (int i = ng; i < nt; ++i) { 3707c0522136SRichard Henderson TCGTemp *ts = &s->temps[i]; 3708c0522136SRichard Henderson int state; 3709c0522136SRichard Henderson 3710c0522136SRichard Henderson switch (ts->kind) { 3711f57c6915SRichard Henderson case TEMP_TB: 3712c0522136SRichard Henderson state = ts->state; 3713c0522136SRichard Henderson ts->state = state | TS_MEM; 3714b4cb76e6SRichard Henderson if (state != TS_DEAD) { 3715b4cb76e6SRichard Henderson continue; 3716b4cb76e6SRichard Henderson } 3717c0522136SRichard Henderson break; 3718c7482438SRichard Henderson case TEMP_EBB: 3719c0522136SRichard Henderson case TEMP_CONST: 3720c0522136SRichard Henderson continue; 3721c0522136SRichard Henderson default: 3722c0522136SRichard Henderson g_assert_not_reached(); 3723b4cb76e6SRichard Henderson } 3724b4cb76e6SRichard Henderson la_reset_pref(&s->temps[i]); 3725b4cb76e6SRichard Henderson } 3726b4cb76e6SRichard Henderson } 3727b4cb76e6SRichard Henderson 3728f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill. */ 3729f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng) 3730f65a061cSRichard Henderson { 3731f65a061cSRichard Henderson int i; 3732f65a061cSRichard Henderson 3733f65a061cSRichard Henderson for (i = 0; i < ng; i++) { 3734f65a061cSRichard Henderson s->temps[i].state = TS_DEAD | TS_MEM; 373525f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 373625f49c5fSRichard Henderson } 373725f49c5fSRichard Henderson } 373825f49c5fSRichard Henderson 373925f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls. */ 374025f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt) 374125f49c5fSRichard Henderson { 374225f49c5fSRichard Henderson TCGRegSet mask = ~tcg_target_call_clobber_regs; 374325f49c5fSRichard Henderson int i; 374425f49c5fSRichard Henderson 374525f49c5fSRichard Henderson for (i = 0; i < nt; i++) { 374625f49c5fSRichard Henderson TCGTemp *ts = &s->temps[i]; 374725f49c5fSRichard Henderson if (!(ts->state & TS_DEAD)) { 374825f49c5fSRichard Henderson TCGRegSet *pset = la_temp_pref(ts); 374925f49c5fSRichard Henderson TCGRegSet set = *pset; 375025f49c5fSRichard Henderson 375125f49c5fSRichard Henderson set &= mask; 375225f49c5fSRichard Henderson /* If the combination is not possible, restart. */ 375325f49c5fSRichard Henderson if (set == 0) { 375425f49c5fSRichard Henderson set = tcg_target_available_regs[ts->type] & mask; 375525f49c5fSRichard Henderson } 375625f49c5fSRichard Henderson *pset = set; 375725f49c5fSRichard Henderson } 3758f65a061cSRichard Henderson } 3759f65a061cSRichard Henderson } 3760f65a061cSRichard Henderson 3761874b8574SRichard Henderson /* 3762874b8574SRichard Henderson * Liveness analysis: Verify the lifetime of TEMP_TB, and reduce 3763874b8574SRichard Henderson * to TEMP_EBB, if possible. 3764874b8574SRichard Henderson */ 3765874b8574SRichard Henderson static void __attribute__((noinline)) 3766874b8574SRichard Henderson liveness_pass_0(TCGContext *s) 3767874b8574SRichard Henderson { 3768874b8574SRichard Henderson void * const multiple_ebb = (void *)(uintptr_t)-1; 3769874b8574SRichard Henderson int nb_temps = s->nb_temps; 3770874b8574SRichard Henderson TCGOp *op, *ebb; 3771874b8574SRichard Henderson 3772874b8574SRichard Henderson for (int i = s->nb_globals; i < nb_temps; ++i) { 3773874b8574SRichard Henderson s->temps[i].state_ptr = NULL; 3774874b8574SRichard Henderson } 3775874b8574SRichard Henderson 3776874b8574SRichard Henderson /* 3777874b8574SRichard Henderson * Represent each EBB by the op at which it begins. In the case of 3778874b8574SRichard Henderson * the first EBB, this is the first op, otherwise it is a label. 3779874b8574SRichard Henderson * Collect the uses of each TEMP_TB: NULL for unused, EBB for use 3780874b8574SRichard Henderson * within a single EBB, else MULTIPLE_EBB. 3781874b8574SRichard Henderson */ 3782874b8574SRichard Henderson ebb = QTAILQ_FIRST(&s->ops); 3783874b8574SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 3784874b8574SRichard Henderson const TCGOpDef *def; 3785874b8574SRichard Henderson int nb_oargs, nb_iargs; 3786874b8574SRichard Henderson 3787874b8574SRichard Henderson switch (op->opc) { 3788874b8574SRichard Henderson case INDEX_op_set_label: 3789874b8574SRichard Henderson ebb = op; 3790874b8574SRichard Henderson continue; 3791874b8574SRichard Henderson case INDEX_op_discard: 3792874b8574SRichard Henderson continue; 3793874b8574SRichard Henderson case INDEX_op_call: 3794874b8574SRichard Henderson nb_oargs = TCGOP_CALLO(op); 3795874b8574SRichard Henderson nb_iargs = TCGOP_CALLI(op); 3796874b8574SRichard Henderson break; 3797874b8574SRichard Henderson default: 3798874b8574SRichard Henderson def = &tcg_op_defs[op->opc]; 3799874b8574SRichard Henderson nb_oargs = def->nb_oargs; 3800874b8574SRichard Henderson nb_iargs = def->nb_iargs; 3801874b8574SRichard Henderson break; 3802874b8574SRichard Henderson } 3803874b8574SRichard Henderson 3804874b8574SRichard Henderson for (int i = 0; i < nb_oargs + nb_iargs; ++i) { 3805874b8574SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]); 3806874b8574SRichard Henderson 3807874b8574SRichard Henderson if (ts->kind != TEMP_TB) { 3808874b8574SRichard Henderson continue; 3809874b8574SRichard Henderson } 3810874b8574SRichard Henderson if (ts->state_ptr == NULL) { 3811874b8574SRichard Henderson ts->state_ptr = ebb; 3812874b8574SRichard Henderson } else if (ts->state_ptr != ebb) { 3813874b8574SRichard Henderson ts->state_ptr = multiple_ebb; 3814874b8574SRichard Henderson } 3815874b8574SRichard Henderson } 3816874b8574SRichard Henderson } 3817874b8574SRichard Henderson 3818874b8574SRichard Henderson /* 3819874b8574SRichard Henderson * For TEMP_TB that turned out not to be used beyond one EBB, 3820874b8574SRichard Henderson * reduce the liveness to TEMP_EBB. 3821874b8574SRichard Henderson */ 3822874b8574SRichard Henderson for (int i = s->nb_globals; i < nb_temps; ++i) { 3823874b8574SRichard Henderson TCGTemp *ts = &s->temps[i]; 3824874b8574SRichard Henderson if (ts->kind == TEMP_TB && ts->state_ptr != multiple_ebb) { 3825874b8574SRichard Henderson ts->kind = TEMP_EBB; 3826874b8574SRichard Henderson } 3827874b8574SRichard Henderson } 3828874b8574SRichard Henderson } 3829874b8574SRichard Henderson 3830a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a 3831c896fe29Sbellard given input arguments is dead. Instructions updating dead 3832c896fe29Sbellard temporaries are removed. */ 38339bbee4c0SRichard Henderson static void __attribute__((noinline)) 38349bbee4c0SRichard Henderson liveness_pass_1(TCGContext *s) 3835c896fe29Sbellard { 3836c70fbf0aSRichard Henderson int nb_globals = s->nb_globals; 38372616c808SRichard Henderson int nb_temps = s->nb_temps; 383815fa08f8SRichard Henderson TCGOp *op, *op_prev; 383925f49c5fSRichard Henderson TCGRegSet *prefs; 384025f49c5fSRichard Henderson int i; 384125f49c5fSRichard Henderson 384225f49c5fSRichard Henderson prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps); 384325f49c5fSRichard Henderson for (i = 0; i < nb_temps; ++i) { 384425f49c5fSRichard Henderson s->temps[i].state_ptr = prefs + i; 384525f49c5fSRichard Henderson } 3846c896fe29Sbellard 3847ae36a246SRichard Henderson /* ??? Should be redundant with the exit_tb that ends the TB. */ 38482616c808SRichard Henderson la_func_end(s, nb_globals, nb_temps); 3849c896fe29Sbellard 3850eae3eb3eSPaolo Bonzini QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) { 385125f49c5fSRichard Henderson int nb_iargs, nb_oargs; 3852c45cb8bbSRichard Henderson TCGOpcode opc_new, opc_new2; 3853c45cb8bbSRichard Henderson bool have_opc_new2; 3854a1b3c48dSRichard Henderson TCGLifeData arg_life = 0; 385525f49c5fSRichard Henderson TCGTemp *ts; 3856c45cb8bbSRichard Henderson TCGOpcode opc = op->opc; 3857c45cb8bbSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 3858501fb3daSRichard Henderson const TCGArgConstraint *args_ct; 3859c45cb8bbSRichard Henderson 3860c45cb8bbSRichard Henderson switch (opc) { 3861c896fe29Sbellard case INDEX_op_call: 3862c6e113f5Sbellard { 386339004a71SRichard Henderson const TCGHelperInfo *info = tcg_call_info(op); 386439004a71SRichard Henderson int call_flags = tcg_call_flags(op); 3865c6e113f5Sbellard 3866cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 3867cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 3868c6e113f5Sbellard 3869c45cb8bbSRichard Henderson /* pure functions can be removed if their result is unused */ 387078505279SAurelien Jarno if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) { 3871c6e113f5Sbellard for (i = 0; i < nb_oargs; i++) { 387225f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 387325f49c5fSRichard Henderson if (ts->state != TS_DEAD) { 3874c6e113f5Sbellard goto do_not_remove_call; 3875c6e113f5Sbellard } 38769c43b68dSAurelien Jarno } 3877c45cb8bbSRichard Henderson goto do_remove; 3878152c35aaSRichard Henderson } 3879c6e113f5Sbellard do_not_remove_call: 3880c896fe29Sbellard 388125f49c5fSRichard Henderson /* Output args are dead. */ 3882c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 388325f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 388425f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 3885a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 38866b64b624SAurelien Jarno } 388725f49c5fSRichard Henderson if (ts->state & TS_MEM) { 3888a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i; 38899c43b68dSAurelien Jarno } 389025f49c5fSRichard Henderson ts->state = TS_DEAD; 389125f49c5fSRichard Henderson la_reset_pref(ts); 3892c896fe29Sbellard } 3893c896fe29Sbellard 389431fd884bSRichard Henderson /* Not used -- it will be tcg_target_call_oarg_reg(). */ 389531fd884bSRichard Henderson memset(op->output_pref, 0, sizeof(op->output_pref)); 389631fd884bSRichard Henderson 389778505279SAurelien Jarno if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS | 389878505279SAurelien Jarno TCG_CALL_NO_READ_GLOBALS))) { 3899f65a061cSRichard Henderson la_global_kill(s, nb_globals); 3900c70fbf0aSRichard Henderson } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) { 3901f65a061cSRichard Henderson la_global_sync(s, nb_globals); 3902b9c18f56Saurel32 } 3903c896fe29Sbellard 390425f49c5fSRichard Henderson /* Record arguments that die in this helper. */ 3905866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 390625f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 390739004a71SRichard Henderson if (ts->state & TS_DEAD) { 3908a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 3909c896fe29Sbellard } 3910c896fe29Sbellard } 391125f49c5fSRichard Henderson 391225f49c5fSRichard Henderson /* For all live registers, remove call-clobbered prefs. */ 391325f49c5fSRichard Henderson la_cross_call(s, nb_temps); 391425f49c5fSRichard Henderson 391539004a71SRichard Henderson /* 391639004a71SRichard Henderson * Input arguments are live for preceding opcodes. 391739004a71SRichard Henderson * 391839004a71SRichard Henderson * For those arguments that die, and will be allocated in 391939004a71SRichard Henderson * registers, clear the register set for that arg, to be 392039004a71SRichard Henderson * filled in below. For args that will be on the stack, 392139004a71SRichard Henderson * reset to any available reg. Process arguments in reverse 392239004a71SRichard Henderson * order so that if a temp is used more than once, the stack 392339004a71SRichard Henderson * reset to max happens before the register reset to 0. 392425f49c5fSRichard Henderson */ 392539004a71SRichard Henderson for (i = nb_iargs - 1; i >= 0; i--) { 392639004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i]; 392739004a71SRichard Henderson ts = arg_temp(op->args[nb_oargs + i]); 392839004a71SRichard Henderson 392939004a71SRichard Henderson if (ts->state & TS_DEAD) { 393039004a71SRichard Henderson switch (loc->kind) { 393139004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 393239004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 393339004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 3934338b61e9SRichard Henderson if (arg_slot_reg_p(loc->arg_slot)) { 393539004a71SRichard Henderson *la_temp_pref(ts) = 0; 393639004a71SRichard Henderson break; 393739004a71SRichard Henderson } 393839004a71SRichard Henderson /* fall through */ 393939004a71SRichard Henderson default: 394039004a71SRichard Henderson *la_temp_pref(ts) = 394139004a71SRichard Henderson tcg_target_available_regs[ts->type]; 394239004a71SRichard Henderson break; 394339004a71SRichard Henderson } 394425f49c5fSRichard Henderson ts->state &= ~TS_DEAD; 394525f49c5fSRichard Henderson } 394625f49c5fSRichard Henderson } 394725f49c5fSRichard Henderson 394839004a71SRichard Henderson /* 394939004a71SRichard Henderson * For each input argument, add its input register to prefs. 395039004a71SRichard Henderson * If a temp is used once, this produces a single set bit; 395139004a71SRichard Henderson * if a temp is used multiple times, this produces a set. 395239004a71SRichard Henderson */ 395339004a71SRichard Henderson for (i = 0; i < nb_iargs; i++) { 395439004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i]; 395539004a71SRichard Henderson ts = arg_temp(op->args[nb_oargs + i]); 395639004a71SRichard Henderson 395739004a71SRichard Henderson switch (loc->kind) { 395839004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 395939004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 396039004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 3961338b61e9SRichard Henderson if (arg_slot_reg_p(loc->arg_slot)) { 396225f49c5fSRichard Henderson tcg_regset_set_reg(*la_temp_pref(ts), 396339004a71SRichard Henderson tcg_target_call_iarg_regs[loc->arg_slot]); 396439004a71SRichard Henderson } 396539004a71SRichard Henderson break; 396639004a71SRichard Henderson default: 396739004a71SRichard Henderson break; 3968c70fbf0aSRichard Henderson } 3969c19f47bfSAurelien Jarno } 3970c6e113f5Sbellard } 3971c896fe29Sbellard break; 3972765b842aSRichard Henderson case INDEX_op_insn_start: 3973c896fe29Sbellard break; 39745ff9d6a4Sbellard case INDEX_op_discard: 39755ff9d6a4Sbellard /* mark the temporary as dead */ 397625f49c5fSRichard Henderson ts = arg_temp(op->args[0]); 397725f49c5fSRichard Henderson ts->state = TS_DEAD; 397825f49c5fSRichard Henderson la_reset_pref(ts); 39795ff9d6a4Sbellard break; 39801305c451SRichard Henderson 39811305c451SRichard Henderson case INDEX_op_add2_i32: 3982c45cb8bbSRichard Henderson opc_new = INDEX_op_add_i32; 3983f1fae40cSRichard Henderson goto do_addsub2; 39841305c451SRichard Henderson case INDEX_op_sub2_i32: 3985c45cb8bbSRichard Henderson opc_new = INDEX_op_sub_i32; 3986f1fae40cSRichard Henderson goto do_addsub2; 3987f1fae40cSRichard Henderson case INDEX_op_add2_i64: 3988c45cb8bbSRichard Henderson opc_new = INDEX_op_add_i64; 3989f1fae40cSRichard Henderson goto do_addsub2; 3990f1fae40cSRichard Henderson case INDEX_op_sub2_i64: 3991c45cb8bbSRichard Henderson opc_new = INDEX_op_sub_i64; 3992f1fae40cSRichard Henderson do_addsub2: 39931305c451SRichard Henderson nb_iargs = 4; 39941305c451SRichard Henderson nb_oargs = 2; 39951305c451SRichard Henderson /* Test if the high part of the operation is dead, but not 39961305c451SRichard Henderson the low part. The result can be optimized to a simple 39971305c451SRichard Henderson add or sub. This happens often for x86_64 guest when the 39981305c451SRichard Henderson cpu mode is set to 32 bit. */ 3999b83eabeaSRichard Henderson if (arg_temp(op->args[1])->state == TS_DEAD) { 4000b83eabeaSRichard Henderson if (arg_temp(op->args[0])->state == TS_DEAD) { 40011305c451SRichard Henderson goto do_remove; 40021305c451SRichard Henderson } 4003c45cb8bbSRichard Henderson /* Replace the opcode and adjust the args in place, 4004c45cb8bbSRichard Henderson leaving 3 unused args at the end. */ 4005c45cb8bbSRichard Henderson op->opc = opc = opc_new; 4006efee3746SRichard Henderson op->args[1] = op->args[2]; 4007efee3746SRichard Henderson op->args[2] = op->args[4]; 40081305c451SRichard Henderson /* Fall through and mark the single-word operation live. */ 40091305c451SRichard Henderson nb_iargs = 2; 40101305c451SRichard Henderson nb_oargs = 1; 40111305c451SRichard Henderson } 40121305c451SRichard Henderson goto do_not_remove; 40131305c451SRichard Henderson 40141414968aSRichard Henderson case INDEX_op_mulu2_i32: 4015c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i32; 4016c45cb8bbSRichard Henderson opc_new2 = INDEX_op_muluh_i32; 4017c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_muluh_i32; 401803271524SRichard Henderson goto do_mul2; 4019f1fae40cSRichard Henderson case INDEX_op_muls2_i32: 4020c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i32; 4021c45cb8bbSRichard Henderson opc_new2 = INDEX_op_mulsh_i32; 4022c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_mulsh_i32; 4023f1fae40cSRichard Henderson goto do_mul2; 4024f1fae40cSRichard Henderson case INDEX_op_mulu2_i64: 4025c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i64; 4026c45cb8bbSRichard Henderson opc_new2 = INDEX_op_muluh_i64; 4027c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_muluh_i64; 402803271524SRichard Henderson goto do_mul2; 4029f1fae40cSRichard Henderson case INDEX_op_muls2_i64: 4030c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i64; 4031c45cb8bbSRichard Henderson opc_new2 = INDEX_op_mulsh_i64; 4032c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_mulsh_i64; 403303271524SRichard Henderson goto do_mul2; 4034f1fae40cSRichard Henderson do_mul2: 40351414968aSRichard Henderson nb_iargs = 2; 40361414968aSRichard Henderson nb_oargs = 2; 4037b83eabeaSRichard Henderson if (arg_temp(op->args[1])->state == TS_DEAD) { 4038b83eabeaSRichard Henderson if (arg_temp(op->args[0])->state == TS_DEAD) { 403903271524SRichard Henderson /* Both parts of the operation are dead. */ 40401414968aSRichard Henderson goto do_remove; 40411414968aSRichard Henderson } 404203271524SRichard Henderson /* The high part of the operation is dead; generate the low. */ 4043c45cb8bbSRichard Henderson op->opc = opc = opc_new; 4044efee3746SRichard Henderson op->args[1] = op->args[2]; 4045efee3746SRichard Henderson op->args[2] = op->args[3]; 4046b83eabeaSRichard Henderson } else if (arg_temp(op->args[0])->state == TS_DEAD && have_opc_new2) { 404703271524SRichard Henderson /* The low part of the operation is dead; generate the high. */ 4048c45cb8bbSRichard Henderson op->opc = opc = opc_new2; 4049efee3746SRichard Henderson op->args[0] = op->args[1]; 4050efee3746SRichard Henderson op->args[1] = op->args[2]; 4051efee3746SRichard Henderson op->args[2] = op->args[3]; 405203271524SRichard Henderson } else { 405303271524SRichard Henderson goto do_not_remove; 405403271524SRichard Henderson } 405503271524SRichard Henderson /* Mark the single-word operation live. */ 40561414968aSRichard Henderson nb_oargs = 1; 40571414968aSRichard Henderson goto do_not_remove; 40581414968aSRichard Henderson 4059c896fe29Sbellard default: 40601305c451SRichard Henderson /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */ 4061c896fe29Sbellard nb_iargs = def->nb_iargs; 4062c896fe29Sbellard nb_oargs = def->nb_oargs; 4063c896fe29Sbellard 4064c896fe29Sbellard /* Test if the operation can be removed because all 40655ff9d6a4Sbellard its outputs are dead. We assume that nb_oargs == 0 40665ff9d6a4Sbellard implies side effects */ 40675ff9d6a4Sbellard if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) { 4068c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 4069b83eabeaSRichard Henderson if (arg_temp(op->args[i])->state != TS_DEAD) { 4070c896fe29Sbellard goto do_not_remove; 4071c896fe29Sbellard } 40729c43b68dSAurelien Jarno } 4073152c35aaSRichard Henderson goto do_remove; 4074152c35aaSRichard Henderson } 4075152c35aaSRichard Henderson goto do_not_remove; 4076152c35aaSRichard Henderson 40771305c451SRichard Henderson do_remove: 40780c627cdcSRichard Henderson tcg_op_remove(s, op); 4079152c35aaSRichard Henderson break; 4080152c35aaSRichard Henderson 4081c896fe29Sbellard do_not_remove: 4082c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 408325f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 408425f49c5fSRichard Henderson 408525f49c5fSRichard Henderson /* Remember the preference of the uses that followed. */ 408631fd884bSRichard Henderson if (i < ARRAY_SIZE(op->output_pref)) { 408725f49c5fSRichard Henderson op->output_pref[i] = *la_temp_pref(ts); 408831fd884bSRichard Henderson } 408925f49c5fSRichard Henderson 409025f49c5fSRichard Henderson /* Output args are dead. */ 409125f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 4092a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 40936b64b624SAurelien Jarno } 409425f49c5fSRichard Henderson if (ts->state & TS_MEM) { 4095a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i; 40969c43b68dSAurelien Jarno } 409725f49c5fSRichard Henderson ts->state = TS_DEAD; 409825f49c5fSRichard Henderson la_reset_pref(ts); 4099c896fe29Sbellard } 4100c896fe29Sbellard 410125f49c5fSRichard Henderson /* If end of basic block, update. */ 4102ae36a246SRichard Henderson if (def->flags & TCG_OPF_BB_EXIT) { 4103ae36a246SRichard Henderson la_func_end(s, nb_globals, nb_temps); 4104b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_COND_BRANCH) { 4105b4cb76e6SRichard Henderson la_bb_sync(s, nb_globals, nb_temps); 4106ae36a246SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 41072616c808SRichard Henderson la_bb_end(s, nb_globals, nb_temps); 41083d5c5f87SAurelien Jarno } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { 4109f65a061cSRichard Henderson la_global_sync(s, nb_globals); 411025f49c5fSRichard Henderson if (def->flags & TCG_OPF_CALL_CLOBBER) { 411125f49c5fSRichard Henderson la_cross_call(s, nb_temps); 411225f49c5fSRichard Henderson } 4113c896fe29Sbellard } 4114c896fe29Sbellard 411525f49c5fSRichard Henderson /* Record arguments that die in this opcode. */ 4116866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 411725f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 411825f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 4119a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 4120c896fe29Sbellard } 4121c19f47bfSAurelien Jarno } 412225f49c5fSRichard Henderson 412325f49c5fSRichard Henderson /* Input arguments are live for preceding opcodes. */ 4124c19f47bfSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 412525f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 412625f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 412725f49c5fSRichard Henderson /* For operands that were dead, initially allow 412825f49c5fSRichard Henderson all regs for the type. */ 412925f49c5fSRichard Henderson *la_temp_pref(ts) = tcg_target_available_regs[ts->type]; 413025f49c5fSRichard Henderson ts->state &= ~TS_DEAD; 413125f49c5fSRichard Henderson } 413225f49c5fSRichard Henderson } 413325f49c5fSRichard Henderson 413425f49c5fSRichard Henderson /* Incorporate constraints for this operand. */ 413525f49c5fSRichard Henderson switch (opc) { 413625f49c5fSRichard Henderson case INDEX_op_mov_i32: 413725f49c5fSRichard Henderson case INDEX_op_mov_i64: 413825f49c5fSRichard Henderson /* Note that these are TCG_OPF_NOT_PRESENT and do not 413925f49c5fSRichard Henderson have proper constraints. That said, special case 414025f49c5fSRichard Henderson moves to propagate preferences backward. */ 414125f49c5fSRichard Henderson if (IS_DEAD_ARG(1)) { 414225f49c5fSRichard Henderson *la_temp_pref(arg_temp(op->args[0])) 414325f49c5fSRichard Henderson = *la_temp_pref(arg_temp(op->args[1])); 414425f49c5fSRichard Henderson } 414525f49c5fSRichard Henderson break; 414625f49c5fSRichard Henderson 414725f49c5fSRichard Henderson default: 4148501fb3daSRichard Henderson args_ct = opcode_args_ct(op); 414925f49c5fSRichard Henderson for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 4150501fb3daSRichard Henderson const TCGArgConstraint *ct = &args_ct[i]; 415125f49c5fSRichard Henderson TCGRegSet set, *pset; 415225f49c5fSRichard Henderson 415325f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 415425f49c5fSRichard Henderson pset = la_temp_pref(ts); 415525f49c5fSRichard Henderson set = *pset; 415625f49c5fSRichard Henderson 41579be0d080SRichard Henderson set &= ct->regs; 4158bc2b17e6SRichard Henderson if (ct->ialias) { 415931fd884bSRichard Henderson set &= output_pref(op, ct->alias_index); 416025f49c5fSRichard Henderson } 416125f49c5fSRichard Henderson /* If the combination is not possible, restart. */ 416225f49c5fSRichard Henderson if (set == 0) { 41639be0d080SRichard Henderson set = ct->regs; 416425f49c5fSRichard Henderson } 416525f49c5fSRichard Henderson *pset = set; 416625f49c5fSRichard Henderson } 416725f49c5fSRichard Henderson break; 4168c896fe29Sbellard } 4169c896fe29Sbellard break; 4170c896fe29Sbellard } 4171bee158cbSRichard Henderson op->life = arg_life; 4172c896fe29Sbellard } 41731ff0a2c5SEvgeny Voevodin } 4174c896fe29Sbellard 41755a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries. */ 41769bbee4c0SRichard Henderson static bool __attribute__((noinline)) 41779bbee4c0SRichard Henderson liveness_pass_2(TCGContext *s) 41785a18407fSRichard Henderson { 41795a18407fSRichard Henderson int nb_globals = s->nb_globals; 418015fa08f8SRichard Henderson int nb_temps, i; 41815a18407fSRichard Henderson bool changes = false; 418215fa08f8SRichard Henderson TCGOp *op, *op_next; 41835a18407fSRichard Henderson 41845a18407fSRichard Henderson /* Create a temporary for each indirect global. */ 41855a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 41865a18407fSRichard Henderson TCGTemp *its = &s->temps[i]; 41875a18407fSRichard Henderson if (its->indirect_reg) { 41885a18407fSRichard Henderson TCGTemp *dts = tcg_temp_alloc(s); 41895a18407fSRichard Henderson dts->type = its->type; 41905a18407fSRichard Henderson dts->base_type = its->base_type; 4191e1e64652SRichard Henderson dts->temp_subindex = its->temp_subindex; 4192c7482438SRichard Henderson dts->kind = TEMP_EBB; 4193b83eabeaSRichard Henderson its->state_ptr = dts; 4194b83eabeaSRichard Henderson } else { 4195b83eabeaSRichard Henderson its->state_ptr = NULL; 41965a18407fSRichard Henderson } 4197b83eabeaSRichard Henderson /* All globals begin dead. */ 4198b83eabeaSRichard Henderson its->state = TS_DEAD; 41995a18407fSRichard Henderson } 4200b83eabeaSRichard Henderson for (nb_temps = s->nb_temps; i < nb_temps; ++i) { 4201b83eabeaSRichard Henderson TCGTemp *its = &s->temps[i]; 4202b83eabeaSRichard Henderson its->state_ptr = NULL; 4203b83eabeaSRichard Henderson its->state = TS_DEAD; 4204b83eabeaSRichard Henderson } 42055a18407fSRichard Henderson 420615fa08f8SRichard Henderson QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) { 42075a18407fSRichard Henderson TCGOpcode opc = op->opc; 42085a18407fSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 42095a18407fSRichard Henderson TCGLifeData arg_life = op->life; 42105a18407fSRichard Henderson int nb_iargs, nb_oargs, call_flags; 4211b83eabeaSRichard Henderson TCGTemp *arg_ts, *dir_ts; 42125a18407fSRichard Henderson 42135a18407fSRichard Henderson if (opc == INDEX_op_call) { 4214cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 4215cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 421690163900SRichard Henderson call_flags = tcg_call_flags(op); 42175a18407fSRichard Henderson } else { 42185a18407fSRichard Henderson nb_iargs = def->nb_iargs; 42195a18407fSRichard Henderson nb_oargs = def->nb_oargs; 42205a18407fSRichard Henderson 42215a18407fSRichard Henderson /* Set flags similar to how calls require. */ 4222b4cb76e6SRichard Henderson if (def->flags & TCG_OPF_COND_BRANCH) { 4223b4cb76e6SRichard Henderson /* Like reading globals: sync_globals */ 4224b4cb76e6SRichard Henderson call_flags = TCG_CALL_NO_WRITE_GLOBALS; 4225b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 42265a18407fSRichard Henderson /* Like writing globals: save_globals */ 42275a18407fSRichard Henderson call_flags = 0; 42285a18407fSRichard Henderson } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { 42295a18407fSRichard Henderson /* Like reading globals: sync_globals */ 42305a18407fSRichard Henderson call_flags = TCG_CALL_NO_WRITE_GLOBALS; 42315a18407fSRichard Henderson } else { 42325a18407fSRichard Henderson /* No effect on globals. */ 42335a18407fSRichard Henderson call_flags = (TCG_CALL_NO_READ_GLOBALS | 42345a18407fSRichard Henderson TCG_CALL_NO_WRITE_GLOBALS); 42355a18407fSRichard Henderson } 42365a18407fSRichard Henderson } 42375a18407fSRichard Henderson 42385a18407fSRichard Henderson /* Make sure that input arguments are available. */ 42395a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 4240b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 4241b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 4242b83eabeaSRichard Henderson if (dir_ts && arg_ts->state == TS_DEAD) { 4243b83eabeaSRichard Henderson TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32 42445a18407fSRichard Henderson ? INDEX_op_ld_i32 42455a18407fSRichard Henderson : INDEX_op_ld_i64); 4246d4478943SPhilippe Mathieu-Daudé TCGOp *lop = tcg_op_insert_before(s, op, lopc, 3); 42475a18407fSRichard Henderson 4248b83eabeaSRichard Henderson lop->args[0] = temp_arg(dir_ts); 4249b83eabeaSRichard Henderson lop->args[1] = temp_arg(arg_ts->mem_base); 4250b83eabeaSRichard Henderson lop->args[2] = arg_ts->mem_offset; 42515a18407fSRichard Henderson 42525a18407fSRichard Henderson /* Loaded, but synced with memory. */ 4253b83eabeaSRichard Henderson arg_ts->state = TS_MEM; 42545a18407fSRichard Henderson } 42555a18407fSRichard Henderson } 42565a18407fSRichard Henderson 42575a18407fSRichard Henderson /* Perform input replacement, and mark inputs that became dead. 42585a18407fSRichard Henderson No action is required except keeping temp_state up to date 42595a18407fSRichard Henderson so that we reload when needed. */ 42605a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 4261b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 4262b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 4263b83eabeaSRichard Henderson if (dir_ts) { 4264b83eabeaSRichard Henderson op->args[i] = temp_arg(dir_ts); 42655a18407fSRichard Henderson changes = true; 42665a18407fSRichard Henderson if (IS_DEAD_ARG(i)) { 4267b83eabeaSRichard Henderson arg_ts->state = TS_DEAD; 42685a18407fSRichard Henderson } 42695a18407fSRichard Henderson } 42705a18407fSRichard Henderson } 42715a18407fSRichard Henderson 42725a18407fSRichard Henderson /* Liveness analysis should ensure that the following are 42735a18407fSRichard Henderson all correct, for call sites and basic block end points. */ 42745a18407fSRichard Henderson if (call_flags & TCG_CALL_NO_READ_GLOBALS) { 42755a18407fSRichard Henderson /* Nothing to do */ 42765a18407fSRichard Henderson } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) { 42775a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 42785a18407fSRichard Henderson /* Liveness should see that globals are synced back, 42795a18407fSRichard Henderson that is, either TS_DEAD or TS_MEM. */ 4280b83eabeaSRichard Henderson arg_ts = &s->temps[i]; 4281b83eabeaSRichard Henderson tcg_debug_assert(arg_ts->state_ptr == 0 4282b83eabeaSRichard Henderson || arg_ts->state != 0); 42835a18407fSRichard Henderson } 42845a18407fSRichard Henderson } else { 42855a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 42865a18407fSRichard Henderson /* Liveness should see that globals are saved back, 42875a18407fSRichard Henderson that is, TS_DEAD, waiting to be reloaded. */ 4288b83eabeaSRichard Henderson arg_ts = &s->temps[i]; 4289b83eabeaSRichard Henderson tcg_debug_assert(arg_ts->state_ptr == 0 4290b83eabeaSRichard Henderson || arg_ts->state == TS_DEAD); 42915a18407fSRichard Henderson } 42925a18407fSRichard Henderson } 42935a18407fSRichard Henderson 42945a18407fSRichard Henderson /* Outputs become available. */ 429561f15c48SRichard Henderson if (opc == INDEX_op_mov_i32 || opc == INDEX_op_mov_i64) { 429661f15c48SRichard Henderson arg_ts = arg_temp(op->args[0]); 429761f15c48SRichard Henderson dir_ts = arg_ts->state_ptr; 429861f15c48SRichard Henderson if (dir_ts) { 429961f15c48SRichard Henderson op->args[0] = temp_arg(dir_ts); 430061f15c48SRichard Henderson changes = true; 430161f15c48SRichard Henderson 430261f15c48SRichard Henderson /* The output is now live and modified. */ 430361f15c48SRichard Henderson arg_ts->state = 0; 430461f15c48SRichard Henderson 430561f15c48SRichard Henderson if (NEED_SYNC_ARG(0)) { 430661f15c48SRichard Henderson TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 430761f15c48SRichard Henderson ? INDEX_op_st_i32 430861f15c48SRichard Henderson : INDEX_op_st_i64); 4309d4478943SPhilippe Mathieu-Daudé TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3); 431061f15c48SRichard Henderson TCGTemp *out_ts = dir_ts; 431161f15c48SRichard Henderson 431261f15c48SRichard Henderson if (IS_DEAD_ARG(0)) { 431361f15c48SRichard Henderson out_ts = arg_temp(op->args[1]); 431461f15c48SRichard Henderson arg_ts->state = TS_DEAD; 431561f15c48SRichard Henderson tcg_op_remove(s, op); 431661f15c48SRichard Henderson } else { 431761f15c48SRichard Henderson arg_ts->state = TS_MEM; 431861f15c48SRichard Henderson } 431961f15c48SRichard Henderson 432061f15c48SRichard Henderson sop->args[0] = temp_arg(out_ts); 432161f15c48SRichard Henderson sop->args[1] = temp_arg(arg_ts->mem_base); 432261f15c48SRichard Henderson sop->args[2] = arg_ts->mem_offset; 432361f15c48SRichard Henderson } else { 432461f15c48SRichard Henderson tcg_debug_assert(!IS_DEAD_ARG(0)); 432561f15c48SRichard Henderson } 432661f15c48SRichard Henderson } 432761f15c48SRichard Henderson } else { 43285a18407fSRichard Henderson for (i = 0; i < nb_oargs; i++) { 4329b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 4330b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 4331b83eabeaSRichard Henderson if (!dir_ts) { 43325a18407fSRichard Henderson continue; 43335a18407fSRichard Henderson } 4334b83eabeaSRichard Henderson op->args[i] = temp_arg(dir_ts); 43355a18407fSRichard Henderson changes = true; 43365a18407fSRichard Henderson 43375a18407fSRichard Henderson /* The output is now live and modified. */ 4338b83eabeaSRichard Henderson arg_ts->state = 0; 43395a18407fSRichard Henderson 43405a18407fSRichard Henderson /* Sync outputs upon their last write. */ 43415a18407fSRichard Henderson if (NEED_SYNC_ARG(i)) { 4342b83eabeaSRichard Henderson TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 43435a18407fSRichard Henderson ? INDEX_op_st_i32 43445a18407fSRichard Henderson : INDEX_op_st_i64); 4345d4478943SPhilippe Mathieu-Daudé TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3); 43465a18407fSRichard Henderson 4347b83eabeaSRichard Henderson sop->args[0] = temp_arg(dir_ts); 4348b83eabeaSRichard Henderson sop->args[1] = temp_arg(arg_ts->mem_base); 4349b83eabeaSRichard Henderson sop->args[2] = arg_ts->mem_offset; 43505a18407fSRichard Henderson 4351b83eabeaSRichard Henderson arg_ts->state = TS_MEM; 43525a18407fSRichard Henderson } 43535a18407fSRichard Henderson /* Drop outputs that are dead. */ 43545a18407fSRichard Henderson if (IS_DEAD_ARG(i)) { 4355b83eabeaSRichard Henderson arg_ts->state = TS_DEAD; 43565a18407fSRichard Henderson } 43575a18407fSRichard Henderson } 43585a18407fSRichard Henderson } 435961f15c48SRichard Henderson } 43605a18407fSRichard Henderson 43615a18407fSRichard Henderson return changes; 43625a18407fSRichard Henderson } 43635a18407fSRichard Henderson 43642272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts) 4365c896fe29Sbellard { 436631c96417SRichard Henderson intptr_t off; 4367273eb50cSRichard Henderson int size, align; 4368c1c09194SRichard Henderson 4369273eb50cSRichard Henderson /* When allocating an object, look at the full type. */ 4370273eb50cSRichard Henderson size = tcg_type_size(ts->base_type); 4371273eb50cSRichard Henderson switch (ts->base_type) { 4372c1c09194SRichard Henderson case TCG_TYPE_I32: 437331c96417SRichard Henderson align = 4; 4374c1c09194SRichard Henderson break; 4375c1c09194SRichard Henderson case TCG_TYPE_I64: 4376c1c09194SRichard Henderson case TCG_TYPE_V64: 437731c96417SRichard Henderson align = 8; 4378c1c09194SRichard Henderson break; 437943eef72fSRichard Henderson case TCG_TYPE_I128: 4380c1c09194SRichard Henderson case TCG_TYPE_V128: 4381c1c09194SRichard Henderson case TCG_TYPE_V256: 438243eef72fSRichard Henderson /* 438343eef72fSRichard Henderson * Note that we do not require aligned storage for V256, 438443eef72fSRichard Henderson * and that we provide alignment for I128 to match V128, 438543eef72fSRichard Henderson * even if that's above what the host ABI requires. 438643eef72fSRichard Henderson */ 438731c96417SRichard Henderson align = 16; 4388c1c09194SRichard Henderson break; 4389c1c09194SRichard Henderson default: 4390c1c09194SRichard Henderson g_assert_not_reached(); 4391b591dc59SBlue Swirl } 4392c1c09194SRichard Henderson 4393b9537d59SRichard Henderson /* 4394b9537d59SRichard Henderson * Assume the stack is sufficiently aligned. 4395b9537d59SRichard Henderson * This affects e.g. ARM NEON, where we have 8 byte stack alignment 4396b9537d59SRichard Henderson * and do not require 16 byte vector alignment. This seems slightly 4397b9537d59SRichard Henderson * easier than fully parameterizing the above switch statement. 4398b9537d59SRichard Henderson */ 4399b9537d59SRichard Henderson align = MIN(TCG_TARGET_STACK_ALIGN, align); 4400c1c09194SRichard Henderson off = ROUND_UP(s->current_frame_offset, align); 4401732d5897SRichard Henderson 4402732d5897SRichard Henderson /* If we've exhausted the stack frame, restart with a smaller TB. */ 4403732d5897SRichard Henderson if (off + size > s->frame_end) { 4404732d5897SRichard Henderson tcg_raise_tb_overflow(s); 4405732d5897SRichard Henderson } 4406c1c09194SRichard Henderson s->current_frame_offset = off + size; 44079defd1bdSRichard Henderson #if defined(__sparc__) 4408273eb50cSRichard Henderson off += TCG_TARGET_STACK_BIAS; 44099defd1bdSRichard Henderson #endif 4410273eb50cSRichard Henderson 4411273eb50cSRichard Henderson /* If the object was subdivided, assign memory to all the parts. */ 4412273eb50cSRichard Henderson if (ts->base_type != ts->type) { 4413273eb50cSRichard Henderson int part_size = tcg_type_size(ts->type); 4414273eb50cSRichard Henderson int part_count = size / part_size; 4415273eb50cSRichard Henderson 4416273eb50cSRichard Henderson /* 4417273eb50cSRichard Henderson * Each part is allocated sequentially in tcg_temp_new_internal. 4418273eb50cSRichard Henderson * Jump back to the first part by subtracting the current index. 4419273eb50cSRichard Henderson */ 4420273eb50cSRichard Henderson ts -= ts->temp_subindex; 4421273eb50cSRichard Henderson for (int i = 0; i < part_count; ++i) { 4422273eb50cSRichard Henderson ts[i].mem_offset = off + i * part_size; 4423273eb50cSRichard Henderson ts[i].mem_base = s->frame_temp; 4424273eb50cSRichard Henderson ts[i].mem_allocated = 1; 4425273eb50cSRichard Henderson } 4426273eb50cSRichard Henderson } else { 4427273eb50cSRichard Henderson ts->mem_offset = off; 4428b3a62939SRichard Henderson ts->mem_base = s->frame_temp; 4429c896fe29Sbellard ts->mem_allocated = 1; 4430c896fe29Sbellard } 4431273eb50cSRichard Henderson } 4432c896fe29Sbellard 4433098859f1SRichard Henderson /* Assign @reg to @ts, and update reg_to_temp[]. */ 4434098859f1SRichard Henderson static void set_temp_val_reg(TCGContext *s, TCGTemp *ts, TCGReg reg) 4435098859f1SRichard Henderson { 4436098859f1SRichard Henderson if (ts->val_type == TEMP_VAL_REG) { 4437098859f1SRichard Henderson TCGReg old = ts->reg; 4438098859f1SRichard Henderson tcg_debug_assert(s->reg_to_temp[old] == ts); 4439098859f1SRichard Henderson if (old == reg) { 4440098859f1SRichard Henderson return; 4441098859f1SRichard Henderson } 4442098859f1SRichard Henderson s->reg_to_temp[old] = NULL; 4443098859f1SRichard Henderson } 4444098859f1SRichard Henderson tcg_debug_assert(s->reg_to_temp[reg] == NULL); 4445098859f1SRichard Henderson s->reg_to_temp[reg] = ts; 4446098859f1SRichard Henderson ts->val_type = TEMP_VAL_REG; 4447098859f1SRichard Henderson ts->reg = reg; 4448098859f1SRichard Henderson } 4449098859f1SRichard Henderson 4450098859f1SRichard Henderson /* Assign a non-register value type to @ts, and update reg_to_temp[]. */ 4451098859f1SRichard Henderson static void set_temp_val_nonreg(TCGContext *s, TCGTemp *ts, TCGTempVal type) 4452098859f1SRichard Henderson { 4453098859f1SRichard Henderson tcg_debug_assert(type != TEMP_VAL_REG); 4454098859f1SRichard Henderson if (ts->val_type == TEMP_VAL_REG) { 4455098859f1SRichard Henderson TCGReg reg = ts->reg; 4456098859f1SRichard Henderson tcg_debug_assert(s->reg_to_temp[reg] == ts); 4457098859f1SRichard Henderson s->reg_to_temp[reg] = NULL; 4458098859f1SRichard Henderson } 4459098859f1SRichard Henderson ts->val_type = type; 4460098859f1SRichard Henderson } 4461098859f1SRichard Henderson 4462b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet); 4463b3915dbbSRichard Henderson 446459d7c14eSRichard Henderson /* Mark a temporary as free or dead. If 'free_or_dead' is negative, 446559d7c14eSRichard Henderson mark it free; otherwise mark it dead. */ 446659d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead) 4467c896fe29Sbellard { 4468c0522136SRichard Henderson TCGTempVal new_type; 4469c0522136SRichard Henderson 4470c0522136SRichard Henderson switch (ts->kind) { 4471c0522136SRichard Henderson case TEMP_FIXED: 447259d7c14eSRichard Henderson return; 4473c0522136SRichard Henderson case TEMP_GLOBAL: 4474f57c6915SRichard Henderson case TEMP_TB: 4475c0522136SRichard Henderson new_type = TEMP_VAL_MEM; 4476c0522136SRichard Henderson break; 4477c7482438SRichard Henderson case TEMP_EBB: 4478c0522136SRichard Henderson new_type = free_or_dead < 0 ? TEMP_VAL_MEM : TEMP_VAL_DEAD; 4479c0522136SRichard Henderson break; 4480c0522136SRichard Henderson case TEMP_CONST: 4481c0522136SRichard Henderson new_type = TEMP_VAL_CONST; 4482c0522136SRichard Henderson break; 4483c0522136SRichard Henderson default: 4484c0522136SRichard Henderson g_assert_not_reached(); 448559d7c14eSRichard Henderson } 4486098859f1SRichard Henderson set_temp_val_nonreg(s, ts, new_type); 448759d7c14eSRichard Henderson } 4488c896fe29Sbellard 448959d7c14eSRichard Henderson /* Mark a temporary as dead. */ 449059d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts) 449159d7c14eSRichard Henderson { 449259d7c14eSRichard Henderson temp_free_or_dead(s, ts, 1); 449359d7c14eSRichard Henderson } 449459d7c14eSRichard Henderson 449559d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary 449659d7c14eSRichard Henderson registers needs to be allocated to store a constant. If 'free_or_dead' 449759d7c14eSRichard Henderson is non-zero, subsequently release the temporary; if it is positive, the 449859d7c14eSRichard Henderson temp is dead; if it is negative, the temp is free. */ 449998b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs, 450098b4e186SRichard Henderson TCGRegSet preferred_regs, int free_or_dead) 450159d7c14eSRichard Henderson { 4502c0522136SRichard Henderson if (!temp_readonly(ts) && !ts->mem_coherent) { 45037f6ceedfSAurelien Jarno if (!ts->mem_allocated) { 45042272e4a7SRichard Henderson temp_allocate_frame(s, ts); 450559d7c14eSRichard Henderson } 450659d7c14eSRichard Henderson switch (ts->val_type) { 450759d7c14eSRichard Henderson case TEMP_VAL_CONST: 450859d7c14eSRichard Henderson /* If we're going to free the temp immediately, then we won't 450959d7c14eSRichard Henderson require it later in a register, so attempt to store the 451059d7c14eSRichard Henderson constant to memory directly. */ 451159d7c14eSRichard Henderson if (free_or_dead 451259d7c14eSRichard Henderson && tcg_out_sti(s, ts->type, ts->val, 451359d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset)) { 451459d7c14eSRichard Henderson break; 451559d7c14eSRichard Henderson } 451659d7c14eSRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 451798b4e186SRichard Henderson allocated_regs, preferred_regs); 451859d7c14eSRichard Henderson /* fallthrough */ 451959d7c14eSRichard Henderson 452059d7c14eSRichard Henderson case TEMP_VAL_REG: 452159d7c14eSRichard Henderson tcg_out_st(s, ts->type, ts->reg, 452259d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset); 452359d7c14eSRichard Henderson break; 452459d7c14eSRichard Henderson 452559d7c14eSRichard Henderson case TEMP_VAL_MEM: 452659d7c14eSRichard Henderson break; 452759d7c14eSRichard Henderson 452859d7c14eSRichard Henderson case TEMP_VAL_DEAD: 452959d7c14eSRichard Henderson default: 4530732e89f4SRichard Henderson g_assert_not_reached(); 4531c896fe29Sbellard } 45327f6ceedfSAurelien Jarno ts->mem_coherent = 1; 45337f6ceedfSAurelien Jarno } 453459d7c14eSRichard Henderson if (free_or_dead) { 453559d7c14eSRichard Henderson temp_free_or_dead(s, ts, free_or_dead); 453659d7c14eSRichard Henderson } 453759d7c14eSRichard Henderson } 45387f6ceedfSAurelien Jarno 45397f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */ 4540b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs) 45417f6ceedfSAurelien Jarno { 4542f8b2f202SRichard Henderson TCGTemp *ts = s->reg_to_temp[reg]; 4543f8b2f202SRichard Henderson if (ts != NULL) { 454498b4e186SRichard Henderson temp_sync(s, ts, allocated_regs, 0, -1); 4545c896fe29Sbellard } 4546c896fe29Sbellard } 4547c896fe29Sbellard 4548b016486eSRichard Henderson /** 4549b016486eSRichard Henderson * tcg_reg_alloc: 4550b016486eSRichard Henderson * @required_regs: Set of registers in which we must allocate. 4551b016486eSRichard Henderson * @allocated_regs: Set of registers which must be avoided. 4552b016486eSRichard Henderson * @preferred_regs: Set of registers we should prefer. 4553b016486eSRichard Henderson * @rev: True if we search the registers in "indirect" order. 4554b016486eSRichard Henderson * 4555b016486eSRichard Henderson * The allocated register must be in @required_regs & ~@allocated_regs, 4556b016486eSRichard Henderson * but if we can put it in @preferred_regs we may save a move later. 4557b016486eSRichard Henderson */ 4558b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs, 4559b016486eSRichard Henderson TCGRegSet allocated_regs, 4560b016486eSRichard Henderson TCGRegSet preferred_regs, bool rev) 4561c896fe29Sbellard { 4562b016486eSRichard Henderson int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order); 4563b016486eSRichard Henderson TCGRegSet reg_ct[2]; 456491478cefSRichard Henderson const int *order; 4565c896fe29Sbellard 4566b016486eSRichard Henderson reg_ct[1] = required_regs & ~allocated_regs; 4567b016486eSRichard Henderson tcg_debug_assert(reg_ct[1] != 0); 4568b016486eSRichard Henderson reg_ct[0] = reg_ct[1] & preferred_regs; 4569b016486eSRichard Henderson 4570b016486eSRichard Henderson /* Skip the preferred_regs option if it cannot be satisfied, 4571b016486eSRichard Henderson or if the preference made no difference. */ 4572b016486eSRichard Henderson f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1]; 4573b016486eSRichard Henderson 457491478cefSRichard Henderson order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order; 4575c896fe29Sbellard 4576b016486eSRichard Henderson /* Try free registers, preferences first. */ 4577b016486eSRichard Henderson for (j = f; j < 2; j++) { 4578b016486eSRichard Henderson TCGRegSet set = reg_ct[j]; 4579b016486eSRichard Henderson 4580b016486eSRichard Henderson if (tcg_regset_single(set)) { 4581b016486eSRichard Henderson /* One register in the set. */ 4582b016486eSRichard Henderson TCGReg reg = tcg_regset_first(set); 4583b016486eSRichard Henderson if (s->reg_to_temp[reg] == NULL) { 4584c896fe29Sbellard return reg; 4585c896fe29Sbellard } 4586b016486eSRichard Henderson } else { 458791478cefSRichard Henderson for (i = 0; i < n; i++) { 4588b016486eSRichard Henderson TCGReg reg = order[i]; 4589b016486eSRichard Henderson if (s->reg_to_temp[reg] == NULL && 4590b016486eSRichard Henderson tcg_regset_test_reg(set, reg)) { 4591b016486eSRichard Henderson return reg; 4592b016486eSRichard Henderson } 4593b016486eSRichard Henderson } 4594b016486eSRichard Henderson } 4595b016486eSRichard Henderson } 4596b016486eSRichard Henderson 4597b016486eSRichard Henderson /* We must spill something. */ 4598b016486eSRichard Henderson for (j = f; j < 2; j++) { 4599b016486eSRichard Henderson TCGRegSet set = reg_ct[j]; 4600b016486eSRichard Henderson 4601b016486eSRichard Henderson if (tcg_regset_single(set)) { 4602b016486eSRichard Henderson /* One register in the set. */ 4603b016486eSRichard Henderson TCGReg reg = tcg_regset_first(set); 4604b3915dbbSRichard Henderson tcg_reg_free(s, reg, allocated_regs); 4605c896fe29Sbellard return reg; 4606b016486eSRichard Henderson } else { 4607b016486eSRichard Henderson for (i = 0; i < n; i++) { 4608b016486eSRichard Henderson TCGReg reg = order[i]; 4609b016486eSRichard Henderson if (tcg_regset_test_reg(set, reg)) { 4610b016486eSRichard Henderson tcg_reg_free(s, reg, allocated_regs); 4611b016486eSRichard Henderson return reg; 4612b016486eSRichard Henderson } 4613b016486eSRichard Henderson } 4614c896fe29Sbellard } 4615c896fe29Sbellard } 4616c896fe29Sbellard 4617732e89f4SRichard Henderson g_assert_not_reached(); 4618c896fe29Sbellard } 4619c896fe29Sbellard 462029f5e925SRichard Henderson static TCGReg tcg_reg_alloc_pair(TCGContext *s, TCGRegSet required_regs, 462129f5e925SRichard Henderson TCGRegSet allocated_regs, 462229f5e925SRichard Henderson TCGRegSet preferred_regs, bool rev) 462329f5e925SRichard Henderson { 462429f5e925SRichard Henderson int i, j, k, fmin, n = ARRAY_SIZE(tcg_target_reg_alloc_order); 462529f5e925SRichard Henderson TCGRegSet reg_ct[2]; 462629f5e925SRichard Henderson const int *order; 462729f5e925SRichard Henderson 462829f5e925SRichard Henderson /* Ensure that if I is not in allocated_regs, I+1 is not either. */ 462929f5e925SRichard Henderson reg_ct[1] = required_regs & ~(allocated_regs | (allocated_regs >> 1)); 463029f5e925SRichard Henderson tcg_debug_assert(reg_ct[1] != 0); 463129f5e925SRichard Henderson reg_ct[0] = reg_ct[1] & preferred_regs; 463229f5e925SRichard Henderson 463329f5e925SRichard Henderson order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order; 463429f5e925SRichard Henderson 463529f5e925SRichard Henderson /* 463629f5e925SRichard Henderson * Skip the preferred_regs option if it cannot be satisfied, 463729f5e925SRichard Henderson * or if the preference made no difference. 463829f5e925SRichard Henderson */ 463929f5e925SRichard Henderson k = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1]; 464029f5e925SRichard Henderson 464129f5e925SRichard Henderson /* 464229f5e925SRichard Henderson * Minimize the number of flushes by looking for 2 free registers first, 464329f5e925SRichard Henderson * then a single flush, then two flushes. 464429f5e925SRichard Henderson */ 464529f5e925SRichard Henderson for (fmin = 2; fmin >= 0; fmin--) { 464629f5e925SRichard Henderson for (j = k; j < 2; j++) { 464729f5e925SRichard Henderson TCGRegSet set = reg_ct[j]; 464829f5e925SRichard Henderson 464929f5e925SRichard Henderson for (i = 0; i < n; i++) { 465029f5e925SRichard Henderson TCGReg reg = order[i]; 465129f5e925SRichard Henderson 465229f5e925SRichard Henderson if (tcg_regset_test_reg(set, reg)) { 465329f5e925SRichard Henderson int f = !s->reg_to_temp[reg] + !s->reg_to_temp[reg + 1]; 465429f5e925SRichard Henderson if (f >= fmin) { 465529f5e925SRichard Henderson tcg_reg_free(s, reg, allocated_regs); 465629f5e925SRichard Henderson tcg_reg_free(s, reg + 1, allocated_regs); 465729f5e925SRichard Henderson return reg; 465829f5e925SRichard Henderson } 465929f5e925SRichard Henderson } 466029f5e925SRichard Henderson } 466129f5e925SRichard Henderson } 466229f5e925SRichard Henderson } 4663732e89f4SRichard Henderson g_assert_not_reached(); 466429f5e925SRichard Henderson } 466529f5e925SRichard Henderson 466640ae5c62SRichard Henderson /* Make sure the temporary is in a register. If needed, allocate the register 466740ae5c62SRichard Henderson from DESIRED while avoiding ALLOCATED. */ 466840ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs, 4669b722452aSRichard Henderson TCGRegSet allocated_regs, TCGRegSet preferred_regs) 467040ae5c62SRichard Henderson { 467140ae5c62SRichard Henderson TCGReg reg; 467240ae5c62SRichard Henderson 467340ae5c62SRichard Henderson switch (ts->val_type) { 467440ae5c62SRichard Henderson case TEMP_VAL_REG: 467540ae5c62SRichard Henderson return; 467640ae5c62SRichard Henderson case TEMP_VAL_CONST: 4677b016486eSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs, 4678b722452aSRichard Henderson preferred_regs, ts->indirect_base); 46790a6a8bc8SRichard Henderson if (ts->type <= TCG_TYPE_I64) { 468040ae5c62SRichard Henderson tcg_out_movi(s, ts->type, reg, ts->val); 46810a6a8bc8SRichard Henderson } else { 46824e186175SRichard Henderson uint64_t val = ts->val; 46834e186175SRichard Henderson MemOp vece = MO_64; 46844e186175SRichard Henderson 46854e186175SRichard Henderson /* 46864e186175SRichard Henderson * Find the minimal vector element that matches the constant. 46874e186175SRichard Henderson * The targets will, in general, have to do this search anyway, 46884e186175SRichard Henderson * do this generically. 46894e186175SRichard Henderson */ 46904e186175SRichard Henderson if (val == dup_const(MO_8, val)) { 46914e186175SRichard Henderson vece = MO_8; 46924e186175SRichard Henderson } else if (val == dup_const(MO_16, val)) { 46934e186175SRichard Henderson vece = MO_16; 46940b4286ddSRichard Henderson } else if (val == dup_const(MO_32, val)) { 46954e186175SRichard Henderson vece = MO_32; 46964e186175SRichard Henderson } 46974e186175SRichard Henderson 46984e186175SRichard Henderson tcg_out_dupi_vec(s, ts->type, vece, reg, ts->val); 46990a6a8bc8SRichard Henderson } 470040ae5c62SRichard Henderson ts->mem_coherent = 0; 470140ae5c62SRichard Henderson break; 470240ae5c62SRichard Henderson case TEMP_VAL_MEM: 4703b016486eSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs, 4704b722452aSRichard Henderson preferred_regs, ts->indirect_base); 470540ae5c62SRichard Henderson tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset); 470640ae5c62SRichard Henderson ts->mem_coherent = 1; 470740ae5c62SRichard Henderson break; 470840ae5c62SRichard Henderson case TEMP_VAL_DEAD: 470940ae5c62SRichard Henderson default: 4710732e89f4SRichard Henderson g_assert_not_reached(); 471140ae5c62SRichard Henderson } 4712098859f1SRichard Henderson set_temp_val_reg(s, ts, reg); 471340ae5c62SRichard Henderson } 471440ae5c62SRichard Henderson 471559d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a 4716e8996ee0Sbellard temporary registers needs to be allocated to store a constant. */ 471759d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs) 47181ad80729SAurelien Jarno { 47192c0366f0SAurelien Jarno /* The liveness analysis already ensures that globals are back 4720eabb7b91SAurelien Jarno in memory. Keep an tcg_debug_assert for safety. */ 4721e01fa97dSRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || temp_readonly(ts)); 47221ad80729SAurelien Jarno } 47231ad80729SAurelien Jarno 47249814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be 4725641d5fbeSbellard modified be the following code. 'allocated_regs' is used in case a 4726641d5fbeSbellard temporary registers needs to be allocated to store a constant. */ 4727641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs) 4728641d5fbeSbellard { 4729ac3b8891SRichard Henderson int i, n; 4730641d5fbeSbellard 4731ac3b8891SRichard Henderson for (i = 0, n = s->nb_globals; i < n; i++) { 4732b13eb728SRichard Henderson temp_save(s, &s->temps[i], allocated_regs); 4733641d5fbeSbellard } 4734e5097dc8Sbellard } 4735e5097dc8Sbellard 47363d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be 47373d5c5f87SAurelien Jarno read by the following code. 'allocated_regs' is used in case a 47383d5c5f87SAurelien Jarno temporary registers needs to be allocated to store a constant. */ 47393d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs) 47403d5c5f87SAurelien Jarno { 4741ac3b8891SRichard Henderson int i, n; 47423d5c5f87SAurelien Jarno 4743ac3b8891SRichard Henderson for (i = 0, n = s->nb_globals; i < n; i++) { 474412b9b11aSRichard Henderson TCGTemp *ts = &s->temps[i]; 474512b9b11aSRichard Henderson tcg_debug_assert(ts->val_type != TEMP_VAL_REG 4746ee17db83SRichard Henderson || ts->kind == TEMP_FIXED 474712b9b11aSRichard Henderson || ts->mem_coherent); 47483d5c5f87SAurelien Jarno } 47493d5c5f87SAurelien Jarno } 47503d5c5f87SAurelien Jarno 4751e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and 4752e8996ee0Sbellard all globals are stored at their canonical location. */ 4753e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs) 4754e5097dc8Sbellard { 4755e5097dc8Sbellard int i; 4756e5097dc8Sbellard 4757c896fe29Sbellard for (i = s->nb_globals; i < s->nb_temps; i++) { 4758b13eb728SRichard Henderson TCGTemp *ts = &s->temps[i]; 4759c0522136SRichard Henderson 4760c0522136SRichard Henderson switch (ts->kind) { 4761f57c6915SRichard Henderson case TEMP_TB: 4762b13eb728SRichard Henderson temp_save(s, ts, allocated_regs); 4763c0522136SRichard Henderson break; 4764c7482438SRichard Henderson case TEMP_EBB: 47652c0366f0SAurelien Jarno /* The liveness analysis already ensures that temps are dead. 4766eabb7b91SAurelien Jarno Keep an tcg_debug_assert for safety. */ 4767eabb7b91SAurelien Jarno tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD); 4768c0522136SRichard Henderson break; 4769c0522136SRichard Henderson case TEMP_CONST: 4770c0522136SRichard Henderson /* Similarly, we should have freed any allocated register. */ 4771c0522136SRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_CONST); 4772c0522136SRichard Henderson break; 4773c0522136SRichard Henderson default: 4774c0522136SRichard Henderson g_assert_not_reached(); 4775c896fe29Sbellard } 4776641d5fbeSbellard } 4777e8996ee0Sbellard 4778e8996ee0Sbellard save_globals(s, allocated_regs); 4779c896fe29Sbellard } 4780c896fe29Sbellard 4781bab1671fSRichard Henderson /* 4782c7482438SRichard Henderson * At a conditional branch, we assume all temporaries are dead unless 4783c7482438SRichard Henderson * explicitly live-across-conditional-branch; all globals and local 4784c7482438SRichard Henderson * temps are synced to their location. 4785b4cb76e6SRichard Henderson */ 4786b4cb76e6SRichard Henderson static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs) 4787b4cb76e6SRichard Henderson { 4788b4cb76e6SRichard Henderson sync_globals(s, allocated_regs); 4789b4cb76e6SRichard Henderson 4790b4cb76e6SRichard Henderson for (int i = s->nb_globals; i < s->nb_temps; i++) { 4791b4cb76e6SRichard Henderson TCGTemp *ts = &s->temps[i]; 4792b4cb76e6SRichard Henderson /* 4793b4cb76e6SRichard Henderson * The liveness analysis already ensures that temps are dead. 4794b4cb76e6SRichard Henderson * Keep tcg_debug_asserts for safety. 4795b4cb76e6SRichard Henderson */ 4796c0522136SRichard Henderson switch (ts->kind) { 4797f57c6915SRichard Henderson case TEMP_TB: 4798b4cb76e6SRichard Henderson tcg_debug_assert(ts->val_type != TEMP_VAL_REG || ts->mem_coherent); 4799c0522136SRichard Henderson break; 4800c7482438SRichard Henderson case TEMP_EBB: 4801c0522136SRichard Henderson case TEMP_CONST: 4802c0522136SRichard Henderson break; 4803c0522136SRichard Henderson default: 4804c0522136SRichard Henderson g_assert_not_reached(); 4805b4cb76e6SRichard Henderson } 4806b4cb76e6SRichard Henderson } 4807b4cb76e6SRichard Henderson } 4808b4cb76e6SRichard Henderson 4809b4cb76e6SRichard Henderson /* 4810c58f4c97SRichard Henderson * Specialized code generation for INDEX_op_mov_* with a constant. 4811bab1671fSRichard Henderson */ 48120fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots, 4813ba87719cSRichard Henderson tcg_target_ulong val, TCGLifeData arg_life, 4814ba87719cSRichard Henderson TCGRegSet preferred_regs) 4815e8996ee0Sbellard { 4816d63e3b6eSRichard Henderson /* ENV should not be modified. */ 4817e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 481859d7c14eSRichard Henderson 481959d7c14eSRichard Henderson /* The movi is not explicitly generated here. */ 4820098859f1SRichard Henderson set_temp_val_nonreg(s, ots, TEMP_VAL_CONST); 4821e8996ee0Sbellard ots->val = val; 482259d7c14eSRichard Henderson ots->mem_coherent = 0; 4823ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) { 4824ba87719cSRichard Henderson temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0)); 482559d7c14eSRichard Henderson } else if (IS_DEAD_ARG(0)) { 4826f8bf00f1SRichard Henderson temp_dead(s, ots); 48274c4e1ab2SAurelien Jarno } 4828e8996ee0Sbellard } 4829e8996ee0Sbellard 4830bab1671fSRichard Henderson /* 4831bab1671fSRichard Henderson * Specialized code generation for INDEX_op_mov_*. 4832bab1671fSRichard Henderson */ 4833dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op) 4834c896fe29Sbellard { 4835dd186292SRichard Henderson const TCGLifeData arg_life = op->life; 483669e3706dSRichard Henderson TCGRegSet allocated_regs, preferred_regs; 4837c896fe29Sbellard TCGTemp *ts, *ots; 4838450445d5SRichard Henderson TCGType otype, itype; 4839098859f1SRichard Henderson TCGReg oreg, ireg; 4840c896fe29Sbellard 4841d21369f5SRichard Henderson allocated_regs = s->reserved_regs; 484231fd884bSRichard Henderson preferred_regs = output_pref(op, 0); 484343439139SRichard Henderson ots = arg_temp(op->args[0]); 484443439139SRichard Henderson ts = arg_temp(op->args[1]); 4845450445d5SRichard Henderson 4846d63e3b6eSRichard Henderson /* ENV should not be modified. */ 4847e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 4848d63e3b6eSRichard Henderson 4849450445d5SRichard Henderson /* Note that otype != itype for no-op truncation. */ 4850450445d5SRichard Henderson otype = ots->type; 4851450445d5SRichard Henderson itype = ts->type; 4852c896fe29Sbellard 48530fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_CONST) { 48540fe4fca4SPaolo Bonzini /* propagate constant or generate sti */ 48550fe4fca4SPaolo Bonzini tcg_target_ulong val = ts->val; 48560fe4fca4SPaolo Bonzini if (IS_DEAD_ARG(1)) { 48570fe4fca4SPaolo Bonzini temp_dead(s, ts); 48580fe4fca4SPaolo Bonzini } 485969e3706dSRichard Henderson tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs); 48600fe4fca4SPaolo Bonzini return; 48610fe4fca4SPaolo Bonzini } 48620fe4fca4SPaolo Bonzini 48630fe4fca4SPaolo Bonzini /* If the source value is in memory we're going to be forced 48640fe4fca4SPaolo Bonzini to have it in a register in order to perform the copy. Copy 48650fe4fca4SPaolo Bonzini the SOURCE value into its own register first, that way we 48660fe4fca4SPaolo Bonzini don't have to reload SOURCE the next time it is used. */ 48670fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_MEM) { 486869e3706dSRichard Henderson temp_load(s, ts, tcg_target_available_regs[itype], 486969e3706dSRichard Henderson allocated_regs, preferred_regs); 4870c29c1d7eSAurelien Jarno } 48710fe4fca4SPaolo Bonzini tcg_debug_assert(ts->val_type == TEMP_VAL_REG); 4872098859f1SRichard Henderson ireg = ts->reg; 4873098859f1SRichard Henderson 4874d63e3b6eSRichard Henderson if (IS_DEAD_ARG(0)) { 4875c29c1d7eSAurelien Jarno /* mov to a non-saved dead register makes no sense (even with 4876c29c1d7eSAurelien Jarno liveness analysis disabled). */ 4877eabb7b91SAurelien Jarno tcg_debug_assert(NEED_SYNC_ARG(0)); 4878c29c1d7eSAurelien Jarno if (!ots->mem_allocated) { 48792272e4a7SRichard Henderson temp_allocate_frame(s, ots); 4880c29c1d7eSAurelien Jarno } 4881098859f1SRichard Henderson tcg_out_st(s, otype, ireg, ots->mem_base->reg, ots->mem_offset); 4882c29c1d7eSAurelien Jarno if (IS_DEAD_ARG(1)) { 4883f8bf00f1SRichard Henderson temp_dead(s, ts); 4884c29c1d7eSAurelien Jarno } 4885f8bf00f1SRichard Henderson temp_dead(s, ots); 4886098859f1SRichard Henderson return; 4887098859f1SRichard Henderson } 4888098859f1SRichard Henderson 4889ee17db83SRichard Henderson if (IS_DEAD_ARG(1) && ts->kind != TEMP_FIXED) { 4890098859f1SRichard Henderson /* 4891098859f1SRichard Henderson * The mov can be suppressed. Kill input first, so that it 4892098859f1SRichard Henderson * is unlinked from reg_to_temp, then set the output to the 4893098859f1SRichard Henderson * reg that we saved from the input. 4894098859f1SRichard Henderson */ 4895f8bf00f1SRichard Henderson temp_dead(s, ts); 4896098859f1SRichard Henderson oreg = ireg; 4897c29c1d7eSAurelien Jarno } else { 4898098859f1SRichard Henderson if (ots->val_type == TEMP_VAL_REG) { 4899098859f1SRichard Henderson oreg = ots->reg; 4900098859f1SRichard Henderson } else { 4901098859f1SRichard Henderson /* Make sure to not spill the input register during allocation. */ 4902098859f1SRichard Henderson oreg = tcg_reg_alloc(s, tcg_target_available_regs[otype], 4903098859f1SRichard Henderson allocated_regs | ((TCGRegSet)1 << ireg), 4904098859f1SRichard Henderson preferred_regs, ots->indirect_base); 4905c29c1d7eSAurelien Jarno } 4906098859f1SRichard Henderson if (!tcg_out_mov(s, otype, oreg, ireg)) { 4907240c08d0SRichard Henderson /* 4908240c08d0SRichard Henderson * Cross register class move not supported. 4909240c08d0SRichard Henderson * Store the source register into the destination slot 4910240c08d0SRichard Henderson * and leave the destination temp as TEMP_VAL_MEM. 4911240c08d0SRichard Henderson */ 4912e01fa97dSRichard Henderson assert(!temp_readonly(ots)); 4913240c08d0SRichard Henderson if (!ts->mem_allocated) { 4914240c08d0SRichard Henderson temp_allocate_frame(s, ots); 4915240c08d0SRichard Henderson } 4916098859f1SRichard Henderson tcg_out_st(s, ts->type, ireg, ots->mem_base->reg, ots->mem_offset); 4917098859f1SRichard Henderson set_temp_val_nonreg(s, ts, TEMP_VAL_MEM); 4918240c08d0SRichard Henderson ots->mem_coherent = 1; 4919240c08d0SRichard Henderson return; 492078113e83SRichard Henderson } 4921c29c1d7eSAurelien Jarno } 4922098859f1SRichard Henderson set_temp_val_reg(s, ots, oreg); 4923c896fe29Sbellard ots->mem_coherent = 0; 4924098859f1SRichard Henderson 4925ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) { 492698b4e186SRichard Henderson temp_sync(s, ots, allocated_regs, 0, 0); 4927c29c1d7eSAurelien Jarno } 4928ec7a869dSAurelien Jarno } 4929c896fe29Sbellard 4930bab1671fSRichard Henderson /* 4931bab1671fSRichard Henderson * Specialized code generation for INDEX_op_dup_vec. 4932bab1671fSRichard Henderson */ 4933bab1671fSRichard Henderson static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op) 4934bab1671fSRichard Henderson { 4935bab1671fSRichard Henderson const TCGLifeData arg_life = op->life; 4936bab1671fSRichard Henderson TCGRegSet dup_out_regs, dup_in_regs; 4937501fb3daSRichard Henderson const TCGArgConstraint *dup_args_ct; 4938bab1671fSRichard Henderson TCGTemp *its, *ots; 4939bab1671fSRichard Henderson TCGType itype, vtype; 4940bab1671fSRichard Henderson unsigned vece; 494131c96417SRichard Henderson int lowpart_ofs; 4942bab1671fSRichard Henderson bool ok; 4943bab1671fSRichard Henderson 4944bab1671fSRichard Henderson ots = arg_temp(op->args[0]); 4945bab1671fSRichard Henderson its = arg_temp(op->args[1]); 4946bab1671fSRichard Henderson 4947bab1671fSRichard Henderson /* ENV should not be modified. */ 4948e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 4949bab1671fSRichard Henderson 4950bab1671fSRichard Henderson itype = its->type; 4951bab1671fSRichard Henderson vece = TCGOP_VECE(op); 49524d872218SRichard Henderson vtype = TCGOP_TYPE(op); 4953bab1671fSRichard Henderson 4954bab1671fSRichard Henderson if (its->val_type == TEMP_VAL_CONST) { 4955bab1671fSRichard Henderson /* Propagate constant via movi -> dupi. */ 4956bab1671fSRichard Henderson tcg_target_ulong val = its->val; 4957bab1671fSRichard Henderson if (IS_DEAD_ARG(1)) { 4958bab1671fSRichard Henderson temp_dead(s, its); 4959bab1671fSRichard Henderson } 496031fd884bSRichard Henderson tcg_reg_alloc_do_movi(s, ots, val, arg_life, output_pref(op, 0)); 4961bab1671fSRichard Henderson return; 4962bab1671fSRichard Henderson } 4963bab1671fSRichard Henderson 4964501fb3daSRichard Henderson dup_args_ct = opcode_args_ct(op); 4965501fb3daSRichard Henderson dup_out_regs = dup_args_ct[0].regs; 4966501fb3daSRichard Henderson dup_in_regs = dup_args_ct[1].regs; 4967bab1671fSRichard Henderson 4968bab1671fSRichard Henderson /* Allocate the output register now. */ 4969bab1671fSRichard Henderson if (ots->val_type != TEMP_VAL_REG) { 4970bab1671fSRichard Henderson TCGRegSet allocated_regs = s->reserved_regs; 4971098859f1SRichard Henderson TCGReg oreg; 4972bab1671fSRichard Henderson 4973bab1671fSRichard Henderson if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) { 4974bab1671fSRichard Henderson /* Make sure to not spill the input register. */ 4975bab1671fSRichard Henderson tcg_regset_set_reg(allocated_regs, its->reg); 4976bab1671fSRichard Henderson } 4977098859f1SRichard Henderson oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs, 497831fd884bSRichard Henderson output_pref(op, 0), ots->indirect_base); 4979098859f1SRichard Henderson set_temp_val_reg(s, ots, oreg); 4980bab1671fSRichard Henderson } 4981bab1671fSRichard Henderson 4982bab1671fSRichard Henderson switch (its->val_type) { 4983bab1671fSRichard Henderson case TEMP_VAL_REG: 4984bab1671fSRichard Henderson /* 4985bab1671fSRichard Henderson * The dup constriaints must be broad, covering all possible VECE. 4986bab1671fSRichard Henderson * However, tcg_op_dup_vec() gets to see the VECE and we allow it 4987bab1671fSRichard Henderson * to fail, indicating that extra moves are required for that case. 4988bab1671fSRichard Henderson */ 4989bab1671fSRichard Henderson if (tcg_regset_test_reg(dup_in_regs, its->reg)) { 4990bab1671fSRichard Henderson if (tcg_out_dup_vec(s, vtype, vece, ots->reg, its->reg)) { 4991bab1671fSRichard Henderson goto done; 4992bab1671fSRichard Henderson } 4993bab1671fSRichard Henderson /* Try again from memory or a vector input register. */ 4994bab1671fSRichard Henderson } 4995bab1671fSRichard Henderson if (!its->mem_coherent) { 4996bab1671fSRichard Henderson /* 4997bab1671fSRichard Henderson * The input register is not synced, and so an extra store 4998bab1671fSRichard Henderson * would be required to use memory. Attempt an integer-vector 4999bab1671fSRichard Henderson * register move first. We do not have a TCGRegSet for this. 5000bab1671fSRichard Henderson */ 5001bab1671fSRichard Henderson if (tcg_out_mov(s, itype, ots->reg, its->reg)) { 5002bab1671fSRichard Henderson break; 5003bab1671fSRichard Henderson } 5004bab1671fSRichard Henderson /* Sync the temp back to its slot and load from there. */ 5005bab1671fSRichard Henderson temp_sync(s, its, s->reserved_regs, 0, 0); 5006bab1671fSRichard Henderson } 5007bab1671fSRichard Henderson /* fall through */ 5008bab1671fSRichard Henderson 5009bab1671fSRichard Henderson case TEMP_VAL_MEM: 501031c96417SRichard Henderson lowpart_ofs = 0; 501131c96417SRichard Henderson if (HOST_BIG_ENDIAN) { 501231c96417SRichard Henderson lowpart_ofs = tcg_type_size(itype) - (1 << vece); 501331c96417SRichard Henderson } 5014d6ecb4a9SRichard Henderson if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg, 501531c96417SRichard Henderson its->mem_offset + lowpart_ofs)) { 5016d6ecb4a9SRichard Henderson goto done; 5017d6ecb4a9SRichard Henderson } 5018098859f1SRichard Henderson /* Load the input into the destination vector register. */ 5019bab1671fSRichard Henderson tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset); 5020bab1671fSRichard Henderson break; 5021bab1671fSRichard Henderson 5022bab1671fSRichard Henderson default: 5023bab1671fSRichard Henderson g_assert_not_reached(); 5024bab1671fSRichard Henderson } 5025bab1671fSRichard Henderson 5026bab1671fSRichard Henderson /* We now have a vector input register, so dup must succeed. */ 5027bab1671fSRichard Henderson ok = tcg_out_dup_vec(s, vtype, vece, ots->reg, ots->reg); 5028bab1671fSRichard Henderson tcg_debug_assert(ok); 5029bab1671fSRichard Henderson 5030bab1671fSRichard Henderson done: 503136f5539cSRichard Henderson ots->mem_coherent = 0; 5032bab1671fSRichard Henderson if (IS_DEAD_ARG(1)) { 5033bab1671fSRichard Henderson temp_dead(s, its); 5034bab1671fSRichard Henderson } 5035bab1671fSRichard Henderson if (NEED_SYNC_ARG(0)) { 5036bab1671fSRichard Henderson temp_sync(s, ots, s->reserved_regs, 0, 0); 5037bab1671fSRichard Henderson } 5038bab1671fSRichard Henderson if (IS_DEAD_ARG(0)) { 5039bab1671fSRichard Henderson temp_dead(s, ots); 5040bab1671fSRichard Henderson } 5041bab1671fSRichard Henderson } 5042bab1671fSRichard Henderson 5043dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) 5044c896fe29Sbellard { 5045dd186292SRichard Henderson const TCGLifeData arg_life = op->life; 5046dd186292SRichard Henderson const TCGOpDef * const def = &tcg_op_defs[op->opc]; 504782790a87SRichard Henderson TCGRegSet i_allocated_regs; 504882790a87SRichard Henderson TCGRegSet o_allocated_regs; 5049b6638662SRichard Henderson int i, k, nb_iargs, nb_oargs; 5050b6638662SRichard Henderson TCGReg reg; 5051c896fe29Sbellard TCGArg arg; 5052501fb3daSRichard Henderson const TCGArgConstraint *args_ct; 5053c896fe29Sbellard const TCGArgConstraint *arg_ct; 5054c896fe29Sbellard TCGTemp *ts; 5055c896fe29Sbellard TCGArg new_args[TCG_MAX_OP_ARGS]; 5056c896fe29Sbellard int const_args[TCG_MAX_OP_ARGS]; 505721e9a8aeSRichard Henderson TCGCond op_cond; 5058c896fe29Sbellard 5059c896fe29Sbellard nb_oargs = def->nb_oargs; 5060c896fe29Sbellard nb_iargs = def->nb_iargs; 5061c896fe29Sbellard 5062c896fe29Sbellard /* copy constants */ 5063c896fe29Sbellard memcpy(new_args + nb_oargs + nb_iargs, 5064dd186292SRichard Henderson op->args + nb_oargs + nb_iargs, 5065c896fe29Sbellard sizeof(TCGArg) * def->nb_cargs); 5066c896fe29Sbellard 5067d21369f5SRichard Henderson i_allocated_regs = s->reserved_regs; 5068d21369f5SRichard Henderson o_allocated_regs = s->reserved_regs; 506982790a87SRichard Henderson 507021e9a8aeSRichard Henderson switch (op->opc) { 507121e9a8aeSRichard Henderson case INDEX_op_brcond_i32: 507221e9a8aeSRichard Henderson case INDEX_op_brcond_i64: 507321e9a8aeSRichard Henderson op_cond = op->args[2]; 507421e9a8aeSRichard Henderson break; 507521e9a8aeSRichard Henderson case INDEX_op_setcond_i32: 507621e9a8aeSRichard Henderson case INDEX_op_setcond_i64: 507721e9a8aeSRichard Henderson case INDEX_op_negsetcond_i32: 507821e9a8aeSRichard Henderson case INDEX_op_negsetcond_i64: 507921e9a8aeSRichard Henderson case INDEX_op_cmp_vec: 508021e9a8aeSRichard Henderson op_cond = op->args[3]; 508121e9a8aeSRichard Henderson break; 508221e9a8aeSRichard Henderson case INDEX_op_brcond2_i32: 508321e9a8aeSRichard Henderson op_cond = op->args[4]; 508421e9a8aeSRichard Henderson break; 508521e9a8aeSRichard Henderson case INDEX_op_movcond_i32: 508621e9a8aeSRichard Henderson case INDEX_op_movcond_i64: 508721e9a8aeSRichard Henderson case INDEX_op_setcond2_i32: 508821e9a8aeSRichard Henderson case INDEX_op_cmpsel_vec: 508921e9a8aeSRichard Henderson op_cond = op->args[5]; 509021e9a8aeSRichard Henderson break; 509121e9a8aeSRichard Henderson default: 509221e9a8aeSRichard Henderson /* No condition within opcode. */ 509321e9a8aeSRichard Henderson op_cond = TCG_COND_ALWAYS; 509421e9a8aeSRichard Henderson break; 509521e9a8aeSRichard Henderson } 509621e9a8aeSRichard Henderson 5097501fb3daSRichard Henderson args_ct = opcode_args_ct(op); 5098501fb3daSRichard Henderson 5099c896fe29Sbellard /* satisfy input constraints */ 5100c896fe29Sbellard for (k = 0; k < nb_iargs; k++) { 510129f5e925SRichard Henderson TCGRegSet i_preferred_regs, i_required_regs; 510229f5e925SRichard Henderson bool allocate_new_reg, copyto_new_reg; 510329f5e925SRichard Henderson TCGTemp *ts2; 510429f5e925SRichard Henderson int i1, i2; 5105d62816f2SRichard Henderson 5106501fb3daSRichard Henderson i = args_ct[nb_oargs + k].sort_index; 5107dd186292SRichard Henderson arg = op->args[i]; 5108501fb3daSRichard Henderson arg_ct = &args_ct[i]; 510943439139SRichard Henderson ts = arg_temp(arg); 511040ae5c62SRichard Henderson 511140ae5c62SRichard Henderson if (ts->val_type == TEMP_VAL_CONST 511221e9a8aeSRichard Henderson && tcg_target_const_match(ts->val, arg_ct->ct, ts->type, 511321e9a8aeSRichard Henderson op_cond, TCGOP_VECE(op))) { 5114c896fe29Sbellard /* constant is OK for instruction */ 5115c896fe29Sbellard const_args[i] = 1; 5116c896fe29Sbellard new_args[i] = ts->val; 5117d62816f2SRichard Henderson continue; 5118c896fe29Sbellard } 511940ae5c62SRichard Henderson 51201c1824dcSRichard Henderson reg = ts->reg; 51211c1824dcSRichard Henderson i_preferred_regs = 0; 512229f5e925SRichard Henderson i_required_regs = arg_ct->regs; 51231c1824dcSRichard Henderson allocate_new_reg = false; 512429f5e925SRichard Henderson copyto_new_reg = false; 51251c1824dcSRichard Henderson 512629f5e925SRichard Henderson switch (arg_ct->pair) { 512729f5e925SRichard Henderson case 0: /* not paired */ 5128bc2b17e6SRichard Henderson if (arg_ct->ialias) { 512931fd884bSRichard Henderson i_preferred_regs = output_pref(op, arg_ct->alias_index); 5130c0522136SRichard Henderson 5131c0522136SRichard Henderson /* 5132c0522136SRichard Henderson * If the input is readonly, then it cannot also be an 5133c0522136SRichard Henderson * output and aliased to itself. If the input is not 5134c0522136SRichard Henderson * dead after the instruction, we must allocate a new 5135c0522136SRichard Henderson * register and move it. 5136c0522136SRichard Henderson */ 513722d2e535SIlya Leoshkevich if (temp_readonly(ts) || !IS_DEAD_ARG(i) 5138501fb3daSRichard Henderson || args_ct[arg_ct->alias_index].newreg) { 51391c1824dcSRichard Henderson allocate_new_reg = true; 51401c1824dcSRichard Henderson } else if (ts->val_type == TEMP_VAL_REG) { 5141c0522136SRichard Henderson /* 51421c1824dcSRichard Henderson * Check if the current register has already been 51431c1824dcSRichard Henderson * allocated for another input. 5144c0522136SRichard Henderson */ 514529f5e925SRichard Henderson allocate_new_reg = 514629f5e925SRichard Henderson tcg_regset_test_reg(i_allocated_regs, reg); 51477e1df267SAurelien Jarno } 51487e1df267SAurelien Jarno } 51491c1824dcSRichard Henderson if (!allocate_new_reg) { 515029f5e925SRichard Henderson temp_load(s, ts, i_required_regs, i_allocated_regs, 515129f5e925SRichard Henderson i_preferred_regs); 5152c896fe29Sbellard reg = ts->reg; 515329f5e925SRichard Henderson allocate_new_reg = !tcg_regset_test_reg(i_required_regs, reg); 51541c1824dcSRichard Henderson } 51551c1824dcSRichard Henderson if (allocate_new_reg) { 5156c0522136SRichard Henderson /* 5157c0522136SRichard Henderson * Allocate a new register matching the constraint 5158c0522136SRichard Henderson * and move the temporary register into it. 5159c0522136SRichard Henderson */ 5160d62816f2SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 5161d62816f2SRichard Henderson i_allocated_regs, 0); 516229f5e925SRichard Henderson reg = tcg_reg_alloc(s, i_required_regs, i_allocated_regs, 51631c1824dcSRichard Henderson i_preferred_regs, ts->indirect_base); 516429f5e925SRichard Henderson copyto_new_reg = true; 516529f5e925SRichard Henderson } 516629f5e925SRichard Henderson break; 516729f5e925SRichard Henderson 516829f5e925SRichard Henderson case 1: 516929f5e925SRichard Henderson /* First of an input pair; if i1 == i2, the second is an output. */ 517029f5e925SRichard Henderson i1 = i; 517129f5e925SRichard Henderson i2 = arg_ct->pair_index; 517229f5e925SRichard Henderson ts2 = i1 != i2 ? arg_temp(op->args[i2]) : NULL; 517329f5e925SRichard Henderson 517429f5e925SRichard Henderson /* 517529f5e925SRichard Henderson * It is easier to default to allocating a new pair 517629f5e925SRichard Henderson * and to identify a few cases where it's not required. 517729f5e925SRichard Henderson */ 517829f5e925SRichard Henderson if (arg_ct->ialias) { 517931fd884bSRichard Henderson i_preferred_regs = output_pref(op, arg_ct->alias_index); 518029f5e925SRichard Henderson if (IS_DEAD_ARG(i1) && 518129f5e925SRichard Henderson IS_DEAD_ARG(i2) && 518229f5e925SRichard Henderson !temp_readonly(ts) && 518329f5e925SRichard Henderson ts->val_type == TEMP_VAL_REG && 518429f5e925SRichard Henderson ts->reg < TCG_TARGET_NB_REGS - 1 && 518529f5e925SRichard Henderson tcg_regset_test_reg(i_required_regs, reg) && 518629f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg) && 518729f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg + 1) && 518829f5e925SRichard Henderson (ts2 518929f5e925SRichard Henderson ? ts2->val_type == TEMP_VAL_REG && 519029f5e925SRichard Henderson ts2->reg == reg + 1 && 519129f5e925SRichard Henderson !temp_readonly(ts2) 519229f5e925SRichard Henderson : s->reg_to_temp[reg + 1] == NULL)) { 519329f5e925SRichard Henderson break; 519429f5e925SRichard Henderson } 519529f5e925SRichard Henderson } else { 519629f5e925SRichard Henderson /* Without aliasing, the pair must also be an input. */ 519729f5e925SRichard Henderson tcg_debug_assert(ts2); 519829f5e925SRichard Henderson if (ts->val_type == TEMP_VAL_REG && 519929f5e925SRichard Henderson ts2->val_type == TEMP_VAL_REG && 520029f5e925SRichard Henderson ts2->reg == reg + 1 && 520129f5e925SRichard Henderson tcg_regset_test_reg(i_required_regs, reg)) { 520229f5e925SRichard Henderson break; 520329f5e925SRichard Henderson } 520429f5e925SRichard Henderson } 520529f5e925SRichard Henderson reg = tcg_reg_alloc_pair(s, i_required_regs, i_allocated_regs, 520629f5e925SRichard Henderson 0, ts->indirect_base); 520729f5e925SRichard Henderson goto do_pair; 520829f5e925SRichard Henderson 520929f5e925SRichard Henderson case 2: /* pair second */ 521029f5e925SRichard Henderson reg = new_args[arg_ct->pair_index] + 1; 521129f5e925SRichard Henderson goto do_pair; 521229f5e925SRichard Henderson 521329f5e925SRichard Henderson case 3: /* ialias with second output, no first input */ 521429f5e925SRichard Henderson tcg_debug_assert(arg_ct->ialias); 521531fd884bSRichard Henderson i_preferred_regs = output_pref(op, arg_ct->alias_index); 521629f5e925SRichard Henderson 521729f5e925SRichard Henderson if (IS_DEAD_ARG(i) && 521829f5e925SRichard Henderson !temp_readonly(ts) && 521929f5e925SRichard Henderson ts->val_type == TEMP_VAL_REG && 522029f5e925SRichard Henderson reg > 0 && 522129f5e925SRichard Henderson s->reg_to_temp[reg - 1] == NULL && 522229f5e925SRichard Henderson tcg_regset_test_reg(i_required_regs, reg) && 522329f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg) && 522429f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg - 1)) { 522529f5e925SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg - 1); 522629f5e925SRichard Henderson break; 522729f5e925SRichard Henderson } 522829f5e925SRichard Henderson reg = tcg_reg_alloc_pair(s, i_required_regs >> 1, 522929f5e925SRichard Henderson i_allocated_regs, 0, 523029f5e925SRichard Henderson ts->indirect_base); 523129f5e925SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg); 523229f5e925SRichard Henderson reg += 1; 523329f5e925SRichard Henderson goto do_pair; 523429f5e925SRichard Henderson 523529f5e925SRichard Henderson do_pair: 523629f5e925SRichard Henderson /* 523729f5e925SRichard Henderson * If an aliased input is not dead after the instruction, 523829f5e925SRichard Henderson * we must allocate a new register and move it. 523929f5e925SRichard Henderson */ 524029f5e925SRichard Henderson if (arg_ct->ialias && (!IS_DEAD_ARG(i) || temp_readonly(ts))) { 524129f5e925SRichard Henderson TCGRegSet t_allocated_regs = i_allocated_regs; 524229f5e925SRichard Henderson 524329f5e925SRichard Henderson /* 524429f5e925SRichard Henderson * Because of the alias, and the continued life, make sure 524529f5e925SRichard Henderson * that the temp is somewhere *other* than the reg pair, 524629f5e925SRichard Henderson * and we get a copy in reg. 524729f5e925SRichard Henderson */ 524829f5e925SRichard Henderson tcg_regset_set_reg(t_allocated_regs, reg); 524929f5e925SRichard Henderson tcg_regset_set_reg(t_allocated_regs, reg + 1); 525029f5e925SRichard Henderson if (ts->val_type == TEMP_VAL_REG && ts->reg == reg) { 525129f5e925SRichard Henderson /* If ts was already in reg, copy it somewhere else. */ 525229f5e925SRichard Henderson TCGReg nr; 525329f5e925SRichard Henderson bool ok; 525429f5e925SRichard Henderson 525529f5e925SRichard Henderson tcg_debug_assert(ts->kind != TEMP_FIXED); 525629f5e925SRichard Henderson nr = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], 525729f5e925SRichard Henderson t_allocated_regs, 0, ts->indirect_base); 525829f5e925SRichard Henderson ok = tcg_out_mov(s, ts->type, nr, reg); 525929f5e925SRichard Henderson tcg_debug_assert(ok); 526029f5e925SRichard Henderson 526129f5e925SRichard Henderson set_temp_val_reg(s, ts, nr); 526229f5e925SRichard Henderson } else { 526329f5e925SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 526429f5e925SRichard Henderson t_allocated_regs, 0); 526529f5e925SRichard Henderson copyto_new_reg = true; 526629f5e925SRichard Henderson } 526729f5e925SRichard Henderson } else { 526829f5e925SRichard Henderson /* Preferably allocate to reg, otherwise copy. */ 526929f5e925SRichard Henderson i_required_regs = (TCGRegSet)1 << reg; 527029f5e925SRichard Henderson temp_load(s, ts, i_required_regs, i_allocated_regs, 527129f5e925SRichard Henderson i_preferred_regs); 527229f5e925SRichard Henderson copyto_new_reg = ts->reg != reg; 527329f5e925SRichard Henderson } 527429f5e925SRichard Henderson break; 527529f5e925SRichard Henderson 527629f5e925SRichard Henderson default: 527729f5e925SRichard Henderson g_assert_not_reached(); 527829f5e925SRichard Henderson } 527929f5e925SRichard Henderson 528029f5e925SRichard Henderson if (copyto_new_reg) { 528178113e83SRichard Henderson if (!tcg_out_mov(s, ts->type, reg, ts->reg)) { 5282240c08d0SRichard Henderson /* 5283240c08d0SRichard Henderson * Cross register class move not supported. Sync the 5284240c08d0SRichard Henderson * temp back to its slot and load from there. 5285240c08d0SRichard Henderson */ 5286240c08d0SRichard Henderson temp_sync(s, ts, i_allocated_regs, 0, 0); 5287240c08d0SRichard Henderson tcg_out_ld(s, ts->type, reg, 5288240c08d0SRichard Henderson ts->mem_base->reg, ts->mem_offset); 528978113e83SRichard Henderson } 5290c896fe29Sbellard } 5291c896fe29Sbellard new_args[i] = reg; 5292c896fe29Sbellard const_args[i] = 0; 529382790a87SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg); 5294c896fe29Sbellard } 5295c896fe29Sbellard 5296c896fe29Sbellard /* mark dead temporaries and free the associated registers */ 5297866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 5298866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) { 529943439139SRichard Henderson temp_dead(s, arg_temp(op->args[i])); 5300c896fe29Sbellard } 5301c896fe29Sbellard } 5302c896fe29Sbellard 5303b4cb76e6SRichard Henderson if (def->flags & TCG_OPF_COND_BRANCH) { 5304b4cb76e6SRichard Henderson tcg_reg_alloc_cbranch(s, i_allocated_regs); 5305b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 530682790a87SRichard Henderson tcg_reg_alloc_bb_end(s, i_allocated_regs); 5307a52ad07eSAurelien Jarno } else { 5308c896fe29Sbellard if (def->flags & TCG_OPF_CALL_CLOBBER) { 5309b03cce8eSbellard /* XXX: permit generic clobber register list ? */ 5310c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) { 5311c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { 531282790a87SRichard Henderson tcg_reg_free(s, i, i_allocated_regs); 5313c896fe29Sbellard } 5314c896fe29Sbellard } 53153d5c5f87SAurelien Jarno } 53163d5c5f87SAurelien Jarno if (def->flags & TCG_OPF_SIDE_EFFECTS) { 53173d5c5f87SAurelien Jarno /* sync globals if the op has side effects and might trigger 53183d5c5f87SAurelien Jarno an exception. */ 531982790a87SRichard Henderson sync_globals(s, i_allocated_regs); 5320c896fe29Sbellard } 5321c896fe29Sbellard 5322c896fe29Sbellard /* satisfy the output constraints */ 5323c896fe29Sbellard for (k = 0; k < nb_oargs; k++) { 5324501fb3daSRichard Henderson i = args_ct[k].sort_index; 5325dd186292SRichard Henderson arg = op->args[i]; 5326501fb3daSRichard Henderson arg_ct = &args_ct[i]; 532743439139SRichard Henderson ts = arg_temp(arg); 5328d63e3b6eSRichard Henderson 5329d63e3b6eSRichard Henderson /* ENV should not be modified. */ 5330e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ts)); 5331d63e3b6eSRichard Henderson 533229f5e925SRichard Henderson switch (arg_ct->pair) { 533329f5e925SRichard Henderson case 0: /* not paired */ 5334bc2b17e6SRichard Henderson if (arg_ct->oalias && !const_args[arg_ct->alias_index]) { 53355ff9d6a4Sbellard reg = new_args[arg_ct->alias_index]; 5336bc2b17e6SRichard Henderson } else if (arg_ct->newreg) { 53379be0d080SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->regs, 533882790a87SRichard Henderson i_allocated_regs | o_allocated_regs, 533931fd884bSRichard Henderson output_pref(op, k), ts->indirect_base); 5340c896fe29Sbellard } else { 53419be0d080SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs, 534231fd884bSRichard Henderson output_pref(op, k), ts->indirect_base); 5343c896fe29Sbellard } 534429f5e925SRichard Henderson break; 534529f5e925SRichard Henderson 534629f5e925SRichard Henderson case 1: /* first of pair */ 534729f5e925SRichard Henderson if (arg_ct->oalias) { 534829f5e925SRichard Henderson reg = new_args[arg_ct->alias_index]; 5349ca5bed07SRichard Henderson } else if (arg_ct->newreg) { 5350ca5bed07SRichard Henderson reg = tcg_reg_alloc_pair(s, arg_ct->regs, 5351ca5bed07SRichard Henderson i_allocated_regs | o_allocated_regs, 5352ca5bed07SRichard Henderson output_pref(op, k), 5353ca5bed07SRichard Henderson ts->indirect_base); 5354ca5bed07SRichard Henderson } else { 535529f5e925SRichard Henderson reg = tcg_reg_alloc_pair(s, arg_ct->regs, o_allocated_regs, 5356ca5bed07SRichard Henderson output_pref(op, k), 5357ca5bed07SRichard Henderson ts->indirect_base); 5358ca5bed07SRichard Henderson } 535929f5e925SRichard Henderson break; 536029f5e925SRichard Henderson 536129f5e925SRichard Henderson case 2: /* second of pair */ 536229f5e925SRichard Henderson if (arg_ct->oalias) { 536329f5e925SRichard Henderson reg = new_args[arg_ct->alias_index]; 536429f5e925SRichard Henderson } else { 536529f5e925SRichard Henderson reg = new_args[arg_ct->pair_index] + 1; 536629f5e925SRichard Henderson } 536729f5e925SRichard Henderson break; 536829f5e925SRichard Henderson 536929f5e925SRichard Henderson case 3: /* first of pair, aliasing with a second input */ 537029f5e925SRichard Henderson tcg_debug_assert(!arg_ct->newreg); 537129f5e925SRichard Henderson reg = new_args[arg_ct->pair_index] - 1; 537229f5e925SRichard Henderson break; 537329f5e925SRichard Henderson 537429f5e925SRichard Henderson default: 537529f5e925SRichard Henderson g_assert_not_reached(); 537629f5e925SRichard Henderson } 537782790a87SRichard Henderson tcg_regset_set_reg(o_allocated_regs, reg); 5378098859f1SRichard Henderson set_temp_val_reg(s, ts, reg); 5379c896fe29Sbellard ts->mem_coherent = 0; 5380c896fe29Sbellard new_args[i] = reg; 5381c896fe29Sbellard } 5382e8996ee0Sbellard } 5383c896fe29Sbellard 5384c896fe29Sbellard /* emit instruction */ 5385678155b2SRichard Henderson switch (op->opc) { 5386678155b2SRichard Henderson case INDEX_op_ext8s_i32: 5387678155b2SRichard Henderson tcg_out_ext8s(s, TCG_TYPE_I32, new_args[0], new_args[1]); 5388678155b2SRichard Henderson break; 5389678155b2SRichard Henderson case INDEX_op_ext8s_i64: 5390678155b2SRichard Henderson tcg_out_ext8s(s, TCG_TYPE_I64, new_args[0], new_args[1]); 5391678155b2SRichard Henderson break; 5392d0e66c89SRichard Henderson case INDEX_op_ext8u_i32: 5393d0e66c89SRichard Henderson case INDEX_op_ext8u_i64: 5394d0e66c89SRichard Henderson tcg_out_ext8u(s, new_args[0], new_args[1]); 5395d0e66c89SRichard Henderson break; 5396753e42eaSRichard Henderson case INDEX_op_ext16s_i32: 5397753e42eaSRichard Henderson tcg_out_ext16s(s, TCG_TYPE_I32, new_args[0], new_args[1]); 5398753e42eaSRichard Henderson break; 5399753e42eaSRichard Henderson case INDEX_op_ext16s_i64: 5400753e42eaSRichard Henderson tcg_out_ext16s(s, TCG_TYPE_I64, new_args[0], new_args[1]); 5401753e42eaSRichard Henderson break; 5402379afdffSRichard Henderson case INDEX_op_ext16u_i32: 5403379afdffSRichard Henderson case INDEX_op_ext16u_i64: 5404379afdffSRichard Henderson tcg_out_ext16u(s, new_args[0], new_args[1]); 5405379afdffSRichard Henderson break; 540652bf3398SRichard Henderson case INDEX_op_ext32s_i64: 540752bf3398SRichard Henderson tcg_out_ext32s(s, new_args[0], new_args[1]); 540852bf3398SRichard Henderson break; 54099ecf5f61SRichard Henderson case INDEX_op_ext32u_i64: 54109ecf5f61SRichard Henderson tcg_out_ext32u(s, new_args[0], new_args[1]); 54119ecf5f61SRichard Henderson break; 54129c6aa274SRichard Henderson case INDEX_op_ext_i32_i64: 54139c6aa274SRichard Henderson tcg_out_exts_i32_i64(s, new_args[0], new_args[1]); 54149c6aa274SRichard Henderson break; 5415b9bfe000SRichard Henderson case INDEX_op_extu_i32_i64: 5416b9bfe000SRichard Henderson tcg_out_extu_i32_i64(s, new_args[0], new_args[1]); 5417b9bfe000SRichard Henderson break; 5418b8b94ac6SRichard Henderson case INDEX_op_extrl_i64_i32: 5419b8b94ac6SRichard Henderson tcg_out_extrl_i64_i32(s, new_args[0], new_args[1]); 5420b8b94ac6SRichard Henderson break; 5421678155b2SRichard Henderson default: 5422d2fd745fSRichard Henderson if (def->flags & TCG_OPF_VECTOR) { 54234d872218SRichard Henderson tcg_out_vec_op(s, op->opc, TCGOP_TYPE(op) - TCG_TYPE_V64, 54244d872218SRichard Henderson TCGOP_VECE(op), new_args, const_args); 5425d2fd745fSRichard Henderson } else { 5426*4e350091SRichard Henderson tcg_out_op(s, op->opc, TCGOP_TYPE(op), new_args, const_args); 5427d2fd745fSRichard Henderson } 5428678155b2SRichard Henderson break; 5429678155b2SRichard Henderson } 5430c896fe29Sbellard 5431c896fe29Sbellard /* move the outputs in the correct register if needed */ 5432c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 543343439139SRichard Henderson ts = arg_temp(op->args[i]); 5434d63e3b6eSRichard Henderson 5435d63e3b6eSRichard Henderson /* ENV should not be modified. */ 5436e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ts)); 5437d63e3b6eSRichard Henderson 5438ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) { 543998b4e186SRichard Henderson temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i)); 544059d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) { 5441f8bf00f1SRichard Henderson temp_dead(s, ts); 5442ec7a869dSAurelien Jarno } 5443c896fe29Sbellard } 5444c896fe29Sbellard } 5445c896fe29Sbellard 5446efe86b21SRichard Henderson static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op) 5447efe86b21SRichard Henderson { 5448efe86b21SRichard Henderson const TCGLifeData arg_life = op->life; 5449efe86b21SRichard Henderson TCGTemp *ots, *itsl, *itsh; 54504d872218SRichard Henderson TCGType vtype = TCGOP_TYPE(op); 5451efe86b21SRichard Henderson 5452efe86b21SRichard Henderson /* This opcode is only valid for 32-bit hosts, for 64-bit elements. */ 5453efe86b21SRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 32); 5454efe86b21SRichard Henderson tcg_debug_assert(TCGOP_VECE(op) == MO_64); 5455efe86b21SRichard Henderson 5456efe86b21SRichard Henderson ots = arg_temp(op->args[0]); 5457efe86b21SRichard Henderson itsl = arg_temp(op->args[1]); 5458efe86b21SRichard Henderson itsh = arg_temp(op->args[2]); 5459efe86b21SRichard Henderson 5460efe86b21SRichard Henderson /* ENV should not be modified. */ 5461efe86b21SRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 5462efe86b21SRichard Henderson 5463efe86b21SRichard Henderson /* Allocate the output register now. */ 5464efe86b21SRichard Henderson if (ots->val_type != TEMP_VAL_REG) { 5465efe86b21SRichard Henderson TCGRegSet allocated_regs = s->reserved_regs; 5466501fb3daSRichard Henderson TCGRegSet dup_out_regs = opcode_args_ct(op)[0].regs; 5467098859f1SRichard Henderson TCGReg oreg; 5468efe86b21SRichard Henderson 5469efe86b21SRichard Henderson /* Make sure to not spill the input registers. */ 5470efe86b21SRichard Henderson if (!IS_DEAD_ARG(1) && itsl->val_type == TEMP_VAL_REG) { 5471efe86b21SRichard Henderson tcg_regset_set_reg(allocated_regs, itsl->reg); 5472efe86b21SRichard Henderson } 5473efe86b21SRichard Henderson if (!IS_DEAD_ARG(2) && itsh->val_type == TEMP_VAL_REG) { 5474efe86b21SRichard Henderson tcg_regset_set_reg(allocated_regs, itsh->reg); 5475efe86b21SRichard Henderson } 5476efe86b21SRichard Henderson 5477098859f1SRichard Henderson oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs, 547831fd884bSRichard Henderson output_pref(op, 0), ots->indirect_base); 5479098859f1SRichard Henderson set_temp_val_reg(s, ots, oreg); 5480efe86b21SRichard Henderson } 5481efe86b21SRichard Henderson 5482efe86b21SRichard Henderson /* Promote dup2 of immediates to dupi_vec. */ 5483efe86b21SRichard Henderson if (itsl->val_type == TEMP_VAL_CONST && itsh->val_type == TEMP_VAL_CONST) { 5484efe86b21SRichard Henderson uint64_t val = deposit64(itsl->val, 32, 32, itsh->val); 5485efe86b21SRichard Henderson MemOp vece = MO_64; 5486efe86b21SRichard Henderson 5487efe86b21SRichard Henderson if (val == dup_const(MO_8, val)) { 5488efe86b21SRichard Henderson vece = MO_8; 5489efe86b21SRichard Henderson } else if (val == dup_const(MO_16, val)) { 5490efe86b21SRichard Henderson vece = MO_16; 5491efe86b21SRichard Henderson } else if (val == dup_const(MO_32, val)) { 5492efe86b21SRichard Henderson vece = MO_32; 5493efe86b21SRichard Henderson } 5494efe86b21SRichard Henderson 5495efe86b21SRichard Henderson tcg_out_dupi_vec(s, vtype, vece, ots->reg, val); 5496efe86b21SRichard Henderson goto done; 5497efe86b21SRichard Henderson } 5498efe86b21SRichard Henderson 5499efe86b21SRichard Henderson /* If the two inputs form one 64-bit value, try dupm_vec. */ 5500aef85402SRichard Henderson if (itsl->temp_subindex == HOST_BIG_ENDIAN && 5501aef85402SRichard Henderson itsh->temp_subindex == !HOST_BIG_ENDIAN && 5502aef85402SRichard Henderson itsl == itsh + (HOST_BIG_ENDIAN ? 1 : -1)) { 5503aef85402SRichard Henderson TCGTemp *its = itsl - HOST_BIG_ENDIAN; 5504aef85402SRichard Henderson 5505aef85402SRichard Henderson temp_sync(s, its + 0, s->reserved_regs, 0, 0); 5506aef85402SRichard Henderson temp_sync(s, its + 1, s->reserved_regs, 0, 0); 5507aef85402SRichard Henderson 5508efe86b21SRichard Henderson if (tcg_out_dupm_vec(s, vtype, MO_64, ots->reg, 5509efe86b21SRichard Henderson its->mem_base->reg, its->mem_offset)) { 5510efe86b21SRichard Henderson goto done; 5511efe86b21SRichard Henderson } 5512efe86b21SRichard Henderson } 5513efe86b21SRichard Henderson 5514efe86b21SRichard Henderson /* Fall back to generic expansion. */ 5515efe86b21SRichard Henderson return false; 5516efe86b21SRichard Henderson 5517efe86b21SRichard Henderson done: 551836f5539cSRichard Henderson ots->mem_coherent = 0; 5519efe86b21SRichard Henderson if (IS_DEAD_ARG(1)) { 5520efe86b21SRichard Henderson temp_dead(s, itsl); 5521efe86b21SRichard Henderson } 5522efe86b21SRichard Henderson if (IS_DEAD_ARG(2)) { 5523efe86b21SRichard Henderson temp_dead(s, itsh); 5524efe86b21SRichard Henderson } 5525efe86b21SRichard Henderson if (NEED_SYNC_ARG(0)) { 5526efe86b21SRichard Henderson temp_sync(s, ots, s->reserved_regs, 0, IS_DEAD_ARG(0)); 5527efe86b21SRichard Henderson } else if (IS_DEAD_ARG(0)) { 5528efe86b21SRichard Henderson temp_dead(s, ots); 5529efe86b21SRichard Henderson } 5530efe86b21SRichard Henderson return true; 5531efe86b21SRichard Henderson } 5532efe86b21SRichard Henderson 553339004a71SRichard Henderson static void load_arg_reg(TCGContext *s, TCGReg reg, TCGTemp *ts, 553439004a71SRichard Henderson TCGRegSet allocated_regs) 5535c896fe29Sbellard { 5536c896fe29Sbellard if (ts->val_type == TEMP_VAL_REG) { 5537c896fe29Sbellard if (ts->reg != reg) { 55384250da10SRichard Henderson tcg_reg_free(s, reg, allocated_regs); 553978113e83SRichard Henderson if (!tcg_out_mov(s, ts->type, reg, ts->reg)) { 5540240c08d0SRichard Henderson /* 5541240c08d0SRichard Henderson * Cross register class move not supported. Sync the 5542240c08d0SRichard Henderson * temp back to its slot and load from there. 5543240c08d0SRichard Henderson */ 5544240c08d0SRichard Henderson temp_sync(s, ts, allocated_regs, 0, 0); 5545240c08d0SRichard Henderson tcg_out_ld(s, ts->type, reg, 5546240c08d0SRichard Henderson ts->mem_base->reg, ts->mem_offset); 554778113e83SRichard Henderson } 5548c896fe29Sbellard } 5549c896fe29Sbellard } else { 5550ccb1bb66SRichard Henderson TCGRegSet arg_set = 0; 555140ae5c62SRichard Henderson 55524250da10SRichard Henderson tcg_reg_free(s, reg, allocated_regs); 555340ae5c62SRichard Henderson tcg_regset_set_reg(arg_set, reg); 5554b722452aSRichard Henderson temp_load(s, ts, arg_set, allocated_regs, 0); 5555c896fe29Sbellard } 555639004a71SRichard Henderson } 555740ae5c62SRichard Henderson 5558d78e4a4fSRichard Henderson static void load_arg_stk(TCGContext *s, unsigned arg_slot, TCGTemp *ts, 555939004a71SRichard Henderson TCGRegSet allocated_regs) 556039004a71SRichard Henderson { 556139004a71SRichard Henderson /* 556239004a71SRichard Henderson * When the destination is on the stack, load up the temp and store. 556339004a71SRichard Henderson * If there are many call-saved registers, the temp might live to 556439004a71SRichard Henderson * see another use; otherwise it'll be discarded. 556539004a71SRichard Henderson */ 556639004a71SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], allocated_regs, 0); 556739004a71SRichard Henderson tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, 5568d78e4a4fSRichard Henderson arg_slot_stk_ofs(arg_slot)); 556939004a71SRichard Henderson } 557039004a71SRichard Henderson 557139004a71SRichard Henderson static void load_arg_normal(TCGContext *s, const TCGCallArgumentLoc *l, 557239004a71SRichard Henderson TCGTemp *ts, TCGRegSet *allocated_regs) 557339004a71SRichard Henderson { 5574338b61e9SRichard Henderson if (arg_slot_reg_p(l->arg_slot)) { 557539004a71SRichard Henderson TCGReg reg = tcg_target_call_iarg_regs[l->arg_slot]; 557639004a71SRichard Henderson load_arg_reg(s, reg, ts, *allocated_regs); 557739004a71SRichard Henderson tcg_regset_set_reg(*allocated_regs, reg); 557839004a71SRichard Henderson } else { 5579d78e4a4fSRichard Henderson load_arg_stk(s, l->arg_slot, ts, *allocated_regs); 5580c896fe29Sbellard } 558139cf05d3Sbellard } 5582c896fe29Sbellard 5583d78e4a4fSRichard Henderson static void load_arg_ref(TCGContext *s, unsigned arg_slot, TCGReg ref_base, 5584313bdea8SRichard Henderson intptr_t ref_off, TCGRegSet *allocated_regs) 5585313bdea8SRichard Henderson { 5586313bdea8SRichard Henderson TCGReg reg; 5587313bdea8SRichard Henderson 5588d78e4a4fSRichard Henderson if (arg_slot_reg_p(arg_slot)) { 5589313bdea8SRichard Henderson reg = tcg_target_call_iarg_regs[arg_slot]; 5590313bdea8SRichard Henderson tcg_reg_free(s, reg, *allocated_regs); 5591313bdea8SRichard Henderson tcg_out_addi_ptr(s, reg, ref_base, ref_off); 5592313bdea8SRichard Henderson tcg_regset_set_reg(*allocated_regs, reg); 5593313bdea8SRichard Henderson } else { 5594313bdea8SRichard Henderson reg = tcg_reg_alloc(s, tcg_target_available_regs[TCG_TYPE_PTR], 5595313bdea8SRichard Henderson *allocated_regs, 0, false); 5596313bdea8SRichard Henderson tcg_out_addi_ptr(s, reg, ref_base, ref_off); 5597313bdea8SRichard Henderson tcg_out_st(s, TCG_TYPE_PTR, reg, TCG_REG_CALL_STACK, 5598d78e4a4fSRichard Henderson arg_slot_stk_ofs(arg_slot)); 5599313bdea8SRichard Henderson } 5600313bdea8SRichard Henderson } 5601313bdea8SRichard Henderson 560239004a71SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op) 560339004a71SRichard Henderson { 560439004a71SRichard Henderson const int nb_oargs = TCGOP_CALLO(op); 560539004a71SRichard Henderson const int nb_iargs = TCGOP_CALLI(op); 560639004a71SRichard Henderson const TCGLifeData arg_life = op->life; 560739004a71SRichard Henderson const TCGHelperInfo *info = tcg_call_info(op); 560839004a71SRichard Henderson TCGRegSet allocated_regs = s->reserved_regs; 560939004a71SRichard Henderson int i; 561039004a71SRichard Henderson 561139004a71SRichard Henderson /* 561239004a71SRichard Henderson * Move inputs into place in reverse order, 561339004a71SRichard Henderson * so that we place stacked arguments first. 561439004a71SRichard Henderson */ 561539004a71SRichard Henderson for (i = nb_iargs - 1; i >= 0; --i) { 561639004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i]; 561739004a71SRichard Henderson TCGTemp *ts = arg_temp(op->args[nb_oargs + i]); 561839004a71SRichard Henderson 561939004a71SRichard Henderson switch (loc->kind) { 562039004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 562139004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 562239004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 562339004a71SRichard Henderson load_arg_normal(s, loc, ts, &allocated_regs); 562439004a71SRichard Henderson break; 5625313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF: 5626313bdea8SRichard Henderson load_arg_stk(s, loc->ref_slot, ts, allocated_regs); 5627313bdea8SRichard Henderson load_arg_ref(s, loc->arg_slot, TCG_REG_CALL_STACK, 5628d78e4a4fSRichard Henderson arg_slot_stk_ofs(loc->ref_slot), 5629313bdea8SRichard Henderson &allocated_regs); 5630313bdea8SRichard Henderson break; 5631313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF_N: 5632313bdea8SRichard Henderson load_arg_stk(s, loc->ref_slot, ts, allocated_regs); 5633313bdea8SRichard Henderson break; 563439004a71SRichard Henderson default: 563539004a71SRichard Henderson g_assert_not_reached(); 563639004a71SRichard Henderson } 563739004a71SRichard Henderson } 563839004a71SRichard Henderson 563939004a71SRichard Henderson /* Mark dead temporaries and free the associated registers. */ 5640866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 5641866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) { 564243439139SRichard Henderson temp_dead(s, arg_temp(op->args[i])); 5643c896fe29Sbellard } 5644c896fe29Sbellard } 5645c896fe29Sbellard 564639004a71SRichard Henderson /* Clobber call registers. */ 5647c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) { 5648c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { 5649b3915dbbSRichard Henderson tcg_reg_free(s, i, allocated_regs); 5650c896fe29Sbellard } 5651c896fe29Sbellard } 5652c896fe29Sbellard 565339004a71SRichard Henderson /* 565439004a71SRichard Henderson * Save globals if they might be written by the helper, 565539004a71SRichard Henderson * sync them if they might be read. 565639004a71SRichard Henderson */ 565739004a71SRichard Henderson if (info->flags & TCG_CALL_NO_READ_GLOBALS) { 565878505279SAurelien Jarno /* Nothing to do */ 565939004a71SRichard Henderson } else if (info->flags & TCG_CALL_NO_WRITE_GLOBALS) { 566078505279SAurelien Jarno sync_globals(s, allocated_regs); 566178505279SAurelien Jarno } else { 5662e8996ee0Sbellard save_globals(s, allocated_regs); 5663b9c18f56Saurel32 } 5664c896fe29Sbellard 5665313bdea8SRichard Henderson /* 5666313bdea8SRichard Henderson * If the ABI passes a pointer to the returned struct as the first 5667313bdea8SRichard Henderson * argument, load that now. Pass a pointer to the output home slot. 5668313bdea8SRichard Henderson */ 5669313bdea8SRichard Henderson if (info->out_kind == TCG_CALL_RET_BY_REF) { 5670313bdea8SRichard Henderson TCGTemp *ts = arg_temp(op->args[0]); 5671313bdea8SRichard Henderson 5672313bdea8SRichard Henderson if (!ts->mem_allocated) { 5673313bdea8SRichard Henderson temp_allocate_frame(s, ts); 5674313bdea8SRichard Henderson } 5675313bdea8SRichard Henderson load_arg_ref(s, 0, ts->mem_base->reg, ts->mem_offset, &allocated_regs); 5676313bdea8SRichard Henderson } 5677313bdea8SRichard Henderson 5678cee44b03SRichard Henderson tcg_out_call(s, tcg_call_func(op), info); 5679c896fe29Sbellard 568039004a71SRichard Henderson /* Assign output registers and emit moves if needed. */ 568139004a71SRichard Henderson switch (info->out_kind) { 568239004a71SRichard Henderson case TCG_CALL_RET_NORMAL: 5683c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 568439004a71SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]); 56855e3d0c19SRichard Henderson TCGReg reg = tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, i); 5686d63e3b6eSRichard Henderson 5687d63e3b6eSRichard Henderson /* ENV should not be modified. */ 5688e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ts)); 5689d63e3b6eSRichard Henderson 5690098859f1SRichard Henderson set_temp_val_reg(s, ts, reg); 5691c896fe29Sbellard ts->mem_coherent = 0; 569239004a71SRichard Henderson } 569339004a71SRichard Henderson break; 5694313bdea8SRichard Henderson 5695c6556aa0SRichard Henderson case TCG_CALL_RET_BY_VEC: 5696c6556aa0SRichard Henderson { 5697c6556aa0SRichard Henderson TCGTemp *ts = arg_temp(op->args[0]); 5698c6556aa0SRichard Henderson 5699c6556aa0SRichard Henderson tcg_debug_assert(ts->base_type == TCG_TYPE_I128); 5700c6556aa0SRichard Henderson tcg_debug_assert(ts->temp_subindex == 0); 5701c6556aa0SRichard Henderson if (!ts->mem_allocated) { 5702c6556aa0SRichard Henderson temp_allocate_frame(s, ts); 5703c6556aa0SRichard Henderson } 5704c6556aa0SRichard Henderson tcg_out_st(s, TCG_TYPE_V128, 5705c6556aa0SRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0), 5706c6556aa0SRichard Henderson ts->mem_base->reg, ts->mem_offset); 5707c6556aa0SRichard Henderson } 5708c6556aa0SRichard Henderson /* fall through to mark all parts in memory */ 5709c6556aa0SRichard Henderson 5710313bdea8SRichard Henderson case TCG_CALL_RET_BY_REF: 5711313bdea8SRichard Henderson /* The callee has performed a write through the reference. */ 5712313bdea8SRichard Henderson for (i = 0; i < nb_oargs; i++) { 5713313bdea8SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]); 5714313bdea8SRichard Henderson ts->val_type = TEMP_VAL_MEM; 5715313bdea8SRichard Henderson } 5716313bdea8SRichard Henderson break; 5717313bdea8SRichard Henderson 571839004a71SRichard Henderson default: 571939004a71SRichard Henderson g_assert_not_reached(); 572039004a71SRichard Henderson } 572139004a71SRichard Henderson 572239004a71SRichard Henderson /* Flush or discard output registers as needed. */ 572339004a71SRichard Henderson for (i = 0; i < nb_oargs; i++) { 572439004a71SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]); 5725ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) { 572639004a71SRichard Henderson temp_sync(s, ts, s->reserved_regs, 0, IS_DEAD_ARG(i)); 572759d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) { 5728f8bf00f1SRichard Henderson temp_dead(s, ts); 5729c896fe29Sbellard } 5730c896fe29Sbellard } 57318c11ad25SAurelien Jarno } 5732c896fe29Sbellard 5733e63b8a29SRichard Henderson /** 5734e63b8a29SRichard Henderson * atom_and_align_for_opc: 5735e63b8a29SRichard Henderson * @s: tcg context 5736e63b8a29SRichard Henderson * @opc: memory operation code 5737e63b8a29SRichard Henderson * @host_atom: MO_ATOM_{IFALIGN,WITHIN16,SUBALIGN} for host operations 5738e63b8a29SRichard Henderson * @allow_two_ops: true if we are prepared to issue two operations 5739e63b8a29SRichard Henderson * 5740e63b8a29SRichard Henderson * Return the alignment and atomicity to use for the inline fast path 5741e63b8a29SRichard Henderson * for the given memory operation. The alignment may be larger than 5742e63b8a29SRichard Henderson * that specified in @opc, and the correct alignment will be diagnosed 5743e63b8a29SRichard Henderson * by the slow path helper. 5744e63b8a29SRichard Henderson * 5745e63b8a29SRichard Henderson * If @allow_two_ops, the host is prepared to test for 2x alignment, 5746e63b8a29SRichard Henderson * and issue two loads or stores for subalignment. 5747e63b8a29SRichard Henderson */ 5748e63b8a29SRichard Henderson static TCGAtomAlign atom_and_align_for_opc(TCGContext *s, MemOp opc, 5749e63b8a29SRichard Henderson MemOp host_atom, bool allow_two_ops) 5750e63b8a29SRichard Henderson { 5751c5809eeeSRichard Henderson MemOp align = memop_alignment_bits(opc); 5752e63b8a29SRichard Henderson MemOp size = opc & MO_SIZE; 5753e63b8a29SRichard Henderson MemOp half = size ? size - 1 : 0; 5754cbb14556SRichard Henderson MemOp atom = opc & MO_ATOM_MASK; 5755e63b8a29SRichard Henderson MemOp atmax; 5756e63b8a29SRichard Henderson 5757e63b8a29SRichard Henderson switch (atom) { 5758e63b8a29SRichard Henderson case MO_ATOM_NONE: 5759e63b8a29SRichard Henderson /* The operation requires no specific atomicity. */ 5760e63b8a29SRichard Henderson atmax = MO_8; 5761e63b8a29SRichard Henderson break; 5762e63b8a29SRichard Henderson 5763e63b8a29SRichard Henderson case MO_ATOM_IFALIGN: 5764e63b8a29SRichard Henderson atmax = size; 5765e63b8a29SRichard Henderson break; 5766e63b8a29SRichard Henderson 5767e63b8a29SRichard Henderson case MO_ATOM_IFALIGN_PAIR: 5768e63b8a29SRichard Henderson atmax = half; 5769e63b8a29SRichard Henderson break; 5770e63b8a29SRichard Henderson 5771e63b8a29SRichard Henderson case MO_ATOM_WITHIN16: 5772e63b8a29SRichard Henderson atmax = size; 5773e63b8a29SRichard Henderson if (size == MO_128) { 5774e63b8a29SRichard Henderson /* Misalignment implies !within16, and therefore no atomicity. */ 5775e63b8a29SRichard Henderson } else if (host_atom != MO_ATOM_WITHIN16) { 5776e63b8a29SRichard Henderson /* The host does not implement within16, so require alignment. */ 5777e63b8a29SRichard Henderson align = MAX(align, size); 5778e63b8a29SRichard Henderson } 5779e63b8a29SRichard Henderson break; 5780e63b8a29SRichard Henderson 5781e63b8a29SRichard Henderson case MO_ATOM_WITHIN16_PAIR: 5782e63b8a29SRichard Henderson atmax = size; 5783e63b8a29SRichard Henderson /* 5784e63b8a29SRichard Henderson * Misalignment implies !within16, and therefore half atomicity. 5785e63b8a29SRichard Henderson * Any host prepared for two operations can implement this with 5786e63b8a29SRichard Henderson * half alignment. 5787e63b8a29SRichard Henderson */ 5788e63b8a29SRichard Henderson if (host_atom != MO_ATOM_WITHIN16 && allow_two_ops) { 5789e63b8a29SRichard Henderson align = MAX(align, half); 5790e63b8a29SRichard Henderson } 5791e63b8a29SRichard Henderson break; 5792e63b8a29SRichard Henderson 5793e63b8a29SRichard Henderson case MO_ATOM_SUBALIGN: 5794e63b8a29SRichard Henderson atmax = size; 5795e63b8a29SRichard Henderson if (host_atom != MO_ATOM_SUBALIGN) { 5796e63b8a29SRichard Henderson /* If unaligned but not odd, there are subobjects up to half. */ 5797e63b8a29SRichard Henderson if (allow_two_ops) { 5798e63b8a29SRichard Henderson align = MAX(align, half); 5799e63b8a29SRichard Henderson } else { 5800e63b8a29SRichard Henderson align = MAX(align, size); 5801e63b8a29SRichard Henderson } 5802e63b8a29SRichard Henderson } 5803e63b8a29SRichard Henderson break; 5804e63b8a29SRichard Henderson 5805e63b8a29SRichard Henderson default: 5806e63b8a29SRichard Henderson g_assert_not_reached(); 5807e63b8a29SRichard Henderson } 5808e63b8a29SRichard Henderson 5809e63b8a29SRichard Henderson return (TCGAtomAlign){ .atom = atmax, .align = align }; 5810e63b8a29SRichard Henderson } 5811e63b8a29SRichard Henderson 58128429a1caSRichard Henderson /* 58138429a1caSRichard Henderson * Similarly for qemu_ld/st slow path helpers. 58148429a1caSRichard Henderson * We must re-implement tcg_gen_callN and tcg_reg_alloc_call simultaneously, 58158429a1caSRichard Henderson * using only the provided backend tcg_out_* functions. 58168429a1caSRichard Henderson */ 58178429a1caSRichard Henderson 58188429a1caSRichard Henderson static int tcg_out_helper_stk_ofs(TCGType type, unsigned slot) 58198429a1caSRichard Henderson { 58208429a1caSRichard Henderson int ofs = arg_slot_stk_ofs(slot); 58218429a1caSRichard Henderson 58228429a1caSRichard Henderson /* 58238429a1caSRichard Henderson * Each stack slot is TCG_TARGET_LONG_BITS. If the host does not 58248429a1caSRichard Henderson * require extension to uint64_t, adjust the address for uint32_t. 58258429a1caSRichard Henderson */ 58268429a1caSRichard Henderson if (HOST_BIG_ENDIAN && 58278429a1caSRichard Henderson TCG_TARGET_REG_BITS == 64 && 58288429a1caSRichard Henderson type == TCG_TYPE_I32) { 58298429a1caSRichard Henderson ofs += 4; 58308429a1caSRichard Henderson } 58318429a1caSRichard Henderson return ofs; 58328429a1caSRichard Henderson } 58338429a1caSRichard Henderson 58348d314041SRichard Henderson static void tcg_out_helper_load_slots(TCGContext *s, 58358429a1caSRichard Henderson unsigned nmov, TCGMovExtend *mov, 58362462e30eSRichard Henderson const TCGLdstHelperParam *parm) 58378429a1caSRichard Henderson { 58388d314041SRichard Henderson unsigned i; 58392462e30eSRichard Henderson TCGReg dst3; 58402462e30eSRichard Henderson 58418d314041SRichard Henderson /* 58428d314041SRichard Henderson * Start from the end, storing to the stack first. 58438d314041SRichard Henderson * This frees those registers, so we need not consider overlap. 58448d314041SRichard Henderson */ 58458d314041SRichard Henderson for (i = nmov; i-- > 0; ) { 58468d314041SRichard Henderson unsigned slot = mov[i].dst; 58478d314041SRichard Henderson 58488d314041SRichard Henderson if (arg_slot_reg_p(slot)) { 58498d314041SRichard Henderson goto found_reg; 58508d314041SRichard Henderson } 58518d314041SRichard Henderson 58528d314041SRichard Henderson TCGReg src = mov[i].src; 58538d314041SRichard Henderson TCGType dst_type = mov[i].dst_type; 58548d314041SRichard Henderson MemOp dst_mo = dst_type == TCG_TYPE_I32 ? MO_32 : MO_64; 58558d314041SRichard Henderson 58568d314041SRichard Henderson /* The argument is going onto the stack; extend into scratch. */ 58578d314041SRichard Henderson if ((mov[i].src_ext & MO_SIZE) != dst_mo) { 58588d314041SRichard Henderson tcg_debug_assert(parm->ntmp != 0); 58598d314041SRichard Henderson mov[i].dst = src = parm->tmp[0]; 58608d314041SRichard Henderson tcg_out_movext1(s, &mov[i]); 58618d314041SRichard Henderson } 58628d314041SRichard Henderson 58638d314041SRichard Henderson tcg_out_st(s, dst_type, src, TCG_REG_CALL_STACK, 58648d314041SRichard Henderson tcg_out_helper_stk_ofs(dst_type, slot)); 58658d314041SRichard Henderson } 58668d314041SRichard Henderson return; 58678d314041SRichard Henderson 58688d314041SRichard Henderson found_reg: 58698d314041SRichard Henderson /* 58708d314041SRichard Henderson * The remaining arguments are in registers. 58718d314041SRichard Henderson * Convert slot numbers to argument registers. 58728d314041SRichard Henderson */ 58738d314041SRichard Henderson nmov = i + 1; 58748d314041SRichard Henderson for (i = 0; i < nmov; ++i) { 58758d314041SRichard Henderson mov[i].dst = tcg_target_call_iarg_regs[mov[i].dst]; 58768d314041SRichard Henderson } 58778d314041SRichard Henderson 58788429a1caSRichard Henderson switch (nmov) { 58792462e30eSRichard Henderson case 4: 58808429a1caSRichard Henderson /* The backend must have provided enough temps for the worst case. */ 58812462e30eSRichard Henderson tcg_debug_assert(parm->ntmp >= 2); 58828429a1caSRichard Henderson 58832462e30eSRichard Henderson dst3 = mov[3].dst; 58842462e30eSRichard Henderson for (unsigned j = 0; j < 3; ++j) { 58852462e30eSRichard Henderson if (dst3 == mov[j].src) { 58868429a1caSRichard Henderson /* 58872462e30eSRichard Henderson * Conflict. Copy the source to a temporary, perform the 58882462e30eSRichard Henderson * remaining moves, then the extension from our scratch 58892462e30eSRichard Henderson * on the way out. 58908429a1caSRichard Henderson */ 58912462e30eSRichard Henderson TCGReg scratch = parm->tmp[1]; 58928429a1caSRichard Henderson 58932462e30eSRichard Henderson tcg_out_mov(s, mov[3].src_type, scratch, mov[3].src); 58942462e30eSRichard Henderson tcg_out_movext3(s, mov, mov + 1, mov + 2, parm->tmp[0]); 58952462e30eSRichard Henderson tcg_out_movext1_new_src(s, &mov[3], scratch); 58962462e30eSRichard Henderson break; 58978429a1caSRichard Henderson } 58988429a1caSRichard Henderson } 58998429a1caSRichard Henderson 59008429a1caSRichard Henderson /* No conflicts: perform this move and continue. */ 59012462e30eSRichard Henderson tcg_out_movext1(s, &mov[3]); 59022462e30eSRichard Henderson /* fall through */ 59038429a1caSRichard Henderson 59042462e30eSRichard Henderson case 3: 59052462e30eSRichard Henderson tcg_out_movext3(s, mov, mov + 1, mov + 2, 59062462e30eSRichard Henderson parm->ntmp ? parm->tmp[0] : -1); 59072462e30eSRichard Henderson break; 59088429a1caSRichard Henderson case 2: 59092462e30eSRichard Henderson tcg_out_movext2(s, mov, mov + 1, 59102462e30eSRichard Henderson parm->ntmp ? parm->tmp[0] : -1); 59112462e30eSRichard Henderson break; 59128429a1caSRichard Henderson case 1: 59138429a1caSRichard Henderson tcg_out_movext1(s, mov); 59142462e30eSRichard Henderson break; 59152462e30eSRichard Henderson default: 59168429a1caSRichard Henderson g_assert_not_reached(); 59178429a1caSRichard Henderson } 59188429a1caSRichard Henderson } 59198429a1caSRichard Henderson 59208429a1caSRichard Henderson static void tcg_out_helper_load_imm(TCGContext *s, unsigned slot, 59218429a1caSRichard Henderson TCGType type, tcg_target_long imm, 59228429a1caSRichard Henderson const TCGLdstHelperParam *parm) 59238429a1caSRichard Henderson { 59248429a1caSRichard Henderson if (arg_slot_reg_p(slot)) { 59258429a1caSRichard Henderson tcg_out_movi(s, type, tcg_target_call_iarg_regs[slot], imm); 59268429a1caSRichard Henderson } else { 59278429a1caSRichard Henderson int ofs = tcg_out_helper_stk_ofs(type, slot); 59288429a1caSRichard Henderson if (!tcg_out_sti(s, type, imm, TCG_REG_CALL_STACK, ofs)) { 59298429a1caSRichard Henderson tcg_debug_assert(parm->ntmp != 0); 59308429a1caSRichard Henderson tcg_out_movi(s, type, parm->tmp[0], imm); 59318429a1caSRichard Henderson tcg_out_st(s, type, parm->tmp[0], TCG_REG_CALL_STACK, ofs); 59328429a1caSRichard Henderson } 59338429a1caSRichard Henderson } 59348429a1caSRichard Henderson } 59358429a1caSRichard Henderson 59368429a1caSRichard Henderson static void tcg_out_helper_load_common_args(TCGContext *s, 59378429a1caSRichard Henderson const TCGLabelQemuLdst *ldst, 59388429a1caSRichard Henderson const TCGLdstHelperParam *parm, 59398429a1caSRichard Henderson const TCGHelperInfo *info, 59408429a1caSRichard Henderson unsigned next_arg) 59418429a1caSRichard Henderson { 59428429a1caSRichard Henderson TCGMovExtend ptr_mov = { 59438429a1caSRichard Henderson .dst_type = TCG_TYPE_PTR, 59448429a1caSRichard Henderson .src_type = TCG_TYPE_PTR, 59458429a1caSRichard Henderson .src_ext = sizeof(void *) == 4 ? MO_32 : MO_64 59468429a1caSRichard Henderson }; 59478429a1caSRichard Henderson const TCGCallArgumentLoc *loc = &info->in[0]; 59488429a1caSRichard Henderson TCGType type; 59498429a1caSRichard Henderson unsigned slot; 59508429a1caSRichard Henderson tcg_target_ulong imm; 59518429a1caSRichard Henderson 59528429a1caSRichard Henderson /* 59538429a1caSRichard Henderson * Handle env, which is always first. 59548429a1caSRichard Henderson */ 59558429a1caSRichard Henderson ptr_mov.dst = loc->arg_slot; 59568429a1caSRichard Henderson ptr_mov.src = TCG_AREG0; 59578429a1caSRichard Henderson tcg_out_helper_load_slots(s, 1, &ptr_mov, parm); 59588429a1caSRichard Henderson 59598429a1caSRichard Henderson /* 59608429a1caSRichard Henderson * Handle oi. 59618429a1caSRichard Henderson */ 59628429a1caSRichard Henderson imm = ldst->oi; 59638429a1caSRichard Henderson loc = &info->in[next_arg]; 59648429a1caSRichard Henderson type = TCG_TYPE_I32; 59658429a1caSRichard Henderson switch (loc->kind) { 59668429a1caSRichard Henderson case TCG_CALL_ARG_NORMAL: 59678429a1caSRichard Henderson break; 59688429a1caSRichard Henderson case TCG_CALL_ARG_EXTEND_U: 59698429a1caSRichard Henderson case TCG_CALL_ARG_EXTEND_S: 59708429a1caSRichard Henderson /* No extension required for MemOpIdx. */ 59718429a1caSRichard Henderson tcg_debug_assert(imm <= INT32_MAX); 59728429a1caSRichard Henderson type = TCG_TYPE_REG; 59738429a1caSRichard Henderson break; 59748429a1caSRichard Henderson default: 59758429a1caSRichard Henderson g_assert_not_reached(); 59768429a1caSRichard Henderson } 59778429a1caSRichard Henderson tcg_out_helper_load_imm(s, loc->arg_slot, type, imm, parm); 59788429a1caSRichard Henderson next_arg++; 59798429a1caSRichard Henderson 59808429a1caSRichard Henderson /* 59818429a1caSRichard Henderson * Handle ra. 59828429a1caSRichard Henderson */ 59838429a1caSRichard Henderson loc = &info->in[next_arg]; 59848429a1caSRichard Henderson slot = loc->arg_slot; 59858429a1caSRichard Henderson if (parm->ra_gen) { 59868429a1caSRichard Henderson int arg_reg = -1; 59878429a1caSRichard Henderson TCGReg ra_reg; 59888429a1caSRichard Henderson 59898429a1caSRichard Henderson if (arg_slot_reg_p(slot)) { 59908429a1caSRichard Henderson arg_reg = tcg_target_call_iarg_regs[slot]; 59918429a1caSRichard Henderson } 59928429a1caSRichard Henderson ra_reg = parm->ra_gen(s, ldst, arg_reg); 59938429a1caSRichard Henderson 59948429a1caSRichard Henderson ptr_mov.dst = slot; 59958429a1caSRichard Henderson ptr_mov.src = ra_reg; 59968429a1caSRichard Henderson tcg_out_helper_load_slots(s, 1, &ptr_mov, parm); 59978429a1caSRichard Henderson } else { 59988429a1caSRichard Henderson imm = (uintptr_t)ldst->raddr; 59998429a1caSRichard Henderson tcg_out_helper_load_imm(s, slot, TCG_TYPE_PTR, imm, parm); 60008429a1caSRichard Henderson } 60018429a1caSRichard Henderson } 60028429a1caSRichard Henderson 60038429a1caSRichard Henderson static unsigned tcg_out_helper_add_mov(TCGMovExtend *mov, 60048429a1caSRichard Henderson const TCGCallArgumentLoc *loc, 60058429a1caSRichard Henderson TCGType dst_type, TCGType src_type, 60068429a1caSRichard Henderson TCGReg lo, TCGReg hi) 60078429a1caSRichard Henderson { 6008ebebea53SRichard Henderson MemOp reg_mo; 6009ebebea53SRichard Henderson 60108429a1caSRichard Henderson if (dst_type <= TCG_TYPE_REG) { 60118429a1caSRichard Henderson MemOp src_ext; 60128429a1caSRichard Henderson 60138429a1caSRichard Henderson switch (loc->kind) { 60148429a1caSRichard Henderson case TCG_CALL_ARG_NORMAL: 60158429a1caSRichard Henderson src_ext = src_type == TCG_TYPE_I32 ? MO_32 : MO_64; 60168429a1caSRichard Henderson break; 60178429a1caSRichard Henderson case TCG_CALL_ARG_EXTEND_U: 60188429a1caSRichard Henderson dst_type = TCG_TYPE_REG; 60198429a1caSRichard Henderson src_ext = MO_UL; 60208429a1caSRichard Henderson break; 60218429a1caSRichard Henderson case TCG_CALL_ARG_EXTEND_S: 60228429a1caSRichard Henderson dst_type = TCG_TYPE_REG; 60238429a1caSRichard Henderson src_ext = MO_SL; 60248429a1caSRichard Henderson break; 60258429a1caSRichard Henderson default: 60268429a1caSRichard Henderson g_assert_not_reached(); 60278429a1caSRichard Henderson } 60288429a1caSRichard Henderson 60298429a1caSRichard Henderson mov[0].dst = loc->arg_slot; 60308429a1caSRichard Henderson mov[0].dst_type = dst_type; 60318429a1caSRichard Henderson mov[0].src = lo; 60328429a1caSRichard Henderson mov[0].src_type = src_type; 60338429a1caSRichard Henderson mov[0].src_ext = src_ext; 60348429a1caSRichard Henderson return 1; 60358429a1caSRichard Henderson } 60368429a1caSRichard Henderson 6037ebebea53SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 6038ebebea53SRichard Henderson assert(dst_type == TCG_TYPE_I64); 6039ebebea53SRichard Henderson reg_mo = MO_32; 6040ebebea53SRichard Henderson } else { 6041ebebea53SRichard Henderson assert(dst_type == TCG_TYPE_I128); 6042ebebea53SRichard Henderson reg_mo = MO_64; 6043ebebea53SRichard Henderson } 60448429a1caSRichard Henderson 60458429a1caSRichard Henderson mov[0].dst = loc[HOST_BIG_ENDIAN].arg_slot; 60468429a1caSRichard Henderson mov[0].src = lo; 6047ebebea53SRichard Henderson mov[0].dst_type = TCG_TYPE_REG; 6048ebebea53SRichard Henderson mov[0].src_type = TCG_TYPE_REG; 6049ebebea53SRichard Henderson mov[0].src_ext = reg_mo; 60508429a1caSRichard Henderson 60518429a1caSRichard Henderson mov[1].dst = loc[!HOST_BIG_ENDIAN].arg_slot; 60528429a1caSRichard Henderson mov[1].src = hi; 6053ebebea53SRichard Henderson mov[1].dst_type = TCG_TYPE_REG; 6054ebebea53SRichard Henderson mov[1].src_type = TCG_TYPE_REG; 6055ebebea53SRichard Henderson mov[1].src_ext = reg_mo; 60568429a1caSRichard Henderson 60578429a1caSRichard Henderson return 2; 60588429a1caSRichard Henderson } 60598429a1caSRichard Henderson 60608429a1caSRichard Henderson static void tcg_out_ld_helper_args(TCGContext *s, const TCGLabelQemuLdst *ldst, 60618429a1caSRichard Henderson const TCGLdstHelperParam *parm) 60628429a1caSRichard Henderson { 60638429a1caSRichard Henderson const TCGHelperInfo *info; 60648429a1caSRichard Henderson const TCGCallArgumentLoc *loc; 60658429a1caSRichard Henderson TCGMovExtend mov[2]; 60668429a1caSRichard Henderson unsigned next_arg, nmov; 60678429a1caSRichard Henderson MemOp mop = get_memop(ldst->oi); 60688429a1caSRichard Henderson 60698429a1caSRichard Henderson switch (mop & MO_SIZE) { 60708429a1caSRichard Henderson case MO_8: 60718429a1caSRichard Henderson case MO_16: 60728429a1caSRichard Henderson case MO_32: 60738429a1caSRichard Henderson info = &info_helper_ld32_mmu; 60748429a1caSRichard Henderson break; 60758429a1caSRichard Henderson case MO_64: 60768429a1caSRichard Henderson info = &info_helper_ld64_mmu; 60778429a1caSRichard Henderson break; 6078ebebea53SRichard Henderson case MO_128: 6079ebebea53SRichard Henderson info = &info_helper_ld128_mmu; 6080ebebea53SRichard Henderson break; 60818429a1caSRichard Henderson default: 60828429a1caSRichard Henderson g_assert_not_reached(); 60838429a1caSRichard Henderson } 60848429a1caSRichard Henderson 60858429a1caSRichard Henderson /* Defer env argument. */ 60868429a1caSRichard Henderson next_arg = 1; 60878429a1caSRichard Henderson 60888429a1caSRichard Henderson loc = &info->in[next_arg]; 6089c31e5fa4SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && s->addr_type == TCG_TYPE_I32) { 609024e46e6cSRichard Henderson /* 609124e46e6cSRichard Henderson * 32-bit host with 32-bit guest: zero-extend the guest address 609224e46e6cSRichard Henderson * to 64-bits for the helper by storing the low part, then 609324e46e6cSRichard Henderson * load a zero for the high part. 609424e46e6cSRichard Henderson */ 609524e46e6cSRichard Henderson tcg_out_helper_add_mov(mov, loc + HOST_BIG_ENDIAN, 609624e46e6cSRichard Henderson TCG_TYPE_I32, TCG_TYPE_I32, 609724e46e6cSRichard Henderson ldst->addrlo_reg, -1); 609824e46e6cSRichard Henderson tcg_out_helper_load_slots(s, 1, mov, parm); 609924e46e6cSRichard Henderson 610024e46e6cSRichard Henderson tcg_out_helper_load_imm(s, loc[!HOST_BIG_ENDIAN].arg_slot, 610124e46e6cSRichard Henderson TCG_TYPE_I32, 0, parm); 610224e46e6cSRichard Henderson next_arg += 2; 6103c31e5fa4SRichard Henderson } else { 6104c31e5fa4SRichard Henderson nmov = tcg_out_helper_add_mov(mov, loc, TCG_TYPE_I64, s->addr_type, 6105c31e5fa4SRichard Henderson ldst->addrlo_reg, ldst->addrhi_reg); 6106c31e5fa4SRichard Henderson tcg_out_helper_load_slots(s, nmov, mov, parm); 6107c31e5fa4SRichard Henderson next_arg += nmov; 610824e46e6cSRichard Henderson } 61098429a1caSRichard Henderson 6110ebebea53SRichard Henderson switch (info->out_kind) { 6111ebebea53SRichard Henderson case TCG_CALL_RET_NORMAL: 6112ebebea53SRichard Henderson case TCG_CALL_RET_BY_VEC: 6113ebebea53SRichard Henderson break; 6114ebebea53SRichard Henderson case TCG_CALL_RET_BY_REF: 6115ebebea53SRichard Henderson /* 6116ebebea53SRichard Henderson * The return reference is in the first argument slot. 6117ebebea53SRichard Henderson * We need memory in which to return: re-use the top of stack. 6118ebebea53SRichard Henderson */ 6119ebebea53SRichard Henderson { 6120ebebea53SRichard Henderson int ofs_slot0 = TCG_TARGET_CALL_STACK_OFFSET; 6121ebebea53SRichard Henderson 6122ebebea53SRichard Henderson if (arg_slot_reg_p(0)) { 6123ebebea53SRichard Henderson tcg_out_addi_ptr(s, tcg_target_call_iarg_regs[0], 6124ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0); 6125ebebea53SRichard Henderson } else { 6126ebebea53SRichard Henderson tcg_debug_assert(parm->ntmp != 0); 6127ebebea53SRichard Henderson tcg_out_addi_ptr(s, parm->tmp[0], 6128ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0); 6129ebebea53SRichard Henderson tcg_out_st(s, TCG_TYPE_PTR, parm->tmp[0], 6130ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0); 6131ebebea53SRichard Henderson } 6132ebebea53SRichard Henderson } 6133ebebea53SRichard Henderson break; 6134ebebea53SRichard Henderson default: 6135ebebea53SRichard Henderson g_assert_not_reached(); 6136ebebea53SRichard Henderson } 61378429a1caSRichard Henderson 61388429a1caSRichard Henderson tcg_out_helper_load_common_args(s, ldst, parm, info, next_arg); 61398429a1caSRichard Henderson } 61408429a1caSRichard Henderson 61418429a1caSRichard Henderson static void tcg_out_ld_helper_ret(TCGContext *s, const TCGLabelQemuLdst *ldst, 61428429a1caSRichard Henderson bool load_sign, 61438429a1caSRichard Henderson const TCGLdstHelperParam *parm) 61448429a1caSRichard Henderson { 61458429a1caSRichard Henderson MemOp mop = get_memop(ldst->oi); 6146ebebea53SRichard Henderson TCGMovExtend mov[2]; 6147ebebea53SRichard Henderson int ofs_slot0; 61488429a1caSRichard Henderson 6149ebebea53SRichard Henderson switch (ldst->type) { 6150ebebea53SRichard Henderson case TCG_TYPE_I64: 6151ebebea53SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 6152ebebea53SRichard Henderson break; 6153ebebea53SRichard Henderson } 6154ebebea53SRichard Henderson /* fall through */ 6155ebebea53SRichard Henderson 6156ebebea53SRichard Henderson case TCG_TYPE_I32: 61578429a1caSRichard Henderson mov[0].dst = ldst->datalo_reg; 61588429a1caSRichard Henderson mov[0].src = tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, 0); 61598429a1caSRichard Henderson mov[0].dst_type = ldst->type; 61608429a1caSRichard Henderson mov[0].src_type = TCG_TYPE_REG; 61618429a1caSRichard Henderson 61628429a1caSRichard Henderson /* 61638429a1caSRichard Henderson * If load_sign, then we allowed the helper to perform the 61648429a1caSRichard Henderson * appropriate sign extension to tcg_target_ulong, and all 61658429a1caSRichard Henderson * we need now is a plain move. 61668429a1caSRichard Henderson * 61678429a1caSRichard Henderson * If they do not, then we expect the relevant extension 61688429a1caSRichard Henderson * instruction to be no more expensive than a move, and 61698429a1caSRichard Henderson * we thus save the icache etc by only using one of two 61708429a1caSRichard Henderson * helper functions. 61718429a1caSRichard Henderson */ 61728429a1caSRichard Henderson if (load_sign || !(mop & MO_SIGN)) { 61738429a1caSRichard Henderson if (TCG_TARGET_REG_BITS == 32 || ldst->type == TCG_TYPE_I32) { 61748429a1caSRichard Henderson mov[0].src_ext = MO_32; 61758429a1caSRichard Henderson } else { 61768429a1caSRichard Henderson mov[0].src_ext = MO_64; 61778429a1caSRichard Henderson } 61788429a1caSRichard Henderson } else { 61798429a1caSRichard Henderson mov[0].src_ext = mop & MO_SSIZE; 61808429a1caSRichard Henderson } 61818429a1caSRichard Henderson tcg_out_movext1(s, mov); 6182ebebea53SRichard Henderson return; 6183ebebea53SRichard Henderson 6184ebebea53SRichard Henderson case TCG_TYPE_I128: 6185ebebea53SRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 64); 6186ebebea53SRichard Henderson ofs_slot0 = TCG_TARGET_CALL_STACK_OFFSET; 6187ebebea53SRichard Henderson switch (TCG_TARGET_CALL_RET_I128) { 6188ebebea53SRichard Henderson case TCG_CALL_RET_NORMAL: 6189ebebea53SRichard Henderson break; 6190ebebea53SRichard Henderson case TCG_CALL_RET_BY_VEC: 6191ebebea53SRichard Henderson tcg_out_st(s, TCG_TYPE_V128, 6192ebebea53SRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0), 6193ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0); 6194ebebea53SRichard Henderson /* fall through */ 6195ebebea53SRichard Henderson case TCG_CALL_RET_BY_REF: 6196ebebea53SRichard Henderson tcg_out_ld(s, TCG_TYPE_I64, ldst->datalo_reg, 6197ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0 + 8 * HOST_BIG_ENDIAN); 6198ebebea53SRichard Henderson tcg_out_ld(s, TCG_TYPE_I64, ldst->datahi_reg, 6199ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0 + 8 * !HOST_BIG_ENDIAN); 6200ebebea53SRichard Henderson return; 6201ebebea53SRichard Henderson default: 6202ebebea53SRichard Henderson g_assert_not_reached(); 6203ebebea53SRichard Henderson } 6204ebebea53SRichard Henderson break; 6205ebebea53SRichard Henderson 6206ebebea53SRichard Henderson default: 6207ebebea53SRichard Henderson g_assert_not_reached(); 6208ebebea53SRichard Henderson } 62098429a1caSRichard Henderson 62108429a1caSRichard Henderson mov[0].dst = ldst->datalo_reg; 62118429a1caSRichard Henderson mov[0].src = 62128429a1caSRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, HOST_BIG_ENDIAN); 6213723d3a27SRichard Henderson mov[0].dst_type = TCG_TYPE_REG; 6214723d3a27SRichard Henderson mov[0].src_type = TCG_TYPE_REG; 6215ebebea53SRichard Henderson mov[0].src_ext = TCG_TARGET_REG_BITS == 32 ? MO_32 : MO_64; 62168429a1caSRichard Henderson 62178429a1caSRichard Henderson mov[1].dst = ldst->datahi_reg; 62188429a1caSRichard Henderson mov[1].src = 62198429a1caSRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, !HOST_BIG_ENDIAN); 62208429a1caSRichard Henderson mov[1].dst_type = TCG_TYPE_REG; 62218429a1caSRichard Henderson mov[1].src_type = TCG_TYPE_REG; 6222ebebea53SRichard Henderson mov[1].src_ext = TCG_TARGET_REG_BITS == 32 ? MO_32 : MO_64; 62238429a1caSRichard Henderson 62248429a1caSRichard Henderson tcg_out_movext2(s, mov, mov + 1, parm->ntmp ? parm->tmp[0] : -1); 62258429a1caSRichard Henderson } 62268429a1caSRichard Henderson 62278429a1caSRichard Henderson static void tcg_out_st_helper_args(TCGContext *s, const TCGLabelQemuLdst *ldst, 62288429a1caSRichard Henderson const TCGLdstHelperParam *parm) 62298429a1caSRichard Henderson { 62308429a1caSRichard Henderson const TCGHelperInfo *info; 62318429a1caSRichard Henderson const TCGCallArgumentLoc *loc; 62328429a1caSRichard Henderson TCGMovExtend mov[4]; 62338429a1caSRichard Henderson TCGType data_type; 62348429a1caSRichard Henderson unsigned next_arg, nmov, n; 62358429a1caSRichard Henderson MemOp mop = get_memop(ldst->oi); 62368429a1caSRichard Henderson 62378429a1caSRichard Henderson switch (mop & MO_SIZE) { 62388429a1caSRichard Henderson case MO_8: 62398429a1caSRichard Henderson case MO_16: 62408429a1caSRichard Henderson case MO_32: 62418429a1caSRichard Henderson info = &info_helper_st32_mmu; 62428429a1caSRichard Henderson data_type = TCG_TYPE_I32; 62438429a1caSRichard Henderson break; 62448429a1caSRichard Henderson case MO_64: 62458429a1caSRichard Henderson info = &info_helper_st64_mmu; 62468429a1caSRichard Henderson data_type = TCG_TYPE_I64; 62478429a1caSRichard Henderson break; 6248ebebea53SRichard Henderson case MO_128: 6249ebebea53SRichard Henderson info = &info_helper_st128_mmu; 6250ebebea53SRichard Henderson data_type = TCG_TYPE_I128; 6251ebebea53SRichard Henderson break; 62528429a1caSRichard Henderson default: 62538429a1caSRichard Henderson g_assert_not_reached(); 62548429a1caSRichard Henderson } 62558429a1caSRichard Henderson 62568429a1caSRichard Henderson /* Defer env argument. */ 62578429a1caSRichard Henderson next_arg = 1; 62588429a1caSRichard Henderson nmov = 0; 62598429a1caSRichard Henderson 62608429a1caSRichard Henderson /* Handle addr argument. */ 62618429a1caSRichard Henderson loc = &info->in[next_arg]; 6262c31e5fa4SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && s->addr_type == TCG_TYPE_I32) { 626324e46e6cSRichard Henderson /* 626424e46e6cSRichard Henderson * 32-bit host with 32-bit guest: zero-extend the guest address 626524e46e6cSRichard Henderson * to 64-bits for the helper by storing the low part. Later, 626624e46e6cSRichard Henderson * after we have processed the register inputs, we will load a 626724e46e6cSRichard Henderson * zero for the high part. 626824e46e6cSRichard Henderson */ 626924e46e6cSRichard Henderson tcg_out_helper_add_mov(mov, loc + HOST_BIG_ENDIAN, 627024e46e6cSRichard Henderson TCG_TYPE_I32, TCG_TYPE_I32, 627124e46e6cSRichard Henderson ldst->addrlo_reg, -1); 627224e46e6cSRichard Henderson next_arg += 2; 627324e46e6cSRichard Henderson nmov += 1; 6274c31e5fa4SRichard Henderson } else { 6275c31e5fa4SRichard Henderson n = tcg_out_helper_add_mov(mov, loc, TCG_TYPE_I64, s->addr_type, 6276c31e5fa4SRichard Henderson ldst->addrlo_reg, ldst->addrhi_reg); 6277c31e5fa4SRichard Henderson next_arg += n; 6278c31e5fa4SRichard Henderson nmov += n; 627924e46e6cSRichard Henderson } 62808429a1caSRichard Henderson 62818429a1caSRichard Henderson /* Handle data argument. */ 62828429a1caSRichard Henderson loc = &info->in[next_arg]; 6283ebebea53SRichard Henderson switch (loc->kind) { 6284ebebea53SRichard Henderson case TCG_CALL_ARG_NORMAL: 6285ebebea53SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 6286ebebea53SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 62878429a1caSRichard Henderson n = tcg_out_helper_add_mov(mov + nmov, loc, data_type, ldst->type, 62888429a1caSRichard Henderson ldst->datalo_reg, ldst->datahi_reg); 62898429a1caSRichard Henderson next_arg += n; 62908429a1caSRichard Henderson nmov += n; 6291ebebea53SRichard Henderson tcg_out_helper_load_slots(s, nmov, mov, parm); 6292ebebea53SRichard Henderson break; 6293ebebea53SRichard Henderson 6294ebebea53SRichard Henderson case TCG_CALL_ARG_BY_REF: 6295ebebea53SRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 64); 6296ebebea53SRichard Henderson tcg_debug_assert(data_type == TCG_TYPE_I128); 6297ebebea53SRichard Henderson tcg_out_st(s, TCG_TYPE_I64, 6298ebebea53SRichard Henderson HOST_BIG_ENDIAN ? ldst->datahi_reg : ldst->datalo_reg, 6299ebebea53SRichard Henderson TCG_REG_CALL_STACK, arg_slot_stk_ofs(loc[0].ref_slot)); 6300ebebea53SRichard Henderson tcg_out_st(s, TCG_TYPE_I64, 6301ebebea53SRichard Henderson HOST_BIG_ENDIAN ? ldst->datalo_reg : ldst->datahi_reg, 6302ebebea53SRichard Henderson TCG_REG_CALL_STACK, arg_slot_stk_ofs(loc[1].ref_slot)); 63038429a1caSRichard Henderson 63048429a1caSRichard Henderson tcg_out_helper_load_slots(s, nmov, mov, parm); 6305ebebea53SRichard Henderson 6306ebebea53SRichard Henderson if (arg_slot_reg_p(loc->arg_slot)) { 6307ebebea53SRichard Henderson tcg_out_addi_ptr(s, tcg_target_call_iarg_regs[loc->arg_slot], 6308ebebea53SRichard Henderson TCG_REG_CALL_STACK, 6309ebebea53SRichard Henderson arg_slot_stk_ofs(loc->ref_slot)); 6310ebebea53SRichard Henderson } else { 6311ebebea53SRichard Henderson tcg_debug_assert(parm->ntmp != 0); 6312ebebea53SRichard Henderson tcg_out_addi_ptr(s, parm->tmp[0], TCG_REG_CALL_STACK, 6313ebebea53SRichard Henderson arg_slot_stk_ofs(loc->ref_slot)); 6314ebebea53SRichard Henderson tcg_out_st(s, TCG_TYPE_PTR, parm->tmp[0], 6315ebebea53SRichard Henderson TCG_REG_CALL_STACK, arg_slot_stk_ofs(loc->arg_slot)); 6316ebebea53SRichard Henderson } 6317ebebea53SRichard Henderson next_arg += 2; 6318ebebea53SRichard Henderson break; 6319ebebea53SRichard Henderson 6320ebebea53SRichard Henderson default: 6321ebebea53SRichard Henderson g_assert_not_reached(); 6322ebebea53SRichard Henderson } 6323ebebea53SRichard Henderson 6324c31e5fa4SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && s->addr_type == TCG_TYPE_I32) { 6325c31e5fa4SRichard Henderson /* Zero extend the address by loading a zero for the high part. */ 632624e46e6cSRichard Henderson loc = &info->in[1 + !HOST_BIG_ENDIAN]; 632724e46e6cSRichard Henderson tcg_out_helper_load_imm(s, loc->arg_slot, TCG_TYPE_I32, 0, parm); 632824e46e6cSRichard Henderson } 632924e46e6cSRichard Henderson 63308429a1caSRichard Henderson tcg_out_helper_load_common_args(s, ldst, parm, info, next_arg); 63318429a1caSRichard Henderson } 63328429a1caSRichard Henderson 633376cef4b2SRichard Henderson int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start) 6334c896fe29Sbellard { 6335747bd69dSRichard Henderson int i, start_words, num_insns; 633615fa08f8SRichard Henderson TCGOp *op; 6337c896fe29Sbellard 6338d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP) 6339fbf59aadSRichard Henderson && qemu_log_in_addr_range(pc_start))) { 6340c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock(); 634178b54858SRichard Henderson if (logfile) { 634278b54858SRichard Henderson fprintf(logfile, "OP:\n"); 6343b7a83ff8SRichard Henderson tcg_dump_ops(s, logfile, false); 634478b54858SRichard Henderson fprintf(logfile, "\n"); 6345fc59d2d8SRobert Foley qemu_log_unlock(logfile); 6346c896fe29Sbellard } 634778b54858SRichard Henderson } 6348c896fe29Sbellard 6349bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG 6350bef16ab4SRichard Henderson /* Ensure all labels referenced have been emitted. */ 6351bef16ab4SRichard Henderson { 6352bef16ab4SRichard Henderson TCGLabel *l; 6353bef16ab4SRichard Henderson bool error = false; 6354bef16ab4SRichard Henderson 6355bef16ab4SRichard Henderson QSIMPLEQ_FOREACH(l, &s->labels, next) { 6356f85b1fc4SRichard Henderson if (unlikely(!l->present) && !QSIMPLEQ_EMPTY(&l->branches)) { 6357bef16ab4SRichard Henderson qemu_log_mask(CPU_LOG_TB_OP, 6358bef16ab4SRichard Henderson "$L%d referenced but not present.\n", l->id); 6359bef16ab4SRichard Henderson error = true; 6360bef16ab4SRichard Henderson } 6361bef16ab4SRichard Henderson } 6362bef16ab4SRichard Henderson assert(!error); 6363bef16ab4SRichard Henderson } 6364bef16ab4SRichard Henderson #endif 6365bef16ab4SRichard Henderson 636604e006abSRichard Henderson /* Do not reuse any EBB that may be allocated within the TB. */ 636704e006abSRichard Henderson tcg_temp_ebb_reset_freed(s); 636804e006abSRichard Henderson 6369c45cb8bbSRichard Henderson tcg_optimize(s); 63708f2e8c07SKirill Batuzov 6371b4fc67c7SRichard Henderson reachable_code_pass(s); 6372874b8574SRichard Henderson liveness_pass_0(s); 6373b83eabeaSRichard Henderson liveness_pass_1(s); 63745a18407fSRichard Henderson 63755a18407fSRichard Henderson if (s->nb_indirects > 0) { 63765a18407fSRichard Henderson if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND) 6377fbf59aadSRichard Henderson && qemu_log_in_addr_range(pc_start))) { 6378c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock(); 637978b54858SRichard Henderson if (logfile) { 638078b54858SRichard Henderson fprintf(logfile, "OP before indirect lowering:\n"); 6381b7a83ff8SRichard Henderson tcg_dump_ops(s, logfile, false); 638278b54858SRichard Henderson fprintf(logfile, "\n"); 6383fc59d2d8SRobert Foley qemu_log_unlock(logfile); 63845a18407fSRichard Henderson } 638578b54858SRichard Henderson } 6386645e3a81SRichard Henderson 63875a18407fSRichard Henderson /* Replace indirect temps with direct temps. */ 6388b83eabeaSRichard Henderson if (liveness_pass_2(s)) { 63895a18407fSRichard Henderson /* If changes were made, re-run liveness. */ 6390b83eabeaSRichard Henderson liveness_pass_1(s); 63915a18407fSRichard Henderson } 63925a18407fSRichard Henderson } 6393c5cc28ffSAurelien Jarno 6394d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT) 6395fbf59aadSRichard Henderson && qemu_log_in_addr_range(pc_start))) { 6396c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock(); 639778b54858SRichard Henderson if (logfile) { 639878b54858SRichard Henderson fprintf(logfile, "OP after optimization and liveness analysis:\n"); 6399b7a83ff8SRichard Henderson tcg_dump_ops(s, logfile, true); 640078b54858SRichard Henderson fprintf(logfile, "\n"); 6401fc59d2d8SRobert Foley qemu_log_unlock(logfile); 6402c896fe29Sbellard } 640378b54858SRichard Henderson } 6404c896fe29Sbellard 640535abb009SRichard Henderson /* Initialize goto_tb jump offsets. */ 64063a50f424SRichard Henderson tb->jmp_reset_offset[0] = TB_JMP_OFFSET_INVALID; 64073a50f424SRichard Henderson tb->jmp_reset_offset[1] = TB_JMP_OFFSET_INVALID; 64089da6079bSRichard Henderson tb->jmp_insn_offset[0] = TB_JMP_OFFSET_INVALID; 64099da6079bSRichard Henderson tb->jmp_insn_offset[1] = TB_JMP_OFFSET_INVALID; 641035abb009SRichard Henderson 6411c896fe29Sbellard tcg_reg_alloc_start(s); 6412c896fe29Sbellard 6413db0c51a3SRichard Henderson /* 6414db0c51a3SRichard Henderson * Reset the buffer pointers when restarting after overflow. 6415db0c51a3SRichard Henderson * TODO: Move this into translate-all.c with the rest of the 6416db0c51a3SRichard Henderson * buffer management. Having only this done here is confusing. 6417db0c51a3SRichard Henderson */ 6418db0c51a3SRichard Henderson s->code_buf = tcg_splitwx_to_rw(tb->tc.ptr); 6419db0c51a3SRichard Henderson s->code_ptr = s->code_buf; 6420a7cfd751SRichard Henderson s->data_gen_ptr = NULL; 6421c896fe29Sbellard 64226001f772SLaurent Vivier QSIMPLEQ_INIT(&s->ldst_labels); 642357a26946SRichard Henderson s->pool_labels = NULL; 64249ecefc84SRichard Henderson 6425747bd69dSRichard Henderson start_words = s->insn_start_words; 6426747bd69dSRichard Henderson s->gen_insn_data = 6427747bd69dSRichard Henderson tcg_malloc(sizeof(uint64_t) * s->gen_tb->icount * start_words); 6428747bd69dSRichard Henderson 64299358fbbfSRichard Henderson tcg_out_tb_start(s); 64309358fbbfSRichard Henderson 6431fca8a500SRichard Henderson num_insns = -1; 643215fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 6433c45cb8bbSRichard Henderson TCGOpcode opc = op->opc; 6434b3db8758Sblueswir1 6435c896fe29Sbellard switch (opc) { 6436c896fe29Sbellard case INDEX_op_mov_i32: 6437c896fe29Sbellard case INDEX_op_mov_i64: 6438d2fd745fSRichard Henderson case INDEX_op_mov_vec: 6439dd186292SRichard Henderson tcg_reg_alloc_mov(s, op); 6440c896fe29Sbellard break; 6441bab1671fSRichard Henderson case INDEX_op_dup_vec: 6442bab1671fSRichard Henderson tcg_reg_alloc_dup(s, op); 6443bab1671fSRichard Henderson break; 6444765b842aSRichard Henderson case INDEX_op_insn_start: 6445fca8a500SRichard Henderson if (num_insns >= 0) { 64469f754620SRichard Henderson size_t off = tcg_current_code_size(s); 64479f754620SRichard Henderson s->gen_insn_end_off[num_insns] = off; 64489f754620SRichard Henderson /* Assert that we do not overflow our stored offset. */ 64499f754620SRichard Henderson assert(s->gen_insn_end_off[num_insns] == off); 6450fca8a500SRichard Henderson } 6451fca8a500SRichard Henderson num_insns++; 6452747bd69dSRichard Henderson for (i = 0; i < start_words; ++i) { 6453747bd69dSRichard Henderson s->gen_insn_data[num_insns * start_words + i] = 6454c9ad8d27SRichard Henderson tcg_get_insn_start_param(op, i); 6455bad729e2SRichard Henderson } 6456c896fe29Sbellard break; 64575ff9d6a4Sbellard case INDEX_op_discard: 645843439139SRichard Henderson temp_dead(s, arg_temp(op->args[0])); 64595ff9d6a4Sbellard break; 6460c896fe29Sbellard case INDEX_op_set_label: 6461e8996ee0Sbellard tcg_reg_alloc_bb_end(s, s->reserved_regs); 646292ab8e7dSRichard Henderson tcg_out_label(s, arg_label(op->args[0])); 6463c896fe29Sbellard break; 6464c896fe29Sbellard case INDEX_op_call: 6465dd186292SRichard Henderson tcg_reg_alloc_call(s, op); 6466c45cb8bbSRichard Henderson break; 6467b55a8d9dSRichard Henderson case INDEX_op_exit_tb: 6468b55a8d9dSRichard Henderson tcg_out_exit_tb(s, op->args[0]); 6469b55a8d9dSRichard Henderson break; 6470cf7d6b8eSRichard Henderson case INDEX_op_goto_tb: 6471cf7d6b8eSRichard Henderson tcg_out_goto_tb(s, op->args[0]); 6472cf7d6b8eSRichard Henderson break; 6473efe86b21SRichard Henderson case INDEX_op_dup2_vec: 6474efe86b21SRichard Henderson if (tcg_reg_alloc_dup2(s, op)) { 6475efe86b21SRichard Henderson break; 6476efe86b21SRichard Henderson } 6477efe86b21SRichard Henderson /* fall through */ 6478c896fe29Sbellard default: 647925c4d9ccSRichard Henderson /* Sanity check that we've not introduced any unhandled opcodes. */ 6480771a5925SRichard Henderson tcg_debug_assert(tcg_op_supported(opc, TCGOP_TYPE(op), 6481771a5925SRichard Henderson TCGOP_FLAGS(op))); 6482c896fe29Sbellard /* Note: in order to speed up the code, it would be much 6483c896fe29Sbellard faster to have specialized register allocator functions for 6484c896fe29Sbellard some common argument patterns */ 6485dd186292SRichard Henderson tcg_reg_alloc_op(s, op); 6486c896fe29Sbellard break; 6487c896fe29Sbellard } 6488b125f9dcSRichard Henderson /* Test for (pending) buffer overflow. The assumption is that any 6489b125f9dcSRichard Henderson one operation beginning below the high water mark cannot overrun 6490b125f9dcSRichard Henderson the buffer completely. Thus we can test for overflow after 6491b125f9dcSRichard Henderson generating code without having to check during generation. */ 6492644da9b3SJohn Clarke if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) { 6493b125f9dcSRichard Henderson return -1; 6494b125f9dcSRichard Henderson } 64956e6c4efeSRichard Henderson /* Test for TB overflow, as seen by gen_insn_end_off. */ 64966e6c4efeSRichard Henderson if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) { 64976e6c4efeSRichard Henderson return -2; 64986e6c4efeSRichard Henderson } 6499c896fe29Sbellard } 6500747bd69dSRichard Henderson tcg_debug_assert(num_insns + 1 == s->gen_tb->icount); 6501fca8a500SRichard Henderson s->gen_insn_end_off[num_insns] = tcg_current_code_size(s); 6502c45cb8bbSRichard Henderson 6503b76f0d8cSYeongkyoon Lee /* Generate TB finalization at the end of block */ 6504aeee05f5SRichard Henderson i = tcg_out_ldst_finalize(s); 6505aeee05f5SRichard Henderson if (i < 0) { 6506aeee05f5SRichard Henderson return i; 650723dceda6SRichard Henderson } 65081768987bSRichard Henderson i = tcg_out_pool_finalize(s); 65091768987bSRichard Henderson if (i < 0) { 65101768987bSRichard Henderson return i; 651157a26946SRichard Henderson } 65127ecd02a0SRichard Henderson if (!tcg_resolve_relocs(s)) { 65137ecd02a0SRichard Henderson return -2; 65147ecd02a0SRichard Henderson } 6515c896fe29Sbellard 6516df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 6517c896fe29Sbellard /* flush instruction cache */ 6518db0c51a3SRichard Henderson flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf), 6519db0c51a3SRichard Henderson (uintptr_t)s->code_buf, 65201da8de39SRichard Henderson tcg_ptr_byte_diff(s->code_ptr, s->code_buf)); 6521df5d2b16SRichard Henderson #endif 65222aeabc08SStefan Weil 65231813e175SRichard Henderson return tcg_current_code_size(s); 6524c896fe29Sbellard } 6525c896fe29Sbellard 6526813da627SRichard Henderson #ifdef ELF_HOST_MACHINE 65275872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things: 65285872bbf2SRichard Henderson 65295872bbf2SRichard Henderson (1) Define ELF_HOST_MACHINE to indicate both what value to 65305872bbf2SRichard Henderson put into the ELF image and to indicate support for the feature. 65315872bbf2SRichard Henderson 65325872bbf2SRichard Henderson (2) Define tcg_register_jit. This should create a buffer containing 65335872bbf2SRichard Henderson the contents of a .debug_frame section that describes the post- 65345872bbf2SRichard Henderson prologue unwind info for the tcg machine. 65355872bbf2SRichard Henderson 65365872bbf2SRichard Henderson (3) Call tcg_register_jit_int, with the constructed .debug_frame. 65375872bbf2SRichard Henderson */ 6538813da627SRichard Henderson 6539813da627SRichard Henderson /* Begin GDB interface. THE FOLLOWING MUST MATCH GDB DOCS. */ 6540813da627SRichard Henderson typedef enum { 6541813da627SRichard Henderson JIT_NOACTION = 0, 6542813da627SRichard Henderson JIT_REGISTER_FN, 6543813da627SRichard Henderson JIT_UNREGISTER_FN 6544813da627SRichard Henderson } jit_actions_t; 6545813da627SRichard Henderson 6546813da627SRichard Henderson struct jit_code_entry { 6547813da627SRichard Henderson struct jit_code_entry *next_entry; 6548813da627SRichard Henderson struct jit_code_entry *prev_entry; 6549813da627SRichard Henderson const void *symfile_addr; 6550813da627SRichard Henderson uint64_t symfile_size; 6551813da627SRichard Henderson }; 6552813da627SRichard Henderson 6553813da627SRichard Henderson struct jit_descriptor { 6554813da627SRichard Henderson uint32_t version; 6555813da627SRichard Henderson uint32_t action_flag; 6556813da627SRichard Henderson struct jit_code_entry *relevant_entry; 6557813da627SRichard Henderson struct jit_code_entry *first_entry; 6558813da627SRichard Henderson }; 6559813da627SRichard Henderson 6560813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline)); 6561813da627SRichard Henderson void __jit_debug_register_code(void) 6562813da627SRichard Henderson { 6563813da627SRichard Henderson asm(""); 6564813da627SRichard Henderson } 6565813da627SRichard Henderson 6566813da627SRichard Henderson /* Must statically initialize the version, because GDB may check 6567813da627SRichard Henderson the version before we can set it. */ 6568813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 }; 6569813da627SRichard Henderson 6570813da627SRichard Henderson /* End GDB interface. */ 6571813da627SRichard Henderson 6572813da627SRichard Henderson static int find_string(const char *strtab, const char *str) 6573813da627SRichard Henderson { 6574813da627SRichard Henderson const char *p = strtab + 1; 6575813da627SRichard Henderson 6576813da627SRichard Henderson while (1) { 6577813da627SRichard Henderson if (strcmp(p, str) == 0) { 6578813da627SRichard Henderson return p - strtab; 6579813da627SRichard Henderson } 6580813da627SRichard Henderson p += strlen(p) + 1; 6581813da627SRichard Henderson } 6582813da627SRichard Henderson } 6583813da627SRichard Henderson 6584755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf_ptr, size_t buf_size, 65852c90784aSRichard Henderson const void *debug_frame, 65862c90784aSRichard Henderson size_t debug_frame_size) 6587813da627SRichard Henderson { 65885872bbf2SRichard Henderson struct __attribute__((packed)) DebugInfo { 65895872bbf2SRichard Henderson uint32_t len; 65905872bbf2SRichard Henderson uint16_t version; 65915872bbf2SRichard Henderson uint32_t abbrev; 65925872bbf2SRichard Henderson uint8_t ptr_size; 65935872bbf2SRichard Henderson uint8_t cu_die; 65945872bbf2SRichard Henderson uint16_t cu_lang; 65955872bbf2SRichard Henderson uintptr_t cu_low_pc; 65965872bbf2SRichard Henderson uintptr_t cu_high_pc; 65975872bbf2SRichard Henderson uint8_t fn_die; 65985872bbf2SRichard Henderson char fn_name[16]; 65995872bbf2SRichard Henderson uintptr_t fn_low_pc; 66005872bbf2SRichard Henderson uintptr_t fn_high_pc; 66015872bbf2SRichard Henderson uint8_t cu_eoc; 66025872bbf2SRichard Henderson }; 6603813da627SRichard Henderson 6604813da627SRichard Henderson struct ElfImage { 6605813da627SRichard Henderson ElfW(Ehdr) ehdr; 6606813da627SRichard Henderson ElfW(Phdr) phdr; 66075872bbf2SRichard Henderson ElfW(Shdr) shdr[7]; 66085872bbf2SRichard Henderson ElfW(Sym) sym[2]; 66095872bbf2SRichard Henderson struct DebugInfo di; 66105872bbf2SRichard Henderson uint8_t da[24]; 66115872bbf2SRichard Henderson char str[80]; 66125872bbf2SRichard Henderson }; 66135872bbf2SRichard Henderson 66145872bbf2SRichard Henderson struct ElfImage *img; 66155872bbf2SRichard Henderson 66165872bbf2SRichard Henderson static const struct ElfImage img_template = { 66175872bbf2SRichard Henderson .ehdr = { 66185872bbf2SRichard Henderson .e_ident[EI_MAG0] = ELFMAG0, 66195872bbf2SRichard Henderson .e_ident[EI_MAG1] = ELFMAG1, 66205872bbf2SRichard Henderson .e_ident[EI_MAG2] = ELFMAG2, 66215872bbf2SRichard Henderson .e_ident[EI_MAG3] = ELFMAG3, 66225872bbf2SRichard Henderson .e_ident[EI_CLASS] = ELF_CLASS, 66235872bbf2SRichard Henderson .e_ident[EI_DATA] = ELF_DATA, 66245872bbf2SRichard Henderson .e_ident[EI_VERSION] = EV_CURRENT, 66255872bbf2SRichard Henderson .e_type = ET_EXEC, 66265872bbf2SRichard Henderson .e_machine = ELF_HOST_MACHINE, 66275872bbf2SRichard Henderson .e_version = EV_CURRENT, 66285872bbf2SRichard Henderson .e_phoff = offsetof(struct ElfImage, phdr), 66295872bbf2SRichard Henderson .e_shoff = offsetof(struct ElfImage, shdr), 66305872bbf2SRichard Henderson .e_ehsize = sizeof(ElfW(Shdr)), 66315872bbf2SRichard Henderson .e_phentsize = sizeof(ElfW(Phdr)), 66325872bbf2SRichard Henderson .e_phnum = 1, 66335872bbf2SRichard Henderson .e_shentsize = sizeof(ElfW(Shdr)), 66345872bbf2SRichard Henderson .e_shnum = ARRAY_SIZE(img->shdr), 66355872bbf2SRichard Henderson .e_shstrndx = ARRAY_SIZE(img->shdr) - 1, 6636abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS 6637abbb3eaeSRichard Henderson .e_flags = ELF_HOST_FLAGS, 6638abbb3eaeSRichard Henderson #endif 6639abbb3eaeSRichard Henderson #ifdef ELF_OSABI 6640abbb3eaeSRichard Henderson .e_ident[EI_OSABI] = ELF_OSABI, 6641abbb3eaeSRichard Henderson #endif 66425872bbf2SRichard Henderson }, 66435872bbf2SRichard Henderson .phdr = { 66445872bbf2SRichard Henderson .p_type = PT_LOAD, 66455872bbf2SRichard Henderson .p_flags = PF_X, 66465872bbf2SRichard Henderson }, 66475872bbf2SRichard Henderson .shdr = { 66485872bbf2SRichard Henderson [0] = { .sh_type = SHT_NULL }, 66495872bbf2SRichard Henderson /* Trick: The contents of code_gen_buffer are not present in 66505872bbf2SRichard Henderson this fake ELF file; that got allocated elsewhere. Therefore 66515872bbf2SRichard Henderson we mark .text as SHT_NOBITS (similar to .bss) so that readers 66525872bbf2SRichard Henderson will not look for contents. We can record any address. */ 66535872bbf2SRichard Henderson [1] = { /* .text */ 66545872bbf2SRichard Henderson .sh_type = SHT_NOBITS, 66555872bbf2SRichard Henderson .sh_flags = SHF_EXECINSTR | SHF_ALLOC, 66565872bbf2SRichard Henderson }, 66575872bbf2SRichard Henderson [2] = { /* .debug_info */ 66585872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 66595872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, di), 66605872bbf2SRichard Henderson .sh_size = sizeof(struct DebugInfo), 66615872bbf2SRichard Henderson }, 66625872bbf2SRichard Henderson [3] = { /* .debug_abbrev */ 66635872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 66645872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, da), 66655872bbf2SRichard Henderson .sh_size = sizeof(img->da), 66665872bbf2SRichard Henderson }, 66675872bbf2SRichard Henderson [4] = { /* .debug_frame */ 66685872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 66695872bbf2SRichard Henderson .sh_offset = sizeof(struct ElfImage), 66705872bbf2SRichard Henderson }, 66715872bbf2SRichard Henderson [5] = { /* .symtab */ 66725872bbf2SRichard Henderson .sh_type = SHT_SYMTAB, 66735872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, sym), 66745872bbf2SRichard Henderson .sh_size = sizeof(img->sym), 66755872bbf2SRichard Henderson .sh_info = 1, 66765872bbf2SRichard Henderson .sh_link = ARRAY_SIZE(img->shdr) - 1, 66775872bbf2SRichard Henderson .sh_entsize = sizeof(ElfW(Sym)), 66785872bbf2SRichard Henderson }, 66795872bbf2SRichard Henderson [6] = { /* .strtab */ 66805872bbf2SRichard Henderson .sh_type = SHT_STRTAB, 66815872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, str), 66825872bbf2SRichard Henderson .sh_size = sizeof(img->str), 66835872bbf2SRichard Henderson } 66845872bbf2SRichard Henderson }, 66855872bbf2SRichard Henderson .sym = { 66865872bbf2SRichard Henderson [1] = { /* code_gen_buffer */ 66875872bbf2SRichard Henderson .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC), 66885872bbf2SRichard Henderson .st_shndx = 1, 66895872bbf2SRichard Henderson } 66905872bbf2SRichard Henderson }, 66915872bbf2SRichard Henderson .di = { 66925872bbf2SRichard Henderson .len = sizeof(struct DebugInfo) - 4, 66935872bbf2SRichard Henderson .version = 2, 66945872bbf2SRichard Henderson .ptr_size = sizeof(void *), 66955872bbf2SRichard Henderson .cu_die = 1, 66965872bbf2SRichard Henderson .cu_lang = 0x8001, /* DW_LANG_Mips_Assembler */ 66975872bbf2SRichard Henderson .fn_die = 2, 66985872bbf2SRichard Henderson .fn_name = "code_gen_buffer" 66995872bbf2SRichard Henderson }, 67005872bbf2SRichard Henderson .da = { 67015872bbf2SRichard Henderson 1, /* abbrev number (the cu) */ 67025872bbf2SRichard Henderson 0x11, 1, /* DW_TAG_compile_unit, has children */ 67035872bbf2SRichard Henderson 0x13, 0x5, /* DW_AT_language, DW_FORM_data2 */ 67045872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */ 67055872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */ 67065872bbf2SRichard Henderson 0, 0, /* end of abbrev */ 67075872bbf2SRichard Henderson 2, /* abbrev number (the fn) */ 67085872bbf2SRichard Henderson 0x2e, 0, /* DW_TAG_subprogram, no children */ 67095872bbf2SRichard Henderson 0x3, 0x8, /* DW_AT_name, DW_FORM_string */ 67105872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */ 67115872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */ 67125872bbf2SRichard Henderson 0, 0, /* end of abbrev */ 67135872bbf2SRichard Henderson 0 /* no more abbrev */ 67145872bbf2SRichard Henderson }, 67155872bbf2SRichard Henderson .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0" 67165872bbf2SRichard Henderson ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer", 6717813da627SRichard Henderson }; 6718813da627SRichard Henderson 6719813da627SRichard Henderson /* We only need a single jit entry; statically allocate it. */ 6720813da627SRichard Henderson static struct jit_code_entry one_entry; 6721813da627SRichard Henderson 67225872bbf2SRichard Henderson uintptr_t buf = (uintptr_t)buf_ptr; 6723813da627SRichard Henderson size_t img_size = sizeof(struct ElfImage) + debug_frame_size; 67242c90784aSRichard Henderson DebugFrameHeader *dfh; 6725813da627SRichard Henderson 67265872bbf2SRichard Henderson img = g_malloc(img_size); 67275872bbf2SRichard Henderson *img = img_template; 6728813da627SRichard Henderson 67295872bbf2SRichard Henderson img->phdr.p_vaddr = buf; 67305872bbf2SRichard Henderson img->phdr.p_paddr = buf; 67315872bbf2SRichard Henderson img->phdr.p_memsz = buf_size; 6732813da627SRichard Henderson 67335872bbf2SRichard Henderson img->shdr[1].sh_name = find_string(img->str, ".text"); 67345872bbf2SRichard Henderson img->shdr[1].sh_addr = buf; 67355872bbf2SRichard Henderson img->shdr[1].sh_size = buf_size; 6736813da627SRichard Henderson 67375872bbf2SRichard Henderson img->shdr[2].sh_name = find_string(img->str, ".debug_info"); 67385872bbf2SRichard Henderson img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev"); 67395872bbf2SRichard Henderson 67405872bbf2SRichard Henderson img->shdr[4].sh_name = find_string(img->str, ".debug_frame"); 67415872bbf2SRichard Henderson img->shdr[4].sh_size = debug_frame_size; 67425872bbf2SRichard Henderson 67435872bbf2SRichard Henderson img->shdr[5].sh_name = find_string(img->str, ".symtab"); 67445872bbf2SRichard Henderson img->shdr[6].sh_name = find_string(img->str, ".strtab"); 67455872bbf2SRichard Henderson 67465872bbf2SRichard Henderson img->sym[1].st_name = find_string(img->str, "code_gen_buffer"); 67475872bbf2SRichard Henderson img->sym[1].st_value = buf; 67485872bbf2SRichard Henderson img->sym[1].st_size = buf_size; 67495872bbf2SRichard Henderson 67505872bbf2SRichard Henderson img->di.cu_low_pc = buf; 675145aba097SRichard Henderson img->di.cu_high_pc = buf + buf_size; 67525872bbf2SRichard Henderson img->di.fn_low_pc = buf; 675345aba097SRichard Henderson img->di.fn_high_pc = buf + buf_size; 6754813da627SRichard Henderson 67552c90784aSRichard Henderson dfh = (DebugFrameHeader *)(img + 1); 67562c90784aSRichard Henderson memcpy(dfh, debug_frame, debug_frame_size); 67572c90784aSRichard Henderson dfh->fde.func_start = buf; 67582c90784aSRichard Henderson dfh->fde.func_len = buf_size; 67592c90784aSRichard Henderson 6760813da627SRichard Henderson #ifdef DEBUG_JIT 6761813da627SRichard Henderson /* Enable this block to be able to debug the ELF image file creation. 6762813da627SRichard Henderson One can use readelf, objdump, or other inspection utilities. */ 6763813da627SRichard Henderson { 6764eb6b2edfSBin Meng g_autofree char *jit = g_strdup_printf("%s/qemu.jit", g_get_tmp_dir()); 6765eb6b2edfSBin Meng FILE *f = fopen(jit, "w+b"); 6766813da627SRichard Henderson if (f) { 67675872bbf2SRichard Henderson if (fwrite(img, img_size, 1, f) != img_size) { 6768813da627SRichard Henderson /* Avoid stupid unused return value warning for fwrite. */ 6769813da627SRichard Henderson } 6770813da627SRichard Henderson fclose(f); 6771813da627SRichard Henderson } 6772813da627SRichard Henderson } 6773813da627SRichard Henderson #endif 6774813da627SRichard Henderson 6775813da627SRichard Henderson one_entry.symfile_addr = img; 6776813da627SRichard Henderson one_entry.symfile_size = img_size; 6777813da627SRichard Henderson 6778813da627SRichard Henderson __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; 6779813da627SRichard Henderson __jit_debug_descriptor.relevant_entry = &one_entry; 6780813da627SRichard Henderson __jit_debug_descriptor.first_entry = &one_entry; 6781813da627SRichard Henderson __jit_debug_register_code(); 6782813da627SRichard Henderson } 6783813da627SRichard Henderson #else 67845872bbf2SRichard Henderson /* No support for the feature. Provide the entry point expected by exec.c, 67855872bbf2SRichard Henderson and implement the internal function we declared earlier. */ 6786813da627SRichard Henderson 6787755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size, 67882c90784aSRichard Henderson const void *debug_frame, 67892c90784aSRichard Henderson size_t debug_frame_size) 6790813da627SRichard Henderson { 6791813da627SRichard Henderson } 6792813da627SRichard Henderson 6793755bf9e5SRichard Henderson void tcg_register_jit(const void *buf, size_t buf_size) 6794813da627SRichard Henderson { 6795813da627SRichard Henderson } 6796813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */ 6797db432672SRichard Henderson 6798db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec 6799db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...) 6800db432672SRichard Henderson { 6801db432672SRichard Henderson g_assert_not_reached(); 6802db432672SRichard Henderson } 6803db432672SRichard Henderson #endif 6804