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); 1374e350091SRichard 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 s->pool_labels = NULL; 16025b38ee31SRichard Henderson 1603653b87ebSRoman Bolshakov qemu_thread_jit_write(); 16048163b749SRichard Henderson /* Generate the prologue. */ 1605b03cce8eSbellard tcg_target_qemu_prologue(s); 16065b38ee31SRichard Henderson 16075b38ee31SRichard Henderson /* Allow the prologue to put e.g. guest_base into a pool entry. */ 16085b38ee31SRichard Henderson { 16091768987bSRichard Henderson int result = tcg_out_pool_finalize(s); 16101768987bSRichard Henderson tcg_debug_assert(result == 0); 16115b38ee31SRichard Henderson } 16125b38ee31SRichard Henderson 1613b0a0794aSRichard Henderson prologue_size = tcg_current_code_size(s); 16145584e2dbSIlya Leoshkevich perf_report_prologue(s->code_gen_ptr, prologue_size); 1615b0a0794aSRichard Henderson 1616df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 1617b0a0794aSRichard Henderson flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf), 1618b0a0794aSRichard Henderson (uintptr_t)s->code_buf, prologue_size); 1619df5d2b16SRichard Henderson #endif 16208163b749SRichard Henderson 1621d6b64b2bSRichard Henderson if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) { 1622c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock(); 162378b54858SRichard Henderson if (logfile) { 162478b54858SRichard Henderson fprintf(logfile, "PROLOGUE: [size=%zu]\n", prologue_size); 16255b38ee31SRichard Henderson if (s->data_gen_ptr) { 1626b0a0794aSRichard Henderson size_t code_size = s->data_gen_ptr - s->code_gen_ptr; 16275b38ee31SRichard Henderson size_t data_size = prologue_size - code_size; 16285b38ee31SRichard Henderson size_t i; 16295b38ee31SRichard Henderson 163078b54858SRichard Henderson disas(logfile, s->code_gen_ptr, code_size); 16315b38ee31SRichard Henderson 16325b38ee31SRichard Henderson for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) { 16335b38ee31SRichard Henderson if (sizeof(tcg_target_ulong) == 8) { 163478b54858SRichard Henderson fprintf(logfile, 163578b54858SRichard Henderson "0x%08" PRIxPTR ": .quad 0x%016" PRIx64 "\n", 16365b38ee31SRichard Henderson (uintptr_t)s->data_gen_ptr + i, 16375b38ee31SRichard Henderson *(uint64_t *)(s->data_gen_ptr + i)); 16385b38ee31SRichard Henderson } else { 163978b54858SRichard Henderson fprintf(logfile, 164078b54858SRichard Henderson "0x%08" PRIxPTR ": .long 0x%08x\n", 16415b38ee31SRichard Henderson (uintptr_t)s->data_gen_ptr + i, 16425b38ee31SRichard Henderson *(uint32_t *)(s->data_gen_ptr + i)); 16435b38ee31SRichard Henderson } 16445b38ee31SRichard Henderson } 16455b38ee31SRichard Henderson } else { 164678b54858SRichard Henderson disas(logfile, s->code_gen_ptr, prologue_size); 16475b38ee31SRichard Henderson } 164878b54858SRichard Henderson fprintf(logfile, "\n"); 1649fc59d2d8SRobert Foley qemu_log_unlock(logfile); 1650d6b64b2bSRichard Henderson } 165178b54858SRichard Henderson } 1652cedbcb01SEmilio G. Cota 16536eea0434SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 16546eea0434SRichard Henderson /* 16556eea0434SRichard Henderson * Assert that goto_ptr is implemented completely, setting an epilogue. 16566eea0434SRichard Henderson * For tci, we use NULL as the signal to return from the interpreter, 16576eea0434SRichard Henderson * so skip this check. 16586eea0434SRichard Henderson */ 16598b5c2b62SRichard Henderson tcg_debug_assert(tcg_code_gen_epilogue != NULL); 16606eea0434SRichard Henderson #endif 1661d1c74ab3SRichard Henderson 1662d1c74ab3SRichard Henderson tcg_region_prologue_set(s); 1663c896fe29Sbellard } 1664c896fe29Sbellard 1665c896fe29Sbellard void tcg_func_start(TCGContext *s) 1666c896fe29Sbellard { 1667c896fe29Sbellard tcg_pool_reset(s); 1668c896fe29Sbellard s->nb_temps = s->nb_globals; 16690ec9eabcSRichard Henderson 16700ec9eabcSRichard Henderson /* No temps have been previously allocated for size or locality. */ 167104e006abSRichard Henderson tcg_temp_ebb_reset_freed(s); 16720ec9eabcSRichard Henderson 1673c0522136SRichard Henderson /* No constant temps have been previously allocated. */ 1674c0522136SRichard Henderson for (int i = 0; i < TCG_TYPE_COUNT; ++i) { 1675c0522136SRichard Henderson if (s->const_table[i]) { 1676c0522136SRichard Henderson g_hash_table_remove_all(s->const_table[i]); 1677c0522136SRichard Henderson } 1678c0522136SRichard Henderson } 1679c0522136SRichard Henderson 1680abebf925SRichard Henderson s->nb_ops = 0; 1681c896fe29Sbellard s->nb_labels = 0; 1682c896fe29Sbellard s->current_frame_offset = s->frame_start; 1683c896fe29Sbellard 16840a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG 16850a209d4bSRichard Henderson s->goto_tb_issue_mask = 0; 16860a209d4bSRichard Henderson #endif 16870a209d4bSRichard Henderson 168815fa08f8SRichard Henderson QTAILQ_INIT(&s->ops); 168915fa08f8SRichard Henderson QTAILQ_INIT(&s->free_ops); 169007843f75SRichard Henderson s->emit_before_op = NULL; 1691bef16ab4SRichard Henderson QSIMPLEQ_INIT(&s->labels); 16924baf3978SRichard Henderson 1693a0ecb8e4SRichard Henderson tcg_debug_assert(s->addr_type <= TCG_TYPE_REG); 1694747bd69dSRichard Henderson tcg_debug_assert(s->insn_start_words > 0); 1695c896fe29Sbellard } 1696c896fe29Sbellard 1697ae30e866SRichard Henderson static TCGTemp *tcg_temp_alloc(TCGContext *s) 16987ca4b752SRichard Henderson { 16997ca4b752SRichard Henderson int n = s->nb_temps++; 1700ae30e866SRichard Henderson 1701ae30e866SRichard Henderson if (n >= TCG_MAX_TEMPS) { 1702db6b7d0cSRichard Henderson tcg_raise_tb_overflow(s); 1703ae30e866SRichard Henderson } 17047ca4b752SRichard Henderson return memset(&s->temps[n], 0, sizeof(TCGTemp)); 17057ca4b752SRichard Henderson } 17067ca4b752SRichard Henderson 1707ae30e866SRichard Henderson static TCGTemp *tcg_global_alloc(TCGContext *s) 17087ca4b752SRichard Henderson { 1709fa477d25SRichard Henderson TCGTemp *ts; 1710fa477d25SRichard Henderson 17117ca4b752SRichard Henderson tcg_debug_assert(s->nb_globals == s->nb_temps); 1712ae30e866SRichard Henderson tcg_debug_assert(s->nb_globals < TCG_MAX_TEMPS); 17137ca4b752SRichard Henderson s->nb_globals++; 1714fa477d25SRichard Henderson ts = tcg_temp_alloc(s); 1715ee17db83SRichard Henderson ts->kind = TEMP_GLOBAL; 1716fa477d25SRichard Henderson 1717fa477d25SRichard Henderson return ts; 1718c896fe29Sbellard } 1719c896fe29Sbellard 1720085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type, 1721b6638662SRichard Henderson TCGReg reg, const char *name) 1722c896fe29Sbellard { 1723c896fe29Sbellard TCGTemp *ts; 1724c896fe29Sbellard 17251a057554SRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 64 || type == TCG_TYPE_I32); 17267ca4b752SRichard Henderson 17277ca4b752SRichard Henderson ts = tcg_global_alloc(s); 1728c896fe29Sbellard ts->base_type = type; 1729c896fe29Sbellard ts->type = type; 1730ee17db83SRichard Henderson ts->kind = TEMP_FIXED; 1731c896fe29Sbellard ts->reg = reg; 1732c896fe29Sbellard ts->name = name; 1733c896fe29Sbellard tcg_regset_set_reg(s->reserved_regs, reg); 17347ca4b752SRichard Henderson 1735085272b3SRichard Henderson return ts; 1736a7812ae4Spbrook } 1737a7812ae4Spbrook 1738b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size) 1739a7812ae4Spbrook { 1740b3a62939SRichard Henderson s->frame_start = start; 1741b3a62939SRichard Henderson s->frame_end = start + size; 1742085272b3SRichard Henderson s->frame_temp 1743085272b3SRichard Henderson = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame"); 1744b3a62939SRichard Henderson } 1745a7812ae4Spbrook 17464643f3e0SRichard Henderson static TCGTemp *tcg_global_mem_new_internal(TCGv_ptr base, intptr_t offset, 17474643f3e0SRichard Henderson const char *name, TCGType type) 1748c896fe29Sbellard { 1749b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1750dc41aa7dSRichard Henderson TCGTemp *base_ts = tcgv_ptr_temp(base); 17517ca4b752SRichard Henderson TCGTemp *ts = tcg_global_alloc(s); 1752aef85402SRichard Henderson int indirect_reg = 0; 1753c896fe29Sbellard 1754c0522136SRichard Henderson switch (base_ts->kind) { 1755c0522136SRichard Henderson case TEMP_FIXED: 1756c0522136SRichard Henderson break; 1757c0522136SRichard Henderson case TEMP_GLOBAL: 17585a18407fSRichard Henderson /* We do not support double-indirect registers. */ 17595a18407fSRichard Henderson tcg_debug_assert(!base_ts->indirect_reg); 1760b3915dbbSRichard Henderson base_ts->indirect_base = 1; 17615a18407fSRichard Henderson s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64 17625a18407fSRichard Henderson ? 2 : 1); 17635a18407fSRichard Henderson indirect_reg = 1; 1764c0522136SRichard Henderson break; 1765c0522136SRichard Henderson default: 1766c0522136SRichard Henderson g_assert_not_reached(); 1767b3915dbbSRichard Henderson } 1768b3915dbbSRichard Henderson 17697ca4b752SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { 17707ca4b752SRichard Henderson TCGTemp *ts2 = tcg_global_alloc(s); 1771c896fe29Sbellard char buf[64]; 17727ca4b752SRichard Henderson 17737ca4b752SRichard Henderson ts->base_type = TCG_TYPE_I64; 1774c896fe29Sbellard ts->type = TCG_TYPE_I32; 1775b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg; 1776c896fe29Sbellard ts->mem_allocated = 1; 1777b3a62939SRichard Henderson ts->mem_base = base_ts; 1778aef85402SRichard Henderson ts->mem_offset = offset; 1779c896fe29Sbellard pstrcpy(buf, sizeof(buf), name); 1780c896fe29Sbellard pstrcat(buf, sizeof(buf), "_0"); 1781c896fe29Sbellard ts->name = strdup(buf); 1782c896fe29Sbellard 17837ca4b752SRichard Henderson tcg_debug_assert(ts2 == ts + 1); 17847ca4b752SRichard Henderson ts2->base_type = TCG_TYPE_I64; 17857ca4b752SRichard Henderson ts2->type = TCG_TYPE_I32; 1786b3915dbbSRichard Henderson ts2->indirect_reg = indirect_reg; 17877ca4b752SRichard Henderson ts2->mem_allocated = 1; 17887ca4b752SRichard Henderson ts2->mem_base = base_ts; 1789aef85402SRichard Henderson ts2->mem_offset = offset + 4; 1790fac87bd2SRichard Henderson ts2->temp_subindex = 1; 1791c896fe29Sbellard pstrcpy(buf, sizeof(buf), name); 1792c896fe29Sbellard pstrcat(buf, sizeof(buf), "_1"); 1793120c1084SRichard Henderson ts2->name = strdup(buf); 17947ca4b752SRichard Henderson } else { 1795c896fe29Sbellard ts->base_type = type; 1796c896fe29Sbellard ts->type = type; 1797b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg; 1798c896fe29Sbellard ts->mem_allocated = 1; 1799b3a62939SRichard Henderson ts->mem_base = base_ts; 1800c896fe29Sbellard ts->mem_offset = offset; 1801c896fe29Sbellard ts->name = name; 1802c896fe29Sbellard } 1803085272b3SRichard Henderson return ts; 1804c896fe29Sbellard } 1805c896fe29Sbellard 18064643f3e0SRichard Henderson TCGv_i32 tcg_global_mem_new_i32(TCGv_ptr reg, intptr_t off, const char *name) 18074643f3e0SRichard Henderson { 18084643f3e0SRichard Henderson TCGTemp *ts = tcg_global_mem_new_internal(reg, off, name, TCG_TYPE_I32); 18094643f3e0SRichard Henderson return temp_tcgv_i32(ts); 18104643f3e0SRichard Henderson } 18114643f3e0SRichard Henderson 18124643f3e0SRichard Henderson TCGv_i64 tcg_global_mem_new_i64(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_I64); 18154643f3e0SRichard Henderson return temp_tcgv_i64(ts); 18164643f3e0SRichard Henderson } 18174643f3e0SRichard Henderson 18184643f3e0SRichard Henderson TCGv_ptr tcg_global_mem_new_ptr(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_PTR); 18214643f3e0SRichard Henderson return temp_tcgv_ptr(ts); 18224643f3e0SRichard Henderson } 18234643f3e0SRichard Henderson 1824fb04ab7dSRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, TCGTempKind kind) 1825c896fe29Sbellard { 1826b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1827c896fe29Sbellard TCGTemp *ts; 1828e1c08b00SRichard Henderson int n; 1829c896fe29Sbellard 1830e1c08b00SRichard Henderson if (kind == TEMP_EBB) { 1831e1c08b00SRichard Henderson int idx = find_first_bit(s->free_temps[type].l, TCG_MAX_TEMPS); 1832e1c08b00SRichard Henderson 18330ec9eabcSRichard Henderson if (idx < TCG_MAX_TEMPS) { 18340ec9eabcSRichard Henderson /* There is already an available temp with the right type. */ 1835e1c08b00SRichard Henderson clear_bit(idx, s->free_temps[type].l); 18360ec9eabcSRichard Henderson 1837e8996ee0Sbellard ts = &s->temps[idx]; 1838e8996ee0Sbellard ts->temp_allocated = 1; 18397ca4b752SRichard Henderson tcg_debug_assert(ts->base_type == type); 1840ee17db83SRichard Henderson tcg_debug_assert(ts->kind == kind); 18412f2e911dSRichard Henderson return ts; 1842e1c08b00SRichard Henderson } 1843e8996ee0Sbellard } else { 1844e1c08b00SRichard Henderson tcg_debug_assert(kind == TEMP_TB); 1845e1c08b00SRichard Henderson } 184643eef72fSRichard Henderson 184743eef72fSRichard Henderson switch (type) { 184843eef72fSRichard Henderson case TCG_TYPE_I32: 184943eef72fSRichard Henderson case TCG_TYPE_V64: 185043eef72fSRichard Henderson case TCG_TYPE_V128: 185143eef72fSRichard Henderson case TCG_TYPE_V256: 185243eef72fSRichard Henderson n = 1; 185343eef72fSRichard Henderson break; 185443eef72fSRichard Henderson case TCG_TYPE_I64: 185543eef72fSRichard Henderson n = 64 / TCG_TARGET_REG_BITS; 185643eef72fSRichard Henderson break; 185743eef72fSRichard Henderson case TCG_TYPE_I128: 185843eef72fSRichard Henderson n = 128 / TCG_TARGET_REG_BITS; 185943eef72fSRichard Henderson break; 186043eef72fSRichard Henderson default: 186143eef72fSRichard Henderson g_assert_not_reached(); 186243eef72fSRichard Henderson } 186343eef72fSRichard Henderson 18647ca4b752SRichard Henderson ts = tcg_temp_alloc(s); 186543eef72fSRichard Henderson ts->base_type = type; 186643eef72fSRichard Henderson ts->temp_allocated = 1; 186743eef72fSRichard Henderson ts->kind = kind; 186843eef72fSRichard Henderson 186943eef72fSRichard Henderson if (n == 1) { 187043eef72fSRichard Henderson ts->type = type; 187143eef72fSRichard Henderson } else { 187243eef72fSRichard Henderson ts->type = TCG_TYPE_REG; 187343eef72fSRichard Henderson 1874e1c08b00SRichard Henderson for (int i = 1; i < n; ++i) { 18757ca4b752SRichard Henderson TCGTemp *ts2 = tcg_temp_alloc(s); 18767ca4b752SRichard Henderson 187743eef72fSRichard Henderson tcg_debug_assert(ts2 == ts + i); 187843eef72fSRichard Henderson ts2->base_type = type; 187943eef72fSRichard Henderson ts2->type = TCG_TYPE_REG; 18807ca4b752SRichard Henderson ts2->temp_allocated = 1; 188143eef72fSRichard Henderson ts2->temp_subindex = i; 1882ee17db83SRichard Henderson ts2->kind = kind; 188343eef72fSRichard Henderson } 1884c896fe29Sbellard } 1885085272b3SRichard Henderson return ts; 1886c896fe29Sbellard } 1887c896fe29Sbellard 18884643f3e0SRichard Henderson TCGv_i32 tcg_temp_new_i32(void) 18894643f3e0SRichard Henderson { 18904643f3e0SRichard Henderson return temp_tcgv_i32(tcg_temp_new_internal(TCG_TYPE_I32, TEMP_TB)); 18914643f3e0SRichard Henderson } 18924643f3e0SRichard Henderson 18934643f3e0SRichard Henderson TCGv_i32 tcg_temp_ebb_new_i32(void) 18944643f3e0SRichard Henderson { 18954643f3e0SRichard Henderson return temp_tcgv_i32(tcg_temp_new_internal(TCG_TYPE_I32, TEMP_EBB)); 18964643f3e0SRichard Henderson } 18974643f3e0SRichard Henderson 18984643f3e0SRichard Henderson TCGv_i64 tcg_temp_new_i64(void) 18994643f3e0SRichard Henderson { 19004643f3e0SRichard Henderson return temp_tcgv_i64(tcg_temp_new_internal(TCG_TYPE_I64, TEMP_TB)); 19014643f3e0SRichard Henderson } 19024643f3e0SRichard Henderson 19034643f3e0SRichard Henderson TCGv_i64 tcg_temp_ebb_new_i64(void) 19044643f3e0SRichard Henderson { 19054643f3e0SRichard Henderson return temp_tcgv_i64(tcg_temp_new_internal(TCG_TYPE_I64, TEMP_EBB)); 19064643f3e0SRichard Henderson } 19074643f3e0SRichard Henderson 19084643f3e0SRichard Henderson TCGv_ptr tcg_temp_new_ptr(void) 19094643f3e0SRichard Henderson { 19104643f3e0SRichard Henderson return temp_tcgv_ptr(tcg_temp_new_internal(TCG_TYPE_PTR, TEMP_TB)); 19114643f3e0SRichard Henderson } 19124643f3e0SRichard Henderson 19134643f3e0SRichard Henderson TCGv_ptr tcg_temp_ebb_new_ptr(void) 19144643f3e0SRichard Henderson { 19154643f3e0SRichard Henderson return temp_tcgv_ptr(tcg_temp_new_internal(TCG_TYPE_PTR, TEMP_EBB)); 19164643f3e0SRichard Henderson } 19174643f3e0SRichard Henderson 19184643f3e0SRichard Henderson TCGv_i128 tcg_temp_new_i128(void) 19194643f3e0SRichard Henderson { 19204643f3e0SRichard Henderson return temp_tcgv_i128(tcg_temp_new_internal(TCG_TYPE_I128, TEMP_TB)); 19214643f3e0SRichard Henderson } 19224643f3e0SRichard Henderson 19234643f3e0SRichard Henderson TCGv_i128 tcg_temp_ebb_new_i128(void) 19244643f3e0SRichard Henderson { 19254643f3e0SRichard Henderson return temp_tcgv_i128(tcg_temp_new_internal(TCG_TYPE_I128, TEMP_EBB)); 19264643f3e0SRichard Henderson } 19274643f3e0SRichard Henderson 1928d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type) 1929d2fd745fSRichard Henderson { 1930d2fd745fSRichard Henderson TCGTemp *t; 1931d2fd745fSRichard Henderson 1932d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG 1933d2fd745fSRichard Henderson switch (type) { 1934d2fd745fSRichard Henderson case TCG_TYPE_V64: 1935d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v64); 1936d2fd745fSRichard Henderson break; 1937d2fd745fSRichard Henderson case TCG_TYPE_V128: 1938d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v128); 1939d2fd745fSRichard Henderson break; 1940d2fd745fSRichard Henderson case TCG_TYPE_V256: 1941d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v256); 1942d2fd745fSRichard Henderson break; 1943d2fd745fSRichard Henderson default: 1944d2fd745fSRichard Henderson g_assert_not_reached(); 1945d2fd745fSRichard Henderson } 1946d2fd745fSRichard Henderson #endif 1947d2fd745fSRichard Henderson 1948bbf989bfSRichard Henderson t = tcg_temp_new_internal(type, TEMP_EBB); 1949d2fd745fSRichard Henderson return temp_tcgv_vec(t); 1950d2fd745fSRichard Henderson } 1951d2fd745fSRichard Henderson 1952d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp. */ 1953d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match) 1954d2fd745fSRichard Henderson { 1955d2fd745fSRichard Henderson TCGTemp *t = tcgv_vec_temp(match); 1956d2fd745fSRichard Henderson 1957d2fd745fSRichard Henderson tcg_debug_assert(t->temp_allocated != 0); 1958d2fd745fSRichard Henderson 1959bbf989bfSRichard Henderson t = tcg_temp_new_internal(t->base_type, TEMP_EBB); 1960d2fd745fSRichard Henderson return temp_tcgv_vec(t); 1961d2fd745fSRichard Henderson } 1962d2fd745fSRichard Henderson 19635bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts) 1964c896fe29Sbellard { 1965b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1966c896fe29Sbellard 1967c7482438SRichard Henderson switch (ts->kind) { 1968c7482438SRichard Henderson case TEMP_CONST: 1969f57c6915SRichard Henderson case TEMP_TB: 19702f2e911dSRichard Henderson /* Silently ignore free. */ 1971c7482438SRichard Henderson break; 19722f2e911dSRichard Henderson case TEMP_EBB: 1973eabb7b91SAurelien Jarno tcg_debug_assert(ts->temp_allocated != 0); 1974e8996ee0Sbellard ts->temp_allocated = 0; 19752f2e911dSRichard Henderson set_bit(temp_idx(ts), s->free_temps[ts->base_type].l); 19762f2e911dSRichard Henderson break; 19772f2e911dSRichard Henderson default: 19782f2e911dSRichard Henderson /* It never made sense to free TEMP_FIXED or TEMP_GLOBAL. */ 19792f2e911dSRichard Henderson g_assert_not_reached(); 1980e1c08b00SRichard Henderson } 1981e8996ee0Sbellard } 1982e8996ee0Sbellard 198358b79713SRichard Henderson void tcg_temp_free_i32(TCGv_i32 arg) 198458b79713SRichard Henderson { 198558b79713SRichard Henderson tcg_temp_free_internal(tcgv_i32_temp(arg)); 198658b79713SRichard Henderson } 198758b79713SRichard Henderson 198858b79713SRichard Henderson void tcg_temp_free_i64(TCGv_i64 arg) 198958b79713SRichard Henderson { 199058b79713SRichard Henderson tcg_temp_free_internal(tcgv_i64_temp(arg)); 199158b79713SRichard Henderson } 199258b79713SRichard Henderson 199358b79713SRichard Henderson void tcg_temp_free_i128(TCGv_i128 arg) 199458b79713SRichard Henderson { 199558b79713SRichard Henderson tcg_temp_free_internal(tcgv_i128_temp(arg)); 199658b79713SRichard Henderson } 199758b79713SRichard Henderson 199858b79713SRichard Henderson void tcg_temp_free_ptr(TCGv_ptr arg) 199958b79713SRichard Henderson { 200058b79713SRichard Henderson tcg_temp_free_internal(tcgv_ptr_temp(arg)); 200158b79713SRichard Henderson } 200258b79713SRichard Henderson 200358b79713SRichard Henderson void tcg_temp_free_vec(TCGv_vec arg) 200458b79713SRichard Henderson { 200558b79713SRichard Henderson tcg_temp_free_internal(tcgv_vec_temp(arg)); 200658b79713SRichard Henderson } 200758b79713SRichard Henderson 2008c0522136SRichard Henderson TCGTemp *tcg_constant_internal(TCGType type, int64_t val) 2009c0522136SRichard Henderson { 2010c0522136SRichard Henderson TCGContext *s = tcg_ctx; 2011c0522136SRichard Henderson GHashTable *h = s->const_table[type]; 2012c0522136SRichard Henderson TCGTemp *ts; 2013c0522136SRichard Henderson 2014c0522136SRichard Henderson if (h == NULL) { 2015c0522136SRichard Henderson h = g_hash_table_new(g_int64_hash, g_int64_equal); 2016c0522136SRichard Henderson s->const_table[type] = h; 2017c0522136SRichard Henderson } 2018c0522136SRichard Henderson 2019c0522136SRichard Henderson ts = g_hash_table_lookup(h, &val); 2020c0522136SRichard Henderson if (ts == NULL) { 2021aef85402SRichard Henderson int64_t *val_ptr; 2022aef85402SRichard Henderson 2023c0522136SRichard Henderson ts = tcg_temp_alloc(s); 2024c0522136SRichard Henderson 2025c0522136SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { 2026c0522136SRichard Henderson TCGTemp *ts2 = tcg_temp_alloc(s); 2027c0522136SRichard Henderson 2028aef85402SRichard Henderson tcg_debug_assert(ts2 == ts + 1); 2029aef85402SRichard Henderson 2030c0522136SRichard Henderson ts->base_type = TCG_TYPE_I64; 2031c0522136SRichard Henderson ts->type = TCG_TYPE_I32; 2032c0522136SRichard Henderson ts->kind = TEMP_CONST; 2033c0522136SRichard Henderson ts->temp_allocated = 1; 2034c0522136SRichard Henderson 2035c0522136SRichard Henderson ts2->base_type = TCG_TYPE_I64; 2036c0522136SRichard Henderson ts2->type = TCG_TYPE_I32; 2037c0522136SRichard Henderson ts2->kind = TEMP_CONST; 2038c0522136SRichard Henderson ts2->temp_allocated = 1; 2039fac87bd2SRichard Henderson ts2->temp_subindex = 1; 2040aef85402SRichard Henderson 2041aef85402SRichard Henderson /* 2042aef85402SRichard Henderson * Retain the full value of the 64-bit constant in the low 2043aef85402SRichard Henderson * part, so that the hash table works. Actual uses will 2044aef85402SRichard Henderson * truncate the value to the low part. 2045aef85402SRichard Henderson */ 2046aef85402SRichard Henderson ts[HOST_BIG_ENDIAN].val = val; 2047aef85402SRichard Henderson ts[!HOST_BIG_ENDIAN].val = val >> 32; 2048aef85402SRichard Henderson val_ptr = &ts[HOST_BIG_ENDIAN].val; 2049c0522136SRichard Henderson } else { 2050c0522136SRichard Henderson ts->base_type = type; 2051c0522136SRichard Henderson ts->type = type; 2052c0522136SRichard Henderson ts->kind = TEMP_CONST; 2053c0522136SRichard Henderson ts->temp_allocated = 1; 2054c0522136SRichard Henderson ts->val = val; 2055aef85402SRichard Henderson val_ptr = &ts->val; 2056c0522136SRichard Henderson } 2057aef85402SRichard Henderson g_hash_table_insert(h, val_ptr, ts); 2058c0522136SRichard Henderson } 2059c0522136SRichard Henderson 2060c0522136SRichard Henderson return ts; 2061c0522136SRichard Henderson } 2062c0522136SRichard Henderson 206316edaee7SRichard Henderson TCGv_i32 tcg_constant_i32(int32_t val) 206416edaee7SRichard Henderson { 206516edaee7SRichard Henderson return temp_tcgv_i32(tcg_constant_internal(TCG_TYPE_I32, val)); 206616edaee7SRichard Henderson } 206716edaee7SRichard Henderson 206816edaee7SRichard Henderson TCGv_i64 tcg_constant_i64(int64_t val) 206916edaee7SRichard Henderson { 207016edaee7SRichard Henderson return temp_tcgv_i64(tcg_constant_internal(TCG_TYPE_I64, val)); 207116edaee7SRichard Henderson } 207216edaee7SRichard Henderson 207316edaee7SRichard Henderson TCGv_ptr tcg_constant_ptr_int(intptr_t val) 207416edaee7SRichard Henderson { 207516edaee7SRichard Henderson return temp_tcgv_ptr(tcg_constant_internal(TCG_TYPE_PTR, val)); 207616edaee7SRichard Henderson } 207716edaee7SRichard Henderson 2078c0522136SRichard Henderson TCGv_vec tcg_constant_vec(TCGType type, unsigned vece, int64_t val) 2079c0522136SRichard Henderson { 2080c0522136SRichard Henderson val = dup_const(vece, val); 2081c0522136SRichard Henderson return temp_tcgv_vec(tcg_constant_internal(type, val)); 2082c0522136SRichard Henderson } 2083c0522136SRichard Henderson 208488d4005bSRichard Henderson TCGv_vec tcg_constant_vec_matching(TCGv_vec match, unsigned vece, int64_t val) 208588d4005bSRichard Henderson { 208688d4005bSRichard Henderson TCGTemp *t = tcgv_vec_temp(match); 208788d4005bSRichard Henderson 208888d4005bSRichard Henderson tcg_debug_assert(t->temp_allocated != 0); 208988d4005bSRichard Henderson return tcg_constant_vec(t->base_type, vece, val); 209088d4005bSRichard Henderson } 209188d4005bSRichard Henderson 2092177f648fSRichard Henderson #ifdef CONFIG_DEBUG_TCG 2093177f648fSRichard Henderson size_t temp_idx(TCGTemp *ts) 2094177f648fSRichard Henderson { 2095177f648fSRichard Henderson ptrdiff_t n = ts - tcg_ctx->temps; 2096177f648fSRichard Henderson assert(n >= 0 && n < tcg_ctx->nb_temps); 2097177f648fSRichard Henderson return n; 2098177f648fSRichard Henderson } 2099177f648fSRichard Henderson 2100177f648fSRichard Henderson TCGTemp *tcgv_i32_temp(TCGv_i32 v) 2101177f648fSRichard Henderson { 2102177f648fSRichard Henderson uintptr_t o = (uintptr_t)v - offsetof(TCGContext, temps); 2103177f648fSRichard Henderson 2104177f648fSRichard Henderson assert(o < sizeof(TCGTemp) * tcg_ctx->nb_temps); 2105177f648fSRichard Henderson assert(o % sizeof(TCGTemp) == 0); 2106177f648fSRichard Henderson 2107177f648fSRichard Henderson return (void *)tcg_ctx + (uintptr_t)v; 2108177f648fSRichard Henderson } 2109177f648fSRichard Henderson #endif /* CONFIG_DEBUG_TCG */ 2110177f648fSRichard Henderson 2111771a5925SRichard Henderson /* 2112771a5925SRichard Henderson * Return true if OP may appear in the opcode stream with TYPE. 2113771a5925SRichard Henderson * Test the runtime variable that controls each opcode. 2114771a5925SRichard Henderson */ 2115771a5925SRichard Henderson bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) 2116be0f34b5SRichard Henderson { 2117f44824ccSRichard Henderson bool has_type; 2118f44824ccSRichard Henderson 2119f44824ccSRichard Henderson switch (type) { 2120f44824ccSRichard Henderson case TCG_TYPE_I32: 2121f44824ccSRichard Henderson has_type = true; 2122f44824ccSRichard Henderson break; 2123f44824ccSRichard Henderson case TCG_TYPE_I64: 2124f44824ccSRichard Henderson has_type = TCG_TARGET_REG_BITS == 64; 2125f44824ccSRichard Henderson break; 2126f44824ccSRichard Henderson case TCG_TYPE_V64: 2127f44824ccSRichard Henderson has_type = TCG_TARGET_HAS_v64; 2128f44824ccSRichard Henderson break; 2129f44824ccSRichard Henderson case TCG_TYPE_V128: 2130f44824ccSRichard Henderson has_type = TCG_TARGET_HAS_v128; 2131f44824ccSRichard Henderson break; 2132f44824ccSRichard Henderson case TCG_TYPE_V256: 2133f44824ccSRichard Henderson has_type = TCG_TARGET_HAS_v256; 2134f44824ccSRichard Henderson break; 2135f44824ccSRichard Henderson default: 2136f44824ccSRichard Henderson has_type = false; 2137f44824ccSRichard Henderson break; 2138f44824ccSRichard Henderson } 2139d2fd745fSRichard Henderson 2140be0f34b5SRichard Henderson switch (op) { 2141be0f34b5SRichard Henderson case INDEX_op_discard: 2142be0f34b5SRichard Henderson case INDEX_op_set_label: 2143be0f34b5SRichard Henderson case INDEX_op_call: 2144be0f34b5SRichard Henderson case INDEX_op_br: 2145be0f34b5SRichard Henderson case INDEX_op_mb: 2146be0f34b5SRichard Henderson case INDEX_op_insn_start: 2147be0f34b5SRichard Henderson case INDEX_op_exit_tb: 2148be0f34b5SRichard Henderson case INDEX_op_goto_tb: 2149f4e01e30SRichard Henderson case INDEX_op_goto_ptr: 2150*50b7a197SRichard Henderson case INDEX_op_qemu_ld_i32: 2151*50b7a197SRichard Henderson case INDEX_op_qemu_st_i32: 2152*50b7a197SRichard Henderson case INDEX_op_qemu_ld_i64: 2153*50b7a197SRichard Henderson case INDEX_op_qemu_st_i64: 2154be0f34b5SRichard Henderson return true; 2155be0f34b5SRichard Henderson 2156*50b7a197SRichard Henderson case INDEX_op_qemu_st8_i32: 215707ce0b05SRichard Henderson return TCG_TARGET_HAS_qemu_st8_i32; 215807ce0b05SRichard Henderson 2159*50b7a197SRichard Henderson case INDEX_op_qemu_ld_i128: 2160*50b7a197SRichard Henderson case INDEX_op_qemu_st_i128: 216112fde9bcSRichard Henderson return TCG_TARGET_HAS_qemu_ldst_i128; 216212fde9bcSRichard Henderson 2163be0f34b5SRichard Henderson case INDEX_op_mov_i32: 2164be0f34b5SRichard Henderson case INDEX_op_setcond_i32: 2165be0f34b5SRichard Henderson case INDEX_op_brcond_i32: 21663871be75SRichard Henderson case INDEX_op_movcond_i32: 2167be0f34b5SRichard Henderson case INDEX_op_ld8u_i32: 2168be0f34b5SRichard Henderson case INDEX_op_ld8s_i32: 2169be0f34b5SRichard Henderson case INDEX_op_ld16u_i32: 2170be0f34b5SRichard Henderson case INDEX_op_ld16s_i32: 2171be0f34b5SRichard Henderson case INDEX_op_ld_i32: 2172be0f34b5SRichard Henderson case INDEX_op_st8_i32: 2173be0f34b5SRichard Henderson case INDEX_op_st16_i32: 2174be0f34b5SRichard Henderson case INDEX_op_st_i32: 2175be0f34b5SRichard Henderson case INDEX_op_add_i32: 2176be0f34b5SRichard Henderson case INDEX_op_sub_i32: 2177b701f195SRichard Henderson case INDEX_op_neg_i32: 2178be0f34b5SRichard Henderson case INDEX_op_mul_i32: 2179be0f34b5SRichard Henderson case INDEX_op_and_i32: 2180be0f34b5SRichard Henderson case INDEX_op_or_i32: 2181be0f34b5SRichard Henderson case INDEX_op_xor_i32: 2182be0f34b5SRichard Henderson case INDEX_op_shl_i32: 2183be0f34b5SRichard Henderson case INDEX_op_shr_i32: 2184be0f34b5SRichard Henderson case INDEX_op_sar_i32: 2185c334de11SRichard Henderson case INDEX_op_extract_i32: 2186c334de11SRichard Henderson case INDEX_op_sextract_i32: 21876482e9d2SRichard Henderson case INDEX_op_deposit_i32: 2188be0f34b5SRichard Henderson return true; 2189be0f34b5SRichard Henderson 21903635502dSRichard Henderson case INDEX_op_negsetcond_i32: 21913635502dSRichard Henderson return TCG_TARGET_HAS_negsetcond_i32; 2192be0f34b5SRichard Henderson case INDEX_op_div_i32: 2193be0f34b5SRichard Henderson case INDEX_op_divu_i32: 2194be0f34b5SRichard Henderson return TCG_TARGET_HAS_div_i32; 2195be0f34b5SRichard Henderson case INDEX_op_rem_i32: 2196be0f34b5SRichard Henderson case INDEX_op_remu_i32: 2197be0f34b5SRichard Henderson return TCG_TARGET_HAS_rem_i32; 2198be0f34b5SRichard Henderson case INDEX_op_div2_i32: 2199be0f34b5SRichard Henderson case INDEX_op_divu2_i32: 2200be0f34b5SRichard Henderson return TCG_TARGET_HAS_div2_i32; 2201be0f34b5SRichard Henderson case INDEX_op_rotl_i32: 2202be0f34b5SRichard Henderson case INDEX_op_rotr_i32: 2203be0f34b5SRichard Henderson return TCG_TARGET_HAS_rot_i32; 2204fce1296fSRichard Henderson case INDEX_op_extract2_i32: 2205fce1296fSRichard Henderson return TCG_TARGET_HAS_extract2_i32; 2206be0f34b5SRichard Henderson case INDEX_op_add2_i32: 2207be0f34b5SRichard Henderson return TCG_TARGET_HAS_add2_i32; 2208be0f34b5SRichard Henderson case INDEX_op_sub2_i32: 2209be0f34b5SRichard Henderson return TCG_TARGET_HAS_sub2_i32; 2210be0f34b5SRichard Henderson case INDEX_op_mulu2_i32: 2211be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulu2_i32; 2212be0f34b5SRichard Henderson case INDEX_op_muls2_i32: 2213be0f34b5SRichard Henderson return TCG_TARGET_HAS_muls2_i32; 2214be0f34b5SRichard Henderson case INDEX_op_muluh_i32: 2215be0f34b5SRichard Henderson return TCG_TARGET_HAS_muluh_i32; 2216be0f34b5SRichard Henderson case INDEX_op_mulsh_i32: 2217be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulsh_i32; 2218be0f34b5SRichard Henderson case INDEX_op_ext8s_i32: 2219be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8s_i32; 2220be0f34b5SRichard Henderson case INDEX_op_ext16s_i32: 2221be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16s_i32; 2222be0f34b5SRichard Henderson case INDEX_op_ext8u_i32: 2223be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8u_i32; 2224be0f34b5SRichard Henderson case INDEX_op_ext16u_i32: 2225be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16u_i32; 2226be0f34b5SRichard Henderson case INDEX_op_bswap16_i32: 2227be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap16_i32; 2228be0f34b5SRichard Henderson case INDEX_op_bswap32_i32: 2229be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap32_i32; 2230be0f34b5SRichard Henderson case INDEX_op_not_i32: 2231be0f34b5SRichard Henderson return TCG_TARGET_HAS_not_i32; 2232be0f34b5SRichard Henderson case INDEX_op_andc_i32: 2233be0f34b5SRichard Henderson return TCG_TARGET_HAS_andc_i32; 2234be0f34b5SRichard Henderson case INDEX_op_orc_i32: 2235be0f34b5SRichard Henderson return TCG_TARGET_HAS_orc_i32; 2236be0f34b5SRichard Henderson case INDEX_op_eqv_i32: 2237be0f34b5SRichard Henderson return TCG_TARGET_HAS_eqv_i32; 2238be0f34b5SRichard Henderson case INDEX_op_nand_i32: 2239be0f34b5SRichard Henderson return TCG_TARGET_HAS_nand_i32; 2240be0f34b5SRichard Henderson case INDEX_op_nor_i32: 2241be0f34b5SRichard Henderson return TCG_TARGET_HAS_nor_i32; 2242be0f34b5SRichard Henderson case INDEX_op_clz_i32: 2243be0f34b5SRichard Henderson return TCG_TARGET_HAS_clz_i32; 2244be0f34b5SRichard Henderson case INDEX_op_ctz_i32: 2245be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctz_i32; 2246be0f34b5SRichard Henderson case INDEX_op_ctpop_i32: 2247be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctpop_i32; 2248be0f34b5SRichard Henderson 2249be0f34b5SRichard Henderson case INDEX_op_brcond2_i32: 2250be0f34b5SRichard Henderson case INDEX_op_setcond2_i32: 2251be0f34b5SRichard Henderson return TCG_TARGET_REG_BITS == 32; 2252be0f34b5SRichard Henderson 2253be0f34b5SRichard Henderson case INDEX_op_mov_i64: 2254be0f34b5SRichard Henderson case INDEX_op_setcond_i64: 2255be0f34b5SRichard Henderson case INDEX_op_brcond_i64: 22563871be75SRichard Henderson case INDEX_op_movcond_i64: 2257be0f34b5SRichard Henderson case INDEX_op_ld8u_i64: 2258be0f34b5SRichard Henderson case INDEX_op_ld8s_i64: 2259be0f34b5SRichard Henderson case INDEX_op_ld16u_i64: 2260be0f34b5SRichard Henderson case INDEX_op_ld16s_i64: 2261be0f34b5SRichard Henderson case INDEX_op_ld32u_i64: 2262be0f34b5SRichard Henderson case INDEX_op_ld32s_i64: 2263be0f34b5SRichard Henderson case INDEX_op_ld_i64: 2264be0f34b5SRichard Henderson case INDEX_op_st8_i64: 2265be0f34b5SRichard Henderson case INDEX_op_st16_i64: 2266be0f34b5SRichard Henderson case INDEX_op_st32_i64: 2267be0f34b5SRichard Henderson case INDEX_op_st_i64: 2268be0f34b5SRichard Henderson case INDEX_op_add_i64: 2269be0f34b5SRichard Henderson case INDEX_op_sub_i64: 2270b701f195SRichard Henderson case INDEX_op_neg_i64: 2271be0f34b5SRichard Henderson case INDEX_op_mul_i64: 2272be0f34b5SRichard Henderson case INDEX_op_and_i64: 2273be0f34b5SRichard Henderson case INDEX_op_or_i64: 2274be0f34b5SRichard Henderson case INDEX_op_xor_i64: 2275be0f34b5SRichard Henderson case INDEX_op_shl_i64: 2276be0f34b5SRichard Henderson case INDEX_op_shr_i64: 2277be0f34b5SRichard Henderson case INDEX_op_sar_i64: 2278be0f34b5SRichard Henderson case INDEX_op_ext_i32_i64: 2279be0f34b5SRichard Henderson case INDEX_op_extu_i32_i64: 2280c334de11SRichard Henderson case INDEX_op_extract_i64: 2281c334de11SRichard Henderson case INDEX_op_sextract_i64: 22826482e9d2SRichard Henderson case INDEX_op_deposit_i64: 2283be0f34b5SRichard Henderson return TCG_TARGET_REG_BITS == 64; 2284be0f34b5SRichard Henderson 22853635502dSRichard Henderson case INDEX_op_negsetcond_i64: 22863635502dSRichard Henderson return TCG_TARGET_HAS_negsetcond_i64; 2287be0f34b5SRichard Henderson case INDEX_op_div_i64: 2288be0f34b5SRichard Henderson case INDEX_op_divu_i64: 2289be0f34b5SRichard Henderson return TCG_TARGET_HAS_div_i64; 2290be0f34b5SRichard Henderson case INDEX_op_rem_i64: 2291be0f34b5SRichard Henderson case INDEX_op_remu_i64: 2292be0f34b5SRichard Henderson return TCG_TARGET_HAS_rem_i64; 2293be0f34b5SRichard Henderson case INDEX_op_div2_i64: 2294be0f34b5SRichard Henderson case INDEX_op_divu2_i64: 2295be0f34b5SRichard Henderson return TCG_TARGET_HAS_div2_i64; 2296be0f34b5SRichard Henderson case INDEX_op_rotl_i64: 2297be0f34b5SRichard Henderson case INDEX_op_rotr_i64: 2298be0f34b5SRichard Henderson return TCG_TARGET_HAS_rot_i64; 2299fce1296fSRichard Henderson case INDEX_op_extract2_i64: 2300fce1296fSRichard Henderson return TCG_TARGET_HAS_extract2_i64; 2301be0f34b5SRichard Henderson case INDEX_op_extrl_i64_i32: 2302be0f34b5SRichard Henderson case INDEX_op_extrh_i64_i32: 230313d885b0SRichard Henderson return TCG_TARGET_HAS_extr_i64_i32; 2304be0f34b5SRichard Henderson case INDEX_op_ext8s_i64: 2305be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8s_i64; 2306be0f34b5SRichard Henderson case INDEX_op_ext16s_i64: 2307be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16s_i64; 2308be0f34b5SRichard Henderson case INDEX_op_ext32s_i64: 2309be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext32s_i64; 2310be0f34b5SRichard Henderson case INDEX_op_ext8u_i64: 2311be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8u_i64; 2312be0f34b5SRichard Henderson case INDEX_op_ext16u_i64: 2313be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16u_i64; 2314be0f34b5SRichard Henderson case INDEX_op_ext32u_i64: 2315be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext32u_i64; 2316be0f34b5SRichard Henderson case INDEX_op_bswap16_i64: 2317be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap16_i64; 2318be0f34b5SRichard Henderson case INDEX_op_bswap32_i64: 2319be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap32_i64; 2320be0f34b5SRichard Henderson case INDEX_op_bswap64_i64: 2321be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap64_i64; 2322be0f34b5SRichard Henderson case INDEX_op_not_i64: 2323be0f34b5SRichard Henderson return TCG_TARGET_HAS_not_i64; 2324be0f34b5SRichard Henderson case INDEX_op_andc_i64: 2325be0f34b5SRichard Henderson return TCG_TARGET_HAS_andc_i64; 2326be0f34b5SRichard Henderson case INDEX_op_orc_i64: 2327be0f34b5SRichard Henderson return TCG_TARGET_HAS_orc_i64; 2328be0f34b5SRichard Henderson case INDEX_op_eqv_i64: 2329be0f34b5SRichard Henderson return TCG_TARGET_HAS_eqv_i64; 2330be0f34b5SRichard Henderson case INDEX_op_nand_i64: 2331be0f34b5SRichard Henderson return TCG_TARGET_HAS_nand_i64; 2332be0f34b5SRichard Henderson case INDEX_op_nor_i64: 2333be0f34b5SRichard Henderson return TCG_TARGET_HAS_nor_i64; 2334be0f34b5SRichard Henderson case INDEX_op_clz_i64: 2335be0f34b5SRichard Henderson return TCG_TARGET_HAS_clz_i64; 2336be0f34b5SRichard Henderson case INDEX_op_ctz_i64: 2337be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctz_i64; 2338be0f34b5SRichard Henderson case INDEX_op_ctpop_i64: 2339be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctpop_i64; 2340be0f34b5SRichard Henderson case INDEX_op_add2_i64: 2341be0f34b5SRichard Henderson return TCG_TARGET_HAS_add2_i64; 2342be0f34b5SRichard Henderson case INDEX_op_sub2_i64: 2343be0f34b5SRichard Henderson return TCG_TARGET_HAS_sub2_i64; 2344be0f34b5SRichard Henderson case INDEX_op_mulu2_i64: 2345be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulu2_i64; 2346be0f34b5SRichard Henderson case INDEX_op_muls2_i64: 2347be0f34b5SRichard Henderson return TCG_TARGET_HAS_muls2_i64; 2348be0f34b5SRichard Henderson case INDEX_op_muluh_i64: 2349be0f34b5SRichard Henderson return TCG_TARGET_HAS_muluh_i64; 2350be0f34b5SRichard Henderson case INDEX_op_mulsh_i64: 2351be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulsh_i64; 2352be0f34b5SRichard Henderson 2353d2fd745fSRichard Henderson case INDEX_op_mov_vec: 2354d2fd745fSRichard Henderson case INDEX_op_dup_vec: 235537ee55a0SRichard Henderson case INDEX_op_dupm_vec: 2356d2fd745fSRichard Henderson case INDEX_op_ld_vec: 2357d2fd745fSRichard Henderson case INDEX_op_st_vec: 2358d2fd745fSRichard Henderson case INDEX_op_add_vec: 2359d2fd745fSRichard Henderson case INDEX_op_sub_vec: 2360d2fd745fSRichard Henderson case INDEX_op_and_vec: 2361d2fd745fSRichard Henderson case INDEX_op_or_vec: 2362d2fd745fSRichard Henderson case INDEX_op_xor_vec: 2363212be173SRichard Henderson case INDEX_op_cmp_vec: 2364f44824ccSRichard Henderson return has_type; 2365d2fd745fSRichard Henderson case INDEX_op_dup2_vec: 2366f44824ccSRichard Henderson return has_type && TCG_TARGET_REG_BITS == 32; 2367d2fd745fSRichard Henderson case INDEX_op_not_vec: 2368f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_not_vec; 2369d2fd745fSRichard Henderson case INDEX_op_neg_vec: 2370f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_neg_vec; 2371bcefc902SRichard Henderson case INDEX_op_abs_vec: 2372f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_abs_vec; 2373d2fd745fSRichard Henderson case INDEX_op_andc_vec: 2374f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_andc_vec; 2375d2fd745fSRichard Henderson case INDEX_op_orc_vec: 2376f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_orc_vec; 2377ed523473SRichard Henderson case INDEX_op_nand_vec: 2378f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_nand_vec; 2379ed523473SRichard Henderson case INDEX_op_nor_vec: 2380f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_nor_vec; 2381ed523473SRichard Henderson case INDEX_op_eqv_vec: 2382f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_eqv_vec; 23833774030aSRichard Henderson case INDEX_op_mul_vec: 2384f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_mul_vec; 2385d0ec9796SRichard Henderson case INDEX_op_shli_vec: 2386d0ec9796SRichard Henderson case INDEX_op_shri_vec: 2387d0ec9796SRichard Henderson case INDEX_op_sari_vec: 2388f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_shi_vec; 2389d0ec9796SRichard Henderson case INDEX_op_shls_vec: 2390d0ec9796SRichard Henderson case INDEX_op_shrs_vec: 2391d0ec9796SRichard Henderson case INDEX_op_sars_vec: 2392f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_shs_vec; 2393d0ec9796SRichard Henderson case INDEX_op_shlv_vec: 2394d0ec9796SRichard Henderson case INDEX_op_shrv_vec: 2395d0ec9796SRichard Henderson case INDEX_op_sarv_vec: 2396f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_shv_vec; 2397b0f7e744SRichard Henderson case INDEX_op_rotli_vec: 2398f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_roti_vec; 239923850a74SRichard Henderson case INDEX_op_rotls_vec: 2400f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_rots_vec; 24015d0ceda9SRichard Henderson case INDEX_op_rotlv_vec: 24025d0ceda9SRichard Henderson case INDEX_op_rotrv_vec: 2403f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_rotv_vec; 24048afaf050SRichard Henderson case INDEX_op_ssadd_vec: 24058afaf050SRichard Henderson case INDEX_op_usadd_vec: 24068afaf050SRichard Henderson case INDEX_op_sssub_vec: 24078afaf050SRichard Henderson case INDEX_op_ussub_vec: 2408f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_sat_vec; 2409dd0a0fcdSRichard Henderson case INDEX_op_smin_vec: 2410dd0a0fcdSRichard Henderson case INDEX_op_umin_vec: 2411dd0a0fcdSRichard Henderson case INDEX_op_smax_vec: 2412dd0a0fcdSRichard Henderson case INDEX_op_umax_vec: 2413f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_minmax_vec; 241438dc1294SRichard Henderson case INDEX_op_bitsel_vec: 2415f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_bitsel_vec; 2416f75da298SRichard Henderson case INDEX_op_cmpsel_vec: 2417f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_cmpsel_vec; 2418d2fd745fSRichard Henderson 2419db432672SRichard Henderson default: 2420db432672SRichard Henderson tcg_debug_assert(op > INDEX_op_last_generic && op < NB_OPS); 2421db432672SRichard Henderson return true; 2422be0f34b5SRichard Henderson } 2423be0f34b5SRichard Henderson } 2424be0f34b5SRichard Henderson 24250e4c6424SRichard Henderson bool tcg_op_deposit_valid(TCGType type, unsigned ofs, unsigned len) 24260e4c6424SRichard Henderson { 24276482e9d2SRichard Henderson unsigned width; 24286482e9d2SRichard Henderson 24296482e9d2SRichard Henderson tcg_debug_assert(type == TCG_TYPE_I32 || type == TCG_TYPE_I64); 24306482e9d2SRichard Henderson width = (type == TCG_TYPE_I32 ? 32 : 64); 24316482e9d2SRichard Henderson 24326482e9d2SRichard Henderson tcg_debug_assert(ofs < width); 24330e4c6424SRichard Henderson tcg_debug_assert(len > 0); 24346482e9d2SRichard Henderson tcg_debug_assert(len <= width - ofs); 24356482e9d2SRichard Henderson 24366482e9d2SRichard Henderson return TCG_TARGET_deposit_valid(type, ofs, len); 24370e4c6424SRichard Henderson } 24380e4c6424SRichard Henderson 243939004a71SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs); 244039004a71SRichard Henderson 244183a0ad26SRichard Henderson static void tcg_gen_callN(void *func, TCGHelperInfo *info, 244283a0ad26SRichard Henderson TCGTemp *ret, TCGTemp **args) 2443c896fe29Sbellard { 244439004a71SRichard Henderson TCGv_i64 extend_free[MAX_CALL_IARGS]; 244539004a71SRichard Henderson int n_extend = 0; 244675e8b9b7SRichard Henderson TCGOp *op; 244739004a71SRichard Henderson int i, n, pi = 0, total_args; 2448afb49896SRichard Henderson 2449d53106c9SRichard Henderson if (unlikely(g_once_init_enter(HELPER_INFO_INIT(info)))) { 2450d53106c9SRichard Henderson init_call_layout(info); 2451d53106c9SRichard Henderson g_once_init_leave(HELPER_INFO_INIT(info), HELPER_INFO_INIT_VAL(info)); 2452d53106c9SRichard Henderson } 2453d53106c9SRichard Henderson 245439004a71SRichard Henderson total_args = info->nr_out + info->nr_in + 2; 245539004a71SRichard Henderson op = tcg_op_alloc(INDEX_op_call, total_args); 24562bece2c8SRichard Henderson 245738b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN 245817083f6fSEmilio Cota /* Flag helpers that may affect guest state */ 2459b0748975SRichard Henderson if (tcg_ctx->plugin_insn && !(info->flags & TCG_CALL_NO_SIDE_EFFECTS)) { 246038b47b19SEmilio G. Cota tcg_ctx->plugin_insn->calls_helpers = true; 246138b47b19SEmilio G. Cota } 246238b47b19SEmilio G. Cota #endif 246338b47b19SEmilio G. Cota 246439004a71SRichard Henderson TCGOP_CALLO(op) = n = info->nr_out; 246539004a71SRichard Henderson switch (n) { 246639004a71SRichard Henderson case 0: 246739004a71SRichard Henderson tcg_debug_assert(ret == NULL); 246839004a71SRichard Henderson break; 246939004a71SRichard Henderson case 1: 247039004a71SRichard Henderson tcg_debug_assert(ret != NULL); 247139004a71SRichard Henderson op->args[pi++] = temp_arg(ret); 247239004a71SRichard Henderson break; 247339004a71SRichard Henderson case 2: 2474466d3759SRichard Henderson case 4: 247539004a71SRichard Henderson tcg_debug_assert(ret != NULL); 2476466d3759SRichard Henderson tcg_debug_assert(ret->base_type == ret->type + ctz32(n)); 247739004a71SRichard Henderson tcg_debug_assert(ret->temp_subindex == 0); 2478466d3759SRichard Henderson for (i = 0; i < n; ++i) { 2479466d3759SRichard Henderson op->args[pi++] = temp_arg(ret + i); 2480466d3759SRichard Henderson } 248139004a71SRichard Henderson break; 248239004a71SRichard Henderson default: 248339004a71SRichard Henderson g_assert_not_reached(); 248439004a71SRichard Henderson } 24857319d83aSRichard Henderson 248639004a71SRichard Henderson TCGOP_CALLI(op) = n = info->nr_in; 248739004a71SRichard Henderson for (i = 0; i < n; i++) { 248839004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i]; 248939004a71SRichard Henderson TCGTemp *ts = args[loc->arg_idx] + loc->tmp_subindex; 249039004a71SRichard Henderson 249139004a71SRichard Henderson switch (loc->kind) { 249239004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 2493313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF: 2494313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF_N: 249539004a71SRichard Henderson op->args[pi++] = temp_arg(ts); 249639004a71SRichard Henderson break; 249739004a71SRichard Henderson 249839004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 249939004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 250039004a71SRichard Henderson { 25015dd48602SRichard Henderson TCGv_i64 temp = tcg_temp_ebb_new_i64(); 250239004a71SRichard Henderson TCGv_i32 orig = temp_tcgv_i32(ts); 250339004a71SRichard Henderson 250439004a71SRichard Henderson if (loc->kind == TCG_CALL_ARG_EXTEND_S) { 250518cf3d07SRichard Henderson tcg_gen_ext_i32_i64(temp, orig); 25062bece2c8SRichard Henderson } else { 250718cf3d07SRichard Henderson tcg_gen_extu_i32_i64(temp, orig); 25082bece2c8SRichard Henderson } 250939004a71SRichard Henderson op->args[pi++] = tcgv_i64_arg(temp); 251039004a71SRichard Henderson extend_free[n_extend++] = temp; 25112bece2c8SRichard Henderson } 251239004a71SRichard Henderson break; 25132bece2c8SRichard Henderson 2514e2a9dd6bSRichard Henderson default: 2515e2a9dd6bSRichard Henderson g_assert_not_reached(); 2516e2a9dd6bSRichard Henderson } 2517c896fe29Sbellard } 251883a0ad26SRichard Henderson op->args[pi++] = (uintptr_t)func; 25193e92aa34SRichard Henderson op->args[pi++] = (uintptr_t)info; 252039004a71SRichard Henderson tcg_debug_assert(pi == total_args); 2521a7812ae4Spbrook 252207843f75SRichard Henderson if (tcg_ctx->emit_before_op) { 252307843f75SRichard Henderson QTAILQ_INSERT_BEFORE(tcg_ctx->emit_before_op, op, link); 252407843f75SRichard Henderson } else { 252539004a71SRichard Henderson QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link); 252607843f75SRichard Henderson } 25272bece2c8SRichard Henderson 252839004a71SRichard Henderson tcg_debug_assert(n_extend < ARRAY_SIZE(extend_free)); 252939004a71SRichard Henderson for (i = 0; i < n_extend; ++i) { 253039004a71SRichard Henderson tcg_temp_free_i64(extend_free[i]); 2531eb8b0224SRichard Henderson } 2532a7812ae4Spbrook } 2533c896fe29Sbellard 253483a0ad26SRichard Henderson void tcg_gen_call0(void *func, TCGHelperInfo *info, TCGTemp *ret) 2535a3a692b8SRichard Henderson { 253683a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, NULL); 2537a3a692b8SRichard Henderson } 2538a3a692b8SRichard Henderson 253983a0ad26SRichard Henderson void tcg_gen_call1(void *func, TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1) 2540a3a692b8SRichard Henderson { 254183a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, &t1); 2542a3a692b8SRichard Henderson } 2543a3a692b8SRichard Henderson 254483a0ad26SRichard Henderson void tcg_gen_call2(void *func, TCGHelperInfo *info, TCGTemp *ret, 254583a0ad26SRichard Henderson TCGTemp *t1, TCGTemp *t2) 2546a3a692b8SRichard Henderson { 2547a3a692b8SRichard Henderson TCGTemp *args[2] = { t1, t2 }; 254883a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, args); 2549a3a692b8SRichard Henderson } 2550a3a692b8SRichard Henderson 255183a0ad26SRichard Henderson void tcg_gen_call3(void *func, TCGHelperInfo *info, TCGTemp *ret, 255283a0ad26SRichard Henderson TCGTemp *t1, TCGTemp *t2, TCGTemp *t3) 2553a3a692b8SRichard Henderson { 2554a3a692b8SRichard Henderson TCGTemp *args[3] = { t1, t2, t3 }; 255583a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, args); 2556a3a692b8SRichard Henderson } 2557a3a692b8SRichard Henderson 255883a0ad26SRichard Henderson void tcg_gen_call4(void *func, TCGHelperInfo *info, TCGTemp *ret, 255983a0ad26SRichard Henderson TCGTemp *t1, TCGTemp *t2, TCGTemp *t3, TCGTemp *t4) 2560a3a692b8SRichard Henderson { 2561a3a692b8SRichard Henderson TCGTemp *args[4] = { t1, t2, t3, t4 }; 256283a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, args); 2563a3a692b8SRichard Henderson } 2564a3a692b8SRichard Henderson 256583a0ad26SRichard Henderson void tcg_gen_call5(void *func, TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1, 2566a3a692b8SRichard Henderson TCGTemp *t2, TCGTemp *t3, TCGTemp *t4, TCGTemp *t5) 2567a3a692b8SRichard Henderson { 2568a3a692b8SRichard Henderson TCGTemp *args[5] = { t1, t2, t3, t4, t5 }; 256983a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, args); 2570a3a692b8SRichard Henderson } 2571a3a692b8SRichard Henderson 257283a0ad26SRichard Henderson void tcg_gen_call6(void *func, TCGHelperInfo *info, TCGTemp *ret, 257383a0ad26SRichard Henderson TCGTemp *t1, TCGTemp *t2, TCGTemp *t3, 257483a0ad26SRichard Henderson TCGTemp *t4, TCGTemp *t5, TCGTemp *t6) 2575a3a692b8SRichard Henderson { 2576a3a692b8SRichard Henderson TCGTemp *args[6] = { t1, t2, t3, t4, t5, t6 }; 257783a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, args); 2578a3a692b8SRichard Henderson } 2579a3a692b8SRichard Henderson 258083a0ad26SRichard Henderson void tcg_gen_call7(void *func, TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1, 2581a3a692b8SRichard Henderson TCGTemp *t2, TCGTemp *t3, TCGTemp *t4, 2582a3a692b8SRichard Henderson TCGTemp *t5, TCGTemp *t6, TCGTemp *t7) 2583a3a692b8SRichard Henderson { 2584a3a692b8SRichard Henderson TCGTemp *args[7] = { t1, t2, t3, t4, t5, t6, t7 }; 258583a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, args); 2586a3a692b8SRichard Henderson } 2587a3a692b8SRichard Henderson 25888fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s) 2589c896fe29Sbellard { 2590ac3b8891SRichard Henderson int i, n; 2591ac3b8891SRichard Henderson 2592ee17db83SRichard Henderson for (i = 0, n = s->nb_temps; i < n; i++) { 2593ee17db83SRichard Henderson TCGTemp *ts = &s->temps[i]; 2594ee17db83SRichard Henderson TCGTempVal val = TEMP_VAL_MEM; 2595ee17db83SRichard Henderson 2596ee17db83SRichard Henderson switch (ts->kind) { 2597c0522136SRichard Henderson case TEMP_CONST: 2598c0522136SRichard Henderson val = TEMP_VAL_CONST; 2599c0522136SRichard Henderson break; 2600ee17db83SRichard Henderson case TEMP_FIXED: 2601ee17db83SRichard Henderson val = TEMP_VAL_REG; 2602ee17db83SRichard Henderson break; 2603ee17db83SRichard Henderson case TEMP_GLOBAL: 2604ee17db83SRichard Henderson break; 2605c7482438SRichard Henderson case TEMP_EBB: 2606ee17db83SRichard Henderson val = TEMP_VAL_DEAD; 2607ee17db83SRichard Henderson /* fall through */ 2608f57c6915SRichard Henderson case TEMP_TB: 2609e8996ee0Sbellard ts->mem_allocated = 0; 2610ee17db83SRichard Henderson break; 2611ee17db83SRichard Henderson default: 2612ee17db83SRichard Henderson g_assert_not_reached(); 2613ee17db83SRichard Henderson } 2614ee17db83SRichard Henderson ts->val_type = val; 2615e8996ee0Sbellard } 2616f8b2f202SRichard Henderson 2617f8b2f202SRichard Henderson memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp)); 2618c896fe29Sbellard } 2619c896fe29Sbellard 2620f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size, 2621f8b2f202SRichard Henderson TCGTemp *ts) 2622c896fe29Sbellard { 26231807f4c4SRichard Henderson int idx = temp_idx(ts); 2624ac56dd48Spbrook 2625ee17db83SRichard Henderson switch (ts->kind) { 2626ee17db83SRichard Henderson case TEMP_FIXED: 2627ee17db83SRichard Henderson case TEMP_GLOBAL: 2628ac56dd48Spbrook pstrcpy(buf, buf_size, ts->name); 2629ee17db83SRichard Henderson break; 2630f57c6915SRichard Henderson case TEMP_TB: 2631641d5fbeSbellard snprintf(buf, buf_size, "loc%d", idx - s->nb_globals); 2632ee17db83SRichard Henderson break; 2633c7482438SRichard Henderson case TEMP_EBB: 2634ac56dd48Spbrook snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals); 2635ee17db83SRichard Henderson break; 2636c0522136SRichard Henderson case TEMP_CONST: 2637c0522136SRichard Henderson switch (ts->type) { 2638c0522136SRichard Henderson case TCG_TYPE_I32: 2639c0522136SRichard Henderson snprintf(buf, buf_size, "$0x%x", (int32_t)ts->val); 2640c0522136SRichard Henderson break; 2641c0522136SRichard Henderson #if TCG_TARGET_REG_BITS > 32 2642c0522136SRichard Henderson case TCG_TYPE_I64: 2643c0522136SRichard Henderson snprintf(buf, buf_size, "$0x%" PRIx64, ts->val); 2644c0522136SRichard Henderson break; 2645c0522136SRichard Henderson #endif 2646c0522136SRichard Henderson case TCG_TYPE_V64: 2647c0522136SRichard Henderson case TCG_TYPE_V128: 2648c0522136SRichard Henderson case TCG_TYPE_V256: 2649c0522136SRichard Henderson snprintf(buf, buf_size, "v%d$0x%" PRIx64, 2650c0522136SRichard Henderson 64 << (ts->type - TCG_TYPE_V64), ts->val); 2651c0522136SRichard Henderson break; 2652c0522136SRichard Henderson default: 2653c0522136SRichard Henderson g_assert_not_reached(); 2654c0522136SRichard Henderson } 2655c0522136SRichard Henderson break; 2656c896fe29Sbellard } 2657c896fe29Sbellard return buf; 2658c896fe29Sbellard } 2659c896fe29Sbellard 266043439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf, 266143439139SRichard Henderson int buf_size, TCGArg arg) 2662f8b2f202SRichard Henderson { 266343439139SRichard Henderson return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg)); 2664f8b2f202SRichard Henderson } 2665f8b2f202SRichard Henderson 2666f48f3edeSblueswir1 static const char * const cond_name[] = 2667f48f3edeSblueswir1 { 26680aed257fSRichard Henderson [TCG_COND_NEVER] = "never", 26690aed257fSRichard Henderson [TCG_COND_ALWAYS] = "always", 2670f48f3edeSblueswir1 [TCG_COND_EQ] = "eq", 2671f48f3edeSblueswir1 [TCG_COND_NE] = "ne", 2672f48f3edeSblueswir1 [TCG_COND_LT] = "lt", 2673f48f3edeSblueswir1 [TCG_COND_GE] = "ge", 2674f48f3edeSblueswir1 [TCG_COND_LE] = "le", 2675f48f3edeSblueswir1 [TCG_COND_GT] = "gt", 2676f48f3edeSblueswir1 [TCG_COND_LTU] = "ltu", 2677f48f3edeSblueswir1 [TCG_COND_GEU] = "geu", 2678f48f3edeSblueswir1 [TCG_COND_LEU] = "leu", 2679d48097d0SRichard Henderson [TCG_COND_GTU] = "gtu", 2680d48097d0SRichard Henderson [TCG_COND_TSTEQ] = "tsteq", 2681d48097d0SRichard Henderson [TCG_COND_TSTNE] = "tstne", 2682f48f3edeSblueswir1 }; 2683f48f3edeSblueswir1 268412fde9bcSRichard Henderson static const char * const ldst_name[(MO_BSWAP | MO_SSIZE) + 1] = 2685f713d6adSRichard Henderson { 2686f713d6adSRichard Henderson [MO_UB] = "ub", 2687f713d6adSRichard Henderson [MO_SB] = "sb", 2688f713d6adSRichard Henderson [MO_LEUW] = "leuw", 2689f713d6adSRichard Henderson [MO_LESW] = "lesw", 2690f713d6adSRichard Henderson [MO_LEUL] = "leul", 2691f713d6adSRichard Henderson [MO_LESL] = "lesl", 2692fc313c64SFrédéric Pétrot [MO_LEUQ] = "leq", 2693f713d6adSRichard Henderson [MO_BEUW] = "beuw", 2694f713d6adSRichard Henderson [MO_BESW] = "besw", 2695f713d6adSRichard Henderson [MO_BEUL] = "beul", 2696f713d6adSRichard Henderson [MO_BESL] = "besl", 2697fc313c64SFrédéric Pétrot [MO_BEUQ] = "beq", 269812fde9bcSRichard Henderson [MO_128 + MO_BE] = "beo", 269912fde9bcSRichard Henderson [MO_128 + MO_LE] = "leo", 2700f713d6adSRichard Henderson }; 2701f713d6adSRichard Henderson 27021f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = { 27031f00b27fSSergey Sorokin [MO_UNALN >> MO_ASHIFT] = "un+", 27041f00b27fSSergey Sorokin [MO_ALIGN >> MO_ASHIFT] = "al+", 27051f00b27fSSergey Sorokin [MO_ALIGN_2 >> MO_ASHIFT] = "al2+", 27061f00b27fSSergey Sorokin [MO_ALIGN_4 >> MO_ASHIFT] = "al4+", 27071f00b27fSSergey Sorokin [MO_ALIGN_8 >> MO_ASHIFT] = "al8+", 27081f00b27fSSergey Sorokin [MO_ALIGN_16 >> MO_ASHIFT] = "al16+", 27091f00b27fSSergey Sorokin [MO_ALIGN_32 >> MO_ASHIFT] = "al32+", 27101f00b27fSSergey Sorokin [MO_ALIGN_64 >> MO_ASHIFT] = "al64+", 27111f00b27fSSergey Sorokin }; 27121f00b27fSSergey Sorokin 271337031fefSRichard Henderson static const char * const atom_name[(MO_ATOM_MASK >> MO_ATOM_SHIFT) + 1] = { 271437031fefSRichard Henderson [MO_ATOM_IFALIGN >> MO_ATOM_SHIFT] = "", 271537031fefSRichard Henderson [MO_ATOM_IFALIGN_PAIR >> MO_ATOM_SHIFT] = "pair+", 271637031fefSRichard Henderson [MO_ATOM_WITHIN16 >> MO_ATOM_SHIFT] = "w16+", 271737031fefSRichard Henderson [MO_ATOM_WITHIN16_PAIR >> MO_ATOM_SHIFT] = "w16p+", 271837031fefSRichard Henderson [MO_ATOM_SUBALIGN >> MO_ATOM_SHIFT] = "sub+", 271937031fefSRichard Henderson [MO_ATOM_NONE >> MO_ATOM_SHIFT] = "noat+", 272037031fefSRichard Henderson }; 272137031fefSRichard Henderson 2722587195bdSRichard Henderson static const char bswap_flag_name[][6] = { 2723587195bdSRichard Henderson [TCG_BSWAP_IZ] = "iz", 2724587195bdSRichard Henderson [TCG_BSWAP_OZ] = "oz", 2725587195bdSRichard Henderson [TCG_BSWAP_OS] = "os", 2726587195bdSRichard Henderson [TCG_BSWAP_IZ | TCG_BSWAP_OZ] = "iz,oz", 2727587195bdSRichard Henderson [TCG_BSWAP_IZ | TCG_BSWAP_OS] = "iz,os", 2728587195bdSRichard Henderson }; 2729587195bdSRichard Henderson 2730b384c734SRichard Henderson #ifdef CONFIG_PLUGIN 2731b384c734SRichard Henderson static const char * const plugin_from_name[] = { 2732b384c734SRichard Henderson "from-tb", 2733b384c734SRichard Henderson "from-insn", 2734b384c734SRichard Henderson "after-insn", 2735b384c734SRichard Henderson "after-tb", 2736b384c734SRichard Henderson }; 2737b384c734SRichard Henderson #endif 2738b384c734SRichard Henderson 2739b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d) 2740b016486eSRichard Henderson { 2741b016486eSRichard Henderson return (d & (d - 1)) == 0; 2742b016486eSRichard Henderson } 2743b016486eSRichard Henderson 2744b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d) 2745b016486eSRichard Henderson { 2746b016486eSRichard Henderson if (TCG_TARGET_NB_REGS <= 32) { 2747b016486eSRichard Henderson return ctz32(d); 2748b016486eSRichard Henderson } else { 2749b016486eSRichard Henderson return ctz64(d); 2750b016486eSRichard Henderson } 2751b016486eSRichard Henderson } 2752b016486eSRichard Henderson 2753b7a83ff8SRichard Henderson /* Return only the number of characters output -- no error return. */ 2754b7a83ff8SRichard Henderson #define ne_fprintf(...) \ 2755b7a83ff8SRichard Henderson ({ int ret_ = fprintf(__VA_ARGS__); ret_ >= 0 ? ret_ : 0; }) 2756b7a83ff8SRichard Henderson 2757b384c734SRichard Henderson void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs) 2758c896fe29Sbellard { 2759c896fe29Sbellard char buf[128]; 2760c45cb8bbSRichard Henderson TCGOp *op; 2761c896fe29Sbellard 276215fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 2763c45cb8bbSRichard Henderson int i, k, nb_oargs, nb_iargs, nb_cargs; 2764c45cb8bbSRichard Henderson const TCGOpDef *def; 2765c45cb8bbSRichard Henderson TCGOpcode c; 2766bdfb460eSRichard Henderson int col = 0; 2767c45cb8bbSRichard Henderson 2768c45cb8bbSRichard Henderson c = op->opc; 2769c896fe29Sbellard def = &tcg_op_defs[c]; 2770c45cb8bbSRichard Henderson 2771765b842aSRichard Henderson if (c == INDEX_op_insn_start) { 2772b016486eSRichard Henderson nb_oargs = 0; 2773b7a83ff8SRichard Henderson col += ne_fprintf(f, "\n ----"); 27749aef40edSRichard Henderson 2775747bd69dSRichard Henderson for (i = 0, k = s->insn_start_words; i < k; ++i) { 2776c9ad8d27SRichard Henderson col += ne_fprintf(f, " %016" PRIx64, 2777c9ad8d27SRichard Henderson tcg_get_insn_start_param(op, i)); 2778eeacee4dSBlue Swirl } 27797e4597d7Sbellard } else if (c == INDEX_op_call) { 27803e92aa34SRichard Henderson const TCGHelperInfo *info = tcg_call_info(op); 2781fa52e660SRichard Henderson void *func = tcg_call_func(op); 27823e92aa34SRichard Henderson 2783c896fe29Sbellard /* variable number of arguments */ 2784cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 2785cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 2786c896fe29Sbellard nb_cargs = def->nb_cargs; 2787b03cce8eSbellard 2788b7a83ff8SRichard Henderson col += ne_fprintf(f, " %s ", def->name); 27893e92aa34SRichard Henderson 27903e92aa34SRichard Henderson /* 27913e92aa34SRichard Henderson * Print the function name from TCGHelperInfo, if available. 27923e92aa34SRichard Henderson * Note that plugins have a template function for the info, 27933e92aa34SRichard Henderson * but the actual function pointer comes from the plugin. 27943e92aa34SRichard Henderson */ 27953e92aa34SRichard Henderson if (func == info->func) { 2796b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s", info->name); 27973e92aa34SRichard Henderson } else { 2798b7a83ff8SRichard Henderson col += ne_fprintf(f, "plugin(%p)", func); 27993e92aa34SRichard Henderson } 28003e92aa34SRichard Henderson 2801b7a83ff8SRichard Henderson col += ne_fprintf(f, ",$0x%x,$%d", info->flags, nb_oargs); 2802b03cce8eSbellard for (i = 0; i < nb_oargs; i++) { 2803b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", tcg_get_arg_str(s, buf, sizeof(buf), 2804efee3746SRichard Henderson op->args[i])); 2805b03cce8eSbellard } 2806cf066674SRichard Henderson for (i = 0; i < nb_iargs; i++) { 2807efee3746SRichard Henderson TCGArg arg = op->args[nb_oargs + i]; 280839004a71SRichard Henderson const char *t = tcg_get_arg_str(s, buf, sizeof(buf), arg); 2809b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", t); 2810e8996ee0Sbellard } 2811b03cce8eSbellard } else { 2812b7a83ff8SRichard Henderson col += ne_fprintf(f, " %s ", def->name); 2813c45cb8bbSRichard Henderson 2814c896fe29Sbellard nb_oargs = def->nb_oargs; 2815c896fe29Sbellard nb_iargs = def->nb_iargs; 2816c896fe29Sbellard nb_cargs = def->nb_cargs; 2817c896fe29Sbellard 2818d2fd745fSRichard Henderson if (def->flags & TCG_OPF_VECTOR) { 28194d872218SRichard Henderson col += ne_fprintf(f, "v%d,e%d,", 28204d872218SRichard Henderson 8 * tcg_type_size(TCGOP_TYPE(op)), 2821d2fd745fSRichard Henderson 8 << TCGOP_VECE(op)); 2822d2fd745fSRichard Henderson } 2823d2fd745fSRichard Henderson 2824c896fe29Sbellard k = 0; 2825c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 2826b7a83ff8SRichard Henderson const char *sep = k ? "," : ""; 2827b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s%s", sep, 2828b7a83ff8SRichard Henderson tcg_get_arg_str(s, buf, sizeof(buf), 2829efee3746SRichard Henderson op->args[k++])); 2830c896fe29Sbellard } 2831c896fe29Sbellard for (i = 0; i < nb_iargs; i++) { 2832b7a83ff8SRichard Henderson const char *sep = k ? "," : ""; 2833b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s%s", sep, 2834b7a83ff8SRichard Henderson tcg_get_arg_str(s, buf, sizeof(buf), 2835efee3746SRichard Henderson op->args[k++])); 2836c896fe29Sbellard } 2837be210acbSRichard Henderson switch (c) { 2838be210acbSRichard Henderson case INDEX_op_brcond_i32: 2839ffc5ea09SRichard Henderson case INDEX_op_setcond_i32: 28403635502dSRichard Henderson case INDEX_op_negsetcond_i32: 2841ffc5ea09SRichard Henderson case INDEX_op_movcond_i32: 2842be210acbSRichard Henderson case INDEX_op_brcond2_i32: 2843be210acbSRichard Henderson case INDEX_op_setcond2_i32: 2844ffc5ea09SRichard Henderson case INDEX_op_brcond_i64: 2845be210acbSRichard Henderson case INDEX_op_setcond_i64: 28463635502dSRichard Henderson case INDEX_op_negsetcond_i64: 2847ffc5ea09SRichard Henderson case INDEX_op_movcond_i64: 2848212be173SRichard Henderson case INDEX_op_cmp_vec: 2849f75da298SRichard Henderson case INDEX_op_cmpsel_vec: 2850efee3746SRichard Henderson if (op->args[k] < ARRAY_SIZE(cond_name) 2851efee3746SRichard Henderson && cond_name[op->args[k]]) { 2852b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", cond_name[op->args[k++]]); 2853eeacee4dSBlue Swirl } else { 2854b7a83ff8SRichard Henderson col += ne_fprintf(f, ",$0x%" TCG_PRIlx, op->args[k++]); 2855eeacee4dSBlue Swirl } 2856f48f3edeSblueswir1 i = 1; 2857be210acbSRichard Henderson break; 2858*50b7a197SRichard Henderson case INDEX_op_qemu_ld_i32: 2859*50b7a197SRichard Henderson case INDEX_op_qemu_st_i32: 2860*50b7a197SRichard Henderson case INDEX_op_qemu_st8_i32: 2861*50b7a197SRichard Henderson case INDEX_op_qemu_ld_i64: 2862*50b7a197SRichard Henderson case INDEX_op_qemu_st_i64: 2863*50b7a197SRichard Henderson case INDEX_op_qemu_ld_i128: 2864*50b7a197SRichard Henderson case INDEX_op_qemu_st_i128: 286559227d5dSRichard Henderson { 286637031fefSRichard Henderson const char *s_al, *s_op, *s_at; 28679002ffcbSRichard Henderson MemOpIdx oi = op->args[k++]; 28689a239c6eSPhilippe Mathieu-Daudé MemOp mop = get_memop(oi); 286959227d5dSRichard Henderson unsigned ix = get_mmuidx(oi); 287059227d5dSRichard Henderson 28719a239c6eSPhilippe Mathieu-Daudé s_al = alignment_name[(mop & MO_AMASK) >> MO_ASHIFT]; 28729a239c6eSPhilippe Mathieu-Daudé s_op = ldst_name[mop & (MO_BSWAP | MO_SSIZE)]; 28739a239c6eSPhilippe Mathieu-Daudé s_at = atom_name[(mop & MO_ATOM_MASK) >> MO_ATOM_SHIFT]; 28749a239c6eSPhilippe Mathieu-Daudé mop &= ~(MO_AMASK | MO_BSWAP | MO_SSIZE | MO_ATOM_MASK); 287537031fefSRichard Henderson 287637031fefSRichard Henderson /* If all fields are accounted for, print symbolically. */ 28779a239c6eSPhilippe Mathieu-Daudé if (!mop && s_al && s_op && s_at) { 287837031fefSRichard Henderson col += ne_fprintf(f, ",%s%s%s,%u", 287937031fefSRichard Henderson s_at, s_al, s_op, ix); 288037031fefSRichard Henderson } else { 28819a239c6eSPhilippe Mathieu-Daudé mop = get_memop(oi); 28829a239c6eSPhilippe Mathieu-Daudé col += ne_fprintf(f, ",$0x%x,%u", mop, ix); 2883f713d6adSRichard Henderson } 2884f713d6adSRichard Henderson i = 1; 288559227d5dSRichard Henderson } 2886f713d6adSRichard Henderson break; 2887587195bdSRichard Henderson case INDEX_op_bswap16_i32: 2888587195bdSRichard Henderson case INDEX_op_bswap16_i64: 2889587195bdSRichard Henderson case INDEX_op_bswap32_i32: 2890587195bdSRichard Henderson case INDEX_op_bswap32_i64: 2891587195bdSRichard Henderson case INDEX_op_bswap64_i64: 2892587195bdSRichard Henderson { 2893587195bdSRichard Henderson TCGArg flags = op->args[k]; 2894587195bdSRichard Henderson const char *name = NULL; 2895587195bdSRichard Henderson 2896587195bdSRichard Henderson if (flags < ARRAY_SIZE(bswap_flag_name)) { 2897587195bdSRichard Henderson name = bswap_flag_name[flags]; 2898587195bdSRichard Henderson } 2899587195bdSRichard Henderson if (name) { 2900b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", name); 2901587195bdSRichard Henderson } else { 2902b7a83ff8SRichard Henderson col += ne_fprintf(f, ",$0x%" TCG_PRIlx, flags); 2903587195bdSRichard Henderson } 2904587195bdSRichard Henderson i = k = 1; 2905587195bdSRichard Henderson } 2906587195bdSRichard Henderson break; 2907b384c734SRichard Henderson #ifdef CONFIG_PLUGIN 2908b384c734SRichard Henderson case INDEX_op_plugin_cb: 2909b384c734SRichard Henderson { 2910b384c734SRichard Henderson TCGArg from = op->args[k++]; 2911b384c734SRichard Henderson const char *name = NULL; 2912b384c734SRichard Henderson 2913b384c734SRichard Henderson if (from < ARRAY_SIZE(plugin_from_name)) { 2914b384c734SRichard Henderson name = plugin_from_name[from]; 2915b384c734SRichard Henderson } 2916b384c734SRichard Henderson if (name) { 2917b384c734SRichard Henderson col += ne_fprintf(f, "%s", name); 2918b384c734SRichard Henderson } else { 2919b384c734SRichard Henderson col += ne_fprintf(f, "$0x%" TCG_PRIlx, from); 2920b384c734SRichard Henderson } 2921b384c734SRichard Henderson i = 1; 2922b384c734SRichard Henderson } 2923b384c734SRichard Henderson break; 2924b384c734SRichard Henderson #endif 2925be210acbSRichard Henderson default: 2926f48f3edeSblueswir1 i = 0; 2927be210acbSRichard Henderson break; 2928be210acbSRichard Henderson } 292951e3972cSRichard Henderson switch (c) { 293051e3972cSRichard Henderson case INDEX_op_set_label: 293151e3972cSRichard Henderson case INDEX_op_br: 293251e3972cSRichard Henderson case INDEX_op_brcond_i32: 293351e3972cSRichard Henderson case INDEX_op_brcond_i64: 293451e3972cSRichard Henderson case INDEX_op_brcond2_i32: 2935b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s$L%d", k ? "," : "", 2936efee3746SRichard Henderson arg_label(op->args[k])->id); 293751e3972cSRichard Henderson i++, k++; 293851e3972cSRichard Henderson break; 29393470867bSRichard Henderson case INDEX_op_mb: 29403470867bSRichard Henderson { 29413470867bSRichard Henderson TCGBar membar = op->args[k]; 29423470867bSRichard Henderson const char *b_op, *m_op; 29433470867bSRichard Henderson 29443470867bSRichard Henderson switch (membar & TCG_BAR_SC) { 29453470867bSRichard Henderson case 0: 29463470867bSRichard Henderson b_op = "none"; 29473470867bSRichard Henderson break; 29483470867bSRichard Henderson case TCG_BAR_LDAQ: 29493470867bSRichard Henderson b_op = "acq"; 29503470867bSRichard Henderson break; 29513470867bSRichard Henderson case TCG_BAR_STRL: 29523470867bSRichard Henderson b_op = "rel"; 29533470867bSRichard Henderson break; 29543470867bSRichard Henderson case TCG_BAR_SC: 29553470867bSRichard Henderson b_op = "seq"; 29563470867bSRichard Henderson break; 29573470867bSRichard Henderson default: 29583470867bSRichard Henderson g_assert_not_reached(); 29593470867bSRichard Henderson } 29603470867bSRichard Henderson 29613470867bSRichard Henderson switch (membar & TCG_MO_ALL) { 29623470867bSRichard Henderson case 0: 29633470867bSRichard Henderson m_op = "none"; 29643470867bSRichard Henderson break; 29653470867bSRichard Henderson case TCG_MO_LD_LD: 29663470867bSRichard Henderson m_op = "rr"; 29673470867bSRichard Henderson break; 29683470867bSRichard Henderson case TCG_MO_LD_ST: 29693470867bSRichard Henderson m_op = "rw"; 29703470867bSRichard Henderson break; 29713470867bSRichard Henderson case TCG_MO_ST_LD: 29723470867bSRichard Henderson m_op = "wr"; 29733470867bSRichard Henderson break; 29743470867bSRichard Henderson case TCG_MO_ST_ST: 29753470867bSRichard Henderson m_op = "ww"; 29763470867bSRichard Henderson break; 29773470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_LD_ST: 29783470867bSRichard Henderson m_op = "rr+rw"; 29793470867bSRichard Henderson break; 29803470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_ST_LD: 29813470867bSRichard Henderson m_op = "rr+wr"; 29823470867bSRichard Henderson break; 29833470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_ST_ST: 29843470867bSRichard Henderson m_op = "rr+ww"; 29853470867bSRichard Henderson break; 29863470867bSRichard Henderson case TCG_MO_LD_ST | TCG_MO_ST_LD: 29873470867bSRichard Henderson m_op = "rw+wr"; 29883470867bSRichard Henderson break; 29893470867bSRichard Henderson case TCG_MO_LD_ST | TCG_MO_ST_ST: 29903470867bSRichard Henderson m_op = "rw+ww"; 29913470867bSRichard Henderson break; 29923470867bSRichard Henderson case TCG_MO_ST_LD | TCG_MO_ST_ST: 29933470867bSRichard Henderson m_op = "wr+ww"; 29943470867bSRichard Henderson break; 29953470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_MO_ST_LD: 29963470867bSRichard Henderson m_op = "rr+rw+wr"; 29973470867bSRichard Henderson break; 29983470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_MO_ST_ST: 29993470867bSRichard Henderson m_op = "rr+rw+ww"; 30003470867bSRichard Henderson break; 30013470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_ST_LD | TCG_MO_ST_ST: 30023470867bSRichard Henderson m_op = "rr+wr+ww"; 30033470867bSRichard Henderson break; 30043470867bSRichard Henderson case TCG_MO_LD_ST | TCG_MO_ST_LD | TCG_MO_ST_ST: 30053470867bSRichard Henderson m_op = "rw+wr+ww"; 30063470867bSRichard Henderson break; 30073470867bSRichard Henderson case TCG_MO_ALL: 30083470867bSRichard Henderson m_op = "all"; 30093470867bSRichard Henderson break; 30103470867bSRichard Henderson default: 30113470867bSRichard Henderson g_assert_not_reached(); 30123470867bSRichard Henderson } 30133470867bSRichard Henderson 30143470867bSRichard Henderson col += ne_fprintf(f, "%s%s:%s", (k ? "," : ""), b_op, m_op); 30153470867bSRichard Henderson i++, k++; 30163470867bSRichard Henderson } 30173470867bSRichard Henderson break; 301851e3972cSRichard Henderson default: 301951e3972cSRichard Henderson break; 3020eeacee4dSBlue Swirl } 302151e3972cSRichard Henderson for (; i < nb_cargs; i++, k++) { 3022b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s$0x%" TCG_PRIlx, k ? "," : "", 3023b7a83ff8SRichard Henderson op->args[k]); 3024bdfb460eSRichard Henderson } 3025bdfb460eSRichard Henderson } 3026bdfb460eSRichard Henderson 30271894f69aSRichard Henderson if (have_prefs || op->life) { 30281894f69aSRichard Henderson for (; col < 40; ++col) { 3029b7a83ff8SRichard Henderson putc(' ', f); 3030bdfb460eSRichard Henderson } 30311894f69aSRichard Henderson } 30321894f69aSRichard Henderson 30331894f69aSRichard Henderson if (op->life) { 30341894f69aSRichard Henderson unsigned life = op->life; 3035bdfb460eSRichard Henderson 3036bdfb460eSRichard Henderson if (life & (SYNC_ARG * 3)) { 3037b7a83ff8SRichard Henderson ne_fprintf(f, " sync:"); 3038bdfb460eSRichard Henderson for (i = 0; i < 2; ++i) { 3039bdfb460eSRichard Henderson if (life & (SYNC_ARG << i)) { 3040b7a83ff8SRichard Henderson ne_fprintf(f, " %d", i); 3041bdfb460eSRichard Henderson } 3042bdfb460eSRichard Henderson } 3043bdfb460eSRichard Henderson } 3044bdfb460eSRichard Henderson life /= DEAD_ARG; 3045bdfb460eSRichard Henderson if (life) { 3046b7a83ff8SRichard Henderson ne_fprintf(f, " dead:"); 3047bdfb460eSRichard Henderson for (i = 0; life; ++i, life >>= 1) { 3048bdfb460eSRichard Henderson if (life & 1) { 3049b7a83ff8SRichard Henderson ne_fprintf(f, " %d", i); 3050bdfb460eSRichard Henderson } 3051bdfb460eSRichard Henderson } 3052c896fe29Sbellard } 3053b03cce8eSbellard } 30541894f69aSRichard Henderson 30551894f69aSRichard Henderson if (have_prefs) { 30561894f69aSRichard Henderson for (i = 0; i < nb_oargs; ++i) { 305731fd884bSRichard Henderson TCGRegSet set = output_pref(op, i); 30581894f69aSRichard Henderson 30591894f69aSRichard Henderson if (i == 0) { 3060b7a83ff8SRichard Henderson ne_fprintf(f, " pref="); 30611894f69aSRichard Henderson } else { 3062b7a83ff8SRichard Henderson ne_fprintf(f, ","); 30631894f69aSRichard Henderson } 30641894f69aSRichard Henderson if (set == 0) { 3065b7a83ff8SRichard Henderson ne_fprintf(f, "none"); 30661894f69aSRichard Henderson } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) { 3067b7a83ff8SRichard Henderson ne_fprintf(f, "all"); 30681894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG 30691894f69aSRichard Henderson } else if (tcg_regset_single(set)) { 30701894f69aSRichard Henderson TCGReg reg = tcg_regset_first(set); 3071b7a83ff8SRichard Henderson ne_fprintf(f, "%s", tcg_target_reg_names[reg]); 30721894f69aSRichard Henderson #endif 30731894f69aSRichard Henderson } else if (TCG_TARGET_NB_REGS <= 32) { 3074b7a83ff8SRichard Henderson ne_fprintf(f, "0x%x", (uint32_t)set); 30751894f69aSRichard Henderson } else { 3076b7a83ff8SRichard Henderson ne_fprintf(f, "0x%" PRIx64, (uint64_t)set); 30771894f69aSRichard Henderson } 30781894f69aSRichard Henderson } 30791894f69aSRichard Henderson } 30801894f69aSRichard Henderson 3081b7a83ff8SRichard Henderson putc('\n', f); 3082c896fe29Sbellard } 3083c896fe29Sbellard } 3084c896fe29Sbellard 3085c896fe29Sbellard /* we give more priority to constraints with less registers */ 30863e80824eSRichard Henderson static int get_constraint_priority(const TCGArgConstraint *arg_ct, int k) 3087c896fe29Sbellard { 30883e80824eSRichard Henderson int n; 30893e80824eSRichard Henderson 30903e80824eSRichard Henderson arg_ct += k; 30913e80824eSRichard Henderson n = ctpop64(arg_ct->regs); 3092c896fe29Sbellard 309329f5e925SRichard Henderson /* 309429f5e925SRichard Henderson * Sort constraints of a single register first, which includes output 309529f5e925SRichard Henderson * aliases (which must exactly match the input already allocated). 309629f5e925SRichard Henderson */ 309729f5e925SRichard Henderson if (n == 1 || arg_ct->oalias) { 309829f5e925SRichard Henderson return INT_MAX; 3099c896fe29Sbellard } 310029f5e925SRichard Henderson 310129f5e925SRichard Henderson /* 310229f5e925SRichard Henderson * Sort register pairs next, first then second immediately after. 310329f5e925SRichard Henderson * Arbitrarily sort multiple pairs by the index of the first reg; 310429f5e925SRichard Henderson * there shouldn't be many pairs. 310529f5e925SRichard Henderson */ 310629f5e925SRichard Henderson switch (arg_ct->pair) { 310729f5e925SRichard Henderson case 1: 310829f5e925SRichard Henderson case 3: 310929f5e925SRichard Henderson return (k + 1) * 2; 311029f5e925SRichard Henderson case 2: 311129f5e925SRichard Henderson return (arg_ct->pair_index + 1) * 2 - 1; 311229f5e925SRichard Henderson } 311329f5e925SRichard Henderson 311429f5e925SRichard Henderson /* Finally, sort by decreasing register count. */ 311529f5e925SRichard Henderson assert(n > 1); 311629f5e925SRichard Henderson return -n; 3117c896fe29Sbellard } 3118c896fe29Sbellard 3119c896fe29Sbellard /* sort from highest priority to lowest */ 31203e80824eSRichard Henderson static void sort_constraints(TCGArgConstraint *a, int start, int n) 3121c896fe29Sbellard { 312266792f90SRichard Henderson int i, j; 3123c896fe29Sbellard 312466792f90SRichard Henderson for (i = 0; i < n; i++) { 312566792f90SRichard Henderson a[start + i].sort_index = start + i; 312666792f90SRichard Henderson } 312766792f90SRichard Henderson if (n <= 1) { 3128c896fe29Sbellard return; 312966792f90SRichard Henderson } 3130c896fe29Sbellard for (i = 0; i < n - 1; i++) { 3131c896fe29Sbellard for (j = i + 1; j < n; j++) { 31323e80824eSRichard Henderson int p1 = get_constraint_priority(a, a[start + i].sort_index); 31333e80824eSRichard Henderson int p2 = get_constraint_priority(a, a[start + j].sort_index); 3134c896fe29Sbellard if (p1 < p2) { 313566792f90SRichard Henderson int tmp = a[start + i].sort_index; 313666792f90SRichard Henderson a[start + i].sort_index = a[start + j].sort_index; 313766792f90SRichard Henderson a[start + j].sort_index = tmp; 3138c896fe29Sbellard } 3139c896fe29Sbellard } 3140c896fe29Sbellard } 3141c896fe29Sbellard } 3142c896fe29Sbellard 31433e80824eSRichard Henderson static const TCGArgConstraint empty_cts[TCG_MAX_OP_ARGS]; 31443e80824eSRichard Henderson static TCGArgConstraint all_cts[ARRAY_SIZE(constraint_sets)][TCG_MAX_OP_ARGS]; 31453e80824eSRichard Henderson 3146501fb3daSRichard Henderson static void process_constraint_sets(void) 3147c896fe29Sbellard { 31483e80824eSRichard Henderson for (size_t c = 0; c < ARRAY_SIZE(constraint_sets); ++c) { 31493e80824eSRichard Henderson const TCGConstraintSet *tdefs = &constraint_sets[c]; 31503e80824eSRichard Henderson TCGArgConstraint *args_ct = all_cts[c]; 31513e80824eSRichard Henderson int nb_oargs = tdefs->nb_oargs; 31523e80824eSRichard Henderson int nb_iargs = tdefs->nb_iargs; 31533e80824eSRichard Henderson int nb_args = nb_oargs + nb_iargs; 315429f5e925SRichard Henderson bool saw_alias_pair = false; 3155f69d277eSRichard Henderson 31563e80824eSRichard Henderson for (int i = 0; i < nb_args; i++) { 3157f69d277eSRichard Henderson const char *ct_str = tdefs->args_ct_str[i]; 31583e80824eSRichard Henderson bool input_p = i >= nb_oargs; 31593e80824eSRichard Henderson int o; 3160f69d277eSRichard Henderson 316117280ff4SRichard Henderson switch (*ct_str) { 316217280ff4SRichard Henderson case '0' ... '9': 31638940ea0dSPhilippe Mathieu-Daudé o = *ct_str - '0'; 31648940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(input_p); 31653e80824eSRichard Henderson tcg_debug_assert(o < nb_oargs); 31663e80824eSRichard Henderson tcg_debug_assert(args_ct[o].regs != 0); 31673e80824eSRichard Henderson tcg_debug_assert(!args_ct[o].oalias); 31683e80824eSRichard Henderson args_ct[i] = args_ct[o]; 3169bc2b17e6SRichard Henderson /* The output sets oalias. */ 31703e80824eSRichard Henderson args_ct[o].oalias = 1; 31713e80824eSRichard Henderson args_ct[o].alias_index = i; 3172bc2b17e6SRichard Henderson /* The input sets ialias. */ 31733e80824eSRichard Henderson args_ct[i].ialias = 1; 31743e80824eSRichard Henderson args_ct[i].alias_index = o; 31753e80824eSRichard Henderson if (args_ct[i].pair) { 317629f5e925SRichard Henderson saw_alias_pair = true; 317729f5e925SRichard Henderson } 31788940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(ct_str[1] == '\0'); 31798940ea0dSPhilippe Mathieu-Daudé continue; 31808940ea0dSPhilippe Mathieu-Daudé 318182790a87SRichard Henderson case '&': 31828940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(!input_p); 31833e80824eSRichard Henderson args_ct[i].newreg = true; 318482790a87SRichard Henderson ct_str++; 318582790a87SRichard Henderson break; 318629f5e925SRichard Henderson 318729f5e925SRichard Henderson case 'p': /* plus */ 318829f5e925SRichard Henderson /* Allocate to the register after the previous. */ 31893e80824eSRichard Henderson tcg_debug_assert(i > (input_p ? nb_oargs : 0)); 319029f5e925SRichard Henderson o = i - 1; 31913e80824eSRichard Henderson tcg_debug_assert(!args_ct[o].pair); 31923e80824eSRichard Henderson tcg_debug_assert(!args_ct[o].ct); 31933e80824eSRichard Henderson args_ct[i] = (TCGArgConstraint){ 319429f5e925SRichard Henderson .pair = 2, 319529f5e925SRichard Henderson .pair_index = o, 31963e80824eSRichard Henderson .regs = args_ct[o].regs << 1, 31973e80824eSRichard Henderson .newreg = args_ct[o].newreg, 319829f5e925SRichard Henderson }; 31993e80824eSRichard Henderson args_ct[o].pair = 1; 32003e80824eSRichard Henderson args_ct[o].pair_index = i; 320129f5e925SRichard Henderson tcg_debug_assert(ct_str[1] == '\0'); 320229f5e925SRichard Henderson continue; 320329f5e925SRichard Henderson 320429f5e925SRichard Henderson case 'm': /* minus */ 320529f5e925SRichard Henderson /* Allocate to the register before the previous. */ 32063e80824eSRichard Henderson tcg_debug_assert(i > (input_p ? nb_oargs : 0)); 320729f5e925SRichard Henderson o = i - 1; 32083e80824eSRichard Henderson tcg_debug_assert(!args_ct[o].pair); 32093e80824eSRichard Henderson tcg_debug_assert(!args_ct[o].ct); 32103e80824eSRichard Henderson args_ct[i] = (TCGArgConstraint){ 321129f5e925SRichard Henderson .pair = 1, 321229f5e925SRichard Henderson .pair_index = o, 32133e80824eSRichard Henderson .regs = args_ct[o].regs >> 1, 32143e80824eSRichard Henderson .newreg = args_ct[o].newreg, 321529f5e925SRichard Henderson }; 32163e80824eSRichard Henderson args_ct[o].pair = 2; 32173e80824eSRichard Henderson args_ct[o].pair_index = i; 321829f5e925SRichard Henderson tcg_debug_assert(ct_str[1] == '\0'); 321929f5e925SRichard Henderson continue; 32208940ea0dSPhilippe Mathieu-Daudé } 32218940ea0dSPhilippe Mathieu-Daudé 32228940ea0dSPhilippe Mathieu-Daudé do { 32238940ea0dSPhilippe Mathieu-Daudé switch (*ct_str) { 3224c896fe29Sbellard case 'i': 32253e80824eSRichard Henderson args_ct[i].ct |= TCG_CT_CONST; 3226c896fe29Sbellard break; 3227358b4923SRichard Henderson 3228358b4923SRichard Henderson /* Include all of the target-specific constraints. */ 3229358b4923SRichard Henderson 3230358b4923SRichard Henderson #undef CONST 3231358b4923SRichard Henderson #define CONST(CASE, MASK) \ 32323e80824eSRichard Henderson case CASE: args_ct[i].ct |= MASK; break; 3233358b4923SRichard Henderson #define REGS(CASE, MASK) \ 32343e80824eSRichard Henderson case CASE: args_ct[i].regs |= MASK; break; 3235358b4923SRichard Henderson 3236358b4923SRichard Henderson #include "tcg-target-con-str.h" 3237358b4923SRichard Henderson 3238358b4923SRichard Henderson #undef REGS 3239358b4923SRichard Henderson #undef CONST 3240c896fe29Sbellard default: 32418940ea0dSPhilippe Mathieu-Daudé case '0' ... '9': 32428940ea0dSPhilippe Mathieu-Daudé case '&': 324329f5e925SRichard Henderson case 'p': 324429f5e925SRichard Henderson case 'm': 32453e80824eSRichard Henderson /* Typo in TCGConstraintSet constraint. */ 3246358b4923SRichard Henderson g_assert_not_reached(); 3247358b4923SRichard Henderson } 32488940ea0dSPhilippe Mathieu-Daudé } while (*++ct_str != '\0'); 3249c896fe29Sbellard } 3250c896fe29Sbellard 325129f5e925SRichard Henderson /* 325229f5e925SRichard Henderson * Fix up output pairs that are aliased with inputs. 325329f5e925SRichard Henderson * When we created the alias, we copied pair from the output. 325429f5e925SRichard Henderson * There are three cases: 325529f5e925SRichard Henderson * (1a) Pairs of inputs alias pairs of outputs. 325629f5e925SRichard Henderson * (1b) One input aliases the first of a pair of outputs. 325729f5e925SRichard Henderson * (2) One input aliases the second of a pair of outputs. 325829f5e925SRichard Henderson * 325929f5e925SRichard Henderson * Case 1a is handled by making sure that the pair_index'es are 326029f5e925SRichard Henderson * properly updated so that they appear the same as a pair of inputs. 326129f5e925SRichard Henderson * 326229f5e925SRichard Henderson * Case 1b is handled by setting the pair_index of the input to 326329f5e925SRichard Henderson * itself, simply so it doesn't point to an unrelated argument. 326429f5e925SRichard Henderson * Since we don't encounter the "second" during the input allocation 326529f5e925SRichard Henderson * phase, nothing happens with the second half of the input pair. 326629f5e925SRichard Henderson * 326729f5e925SRichard Henderson * Case 2 is handled by setting the second input to pair=3, the 326829f5e925SRichard Henderson * first output to pair=3, and the pair_index'es to match. 326929f5e925SRichard Henderson */ 327029f5e925SRichard Henderson if (saw_alias_pair) { 32713e80824eSRichard Henderson for (int i = nb_oargs; i < nb_args; i++) { 32723e80824eSRichard Henderson int o, o2, i2; 32733e80824eSRichard Henderson 327429f5e925SRichard Henderson /* 327529f5e925SRichard Henderson * Since [0-9pm] must be alone in the constraint string, 327629f5e925SRichard Henderson * the only way they can both be set is if the pair comes 327729f5e925SRichard Henderson * from the output alias. 327829f5e925SRichard Henderson */ 32793e80824eSRichard Henderson if (!args_ct[i].ialias) { 328029f5e925SRichard Henderson continue; 328129f5e925SRichard Henderson } 32823e80824eSRichard Henderson switch (args_ct[i].pair) { 328329f5e925SRichard Henderson case 0: 328429f5e925SRichard Henderson break; 328529f5e925SRichard Henderson case 1: 32863e80824eSRichard Henderson o = args_ct[i].alias_index; 32873e80824eSRichard Henderson o2 = args_ct[o].pair_index; 32883e80824eSRichard Henderson tcg_debug_assert(args_ct[o].pair == 1); 32893e80824eSRichard Henderson tcg_debug_assert(args_ct[o2].pair == 2); 32903e80824eSRichard Henderson if (args_ct[o2].oalias) { 329129f5e925SRichard Henderson /* Case 1a */ 32923e80824eSRichard Henderson i2 = args_ct[o2].alias_index; 32933e80824eSRichard Henderson tcg_debug_assert(args_ct[i2].pair == 2); 32943e80824eSRichard Henderson args_ct[i2].pair_index = i; 32953e80824eSRichard Henderson args_ct[i].pair_index = i2; 329629f5e925SRichard Henderson } else { 329729f5e925SRichard Henderson /* Case 1b */ 32983e80824eSRichard Henderson args_ct[i].pair_index = i; 329929f5e925SRichard Henderson } 330029f5e925SRichard Henderson break; 330129f5e925SRichard Henderson case 2: 33023e80824eSRichard Henderson o = args_ct[i].alias_index; 33033e80824eSRichard Henderson o2 = args_ct[o].pair_index; 33043e80824eSRichard Henderson tcg_debug_assert(args_ct[o].pair == 2); 33053e80824eSRichard Henderson tcg_debug_assert(args_ct[o2].pair == 1); 33063e80824eSRichard Henderson if (args_ct[o2].oalias) { 330729f5e925SRichard Henderson /* Case 1a */ 33083e80824eSRichard Henderson i2 = args_ct[o2].alias_index; 33093e80824eSRichard Henderson tcg_debug_assert(args_ct[i2].pair == 1); 33103e80824eSRichard Henderson args_ct[i2].pair_index = i; 33113e80824eSRichard Henderson args_ct[i].pair_index = i2; 331229f5e925SRichard Henderson } else { 331329f5e925SRichard Henderson /* Case 2 */ 33143e80824eSRichard Henderson args_ct[i].pair = 3; 33153e80824eSRichard Henderson args_ct[o2].pair = 3; 33163e80824eSRichard Henderson args_ct[i].pair_index = o2; 33173e80824eSRichard Henderson args_ct[o2].pair_index = i; 331829f5e925SRichard Henderson } 331929f5e925SRichard Henderson break; 332029f5e925SRichard Henderson default: 332129f5e925SRichard Henderson g_assert_not_reached(); 332229f5e925SRichard Henderson } 332329f5e925SRichard Henderson } 332429f5e925SRichard Henderson } 332529f5e925SRichard Henderson 3326c896fe29Sbellard /* sort the constraints (XXX: this is just an heuristic) */ 33273e80824eSRichard Henderson sort_constraints(args_ct, 0, nb_oargs); 33283e80824eSRichard Henderson sort_constraints(args_ct, nb_oargs, nb_iargs); 33293e80824eSRichard Henderson } 3330501fb3daSRichard Henderson } 33313e80824eSRichard Henderson 3332501fb3daSRichard Henderson static const TCGArgConstraint *opcode_args_ct(const TCGOp *op) 3333501fb3daSRichard Henderson { 3334ed1a653bSRichard Henderson const TCGOpDef *def = &tcg_op_defs[op->opc]; 33353e80824eSRichard Henderson TCGConstraintSetIndex con_set; 33363e80824eSRichard Henderson 3337b277cdd2SRichard Henderson #ifdef CONFIG_DEBUG_TCG 3338b277cdd2SRichard Henderson assert(tcg_op_supported(op->opc, TCGOP_TYPE(op), TCGOP_FLAGS(op))); 3339b277cdd2SRichard Henderson #endif 3340b277cdd2SRichard Henderson 33413e80824eSRichard Henderson if (def->flags & TCG_OPF_NOT_PRESENT) { 3342501fb3daSRichard Henderson return empty_cts; 33433e80824eSRichard Henderson } 33443e80824eSRichard Henderson 33456323b363SRichard Henderson con_set = tcg_target_op_def(op->opc, TCGOP_TYPE(op), TCGOP_FLAGS(op)); 33463e80824eSRichard Henderson tcg_debug_assert(con_set >= 0 && con_set < ARRAY_SIZE(constraint_sets)); 33473e80824eSRichard Henderson 33483e80824eSRichard Henderson /* The constraint arguments must match TCGOpcode arguments. */ 3349501fb3daSRichard Henderson tcg_debug_assert(constraint_sets[con_set].nb_oargs == def->nb_oargs); 3350501fb3daSRichard Henderson tcg_debug_assert(constraint_sets[con_set].nb_iargs == def->nb_iargs); 33513e80824eSRichard Henderson 3352501fb3daSRichard Henderson return all_cts[con_set]; 3353c896fe29Sbellard } 3354c896fe29Sbellard 3355f85b1fc4SRichard Henderson static void remove_label_use(TCGOp *op, int idx) 3356f85b1fc4SRichard Henderson { 3357f85b1fc4SRichard Henderson TCGLabel *label = arg_label(op->args[idx]); 3358f85b1fc4SRichard Henderson TCGLabelUse *use; 3359f85b1fc4SRichard Henderson 3360f85b1fc4SRichard Henderson QSIMPLEQ_FOREACH(use, &label->branches, next) { 3361f85b1fc4SRichard Henderson if (use->op == op) { 3362f85b1fc4SRichard Henderson QSIMPLEQ_REMOVE(&label->branches, use, TCGLabelUse, next); 3363f85b1fc4SRichard Henderson return; 3364f85b1fc4SRichard Henderson } 3365f85b1fc4SRichard Henderson } 3366f85b1fc4SRichard Henderson g_assert_not_reached(); 3367f85b1fc4SRichard Henderson } 3368f85b1fc4SRichard Henderson 33690c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op) 33700c627cdcSRichard Henderson { 3371d88a117eSRichard Henderson switch (op->opc) { 3372d88a117eSRichard Henderson case INDEX_op_br: 3373f85b1fc4SRichard Henderson remove_label_use(op, 0); 3374d88a117eSRichard Henderson break; 3375d88a117eSRichard Henderson case INDEX_op_brcond_i32: 3376d88a117eSRichard Henderson case INDEX_op_brcond_i64: 3377f85b1fc4SRichard Henderson remove_label_use(op, 3); 3378d88a117eSRichard Henderson break; 3379d88a117eSRichard Henderson case INDEX_op_brcond2_i32: 3380f85b1fc4SRichard Henderson remove_label_use(op, 5); 3381d88a117eSRichard Henderson break; 3382d88a117eSRichard Henderson default: 3383d88a117eSRichard Henderson break; 3384d88a117eSRichard Henderson } 3385d88a117eSRichard Henderson 338615fa08f8SRichard Henderson QTAILQ_REMOVE(&s->ops, op, link); 338715fa08f8SRichard Henderson QTAILQ_INSERT_TAIL(&s->free_ops, op, link); 3388abebf925SRichard Henderson s->nb_ops--; 33890c627cdcSRichard Henderson } 33900c627cdcSRichard Henderson 3391a80cdd31SRichard Henderson void tcg_remove_ops_after(TCGOp *op) 3392a80cdd31SRichard Henderson { 3393a80cdd31SRichard Henderson TCGContext *s = tcg_ctx; 3394a80cdd31SRichard Henderson 3395a80cdd31SRichard Henderson while (true) { 3396a80cdd31SRichard Henderson TCGOp *last = tcg_last_op(); 3397a80cdd31SRichard Henderson if (last == op) { 3398a80cdd31SRichard Henderson return; 3399a80cdd31SRichard Henderson } 3400a80cdd31SRichard Henderson tcg_op_remove(s, last); 3401a80cdd31SRichard Henderson } 3402a80cdd31SRichard Henderson } 3403a80cdd31SRichard Henderson 3404d4478943SPhilippe Mathieu-Daudé static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs) 340515fa08f8SRichard Henderson { 340615fa08f8SRichard Henderson TCGContext *s = tcg_ctx; 3407cb10bc63SRichard Henderson TCGOp *op = NULL; 340815fa08f8SRichard Henderson 3409cb10bc63SRichard Henderson if (unlikely(!QTAILQ_EMPTY(&s->free_ops))) { 3410cb10bc63SRichard Henderson QTAILQ_FOREACH(op, &s->free_ops, link) { 3411cb10bc63SRichard Henderson if (nargs <= op->nargs) { 341215fa08f8SRichard Henderson QTAILQ_REMOVE(&s->free_ops, op, link); 3413cb10bc63SRichard Henderson nargs = op->nargs; 3414cb10bc63SRichard Henderson goto found; 341515fa08f8SRichard Henderson } 3416cb10bc63SRichard Henderson } 3417cb10bc63SRichard Henderson } 3418cb10bc63SRichard Henderson 3419cb10bc63SRichard Henderson /* Most opcodes have 3 or 4 operands: reduce fragmentation. */ 3420cb10bc63SRichard Henderson nargs = MAX(4, nargs); 3421cb10bc63SRichard Henderson op = tcg_malloc(sizeof(TCGOp) + sizeof(TCGArg) * nargs); 3422cb10bc63SRichard Henderson 3423cb10bc63SRichard Henderson found: 342415fa08f8SRichard Henderson memset(op, 0, offsetof(TCGOp, link)); 342515fa08f8SRichard Henderson op->opc = opc; 3426cb10bc63SRichard Henderson op->nargs = nargs; 342715fa08f8SRichard Henderson 3428cb10bc63SRichard Henderson /* Check for bitfield overflow. */ 3429cb10bc63SRichard Henderson tcg_debug_assert(op->nargs == nargs); 3430cb10bc63SRichard Henderson 3431cb10bc63SRichard Henderson s->nb_ops++; 343215fa08f8SRichard Henderson return op; 343315fa08f8SRichard Henderson } 343415fa08f8SRichard Henderson 3435d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_emit_op(TCGOpcode opc, unsigned nargs) 343615fa08f8SRichard Henderson { 3437d4478943SPhilippe Mathieu-Daudé TCGOp *op = tcg_op_alloc(opc, nargs); 343807843f75SRichard Henderson 343907843f75SRichard Henderson if (tcg_ctx->emit_before_op) { 344007843f75SRichard Henderson QTAILQ_INSERT_BEFORE(tcg_ctx->emit_before_op, op, link); 344107843f75SRichard Henderson } else { 344215fa08f8SRichard Henderson QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link); 344307843f75SRichard Henderson } 344415fa08f8SRichard Henderson return op; 344515fa08f8SRichard Henderson } 344615fa08f8SRichard Henderson 3447d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op, 3448d4478943SPhilippe Mathieu-Daudé TCGOpcode opc, unsigned nargs) 34495a18407fSRichard Henderson { 3450d4478943SPhilippe Mathieu-Daudé TCGOp *new_op = tcg_op_alloc(opc, nargs); 3451fb744eceSRichard Henderson 3452fb744eceSRichard Henderson TCGOP_TYPE(new_op) = TCGOP_TYPE(old_op); 345315fa08f8SRichard Henderson QTAILQ_INSERT_BEFORE(old_op, new_op, link); 34545a18407fSRichard Henderson return new_op; 34555a18407fSRichard Henderson } 34565a18407fSRichard Henderson 3457d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, 3458d4478943SPhilippe Mathieu-Daudé TCGOpcode opc, unsigned nargs) 34595a18407fSRichard Henderson { 3460d4478943SPhilippe Mathieu-Daudé TCGOp *new_op = tcg_op_alloc(opc, nargs); 3461fb744eceSRichard Henderson 3462fb744eceSRichard Henderson TCGOP_TYPE(new_op) = TCGOP_TYPE(old_op); 346315fa08f8SRichard Henderson QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link); 34645a18407fSRichard Henderson return new_op; 34655a18407fSRichard Henderson } 34665a18407fSRichard Henderson 3467968f305eSRichard Henderson static void move_label_uses(TCGLabel *to, TCGLabel *from) 3468968f305eSRichard Henderson { 3469968f305eSRichard Henderson TCGLabelUse *u; 3470968f305eSRichard Henderson 3471968f305eSRichard Henderson QSIMPLEQ_FOREACH(u, &from->branches, next) { 3472968f305eSRichard Henderson TCGOp *op = u->op; 3473968f305eSRichard Henderson switch (op->opc) { 3474968f305eSRichard Henderson case INDEX_op_br: 3475968f305eSRichard Henderson op->args[0] = label_arg(to); 3476968f305eSRichard Henderson break; 3477968f305eSRichard Henderson case INDEX_op_brcond_i32: 3478968f305eSRichard Henderson case INDEX_op_brcond_i64: 3479968f305eSRichard Henderson op->args[3] = label_arg(to); 3480968f305eSRichard Henderson break; 3481968f305eSRichard Henderson case INDEX_op_brcond2_i32: 3482968f305eSRichard Henderson op->args[5] = label_arg(to); 3483968f305eSRichard Henderson break; 3484968f305eSRichard Henderson default: 3485968f305eSRichard Henderson g_assert_not_reached(); 3486968f305eSRichard Henderson } 3487968f305eSRichard Henderson } 3488968f305eSRichard Henderson 3489968f305eSRichard Henderson QSIMPLEQ_CONCAT(&to->branches, &from->branches); 3490968f305eSRichard Henderson } 3491968f305eSRichard Henderson 3492b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code. */ 34939bbee4c0SRichard Henderson static void __attribute__((noinline)) 34949bbee4c0SRichard Henderson reachable_code_pass(TCGContext *s) 3495b4fc67c7SRichard Henderson { 34964d89d0bbSRichard Henderson TCGOp *op, *op_next, *op_prev; 3497b4fc67c7SRichard Henderson bool dead = false; 3498b4fc67c7SRichard Henderson 3499b4fc67c7SRichard Henderson QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) { 3500b4fc67c7SRichard Henderson bool remove = dead; 3501b4fc67c7SRichard Henderson TCGLabel *label; 3502b4fc67c7SRichard Henderson 3503b4fc67c7SRichard Henderson switch (op->opc) { 3504b4fc67c7SRichard Henderson case INDEX_op_set_label: 3505b4fc67c7SRichard Henderson label = arg_label(op->args[0]); 35064d89d0bbSRichard Henderson 35074d89d0bbSRichard Henderson /* 3508968f305eSRichard Henderson * Note that the first op in the TB is always a load, 3509968f305eSRichard Henderson * so there is always something before a label. 3510968f305eSRichard Henderson */ 3511968f305eSRichard Henderson op_prev = QTAILQ_PREV(op, link); 3512968f305eSRichard Henderson 3513968f305eSRichard Henderson /* 3514968f305eSRichard Henderson * If we find two sequential labels, move all branches to 3515968f305eSRichard Henderson * reference the second label and remove the first label. 3516968f305eSRichard Henderson * Do this before branch to next optimization, so that the 3517968f305eSRichard Henderson * middle label is out of the way. 3518968f305eSRichard Henderson */ 3519968f305eSRichard Henderson if (op_prev->opc == INDEX_op_set_label) { 3520968f305eSRichard Henderson move_label_uses(label, arg_label(op_prev->args[0])); 3521968f305eSRichard Henderson tcg_op_remove(s, op_prev); 3522968f305eSRichard Henderson op_prev = QTAILQ_PREV(op, link); 3523968f305eSRichard Henderson } 3524968f305eSRichard Henderson 3525968f305eSRichard Henderson /* 35264d89d0bbSRichard Henderson * Optimization can fold conditional branches to unconditional. 35274d89d0bbSRichard Henderson * If we find a label which is preceded by an unconditional 35284d89d0bbSRichard Henderson * branch to next, remove the branch. We couldn't do this when 35294d89d0bbSRichard Henderson * processing the branch because any dead code between the branch 35304d89d0bbSRichard Henderson * and label had not yet been removed. 35314d89d0bbSRichard Henderson */ 35324d89d0bbSRichard Henderson if (op_prev->opc == INDEX_op_br && 35334d89d0bbSRichard Henderson label == arg_label(op_prev->args[0])) { 35344d89d0bbSRichard Henderson tcg_op_remove(s, op_prev); 35354d89d0bbSRichard Henderson /* Fall through means insns become live again. */ 35364d89d0bbSRichard Henderson dead = false; 35374d89d0bbSRichard Henderson } 35384d89d0bbSRichard Henderson 3539f85b1fc4SRichard Henderson if (QSIMPLEQ_EMPTY(&label->branches)) { 3540b4fc67c7SRichard Henderson /* 3541b4fc67c7SRichard Henderson * While there is an occasional backward branch, virtually 3542b4fc67c7SRichard Henderson * all branches generated by the translators are forward. 3543b4fc67c7SRichard Henderson * Which means that generally we will have already removed 3544b4fc67c7SRichard Henderson * all references to the label that will be, and there is 3545b4fc67c7SRichard Henderson * little to be gained by iterating. 3546b4fc67c7SRichard Henderson */ 3547b4fc67c7SRichard Henderson remove = true; 3548b4fc67c7SRichard Henderson } else { 3549b4fc67c7SRichard Henderson /* Once we see a label, insns become live again. */ 3550b4fc67c7SRichard Henderson dead = false; 3551b4fc67c7SRichard Henderson remove = false; 3552b4fc67c7SRichard Henderson } 3553b4fc67c7SRichard Henderson break; 3554b4fc67c7SRichard Henderson 3555b4fc67c7SRichard Henderson case INDEX_op_br: 3556b4fc67c7SRichard Henderson case INDEX_op_exit_tb: 3557b4fc67c7SRichard Henderson case INDEX_op_goto_ptr: 3558b4fc67c7SRichard Henderson /* Unconditional branches; everything following is dead. */ 3559b4fc67c7SRichard Henderson dead = true; 3560b4fc67c7SRichard Henderson break; 3561b4fc67c7SRichard Henderson 3562b4fc67c7SRichard Henderson case INDEX_op_call: 3563b4fc67c7SRichard Henderson /* Notice noreturn helper calls, raising exceptions. */ 356490163900SRichard Henderson if (tcg_call_flags(op) & TCG_CALL_NO_RETURN) { 3565b4fc67c7SRichard Henderson dead = true; 3566b4fc67c7SRichard Henderson } 3567b4fc67c7SRichard Henderson break; 3568b4fc67c7SRichard Henderson 3569b4fc67c7SRichard Henderson case INDEX_op_insn_start: 3570b4fc67c7SRichard Henderson /* Never remove -- we need to keep these for unwind. */ 3571b4fc67c7SRichard Henderson remove = false; 3572b4fc67c7SRichard Henderson break; 3573b4fc67c7SRichard Henderson 3574b4fc67c7SRichard Henderson default: 3575b4fc67c7SRichard Henderson break; 3576b4fc67c7SRichard Henderson } 3577b4fc67c7SRichard Henderson 3578b4fc67c7SRichard Henderson if (remove) { 3579b4fc67c7SRichard Henderson tcg_op_remove(s, op); 3580b4fc67c7SRichard Henderson } 3581b4fc67c7SRichard Henderson } 3582b4fc67c7SRichard Henderson } 3583b4fc67c7SRichard Henderson 3584c70fbf0aSRichard Henderson #define TS_DEAD 1 3585c70fbf0aSRichard Henderson #define TS_MEM 2 3586c70fbf0aSRichard Henderson 35875a18407fSRichard Henderson #define IS_DEAD_ARG(n) (arg_life & (DEAD_ARG << (n))) 35885a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n))) 35895a18407fSRichard Henderson 359025f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp. */ 359125f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts) 359225f49c5fSRichard Henderson { 359325f49c5fSRichard Henderson return ts->state_ptr; 359425f49c5fSRichard Henderson } 359525f49c5fSRichard Henderson 359625f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the 359725f49c5fSRichard Henderson * maximal regset for its type. 359825f49c5fSRichard Henderson */ 359925f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts) 360025f49c5fSRichard Henderson { 360125f49c5fSRichard Henderson *la_temp_pref(ts) 360225f49c5fSRichard Henderson = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]); 360325f49c5fSRichard Henderson } 360425f49c5fSRichard Henderson 36059c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals 36069c43b68dSAurelien Jarno should be in memory. */ 36072616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt) 3608c896fe29Sbellard { 3609b83eabeaSRichard Henderson int i; 3610b83eabeaSRichard Henderson 3611b83eabeaSRichard Henderson for (i = 0; i < ng; ++i) { 3612b83eabeaSRichard Henderson s->temps[i].state = TS_DEAD | TS_MEM; 361325f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 3614b83eabeaSRichard Henderson } 3615b83eabeaSRichard Henderson for (i = ng; i < nt; ++i) { 3616b83eabeaSRichard Henderson s->temps[i].state = TS_DEAD; 361725f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 3618b83eabeaSRichard Henderson } 3619c896fe29Sbellard } 3620c896fe29Sbellard 36219c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals 36229c43b68dSAurelien Jarno and local temps should be in memory. */ 36232616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt) 3624641d5fbeSbellard { 3625b83eabeaSRichard Henderson int i; 3626641d5fbeSbellard 3627ee17db83SRichard Henderson for (i = 0; i < nt; ++i) { 3628ee17db83SRichard Henderson TCGTemp *ts = &s->temps[i]; 3629ee17db83SRichard Henderson int state; 3630ee17db83SRichard Henderson 3631ee17db83SRichard Henderson switch (ts->kind) { 3632ee17db83SRichard Henderson case TEMP_FIXED: 3633ee17db83SRichard Henderson case TEMP_GLOBAL: 3634f57c6915SRichard Henderson case TEMP_TB: 3635ee17db83SRichard Henderson state = TS_DEAD | TS_MEM; 3636ee17db83SRichard Henderson break; 3637c7482438SRichard Henderson case TEMP_EBB: 3638c0522136SRichard Henderson case TEMP_CONST: 3639ee17db83SRichard Henderson state = TS_DEAD; 3640ee17db83SRichard Henderson break; 3641ee17db83SRichard Henderson default: 3642ee17db83SRichard Henderson g_assert_not_reached(); 3643c70fbf0aSRichard Henderson } 3644ee17db83SRichard Henderson ts->state = state; 3645ee17db83SRichard Henderson la_reset_pref(ts); 3646641d5fbeSbellard } 3647641d5fbeSbellard } 3648641d5fbeSbellard 3649f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory. */ 3650f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng) 3651f65a061cSRichard Henderson { 3652f65a061cSRichard Henderson int i; 3653f65a061cSRichard Henderson 3654f65a061cSRichard Henderson for (i = 0; i < ng; ++i) { 365525f49c5fSRichard Henderson int state = s->temps[i].state; 365625f49c5fSRichard Henderson s->temps[i].state = state | TS_MEM; 365725f49c5fSRichard Henderson if (state == TS_DEAD) { 365825f49c5fSRichard Henderson /* If the global was previously dead, reset prefs. */ 365925f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 366025f49c5fSRichard Henderson } 3661f65a061cSRichard Henderson } 3662f65a061cSRichard Henderson } 3663f65a061cSRichard Henderson 3664b4cb76e6SRichard Henderson /* 3665c7482438SRichard Henderson * liveness analysis: conditional branch: all temps are dead unless 3666c7482438SRichard Henderson * explicitly live-across-conditional-branch, globals and local temps 3667c7482438SRichard Henderson * should be synced. 3668b4cb76e6SRichard Henderson */ 3669b4cb76e6SRichard Henderson static void la_bb_sync(TCGContext *s, int ng, int nt) 3670b4cb76e6SRichard Henderson { 3671b4cb76e6SRichard Henderson la_global_sync(s, ng); 3672b4cb76e6SRichard Henderson 3673b4cb76e6SRichard Henderson for (int i = ng; i < nt; ++i) { 3674c0522136SRichard Henderson TCGTemp *ts = &s->temps[i]; 3675c0522136SRichard Henderson int state; 3676c0522136SRichard Henderson 3677c0522136SRichard Henderson switch (ts->kind) { 3678f57c6915SRichard Henderson case TEMP_TB: 3679c0522136SRichard Henderson state = ts->state; 3680c0522136SRichard Henderson ts->state = state | TS_MEM; 3681b4cb76e6SRichard Henderson if (state != TS_DEAD) { 3682b4cb76e6SRichard Henderson continue; 3683b4cb76e6SRichard Henderson } 3684c0522136SRichard Henderson break; 3685c7482438SRichard Henderson case TEMP_EBB: 3686c0522136SRichard Henderson case TEMP_CONST: 3687c0522136SRichard Henderson continue; 3688c0522136SRichard Henderson default: 3689c0522136SRichard Henderson g_assert_not_reached(); 3690b4cb76e6SRichard Henderson } 3691b4cb76e6SRichard Henderson la_reset_pref(&s->temps[i]); 3692b4cb76e6SRichard Henderson } 3693b4cb76e6SRichard Henderson } 3694b4cb76e6SRichard Henderson 3695f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill. */ 3696f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng) 3697f65a061cSRichard Henderson { 3698f65a061cSRichard Henderson int i; 3699f65a061cSRichard Henderson 3700f65a061cSRichard Henderson for (i = 0; i < ng; i++) { 3701f65a061cSRichard Henderson s->temps[i].state = TS_DEAD | TS_MEM; 370225f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 370325f49c5fSRichard Henderson } 370425f49c5fSRichard Henderson } 370525f49c5fSRichard Henderson 370625f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls. */ 370725f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt) 370825f49c5fSRichard Henderson { 370925f49c5fSRichard Henderson TCGRegSet mask = ~tcg_target_call_clobber_regs; 371025f49c5fSRichard Henderson int i; 371125f49c5fSRichard Henderson 371225f49c5fSRichard Henderson for (i = 0; i < nt; i++) { 371325f49c5fSRichard Henderson TCGTemp *ts = &s->temps[i]; 371425f49c5fSRichard Henderson if (!(ts->state & TS_DEAD)) { 371525f49c5fSRichard Henderson TCGRegSet *pset = la_temp_pref(ts); 371625f49c5fSRichard Henderson TCGRegSet set = *pset; 371725f49c5fSRichard Henderson 371825f49c5fSRichard Henderson set &= mask; 371925f49c5fSRichard Henderson /* If the combination is not possible, restart. */ 372025f49c5fSRichard Henderson if (set == 0) { 372125f49c5fSRichard Henderson set = tcg_target_available_regs[ts->type] & mask; 372225f49c5fSRichard Henderson } 372325f49c5fSRichard Henderson *pset = set; 372425f49c5fSRichard Henderson } 3725f65a061cSRichard Henderson } 3726f65a061cSRichard Henderson } 3727f65a061cSRichard Henderson 3728874b8574SRichard Henderson /* 3729874b8574SRichard Henderson * Liveness analysis: Verify the lifetime of TEMP_TB, and reduce 3730874b8574SRichard Henderson * to TEMP_EBB, if possible. 3731874b8574SRichard Henderson */ 3732874b8574SRichard Henderson static void __attribute__((noinline)) 3733874b8574SRichard Henderson liveness_pass_0(TCGContext *s) 3734874b8574SRichard Henderson { 3735874b8574SRichard Henderson void * const multiple_ebb = (void *)(uintptr_t)-1; 3736874b8574SRichard Henderson int nb_temps = s->nb_temps; 3737874b8574SRichard Henderson TCGOp *op, *ebb; 3738874b8574SRichard Henderson 3739874b8574SRichard Henderson for (int i = s->nb_globals; i < nb_temps; ++i) { 3740874b8574SRichard Henderson s->temps[i].state_ptr = NULL; 3741874b8574SRichard Henderson } 3742874b8574SRichard Henderson 3743874b8574SRichard Henderson /* 3744874b8574SRichard Henderson * Represent each EBB by the op at which it begins. In the case of 3745874b8574SRichard Henderson * the first EBB, this is the first op, otherwise it is a label. 3746874b8574SRichard Henderson * Collect the uses of each TEMP_TB: NULL for unused, EBB for use 3747874b8574SRichard Henderson * within a single EBB, else MULTIPLE_EBB. 3748874b8574SRichard Henderson */ 3749874b8574SRichard Henderson ebb = QTAILQ_FIRST(&s->ops); 3750874b8574SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 3751874b8574SRichard Henderson const TCGOpDef *def; 3752874b8574SRichard Henderson int nb_oargs, nb_iargs; 3753874b8574SRichard Henderson 3754874b8574SRichard Henderson switch (op->opc) { 3755874b8574SRichard Henderson case INDEX_op_set_label: 3756874b8574SRichard Henderson ebb = op; 3757874b8574SRichard Henderson continue; 3758874b8574SRichard Henderson case INDEX_op_discard: 3759874b8574SRichard Henderson continue; 3760874b8574SRichard Henderson case INDEX_op_call: 3761874b8574SRichard Henderson nb_oargs = TCGOP_CALLO(op); 3762874b8574SRichard Henderson nb_iargs = TCGOP_CALLI(op); 3763874b8574SRichard Henderson break; 3764874b8574SRichard Henderson default: 3765874b8574SRichard Henderson def = &tcg_op_defs[op->opc]; 3766874b8574SRichard Henderson nb_oargs = def->nb_oargs; 3767874b8574SRichard Henderson nb_iargs = def->nb_iargs; 3768874b8574SRichard Henderson break; 3769874b8574SRichard Henderson } 3770874b8574SRichard Henderson 3771874b8574SRichard Henderson for (int i = 0; i < nb_oargs + nb_iargs; ++i) { 3772874b8574SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]); 3773874b8574SRichard Henderson 3774874b8574SRichard Henderson if (ts->kind != TEMP_TB) { 3775874b8574SRichard Henderson continue; 3776874b8574SRichard Henderson } 3777874b8574SRichard Henderson if (ts->state_ptr == NULL) { 3778874b8574SRichard Henderson ts->state_ptr = ebb; 3779874b8574SRichard Henderson } else if (ts->state_ptr != ebb) { 3780874b8574SRichard Henderson ts->state_ptr = multiple_ebb; 3781874b8574SRichard Henderson } 3782874b8574SRichard Henderson } 3783874b8574SRichard Henderson } 3784874b8574SRichard Henderson 3785874b8574SRichard Henderson /* 3786874b8574SRichard Henderson * For TEMP_TB that turned out not to be used beyond one EBB, 3787874b8574SRichard Henderson * reduce the liveness to TEMP_EBB. 3788874b8574SRichard Henderson */ 3789874b8574SRichard Henderson for (int i = s->nb_globals; i < nb_temps; ++i) { 3790874b8574SRichard Henderson TCGTemp *ts = &s->temps[i]; 3791874b8574SRichard Henderson if (ts->kind == TEMP_TB && ts->state_ptr != multiple_ebb) { 3792874b8574SRichard Henderson ts->kind = TEMP_EBB; 3793874b8574SRichard Henderson } 3794874b8574SRichard Henderson } 3795874b8574SRichard Henderson } 3796874b8574SRichard Henderson 3797a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a 3798c896fe29Sbellard given input arguments is dead. Instructions updating dead 3799c896fe29Sbellard temporaries are removed. */ 38009bbee4c0SRichard Henderson static void __attribute__((noinline)) 38019bbee4c0SRichard Henderson liveness_pass_1(TCGContext *s) 3802c896fe29Sbellard { 3803c70fbf0aSRichard Henderson int nb_globals = s->nb_globals; 38042616c808SRichard Henderson int nb_temps = s->nb_temps; 380515fa08f8SRichard Henderson TCGOp *op, *op_prev; 380625f49c5fSRichard Henderson TCGRegSet *prefs; 380725f49c5fSRichard Henderson int i; 380825f49c5fSRichard Henderson 380925f49c5fSRichard Henderson prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps); 381025f49c5fSRichard Henderson for (i = 0; i < nb_temps; ++i) { 381125f49c5fSRichard Henderson s->temps[i].state_ptr = prefs + i; 381225f49c5fSRichard Henderson } 3813c896fe29Sbellard 3814ae36a246SRichard Henderson /* ??? Should be redundant with the exit_tb that ends the TB. */ 38152616c808SRichard Henderson la_func_end(s, nb_globals, nb_temps); 3816c896fe29Sbellard 3817eae3eb3eSPaolo Bonzini QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) { 381825f49c5fSRichard Henderson int nb_iargs, nb_oargs; 3819c45cb8bbSRichard Henderson TCGOpcode opc_new, opc_new2; 3820c45cb8bbSRichard Henderson bool have_opc_new2; 3821a1b3c48dSRichard Henderson TCGLifeData arg_life = 0; 382225f49c5fSRichard Henderson TCGTemp *ts; 3823c45cb8bbSRichard Henderson TCGOpcode opc = op->opc; 3824c45cb8bbSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 3825501fb3daSRichard Henderson const TCGArgConstraint *args_ct; 3826c45cb8bbSRichard Henderson 3827c45cb8bbSRichard Henderson switch (opc) { 3828c896fe29Sbellard case INDEX_op_call: 3829c6e113f5Sbellard { 383039004a71SRichard Henderson const TCGHelperInfo *info = tcg_call_info(op); 383139004a71SRichard Henderson int call_flags = tcg_call_flags(op); 3832c6e113f5Sbellard 3833cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 3834cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 3835c6e113f5Sbellard 3836c45cb8bbSRichard Henderson /* pure functions can be removed if their result is unused */ 383778505279SAurelien Jarno if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) { 3838c6e113f5Sbellard for (i = 0; i < nb_oargs; i++) { 383925f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 384025f49c5fSRichard Henderson if (ts->state != TS_DEAD) { 3841c6e113f5Sbellard goto do_not_remove_call; 3842c6e113f5Sbellard } 38439c43b68dSAurelien Jarno } 3844c45cb8bbSRichard Henderson goto do_remove; 3845152c35aaSRichard Henderson } 3846c6e113f5Sbellard do_not_remove_call: 3847c896fe29Sbellard 384825f49c5fSRichard Henderson /* Output args are dead. */ 3849c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 385025f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 385125f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 3852a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 38536b64b624SAurelien Jarno } 385425f49c5fSRichard Henderson if (ts->state & TS_MEM) { 3855a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i; 38569c43b68dSAurelien Jarno } 385725f49c5fSRichard Henderson ts->state = TS_DEAD; 385825f49c5fSRichard Henderson la_reset_pref(ts); 3859c896fe29Sbellard } 3860c896fe29Sbellard 386131fd884bSRichard Henderson /* Not used -- it will be tcg_target_call_oarg_reg(). */ 386231fd884bSRichard Henderson memset(op->output_pref, 0, sizeof(op->output_pref)); 386331fd884bSRichard Henderson 386478505279SAurelien Jarno if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS | 386578505279SAurelien Jarno TCG_CALL_NO_READ_GLOBALS))) { 3866f65a061cSRichard Henderson la_global_kill(s, nb_globals); 3867c70fbf0aSRichard Henderson } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) { 3868f65a061cSRichard Henderson la_global_sync(s, nb_globals); 3869b9c18f56Saurel32 } 3870c896fe29Sbellard 387125f49c5fSRichard Henderson /* Record arguments that die in this helper. */ 3872866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 387325f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 387439004a71SRichard Henderson if (ts->state & TS_DEAD) { 3875a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 3876c896fe29Sbellard } 3877c896fe29Sbellard } 387825f49c5fSRichard Henderson 387925f49c5fSRichard Henderson /* For all live registers, remove call-clobbered prefs. */ 388025f49c5fSRichard Henderson la_cross_call(s, nb_temps); 388125f49c5fSRichard Henderson 388239004a71SRichard Henderson /* 388339004a71SRichard Henderson * Input arguments are live for preceding opcodes. 388439004a71SRichard Henderson * 388539004a71SRichard Henderson * For those arguments that die, and will be allocated in 388639004a71SRichard Henderson * registers, clear the register set for that arg, to be 388739004a71SRichard Henderson * filled in below. For args that will be on the stack, 388839004a71SRichard Henderson * reset to any available reg. Process arguments in reverse 388939004a71SRichard Henderson * order so that if a temp is used more than once, the stack 389039004a71SRichard Henderson * reset to max happens before the register reset to 0. 389125f49c5fSRichard Henderson */ 389239004a71SRichard Henderson for (i = nb_iargs - 1; i >= 0; i--) { 389339004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i]; 389439004a71SRichard Henderson ts = arg_temp(op->args[nb_oargs + i]); 389539004a71SRichard Henderson 389639004a71SRichard Henderson if (ts->state & TS_DEAD) { 389739004a71SRichard Henderson switch (loc->kind) { 389839004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 389939004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 390039004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 3901338b61e9SRichard Henderson if (arg_slot_reg_p(loc->arg_slot)) { 390239004a71SRichard Henderson *la_temp_pref(ts) = 0; 390339004a71SRichard Henderson break; 390439004a71SRichard Henderson } 390539004a71SRichard Henderson /* fall through */ 390639004a71SRichard Henderson default: 390739004a71SRichard Henderson *la_temp_pref(ts) = 390839004a71SRichard Henderson tcg_target_available_regs[ts->type]; 390939004a71SRichard Henderson break; 391039004a71SRichard Henderson } 391125f49c5fSRichard Henderson ts->state &= ~TS_DEAD; 391225f49c5fSRichard Henderson } 391325f49c5fSRichard Henderson } 391425f49c5fSRichard Henderson 391539004a71SRichard Henderson /* 391639004a71SRichard Henderson * For each input argument, add its input register to prefs. 391739004a71SRichard Henderson * If a temp is used once, this produces a single set bit; 391839004a71SRichard Henderson * if a temp is used multiple times, this produces a set. 391939004a71SRichard Henderson */ 392039004a71SRichard Henderson for (i = 0; i < nb_iargs; i++) { 392139004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i]; 392239004a71SRichard Henderson ts = arg_temp(op->args[nb_oargs + i]); 392339004a71SRichard Henderson 392439004a71SRichard Henderson switch (loc->kind) { 392539004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 392639004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 392739004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 3928338b61e9SRichard Henderson if (arg_slot_reg_p(loc->arg_slot)) { 392925f49c5fSRichard Henderson tcg_regset_set_reg(*la_temp_pref(ts), 393039004a71SRichard Henderson tcg_target_call_iarg_regs[loc->arg_slot]); 393139004a71SRichard Henderson } 393239004a71SRichard Henderson break; 393339004a71SRichard Henderson default: 393439004a71SRichard Henderson break; 3935c70fbf0aSRichard Henderson } 3936c19f47bfSAurelien Jarno } 3937c6e113f5Sbellard } 3938c896fe29Sbellard break; 3939765b842aSRichard Henderson case INDEX_op_insn_start: 3940c896fe29Sbellard break; 39415ff9d6a4Sbellard case INDEX_op_discard: 39425ff9d6a4Sbellard /* mark the temporary as dead */ 394325f49c5fSRichard Henderson ts = arg_temp(op->args[0]); 394425f49c5fSRichard Henderson ts->state = TS_DEAD; 394525f49c5fSRichard Henderson la_reset_pref(ts); 39465ff9d6a4Sbellard break; 39471305c451SRichard Henderson 39481305c451SRichard Henderson case INDEX_op_add2_i32: 3949c45cb8bbSRichard Henderson opc_new = INDEX_op_add_i32; 3950f1fae40cSRichard Henderson goto do_addsub2; 39511305c451SRichard Henderson case INDEX_op_sub2_i32: 3952c45cb8bbSRichard Henderson opc_new = INDEX_op_sub_i32; 3953f1fae40cSRichard Henderson goto do_addsub2; 3954f1fae40cSRichard Henderson case INDEX_op_add2_i64: 3955c45cb8bbSRichard Henderson opc_new = INDEX_op_add_i64; 3956f1fae40cSRichard Henderson goto do_addsub2; 3957f1fae40cSRichard Henderson case INDEX_op_sub2_i64: 3958c45cb8bbSRichard Henderson opc_new = INDEX_op_sub_i64; 3959f1fae40cSRichard Henderson do_addsub2: 39601305c451SRichard Henderson nb_iargs = 4; 39611305c451SRichard Henderson nb_oargs = 2; 39621305c451SRichard Henderson /* Test if the high part of the operation is dead, but not 39631305c451SRichard Henderson the low part. The result can be optimized to a simple 39641305c451SRichard Henderson add or sub. This happens often for x86_64 guest when the 39651305c451SRichard Henderson cpu mode is set to 32 bit. */ 3966b83eabeaSRichard Henderson if (arg_temp(op->args[1])->state == TS_DEAD) { 3967b83eabeaSRichard Henderson if (arg_temp(op->args[0])->state == TS_DEAD) { 39681305c451SRichard Henderson goto do_remove; 39691305c451SRichard Henderson } 3970c45cb8bbSRichard Henderson /* Replace the opcode and adjust the args in place, 3971c45cb8bbSRichard Henderson leaving 3 unused args at the end. */ 3972c45cb8bbSRichard Henderson op->opc = opc = opc_new; 3973efee3746SRichard Henderson op->args[1] = op->args[2]; 3974efee3746SRichard Henderson op->args[2] = op->args[4]; 39751305c451SRichard Henderson /* Fall through and mark the single-word operation live. */ 39761305c451SRichard Henderson nb_iargs = 2; 39771305c451SRichard Henderson nb_oargs = 1; 39781305c451SRichard Henderson } 39791305c451SRichard Henderson goto do_not_remove; 39801305c451SRichard Henderson 39811414968aSRichard Henderson case INDEX_op_mulu2_i32: 3982c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i32; 3983c45cb8bbSRichard Henderson opc_new2 = INDEX_op_muluh_i32; 3984c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_muluh_i32; 398503271524SRichard Henderson goto do_mul2; 3986f1fae40cSRichard Henderson case INDEX_op_muls2_i32: 3987c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i32; 3988c45cb8bbSRichard Henderson opc_new2 = INDEX_op_mulsh_i32; 3989c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_mulsh_i32; 3990f1fae40cSRichard Henderson goto do_mul2; 3991f1fae40cSRichard Henderson case INDEX_op_mulu2_i64: 3992c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i64; 3993c45cb8bbSRichard Henderson opc_new2 = INDEX_op_muluh_i64; 3994c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_muluh_i64; 399503271524SRichard Henderson goto do_mul2; 3996f1fae40cSRichard Henderson case INDEX_op_muls2_i64: 3997c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i64; 3998c45cb8bbSRichard Henderson opc_new2 = INDEX_op_mulsh_i64; 3999c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_mulsh_i64; 400003271524SRichard Henderson goto do_mul2; 4001f1fae40cSRichard Henderson do_mul2: 40021414968aSRichard Henderson nb_iargs = 2; 40031414968aSRichard Henderson nb_oargs = 2; 4004b83eabeaSRichard Henderson if (arg_temp(op->args[1])->state == TS_DEAD) { 4005b83eabeaSRichard Henderson if (arg_temp(op->args[0])->state == TS_DEAD) { 400603271524SRichard Henderson /* Both parts of the operation are dead. */ 40071414968aSRichard Henderson goto do_remove; 40081414968aSRichard Henderson } 400903271524SRichard Henderson /* The high part of the operation is dead; generate the low. */ 4010c45cb8bbSRichard Henderson op->opc = opc = opc_new; 4011efee3746SRichard Henderson op->args[1] = op->args[2]; 4012efee3746SRichard Henderson op->args[2] = op->args[3]; 4013b83eabeaSRichard Henderson } else if (arg_temp(op->args[0])->state == TS_DEAD && have_opc_new2) { 401403271524SRichard Henderson /* The low part of the operation is dead; generate the high. */ 4015c45cb8bbSRichard Henderson op->opc = opc = opc_new2; 4016efee3746SRichard Henderson op->args[0] = op->args[1]; 4017efee3746SRichard Henderson op->args[1] = op->args[2]; 4018efee3746SRichard Henderson op->args[2] = op->args[3]; 401903271524SRichard Henderson } else { 402003271524SRichard Henderson goto do_not_remove; 402103271524SRichard Henderson } 402203271524SRichard Henderson /* Mark the single-word operation live. */ 40231414968aSRichard Henderson nb_oargs = 1; 40241414968aSRichard Henderson goto do_not_remove; 40251414968aSRichard Henderson 4026c896fe29Sbellard default: 40271305c451SRichard Henderson /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */ 4028c896fe29Sbellard nb_iargs = def->nb_iargs; 4029c896fe29Sbellard nb_oargs = def->nb_oargs; 4030c896fe29Sbellard 4031c896fe29Sbellard /* Test if the operation can be removed because all 40325ff9d6a4Sbellard its outputs are dead. We assume that nb_oargs == 0 40335ff9d6a4Sbellard implies side effects */ 40345ff9d6a4Sbellard if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) { 4035c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 4036b83eabeaSRichard Henderson if (arg_temp(op->args[i])->state != TS_DEAD) { 4037c896fe29Sbellard goto do_not_remove; 4038c896fe29Sbellard } 40399c43b68dSAurelien Jarno } 4040152c35aaSRichard Henderson goto do_remove; 4041152c35aaSRichard Henderson } 4042152c35aaSRichard Henderson goto do_not_remove; 4043152c35aaSRichard Henderson 40441305c451SRichard Henderson do_remove: 40450c627cdcSRichard Henderson tcg_op_remove(s, op); 4046152c35aaSRichard Henderson break; 4047152c35aaSRichard Henderson 4048c896fe29Sbellard do_not_remove: 4049c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 405025f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 405125f49c5fSRichard Henderson 405225f49c5fSRichard Henderson /* Remember the preference of the uses that followed. */ 405331fd884bSRichard Henderson if (i < ARRAY_SIZE(op->output_pref)) { 405425f49c5fSRichard Henderson op->output_pref[i] = *la_temp_pref(ts); 405531fd884bSRichard Henderson } 405625f49c5fSRichard Henderson 405725f49c5fSRichard Henderson /* Output args are dead. */ 405825f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 4059a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 40606b64b624SAurelien Jarno } 406125f49c5fSRichard Henderson if (ts->state & TS_MEM) { 4062a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i; 40639c43b68dSAurelien Jarno } 406425f49c5fSRichard Henderson ts->state = TS_DEAD; 406525f49c5fSRichard Henderson la_reset_pref(ts); 4066c896fe29Sbellard } 4067c896fe29Sbellard 406825f49c5fSRichard Henderson /* If end of basic block, update. */ 4069ae36a246SRichard Henderson if (def->flags & TCG_OPF_BB_EXIT) { 4070ae36a246SRichard Henderson la_func_end(s, nb_globals, nb_temps); 4071b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_COND_BRANCH) { 4072b4cb76e6SRichard Henderson la_bb_sync(s, nb_globals, nb_temps); 4073ae36a246SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 40742616c808SRichard Henderson la_bb_end(s, nb_globals, nb_temps); 40753d5c5f87SAurelien Jarno } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { 4076f65a061cSRichard Henderson la_global_sync(s, nb_globals); 407725f49c5fSRichard Henderson if (def->flags & TCG_OPF_CALL_CLOBBER) { 407825f49c5fSRichard Henderson la_cross_call(s, nb_temps); 407925f49c5fSRichard Henderson } 4080c896fe29Sbellard } 4081c896fe29Sbellard 408225f49c5fSRichard Henderson /* Record arguments that die in this opcode. */ 4083866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 408425f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 408525f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 4086a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 4087c896fe29Sbellard } 4088c19f47bfSAurelien Jarno } 408925f49c5fSRichard Henderson 409025f49c5fSRichard Henderson /* Input arguments are live for preceding opcodes. */ 4091c19f47bfSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 409225f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 409325f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 409425f49c5fSRichard Henderson /* For operands that were dead, initially allow 409525f49c5fSRichard Henderson all regs for the type. */ 409625f49c5fSRichard Henderson *la_temp_pref(ts) = tcg_target_available_regs[ts->type]; 409725f49c5fSRichard Henderson ts->state &= ~TS_DEAD; 409825f49c5fSRichard Henderson } 409925f49c5fSRichard Henderson } 410025f49c5fSRichard Henderson 410125f49c5fSRichard Henderson /* Incorporate constraints for this operand. */ 410225f49c5fSRichard Henderson switch (opc) { 410325f49c5fSRichard Henderson case INDEX_op_mov_i32: 410425f49c5fSRichard Henderson case INDEX_op_mov_i64: 410525f49c5fSRichard Henderson /* Note that these are TCG_OPF_NOT_PRESENT and do not 410625f49c5fSRichard Henderson have proper constraints. That said, special case 410725f49c5fSRichard Henderson moves to propagate preferences backward. */ 410825f49c5fSRichard Henderson if (IS_DEAD_ARG(1)) { 410925f49c5fSRichard Henderson *la_temp_pref(arg_temp(op->args[0])) 411025f49c5fSRichard Henderson = *la_temp_pref(arg_temp(op->args[1])); 411125f49c5fSRichard Henderson } 411225f49c5fSRichard Henderson break; 411325f49c5fSRichard Henderson 411425f49c5fSRichard Henderson default: 4115501fb3daSRichard Henderson args_ct = opcode_args_ct(op); 411625f49c5fSRichard Henderson for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 4117501fb3daSRichard Henderson const TCGArgConstraint *ct = &args_ct[i]; 411825f49c5fSRichard Henderson TCGRegSet set, *pset; 411925f49c5fSRichard Henderson 412025f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 412125f49c5fSRichard Henderson pset = la_temp_pref(ts); 412225f49c5fSRichard Henderson set = *pset; 412325f49c5fSRichard Henderson 41249be0d080SRichard Henderson set &= ct->regs; 4125bc2b17e6SRichard Henderson if (ct->ialias) { 412631fd884bSRichard Henderson set &= output_pref(op, ct->alias_index); 412725f49c5fSRichard Henderson } 412825f49c5fSRichard Henderson /* If the combination is not possible, restart. */ 412925f49c5fSRichard Henderson if (set == 0) { 41309be0d080SRichard Henderson set = ct->regs; 413125f49c5fSRichard Henderson } 413225f49c5fSRichard Henderson *pset = set; 413325f49c5fSRichard Henderson } 413425f49c5fSRichard Henderson break; 4135c896fe29Sbellard } 4136c896fe29Sbellard break; 4137c896fe29Sbellard } 4138bee158cbSRichard Henderson op->life = arg_life; 4139c896fe29Sbellard } 41401ff0a2c5SEvgeny Voevodin } 4141c896fe29Sbellard 41425a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries. */ 41439bbee4c0SRichard Henderson static bool __attribute__((noinline)) 41449bbee4c0SRichard Henderson liveness_pass_2(TCGContext *s) 41455a18407fSRichard Henderson { 41465a18407fSRichard Henderson int nb_globals = s->nb_globals; 414715fa08f8SRichard Henderson int nb_temps, i; 41485a18407fSRichard Henderson bool changes = false; 414915fa08f8SRichard Henderson TCGOp *op, *op_next; 41505a18407fSRichard Henderson 41515a18407fSRichard Henderson /* Create a temporary for each indirect global. */ 41525a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 41535a18407fSRichard Henderson TCGTemp *its = &s->temps[i]; 41545a18407fSRichard Henderson if (its->indirect_reg) { 41555a18407fSRichard Henderson TCGTemp *dts = tcg_temp_alloc(s); 41565a18407fSRichard Henderson dts->type = its->type; 41575a18407fSRichard Henderson dts->base_type = its->base_type; 4158e1e64652SRichard Henderson dts->temp_subindex = its->temp_subindex; 4159c7482438SRichard Henderson dts->kind = TEMP_EBB; 4160b83eabeaSRichard Henderson its->state_ptr = dts; 4161b83eabeaSRichard Henderson } else { 4162b83eabeaSRichard Henderson its->state_ptr = NULL; 41635a18407fSRichard Henderson } 4164b83eabeaSRichard Henderson /* All globals begin dead. */ 4165b83eabeaSRichard Henderson its->state = TS_DEAD; 41665a18407fSRichard Henderson } 4167b83eabeaSRichard Henderson for (nb_temps = s->nb_temps; i < nb_temps; ++i) { 4168b83eabeaSRichard Henderson TCGTemp *its = &s->temps[i]; 4169b83eabeaSRichard Henderson its->state_ptr = NULL; 4170b83eabeaSRichard Henderson its->state = TS_DEAD; 4171b83eabeaSRichard Henderson } 41725a18407fSRichard Henderson 417315fa08f8SRichard Henderson QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) { 41745a18407fSRichard Henderson TCGOpcode opc = op->opc; 41755a18407fSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 41765a18407fSRichard Henderson TCGLifeData arg_life = op->life; 41775a18407fSRichard Henderson int nb_iargs, nb_oargs, call_flags; 4178b83eabeaSRichard Henderson TCGTemp *arg_ts, *dir_ts; 41795a18407fSRichard Henderson 41805a18407fSRichard Henderson if (opc == INDEX_op_call) { 4181cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 4182cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 418390163900SRichard Henderson call_flags = tcg_call_flags(op); 41845a18407fSRichard Henderson } else { 41855a18407fSRichard Henderson nb_iargs = def->nb_iargs; 41865a18407fSRichard Henderson nb_oargs = def->nb_oargs; 41875a18407fSRichard Henderson 41885a18407fSRichard Henderson /* Set flags similar to how calls require. */ 4189b4cb76e6SRichard Henderson if (def->flags & TCG_OPF_COND_BRANCH) { 4190b4cb76e6SRichard Henderson /* Like reading globals: sync_globals */ 4191b4cb76e6SRichard Henderson call_flags = TCG_CALL_NO_WRITE_GLOBALS; 4192b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 41935a18407fSRichard Henderson /* Like writing globals: save_globals */ 41945a18407fSRichard Henderson call_flags = 0; 41955a18407fSRichard Henderson } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { 41965a18407fSRichard Henderson /* Like reading globals: sync_globals */ 41975a18407fSRichard Henderson call_flags = TCG_CALL_NO_WRITE_GLOBALS; 41985a18407fSRichard Henderson } else { 41995a18407fSRichard Henderson /* No effect on globals. */ 42005a18407fSRichard Henderson call_flags = (TCG_CALL_NO_READ_GLOBALS | 42015a18407fSRichard Henderson TCG_CALL_NO_WRITE_GLOBALS); 42025a18407fSRichard Henderson } 42035a18407fSRichard Henderson } 42045a18407fSRichard Henderson 42055a18407fSRichard Henderson /* Make sure that input arguments are available. */ 42065a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 4207b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 4208b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 4209b83eabeaSRichard Henderson if (dir_ts && arg_ts->state == TS_DEAD) { 4210b83eabeaSRichard Henderson TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32 42115a18407fSRichard Henderson ? INDEX_op_ld_i32 42125a18407fSRichard Henderson : INDEX_op_ld_i64); 4213d4478943SPhilippe Mathieu-Daudé TCGOp *lop = tcg_op_insert_before(s, op, lopc, 3); 42145a18407fSRichard Henderson 4215b83eabeaSRichard Henderson lop->args[0] = temp_arg(dir_ts); 4216b83eabeaSRichard Henderson lop->args[1] = temp_arg(arg_ts->mem_base); 4217b83eabeaSRichard Henderson lop->args[2] = arg_ts->mem_offset; 42185a18407fSRichard Henderson 42195a18407fSRichard Henderson /* Loaded, but synced with memory. */ 4220b83eabeaSRichard Henderson arg_ts->state = TS_MEM; 42215a18407fSRichard Henderson } 42225a18407fSRichard Henderson } 42235a18407fSRichard Henderson 42245a18407fSRichard Henderson /* Perform input replacement, and mark inputs that became dead. 42255a18407fSRichard Henderson No action is required except keeping temp_state up to date 42265a18407fSRichard Henderson so that we reload when needed. */ 42275a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 4228b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 4229b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 4230b83eabeaSRichard Henderson if (dir_ts) { 4231b83eabeaSRichard Henderson op->args[i] = temp_arg(dir_ts); 42325a18407fSRichard Henderson changes = true; 42335a18407fSRichard Henderson if (IS_DEAD_ARG(i)) { 4234b83eabeaSRichard Henderson arg_ts->state = TS_DEAD; 42355a18407fSRichard Henderson } 42365a18407fSRichard Henderson } 42375a18407fSRichard Henderson } 42385a18407fSRichard Henderson 42395a18407fSRichard Henderson /* Liveness analysis should ensure that the following are 42405a18407fSRichard Henderson all correct, for call sites and basic block end points. */ 42415a18407fSRichard Henderson if (call_flags & TCG_CALL_NO_READ_GLOBALS) { 42425a18407fSRichard Henderson /* Nothing to do */ 42435a18407fSRichard Henderson } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) { 42445a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 42455a18407fSRichard Henderson /* Liveness should see that globals are synced back, 42465a18407fSRichard Henderson that is, either TS_DEAD or TS_MEM. */ 4247b83eabeaSRichard Henderson arg_ts = &s->temps[i]; 4248b83eabeaSRichard Henderson tcg_debug_assert(arg_ts->state_ptr == 0 4249b83eabeaSRichard Henderson || arg_ts->state != 0); 42505a18407fSRichard Henderson } 42515a18407fSRichard Henderson } else { 42525a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 42535a18407fSRichard Henderson /* Liveness should see that globals are saved back, 42545a18407fSRichard Henderson that is, TS_DEAD, waiting to be reloaded. */ 4255b83eabeaSRichard Henderson arg_ts = &s->temps[i]; 4256b83eabeaSRichard Henderson tcg_debug_assert(arg_ts->state_ptr == 0 4257b83eabeaSRichard Henderson || arg_ts->state == TS_DEAD); 42585a18407fSRichard Henderson } 42595a18407fSRichard Henderson } 42605a18407fSRichard Henderson 42615a18407fSRichard Henderson /* Outputs become available. */ 426261f15c48SRichard Henderson if (opc == INDEX_op_mov_i32 || opc == INDEX_op_mov_i64) { 426361f15c48SRichard Henderson arg_ts = arg_temp(op->args[0]); 426461f15c48SRichard Henderson dir_ts = arg_ts->state_ptr; 426561f15c48SRichard Henderson if (dir_ts) { 426661f15c48SRichard Henderson op->args[0] = temp_arg(dir_ts); 426761f15c48SRichard Henderson changes = true; 426861f15c48SRichard Henderson 426961f15c48SRichard Henderson /* The output is now live and modified. */ 427061f15c48SRichard Henderson arg_ts->state = 0; 427161f15c48SRichard Henderson 427261f15c48SRichard Henderson if (NEED_SYNC_ARG(0)) { 427361f15c48SRichard Henderson TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 427461f15c48SRichard Henderson ? INDEX_op_st_i32 427561f15c48SRichard Henderson : INDEX_op_st_i64); 4276d4478943SPhilippe Mathieu-Daudé TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3); 427761f15c48SRichard Henderson TCGTemp *out_ts = dir_ts; 427861f15c48SRichard Henderson 427961f15c48SRichard Henderson if (IS_DEAD_ARG(0)) { 428061f15c48SRichard Henderson out_ts = arg_temp(op->args[1]); 428161f15c48SRichard Henderson arg_ts->state = TS_DEAD; 428261f15c48SRichard Henderson tcg_op_remove(s, op); 428361f15c48SRichard Henderson } else { 428461f15c48SRichard Henderson arg_ts->state = TS_MEM; 428561f15c48SRichard Henderson } 428661f15c48SRichard Henderson 428761f15c48SRichard Henderson sop->args[0] = temp_arg(out_ts); 428861f15c48SRichard Henderson sop->args[1] = temp_arg(arg_ts->mem_base); 428961f15c48SRichard Henderson sop->args[2] = arg_ts->mem_offset; 429061f15c48SRichard Henderson } else { 429161f15c48SRichard Henderson tcg_debug_assert(!IS_DEAD_ARG(0)); 429261f15c48SRichard Henderson } 429361f15c48SRichard Henderson } 429461f15c48SRichard Henderson } else { 42955a18407fSRichard Henderson for (i = 0; i < nb_oargs; i++) { 4296b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 4297b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 4298b83eabeaSRichard Henderson if (!dir_ts) { 42995a18407fSRichard Henderson continue; 43005a18407fSRichard Henderson } 4301b83eabeaSRichard Henderson op->args[i] = temp_arg(dir_ts); 43025a18407fSRichard Henderson changes = true; 43035a18407fSRichard Henderson 43045a18407fSRichard Henderson /* The output is now live and modified. */ 4305b83eabeaSRichard Henderson arg_ts->state = 0; 43065a18407fSRichard Henderson 43075a18407fSRichard Henderson /* Sync outputs upon their last write. */ 43085a18407fSRichard Henderson if (NEED_SYNC_ARG(i)) { 4309b83eabeaSRichard Henderson TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 43105a18407fSRichard Henderson ? INDEX_op_st_i32 43115a18407fSRichard Henderson : INDEX_op_st_i64); 4312d4478943SPhilippe Mathieu-Daudé TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3); 43135a18407fSRichard Henderson 4314b83eabeaSRichard Henderson sop->args[0] = temp_arg(dir_ts); 4315b83eabeaSRichard Henderson sop->args[1] = temp_arg(arg_ts->mem_base); 4316b83eabeaSRichard Henderson sop->args[2] = arg_ts->mem_offset; 43175a18407fSRichard Henderson 4318b83eabeaSRichard Henderson arg_ts->state = TS_MEM; 43195a18407fSRichard Henderson } 43205a18407fSRichard Henderson /* Drop outputs that are dead. */ 43215a18407fSRichard Henderson if (IS_DEAD_ARG(i)) { 4322b83eabeaSRichard Henderson arg_ts->state = TS_DEAD; 43235a18407fSRichard Henderson } 43245a18407fSRichard Henderson } 43255a18407fSRichard Henderson } 432661f15c48SRichard Henderson } 43275a18407fSRichard Henderson 43285a18407fSRichard Henderson return changes; 43295a18407fSRichard Henderson } 43305a18407fSRichard Henderson 43312272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts) 4332c896fe29Sbellard { 433331c96417SRichard Henderson intptr_t off; 4334273eb50cSRichard Henderson int size, align; 4335c1c09194SRichard Henderson 4336273eb50cSRichard Henderson /* When allocating an object, look at the full type. */ 4337273eb50cSRichard Henderson size = tcg_type_size(ts->base_type); 4338273eb50cSRichard Henderson switch (ts->base_type) { 4339c1c09194SRichard Henderson case TCG_TYPE_I32: 434031c96417SRichard Henderson align = 4; 4341c1c09194SRichard Henderson break; 4342c1c09194SRichard Henderson case TCG_TYPE_I64: 4343c1c09194SRichard Henderson case TCG_TYPE_V64: 434431c96417SRichard Henderson align = 8; 4345c1c09194SRichard Henderson break; 434643eef72fSRichard Henderson case TCG_TYPE_I128: 4347c1c09194SRichard Henderson case TCG_TYPE_V128: 4348c1c09194SRichard Henderson case TCG_TYPE_V256: 434943eef72fSRichard Henderson /* 435043eef72fSRichard Henderson * Note that we do not require aligned storage for V256, 435143eef72fSRichard Henderson * and that we provide alignment for I128 to match V128, 435243eef72fSRichard Henderson * even if that's above what the host ABI requires. 435343eef72fSRichard Henderson */ 435431c96417SRichard Henderson align = 16; 4355c1c09194SRichard Henderson break; 4356c1c09194SRichard Henderson default: 4357c1c09194SRichard Henderson g_assert_not_reached(); 4358b591dc59SBlue Swirl } 4359c1c09194SRichard Henderson 4360b9537d59SRichard Henderson /* 4361b9537d59SRichard Henderson * Assume the stack is sufficiently aligned. 4362b9537d59SRichard Henderson * This affects e.g. ARM NEON, where we have 8 byte stack alignment 4363b9537d59SRichard Henderson * and do not require 16 byte vector alignment. This seems slightly 4364b9537d59SRichard Henderson * easier than fully parameterizing the above switch statement. 4365b9537d59SRichard Henderson */ 4366b9537d59SRichard Henderson align = MIN(TCG_TARGET_STACK_ALIGN, align); 4367c1c09194SRichard Henderson off = ROUND_UP(s->current_frame_offset, align); 4368732d5897SRichard Henderson 4369732d5897SRichard Henderson /* If we've exhausted the stack frame, restart with a smaller TB. */ 4370732d5897SRichard Henderson if (off + size > s->frame_end) { 4371732d5897SRichard Henderson tcg_raise_tb_overflow(s); 4372732d5897SRichard Henderson } 4373c1c09194SRichard Henderson s->current_frame_offset = off + size; 43749defd1bdSRichard Henderson #if defined(__sparc__) 4375273eb50cSRichard Henderson off += TCG_TARGET_STACK_BIAS; 43769defd1bdSRichard Henderson #endif 4377273eb50cSRichard Henderson 4378273eb50cSRichard Henderson /* If the object was subdivided, assign memory to all the parts. */ 4379273eb50cSRichard Henderson if (ts->base_type != ts->type) { 4380273eb50cSRichard Henderson int part_size = tcg_type_size(ts->type); 4381273eb50cSRichard Henderson int part_count = size / part_size; 4382273eb50cSRichard Henderson 4383273eb50cSRichard Henderson /* 4384273eb50cSRichard Henderson * Each part is allocated sequentially in tcg_temp_new_internal. 4385273eb50cSRichard Henderson * Jump back to the first part by subtracting the current index. 4386273eb50cSRichard Henderson */ 4387273eb50cSRichard Henderson ts -= ts->temp_subindex; 4388273eb50cSRichard Henderson for (int i = 0; i < part_count; ++i) { 4389273eb50cSRichard Henderson ts[i].mem_offset = off + i * part_size; 4390273eb50cSRichard Henderson ts[i].mem_base = s->frame_temp; 4391273eb50cSRichard Henderson ts[i].mem_allocated = 1; 4392273eb50cSRichard Henderson } 4393273eb50cSRichard Henderson } else { 4394273eb50cSRichard Henderson ts->mem_offset = off; 4395b3a62939SRichard Henderson ts->mem_base = s->frame_temp; 4396c896fe29Sbellard ts->mem_allocated = 1; 4397c896fe29Sbellard } 4398273eb50cSRichard Henderson } 4399c896fe29Sbellard 4400098859f1SRichard Henderson /* Assign @reg to @ts, and update reg_to_temp[]. */ 4401098859f1SRichard Henderson static void set_temp_val_reg(TCGContext *s, TCGTemp *ts, TCGReg reg) 4402098859f1SRichard Henderson { 4403098859f1SRichard Henderson if (ts->val_type == TEMP_VAL_REG) { 4404098859f1SRichard Henderson TCGReg old = ts->reg; 4405098859f1SRichard Henderson tcg_debug_assert(s->reg_to_temp[old] == ts); 4406098859f1SRichard Henderson if (old == reg) { 4407098859f1SRichard Henderson return; 4408098859f1SRichard Henderson } 4409098859f1SRichard Henderson s->reg_to_temp[old] = NULL; 4410098859f1SRichard Henderson } 4411098859f1SRichard Henderson tcg_debug_assert(s->reg_to_temp[reg] == NULL); 4412098859f1SRichard Henderson s->reg_to_temp[reg] = ts; 4413098859f1SRichard Henderson ts->val_type = TEMP_VAL_REG; 4414098859f1SRichard Henderson ts->reg = reg; 4415098859f1SRichard Henderson } 4416098859f1SRichard Henderson 4417098859f1SRichard Henderson /* Assign a non-register value type to @ts, and update reg_to_temp[]. */ 4418098859f1SRichard Henderson static void set_temp_val_nonreg(TCGContext *s, TCGTemp *ts, TCGTempVal type) 4419098859f1SRichard Henderson { 4420098859f1SRichard Henderson tcg_debug_assert(type != TEMP_VAL_REG); 4421098859f1SRichard Henderson if (ts->val_type == TEMP_VAL_REG) { 4422098859f1SRichard Henderson TCGReg reg = ts->reg; 4423098859f1SRichard Henderson tcg_debug_assert(s->reg_to_temp[reg] == ts); 4424098859f1SRichard Henderson s->reg_to_temp[reg] = NULL; 4425098859f1SRichard Henderson } 4426098859f1SRichard Henderson ts->val_type = type; 4427098859f1SRichard Henderson } 4428098859f1SRichard Henderson 4429b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet); 4430b3915dbbSRichard Henderson 443159d7c14eSRichard Henderson /* Mark a temporary as free or dead. If 'free_or_dead' is negative, 443259d7c14eSRichard Henderson mark it free; otherwise mark it dead. */ 443359d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead) 4434c896fe29Sbellard { 4435c0522136SRichard Henderson TCGTempVal new_type; 4436c0522136SRichard Henderson 4437c0522136SRichard Henderson switch (ts->kind) { 4438c0522136SRichard Henderson case TEMP_FIXED: 443959d7c14eSRichard Henderson return; 4440c0522136SRichard Henderson case TEMP_GLOBAL: 4441f57c6915SRichard Henderson case TEMP_TB: 4442c0522136SRichard Henderson new_type = TEMP_VAL_MEM; 4443c0522136SRichard Henderson break; 4444c7482438SRichard Henderson case TEMP_EBB: 4445c0522136SRichard Henderson new_type = free_or_dead < 0 ? TEMP_VAL_MEM : TEMP_VAL_DEAD; 4446c0522136SRichard Henderson break; 4447c0522136SRichard Henderson case TEMP_CONST: 4448c0522136SRichard Henderson new_type = TEMP_VAL_CONST; 4449c0522136SRichard Henderson break; 4450c0522136SRichard Henderson default: 4451c0522136SRichard Henderson g_assert_not_reached(); 445259d7c14eSRichard Henderson } 4453098859f1SRichard Henderson set_temp_val_nonreg(s, ts, new_type); 445459d7c14eSRichard Henderson } 4455c896fe29Sbellard 445659d7c14eSRichard Henderson /* Mark a temporary as dead. */ 445759d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts) 445859d7c14eSRichard Henderson { 445959d7c14eSRichard Henderson temp_free_or_dead(s, ts, 1); 446059d7c14eSRichard Henderson } 446159d7c14eSRichard Henderson 446259d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary 446359d7c14eSRichard Henderson registers needs to be allocated to store a constant. If 'free_or_dead' 446459d7c14eSRichard Henderson is non-zero, subsequently release the temporary; if it is positive, the 446559d7c14eSRichard Henderson temp is dead; if it is negative, the temp is free. */ 446698b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs, 446798b4e186SRichard Henderson TCGRegSet preferred_regs, int free_or_dead) 446859d7c14eSRichard Henderson { 4469c0522136SRichard Henderson if (!temp_readonly(ts) && !ts->mem_coherent) { 44707f6ceedfSAurelien Jarno if (!ts->mem_allocated) { 44712272e4a7SRichard Henderson temp_allocate_frame(s, ts); 447259d7c14eSRichard Henderson } 447359d7c14eSRichard Henderson switch (ts->val_type) { 447459d7c14eSRichard Henderson case TEMP_VAL_CONST: 447559d7c14eSRichard Henderson /* If we're going to free the temp immediately, then we won't 447659d7c14eSRichard Henderson require it later in a register, so attempt to store the 447759d7c14eSRichard Henderson constant to memory directly. */ 447859d7c14eSRichard Henderson if (free_or_dead 447959d7c14eSRichard Henderson && tcg_out_sti(s, ts->type, ts->val, 448059d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset)) { 448159d7c14eSRichard Henderson break; 448259d7c14eSRichard Henderson } 448359d7c14eSRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 448498b4e186SRichard Henderson allocated_regs, preferred_regs); 448559d7c14eSRichard Henderson /* fallthrough */ 448659d7c14eSRichard Henderson 448759d7c14eSRichard Henderson case TEMP_VAL_REG: 448859d7c14eSRichard Henderson tcg_out_st(s, ts->type, ts->reg, 448959d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset); 449059d7c14eSRichard Henderson break; 449159d7c14eSRichard Henderson 449259d7c14eSRichard Henderson case TEMP_VAL_MEM: 449359d7c14eSRichard Henderson break; 449459d7c14eSRichard Henderson 449559d7c14eSRichard Henderson case TEMP_VAL_DEAD: 449659d7c14eSRichard Henderson default: 4497732e89f4SRichard Henderson g_assert_not_reached(); 4498c896fe29Sbellard } 44997f6ceedfSAurelien Jarno ts->mem_coherent = 1; 45007f6ceedfSAurelien Jarno } 450159d7c14eSRichard Henderson if (free_or_dead) { 450259d7c14eSRichard Henderson temp_free_or_dead(s, ts, free_or_dead); 450359d7c14eSRichard Henderson } 450459d7c14eSRichard Henderson } 45057f6ceedfSAurelien Jarno 45067f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */ 4507b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs) 45087f6ceedfSAurelien Jarno { 4509f8b2f202SRichard Henderson TCGTemp *ts = s->reg_to_temp[reg]; 4510f8b2f202SRichard Henderson if (ts != NULL) { 451198b4e186SRichard Henderson temp_sync(s, ts, allocated_regs, 0, -1); 4512c896fe29Sbellard } 4513c896fe29Sbellard } 4514c896fe29Sbellard 4515b016486eSRichard Henderson /** 4516b016486eSRichard Henderson * tcg_reg_alloc: 4517b016486eSRichard Henderson * @required_regs: Set of registers in which we must allocate. 4518b016486eSRichard Henderson * @allocated_regs: Set of registers which must be avoided. 4519b016486eSRichard Henderson * @preferred_regs: Set of registers we should prefer. 4520b016486eSRichard Henderson * @rev: True if we search the registers in "indirect" order. 4521b016486eSRichard Henderson * 4522b016486eSRichard Henderson * The allocated register must be in @required_regs & ~@allocated_regs, 4523b016486eSRichard Henderson * but if we can put it in @preferred_regs we may save a move later. 4524b016486eSRichard Henderson */ 4525b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs, 4526b016486eSRichard Henderson TCGRegSet allocated_regs, 4527b016486eSRichard Henderson TCGRegSet preferred_regs, bool rev) 4528c896fe29Sbellard { 4529b016486eSRichard Henderson int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order); 4530b016486eSRichard Henderson TCGRegSet reg_ct[2]; 453191478cefSRichard Henderson const int *order; 4532c896fe29Sbellard 4533b016486eSRichard Henderson reg_ct[1] = required_regs & ~allocated_regs; 4534b016486eSRichard Henderson tcg_debug_assert(reg_ct[1] != 0); 4535b016486eSRichard Henderson reg_ct[0] = reg_ct[1] & preferred_regs; 4536b016486eSRichard Henderson 4537b016486eSRichard Henderson /* Skip the preferred_regs option if it cannot be satisfied, 4538b016486eSRichard Henderson or if the preference made no difference. */ 4539b016486eSRichard Henderson f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1]; 4540b016486eSRichard Henderson 454191478cefSRichard Henderson order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order; 4542c896fe29Sbellard 4543b016486eSRichard Henderson /* Try free registers, preferences first. */ 4544b016486eSRichard Henderson for (j = f; j < 2; j++) { 4545b016486eSRichard Henderson TCGRegSet set = reg_ct[j]; 4546b016486eSRichard Henderson 4547b016486eSRichard Henderson if (tcg_regset_single(set)) { 4548b016486eSRichard Henderson /* One register in the set. */ 4549b016486eSRichard Henderson TCGReg reg = tcg_regset_first(set); 4550b016486eSRichard Henderson if (s->reg_to_temp[reg] == NULL) { 4551c896fe29Sbellard return reg; 4552c896fe29Sbellard } 4553b016486eSRichard Henderson } else { 455491478cefSRichard Henderson for (i = 0; i < n; i++) { 4555b016486eSRichard Henderson TCGReg reg = order[i]; 4556b016486eSRichard Henderson if (s->reg_to_temp[reg] == NULL && 4557b016486eSRichard Henderson tcg_regset_test_reg(set, reg)) { 4558b016486eSRichard Henderson return reg; 4559b016486eSRichard Henderson } 4560b016486eSRichard Henderson } 4561b016486eSRichard Henderson } 4562b016486eSRichard Henderson } 4563b016486eSRichard Henderson 4564b016486eSRichard Henderson /* We must spill something. */ 4565b016486eSRichard Henderson for (j = f; j < 2; j++) { 4566b016486eSRichard Henderson TCGRegSet set = reg_ct[j]; 4567b016486eSRichard Henderson 4568b016486eSRichard Henderson if (tcg_regset_single(set)) { 4569b016486eSRichard Henderson /* One register in the set. */ 4570b016486eSRichard Henderson TCGReg reg = tcg_regset_first(set); 4571b3915dbbSRichard Henderson tcg_reg_free(s, reg, allocated_regs); 4572c896fe29Sbellard return reg; 4573b016486eSRichard Henderson } else { 4574b016486eSRichard Henderson for (i = 0; i < n; i++) { 4575b016486eSRichard Henderson TCGReg reg = order[i]; 4576b016486eSRichard Henderson if (tcg_regset_test_reg(set, reg)) { 4577b016486eSRichard Henderson tcg_reg_free(s, reg, allocated_regs); 4578b016486eSRichard Henderson return reg; 4579b016486eSRichard Henderson } 4580b016486eSRichard Henderson } 4581c896fe29Sbellard } 4582c896fe29Sbellard } 4583c896fe29Sbellard 4584732e89f4SRichard Henderson g_assert_not_reached(); 4585c896fe29Sbellard } 4586c896fe29Sbellard 458729f5e925SRichard Henderson static TCGReg tcg_reg_alloc_pair(TCGContext *s, TCGRegSet required_regs, 458829f5e925SRichard Henderson TCGRegSet allocated_regs, 458929f5e925SRichard Henderson TCGRegSet preferred_regs, bool rev) 459029f5e925SRichard Henderson { 459129f5e925SRichard Henderson int i, j, k, fmin, n = ARRAY_SIZE(tcg_target_reg_alloc_order); 459229f5e925SRichard Henderson TCGRegSet reg_ct[2]; 459329f5e925SRichard Henderson const int *order; 459429f5e925SRichard Henderson 459529f5e925SRichard Henderson /* Ensure that if I is not in allocated_regs, I+1 is not either. */ 459629f5e925SRichard Henderson reg_ct[1] = required_regs & ~(allocated_regs | (allocated_regs >> 1)); 459729f5e925SRichard Henderson tcg_debug_assert(reg_ct[1] != 0); 459829f5e925SRichard Henderson reg_ct[0] = reg_ct[1] & preferred_regs; 459929f5e925SRichard Henderson 460029f5e925SRichard Henderson order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order; 460129f5e925SRichard Henderson 460229f5e925SRichard Henderson /* 460329f5e925SRichard Henderson * Skip the preferred_regs option if it cannot be satisfied, 460429f5e925SRichard Henderson * or if the preference made no difference. 460529f5e925SRichard Henderson */ 460629f5e925SRichard Henderson k = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1]; 460729f5e925SRichard Henderson 460829f5e925SRichard Henderson /* 460929f5e925SRichard Henderson * Minimize the number of flushes by looking for 2 free registers first, 461029f5e925SRichard Henderson * then a single flush, then two flushes. 461129f5e925SRichard Henderson */ 461229f5e925SRichard Henderson for (fmin = 2; fmin >= 0; fmin--) { 461329f5e925SRichard Henderson for (j = k; j < 2; j++) { 461429f5e925SRichard Henderson TCGRegSet set = reg_ct[j]; 461529f5e925SRichard Henderson 461629f5e925SRichard Henderson for (i = 0; i < n; i++) { 461729f5e925SRichard Henderson TCGReg reg = order[i]; 461829f5e925SRichard Henderson 461929f5e925SRichard Henderson if (tcg_regset_test_reg(set, reg)) { 462029f5e925SRichard Henderson int f = !s->reg_to_temp[reg] + !s->reg_to_temp[reg + 1]; 462129f5e925SRichard Henderson if (f >= fmin) { 462229f5e925SRichard Henderson tcg_reg_free(s, reg, allocated_regs); 462329f5e925SRichard Henderson tcg_reg_free(s, reg + 1, allocated_regs); 462429f5e925SRichard Henderson return reg; 462529f5e925SRichard Henderson } 462629f5e925SRichard Henderson } 462729f5e925SRichard Henderson } 462829f5e925SRichard Henderson } 462929f5e925SRichard Henderson } 4630732e89f4SRichard Henderson g_assert_not_reached(); 463129f5e925SRichard Henderson } 463229f5e925SRichard Henderson 463340ae5c62SRichard Henderson /* Make sure the temporary is in a register. If needed, allocate the register 463440ae5c62SRichard Henderson from DESIRED while avoiding ALLOCATED. */ 463540ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs, 4636b722452aSRichard Henderson TCGRegSet allocated_regs, TCGRegSet preferred_regs) 463740ae5c62SRichard Henderson { 463840ae5c62SRichard Henderson TCGReg reg; 463940ae5c62SRichard Henderson 464040ae5c62SRichard Henderson switch (ts->val_type) { 464140ae5c62SRichard Henderson case TEMP_VAL_REG: 464240ae5c62SRichard Henderson return; 464340ae5c62SRichard Henderson case TEMP_VAL_CONST: 4644b016486eSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs, 4645b722452aSRichard Henderson preferred_regs, ts->indirect_base); 46460a6a8bc8SRichard Henderson if (ts->type <= TCG_TYPE_I64) { 464740ae5c62SRichard Henderson tcg_out_movi(s, ts->type, reg, ts->val); 46480a6a8bc8SRichard Henderson } else { 46494e186175SRichard Henderson uint64_t val = ts->val; 46504e186175SRichard Henderson MemOp vece = MO_64; 46514e186175SRichard Henderson 46524e186175SRichard Henderson /* 46534e186175SRichard Henderson * Find the minimal vector element that matches the constant. 46544e186175SRichard Henderson * The targets will, in general, have to do this search anyway, 46554e186175SRichard Henderson * do this generically. 46564e186175SRichard Henderson */ 46574e186175SRichard Henderson if (val == dup_const(MO_8, val)) { 46584e186175SRichard Henderson vece = MO_8; 46594e186175SRichard Henderson } else if (val == dup_const(MO_16, val)) { 46604e186175SRichard Henderson vece = MO_16; 46610b4286ddSRichard Henderson } else if (val == dup_const(MO_32, val)) { 46624e186175SRichard Henderson vece = MO_32; 46634e186175SRichard Henderson } 46644e186175SRichard Henderson 46654e186175SRichard Henderson tcg_out_dupi_vec(s, ts->type, vece, reg, ts->val); 46660a6a8bc8SRichard Henderson } 466740ae5c62SRichard Henderson ts->mem_coherent = 0; 466840ae5c62SRichard Henderson break; 466940ae5c62SRichard Henderson case TEMP_VAL_MEM: 4670b016486eSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs, 4671b722452aSRichard Henderson preferred_regs, ts->indirect_base); 467240ae5c62SRichard Henderson tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset); 467340ae5c62SRichard Henderson ts->mem_coherent = 1; 467440ae5c62SRichard Henderson break; 467540ae5c62SRichard Henderson case TEMP_VAL_DEAD: 467640ae5c62SRichard Henderson default: 4677732e89f4SRichard Henderson g_assert_not_reached(); 467840ae5c62SRichard Henderson } 4679098859f1SRichard Henderson set_temp_val_reg(s, ts, reg); 468040ae5c62SRichard Henderson } 468140ae5c62SRichard Henderson 468259d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a 4683e8996ee0Sbellard temporary registers needs to be allocated to store a constant. */ 468459d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs) 46851ad80729SAurelien Jarno { 46862c0366f0SAurelien Jarno /* The liveness analysis already ensures that globals are back 4687eabb7b91SAurelien Jarno in memory. Keep an tcg_debug_assert for safety. */ 4688e01fa97dSRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || temp_readonly(ts)); 46891ad80729SAurelien Jarno } 46901ad80729SAurelien Jarno 46919814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be 4692641d5fbeSbellard modified be the following code. 'allocated_regs' is used in case a 4693641d5fbeSbellard temporary registers needs to be allocated to store a constant. */ 4694641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs) 4695641d5fbeSbellard { 4696ac3b8891SRichard Henderson int i, n; 4697641d5fbeSbellard 4698ac3b8891SRichard Henderson for (i = 0, n = s->nb_globals; i < n; i++) { 4699b13eb728SRichard Henderson temp_save(s, &s->temps[i], allocated_regs); 4700641d5fbeSbellard } 4701e5097dc8Sbellard } 4702e5097dc8Sbellard 47033d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be 47043d5c5f87SAurelien Jarno read by the following code. 'allocated_regs' is used in case a 47053d5c5f87SAurelien Jarno temporary registers needs to be allocated to store a constant. */ 47063d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs) 47073d5c5f87SAurelien Jarno { 4708ac3b8891SRichard Henderson int i, n; 47093d5c5f87SAurelien Jarno 4710ac3b8891SRichard Henderson for (i = 0, n = s->nb_globals; i < n; i++) { 471112b9b11aSRichard Henderson TCGTemp *ts = &s->temps[i]; 471212b9b11aSRichard Henderson tcg_debug_assert(ts->val_type != TEMP_VAL_REG 4713ee17db83SRichard Henderson || ts->kind == TEMP_FIXED 471412b9b11aSRichard Henderson || ts->mem_coherent); 47153d5c5f87SAurelien Jarno } 47163d5c5f87SAurelien Jarno } 47173d5c5f87SAurelien Jarno 4718e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and 4719e8996ee0Sbellard all globals are stored at their canonical location. */ 4720e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs) 4721e5097dc8Sbellard { 4722e5097dc8Sbellard int i; 4723e5097dc8Sbellard 4724c896fe29Sbellard for (i = s->nb_globals; i < s->nb_temps; i++) { 4725b13eb728SRichard Henderson TCGTemp *ts = &s->temps[i]; 4726c0522136SRichard Henderson 4727c0522136SRichard Henderson switch (ts->kind) { 4728f57c6915SRichard Henderson case TEMP_TB: 4729b13eb728SRichard Henderson temp_save(s, ts, allocated_regs); 4730c0522136SRichard Henderson break; 4731c7482438SRichard Henderson case TEMP_EBB: 47322c0366f0SAurelien Jarno /* The liveness analysis already ensures that temps are dead. 4733eabb7b91SAurelien Jarno Keep an tcg_debug_assert for safety. */ 4734eabb7b91SAurelien Jarno tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD); 4735c0522136SRichard Henderson break; 4736c0522136SRichard Henderson case TEMP_CONST: 4737c0522136SRichard Henderson /* Similarly, we should have freed any allocated register. */ 4738c0522136SRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_CONST); 4739c0522136SRichard Henderson break; 4740c0522136SRichard Henderson default: 4741c0522136SRichard Henderson g_assert_not_reached(); 4742c896fe29Sbellard } 4743641d5fbeSbellard } 4744e8996ee0Sbellard 4745e8996ee0Sbellard save_globals(s, allocated_regs); 4746c896fe29Sbellard } 4747c896fe29Sbellard 4748bab1671fSRichard Henderson /* 4749c7482438SRichard Henderson * At a conditional branch, we assume all temporaries are dead unless 4750c7482438SRichard Henderson * explicitly live-across-conditional-branch; all globals and local 4751c7482438SRichard Henderson * temps are synced to their location. 4752b4cb76e6SRichard Henderson */ 4753b4cb76e6SRichard Henderson static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs) 4754b4cb76e6SRichard Henderson { 4755b4cb76e6SRichard Henderson sync_globals(s, allocated_regs); 4756b4cb76e6SRichard Henderson 4757b4cb76e6SRichard Henderson for (int i = s->nb_globals; i < s->nb_temps; i++) { 4758b4cb76e6SRichard Henderson TCGTemp *ts = &s->temps[i]; 4759b4cb76e6SRichard Henderson /* 4760b4cb76e6SRichard Henderson * The liveness analysis already ensures that temps are dead. 4761b4cb76e6SRichard Henderson * Keep tcg_debug_asserts for safety. 4762b4cb76e6SRichard Henderson */ 4763c0522136SRichard Henderson switch (ts->kind) { 4764f57c6915SRichard Henderson case TEMP_TB: 4765b4cb76e6SRichard Henderson tcg_debug_assert(ts->val_type != TEMP_VAL_REG || ts->mem_coherent); 4766c0522136SRichard Henderson break; 4767c7482438SRichard Henderson case TEMP_EBB: 4768c0522136SRichard Henderson case TEMP_CONST: 4769c0522136SRichard Henderson break; 4770c0522136SRichard Henderson default: 4771c0522136SRichard Henderson g_assert_not_reached(); 4772b4cb76e6SRichard Henderson } 4773b4cb76e6SRichard Henderson } 4774b4cb76e6SRichard Henderson } 4775b4cb76e6SRichard Henderson 4776b4cb76e6SRichard Henderson /* 4777c58f4c97SRichard Henderson * Specialized code generation for INDEX_op_mov_* with a constant. 4778bab1671fSRichard Henderson */ 47790fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots, 4780ba87719cSRichard Henderson tcg_target_ulong val, TCGLifeData arg_life, 4781ba87719cSRichard Henderson TCGRegSet preferred_regs) 4782e8996ee0Sbellard { 4783d63e3b6eSRichard Henderson /* ENV should not be modified. */ 4784e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 478559d7c14eSRichard Henderson 478659d7c14eSRichard Henderson /* The movi is not explicitly generated here. */ 4787098859f1SRichard Henderson set_temp_val_nonreg(s, ots, TEMP_VAL_CONST); 4788e8996ee0Sbellard ots->val = val; 478959d7c14eSRichard Henderson ots->mem_coherent = 0; 4790ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) { 4791ba87719cSRichard Henderson temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0)); 479259d7c14eSRichard Henderson } else if (IS_DEAD_ARG(0)) { 4793f8bf00f1SRichard Henderson temp_dead(s, ots); 47944c4e1ab2SAurelien Jarno } 4795e8996ee0Sbellard } 4796e8996ee0Sbellard 4797bab1671fSRichard Henderson /* 4798bab1671fSRichard Henderson * Specialized code generation for INDEX_op_mov_*. 4799bab1671fSRichard Henderson */ 4800dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op) 4801c896fe29Sbellard { 4802dd186292SRichard Henderson const TCGLifeData arg_life = op->life; 480369e3706dSRichard Henderson TCGRegSet allocated_regs, preferred_regs; 4804c896fe29Sbellard TCGTemp *ts, *ots; 4805450445d5SRichard Henderson TCGType otype, itype; 4806098859f1SRichard Henderson TCGReg oreg, ireg; 4807c896fe29Sbellard 4808d21369f5SRichard Henderson allocated_regs = s->reserved_regs; 480931fd884bSRichard Henderson preferred_regs = output_pref(op, 0); 481043439139SRichard Henderson ots = arg_temp(op->args[0]); 481143439139SRichard Henderson ts = arg_temp(op->args[1]); 4812450445d5SRichard Henderson 4813d63e3b6eSRichard Henderson /* ENV should not be modified. */ 4814e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 4815d63e3b6eSRichard Henderson 4816450445d5SRichard Henderson /* Note that otype != itype for no-op truncation. */ 4817450445d5SRichard Henderson otype = ots->type; 4818450445d5SRichard Henderson itype = ts->type; 4819c896fe29Sbellard 48200fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_CONST) { 48210fe4fca4SPaolo Bonzini /* propagate constant or generate sti */ 48220fe4fca4SPaolo Bonzini tcg_target_ulong val = ts->val; 48230fe4fca4SPaolo Bonzini if (IS_DEAD_ARG(1)) { 48240fe4fca4SPaolo Bonzini temp_dead(s, ts); 48250fe4fca4SPaolo Bonzini } 482669e3706dSRichard Henderson tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs); 48270fe4fca4SPaolo Bonzini return; 48280fe4fca4SPaolo Bonzini } 48290fe4fca4SPaolo Bonzini 48300fe4fca4SPaolo Bonzini /* If the source value is in memory we're going to be forced 48310fe4fca4SPaolo Bonzini to have it in a register in order to perform the copy. Copy 48320fe4fca4SPaolo Bonzini the SOURCE value into its own register first, that way we 48330fe4fca4SPaolo Bonzini don't have to reload SOURCE the next time it is used. */ 48340fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_MEM) { 483569e3706dSRichard Henderson temp_load(s, ts, tcg_target_available_regs[itype], 483669e3706dSRichard Henderson allocated_regs, preferred_regs); 4837c29c1d7eSAurelien Jarno } 48380fe4fca4SPaolo Bonzini tcg_debug_assert(ts->val_type == TEMP_VAL_REG); 4839098859f1SRichard Henderson ireg = ts->reg; 4840098859f1SRichard Henderson 4841d63e3b6eSRichard Henderson if (IS_DEAD_ARG(0)) { 4842c29c1d7eSAurelien Jarno /* mov to a non-saved dead register makes no sense (even with 4843c29c1d7eSAurelien Jarno liveness analysis disabled). */ 4844eabb7b91SAurelien Jarno tcg_debug_assert(NEED_SYNC_ARG(0)); 4845c29c1d7eSAurelien Jarno if (!ots->mem_allocated) { 48462272e4a7SRichard Henderson temp_allocate_frame(s, ots); 4847c29c1d7eSAurelien Jarno } 4848098859f1SRichard Henderson tcg_out_st(s, otype, ireg, ots->mem_base->reg, ots->mem_offset); 4849c29c1d7eSAurelien Jarno if (IS_DEAD_ARG(1)) { 4850f8bf00f1SRichard Henderson temp_dead(s, ts); 4851c29c1d7eSAurelien Jarno } 4852f8bf00f1SRichard Henderson temp_dead(s, ots); 4853098859f1SRichard Henderson return; 4854098859f1SRichard Henderson } 4855098859f1SRichard Henderson 4856ee17db83SRichard Henderson if (IS_DEAD_ARG(1) && ts->kind != TEMP_FIXED) { 4857098859f1SRichard Henderson /* 4858098859f1SRichard Henderson * The mov can be suppressed. Kill input first, so that it 4859098859f1SRichard Henderson * is unlinked from reg_to_temp, then set the output to the 4860098859f1SRichard Henderson * reg that we saved from the input. 4861098859f1SRichard Henderson */ 4862f8bf00f1SRichard Henderson temp_dead(s, ts); 4863098859f1SRichard Henderson oreg = ireg; 4864c29c1d7eSAurelien Jarno } else { 4865098859f1SRichard Henderson if (ots->val_type == TEMP_VAL_REG) { 4866098859f1SRichard Henderson oreg = ots->reg; 4867098859f1SRichard Henderson } else { 4868098859f1SRichard Henderson /* Make sure to not spill the input register during allocation. */ 4869098859f1SRichard Henderson oreg = tcg_reg_alloc(s, tcg_target_available_regs[otype], 4870098859f1SRichard Henderson allocated_regs | ((TCGRegSet)1 << ireg), 4871098859f1SRichard Henderson preferred_regs, ots->indirect_base); 4872c29c1d7eSAurelien Jarno } 4873098859f1SRichard Henderson if (!tcg_out_mov(s, otype, oreg, ireg)) { 4874240c08d0SRichard Henderson /* 4875240c08d0SRichard Henderson * Cross register class move not supported. 4876240c08d0SRichard Henderson * Store the source register into the destination slot 4877240c08d0SRichard Henderson * and leave the destination temp as TEMP_VAL_MEM. 4878240c08d0SRichard Henderson */ 4879e01fa97dSRichard Henderson assert(!temp_readonly(ots)); 4880240c08d0SRichard Henderson if (!ts->mem_allocated) { 4881240c08d0SRichard Henderson temp_allocate_frame(s, ots); 4882240c08d0SRichard Henderson } 4883098859f1SRichard Henderson tcg_out_st(s, ts->type, ireg, ots->mem_base->reg, ots->mem_offset); 4884098859f1SRichard Henderson set_temp_val_nonreg(s, ts, TEMP_VAL_MEM); 4885240c08d0SRichard Henderson ots->mem_coherent = 1; 4886240c08d0SRichard Henderson return; 488778113e83SRichard Henderson } 4888c29c1d7eSAurelien Jarno } 4889098859f1SRichard Henderson set_temp_val_reg(s, ots, oreg); 4890c896fe29Sbellard ots->mem_coherent = 0; 4891098859f1SRichard Henderson 4892ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) { 489398b4e186SRichard Henderson temp_sync(s, ots, allocated_regs, 0, 0); 4894c29c1d7eSAurelien Jarno } 4895ec7a869dSAurelien Jarno } 4896c896fe29Sbellard 4897bab1671fSRichard Henderson /* 4898bab1671fSRichard Henderson * Specialized code generation for INDEX_op_dup_vec. 4899bab1671fSRichard Henderson */ 4900bab1671fSRichard Henderson static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op) 4901bab1671fSRichard Henderson { 4902bab1671fSRichard Henderson const TCGLifeData arg_life = op->life; 4903bab1671fSRichard Henderson TCGRegSet dup_out_regs, dup_in_regs; 4904501fb3daSRichard Henderson const TCGArgConstraint *dup_args_ct; 4905bab1671fSRichard Henderson TCGTemp *its, *ots; 4906bab1671fSRichard Henderson TCGType itype, vtype; 4907bab1671fSRichard Henderson unsigned vece; 490831c96417SRichard Henderson int lowpart_ofs; 4909bab1671fSRichard Henderson bool ok; 4910bab1671fSRichard Henderson 4911bab1671fSRichard Henderson ots = arg_temp(op->args[0]); 4912bab1671fSRichard Henderson its = arg_temp(op->args[1]); 4913bab1671fSRichard Henderson 4914bab1671fSRichard Henderson /* ENV should not be modified. */ 4915e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 4916bab1671fSRichard Henderson 4917bab1671fSRichard Henderson itype = its->type; 4918bab1671fSRichard Henderson vece = TCGOP_VECE(op); 49194d872218SRichard Henderson vtype = TCGOP_TYPE(op); 4920bab1671fSRichard Henderson 4921bab1671fSRichard Henderson if (its->val_type == TEMP_VAL_CONST) { 4922bab1671fSRichard Henderson /* Propagate constant via movi -> dupi. */ 4923bab1671fSRichard Henderson tcg_target_ulong val = its->val; 4924bab1671fSRichard Henderson if (IS_DEAD_ARG(1)) { 4925bab1671fSRichard Henderson temp_dead(s, its); 4926bab1671fSRichard Henderson } 492731fd884bSRichard Henderson tcg_reg_alloc_do_movi(s, ots, val, arg_life, output_pref(op, 0)); 4928bab1671fSRichard Henderson return; 4929bab1671fSRichard Henderson } 4930bab1671fSRichard Henderson 4931501fb3daSRichard Henderson dup_args_ct = opcode_args_ct(op); 4932501fb3daSRichard Henderson dup_out_regs = dup_args_ct[0].regs; 4933501fb3daSRichard Henderson dup_in_regs = dup_args_ct[1].regs; 4934bab1671fSRichard Henderson 4935bab1671fSRichard Henderson /* Allocate the output register now. */ 4936bab1671fSRichard Henderson if (ots->val_type != TEMP_VAL_REG) { 4937bab1671fSRichard Henderson TCGRegSet allocated_regs = s->reserved_regs; 4938098859f1SRichard Henderson TCGReg oreg; 4939bab1671fSRichard Henderson 4940bab1671fSRichard Henderson if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) { 4941bab1671fSRichard Henderson /* Make sure to not spill the input register. */ 4942bab1671fSRichard Henderson tcg_regset_set_reg(allocated_regs, its->reg); 4943bab1671fSRichard Henderson } 4944098859f1SRichard Henderson oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs, 494531fd884bSRichard Henderson output_pref(op, 0), ots->indirect_base); 4946098859f1SRichard Henderson set_temp_val_reg(s, ots, oreg); 4947bab1671fSRichard Henderson } 4948bab1671fSRichard Henderson 4949bab1671fSRichard Henderson switch (its->val_type) { 4950bab1671fSRichard Henderson case TEMP_VAL_REG: 4951bab1671fSRichard Henderson /* 4952bab1671fSRichard Henderson * The dup constriaints must be broad, covering all possible VECE. 4953bab1671fSRichard Henderson * However, tcg_op_dup_vec() gets to see the VECE and we allow it 4954bab1671fSRichard Henderson * to fail, indicating that extra moves are required for that case. 4955bab1671fSRichard Henderson */ 4956bab1671fSRichard Henderson if (tcg_regset_test_reg(dup_in_regs, its->reg)) { 4957bab1671fSRichard Henderson if (tcg_out_dup_vec(s, vtype, vece, ots->reg, its->reg)) { 4958bab1671fSRichard Henderson goto done; 4959bab1671fSRichard Henderson } 4960bab1671fSRichard Henderson /* Try again from memory or a vector input register. */ 4961bab1671fSRichard Henderson } 4962bab1671fSRichard Henderson if (!its->mem_coherent) { 4963bab1671fSRichard Henderson /* 4964bab1671fSRichard Henderson * The input register is not synced, and so an extra store 4965bab1671fSRichard Henderson * would be required to use memory. Attempt an integer-vector 4966bab1671fSRichard Henderson * register move first. We do not have a TCGRegSet for this. 4967bab1671fSRichard Henderson */ 4968bab1671fSRichard Henderson if (tcg_out_mov(s, itype, ots->reg, its->reg)) { 4969bab1671fSRichard Henderson break; 4970bab1671fSRichard Henderson } 4971bab1671fSRichard Henderson /* Sync the temp back to its slot and load from there. */ 4972bab1671fSRichard Henderson temp_sync(s, its, s->reserved_regs, 0, 0); 4973bab1671fSRichard Henderson } 4974bab1671fSRichard Henderson /* fall through */ 4975bab1671fSRichard Henderson 4976bab1671fSRichard Henderson case TEMP_VAL_MEM: 497731c96417SRichard Henderson lowpart_ofs = 0; 497831c96417SRichard Henderson if (HOST_BIG_ENDIAN) { 497931c96417SRichard Henderson lowpart_ofs = tcg_type_size(itype) - (1 << vece); 498031c96417SRichard Henderson } 4981d6ecb4a9SRichard Henderson if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg, 498231c96417SRichard Henderson its->mem_offset + lowpart_ofs)) { 4983d6ecb4a9SRichard Henderson goto done; 4984d6ecb4a9SRichard Henderson } 4985098859f1SRichard Henderson /* Load the input into the destination vector register. */ 4986bab1671fSRichard Henderson tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset); 4987bab1671fSRichard Henderson break; 4988bab1671fSRichard Henderson 4989bab1671fSRichard Henderson default: 4990bab1671fSRichard Henderson g_assert_not_reached(); 4991bab1671fSRichard Henderson } 4992bab1671fSRichard Henderson 4993bab1671fSRichard Henderson /* We now have a vector input register, so dup must succeed. */ 4994bab1671fSRichard Henderson ok = tcg_out_dup_vec(s, vtype, vece, ots->reg, ots->reg); 4995bab1671fSRichard Henderson tcg_debug_assert(ok); 4996bab1671fSRichard Henderson 4997bab1671fSRichard Henderson done: 499836f5539cSRichard Henderson ots->mem_coherent = 0; 4999bab1671fSRichard Henderson if (IS_DEAD_ARG(1)) { 5000bab1671fSRichard Henderson temp_dead(s, its); 5001bab1671fSRichard Henderson } 5002bab1671fSRichard Henderson if (NEED_SYNC_ARG(0)) { 5003bab1671fSRichard Henderson temp_sync(s, ots, s->reserved_regs, 0, 0); 5004bab1671fSRichard Henderson } 5005bab1671fSRichard Henderson if (IS_DEAD_ARG(0)) { 5006bab1671fSRichard Henderson temp_dead(s, ots); 5007bab1671fSRichard Henderson } 5008bab1671fSRichard Henderson } 5009bab1671fSRichard Henderson 5010dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) 5011c896fe29Sbellard { 5012dd186292SRichard Henderson const TCGLifeData arg_life = op->life; 5013dd186292SRichard Henderson const TCGOpDef * const def = &tcg_op_defs[op->opc]; 501482790a87SRichard Henderson TCGRegSet i_allocated_regs; 501582790a87SRichard Henderson TCGRegSet o_allocated_regs; 5016b6638662SRichard Henderson int i, k, nb_iargs, nb_oargs; 5017b6638662SRichard Henderson TCGReg reg; 5018c896fe29Sbellard TCGArg arg; 5019501fb3daSRichard Henderson const TCGArgConstraint *args_ct; 5020c896fe29Sbellard const TCGArgConstraint *arg_ct; 5021c896fe29Sbellard TCGTemp *ts; 5022c896fe29Sbellard TCGArg new_args[TCG_MAX_OP_ARGS]; 5023c896fe29Sbellard int const_args[TCG_MAX_OP_ARGS]; 502421e9a8aeSRichard Henderson TCGCond op_cond; 5025c896fe29Sbellard 5026c896fe29Sbellard nb_oargs = def->nb_oargs; 5027c896fe29Sbellard nb_iargs = def->nb_iargs; 5028c896fe29Sbellard 5029c896fe29Sbellard /* copy constants */ 5030c896fe29Sbellard memcpy(new_args + nb_oargs + nb_iargs, 5031dd186292SRichard Henderson op->args + nb_oargs + nb_iargs, 5032c896fe29Sbellard sizeof(TCGArg) * def->nb_cargs); 5033c896fe29Sbellard 5034d21369f5SRichard Henderson i_allocated_regs = s->reserved_regs; 5035d21369f5SRichard Henderson o_allocated_regs = s->reserved_regs; 503682790a87SRichard Henderson 503721e9a8aeSRichard Henderson switch (op->opc) { 503821e9a8aeSRichard Henderson case INDEX_op_brcond_i32: 503921e9a8aeSRichard Henderson case INDEX_op_brcond_i64: 504021e9a8aeSRichard Henderson op_cond = op->args[2]; 504121e9a8aeSRichard Henderson break; 504221e9a8aeSRichard Henderson case INDEX_op_setcond_i32: 504321e9a8aeSRichard Henderson case INDEX_op_setcond_i64: 504421e9a8aeSRichard Henderson case INDEX_op_negsetcond_i32: 504521e9a8aeSRichard Henderson case INDEX_op_negsetcond_i64: 504621e9a8aeSRichard Henderson case INDEX_op_cmp_vec: 504721e9a8aeSRichard Henderson op_cond = op->args[3]; 504821e9a8aeSRichard Henderson break; 504921e9a8aeSRichard Henderson case INDEX_op_brcond2_i32: 505021e9a8aeSRichard Henderson op_cond = op->args[4]; 505121e9a8aeSRichard Henderson break; 505221e9a8aeSRichard Henderson case INDEX_op_movcond_i32: 505321e9a8aeSRichard Henderson case INDEX_op_movcond_i64: 505421e9a8aeSRichard Henderson case INDEX_op_setcond2_i32: 505521e9a8aeSRichard Henderson case INDEX_op_cmpsel_vec: 505621e9a8aeSRichard Henderson op_cond = op->args[5]; 505721e9a8aeSRichard Henderson break; 505821e9a8aeSRichard Henderson default: 505921e9a8aeSRichard Henderson /* No condition within opcode. */ 506021e9a8aeSRichard Henderson op_cond = TCG_COND_ALWAYS; 506121e9a8aeSRichard Henderson break; 506221e9a8aeSRichard Henderson } 506321e9a8aeSRichard Henderson 5064501fb3daSRichard Henderson args_ct = opcode_args_ct(op); 5065501fb3daSRichard Henderson 5066c896fe29Sbellard /* satisfy input constraints */ 5067c896fe29Sbellard for (k = 0; k < nb_iargs; k++) { 506829f5e925SRichard Henderson TCGRegSet i_preferred_regs, i_required_regs; 506929f5e925SRichard Henderson bool allocate_new_reg, copyto_new_reg; 507029f5e925SRichard Henderson TCGTemp *ts2; 507129f5e925SRichard Henderson int i1, i2; 5072d62816f2SRichard Henderson 5073501fb3daSRichard Henderson i = args_ct[nb_oargs + k].sort_index; 5074dd186292SRichard Henderson arg = op->args[i]; 5075501fb3daSRichard Henderson arg_ct = &args_ct[i]; 507643439139SRichard Henderson ts = arg_temp(arg); 507740ae5c62SRichard Henderson 507840ae5c62SRichard Henderson if (ts->val_type == TEMP_VAL_CONST 507921e9a8aeSRichard Henderson && tcg_target_const_match(ts->val, arg_ct->ct, ts->type, 508021e9a8aeSRichard Henderson op_cond, TCGOP_VECE(op))) { 5081c896fe29Sbellard /* constant is OK for instruction */ 5082c896fe29Sbellard const_args[i] = 1; 5083c896fe29Sbellard new_args[i] = ts->val; 5084d62816f2SRichard Henderson continue; 5085c896fe29Sbellard } 508640ae5c62SRichard Henderson 50871c1824dcSRichard Henderson reg = ts->reg; 50881c1824dcSRichard Henderson i_preferred_regs = 0; 508929f5e925SRichard Henderson i_required_regs = arg_ct->regs; 50901c1824dcSRichard Henderson allocate_new_reg = false; 509129f5e925SRichard Henderson copyto_new_reg = false; 50921c1824dcSRichard Henderson 509329f5e925SRichard Henderson switch (arg_ct->pair) { 509429f5e925SRichard Henderson case 0: /* not paired */ 5095bc2b17e6SRichard Henderson if (arg_ct->ialias) { 509631fd884bSRichard Henderson i_preferred_regs = output_pref(op, arg_ct->alias_index); 5097c0522136SRichard Henderson 5098c0522136SRichard Henderson /* 5099c0522136SRichard Henderson * If the input is readonly, then it cannot also be an 5100c0522136SRichard Henderson * output and aliased to itself. If the input is not 5101c0522136SRichard Henderson * dead after the instruction, we must allocate a new 5102c0522136SRichard Henderson * register and move it. 5103c0522136SRichard Henderson */ 510422d2e535SIlya Leoshkevich if (temp_readonly(ts) || !IS_DEAD_ARG(i) 5105501fb3daSRichard Henderson || args_ct[arg_ct->alias_index].newreg) { 51061c1824dcSRichard Henderson allocate_new_reg = true; 51071c1824dcSRichard Henderson } else if (ts->val_type == TEMP_VAL_REG) { 5108c0522136SRichard Henderson /* 51091c1824dcSRichard Henderson * Check if the current register has already been 51101c1824dcSRichard Henderson * allocated for another input. 5111c0522136SRichard Henderson */ 511229f5e925SRichard Henderson allocate_new_reg = 511329f5e925SRichard Henderson tcg_regset_test_reg(i_allocated_regs, reg); 51147e1df267SAurelien Jarno } 51157e1df267SAurelien Jarno } 51161c1824dcSRichard Henderson if (!allocate_new_reg) { 511729f5e925SRichard Henderson temp_load(s, ts, i_required_regs, i_allocated_regs, 511829f5e925SRichard Henderson i_preferred_regs); 5119c896fe29Sbellard reg = ts->reg; 512029f5e925SRichard Henderson allocate_new_reg = !tcg_regset_test_reg(i_required_regs, reg); 51211c1824dcSRichard Henderson } 51221c1824dcSRichard Henderson if (allocate_new_reg) { 5123c0522136SRichard Henderson /* 5124c0522136SRichard Henderson * Allocate a new register matching the constraint 5125c0522136SRichard Henderson * and move the temporary register into it. 5126c0522136SRichard Henderson */ 5127d62816f2SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 5128d62816f2SRichard Henderson i_allocated_regs, 0); 512929f5e925SRichard Henderson reg = tcg_reg_alloc(s, i_required_regs, i_allocated_regs, 51301c1824dcSRichard Henderson i_preferred_regs, ts->indirect_base); 513129f5e925SRichard Henderson copyto_new_reg = true; 513229f5e925SRichard Henderson } 513329f5e925SRichard Henderson break; 513429f5e925SRichard Henderson 513529f5e925SRichard Henderson case 1: 513629f5e925SRichard Henderson /* First of an input pair; if i1 == i2, the second is an output. */ 513729f5e925SRichard Henderson i1 = i; 513829f5e925SRichard Henderson i2 = arg_ct->pair_index; 513929f5e925SRichard Henderson ts2 = i1 != i2 ? arg_temp(op->args[i2]) : NULL; 514029f5e925SRichard Henderson 514129f5e925SRichard Henderson /* 514229f5e925SRichard Henderson * It is easier to default to allocating a new pair 514329f5e925SRichard Henderson * and to identify a few cases where it's not required. 514429f5e925SRichard Henderson */ 514529f5e925SRichard Henderson if (arg_ct->ialias) { 514631fd884bSRichard Henderson i_preferred_regs = output_pref(op, arg_ct->alias_index); 514729f5e925SRichard Henderson if (IS_DEAD_ARG(i1) && 514829f5e925SRichard Henderson IS_DEAD_ARG(i2) && 514929f5e925SRichard Henderson !temp_readonly(ts) && 515029f5e925SRichard Henderson ts->val_type == TEMP_VAL_REG && 515129f5e925SRichard Henderson ts->reg < TCG_TARGET_NB_REGS - 1 && 515229f5e925SRichard Henderson tcg_regset_test_reg(i_required_regs, reg) && 515329f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg) && 515429f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg + 1) && 515529f5e925SRichard Henderson (ts2 515629f5e925SRichard Henderson ? ts2->val_type == TEMP_VAL_REG && 515729f5e925SRichard Henderson ts2->reg == reg + 1 && 515829f5e925SRichard Henderson !temp_readonly(ts2) 515929f5e925SRichard Henderson : s->reg_to_temp[reg + 1] == NULL)) { 516029f5e925SRichard Henderson break; 516129f5e925SRichard Henderson } 516229f5e925SRichard Henderson } else { 516329f5e925SRichard Henderson /* Without aliasing, the pair must also be an input. */ 516429f5e925SRichard Henderson tcg_debug_assert(ts2); 516529f5e925SRichard Henderson if (ts->val_type == TEMP_VAL_REG && 516629f5e925SRichard Henderson ts2->val_type == TEMP_VAL_REG && 516729f5e925SRichard Henderson ts2->reg == reg + 1 && 516829f5e925SRichard Henderson tcg_regset_test_reg(i_required_regs, reg)) { 516929f5e925SRichard Henderson break; 517029f5e925SRichard Henderson } 517129f5e925SRichard Henderson } 517229f5e925SRichard Henderson reg = tcg_reg_alloc_pair(s, i_required_regs, i_allocated_regs, 517329f5e925SRichard Henderson 0, ts->indirect_base); 517429f5e925SRichard Henderson goto do_pair; 517529f5e925SRichard Henderson 517629f5e925SRichard Henderson case 2: /* pair second */ 517729f5e925SRichard Henderson reg = new_args[arg_ct->pair_index] + 1; 517829f5e925SRichard Henderson goto do_pair; 517929f5e925SRichard Henderson 518029f5e925SRichard Henderson case 3: /* ialias with second output, no first input */ 518129f5e925SRichard Henderson tcg_debug_assert(arg_ct->ialias); 518231fd884bSRichard Henderson i_preferred_regs = output_pref(op, arg_ct->alias_index); 518329f5e925SRichard Henderson 518429f5e925SRichard Henderson if (IS_DEAD_ARG(i) && 518529f5e925SRichard Henderson !temp_readonly(ts) && 518629f5e925SRichard Henderson ts->val_type == TEMP_VAL_REG && 518729f5e925SRichard Henderson reg > 0 && 518829f5e925SRichard Henderson s->reg_to_temp[reg - 1] == NULL && 518929f5e925SRichard Henderson tcg_regset_test_reg(i_required_regs, reg) && 519029f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg) && 519129f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg - 1)) { 519229f5e925SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg - 1); 519329f5e925SRichard Henderson break; 519429f5e925SRichard Henderson } 519529f5e925SRichard Henderson reg = tcg_reg_alloc_pair(s, i_required_regs >> 1, 519629f5e925SRichard Henderson i_allocated_regs, 0, 519729f5e925SRichard Henderson ts->indirect_base); 519829f5e925SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg); 519929f5e925SRichard Henderson reg += 1; 520029f5e925SRichard Henderson goto do_pair; 520129f5e925SRichard Henderson 520229f5e925SRichard Henderson do_pair: 520329f5e925SRichard Henderson /* 520429f5e925SRichard Henderson * If an aliased input is not dead after the instruction, 520529f5e925SRichard Henderson * we must allocate a new register and move it. 520629f5e925SRichard Henderson */ 520729f5e925SRichard Henderson if (arg_ct->ialias && (!IS_DEAD_ARG(i) || temp_readonly(ts))) { 520829f5e925SRichard Henderson TCGRegSet t_allocated_regs = i_allocated_regs; 520929f5e925SRichard Henderson 521029f5e925SRichard Henderson /* 521129f5e925SRichard Henderson * Because of the alias, and the continued life, make sure 521229f5e925SRichard Henderson * that the temp is somewhere *other* than the reg pair, 521329f5e925SRichard Henderson * and we get a copy in reg. 521429f5e925SRichard Henderson */ 521529f5e925SRichard Henderson tcg_regset_set_reg(t_allocated_regs, reg); 521629f5e925SRichard Henderson tcg_regset_set_reg(t_allocated_regs, reg + 1); 521729f5e925SRichard Henderson if (ts->val_type == TEMP_VAL_REG && ts->reg == reg) { 521829f5e925SRichard Henderson /* If ts was already in reg, copy it somewhere else. */ 521929f5e925SRichard Henderson TCGReg nr; 522029f5e925SRichard Henderson bool ok; 522129f5e925SRichard Henderson 522229f5e925SRichard Henderson tcg_debug_assert(ts->kind != TEMP_FIXED); 522329f5e925SRichard Henderson nr = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], 522429f5e925SRichard Henderson t_allocated_regs, 0, ts->indirect_base); 522529f5e925SRichard Henderson ok = tcg_out_mov(s, ts->type, nr, reg); 522629f5e925SRichard Henderson tcg_debug_assert(ok); 522729f5e925SRichard Henderson 522829f5e925SRichard Henderson set_temp_val_reg(s, ts, nr); 522929f5e925SRichard Henderson } else { 523029f5e925SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 523129f5e925SRichard Henderson t_allocated_regs, 0); 523229f5e925SRichard Henderson copyto_new_reg = true; 523329f5e925SRichard Henderson } 523429f5e925SRichard Henderson } else { 523529f5e925SRichard Henderson /* Preferably allocate to reg, otherwise copy. */ 523629f5e925SRichard Henderson i_required_regs = (TCGRegSet)1 << reg; 523729f5e925SRichard Henderson temp_load(s, ts, i_required_regs, i_allocated_regs, 523829f5e925SRichard Henderson i_preferred_regs); 523929f5e925SRichard Henderson copyto_new_reg = ts->reg != reg; 524029f5e925SRichard Henderson } 524129f5e925SRichard Henderson break; 524229f5e925SRichard Henderson 524329f5e925SRichard Henderson default: 524429f5e925SRichard Henderson g_assert_not_reached(); 524529f5e925SRichard Henderson } 524629f5e925SRichard Henderson 524729f5e925SRichard Henderson if (copyto_new_reg) { 524878113e83SRichard Henderson if (!tcg_out_mov(s, ts->type, reg, ts->reg)) { 5249240c08d0SRichard Henderson /* 5250240c08d0SRichard Henderson * Cross register class move not supported. Sync the 5251240c08d0SRichard Henderson * temp back to its slot and load from there. 5252240c08d0SRichard Henderson */ 5253240c08d0SRichard Henderson temp_sync(s, ts, i_allocated_regs, 0, 0); 5254240c08d0SRichard Henderson tcg_out_ld(s, ts->type, reg, 5255240c08d0SRichard Henderson ts->mem_base->reg, ts->mem_offset); 525678113e83SRichard Henderson } 5257c896fe29Sbellard } 5258c896fe29Sbellard new_args[i] = reg; 5259c896fe29Sbellard const_args[i] = 0; 526082790a87SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg); 5261c896fe29Sbellard } 5262c896fe29Sbellard 5263c896fe29Sbellard /* mark dead temporaries and free the associated registers */ 5264866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 5265866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) { 526643439139SRichard Henderson temp_dead(s, arg_temp(op->args[i])); 5267c896fe29Sbellard } 5268c896fe29Sbellard } 5269c896fe29Sbellard 5270b4cb76e6SRichard Henderson if (def->flags & TCG_OPF_COND_BRANCH) { 5271b4cb76e6SRichard Henderson tcg_reg_alloc_cbranch(s, i_allocated_regs); 5272b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 527382790a87SRichard Henderson tcg_reg_alloc_bb_end(s, i_allocated_regs); 5274a52ad07eSAurelien Jarno } else { 5275c896fe29Sbellard if (def->flags & TCG_OPF_CALL_CLOBBER) { 5276b03cce8eSbellard /* XXX: permit generic clobber register list ? */ 5277c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) { 5278c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { 527982790a87SRichard Henderson tcg_reg_free(s, i, i_allocated_regs); 5280c896fe29Sbellard } 5281c896fe29Sbellard } 52823d5c5f87SAurelien Jarno } 52833d5c5f87SAurelien Jarno if (def->flags & TCG_OPF_SIDE_EFFECTS) { 52843d5c5f87SAurelien Jarno /* sync globals if the op has side effects and might trigger 52853d5c5f87SAurelien Jarno an exception. */ 528682790a87SRichard Henderson sync_globals(s, i_allocated_regs); 5287c896fe29Sbellard } 5288c896fe29Sbellard 5289c896fe29Sbellard /* satisfy the output constraints */ 5290c896fe29Sbellard for (k = 0; k < nb_oargs; k++) { 5291501fb3daSRichard Henderson i = args_ct[k].sort_index; 5292dd186292SRichard Henderson arg = op->args[i]; 5293501fb3daSRichard Henderson arg_ct = &args_ct[i]; 529443439139SRichard Henderson ts = arg_temp(arg); 5295d63e3b6eSRichard Henderson 5296d63e3b6eSRichard Henderson /* ENV should not be modified. */ 5297e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ts)); 5298d63e3b6eSRichard Henderson 529929f5e925SRichard Henderson switch (arg_ct->pair) { 530029f5e925SRichard Henderson case 0: /* not paired */ 5301bc2b17e6SRichard Henderson if (arg_ct->oalias && !const_args[arg_ct->alias_index]) { 53025ff9d6a4Sbellard reg = new_args[arg_ct->alias_index]; 5303bc2b17e6SRichard Henderson } else if (arg_ct->newreg) { 53049be0d080SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->regs, 530582790a87SRichard Henderson i_allocated_regs | o_allocated_regs, 530631fd884bSRichard Henderson output_pref(op, k), ts->indirect_base); 5307c896fe29Sbellard } else { 53089be0d080SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs, 530931fd884bSRichard Henderson output_pref(op, k), ts->indirect_base); 5310c896fe29Sbellard } 531129f5e925SRichard Henderson break; 531229f5e925SRichard Henderson 531329f5e925SRichard Henderson case 1: /* first of pair */ 531429f5e925SRichard Henderson if (arg_ct->oalias) { 531529f5e925SRichard Henderson reg = new_args[arg_ct->alias_index]; 5316ca5bed07SRichard Henderson } else if (arg_ct->newreg) { 5317ca5bed07SRichard Henderson reg = tcg_reg_alloc_pair(s, arg_ct->regs, 5318ca5bed07SRichard Henderson i_allocated_regs | o_allocated_regs, 5319ca5bed07SRichard Henderson output_pref(op, k), 5320ca5bed07SRichard Henderson ts->indirect_base); 5321ca5bed07SRichard Henderson } else { 532229f5e925SRichard Henderson reg = tcg_reg_alloc_pair(s, arg_ct->regs, o_allocated_regs, 5323ca5bed07SRichard Henderson output_pref(op, k), 5324ca5bed07SRichard Henderson ts->indirect_base); 5325ca5bed07SRichard Henderson } 532629f5e925SRichard Henderson break; 532729f5e925SRichard Henderson 532829f5e925SRichard Henderson case 2: /* second of pair */ 532929f5e925SRichard Henderson if (arg_ct->oalias) { 533029f5e925SRichard Henderson reg = new_args[arg_ct->alias_index]; 533129f5e925SRichard Henderson } else { 533229f5e925SRichard Henderson reg = new_args[arg_ct->pair_index] + 1; 533329f5e925SRichard Henderson } 533429f5e925SRichard Henderson break; 533529f5e925SRichard Henderson 533629f5e925SRichard Henderson case 3: /* first of pair, aliasing with a second input */ 533729f5e925SRichard Henderson tcg_debug_assert(!arg_ct->newreg); 533829f5e925SRichard Henderson reg = new_args[arg_ct->pair_index] - 1; 533929f5e925SRichard Henderson break; 534029f5e925SRichard Henderson 534129f5e925SRichard Henderson default: 534229f5e925SRichard Henderson g_assert_not_reached(); 534329f5e925SRichard Henderson } 534482790a87SRichard Henderson tcg_regset_set_reg(o_allocated_regs, reg); 5345098859f1SRichard Henderson set_temp_val_reg(s, ts, reg); 5346c896fe29Sbellard ts->mem_coherent = 0; 5347c896fe29Sbellard new_args[i] = reg; 5348c896fe29Sbellard } 5349e8996ee0Sbellard } 5350c896fe29Sbellard 5351c896fe29Sbellard /* emit instruction */ 5352678155b2SRichard Henderson switch (op->opc) { 5353678155b2SRichard Henderson case INDEX_op_ext8s_i32: 5354678155b2SRichard Henderson tcg_out_ext8s(s, TCG_TYPE_I32, new_args[0], new_args[1]); 5355678155b2SRichard Henderson break; 5356678155b2SRichard Henderson case INDEX_op_ext8s_i64: 5357678155b2SRichard Henderson tcg_out_ext8s(s, TCG_TYPE_I64, new_args[0], new_args[1]); 5358678155b2SRichard Henderson break; 5359d0e66c89SRichard Henderson case INDEX_op_ext8u_i32: 5360d0e66c89SRichard Henderson case INDEX_op_ext8u_i64: 5361d0e66c89SRichard Henderson tcg_out_ext8u(s, new_args[0], new_args[1]); 5362d0e66c89SRichard Henderson break; 5363753e42eaSRichard Henderson case INDEX_op_ext16s_i32: 5364753e42eaSRichard Henderson tcg_out_ext16s(s, TCG_TYPE_I32, new_args[0], new_args[1]); 5365753e42eaSRichard Henderson break; 5366753e42eaSRichard Henderson case INDEX_op_ext16s_i64: 5367753e42eaSRichard Henderson tcg_out_ext16s(s, TCG_TYPE_I64, new_args[0], new_args[1]); 5368753e42eaSRichard Henderson break; 5369379afdffSRichard Henderson case INDEX_op_ext16u_i32: 5370379afdffSRichard Henderson case INDEX_op_ext16u_i64: 5371379afdffSRichard Henderson tcg_out_ext16u(s, new_args[0], new_args[1]); 5372379afdffSRichard Henderson break; 537352bf3398SRichard Henderson case INDEX_op_ext32s_i64: 537452bf3398SRichard Henderson tcg_out_ext32s(s, new_args[0], new_args[1]); 537552bf3398SRichard Henderson break; 53769ecf5f61SRichard Henderson case INDEX_op_ext32u_i64: 53779ecf5f61SRichard Henderson tcg_out_ext32u(s, new_args[0], new_args[1]); 53789ecf5f61SRichard Henderson break; 53799c6aa274SRichard Henderson case INDEX_op_ext_i32_i64: 53809c6aa274SRichard Henderson tcg_out_exts_i32_i64(s, new_args[0], new_args[1]); 53819c6aa274SRichard Henderson break; 5382b9bfe000SRichard Henderson case INDEX_op_extu_i32_i64: 5383b9bfe000SRichard Henderson tcg_out_extu_i32_i64(s, new_args[0], new_args[1]); 5384b9bfe000SRichard Henderson break; 5385b8b94ac6SRichard Henderson case INDEX_op_extrl_i64_i32: 5386b8b94ac6SRichard Henderson tcg_out_extrl_i64_i32(s, new_args[0], new_args[1]); 5387b8b94ac6SRichard Henderson break; 5388678155b2SRichard Henderson default: 5389d2fd745fSRichard Henderson if (def->flags & TCG_OPF_VECTOR) { 53904d872218SRichard Henderson tcg_out_vec_op(s, op->opc, TCGOP_TYPE(op) - TCG_TYPE_V64, 53914d872218SRichard Henderson TCGOP_VECE(op), new_args, const_args); 5392d2fd745fSRichard Henderson } else { 53934e350091SRichard Henderson tcg_out_op(s, op->opc, TCGOP_TYPE(op), new_args, const_args); 5394d2fd745fSRichard Henderson } 5395678155b2SRichard Henderson break; 5396678155b2SRichard Henderson } 5397c896fe29Sbellard 5398c896fe29Sbellard /* move the outputs in the correct register if needed */ 5399c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 540043439139SRichard Henderson ts = arg_temp(op->args[i]); 5401d63e3b6eSRichard Henderson 5402d63e3b6eSRichard Henderson /* ENV should not be modified. */ 5403e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ts)); 5404d63e3b6eSRichard Henderson 5405ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) { 540698b4e186SRichard Henderson temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i)); 540759d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) { 5408f8bf00f1SRichard Henderson temp_dead(s, ts); 5409ec7a869dSAurelien Jarno } 5410c896fe29Sbellard } 5411c896fe29Sbellard } 5412c896fe29Sbellard 5413efe86b21SRichard Henderson static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op) 5414efe86b21SRichard Henderson { 5415efe86b21SRichard Henderson const TCGLifeData arg_life = op->life; 5416efe86b21SRichard Henderson TCGTemp *ots, *itsl, *itsh; 54174d872218SRichard Henderson TCGType vtype = TCGOP_TYPE(op); 5418efe86b21SRichard Henderson 5419efe86b21SRichard Henderson /* This opcode is only valid for 32-bit hosts, for 64-bit elements. */ 5420efe86b21SRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 32); 5421efe86b21SRichard Henderson tcg_debug_assert(TCGOP_VECE(op) == MO_64); 5422efe86b21SRichard Henderson 5423efe86b21SRichard Henderson ots = arg_temp(op->args[0]); 5424efe86b21SRichard Henderson itsl = arg_temp(op->args[1]); 5425efe86b21SRichard Henderson itsh = arg_temp(op->args[2]); 5426efe86b21SRichard Henderson 5427efe86b21SRichard Henderson /* ENV should not be modified. */ 5428efe86b21SRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 5429efe86b21SRichard Henderson 5430efe86b21SRichard Henderson /* Allocate the output register now. */ 5431efe86b21SRichard Henderson if (ots->val_type != TEMP_VAL_REG) { 5432efe86b21SRichard Henderson TCGRegSet allocated_regs = s->reserved_regs; 5433501fb3daSRichard Henderson TCGRegSet dup_out_regs = opcode_args_ct(op)[0].regs; 5434098859f1SRichard Henderson TCGReg oreg; 5435efe86b21SRichard Henderson 5436efe86b21SRichard Henderson /* Make sure to not spill the input registers. */ 5437efe86b21SRichard Henderson if (!IS_DEAD_ARG(1) && itsl->val_type == TEMP_VAL_REG) { 5438efe86b21SRichard Henderson tcg_regset_set_reg(allocated_regs, itsl->reg); 5439efe86b21SRichard Henderson } 5440efe86b21SRichard Henderson if (!IS_DEAD_ARG(2) && itsh->val_type == TEMP_VAL_REG) { 5441efe86b21SRichard Henderson tcg_regset_set_reg(allocated_regs, itsh->reg); 5442efe86b21SRichard Henderson } 5443efe86b21SRichard Henderson 5444098859f1SRichard Henderson oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs, 544531fd884bSRichard Henderson output_pref(op, 0), ots->indirect_base); 5446098859f1SRichard Henderson set_temp_val_reg(s, ots, oreg); 5447efe86b21SRichard Henderson } 5448efe86b21SRichard Henderson 5449efe86b21SRichard Henderson /* Promote dup2 of immediates to dupi_vec. */ 5450efe86b21SRichard Henderson if (itsl->val_type == TEMP_VAL_CONST && itsh->val_type == TEMP_VAL_CONST) { 5451efe86b21SRichard Henderson uint64_t val = deposit64(itsl->val, 32, 32, itsh->val); 5452efe86b21SRichard Henderson MemOp vece = MO_64; 5453efe86b21SRichard Henderson 5454efe86b21SRichard Henderson if (val == dup_const(MO_8, val)) { 5455efe86b21SRichard Henderson vece = MO_8; 5456efe86b21SRichard Henderson } else if (val == dup_const(MO_16, val)) { 5457efe86b21SRichard Henderson vece = MO_16; 5458efe86b21SRichard Henderson } else if (val == dup_const(MO_32, val)) { 5459efe86b21SRichard Henderson vece = MO_32; 5460efe86b21SRichard Henderson } 5461efe86b21SRichard Henderson 5462efe86b21SRichard Henderson tcg_out_dupi_vec(s, vtype, vece, ots->reg, val); 5463efe86b21SRichard Henderson goto done; 5464efe86b21SRichard Henderson } 5465efe86b21SRichard Henderson 5466efe86b21SRichard Henderson /* If the two inputs form one 64-bit value, try dupm_vec. */ 5467aef85402SRichard Henderson if (itsl->temp_subindex == HOST_BIG_ENDIAN && 5468aef85402SRichard Henderson itsh->temp_subindex == !HOST_BIG_ENDIAN && 5469aef85402SRichard Henderson itsl == itsh + (HOST_BIG_ENDIAN ? 1 : -1)) { 5470aef85402SRichard Henderson TCGTemp *its = itsl - HOST_BIG_ENDIAN; 5471aef85402SRichard Henderson 5472aef85402SRichard Henderson temp_sync(s, its + 0, s->reserved_regs, 0, 0); 5473aef85402SRichard Henderson temp_sync(s, its + 1, s->reserved_regs, 0, 0); 5474aef85402SRichard Henderson 5475efe86b21SRichard Henderson if (tcg_out_dupm_vec(s, vtype, MO_64, ots->reg, 5476efe86b21SRichard Henderson its->mem_base->reg, its->mem_offset)) { 5477efe86b21SRichard Henderson goto done; 5478efe86b21SRichard Henderson } 5479efe86b21SRichard Henderson } 5480efe86b21SRichard Henderson 5481efe86b21SRichard Henderson /* Fall back to generic expansion. */ 5482efe86b21SRichard Henderson return false; 5483efe86b21SRichard Henderson 5484efe86b21SRichard Henderson done: 548536f5539cSRichard Henderson ots->mem_coherent = 0; 5486efe86b21SRichard Henderson if (IS_DEAD_ARG(1)) { 5487efe86b21SRichard Henderson temp_dead(s, itsl); 5488efe86b21SRichard Henderson } 5489efe86b21SRichard Henderson if (IS_DEAD_ARG(2)) { 5490efe86b21SRichard Henderson temp_dead(s, itsh); 5491efe86b21SRichard Henderson } 5492efe86b21SRichard Henderson if (NEED_SYNC_ARG(0)) { 5493efe86b21SRichard Henderson temp_sync(s, ots, s->reserved_regs, 0, IS_DEAD_ARG(0)); 5494efe86b21SRichard Henderson } else if (IS_DEAD_ARG(0)) { 5495efe86b21SRichard Henderson temp_dead(s, ots); 5496efe86b21SRichard Henderson } 5497efe86b21SRichard Henderson return true; 5498efe86b21SRichard Henderson } 5499efe86b21SRichard Henderson 550039004a71SRichard Henderson static void load_arg_reg(TCGContext *s, TCGReg reg, TCGTemp *ts, 550139004a71SRichard Henderson TCGRegSet allocated_regs) 5502c896fe29Sbellard { 5503c896fe29Sbellard if (ts->val_type == TEMP_VAL_REG) { 5504c896fe29Sbellard if (ts->reg != reg) { 55054250da10SRichard Henderson tcg_reg_free(s, reg, allocated_regs); 550678113e83SRichard Henderson if (!tcg_out_mov(s, ts->type, reg, ts->reg)) { 5507240c08d0SRichard Henderson /* 5508240c08d0SRichard Henderson * Cross register class move not supported. Sync the 5509240c08d0SRichard Henderson * temp back to its slot and load from there. 5510240c08d0SRichard Henderson */ 5511240c08d0SRichard Henderson temp_sync(s, ts, allocated_regs, 0, 0); 5512240c08d0SRichard Henderson tcg_out_ld(s, ts->type, reg, 5513240c08d0SRichard Henderson ts->mem_base->reg, ts->mem_offset); 551478113e83SRichard Henderson } 5515c896fe29Sbellard } 5516c896fe29Sbellard } else { 5517ccb1bb66SRichard Henderson TCGRegSet arg_set = 0; 551840ae5c62SRichard Henderson 55194250da10SRichard Henderson tcg_reg_free(s, reg, allocated_regs); 552040ae5c62SRichard Henderson tcg_regset_set_reg(arg_set, reg); 5521b722452aSRichard Henderson temp_load(s, ts, arg_set, allocated_regs, 0); 5522c896fe29Sbellard } 552339004a71SRichard Henderson } 552440ae5c62SRichard Henderson 5525d78e4a4fSRichard Henderson static void load_arg_stk(TCGContext *s, unsigned arg_slot, TCGTemp *ts, 552639004a71SRichard Henderson TCGRegSet allocated_regs) 552739004a71SRichard Henderson { 552839004a71SRichard Henderson /* 552939004a71SRichard Henderson * When the destination is on the stack, load up the temp and store. 553039004a71SRichard Henderson * If there are many call-saved registers, the temp might live to 553139004a71SRichard Henderson * see another use; otherwise it'll be discarded. 553239004a71SRichard Henderson */ 553339004a71SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], allocated_regs, 0); 553439004a71SRichard Henderson tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, 5535d78e4a4fSRichard Henderson arg_slot_stk_ofs(arg_slot)); 553639004a71SRichard Henderson } 553739004a71SRichard Henderson 553839004a71SRichard Henderson static void load_arg_normal(TCGContext *s, const TCGCallArgumentLoc *l, 553939004a71SRichard Henderson TCGTemp *ts, TCGRegSet *allocated_regs) 554039004a71SRichard Henderson { 5541338b61e9SRichard Henderson if (arg_slot_reg_p(l->arg_slot)) { 554239004a71SRichard Henderson TCGReg reg = tcg_target_call_iarg_regs[l->arg_slot]; 554339004a71SRichard Henderson load_arg_reg(s, reg, ts, *allocated_regs); 554439004a71SRichard Henderson tcg_regset_set_reg(*allocated_regs, reg); 554539004a71SRichard Henderson } else { 5546d78e4a4fSRichard Henderson load_arg_stk(s, l->arg_slot, ts, *allocated_regs); 5547c896fe29Sbellard } 554839cf05d3Sbellard } 5549c896fe29Sbellard 5550d78e4a4fSRichard Henderson static void load_arg_ref(TCGContext *s, unsigned arg_slot, TCGReg ref_base, 5551313bdea8SRichard Henderson intptr_t ref_off, TCGRegSet *allocated_regs) 5552313bdea8SRichard Henderson { 5553313bdea8SRichard Henderson TCGReg reg; 5554313bdea8SRichard Henderson 5555d78e4a4fSRichard Henderson if (arg_slot_reg_p(arg_slot)) { 5556313bdea8SRichard Henderson reg = tcg_target_call_iarg_regs[arg_slot]; 5557313bdea8SRichard Henderson tcg_reg_free(s, reg, *allocated_regs); 5558313bdea8SRichard Henderson tcg_out_addi_ptr(s, reg, ref_base, ref_off); 5559313bdea8SRichard Henderson tcg_regset_set_reg(*allocated_regs, reg); 5560313bdea8SRichard Henderson } else { 5561313bdea8SRichard Henderson reg = tcg_reg_alloc(s, tcg_target_available_regs[TCG_TYPE_PTR], 5562313bdea8SRichard Henderson *allocated_regs, 0, false); 5563313bdea8SRichard Henderson tcg_out_addi_ptr(s, reg, ref_base, ref_off); 5564313bdea8SRichard Henderson tcg_out_st(s, TCG_TYPE_PTR, reg, TCG_REG_CALL_STACK, 5565d78e4a4fSRichard Henderson arg_slot_stk_ofs(arg_slot)); 5566313bdea8SRichard Henderson } 5567313bdea8SRichard Henderson } 5568313bdea8SRichard Henderson 556939004a71SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op) 557039004a71SRichard Henderson { 557139004a71SRichard Henderson const int nb_oargs = TCGOP_CALLO(op); 557239004a71SRichard Henderson const int nb_iargs = TCGOP_CALLI(op); 557339004a71SRichard Henderson const TCGLifeData arg_life = op->life; 557439004a71SRichard Henderson const TCGHelperInfo *info = tcg_call_info(op); 557539004a71SRichard Henderson TCGRegSet allocated_regs = s->reserved_regs; 557639004a71SRichard Henderson int i; 557739004a71SRichard Henderson 557839004a71SRichard Henderson /* 557939004a71SRichard Henderson * Move inputs into place in reverse order, 558039004a71SRichard Henderson * so that we place stacked arguments first. 558139004a71SRichard Henderson */ 558239004a71SRichard Henderson for (i = nb_iargs - 1; i >= 0; --i) { 558339004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i]; 558439004a71SRichard Henderson TCGTemp *ts = arg_temp(op->args[nb_oargs + i]); 558539004a71SRichard Henderson 558639004a71SRichard Henderson switch (loc->kind) { 558739004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 558839004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 558939004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 559039004a71SRichard Henderson load_arg_normal(s, loc, ts, &allocated_regs); 559139004a71SRichard Henderson break; 5592313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF: 5593313bdea8SRichard Henderson load_arg_stk(s, loc->ref_slot, ts, allocated_regs); 5594313bdea8SRichard Henderson load_arg_ref(s, loc->arg_slot, TCG_REG_CALL_STACK, 5595d78e4a4fSRichard Henderson arg_slot_stk_ofs(loc->ref_slot), 5596313bdea8SRichard Henderson &allocated_regs); 5597313bdea8SRichard Henderson break; 5598313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF_N: 5599313bdea8SRichard Henderson load_arg_stk(s, loc->ref_slot, ts, allocated_regs); 5600313bdea8SRichard Henderson break; 560139004a71SRichard Henderson default: 560239004a71SRichard Henderson g_assert_not_reached(); 560339004a71SRichard Henderson } 560439004a71SRichard Henderson } 560539004a71SRichard Henderson 560639004a71SRichard Henderson /* Mark dead temporaries and free the associated registers. */ 5607866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 5608866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) { 560943439139SRichard Henderson temp_dead(s, arg_temp(op->args[i])); 5610c896fe29Sbellard } 5611c896fe29Sbellard } 5612c896fe29Sbellard 561339004a71SRichard Henderson /* Clobber call registers. */ 5614c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) { 5615c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { 5616b3915dbbSRichard Henderson tcg_reg_free(s, i, allocated_regs); 5617c896fe29Sbellard } 5618c896fe29Sbellard } 5619c896fe29Sbellard 562039004a71SRichard Henderson /* 562139004a71SRichard Henderson * Save globals if they might be written by the helper, 562239004a71SRichard Henderson * sync them if they might be read. 562339004a71SRichard Henderson */ 562439004a71SRichard Henderson if (info->flags & TCG_CALL_NO_READ_GLOBALS) { 562578505279SAurelien Jarno /* Nothing to do */ 562639004a71SRichard Henderson } else if (info->flags & TCG_CALL_NO_WRITE_GLOBALS) { 562778505279SAurelien Jarno sync_globals(s, allocated_regs); 562878505279SAurelien Jarno } else { 5629e8996ee0Sbellard save_globals(s, allocated_regs); 5630b9c18f56Saurel32 } 5631c896fe29Sbellard 5632313bdea8SRichard Henderson /* 5633313bdea8SRichard Henderson * If the ABI passes a pointer to the returned struct as the first 5634313bdea8SRichard Henderson * argument, load that now. Pass a pointer to the output home slot. 5635313bdea8SRichard Henderson */ 5636313bdea8SRichard Henderson if (info->out_kind == TCG_CALL_RET_BY_REF) { 5637313bdea8SRichard Henderson TCGTemp *ts = arg_temp(op->args[0]); 5638313bdea8SRichard Henderson 5639313bdea8SRichard Henderson if (!ts->mem_allocated) { 5640313bdea8SRichard Henderson temp_allocate_frame(s, ts); 5641313bdea8SRichard Henderson } 5642313bdea8SRichard Henderson load_arg_ref(s, 0, ts->mem_base->reg, ts->mem_offset, &allocated_regs); 5643313bdea8SRichard Henderson } 5644313bdea8SRichard Henderson 5645cee44b03SRichard Henderson tcg_out_call(s, tcg_call_func(op), info); 5646c896fe29Sbellard 564739004a71SRichard Henderson /* Assign output registers and emit moves if needed. */ 564839004a71SRichard Henderson switch (info->out_kind) { 564939004a71SRichard Henderson case TCG_CALL_RET_NORMAL: 5650c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 565139004a71SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]); 56525e3d0c19SRichard Henderson TCGReg reg = tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, i); 5653d63e3b6eSRichard Henderson 5654d63e3b6eSRichard Henderson /* ENV should not be modified. */ 5655e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ts)); 5656d63e3b6eSRichard Henderson 5657098859f1SRichard Henderson set_temp_val_reg(s, ts, reg); 5658c896fe29Sbellard ts->mem_coherent = 0; 565939004a71SRichard Henderson } 566039004a71SRichard Henderson break; 5661313bdea8SRichard Henderson 5662c6556aa0SRichard Henderson case TCG_CALL_RET_BY_VEC: 5663c6556aa0SRichard Henderson { 5664c6556aa0SRichard Henderson TCGTemp *ts = arg_temp(op->args[0]); 5665c6556aa0SRichard Henderson 5666c6556aa0SRichard Henderson tcg_debug_assert(ts->base_type == TCG_TYPE_I128); 5667c6556aa0SRichard Henderson tcg_debug_assert(ts->temp_subindex == 0); 5668c6556aa0SRichard Henderson if (!ts->mem_allocated) { 5669c6556aa0SRichard Henderson temp_allocate_frame(s, ts); 5670c6556aa0SRichard Henderson } 5671c6556aa0SRichard Henderson tcg_out_st(s, TCG_TYPE_V128, 5672c6556aa0SRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0), 5673c6556aa0SRichard Henderson ts->mem_base->reg, ts->mem_offset); 5674c6556aa0SRichard Henderson } 5675c6556aa0SRichard Henderson /* fall through to mark all parts in memory */ 5676c6556aa0SRichard Henderson 5677313bdea8SRichard Henderson case TCG_CALL_RET_BY_REF: 5678313bdea8SRichard Henderson /* The callee has performed a write through the reference. */ 5679313bdea8SRichard Henderson for (i = 0; i < nb_oargs; i++) { 5680313bdea8SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]); 5681313bdea8SRichard Henderson ts->val_type = TEMP_VAL_MEM; 5682313bdea8SRichard Henderson } 5683313bdea8SRichard Henderson break; 5684313bdea8SRichard Henderson 568539004a71SRichard Henderson default: 568639004a71SRichard Henderson g_assert_not_reached(); 568739004a71SRichard Henderson } 568839004a71SRichard Henderson 568939004a71SRichard Henderson /* Flush or discard output registers as needed. */ 569039004a71SRichard Henderson for (i = 0; i < nb_oargs; i++) { 569139004a71SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]); 5692ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) { 569339004a71SRichard Henderson temp_sync(s, ts, s->reserved_regs, 0, IS_DEAD_ARG(i)); 569459d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) { 5695f8bf00f1SRichard Henderson temp_dead(s, ts); 5696c896fe29Sbellard } 5697c896fe29Sbellard } 56988c11ad25SAurelien Jarno } 5699c896fe29Sbellard 5700e63b8a29SRichard Henderson /** 5701e63b8a29SRichard Henderson * atom_and_align_for_opc: 5702e63b8a29SRichard Henderson * @s: tcg context 5703e63b8a29SRichard Henderson * @opc: memory operation code 5704e63b8a29SRichard Henderson * @host_atom: MO_ATOM_{IFALIGN,WITHIN16,SUBALIGN} for host operations 5705e63b8a29SRichard Henderson * @allow_two_ops: true if we are prepared to issue two operations 5706e63b8a29SRichard Henderson * 5707e63b8a29SRichard Henderson * Return the alignment and atomicity to use for the inline fast path 5708e63b8a29SRichard Henderson * for the given memory operation. The alignment may be larger than 5709e63b8a29SRichard Henderson * that specified in @opc, and the correct alignment will be diagnosed 5710e63b8a29SRichard Henderson * by the slow path helper. 5711e63b8a29SRichard Henderson * 5712e63b8a29SRichard Henderson * If @allow_two_ops, the host is prepared to test for 2x alignment, 5713e63b8a29SRichard Henderson * and issue two loads or stores for subalignment. 5714e63b8a29SRichard Henderson */ 5715e63b8a29SRichard Henderson static TCGAtomAlign atom_and_align_for_opc(TCGContext *s, MemOp opc, 5716e63b8a29SRichard Henderson MemOp host_atom, bool allow_two_ops) 5717e63b8a29SRichard Henderson { 5718c5809eeeSRichard Henderson MemOp align = memop_alignment_bits(opc); 5719e63b8a29SRichard Henderson MemOp size = opc & MO_SIZE; 5720e63b8a29SRichard Henderson MemOp half = size ? size - 1 : 0; 5721cbb14556SRichard Henderson MemOp atom = opc & MO_ATOM_MASK; 5722e63b8a29SRichard Henderson MemOp atmax; 5723e63b8a29SRichard Henderson 5724e63b8a29SRichard Henderson switch (atom) { 5725e63b8a29SRichard Henderson case MO_ATOM_NONE: 5726e63b8a29SRichard Henderson /* The operation requires no specific atomicity. */ 5727e63b8a29SRichard Henderson atmax = MO_8; 5728e63b8a29SRichard Henderson break; 5729e63b8a29SRichard Henderson 5730e63b8a29SRichard Henderson case MO_ATOM_IFALIGN: 5731e63b8a29SRichard Henderson atmax = size; 5732e63b8a29SRichard Henderson break; 5733e63b8a29SRichard Henderson 5734e63b8a29SRichard Henderson case MO_ATOM_IFALIGN_PAIR: 5735e63b8a29SRichard Henderson atmax = half; 5736e63b8a29SRichard Henderson break; 5737e63b8a29SRichard Henderson 5738e63b8a29SRichard Henderson case MO_ATOM_WITHIN16: 5739e63b8a29SRichard Henderson atmax = size; 5740e63b8a29SRichard Henderson if (size == MO_128) { 5741e63b8a29SRichard Henderson /* Misalignment implies !within16, and therefore no atomicity. */ 5742e63b8a29SRichard Henderson } else if (host_atom != MO_ATOM_WITHIN16) { 5743e63b8a29SRichard Henderson /* The host does not implement within16, so require alignment. */ 5744e63b8a29SRichard Henderson align = MAX(align, size); 5745e63b8a29SRichard Henderson } 5746e63b8a29SRichard Henderson break; 5747e63b8a29SRichard Henderson 5748e63b8a29SRichard Henderson case MO_ATOM_WITHIN16_PAIR: 5749e63b8a29SRichard Henderson atmax = size; 5750e63b8a29SRichard Henderson /* 5751e63b8a29SRichard Henderson * Misalignment implies !within16, and therefore half atomicity. 5752e63b8a29SRichard Henderson * Any host prepared for two operations can implement this with 5753e63b8a29SRichard Henderson * half alignment. 5754e63b8a29SRichard Henderson */ 5755e63b8a29SRichard Henderson if (host_atom != MO_ATOM_WITHIN16 && allow_two_ops) { 5756e63b8a29SRichard Henderson align = MAX(align, half); 5757e63b8a29SRichard Henderson } 5758e63b8a29SRichard Henderson break; 5759e63b8a29SRichard Henderson 5760e63b8a29SRichard Henderson case MO_ATOM_SUBALIGN: 5761e63b8a29SRichard Henderson atmax = size; 5762e63b8a29SRichard Henderson if (host_atom != MO_ATOM_SUBALIGN) { 5763e63b8a29SRichard Henderson /* If unaligned but not odd, there are subobjects up to half. */ 5764e63b8a29SRichard Henderson if (allow_two_ops) { 5765e63b8a29SRichard Henderson align = MAX(align, half); 5766e63b8a29SRichard Henderson } else { 5767e63b8a29SRichard Henderson align = MAX(align, size); 5768e63b8a29SRichard Henderson } 5769e63b8a29SRichard Henderson } 5770e63b8a29SRichard Henderson break; 5771e63b8a29SRichard Henderson 5772e63b8a29SRichard Henderson default: 5773e63b8a29SRichard Henderson g_assert_not_reached(); 5774e63b8a29SRichard Henderson } 5775e63b8a29SRichard Henderson 5776e63b8a29SRichard Henderson return (TCGAtomAlign){ .atom = atmax, .align = align }; 5777e63b8a29SRichard Henderson } 5778e63b8a29SRichard Henderson 57798429a1caSRichard Henderson /* 57808429a1caSRichard Henderson * Similarly for qemu_ld/st slow path helpers. 57818429a1caSRichard Henderson * We must re-implement tcg_gen_callN and tcg_reg_alloc_call simultaneously, 57828429a1caSRichard Henderson * using only the provided backend tcg_out_* functions. 57838429a1caSRichard Henderson */ 57848429a1caSRichard Henderson 57858429a1caSRichard Henderson static int tcg_out_helper_stk_ofs(TCGType type, unsigned slot) 57868429a1caSRichard Henderson { 57878429a1caSRichard Henderson int ofs = arg_slot_stk_ofs(slot); 57888429a1caSRichard Henderson 57898429a1caSRichard Henderson /* 57908429a1caSRichard Henderson * Each stack slot is TCG_TARGET_LONG_BITS. If the host does not 57918429a1caSRichard Henderson * require extension to uint64_t, adjust the address for uint32_t. 57928429a1caSRichard Henderson */ 57938429a1caSRichard Henderson if (HOST_BIG_ENDIAN && 57948429a1caSRichard Henderson TCG_TARGET_REG_BITS == 64 && 57958429a1caSRichard Henderson type == TCG_TYPE_I32) { 57968429a1caSRichard Henderson ofs += 4; 57978429a1caSRichard Henderson } 57988429a1caSRichard Henderson return ofs; 57998429a1caSRichard Henderson } 58008429a1caSRichard Henderson 58018d314041SRichard Henderson static void tcg_out_helper_load_slots(TCGContext *s, 58028429a1caSRichard Henderson unsigned nmov, TCGMovExtend *mov, 58032462e30eSRichard Henderson const TCGLdstHelperParam *parm) 58048429a1caSRichard Henderson { 58058d314041SRichard Henderson unsigned i; 58062462e30eSRichard Henderson TCGReg dst3; 58072462e30eSRichard Henderson 58088d314041SRichard Henderson /* 58098d314041SRichard Henderson * Start from the end, storing to the stack first. 58108d314041SRichard Henderson * This frees those registers, so we need not consider overlap. 58118d314041SRichard Henderson */ 58128d314041SRichard Henderson for (i = nmov; i-- > 0; ) { 58138d314041SRichard Henderson unsigned slot = mov[i].dst; 58148d314041SRichard Henderson 58158d314041SRichard Henderson if (arg_slot_reg_p(slot)) { 58168d314041SRichard Henderson goto found_reg; 58178d314041SRichard Henderson } 58188d314041SRichard Henderson 58198d314041SRichard Henderson TCGReg src = mov[i].src; 58208d314041SRichard Henderson TCGType dst_type = mov[i].dst_type; 58218d314041SRichard Henderson MemOp dst_mo = dst_type == TCG_TYPE_I32 ? MO_32 : MO_64; 58228d314041SRichard Henderson 58238d314041SRichard Henderson /* The argument is going onto the stack; extend into scratch. */ 58248d314041SRichard Henderson if ((mov[i].src_ext & MO_SIZE) != dst_mo) { 58258d314041SRichard Henderson tcg_debug_assert(parm->ntmp != 0); 58268d314041SRichard Henderson mov[i].dst = src = parm->tmp[0]; 58278d314041SRichard Henderson tcg_out_movext1(s, &mov[i]); 58288d314041SRichard Henderson } 58298d314041SRichard Henderson 58308d314041SRichard Henderson tcg_out_st(s, dst_type, src, TCG_REG_CALL_STACK, 58318d314041SRichard Henderson tcg_out_helper_stk_ofs(dst_type, slot)); 58328d314041SRichard Henderson } 58338d314041SRichard Henderson return; 58348d314041SRichard Henderson 58358d314041SRichard Henderson found_reg: 58368d314041SRichard Henderson /* 58378d314041SRichard Henderson * The remaining arguments are in registers. 58388d314041SRichard Henderson * Convert slot numbers to argument registers. 58398d314041SRichard Henderson */ 58408d314041SRichard Henderson nmov = i + 1; 58418d314041SRichard Henderson for (i = 0; i < nmov; ++i) { 58428d314041SRichard Henderson mov[i].dst = tcg_target_call_iarg_regs[mov[i].dst]; 58438d314041SRichard Henderson } 58448d314041SRichard Henderson 58458429a1caSRichard Henderson switch (nmov) { 58462462e30eSRichard Henderson case 4: 58478429a1caSRichard Henderson /* The backend must have provided enough temps for the worst case. */ 58482462e30eSRichard Henderson tcg_debug_assert(parm->ntmp >= 2); 58498429a1caSRichard Henderson 58502462e30eSRichard Henderson dst3 = mov[3].dst; 58512462e30eSRichard Henderson for (unsigned j = 0; j < 3; ++j) { 58522462e30eSRichard Henderson if (dst3 == mov[j].src) { 58538429a1caSRichard Henderson /* 58542462e30eSRichard Henderson * Conflict. Copy the source to a temporary, perform the 58552462e30eSRichard Henderson * remaining moves, then the extension from our scratch 58562462e30eSRichard Henderson * on the way out. 58578429a1caSRichard Henderson */ 58582462e30eSRichard Henderson TCGReg scratch = parm->tmp[1]; 58598429a1caSRichard Henderson 58602462e30eSRichard Henderson tcg_out_mov(s, mov[3].src_type, scratch, mov[3].src); 58612462e30eSRichard Henderson tcg_out_movext3(s, mov, mov + 1, mov + 2, parm->tmp[0]); 58622462e30eSRichard Henderson tcg_out_movext1_new_src(s, &mov[3], scratch); 58632462e30eSRichard Henderson break; 58648429a1caSRichard Henderson } 58658429a1caSRichard Henderson } 58668429a1caSRichard Henderson 58678429a1caSRichard Henderson /* No conflicts: perform this move and continue. */ 58682462e30eSRichard Henderson tcg_out_movext1(s, &mov[3]); 58692462e30eSRichard Henderson /* fall through */ 58708429a1caSRichard Henderson 58712462e30eSRichard Henderson case 3: 58722462e30eSRichard Henderson tcg_out_movext3(s, mov, mov + 1, mov + 2, 58732462e30eSRichard Henderson parm->ntmp ? parm->tmp[0] : -1); 58742462e30eSRichard Henderson break; 58758429a1caSRichard Henderson case 2: 58762462e30eSRichard Henderson tcg_out_movext2(s, mov, mov + 1, 58772462e30eSRichard Henderson parm->ntmp ? parm->tmp[0] : -1); 58782462e30eSRichard Henderson break; 58798429a1caSRichard Henderson case 1: 58808429a1caSRichard Henderson tcg_out_movext1(s, mov); 58812462e30eSRichard Henderson break; 58822462e30eSRichard Henderson default: 58838429a1caSRichard Henderson g_assert_not_reached(); 58848429a1caSRichard Henderson } 58858429a1caSRichard Henderson } 58868429a1caSRichard Henderson 58878429a1caSRichard Henderson static void tcg_out_helper_load_imm(TCGContext *s, unsigned slot, 58888429a1caSRichard Henderson TCGType type, tcg_target_long imm, 58898429a1caSRichard Henderson const TCGLdstHelperParam *parm) 58908429a1caSRichard Henderson { 58918429a1caSRichard Henderson if (arg_slot_reg_p(slot)) { 58928429a1caSRichard Henderson tcg_out_movi(s, type, tcg_target_call_iarg_regs[slot], imm); 58938429a1caSRichard Henderson } else { 58948429a1caSRichard Henderson int ofs = tcg_out_helper_stk_ofs(type, slot); 58958429a1caSRichard Henderson if (!tcg_out_sti(s, type, imm, TCG_REG_CALL_STACK, ofs)) { 58968429a1caSRichard Henderson tcg_debug_assert(parm->ntmp != 0); 58978429a1caSRichard Henderson tcg_out_movi(s, type, parm->tmp[0], imm); 58988429a1caSRichard Henderson tcg_out_st(s, type, parm->tmp[0], TCG_REG_CALL_STACK, ofs); 58998429a1caSRichard Henderson } 59008429a1caSRichard Henderson } 59018429a1caSRichard Henderson } 59028429a1caSRichard Henderson 59038429a1caSRichard Henderson static void tcg_out_helper_load_common_args(TCGContext *s, 59048429a1caSRichard Henderson const TCGLabelQemuLdst *ldst, 59058429a1caSRichard Henderson const TCGLdstHelperParam *parm, 59068429a1caSRichard Henderson const TCGHelperInfo *info, 59078429a1caSRichard Henderson unsigned next_arg) 59088429a1caSRichard Henderson { 59098429a1caSRichard Henderson TCGMovExtend ptr_mov = { 59108429a1caSRichard Henderson .dst_type = TCG_TYPE_PTR, 59118429a1caSRichard Henderson .src_type = TCG_TYPE_PTR, 59128429a1caSRichard Henderson .src_ext = sizeof(void *) == 4 ? MO_32 : MO_64 59138429a1caSRichard Henderson }; 59148429a1caSRichard Henderson const TCGCallArgumentLoc *loc = &info->in[0]; 59158429a1caSRichard Henderson TCGType type; 59168429a1caSRichard Henderson unsigned slot; 59178429a1caSRichard Henderson tcg_target_ulong imm; 59188429a1caSRichard Henderson 59198429a1caSRichard Henderson /* 59208429a1caSRichard Henderson * Handle env, which is always first. 59218429a1caSRichard Henderson */ 59228429a1caSRichard Henderson ptr_mov.dst = loc->arg_slot; 59238429a1caSRichard Henderson ptr_mov.src = TCG_AREG0; 59248429a1caSRichard Henderson tcg_out_helper_load_slots(s, 1, &ptr_mov, parm); 59258429a1caSRichard Henderson 59268429a1caSRichard Henderson /* 59278429a1caSRichard Henderson * Handle oi. 59288429a1caSRichard Henderson */ 59298429a1caSRichard Henderson imm = ldst->oi; 59308429a1caSRichard Henderson loc = &info->in[next_arg]; 59318429a1caSRichard Henderson type = TCG_TYPE_I32; 59328429a1caSRichard Henderson switch (loc->kind) { 59338429a1caSRichard Henderson case TCG_CALL_ARG_NORMAL: 59348429a1caSRichard Henderson break; 59358429a1caSRichard Henderson case TCG_CALL_ARG_EXTEND_U: 59368429a1caSRichard Henderson case TCG_CALL_ARG_EXTEND_S: 59378429a1caSRichard Henderson /* No extension required for MemOpIdx. */ 59388429a1caSRichard Henderson tcg_debug_assert(imm <= INT32_MAX); 59398429a1caSRichard Henderson type = TCG_TYPE_REG; 59408429a1caSRichard Henderson break; 59418429a1caSRichard Henderson default: 59428429a1caSRichard Henderson g_assert_not_reached(); 59438429a1caSRichard Henderson } 59448429a1caSRichard Henderson tcg_out_helper_load_imm(s, loc->arg_slot, type, imm, parm); 59458429a1caSRichard Henderson next_arg++; 59468429a1caSRichard Henderson 59478429a1caSRichard Henderson /* 59488429a1caSRichard Henderson * Handle ra. 59498429a1caSRichard Henderson */ 59508429a1caSRichard Henderson loc = &info->in[next_arg]; 59518429a1caSRichard Henderson slot = loc->arg_slot; 59528429a1caSRichard Henderson if (parm->ra_gen) { 59538429a1caSRichard Henderson int arg_reg = -1; 59548429a1caSRichard Henderson TCGReg ra_reg; 59558429a1caSRichard Henderson 59568429a1caSRichard Henderson if (arg_slot_reg_p(slot)) { 59578429a1caSRichard Henderson arg_reg = tcg_target_call_iarg_regs[slot]; 59588429a1caSRichard Henderson } 59598429a1caSRichard Henderson ra_reg = parm->ra_gen(s, ldst, arg_reg); 59608429a1caSRichard Henderson 59618429a1caSRichard Henderson ptr_mov.dst = slot; 59628429a1caSRichard Henderson ptr_mov.src = ra_reg; 59638429a1caSRichard Henderson tcg_out_helper_load_slots(s, 1, &ptr_mov, parm); 59648429a1caSRichard Henderson } else { 59658429a1caSRichard Henderson imm = (uintptr_t)ldst->raddr; 59668429a1caSRichard Henderson tcg_out_helper_load_imm(s, slot, TCG_TYPE_PTR, imm, parm); 59678429a1caSRichard Henderson } 59688429a1caSRichard Henderson } 59698429a1caSRichard Henderson 59708429a1caSRichard Henderson static unsigned tcg_out_helper_add_mov(TCGMovExtend *mov, 59718429a1caSRichard Henderson const TCGCallArgumentLoc *loc, 59728429a1caSRichard Henderson TCGType dst_type, TCGType src_type, 59738429a1caSRichard Henderson TCGReg lo, TCGReg hi) 59748429a1caSRichard Henderson { 5975ebebea53SRichard Henderson MemOp reg_mo; 5976ebebea53SRichard Henderson 59778429a1caSRichard Henderson if (dst_type <= TCG_TYPE_REG) { 59788429a1caSRichard Henderson MemOp src_ext; 59798429a1caSRichard Henderson 59808429a1caSRichard Henderson switch (loc->kind) { 59818429a1caSRichard Henderson case TCG_CALL_ARG_NORMAL: 59828429a1caSRichard Henderson src_ext = src_type == TCG_TYPE_I32 ? MO_32 : MO_64; 59838429a1caSRichard Henderson break; 59848429a1caSRichard Henderson case TCG_CALL_ARG_EXTEND_U: 59858429a1caSRichard Henderson dst_type = TCG_TYPE_REG; 59868429a1caSRichard Henderson src_ext = MO_UL; 59878429a1caSRichard Henderson break; 59888429a1caSRichard Henderson case TCG_CALL_ARG_EXTEND_S: 59898429a1caSRichard Henderson dst_type = TCG_TYPE_REG; 59908429a1caSRichard Henderson src_ext = MO_SL; 59918429a1caSRichard Henderson break; 59928429a1caSRichard Henderson default: 59938429a1caSRichard Henderson g_assert_not_reached(); 59948429a1caSRichard Henderson } 59958429a1caSRichard Henderson 59968429a1caSRichard Henderson mov[0].dst = loc->arg_slot; 59978429a1caSRichard Henderson mov[0].dst_type = dst_type; 59988429a1caSRichard Henderson mov[0].src = lo; 59998429a1caSRichard Henderson mov[0].src_type = src_type; 60008429a1caSRichard Henderson mov[0].src_ext = src_ext; 60018429a1caSRichard Henderson return 1; 60028429a1caSRichard Henderson } 60038429a1caSRichard Henderson 6004ebebea53SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 6005ebebea53SRichard Henderson assert(dst_type == TCG_TYPE_I64); 6006ebebea53SRichard Henderson reg_mo = MO_32; 6007ebebea53SRichard Henderson } else { 6008ebebea53SRichard Henderson assert(dst_type == TCG_TYPE_I128); 6009ebebea53SRichard Henderson reg_mo = MO_64; 6010ebebea53SRichard Henderson } 60118429a1caSRichard Henderson 60128429a1caSRichard Henderson mov[0].dst = loc[HOST_BIG_ENDIAN].arg_slot; 60138429a1caSRichard Henderson mov[0].src = lo; 6014ebebea53SRichard Henderson mov[0].dst_type = TCG_TYPE_REG; 6015ebebea53SRichard Henderson mov[0].src_type = TCG_TYPE_REG; 6016ebebea53SRichard Henderson mov[0].src_ext = reg_mo; 60178429a1caSRichard Henderson 60188429a1caSRichard Henderson mov[1].dst = loc[!HOST_BIG_ENDIAN].arg_slot; 60198429a1caSRichard Henderson mov[1].src = hi; 6020ebebea53SRichard Henderson mov[1].dst_type = TCG_TYPE_REG; 6021ebebea53SRichard Henderson mov[1].src_type = TCG_TYPE_REG; 6022ebebea53SRichard Henderson mov[1].src_ext = reg_mo; 60238429a1caSRichard Henderson 60248429a1caSRichard Henderson return 2; 60258429a1caSRichard Henderson } 60268429a1caSRichard Henderson 60278429a1caSRichard Henderson static void tcg_out_ld_helper_args(TCGContext *s, const TCGLabelQemuLdst *ldst, 60288429a1caSRichard Henderson const TCGLdstHelperParam *parm) 60298429a1caSRichard Henderson { 60308429a1caSRichard Henderson const TCGHelperInfo *info; 60318429a1caSRichard Henderson const TCGCallArgumentLoc *loc; 60328429a1caSRichard Henderson TCGMovExtend mov[2]; 60338429a1caSRichard Henderson unsigned next_arg, nmov; 60348429a1caSRichard Henderson MemOp mop = get_memop(ldst->oi); 60358429a1caSRichard Henderson 60368429a1caSRichard Henderson switch (mop & MO_SIZE) { 60378429a1caSRichard Henderson case MO_8: 60388429a1caSRichard Henderson case MO_16: 60398429a1caSRichard Henderson case MO_32: 60408429a1caSRichard Henderson info = &info_helper_ld32_mmu; 60418429a1caSRichard Henderson break; 60428429a1caSRichard Henderson case MO_64: 60438429a1caSRichard Henderson info = &info_helper_ld64_mmu; 60448429a1caSRichard Henderson break; 6045ebebea53SRichard Henderson case MO_128: 6046ebebea53SRichard Henderson info = &info_helper_ld128_mmu; 6047ebebea53SRichard Henderson break; 60488429a1caSRichard Henderson default: 60498429a1caSRichard Henderson g_assert_not_reached(); 60508429a1caSRichard Henderson } 60518429a1caSRichard Henderson 60528429a1caSRichard Henderson /* Defer env argument. */ 60538429a1caSRichard Henderson next_arg = 1; 60548429a1caSRichard Henderson 60558429a1caSRichard Henderson loc = &info->in[next_arg]; 6056c31e5fa4SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && s->addr_type == TCG_TYPE_I32) { 605724e46e6cSRichard Henderson /* 605824e46e6cSRichard Henderson * 32-bit host with 32-bit guest: zero-extend the guest address 605924e46e6cSRichard Henderson * to 64-bits for the helper by storing the low part, then 606024e46e6cSRichard Henderson * load a zero for the high part. 606124e46e6cSRichard Henderson */ 606224e46e6cSRichard Henderson tcg_out_helper_add_mov(mov, loc + HOST_BIG_ENDIAN, 606324e46e6cSRichard Henderson TCG_TYPE_I32, TCG_TYPE_I32, 606424e46e6cSRichard Henderson ldst->addrlo_reg, -1); 606524e46e6cSRichard Henderson tcg_out_helper_load_slots(s, 1, mov, parm); 606624e46e6cSRichard Henderson 606724e46e6cSRichard Henderson tcg_out_helper_load_imm(s, loc[!HOST_BIG_ENDIAN].arg_slot, 606824e46e6cSRichard Henderson TCG_TYPE_I32, 0, parm); 606924e46e6cSRichard Henderson next_arg += 2; 6070c31e5fa4SRichard Henderson } else { 6071c31e5fa4SRichard Henderson nmov = tcg_out_helper_add_mov(mov, loc, TCG_TYPE_I64, s->addr_type, 6072c31e5fa4SRichard Henderson ldst->addrlo_reg, ldst->addrhi_reg); 6073c31e5fa4SRichard Henderson tcg_out_helper_load_slots(s, nmov, mov, parm); 6074c31e5fa4SRichard Henderson next_arg += nmov; 607524e46e6cSRichard Henderson } 60768429a1caSRichard Henderson 6077ebebea53SRichard Henderson switch (info->out_kind) { 6078ebebea53SRichard Henderson case TCG_CALL_RET_NORMAL: 6079ebebea53SRichard Henderson case TCG_CALL_RET_BY_VEC: 6080ebebea53SRichard Henderson break; 6081ebebea53SRichard Henderson case TCG_CALL_RET_BY_REF: 6082ebebea53SRichard Henderson /* 6083ebebea53SRichard Henderson * The return reference is in the first argument slot. 6084ebebea53SRichard Henderson * We need memory in which to return: re-use the top of stack. 6085ebebea53SRichard Henderson */ 6086ebebea53SRichard Henderson { 6087ebebea53SRichard Henderson int ofs_slot0 = TCG_TARGET_CALL_STACK_OFFSET; 6088ebebea53SRichard Henderson 6089ebebea53SRichard Henderson if (arg_slot_reg_p(0)) { 6090ebebea53SRichard Henderson tcg_out_addi_ptr(s, tcg_target_call_iarg_regs[0], 6091ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0); 6092ebebea53SRichard Henderson } else { 6093ebebea53SRichard Henderson tcg_debug_assert(parm->ntmp != 0); 6094ebebea53SRichard Henderson tcg_out_addi_ptr(s, parm->tmp[0], 6095ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0); 6096ebebea53SRichard Henderson tcg_out_st(s, TCG_TYPE_PTR, parm->tmp[0], 6097ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0); 6098ebebea53SRichard Henderson } 6099ebebea53SRichard Henderson } 6100ebebea53SRichard Henderson break; 6101ebebea53SRichard Henderson default: 6102ebebea53SRichard Henderson g_assert_not_reached(); 6103ebebea53SRichard Henderson } 61048429a1caSRichard Henderson 61058429a1caSRichard Henderson tcg_out_helper_load_common_args(s, ldst, parm, info, next_arg); 61068429a1caSRichard Henderson } 61078429a1caSRichard Henderson 61088429a1caSRichard Henderson static void tcg_out_ld_helper_ret(TCGContext *s, const TCGLabelQemuLdst *ldst, 61098429a1caSRichard Henderson bool load_sign, 61108429a1caSRichard Henderson const TCGLdstHelperParam *parm) 61118429a1caSRichard Henderson { 61128429a1caSRichard Henderson MemOp mop = get_memop(ldst->oi); 6113ebebea53SRichard Henderson TCGMovExtend mov[2]; 6114ebebea53SRichard Henderson int ofs_slot0; 61158429a1caSRichard Henderson 6116ebebea53SRichard Henderson switch (ldst->type) { 6117ebebea53SRichard Henderson case TCG_TYPE_I64: 6118ebebea53SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 6119ebebea53SRichard Henderson break; 6120ebebea53SRichard Henderson } 6121ebebea53SRichard Henderson /* fall through */ 6122ebebea53SRichard Henderson 6123ebebea53SRichard Henderson case TCG_TYPE_I32: 61248429a1caSRichard Henderson mov[0].dst = ldst->datalo_reg; 61258429a1caSRichard Henderson mov[0].src = tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, 0); 61268429a1caSRichard Henderson mov[0].dst_type = ldst->type; 61278429a1caSRichard Henderson mov[0].src_type = TCG_TYPE_REG; 61288429a1caSRichard Henderson 61298429a1caSRichard Henderson /* 61308429a1caSRichard Henderson * If load_sign, then we allowed the helper to perform the 61318429a1caSRichard Henderson * appropriate sign extension to tcg_target_ulong, and all 61328429a1caSRichard Henderson * we need now is a plain move. 61338429a1caSRichard Henderson * 61348429a1caSRichard Henderson * If they do not, then we expect the relevant extension 61358429a1caSRichard Henderson * instruction to be no more expensive than a move, and 61368429a1caSRichard Henderson * we thus save the icache etc by only using one of two 61378429a1caSRichard Henderson * helper functions. 61388429a1caSRichard Henderson */ 61398429a1caSRichard Henderson if (load_sign || !(mop & MO_SIGN)) { 61408429a1caSRichard Henderson if (TCG_TARGET_REG_BITS == 32 || ldst->type == TCG_TYPE_I32) { 61418429a1caSRichard Henderson mov[0].src_ext = MO_32; 61428429a1caSRichard Henderson } else { 61438429a1caSRichard Henderson mov[0].src_ext = MO_64; 61448429a1caSRichard Henderson } 61458429a1caSRichard Henderson } else { 61468429a1caSRichard Henderson mov[0].src_ext = mop & MO_SSIZE; 61478429a1caSRichard Henderson } 61488429a1caSRichard Henderson tcg_out_movext1(s, mov); 6149ebebea53SRichard Henderson return; 6150ebebea53SRichard Henderson 6151ebebea53SRichard Henderson case TCG_TYPE_I128: 6152ebebea53SRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 64); 6153ebebea53SRichard Henderson ofs_slot0 = TCG_TARGET_CALL_STACK_OFFSET; 6154ebebea53SRichard Henderson switch (TCG_TARGET_CALL_RET_I128) { 6155ebebea53SRichard Henderson case TCG_CALL_RET_NORMAL: 6156ebebea53SRichard Henderson break; 6157ebebea53SRichard Henderson case TCG_CALL_RET_BY_VEC: 6158ebebea53SRichard Henderson tcg_out_st(s, TCG_TYPE_V128, 6159ebebea53SRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0), 6160ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0); 6161ebebea53SRichard Henderson /* fall through */ 6162ebebea53SRichard Henderson case TCG_CALL_RET_BY_REF: 6163ebebea53SRichard Henderson tcg_out_ld(s, TCG_TYPE_I64, ldst->datalo_reg, 6164ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0 + 8 * HOST_BIG_ENDIAN); 6165ebebea53SRichard Henderson tcg_out_ld(s, TCG_TYPE_I64, ldst->datahi_reg, 6166ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0 + 8 * !HOST_BIG_ENDIAN); 6167ebebea53SRichard Henderson return; 6168ebebea53SRichard Henderson default: 6169ebebea53SRichard Henderson g_assert_not_reached(); 6170ebebea53SRichard Henderson } 6171ebebea53SRichard Henderson break; 6172ebebea53SRichard Henderson 6173ebebea53SRichard Henderson default: 6174ebebea53SRichard Henderson g_assert_not_reached(); 6175ebebea53SRichard Henderson } 61768429a1caSRichard Henderson 61778429a1caSRichard Henderson mov[0].dst = ldst->datalo_reg; 61788429a1caSRichard Henderson mov[0].src = 61798429a1caSRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, HOST_BIG_ENDIAN); 6180723d3a27SRichard Henderson mov[0].dst_type = TCG_TYPE_REG; 6181723d3a27SRichard Henderson mov[0].src_type = TCG_TYPE_REG; 6182ebebea53SRichard Henderson mov[0].src_ext = TCG_TARGET_REG_BITS == 32 ? MO_32 : MO_64; 61838429a1caSRichard Henderson 61848429a1caSRichard Henderson mov[1].dst = ldst->datahi_reg; 61858429a1caSRichard Henderson mov[1].src = 61868429a1caSRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, !HOST_BIG_ENDIAN); 61878429a1caSRichard Henderson mov[1].dst_type = TCG_TYPE_REG; 61888429a1caSRichard Henderson mov[1].src_type = TCG_TYPE_REG; 6189ebebea53SRichard Henderson mov[1].src_ext = TCG_TARGET_REG_BITS == 32 ? MO_32 : MO_64; 61908429a1caSRichard Henderson 61918429a1caSRichard Henderson tcg_out_movext2(s, mov, mov + 1, parm->ntmp ? parm->tmp[0] : -1); 61928429a1caSRichard Henderson } 61938429a1caSRichard Henderson 61948429a1caSRichard Henderson static void tcg_out_st_helper_args(TCGContext *s, const TCGLabelQemuLdst *ldst, 61958429a1caSRichard Henderson const TCGLdstHelperParam *parm) 61968429a1caSRichard Henderson { 61978429a1caSRichard Henderson const TCGHelperInfo *info; 61988429a1caSRichard Henderson const TCGCallArgumentLoc *loc; 61998429a1caSRichard Henderson TCGMovExtend mov[4]; 62008429a1caSRichard Henderson TCGType data_type; 62018429a1caSRichard Henderson unsigned next_arg, nmov, n; 62028429a1caSRichard Henderson MemOp mop = get_memop(ldst->oi); 62038429a1caSRichard Henderson 62048429a1caSRichard Henderson switch (mop & MO_SIZE) { 62058429a1caSRichard Henderson case MO_8: 62068429a1caSRichard Henderson case MO_16: 62078429a1caSRichard Henderson case MO_32: 62088429a1caSRichard Henderson info = &info_helper_st32_mmu; 62098429a1caSRichard Henderson data_type = TCG_TYPE_I32; 62108429a1caSRichard Henderson break; 62118429a1caSRichard Henderson case MO_64: 62128429a1caSRichard Henderson info = &info_helper_st64_mmu; 62138429a1caSRichard Henderson data_type = TCG_TYPE_I64; 62148429a1caSRichard Henderson break; 6215ebebea53SRichard Henderson case MO_128: 6216ebebea53SRichard Henderson info = &info_helper_st128_mmu; 6217ebebea53SRichard Henderson data_type = TCG_TYPE_I128; 6218ebebea53SRichard Henderson break; 62198429a1caSRichard Henderson default: 62208429a1caSRichard Henderson g_assert_not_reached(); 62218429a1caSRichard Henderson } 62228429a1caSRichard Henderson 62238429a1caSRichard Henderson /* Defer env argument. */ 62248429a1caSRichard Henderson next_arg = 1; 62258429a1caSRichard Henderson nmov = 0; 62268429a1caSRichard Henderson 62278429a1caSRichard Henderson /* Handle addr argument. */ 62288429a1caSRichard Henderson loc = &info->in[next_arg]; 6229c31e5fa4SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && s->addr_type == TCG_TYPE_I32) { 623024e46e6cSRichard Henderson /* 623124e46e6cSRichard Henderson * 32-bit host with 32-bit guest: zero-extend the guest address 623224e46e6cSRichard Henderson * to 64-bits for the helper by storing the low part. Later, 623324e46e6cSRichard Henderson * after we have processed the register inputs, we will load a 623424e46e6cSRichard Henderson * zero for the high part. 623524e46e6cSRichard Henderson */ 623624e46e6cSRichard Henderson tcg_out_helper_add_mov(mov, loc + HOST_BIG_ENDIAN, 623724e46e6cSRichard Henderson TCG_TYPE_I32, TCG_TYPE_I32, 623824e46e6cSRichard Henderson ldst->addrlo_reg, -1); 623924e46e6cSRichard Henderson next_arg += 2; 624024e46e6cSRichard Henderson nmov += 1; 6241c31e5fa4SRichard Henderson } else { 6242c31e5fa4SRichard Henderson n = tcg_out_helper_add_mov(mov, loc, TCG_TYPE_I64, s->addr_type, 6243c31e5fa4SRichard Henderson ldst->addrlo_reg, ldst->addrhi_reg); 6244c31e5fa4SRichard Henderson next_arg += n; 6245c31e5fa4SRichard Henderson nmov += n; 624624e46e6cSRichard Henderson } 62478429a1caSRichard Henderson 62488429a1caSRichard Henderson /* Handle data argument. */ 62498429a1caSRichard Henderson loc = &info->in[next_arg]; 6250ebebea53SRichard Henderson switch (loc->kind) { 6251ebebea53SRichard Henderson case TCG_CALL_ARG_NORMAL: 6252ebebea53SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 6253ebebea53SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 62548429a1caSRichard Henderson n = tcg_out_helper_add_mov(mov + nmov, loc, data_type, ldst->type, 62558429a1caSRichard Henderson ldst->datalo_reg, ldst->datahi_reg); 62568429a1caSRichard Henderson next_arg += n; 62578429a1caSRichard Henderson nmov += n; 6258ebebea53SRichard Henderson tcg_out_helper_load_slots(s, nmov, mov, parm); 6259ebebea53SRichard Henderson break; 6260ebebea53SRichard Henderson 6261ebebea53SRichard Henderson case TCG_CALL_ARG_BY_REF: 6262ebebea53SRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 64); 6263ebebea53SRichard Henderson tcg_debug_assert(data_type == TCG_TYPE_I128); 6264ebebea53SRichard Henderson tcg_out_st(s, TCG_TYPE_I64, 6265ebebea53SRichard Henderson HOST_BIG_ENDIAN ? ldst->datahi_reg : ldst->datalo_reg, 6266ebebea53SRichard Henderson TCG_REG_CALL_STACK, arg_slot_stk_ofs(loc[0].ref_slot)); 6267ebebea53SRichard Henderson tcg_out_st(s, TCG_TYPE_I64, 6268ebebea53SRichard Henderson HOST_BIG_ENDIAN ? ldst->datalo_reg : ldst->datahi_reg, 6269ebebea53SRichard Henderson TCG_REG_CALL_STACK, arg_slot_stk_ofs(loc[1].ref_slot)); 62708429a1caSRichard Henderson 62718429a1caSRichard Henderson tcg_out_helper_load_slots(s, nmov, mov, parm); 6272ebebea53SRichard Henderson 6273ebebea53SRichard Henderson if (arg_slot_reg_p(loc->arg_slot)) { 6274ebebea53SRichard Henderson tcg_out_addi_ptr(s, tcg_target_call_iarg_regs[loc->arg_slot], 6275ebebea53SRichard Henderson TCG_REG_CALL_STACK, 6276ebebea53SRichard Henderson arg_slot_stk_ofs(loc->ref_slot)); 6277ebebea53SRichard Henderson } else { 6278ebebea53SRichard Henderson tcg_debug_assert(parm->ntmp != 0); 6279ebebea53SRichard Henderson tcg_out_addi_ptr(s, parm->tmp[0], TCG_REG_CALL_STACK, 6280ebebea53SRichard Henderson arg_slot_stk_ofs(loc->ref_slot)); 6281ebebea53SRichard Henderson tcg_out_st(s, TCG_TYPE_PTR, parm->tmp[0], 6282ebebea53SRichard Henderson TCG_REG_CALL_STACK, arg_slot_stk_ofs(loc->arg_slot)); 6283ebebea53SRichard Henderson } 6284ebebea53SRichard Henderson next_arg += 2; 6285ebebea53SRichard Henderson break; 6286ebebea53SRichard Henderson 6287ebebea53SRichard Henderson default: 6288ebebea53SRichard Henderson g_assert_not_reached(); 6289ebebea53SRichard Henderson } 6290ebebea53SRichard Henderson 6291c31e5fa4SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && s->addr_type == TCG_TYPE_I32) { 6292c31e5fa4SRichard Henderson /* Zero extend the address by loading a zero for the high part. */ 629324e46e6cSRichard Henderson loc = &info->in[1 + !HOST_BIG_ENDIAN]; 629424e46e6cSRichard Henderson tcg_out_helper_load_imm(s, loc->arg_slot, TCG_TYPE_I32, 0, parm); 629524e46e6cSRichard Henderson } 629624e46e6cSRichard Henderson 62978429a1caSRichard Henderson tcg_out_helper_load_common_args(s, ldst, parm, info, next_arg); 62988429a1caSRichard Henderson } 62998429a1caSRichard Henderson 630076cef4b2SRichard Henderson int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start) 6301c896fe29Sbellard { 6302747bd69dSRichard Henderson int i, start_words, num_insns; 630315fa08f8SRichard Henderson TCGOp *op; 6304c896fe29Sbellard 6305d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP) 6306fbf59aadSRichard Henderson && qemu_log_in_addr_range(pc_start))) { 6307c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock(); 630878b54858SRichard Henderson if (logfile) { 630978b54858SRichard Henderson fprintf(logfile, "OP:\n"); 6310b7a83ff8SRichard Henderson tcg_dump_ops(s, logfile, false); 631178b54858SRichard Henderson fprintf(logfile, "\n"); 6312fc59d2d8SRobert Foley qemu_log_unlock(logfile); 6313c896fe29Sbellard } 631478b54858SRichard Henderson } 6315c896fe29Sbellard 6316bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG 6317bef16ab4SRichard Henderson /* Ensure all labels referenced have been emitted. */ 6318bef16ab4SRichard Henderson { 6319bef16ab4SRichard Henderson TCGLabel *l; 6320bef16ab4SRichard Henderson bool error = false; 6321bef16ab4SRichard Henderson 6322bef16ab4SRichard Henderson QSIMPLEQ_FOREACH(l, &s->labels, next) { 6323f85b1fc4SRichard Henderson if (unlikely(!l->present) && !QSIMPLEQ_EMPTY(&l->branches)) { 6324bef16ab4SRichard Henderson qemu_log_mask(CPU_LOG_TB_OP, 6325bef16ab4SRichard Henderson "$L%d referenced but not present.\n", l->id); 6326bef16ab4SRichard Henderson error = true; 6327bef16ab4SRichard Henderson } 6328bef16ab4SRichard Henderson } 6329bef16ab4SRichard Henderson assert(!error); 6330bef16ab4SRichard Henderson } 6331bef16ab4SRichard Henderson #endif 6332bef16ab4SRichard Henderson 633304e006abSRichard Henderson /* Do not reuse any EBB that may be allocated within the TB. */ 633404e006abSRichard Henderson tcg_temp_ebb_reset_freed(s); 633504e006abSRichard Henderson 6336c45cb8bbSRichard Henderson tcg_optimize(s); 63378f2e8c07SKirill Batuzov 6338b4fc67c7SRichard Henderson reachable_code_pass(s); 6339874b8574SRichard Henderson liveness_pass_0(s); 6340b83eabeaSRichard Henderson liveness_pass_1(s); 63415a18407fSRichard Henderson 63425a18407fSRichard Henderson if (s->nb_indirects > 0) { 63435a18407fSRichard Henderson if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND) 6344fbf59aadSRichard Henderson && qemu_log_in_addr_range(pc_start))) { 6345c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock(); 634678b54858SRichard Henderson if (logfile) { 634778b54858SRichard Henderson fprintf(logfile, "OP before indirect lowering:\n"); 6348b7a83ff8SRichard Henderson tcg_dump_ops(s, logfile, false); 634978b54858SRichard Henderson fprintf(logfile, "\n"); 6350fc59d2d8SRobert Foley qemu_log_unlock(logfile); 63515a18407fSRichard Henderson } 635278b54858SRichard Henderson } 6353645e3a81SRichard Henderson 63545a18407fSRichard Henderson /* Replace indirect temps with direct temps. */ 6355b83eabeaSRichard Henderson if (liveness_pass_2(s)) { 63565a18407fSRichard Henderson /* If changes were made, re-run liveness. */ 6357b83eabeaSRichard Henderson liveness_pass_1(s); 63585a18407fSRichard Henderson } 63595a18407fSRichard Henderson } 6360c5cc28ffSAurelien Jarno 6361d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT) 6362fbf59aadSRichard Henderson && qemu_log_in_addr_range(pc_start))) { 6363c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock(); 636478b54858SRichard Henderson if (logfile) { 636578b54858SRichard Henderson fprintf(logfile, "OP after optimization and liveness analysis:\n"); 6366b7a83ff8SRichard Henderson tcg_dump_ops(s, logfile, true); 636778b54858SRichard Henderson fprintf(logfile, "\n"); 6368fc59d2d8SRobert Foley qemu_log_unlock(logfile); 6369c896fe29Sbellard } 637078b54858SRichard Henderson } 6371c896fe29Sbellard 637235abb009SRichard Henderson /* Initialize goto_tb jump offsets. */ 63733a50f424SRichard Henderson tb->jmp_reset_offset[0] = TB_JMP_OFFSET_INVALID; 63743a50f424SRichard Henderson tb->jmp_reset_offset[1] = TB_JMP_OFFSET_INVALID; 63759da6079bSRichard Henderson tb->jmp_insn_offset[0] = TB_JMP_OFFSET_INVALID; 63769da6079bSRichard Henderson tb->jmp_insn_offset[1] = TB_JMP_OFFSET_INVALID; 637735abb009SRichard Henderson 6378c896fe29Sbellard tcg_reg_alloc_start(s); 6379c896fe29Sbellard 6380db0c51a3SRichard Henderson /* 6381db0c51a3SRichard Henderson * Reset the buffer pointers when restarting after overflow. 6382db0c51a3SRichard Henderson * TODO: Move this into translate-all.c with the rest of the 6383db0c51a3SRichard Henderson * buffer management. Having only this done here is confusing. 6384db0c51a3SRichard Henderson */ 6385db0c51a3SRichard Henderson s->code_buf = tcg_splitwx_to_rw(tb->tc.ptr); 6386db0c51a3SRichard Henderson s->code_ptr = s->code_buf; 6387a7cfd751SRichard Henderson s->data_gen_ptr = NULL; 6388c896fe29Sbellard 63896001f772SLaurent Vivier QSIMPLEQ_INIT(&s->ldst_labels); 639057a26946SRichard Henderson s->pool_labels = NULL; 63919ecefc84SRichard Henderson 6392747bd69dSRichard Henderson start_words = s->insn_start_words; 6393747bd69dSRichard Henderson s->gen_insn_data = 6394747bd69dSRichard Henderson tcg_malloc(sizeof(uint64_t) * s->gen_tb->icount * start_words); 6395747bd69dSRichard Henderson 63969358fbbfSRichard Henderson tcg_out_tb_start(s); 63979358fbbfSRichard Henderson 6398fca8a500SRichard Henderson num_insns = -1; 639915fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 6400c45cb8bbSRichard Henderson TCGOpcode opc = op->opc; 6401b3db8758Sblueswir1 6402c896fe29Sbellard switch (opc) { 6403c896fe29Sbellard case INDEX_op_mov_i32: 6404c896fe29Sbellard case INDEX_op_mov_i64: 6405d2fd745fSRichard Henderson case INDEX_op_mov_vec: 6406dd186292SRichard Henderson tcg_reg_alloc_mov(s, op); 6407c896fe29Sbellard break; 6408bab1671fSRichard Henderson case INDEX_op_dup_vec: 6409bab1671fSRichard Henderson tcg_reg_alloc_dup(s, op); 6410bab1671fSRichard Henderson break; 6411765b842aSRichard Henderson case INDEX_op_insn_start: 6412fca8a500SRichard Henderson if (num_insns >= 0) { 64139f754620SRichard Henderson size_t off = tcg_current_code_size(s); 64149f754620SRichard Henderson s->gen_insn_end_off[num_insns] = off; 64159f754620SRichard Henderson /* Assert that we do not overflow our stored offset. */ 64169f754620SRichard Henderson assert(s->gen_insn_end_off[num_insns] == off); 6417fca8a500SRichard Henderson } 6418fca8a500SRichard Henderson num_insns++; 6419747bd69dSRichard Henderson for (i = 0; i < start_words; ++i) { 6420747bd69dSRichard Henderson s->gen_insn_data[num_insns * start_words + i] = 6421c9ad8d27SRichard Henderson tcg_get_insn_start_param(op, i); 6422bad729e2SRichard Henderson } 6423c896fe29Sbellard break; 64245ff9d6a4Sbellard case INDEX_op_discard: 642543439139SRichard Henderson temp_dead(s, arg_temp(op->args[0])); 64265ff9d6a4Sbellard break; 6427c896fe29Sbellard case INDEX_op_set_label: 6428e8996ee0Sbellard tcg_reg_alloc_bb_end(s, s->reserved_regs); 642992ab8e7dSRichard Henderson tcg_out_label(s, arg_label(op->args[0])); 6430c896fe29Sbellard break; 6431c896fe29Sbellard case INDEX_op_call: 6432dd186292SRichard Henderson tcg_reg_alloc_call(s, op); 6433c45cb8bbSRichard Henderson break; 6434b55a8d9dSRichard Henderson case INDEX_op_exit_tb: 6435b55a8d9dSRichard Henderson tcg_out_exit_tb(s, op->args[0]); 6436b55a8d9dSRichard Henderson break; 6437cf7d6b8eSRichard Henderson case INDEX_op_goto_tb: 6438cf7d6b8eSRichard Henderson tcg_out_goto_tb(s, op->args[0]); 6439cf7d6b8eSRichard Henderson break; 6440efe86b21SRichard Henderson case INDEX_op_dup2_vec: 6441efe86b21SRichard Henderson if (tcg_reg_alloc_dup2(s, op)) { 6442efe86b21SRichard Henderson break; 6443efe86b21SRichard Henderson } 6444efe86b21SRichard Henderson /* fall through */ 6445c896fe29Sbellard default: 644625c4d9ccSRichard Henderson /* Sanity check that we've not introduced any unhandled opcodes. */ 6447771a5925SRichard Henderson tcg_debug_assert(tcg_op_supported(opc, TCGOP_TYPE(op), 6448771a5925SRichard Henderson TCGOP_FLAGS(op))); 6449c896fe29Sbellard /* Note: in order to speed up the code, it would be much 6450c896fe29Sbellard faster to have specialized register allocator functions for 6451c896fe29Sbellard some common argument patterns */ 6452dd186292SRichard Henderson tcg_reg_alloc_op(s, op); 6453c896fe29Sbellard break; 6454c896fe29Sbellard } 6455b125f9dcSRichard Henderson /* Test for (pending) buffer overflow. The assumption is that any 6456b125f9dcSRichard Henderson one operation beginning below the high water mark cannot overrun 6457b125f9dcSRichard Henderson the buffer completely. Thus we can test for overflow after 6458b125f9dcSRichard Henderson generating code without having to check during generation. */ 6459644da9b3SJohn Clarke if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) { 6460b125f9dcSRichard Henderson return -1; 6461b125f9dcSRichard Henderson } 64626e6c4efeSRichard Henderson /* Test for TB overflow, as seen by gen_insn_end_off. */ 64636e6c4efeSRichard Henderson if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) { 64646e6c4efeSRichard Henderson return -2; 64656e6c4efeSRichard Henderson } 6466c896fe29Sbellard } 6467747bd69dSRichard Henderson tcg_debug_assert(num_insns + 1 == s->gen_tb->icount); 6468fca8a500SRichard Henderson s->gen_insn_end_off[num_insns] = tcg_current_code_size(s); 6469c45cb8bbSRichard Henderson 6470b76f0d8cSYeongkyoon Lee /* Generate TB finalization at the end of block */ 6471aeee05f5SRichard Henderson i = tcg_out_ldst_finalize(s); 6472aeee05f5SRichard Henderson if (i < 0) { 6473aeee05f5SRichard Henderson return i; 647423dceda6SRichard Henderson } 64751768987bSRichard Henderson i = tcg_out_pool_finalize(s); 64761768987bSRichard Henderson if (i < 0) { 64771768987bSRichard Henderson return i; 647857a26946SRichard Henderson } 64797ecd02a0SRichard Henderson if (!tcg_resolve_relocs(s)) { 64807ecd02a0SRichard Henderson return -2; 64817ecd02a0SRichard Henderson } 6482c896fe29Sbellard 6483df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 6484c896fe29Sbellard /* flush instruction cache */ 6485db0c51a3SRichard Henderson flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf), 6486db0c51a3SRichard Henderson (uintptr_t)s->code_buf, 64871da8de39SRichard Henderson tcg_ptr_byte_diff(s->code_ptr, s->code_buf)); 6488df5d2b16SRichard Henderson #endif 64892aeabc08SStefan Weil 64901813e175SRichard Henderson return tcg_current_code_size(s); 6491c896fe29Sbellard } 6492c896fe29Sbellard 6493813da627SRichard Henderson #ifdef ELF_HOST_MACHINE 64945872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things: 64955872bbf2SRichard Henderson 64965872bbf2SRichard Henderson (1) Define ELF_HOST_MACHINE to indicate both what value to 64975872bbf2SRichard Henderson put into the ELF image and to indicate support for the feature. 64985872bbf2SRichard Henderson 64995872bbf2SRichard Henderson (2) Define tcg_register_jit. This should create a buffer containing 65005872bbf2SRichard Henderson the contents of a .debug_frame section that describes the post- 65015872bbf2SRichard Henderson prologue unwind info for the tcg machine. 65025872bbf2SRichard Henderson 65035872bbf2SRichard Henderson (3) Call tcg_register_jit_int, with the constructed .debug_frame. 65045872bbf2SRichard Henderson */ 6505813da627SRichard Henderson 6506813da627SRichard Henderson /* Begin GDB interface. THE FOLLOWING MUST MATCH GDB DOCS. */ 6507813da627SRichard Henderson typedef enum { 6508813da627SRichard Henderson JIT_NOACTION = 0, 6509813da627SRichard Henderson JIT_REGISTER_FN, 6510813da627SRichard Henderson JIT_UNREGISTER_FN 6511813da627SRichard Henderson } jit_actions_t; 6512813da627SRichard Henderson 6513813da627SRichard Henderson struct jit_code_entry { 6514813da627SRichard Henderson struct jit_code_entry *next_entry; 6515813da627SRichard Henderson struct jit_code_entry *prev_entry; 6516813da627SRichard Henderson const void *symfile_addr; 6517813da627SRichard Henderson uint64_t symfile_size; 6518813da627SRichard Henderson }; 6519813da627SRichard Henderson 6520813da627SRichard Henderson struct jit_descriptor { 6521813da627SRichard Henderson uint32_t version; 6522813da627SRichard Henderson uint32_t action_flag; 6523813da627SRichard Henderson struct jit_code_entry *relevant_entry; 6524813da627SRichard Henderson struct jit_code_entry *first_entry; 6525813da627SRichard Henderson }; 6526813da627SRichard Henderson 6527813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline)); 6528813da627SRichard Henderson void __jit_debug_register_code(void) 6529813da627SRichard Henderson { 6530813da627SRichard Henderson asm(""); 6531813da627SRichard Henderson } 6532813da627SRichard Henderson 6533813da627SRichard Henderson /* Must statically initialize the version, because GDB may check 6534813da627SRichard Henderson the version before we can set it. */ 6535813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 }; 6536813da627SRichard Henderson 6537813da627SRichard Henderson /* End GDB interface. */ 6538813da627SRichard Henderson 6539813da627SRichard Henderson static int find_string(const char *strtab, const char *str) 6540813da627SRichard Henderson { 6541813da627SRichard Henderson const char *p = strtab + 1; 6542813da627SRichard Henderson 6543813da627SRichard Henderson while (1) { 6544813da627SRichard Henderson if (strcmp(p, str) == 0) { 6545813da627SRichard Henderson return p - strtab; 6546813da627SRichard Henderson } 6547813da627SRichard Henderson p += strlen(p) + 1; 6548813da627SRichard Henderson } 6549813da627SRichard Henderson } 6550813da627SRichard Henderson 6551755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf_ptr, size_t buf_size, 65522c90784aSRichard Henderson const void *debug_frame, 65532c90784aSRichard Henderson size_t debug_frame_size) 6554813da627SRichard Henderson { 65555872bbf2SRichard Henderson struct __attribute__((packed)) DebugInfo { 65565872bbf2SRichard Henderson uint32_t len; 65575872bbf2SRichard Henderson uint16_t version; 65585872bbf2SRichard Henderson uint32_t abbrev; 65595872bbf2SRichard Henderson uint8_t ptr_size; 65605872bbf2SRichard Henderson uint8_t cu_die; 65615872bbf2SRichard Henderson uint16_t cu_lang; 65625872bbf2SRichard Henderson uintptr_t cu_low_pc; 65635872bbf2SRichard Henderson uintptr_t cu_high_pc; 65645872bbf2SRichard Henderson uint8_t fn_die; 65655872bbf2SRichard Henderson char fn_name[16]; 65665872bbf2SRichard Henderson uintptr_t fn_low_pc; 65675872bbf2SRichard Henderson uintptr_t fn_high_pc; 65685872bbf2SRichard Henderson uint8_t cu_eoc; 65695872bbf2SRichard Henderson }; 6570813da627SRichard Henderson 6571813da627SRichard Henderson struct ElfImage { 6572813da627SRichard Henderson ElfW(Ehdr) ehdr; 6573813da627SRichard Henderson ElfW(Phdr) phdr; 65745872bbf2SRichard Henderson ElfW(Shdr) shdr[7]; 65755872bbf2SRichard Henderson ElfW(Sym) sym[2]; 65765872bbf2SRichard Henderson struct DebugInfo di; 65775872bbf2SRichard Henderson uint8_t da[24]; 65785872bbf2SRichard Henderson char str[80]; 65795872bbf2SRichard Henderson }; 65805872bbf2SRichard Henderson 65815872bbf2SRichard Henderson struct ElfImage *img; 65825872bbf2SRichard Henderson 65835872bbf2SRichard Henderson static const struct ElfImage img_template = { 65845872bbf2SRichard Henderson .ehdr = { 65855872bbf2SRichard Henderson .e_ident[EI_MAG0] = ELFMAG0, 65865872bbf2SRichard Henderson .e_ident[EI_MAG1] = ELFMAG1, 65875872bbf2SRichard Henderson .e_ident[EI_MAG2] = ELFMAG2, 65885872bbf2SRichard Henderson .e_ident[EI_MAG3] = ELFMAG3, 65895872bbf2SRichard Henderson .e_ident[EI_CLASS] = ELF_CLASS, 65905872bbf2SRichard Henderson .e_ident[EI_DATA] = ELF_DATA, 65915872bbf2SRichard Henderson .e_ident[EI_VERSION] = EV_CURRENT, 65925872bbf2SRichard Henderson .e_type = ET_EXEC, 65935872bbf2SRichard Henderson .e_machine = ELF_HOST_MACHINE, 65945872bbf2SRichard Henderson .e_version = EV_CURRENT, 65955872bbf2SRichard Henderson .e_phoff = offsetof(struct ElfImage, phdr), 65965872bbf2SRichard Henderson .e_shoff = offsetof(struct ElfImage, shdr), 65975872bbf2SRichard Henderson .e_ehsize = sizeof(ElfW(Shdr)), 65985872bbf2SRichard Henderson .e_phentsize = sizeof(ElfW(Phdr)), 65995872bbf2SRichard Henderson .e_phnum = 1, 66005872bbf2SRichard Henderson .e_shentsize = sizeof(ElfW(Shdr)), 66015872bbf2SRichard Henderson .e_shnum = ARRAY_SIZE(img->shdr), 66025872bbf2SRichard Henderson .e_shstrndx = ARRAY_SIZE(img->shdr) - 1, 6603abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS 6604abbb3eaeSRichard Henderson .e_flags = ELF_HOST_FLAGS, 6605abbb3eaeSRichard Henderson #endif 6606abbb3eaeSRichard Henderson #ifdef ELF_OSABI 6607abbb3eaeSRichard Henderson .e_ident[EI_OSABI] = ELF_OSABI, 6608abbb3eaeSRichard Henderson #endif 66095872bbf2SRichard Henderson }, 66105872bbf2SRichard Henderson .phdr = { 66115872bbf2SRichard Henderson .p_type = PT_LOAD, 66125872bbf2SRichard Henderson .p_flags = PF_X, 66135872bbf2SRichard Henderson }, 66145872bbf2SRichard Henderson .shdr = { 66155872bbf2SRichard Henderson [0] = { .sh_type = SHT_NULL }, 66165872bbf2SRichard Henderson /* Trick: The contents of code_gen_buffer are not present in 66175872bbf2SRichard Henderson this fake ELF file; that got allocated elsewhere. Therefore 66185872bbf2SRichard Henderson we mark .text as SHT_NOBITS (similar to .bss) so that readers 66195872bbf2SRichard Henderson will not look for contents. We can record any address. */ 66205872bbf2SRichard Henderson [1] = { /* .text */ 66215872bbf2SRichard Henderson .sh_type = SHT_NOBITS, 66225872bbf2SRichard Henderson .sh_flags = SHF_EXECINSTR | SHF_ALLOC, 66235872bbf2SRichard Henderson }, 66245872bbf2SRichard Henderson [2] = { /* .debug_info */ 66255872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 66265872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, di), 66275872bbf2SRichard Henderson .sh_size = sizeof(struct DebugInfo), 66285872bbf2SRichard Henderson }, 66295872bbf2SRichard Henderson [3] = { /* .debug_abbrev */ 66305872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 66315872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, da), 66325872bbf2SRichard Henderson .sh_size = sizeof(img->da), 66335872bbf2SRichard Henderson }, 66345872bbf2SRichard Henderson [4] = { /* .debug_frame */ 66355872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 66365872bbf2SRichard Henderson .sh_offset = sizeof(struct ElfImage), 66375872bbf2SRichard Henderson }, 66385872bbf2SRichard Henderson [5] = { /* .symtab */ 66395872bbf2SRichard Henderson .sh_type = SHT_SYMTAB, 66405872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, sym), 66415872bbf2SRichard Henderson .sh_size = sizeof(img->sym), 66425872bbf2SRichard Henderson .sh_info = 1, 66435872bbf2SRichard Henderson .sh_link = ARRAY_SIZE(img->shdr) - 1, 66445872bbf2SRichard Henderson .sh_entsize = sizeof(ElfW(Sym)), 66455872bbf2SRichard Henderson }, 66465872bbf2SRichard Henderson [6] = { /* .strtab */ 66475872bbf2SRichard Henderson .sh_type = SHT_STRTAB, 66485872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, str), 66495872bbf2SRichard Henderson .sh_size = sizeof(img->str), 66505872bbf2SRichard Henderson } 66515872bbf2SRichard Henderson }, 66525872bbf2SRichard Henderson .sym = { 66535872bbf2SRichard Henderson [1] = { /* code_gen_buffer */ 66545872bbf2SRichard Henderson .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC), 66555872bbf2SRichard Henderson .st_shndx = 1, 66565872bbf2SRichard Henderson } 66575872bbf2SRichard Henderson }, 66585872bbf2SRichard Henderson .di = { 66595872bbf2SRichard Henderson .len = sizeof(struct DebugInfo) - 4, 66605872bbf2SRichard Henderson .version = 2, 66615872bbf2SRichard Henderson .ptr_size = sizeof(void *), 66625872bbf2SRichard Henderson .cu_die = 1, 66635872bbf2SRichard Henderson .cu_lang = 0x8001, /* DW_LANG_Mips_Assembler */ 66645872bbf2SRichard Henderson .fn_die = 2, 66655872bbf2SRichard Henderson .fn_name = "code_gen_buffer" 66665872bbf2SRichard Henderson }, 66675872bbf2SRichard Henderson .da = { 66685872bbf2SRichard Henderson 1, /* abbrev number (the cu) */ 66695872bbf2SRichard Henderson 0x11, 1, /* DW_TAG_compile_unit, has children */ 66705872bbf2SRichard Henderson 0x13, 0x5, /* DW_AT_language, DW_FORM_data2 */ 66715872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */ 66725872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */ 66735872bbf2SRichard Henderson 0, 0, /* end of abbrev */ 66745872bbf2SRichard Henderson 2, /* abbrev number (the fn) */ 66755872bbf2SRichard Henderson 0x2e, 0, /* DW_TAG_subprogram, no children */ 66765872bbf2SRichard Henderson 0x3, 0x8, /* DW_AT_name, DW_FORM_string */ 66775872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */ 66785872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */ 66795872bbf2SRichard Henderson 0, 0, /* end of abbrev */ 66805872bbf2SRichard Henderson 0 /* no more abbrev */ 66815872bbf2SRichard Henderson }, 66825872bbf2SRichard Henderson .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0" 66835872bbf2SRichard Henderson ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer", 6684813da627SRichard Henderson }; 6685813da627SRichard Henderson 6686813da627SRichard Henderson /* We only need a single jit entry; statically allocate it. */ 6687813da627SRichard Henderson static struct jit_code_entry one_entry; 6688813da627SRichard Henderson 66895872bbf2SRichard Henderson uintptr_t buf = (uintptr_t)buf_ptr; 6690813da627SRichard Henderson size_t img_size = sizeof(struct ElfImage) + debug_frame_size; 66912c90784aSRichard Henderson DebugFrameHeader *dfh; 6692813da627SRichard Henderson 66935872bbf2SRichard Henderson img = g_malloc(img_size); 66945872bbf2SRichard Henderson *img = img_template; 6695813da627SRichard Henderson 66965872bbf2SRichard Henderson img->phdr.p_vaddr = buf; 66975872bbf2SRichard Henderson img->phdr.p_paddr = buf; 66985872bbf2SRichard Henderson img->phdr.p_memsz = buf_size; 6699813da627SRichard Henderson 67005872bbf2SRichard Henderson img->shdr[1].sh_name = find_string(img->str, ".text"); 67015872bbf2SRichard Henderson img->shdr[1].sh_addr = buf; 67025872bbf2SRichard Henderson img->shdr[1].sh_size = buf_size; 6703813da627SRichard Henderson 67045872bbf2SRichard Henderson img->shdr[2].sh_name = find_string(img->str, ".debug_info"); 67055872bbf2SRichard Henderson img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev"); 67065872bbf2SRichard Henderson 67075872bbf2SRichard Henderson img->shdr[4].sh_name = find_string(img->str, ".debug_frame"); 67085872bbf2SRichard Henderson img->shdr[4].sh_size = debug_frame_size; 67095872bbf2SRichard Henderson 67105872bbf2SRichard Henderson img->shdr[5].sh_name = find_string(img->str, ".symtab"); 67115872bbf2SRichard Henderson img->shdr[6].sh_name = find_string(img->str, ".strtab"); 67125872bbf2SRichard Henderson 67135872bbf2SRichard Henderson img->sym[1].st_name = find_string(img->str, "code_gen_buffer"); 67145872bbf2SRichard Henderson img->sym[1].st_value = buf; 67155872bbf2SRichard Henderson img->sym[1].st_size = buf_size; 67165872bbf2SRichard Henderson 67175872bbf2SRichard Henderson img->di.cu_low_pc = buf; 671845aba097SRichard Henderson img->di.cu_high_pc = buf + buf_size; 67195872bbf2SRichard Henderson img->di.fn_low_pc = buf; 672045aba097SRichard Henderson img->di.fn_high_pc = buf + buf_size; 6721813da627SRichard Henderson 67222c90784aSRichard Henderson dfh = (DebugFrameHeader *)(img + 1); 67232c90784aSRichard Henderson memcpy(dfh, debug_frame, debug_frame_size); 67242c90784aSRichard Henderson dfh->fde.func_start = buf; 67252c90784aSRichard Henderson dfh->fde.func_len = buf_size; 67262c90784aSRichard Henderson 6727813da627SRichard Henderson #ifdef DEBUG_JIT 6728813da627SRichard Henderson /* Enable this block to be able to debug the ELF image file creation. 6729813da627SRichard Henderson One can use readelf, objdump, or other inspection utilities. */ 6730813da627SRichard Henderson { 6731eb6b2edfSBin Meng g_autofree char *jit = g_strdup_printf("%s/qemu.jit", g_get_tmp_dir()); 6732eb6b2edfSBin Meng FILE *f = fopen(jit, "w+b"); 6733813da627SRichard Henderson if (f) { 67345872bbf2SRichard Henderson if (fwrite(img, img_size, 1, f) != img_size) { 6735813da627SRichard Henderson /* Avoid stupid unused return value warning for fwrite. */ 6736813da627SRichard Henderson } 6737813da627SRichard Henderson fclose(f); 6738813da627SRichard Henderson } 6739813da627SRichard Henderson } 6740813da627SRichard Henderson #endif 6741813da627SRichard Henderson 6742813da627SRichard Henderson one_entry.symfile_addr = img; 6743813da627SRichard Henderson one_entry.symfile_size = img_size; 6744813da627SRichard Henderson 6745813da627SRichard Henderson __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; 6746813da627SRichard Henderson __jit_debug_descriptor.relevant_entry = &one_entry; 6747813da627SRichard Henderson __jit_debug_descriptor.first_entry = &one_entry; 6748813da627SRichard Henderson __jit_debug_register_code(); 6749813da627SRichard Henderson } 6750813da627SRichard Henderson #else 67515872bbf2SRichard Henderson /* No support for the feature. Provide the entry point expected by exec.c, 67525872bbf2SRichard Henderson and implement the internal function we declared earlier. */ 6753813da627SRichard Henderson 6754755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size, 67552c90784aSRichard Henderson const void *debug_frame, 67562c90784aSRichard Henderson size_t debug_frame_size) 6757813da627SRichard Henderson { 6758813da627SRichard Henderson } 6759813da627SRichard Henderson 6760755bf9e5SRichard Henderson void tcg_register_jit(const void *buf, size_t buf_size) 6761813da627SRichard Henderson { 6762813da627SRichard Henderson } 6763813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */ 6764db432672SRichard Henderson 6765db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec 6766db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...) 6767db432672SRichard Henderson { 6768db432672SRichard Henderson g_assert_not_reached(); 6769db432672SRichard Henderson } 6770db432672SRichard Henderson #endif 6771