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 */ 1030cd38379SRichard Henderson TCGReg addr_reg; /* reg index for guest virtual addr */ 1042528f771SRichard Henderson TCGReg datalo_reg; /* reg index for low word to be loaded or stored */ 1052528f771SRichard Henderson TCGReg datahi_reg; /* reg index for high word to be loaded or stored */ 1062528f771SRichard Henderson const tcg_insn_unit *raddr; /* addr of the next IR of qemu_ld/st IR */ 1072528f771SRichard Henderson tcg_insn_unit *label_ptr[2]; /* label pointers to be updated */ 1082528f771SRichard Henderson QSIMPLEQ_ENTRY(TCGLabelQemuLdst) next; 109a417ef83SRichard Henderson }; 1102528f771SRichard Henderson 111755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size, 1122c90784aSRichard Henderson const void *debug_frame, 1132c90784aSRichard Henderson size_t debug_frame_size) 114813da627SRichard Henderson __attribute__((unused)); 115813da627SRichard Henderson 116139c1837SPaolo Bonzini /* Forward declarations for functions declared and used in tcg-target.c.inc. */ 1179358fbbfSRichard Henderson static void tcg_out_tb_start(TCGContext *s); 1182a534affSRichard Henderson static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1, 119a05b5b9bSRichard Henderson intptr_t arg2); 12078113e83SRichard Henderson static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg); 121c0ad3001SStefan Weil static void tcg_out_movi(TCGContext *s, TCGType type, 1222a534affSRichard Henderson TCGReg ret, tcg_target_long arg); 123678155b2SRichard Henderson static void tcg_out_ext8s(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg); 124753e42eaSRichard Henderson static void tcg_out_ext16s(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg); 125d0e66c89SRichard Henderson static void tcg_out_ext8u(TCGContext *s, TCGReg ret, TCGReg arg); 126379afdffSRichard Henderson static void tcg_out_ext16u(TCGContext *s, TCGReg ret, TCGReg arg); 12752bf3398SRichard Henderson static void tcg_out_ext32s(TCGContext *s, TCGReg ret, TCGReg arg); 1289ecf5f61SRichard Henderson static void tcg_out_ext32u(TCGContext *s, TCGReg ret, TCGReg arg); 1299c6aa274SRichard Henderson static void tcg_out_exts_i32_i64(TCGContext *s, TCGReg ret, TCGReg arg); 130b9bfe000SRichard Henderson static void tcg_out_extu_i32_i64(TCGContext *s, TCGReg ret, TCGReg arg); 131b8b94ac6SRichard Henderson static void tcg_out_extrl_i64_i32(TCGContext *s, TCGReg ret, TCGReg arg); 132313bdea8SRichard Henderson static void tcg_out_addi_ptr(TCGContext *s, TCGReg, TCGReg, tcg_target_long); 133129f1f9eSRichard Henderson static bool tcg_out_xchg(TCGContext *s, TCGType type, TCGReg r1, TCGReg r2); 134b55a8d9dSRichard Henderson static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg); 135cf7d6b8eSRichard Henderson static void tcg_out_goto_tb(TCGContext *s, int which); 1364e350091SRichard Henderson static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, 1375e8892dbSMiroslav Rezanina const TCGArg args[TCG_MAX_OP_ARGS], 1385e8892dbSMiroslav Rezanina const int const_args[TCG_MAX_OP_ARGS]); 139d2fd745fSRichard Henderson #if TCG_TARGET_MAYBE_vec 140e7632cfaSRichard Henderson static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece, 141e7632cfaSRichard Henderson TCGReg dst, TCGReg src); 142d6ecb4a9SRichard Henderson static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece, 143d6ecb4a9SRichard Henderson TCGReg dst, TCGReg base, intptr_t offset); 1444e186175SRichard Henderson static void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece, 1454e186175SRichard Henderson TCGReg dst, int64_t arg); 1465e8892dbSMiroslav Rezanina static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, 1475e8892dbSMiroslav Rezanina unsigned vecl, unsigned vece, 1485e8892dbSMiroslav Rezanina const TCGArg args[TCG_MAX_OP_ARGS], 1495e8892dbSMiroslav Rezanina const int const_args[TCG_MAX_OP_ARGS]); 150d2fd745fSRichard Henderson #else 151e7632cfaSRichard Henderson static inline bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece, 152e7632cfaSRichard Henderson TCGReg dst, TCGReg src) 153e7632cfaSRichard Henderson { 154e7632cfaSRichard Henderson g_assert_not_reached(); 155e7632cfaSRichard Henderson } 156d6ecb4a9SRichard Henderson static inline bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece, 157d6ecb4a9SRichard Henderson TCGReg dst, TCGReg base, intptr_t offset) 158d6ecb4a9SRichard Henderson { 159d6ecb4a9SRichard Henderson g_assert_not_reached(); 160d6ecb4a9SRichard Henderson } 1614e186175SRichard Henderson static inline void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece, 1624e186175SRichard Henderson TCGReg dst, int64_t arg) 163e7632cfaSRichard Henderson { 164e7632cfaSRichard Henderson g_assert_not_reached(); 165e7632cfaSRichard Henderson } 1665e8892dbSMiroslav Rezanina static inline void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, 1675e8892dbSMiroslav Rezanina unsigned vecl, unsigned vece, 1685e8892dbSMiroslav Rezanina const TCGArg args[TCG_MAX_OP_ARGS], 1695e8892dbSMiroslav Rezanina const int const_args[TCG_MAX_OP_ARGS]) 170d2fd745fSRichard Henderson { 171d2fd745fSRichard Henderson g_assert_not_reached(); 172d2fd745fSRichard Henderson } 1737d3e705aSRichard Henderson int tcg_can_emit_vec_op(TCGOpcode o, TCGType t, unsigned ve) 1747d3e705aSRichard Henderson { 1757d3e705aSRichard Henderson return 0; 1767d3e705aSRichard Henderson } 177d2fd745fSRichard Henderson #endif 1782a534affSRichard Henderson static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1, 179a05b5b9bSRichard Henderson intptr_t arg2); 18059d7c14eSRichard Henderson static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val, 18159d7c14eSRichard Henderson TCGReg base, intptr_t ofs); 1827b7d8b2dSRichard Henderson static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target, 183cee44b03SRichard Henderson const TCGHelperInfo *info); 1845e3d0c19SRichard Henderson static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot); 18521e9a8aeSRichard Henderson static bool tcg_target_const_match(int64_t val, int ct, 18621e9a8aeSRichard Henderson TCGType type, TCGCond cond, int vece); 187c896fe29Sbellard 18823088ca0SRichard Henderson #ifndef CONFIG_USER_ONLY 18923088ca0SRichard Henderson #define guest_base ({ qemu_build_not_reached(); (uintptr_t)0; }) 19023088ca0SRichard Henderson #endif 19123088ca0SRichard Henderson 1928429a1caSRichard Henderson typedef struct TCGLdstHelperParam { 1938429a1caSRichard Henderson TCGReg (*ra_gen)(TCGContext *s, const TCGLabelQemuLdst *l, int arg_reg); 1948429a1caSRichard Henderson unsigned ntmp; 1958429a1caSRichard Henderson int tmp[3]; 1968429a1caSRichard Henderson } TCGLdstHelperParam; 1978429a1caSRichard Henderson 1988429a1caSRichard Henderson static void tcg_out_ld_helper_args(TCGContext *s, const TCGLabelQemuLdst *l, 1998429a1caSRichard Henderson const TCGLdstHelperParam *p) 2008429a1caSRichard Henderson __attribute__((unused)); 2018429a1caSRichard Henderson static void tcg_out_ld_helper_ret(TCGContext *s, const TCGLabelQemuLdst *l, 2028429a1caSRichard Henderson bool load_sign, const TCGLdstHelperParam *p) 2038429a1caSRichard Henderson __attribute__((unused)); 2048429a1caSRichard Henderson static void tcg_out_st_helper_args(TCGContext *s, const TCGLabelQemuLdst *l, 2058429a1caSRichard Henderson const TCGLdstHelperParam *p) 2068429a1caSRichard Henderson __attribute__((unused)); 2078429a1caSRichard Henderson 208de95016dSRichard Henderson static void * const qemu_ld_helpers[MO_SSIZE + 1] __attribute__((unused)) = { 2090cadc1edSRichard Henderson [MO_UB] = helper_ldub_mmu, 2100cadc1edSRichard Henderson [MO_SB] = helper_ldsb_mmu, 2110cadc1edSRichard Henderson [MO_UW] = helper_lduw_mmu, 2120cadc1edSRichard Henderson [MO_SW] = helper_ldsw_mmu, 2130cadc1edSRichard Henderson [MO_UL] = helper_ldul_mmu, 2140cadc1edSRichard Henderson [MO_UQ] = helper_ldq_mmu, 2150cadc1edSRichard Henderson #if TCG_TARGET_REG_BITS == 64 2160cadc1edSRichard Henderson [MO_SL] = helper_ldsl_mmu, 217ebebea53SRichard Henderson [MO_128] = helper_ld16_mmu, 2180cadc1edSRichard Henderson #endif 2190cadc1edSRichard Henderson }; 2200cadc1edSRichard Henderson 221de95016dSRichard Henderson static void * const qemu_st_helpers[MO_SIZE + 1] __attribute__((unused)) = { 2220cadc1edSRichard Henderson [MO_8] = helper_stb_mmu, 2230cadc1edSRichard Henderson [MO_16] = helper_stw_mmu, 2240cadc1edSRichard Henderson [MO_32] = helper_stl_mmu, 2250cadc1edSRichard Henderson [MO_64] = helper_stq_mmu, 226ebebea53SRichard Henderson #if TCG_TARGET_REG_BITS == 64 227ebebea53SRichard Henderson [MO_128] = helper_st16_mmu, 228ebebea53SRichard Henderson #endif 2290cadc1edSRichard Henderson }; 2300cadc1edSRichard Henderson 231e63b8a29SRichard Henderson typedef struct { 232e63b8a29SRichard Henderson MemOp atom; /* lg2 bits of atomicity required */ 233e63b8a29SRichard Henderson MemOp align; /* lg2 bits of alignment to use */ 234e63b8a29SRichard Henderson } TCGAtomAlign; 235e63b8a29SRichard Henderson 236e63b8a29SRichard Henderson static TCGAtomAlign atom_and_align_for_opc(TCGContext *s, MemOp opc, 237e63b8a29SRichard Henderson MemOp host_atom, bool allow_two_ops) 238e63b8a29SRichard Henderson __attribute__((unused)); 239e63b8a29SRichard Henderson 240397cabaaSRichard Henderson #ifdef CONFIG_USER_ONLY 241397cabaaSRichard Henderson bool tcg_use_softmmu; 242397cabaaSRichard Henderson #endif 243397cabaaSRichard Henderson 24442eb6dfcSRichard Henderson TCGContext tcg_init_ctx; 24542eb6dfcSRichard Henderson __thread TCGContext *tcg_ctx; 24642eb6dfcSRichard Henderson 2475ff7258cSRichard Henderson TCGContext **tcg_ctxs; 2480e2d61cfSRichard Henderson unsigned int tcg_cur_ctxs; 2490e2d61cfSRichard Henderson unsigned int tcg_max_ctxs; 250ad75a51eSRichard Henderson TCGv_env tcg_env; 251c8bc1168SRichard Henderson const void *tcg_code_gen_epilogue; 252db0c51a3SRichard Henderson uintptr_t tcg_splitwx_diff; 253df2cce29SEmilio G. Cota 254b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 255b91ccb31SRichard Henderson tcg_prologue_fn *tcg_qemu_tb_exec; 256b91ccb31SRichard Henderson #endif 257b91ccb31SRichard Henderson 258d2fd745fSRichard Henderson static TCGRegSet tcg_target_available_regs[TCG_TYPE_COUNT]; 259b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs; 260c896fe29Sbellard 2611813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1 2624196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v) 263c896fe29Sbellard { 264c896fe29Sbellard *s->code_ptr++ = v; 265c896fe29Sbellard } 266c896fe29Sbellard 2674196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p, 2684196dca6SPeter Maydell uint8_t v) 2695c53bb81SPeter Maydell { 2701813e175SRichard Henderson *p = v; 2715c53bb81SPeter Maydell } 2721813e175SRichard Henderson #endif 2735c53bb81SPeter Maydell 2741813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2 2754196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v) 276c896fe29Sbellard { 2771813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 2) { 2781813e175SRichard Henderson *s->code_ptr++ = v; 2791813e175SRichard Henderson } else { 2801813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 2814387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 2821813e175SRichard Henderson s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE); 2831813e175SRichard Henderson } 284c896fe29Sbellard } 285c896fe29Sbellard 2864196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p, 2874196dca6SPeter Maydell uint16_t v) 2885c53bb81SPeter Maydell { 2891813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 2) { 2901813e175SRichard Henderson *p = v; 2911813e175SRichard Henderson } else { 2925c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 2935c53bb81SPeter Maydell } 2941813e175SRichard Henderson } 2951813e175SRichard Henderson #endif 2965c53bb81SPeter Maydell 2971813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4 2984196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v) 299c896fe29Sbellard { 3001813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 4) { 3011813e175SRichard Henderson *s->code_ptr++ = v; 3021813e175SRichard Henderson } else { 3031813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 3044387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 3051813e175SRichard Henderson s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE); 3061813e175SRichard Henderson } 307c896fe29Sbellard } 308c896fe29Sbellard 3094196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p, 3104196dca6SPeter Maydell uint32_t v) 3115c53bb81SPeter Maydell { 3121813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 4) { 3131813e175SRichard Henderson *p = v; 3141813e175SRichard Henderson } else { 3155c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 3165c53bb81SPeter Maydell } 3171813e175SRichard Henderson } 3181813e175SRichard Henderson #endif 3195c53bb81SPeter Maydell 3201813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 8 3214196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v) 322ac26eb69SRichard Henderson { 3231813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 8) { 3241813e175SRichard Henderson *s->code_ptr++ = v; 3251813e175SRichard Henderson } else { 3261813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 3274387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 3281813e175SRichard Henderson s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE); 3291813e175SRichard Henderson } 330ac26eb69SRichard Henderson } 331ac26eb69SRichard Henderson 3324196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p, 3334196dca6SPeter Maydell uint64_t v) 3345c53bb81SPeter Maydell { 3351813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 8) { 3361813e175SRichard Henderson *p = v; 3371813e175SRichard Henderson } else { 3385c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 3395c53bb81SPeter Maydell } 3401813e175SRichard Henderson } 3411813e175SRichard Henderson #endif 3425c53bb81SPeter Maydell 343c896fe29Sbellard /* label relocation processing */ 344c896fe29Sbellard 3451813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type, 346bec16311SRichard Henderson TCGLabel *l, intptr_t addend) 347c896fe29Sbellard { 3487ecd02a0SRichard Henderson TCGRelocation *r = tcg_malloc(sizeof(TCGRelocation)); 349c896fe29Sbellard 350c896fe29Sbellard r->type = type; 351c896fe29Sbellard r->ptr = code_ptr; 352c896fe29Sbellard r->addend = addend; 3537ecd02a0SRichard Henderson QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next); 354c896fe29Sbellard } 355c896fe29Sbellard 35692ab8e7dSRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l) 357c896fe29Sbellard { 358eabb7b91SAurelien Jarno tcg_debug_assert(!l->has_value); 359c896fe29Sbellard l->has_value = 1; 36092ab8e7dSRichard Henderson l->u.value_ptr = tcg_splitwx_to_rx(s->code_ptr); 361c896fe29Sbellard } 362c896fe29Sbellard 36342a268c2SRichard Henderson TCGLabel *gen_new_label(void) 364c896fe29Sbellard { 365b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 36651e3972cSRichard Henderson TCGLabel *l = tcg_malloc(sizeof(TCGLabel)); 367c896fe29Sbellard 3687ecd02a0SRichard Henderson memset(l, 0, sizeof(TCGLabel)); 3697ecd02a0SRichard Henderson l->id = s->nb_labels++; 370f85b1fc4SRichard Henderson QSIMPLEQ_INIT(&l->branches); 3717ecd02a0SRichard Henderson QSIMPLEQ_INIT(&l->relocs); 3727ecd02a0SRichard Henderson 373bef16ab4SRichard Henderson QSIMPLEQ_INSERT_TAIL(&s->labels, l, next); 37442a268c2SRichard Henderson 37542a268c2SRichard Henderson return l; 376c896fe29Sbellard } 377c896fe29Sbellard 3787ecd02a0SRichard Henderson static bool tcg_resolve_relocs(TCGContext *s) 3797ecd02a0SRichard Henderson { 3807ecd02a0SRichard Henderson TCGLabel *l; 3817ecd02a0SRichard Henderson 3827ecd02a0SRichard Henderson QSIMPLEQ_FOREACH(l, &s->labels, next) { 3837ecd02a0SRichard Henderson TCGRelocation *r; 3847ecd02a0SRichard Henderson uintptr_t value = l->u.value; 3857ecd02a0SRichard Henderson 3867ecd02a0SRichard Henderson QSIMPLEQ_FOREACH(r, &l->relocs, next) { 3877ecd02a0SRichard Henderson if (!patch_reloc(r->ptr, r->type, value, r->addend)) { 3887ecd02a0SRichard Henderson return false; 3897ecd02a0SRichard Henderson } 3907ecd02a0SRichard Henderson } 3917ecd02a0SRichard Henderson } 3927ecd02a0SRichard Henderson return true; 3937ecd02a0SRichard Henderson } 3947ecd02a0SRichard Henderson 3959f754620SRichard Henderson static void set_jmp_reset_offset(TCGContext *s, int which) 3969f754620SRichard Henderson { 397f14bed3fSRichard Henderson /* 398f14bed3fSRichard Henderson * We will check for overflow at the end of the opcode loop in 399f14bed3fSRichard Henderson * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX. 400f14bed3fSRichard Henderson */ 401b7e4afbdSRichard Henderson s->gen_tb->jmp_reset_offset[which] = tcg_current_code_size(s); 4029f754620SRichard Henderson } 4039f754620SRichard Henderson 404b52a2c03SRichard Henderson static void G_GNUC_UNUSED set_jmp_insn_offset(TCGContext *s, int which) 405b52a2c03SRichard Henderson { 406b52a2c03SRichard Henderson /* 407b52a2c03SRichard Henderson * We will check for overflow at the end of the opcode loop in 408b52a2c03SRichard Henderson * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX. 409b52a2c03SRichard Henderson */ 4109da6079bSRichard Henderson s->gen_tb->jmp_insn_offset[which] = tcg_current_code_size(s); 411b52a2c03SRichard Henderson } 412b52a2c03SRichard Henderson 413becc452aSRichard Henderson static uintptr_t G_GNUC_UNUSED get_jmp_target_addr(TCGContext *s, int which) 414becc452aSRichard Henderson { 415becc452aSRichard Henderson /* 416becc452aSRichard Henderson * Return the read-execute version of the pointer, for the benefit 417becc452aSRichard Henderson * of any pc-relative addressing mode. 418becc452aSRichard Henderson */ 4199da6079bSRichard Henderson return (uintptr_t)tcg_splitwx_to_rx(&s->gen_tb->jmp_target_addr[which]); 420becc452aSRichard Henderson } 421becc452aSRichard Henderson 422397cabaaSRichard Henderson static int __attribute__((unused)) 423397cabaaSRichard Henderson tlb_mask_table_ofs(TCGContext *s, int which) 424d0a9bb5eSRichard Henderson { 4257857ee11SRichard Henderson return (offsetof(CPUNegativeOffsetState, tlb.f[which]) - 4267857ee11SRichard Henderson sizeof(CPUNegativeOffsetState)); 427d0a9bb5eSRichard Henderson } 428d0a9bb5eSRichard Henderson 429db6b7d0cSRichard Henderson /* Signal overflow, starting over with fewer guest insns. */ 4308905770bSMarc-André Lureau static G_NORETURN 4318905770bSMarc-André Lureau void tcg_raise_tb_overflow(TCGContext *s) 432db6b7d0cSRichard Henderson { 433db6b7d0cSRichard Henderson siglongjmp(s->jmp_trans, -2); 434db6b7d0cSRichard Henderson } 435db6b7d0cSRichard Henderson 4368429a1caSRichard Henderson /* 4378429a1caSRichard Henderson * Used by tcg_out_movext{1,2} to hold the arguments for tcg_out_movext. 4388429a1caSRichard Henderson * By the time we arrive at tcg_out_movext1, @dst is always a TCGReg. 4398429a1caSRichard Henderson * 4408429a1caSRichard Henderson * However, tcg_out_helper_load_slots reuses this field to hold an 4418429a1caSRichard Henderson * argument slot number (which may designate a argument register or an 4428429a1caSRichard Henderson * argument stack slot), converting to TCGReg once all arguments that 4438429a1caSRichard Henderson * are destined for the stack are processed. 4448429a1caSRichard Henderson */ 445129f1f9eSRichard Henderson typedef struct TCGMovExtend { 4468429a1caSRichard Henderson unsigned dst; 447129f1f9eSRichard Henderson TCGReg src; 448129f1f9eSRichard Henderson TCGType dst_type; 449129f1f9eSRichard Henderson TCGType src_type; 450129f1f9eSRichard Henderson MemOp src_ext; 451129f1f9eSRichard Henderson } TCGMovExtend; 452129f1f9eSRichard Henderson 453b3dfd5fcSRichard Henderson /** 454b3dfd5fcSRichard Henderson * tcg_out_movext -- move and extend 455b3dfd5fcSRichard Henderson * @s: tcg context 456b3dfd5fcSRichard Henderson * @dst_type: integral type for destination 457b3dfd5fcSRichard Henderson * @dst: destination register 458b3dfd5fcSRichard Henderson * @src_type: integral type for source 459b3dfd5fcSRichard Henderson * @src_ext: extension to apply to source 460b3dfd5fcSRichard Henderson * @src: source register 461b3dfd5fcSRichard Henderson * 462b3dfd5fcSRichard Henderson * Move or extend @src into @dst, depending on @src_ext and the types. 463b3dfd5fcSRichard Henderson */ 464129f1f9eSRichard Henderson static void tcg_out_movext(TCGContext *s, TCGType dst_type, TCGReg dst, 465b3dfd5fcSRichard Henderson TCGType src_type, MemOp src_ext, TCGReg src) 466b3dfd5fcSRichard Henderson { 467b3dfd5fcSRichard Henderson switch (src_ext) { 468b3dfd5fcSRichard Henderson case MO_UB: 469b3dfd5fcSRichard Henderson tcg_out_ext8u(s, dst, src); 470b3dfd5fcSRichard Henderson break; 471b3dfd5fcSRichard Henderson case MO_SB: 472b3dfd5fcSRichard Henderson tcg_out_ext8s(s, dst_type, dst, src); 473b3dfd5fcSRichard Henderson break; 474b3dfd5fcSRichard Henderson case MO_UW: 475b3dfd5fcSRichard Henderson tcg_out_ext16u(s, dst, src); 476b3dfd5fcSRichard Henderson break; 477b3dfd5fcSRichard Henderson case MO_SW: 478b3dfd5fcSRichard Henderson tcg_out_ext16s(s, dst_type, dst, src); 479b3dfd5fcSRichard Henderson break; 480b3dfd5fcSRichard Henderson case MO_UL: 481b3dfd5fcSRichard Henderson case MO_SL: 482b3dfd5fcSRichard Henderson if (dst_type == TCG_TYPE_I32) { 483b3dfd5fcSRichard Henderson if (src_type == TCG_TYPE_I32) { 484b3dfd5fcSRichard Henderson tcg_out_mov(s, TCG_TYPE_I32, dst, src); 485b3dfd5fcSRichard Henderson } else { 486b3dfd5fcSRichard Henderson tcg_out_extrl_i64_i32(s, dst, src); 487b3dfd5fcSRichard Henderson } 488b3dfd5fcSRichard Henderson } else if (src_type == TCG_TYPE_I32) { 489b3dfd5fcSRichard Henderson if (src_ext & MO_SIGN) { 490b3dfd5fcSRichard Henderson tcg_out_exts_i32_i64(s, dst, src); 491b3dfd5fcSRichard Henderson } else { 492b3dfd5fcSRichard Henderson tcg_out_extu_i32_i64(s, dst, src); 493b3dfd5fcSRichard Henderson } 494b3dfd5fcSRichard Henderson } else { 495b3dfd5fcSRichard Henderson if (src_ext & MO_SIGN) { 496b3dfd5fcSRichard Henderson tcg_out_ext32s(s, dst, src); 497b3dfd5fcSRichard Henderson } else { 498b3dfd5fcSRichard Henderson tcg_out_ext32u(s, dst, src); 499b3dfd5fcSRichard Henderson } 500b3dfd5fcSRichard Henderson } 501b3dfd5fcSRichard Henderson break; 502b3dfd5fcSRichard Henderson case MO_UQ: 503b3dfd5fcSRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 64); 504b3dfd5fcSRichard Henderson if (dst_type == TCG_TYPE_I32) { 505b3dfd5fcSRichard Henderson tcg_out_extrl_i64_i32(s, dst, src); 506b3dfd5fcSRichard Henderson } else { 507b3dfd5fcSRichard Henderson tcg_out_mov(s, TCG_TYPE_I64, dst, src); 508b3dfd5fcSRichard Henderson } 509b3dfd5fcSRichard Henderson break; 510b3dfd5fcSRichard Henderson default: 511b3dfd5fcSRichard Henderson g_assert_not_reached(); 512b3dfd5fcSRichard Henderson } 513b3dfd5fcSRichard Henderson } 514b3dfd5fcSRichard Henderson 515129f1f9eSRichard Henderson /* Minor variations on a theme, using a structure. */ 516129f1f9eSRichard Henderson static void tcg_out_movext1_new_src(TCGContext *s, const TCGMovExtend *i, 517129f1f9eSRichard Henderson TCGReg src) 518129f1f9eSRichard Henderson { 519129f1f9eSRichard Henderson tcg_out_movext(s, i->dst_type, i->dst, i->src_type, i->src_ext, src); 520129f1f9eSRichard Henderson } 521129f1f9eSRichard Henderson 522129f1f9eSRichard Henderson static void tcg_out_movext1(TCGContext *s, const TCGMovExtend *i) 523129f1f9eSRichard Henderson { 524129f1f9eSRichard Henderson tcg_out_movext1_new_src(s, i, i->src); 525129f1f9eSRichard Henderson } 526129f1f9eSRichard Henderson 527129f1f9eSRichard Henderson /** 528129f1f9eSRichard Henderson * tcg_out_movext2 -- move and extend two pair 529129f1f9eSRichard Henderson * @s: tcg context 530129f1f9eSRichard Henderson * @i1: first move description 531129f1f9eSRichard Henderson * @i2: second move description 532129f1f9eSRichard Henderson * @scratch: temporary register, or -1 for none 533129f1f9eSRichard Henderson * 534129f1f9eSRichard Henderson * As tcg_out_movext, for both @i1 and @i2, caring for overlap 535129f1f9eSRichard Henderson * between the sources and destinations. 536129f1f9eSRichard Henderson */ 537129f1f9eSRichard Henderson 5388429a1caSRichard Henderson static void tcg_out_movext2(TCGContext *s, const TCGMovExtend *i1, 539129f1f9eSRichard Henderson const TCGMovExtend *i2, int scratch) 540129f1f9eSRichard Henderson { 541129f1f9eSRichard Henderson TCGReg src1 = i1->src; 542129f1f9eSRichard Henderson TCGReg src2 = i2->src; 543129f1f9eSRichard Henderson 544129f1f9eSRichard Henderson if (i1->dst != src2) { 545129f1f9eSRichard Henderson tcg_out_movext1(s, i1); 546129f1f9eSRichard Henderson tcg_out_movext1(s, i2); 547129f1f9eSRichard Henderson return; 548129f1f9eSRichard Henderson } 549129f1f9eSRichard Henderson if (i2->dst == src1) { 550129f1f9eSRichard Henderson TCGType src1_type = i1->src_type; 551129f1f9eSRichard Henderson TCGType src2_type = i2->src_type; 552129f1f9eSRichard Henderson 553129f1f9eSRichard Henderson if (tcg_out_xchg(s, MAX(src1_type, src2_type), src1, src2)) { 554129f1f9eSRichard Henderson /* The data is now in the correct registers, now extend. */ 555129f1f9eSRichard Henderson src1 = i2->src; 556129f1f9eSRichard Henderson src2 = i1->src; 557129f1f9eSRichard Henderson } else { 558129f1f9eSRichard Henderson tcg_debug_assert(scratch >= 0); 559129f1f9eSRichard Henderson tcg_out_mov(s, src1_type, scratch, src1); 560129f1f9eSRichard Henderson src1 = scratch; 561129f1f9eSRichard Henderson } 562129f1f9eSRichard Henderson } 563129f1f9eSRichard Henderson tcg_out_movext1_new_src(s, i2, src2); 564129f1f9eSRichard Henderson tcg_out_movext1_new_src(s, i1, src1); 565129f1f9eSRichard Henderson } 566129f1f9eSRichard Henderson 5672462e30eSRichard Henderson /** 5682462e30eSRichard Henderson * tcg_out_movext3 -- move and extend three pair 5692462e30eSRichard Henderson * @s: tcg context 5702462e30eSRichard Henderson * @i1: first move description 5712462e30eSRichard Henderson * @i2: second move description 5722462e30eSRichard Henderson * @i3: third move description 5732462e30eSRichard Henderson * @scratch: temporary register, or -1 for none 5742462e30eSRichard Henderson * 5752462e30eSRichard Henderson * As tcg_out_movext, for all of @i1, @i2 and @i3, caring for overlap 5762462e30eSRichard Henderson * between the sources and destinations. 5772462e30eSRichard Henderson */ 5782462e30eSRichard Henderson 5792462e30eSRichard Henderson static void tcg_out_movext3(TCGContext *s, const TCGMovExtend *i1, 5802462e30eSRichard Henderson const TCGMovExtend *i2, const TCGMovExtend *i3, 5812462e30eSRichard Henderson int scratch) 5822462e30eSRichard Henderson { 5832462e30eSRichard Henderson TCGReg src1 = i1->src; 5842462e30eSRichard Henderson TCGReg src2 = i2->src; 5852462e30eSRichard Henderson TCGReg src3 = i3->src; 5862462e30eSRichard Henderson 5872462e30eSRichard Henderson if (i1->dst != src2 && i1->dst != src3) { 5882462e30eSRichard Henderson tcg_out_movext1(s, i1); 5892462e30eSRichard Henderson tcg_out_movext2(s, i2, i3, scratch); 5902462e30eSRichard Henderson return; 5912462e30eSRichard Henderson } 5922462e30eSRichard Henderson if (i2->dst != src1 && i2->dst != src3) { 5932462e30eSRichard Henderson tcg_out_movext1(s, i2); 5942462e30eSRichard Henderson tcg_out_movext2(s, i1, i3, scratch); 5952462e30eSRichard Henderson return; 5962462e30eSRichard Henderson } 5972462e30eSRichard Henderson if (i3->dst != src1 && i3->dst != src2) { 5982462e30eSRichard Henderson tcg_out_movext1(s, i3); 5992462e30eSRichard Henderson tcg_out_movext2(s, i1, i2, scratch); 6002462e30eSRichard Henderson return; 6012462e30eSRichard Henderson } 6022462e30eSRichard Henderson 6032462e30eSRichard Henderson /* 6042462e30eSRichard Henderson * There is a cycle. Since there are only 3 nodes, the cycle is 6052462e30eSRichard Henderson * either "clockwise" or "anti-clockwise", and can be solved with 6062462e30eSRichard Henderson * a single scratch or two xchg. 6072462e30eSRichard Henderson */ 6082462e30eSRichard Henderson if (i1->dst == src2 && i2->dst == src3 && i3->dst == src1) { 6092462e30eSRichard Henderson /* "Clockwise" */ 6102462e30eSRichard Henderson if (tcg_out_xchg(s, MAX(i1->src_type, i2->src_type), src1, src2)) { 6112462e30eSRichard Henderson tcg_out_xchg(s, MAX(i2->src_type, i3->src_type), src2, src3); 6122462e30eSRichard Henderson /* The data is now in the correct registers, now extend. */ 6132462e30eSRichard Henderson tcg_out_movext1_new_src(s, i1, i1->dst); 6142462e30eSRichard Henderson tcg_out_movext1_new_src(s, i2, i2->dst); 6152462e30eSRichard Henderson tcg_out_movext1_new_src(s, i3, i3->dst); 6162462e30eSRichard Henderson } else { 6172462e30eSRichard Henderson tcg_debug_assert(scratch >= 0); 6182462e30eSRichard Henderson tcg_out_mov(s, i1->src_type, scratch, src1); 6192462e30eSRichard Henderson tcg_out_movext1(s, i3); 6202462e30eSRichard Henderson tcg_out_movext1(s, i2); 6212462e30eSRichard Henderson tcg_out_movext1_new_src(s, i1, scratch); 6222462e30eSRichard Henderson } 6232462e30eSRichard Henderson } else if (i1->dst == src3 && i2->dst == src1 && i3->dst == src2) { 6242462e30eSRichard Henderson /* "Anti-clockwise" */ 6252462e30eSRichard Henderson if (tcg_out_xchg(s, MAX(i2->src_type, i3->src_type), src2, src3)) { 6262462e30eSRichard Henderson tcg_out_xchg(s, MAX(i1->src_type, i2->src_type), src1, src2); 6272462e30eSRichard Henderson /* The data is now in the correct registers, now extend. */ 6282462e30eSRichard Henderson tcg_out_movext1_new_src(s, i1, i1->dst); 6292462e30eSRichard Henderson tcg_out_movext1_new_src(s, i2, i2->dst); 6302462e30eSRichard Henderson tcg_out_movext1_new_src(s, i3, i3->dst); 6312462e30eSRichard Henderson } else { 6322462e30eSRichard Henderson tcg_debug_assert(scratch >= 0); 6332462e30eSRichard Henderson tcg_out_mov(s, i1->src_type, scratch, src1); 6342462e30eSRichard Henderson tcg_out_movext1(s, i2); 6352462e30eSRichard Henderson tcg_out_movext1(s, i3); 6362462e30eSRichard Henderson tcg_out_movext1_new_src(s, i1, scratch); 6372462e30eSRichard Henderson } 6382462e30eSRichard Henderson } else { 6392462e30eSRichard Henderson g_assert_not_reached(); 6402462e30eSRichard Henderson } 6412462e30eSRichard Henderson } 6422462e30eSRichard Henderson 643a417ef83SRichard Henderson /* 644a417ef83SRichard Henderson * Allocate a new TCGLabelQemuLdst entry. 645a417ef83SRichard Henderson */ 646a417ef83SRichard Henderson 647a417ef83SRichard Henderson __attribute__((unused)) 648a417ef83SRichard Henderson static TCGLabelQemuLdst *new_ldst_label(TCGContext *s) 649a417ef83SRichard Henderson { 650a417ef83SRichard Henderson TCGLabelQemuLdst *l = tcg_malloc(sizeof(*l)); 651a417ef83SRichard Henderson 652a417ef83SRichard Henderson memset(l, 0, sizeof(*l)); 653a417ef83SRichard Henderson QSIMPLEQ_INSERT_TAIL(&s->ldst_labels, l, next); 654a417ef83SRichard Henderson 655a417ef83SRichard Henderson return l; 656a417ef83SRichard Henderson } 657a417ef83SRichard Henderson 658a417ef83SRichard Henderson /* 659a417ef83SRichard Henderson * Allocate new constant pool entries. 660a417ef83SRichard Henderson */ 661a417ef83SRichard Henderson 662a417ef83SRichard Henderson typedef struct TCGLabelPoolData { 663a417ef83SRichard Henderson struct TCGLabelPoolData *next; 664a417ef83SRichard Henderson tcg_insn_unit *label; 665a417ef83SRichard Henderson intptr_t addend; 666a417ef83SRichard Henderson int rtype; 667a417ef83SRichard Henderson unsigned nlong; 668a417ef83SRichard Henderson tcg_target_ulong data[]; 669a417ef83SRichard Henderson } TCGLabelPoolData; 670a417ef83SRichard Henderson 671a417ef83SRichard Henderson static TCGLabelPoolData *new_pool_alloc(TCGContext *s, int nlong, int rtype, 672a417ef83SRichard Henderson tcg_insn_unit *label, intptr_t addend) 673a417ef83SRichard Henderson { 674a417ef83SRichard Henderson TCGLabelPoolData *n = tcg_malloc(sizeof(TCGLabelPoolData) 675a417ef83SRichard Henderson + sizeof(tcg_target_ulong) * nlong); 676a417ef83SRichard Henderson 677a417ef83SRichard Henderson n->label = label; 678a417ef83SRichard Henderson n->addend = addend; 679a417ef83SRichard Henderson n->rtype = rtype; 680a417ef83SRichard Henderson n->nlong = nlong; 681a417ef83SRichard Henderson return n; 682a417ef83SRichard Henderson } 683a417ef83SRichard Henderson 684a417ef83SRichard Henderson static void new_pool_insert(TCGContext *s, TCGLabelPoolData *n) 685a417ef83SRichard Henderson { 686a417ef83SRichard Henderson TCGLabelPoolData *i, **pp; 687a417ef83SRichard Henderson int nlong = n->nlong; 688a417ef83SRichard Henderson 689a417ef83SRichard Henderson /* Insertion sort on the pool. */ 690a417ef83SRichard Henderson for (pp = &s->pool_labels; (i = *pp) != NULL; pp = &i->next) { 691a417ef83SRichard Henderson if (nlong > i->nlong) { 692a417ef83SRichard Henderson break; 693a417ef83SRichard Henderson } 694a417ef83SRichard Henderson if (nlong < i->nlong) { 695a417ef83SRichard Henderson continue; 696a417ef83SRichard Henderson } 697a417ef83SRichard Henderson if (memcmp(n->data, i->data, sizeof(tcg_target_ulong) * nlong) >= 0) { 698a417ef83SRichard Henderson break; 699a417ef83SRichard Henderson } 700a417ef83SRichard Henderson } 701a417ef83SRichard Henderson n->next = *pp; 702a417ef83SRichard Henderson *pp = n; 703a417ef83SRichard Henderson } 704a417ef83SRichard Henderson 705a417ef83SRichard Henderson /* The "usual" for generic integer code. */ 706a417ef83SRichard Henderson __attribute__((unused)) 707a417ef83SRichard Henderson static void new_pool_label(TCGContext *s, tcg_target_ulong d, int rtype, 708a417ef83SRichard Henderson tcg_insn_unit *label, intptr_t addend) 709a417ef83SRichard Henderson { 710a417ef83SRichard Henderson TCGLabelPoolData *n = new_pool_alloc(s, 1, rtype, label, addend); 711a417ef83SRichard Henderson n->data[0] = d; 712a417ef83SRichard Henderson new_pool_insert(s, n); 713a417ef83SRichard Henderson } 714a417ef83SRichard Henderson 715a417ef83SRichard Henderson /* For v64 or v128, depending on the host. */ 716a417ef83SRichard Henderson __attribute__((unused)) 717a417ef83SRichard Henderson static void new_pool_l2(TCGContext *s, int rtype, tcg_insn_unit *label, 718a417ef83SRichard Henderson intptr_t addend, tcg_target_ulong d0, 719a417ef83SRichard Henderson tcg_target_ulong d1) 720a417ef83SRichard Henderson { 721a417ef83SRichard Henderson TCGLabelPoolData *n = new_pool_alloc(s, 2, rtype, label, addend); 722a417ef83SRichard Henderson n->data[0] = d0; 723a417ef83SRichard Henderson n->data[1] = d1; 724a417ef83SRichard Henderson new_pool_insert(s, n); 725a417ef83SRichard Henderson } 726a417ef83SRichard Henderson 727a417ef83SRichard Henderson /* For v128 or v256, depending on the host. */ 728a417ef83SRichard Henderson __attribute__((unused)) 729a417ef83SRichard Henderson static void new_pool_l4(TCGContext *s, int rtype, tcg_insn_unit *label, 730a417ef83SRichard Henderson intptr_t addend, tcg_target_ulong d0, 731a417ef83SRichard Henderson tcg_target_ulong d1, tcg_target_ulong d2, 732a417ef83SRichard Henderson tcg_target_ulong d3) 733a417ef83SRichard Henderson { 734a417ef83SRichard Henderson TCGLabelPoolData *n = new_pool_alloc(s, 4, rtype, label, addend); 735a417ef83SRichard Henderson n->data[0] = d0; 736a417ef83SRichard Henderson n->data[1] = d1; 737a417ef83SRichard Henderson n->data[2] = d2; 738a417ef83SRichard Henderson n->data[3] = d3; 739a417ef83SRichard Henderson new_pool_insert(s, n); 740a417ef83SRichard Henderson } 741a417ef83SRichard Henderson 742a417ef83SRichard Henderson /* For v256, for 32-bit host. */ 743a417ef83SRichard Henderson __attribute__((unused)) 744a417ef83SRichard Henderson static void new_pool_l8(TCGContext *s, int rtype, tcg_insn_unit *label, 745a417ef83SRichard Henderson intptr_t addend, tcg_target_ulong d0, 746a417ef83SRichard Henderson tcg_target_ulong d1, tcg_target_ulong d2, 747a417ef83SRichard Henderson tcg_target_ulong d3, tcg_target_ulong d4, 748a417ef83SRichard Henderson tcg_target_ulong d5, tcg_target_ulong d6, 749a417ef83SRichard Henderson tcg_target_ulong d7) 750a417ef83SRichard Henderson { 751a417ef83SRichard Henderson TCGLabelPoolData *n = new_pool_alloc(s, 8, rtype, label, addend); 752a417ef83SRichard Henderson n->data[0] = d0; 753a417ef83SRichard Henderson n->data[1] = d1; 754a417ef83SRichard Henderson n->data[2] = d2; 755a417ef83SRichard Henderson n->data[3] = d3; 756a417ef83SRichard Henderson n->data[4] = d4; 757a417ef83SRichard Henderson n->data[5] = d5; 758a417ef83SRichard Henderson n->data[6] = d6; 759a417ef83SRichard Henderson n->data[7] = d7; 760a417ef83SRichard Henderson new_pool_insert(s, n); 761a417ef83SRichard Henderson } 762a417ef83SRichard Henderson 763a417ef83SRichard Henderson /* 764a417ef83SRichard Henderson * Generate TB finalization at the end of block 765a417ef83SRichard Henderson */ 766a417ef83SRichard Henderson 767a417ef83SRichard Henderson static int tcg_out_ldst_finalize(TCGContext *s) 768a417ef83SRichard Henderson { 769a417ef83SRichard Henderson TCGLabelQemuLdst *lb; 770a417ef83SRichard Henderson 771a417ef83SRichard Henderson /* qemu_ld/st slow paths */ 772a417ef83SRichard Henderson QSIMPLEQ_FOREACH(lb, &s->ldst_labels, next) { 773a417ef83SRichard Henderson if (lb->is_ld 774a417ef83SRichard Henderson ? !tcg_out_qemu_ld_slow_path(s, lb) 775a417ef83SRichard Henderson : !tcg_out_qemu_st_slow_path(s, lb)) { 776a417ef83SRichard Henderson return -2; 777a417ef83SRichard Henderson } 778a417ef83SRichard Henderson 779a417ef83SRichard Henderson /* 780a417ef83SRichard Henderson * Test for (pending) buffer overflow. The assumption is that any 781a417ef83SRichard Henderson * one operation beginning below the high water mark cannot overrun 782a417ef83SRichard Henderson * the buffer completely. Thus we can test for overflow after 783a417ef83SRichard Henderson * generating code without having to check during generation. 784a417ef83SRichard Henderson */ 785a417ef83SRichard Henderson if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) { 786a417ef83SRichard Henderson return -1; 787a417ef83SRichard Henderson } 788a417ef83SRichard Henderson } 789a417ef83SRichard Henderson return 0; 790a417ef83SRichard Henderson } 791a417ef83SRichard Henderson 792a417ef83SRichard Henderson static int tcg_out_pool_finalize(TCGContext *s) 793a417ef83SRichard Henderson { 794a417ef83SRichard Henderson TCGLabelPoolData *p = s->pool_labels; 795a417ef83SRichard Henderson TCGLabelPoolData *l = NULL; 796a417ef83SRichard Henderson void *a; 797a417ef83SRichard Henderson 798a417ef83SRichard Henderson if (p == NULL) { 799a417ef83SRichard Henderson return 0; 800a417ef83SRichard Henderson } 801a417ef83SRichard Henderson 802a417ef83SRichard Henderson /* 803a417ef83SRichard Henderson * ??? Round up to qemu_icache_linesize, but then do not round 804a417ef83SRichard Henderson * again when allocating the next TranslationBlock structure. 805a417ef83SRichard Henderson */ 806a417ef83SRichard Henderson a = (void *)ROUND_UP((uintptr_t)s->code_ptr, 807a417ef83SRichard Henderson sizeof(tcg_target_ulong) * p->nlong); 808a417ef83SRichard Henderson tcg_out_nop_fill(s->code_ptr, (tcg_insn_unit *)a - s->code_ptr); 809a417ef83SRichard Henderson s->data_gen_ptr = a; 810a417ef83SRichard Henderson 811a417ef83SRichard Henderson for (; p != NULL; p = p->next) { 812a417ef83SRichard Henderson size_t size = sizeof(tcg_target_ulong) * p->nlong; 813a417ef83SRichard Henderson uintptr_t value; 814a417ef83SRichard Henderson 815a417ef83SRichard Henderson if (!l || l->nlong != p->nlong || memcmp(l->data, p->data, size)) { 816a417ef83SRichard Henderson if (unlikely(a > s->code_gen_highwater)) { 817a417ef83SRichard Henderson return -1; 818a417ef83SRichard Henderson } 819a417ef83SRichard Henderson memcpy(a, p->data, size); 820a417ef83SRichard Henderson a += size; 821a417ef83SRichard Henderson l = p; 822a417ef83SRichard Henderson } 823a417ef83SRichard Henderson 824a417ef83SRichard Henderson value = (uintptr_t)tcg_splitwx_to_rx(a) - size; 825a417ef83SRichard Henderson if (!patch_reloc(p->label, p->rtype, value, p->addend)) { 826a417ef83SRichard Henderson return -2; 827a417ef83SRichard Henderson } 828a417ef83SRichard Henderson } 829a417ef83SRichard Henderson 830a417ef83SRichard Henderson s->code_ptr = a; 831a417ef83SRichard Henderson return 0; 832a417ef83SRichard Henderson } 833a417ef83SRichard Henderson 8344c22e840SRichard Henderson #define C_PFX1(P, A) P##A 8354c22e840SRichard Henderson #define C_PFX2(P, A, B) P##A##_##B 8364c22e840SRichard Henderson #define C_PFX3(P, A, B, C) P##A##_##B##_##C 8374c22e840SRichard Henderson #define C_PFX4(P, A, B, C, D) P##A##_##B##_##C##_##D 8384c22e840SRichard Henderson #define C_PFX5(P, A, B, C, D, E) P##A##_##B##_##C##_##D##_##E 8394c22e840SRichard Henderson #define C_PFX6(P, A, B, C, D, E, F) P##A##_##B##_##C##_##D##_##E##_##F 8404c22e840SRichard Henderson 8414c22e840SRichard Henderson /* Define an enumeration for the various combinations. */ 8424c22e840SRichard Henderson 8434c22e840SRichard Henderson #define C_O0_I1(I1) C_PFX1(c_o0_i1_, I1), 8444c22e840SRichard Henderson #define C_O0_I2(I1, I2) C_PFX2(c_o0_i2_, I1, I2), 8454c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3) C_PFX3(c_o0_i3_, I1, I2, I3), 8464c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4) C_PFX4(c_o0_i4_, I1, I2, I3, I4), 8474c22e840SRichard Henderson 8484c22e840SRichard Henderson #define C_O1_I1(O1, I1) C_PFX2(c_o1_i1_, O1, I1), 8494c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2) C_PFX3(c_o1_i2_, O1, I1, I2), 8504c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3) C_PFX4(c_o1_i3_, O1, I1, I2, I3), 8514c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4) C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4), 8524c22e840SRichard Henderson 8534c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2) C_PFX3(c_n1_i2_, O1, I1, I2), 854ca5bed07SRichard Henderson #define C_N1O1_I1(O1, O2, I1) C_PFX3(c_n1o1_i1_, O1, O2, I1), 855fa645b48SRichard Henderson #define C_N2_I1(O1, O2, I1) C_PFX3(c_n2_i1_, O1, O2, I1), 8564c22e840SRichard Henderson 8574c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1) C_PFX3(c_o2_i1_, O1, O2, I1), 8584c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2) C_PFX4(c_o2_i2_, O1, O2, I1, I2), 8594c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3) C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3), 8604c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4), 86122d2e535SIlya Leoshkevich #define C_N1_O1_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_n1_o1_i4_, O1, O2, I1, I2, I3, I4), 8624c22e840SRichard Henderson 8634c22e840SRichard Henderson typedef enum { 8645500bd9eSRichard Henderson C_Dynamic = -2, 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 9585500bd9eSRichard Henderson /* 9595500bd9eSRichard Henderson * TCGOutOp is the base class for a set of structures that describe how 9605500bd9eSRichard Henderson * to generate code for a given TCGOpcode. 9615500bd9eSRichard Henderson * 9625500bd9eSRichard Henderson * @static_constraint: 9635500bd9eSRichard Henderson * C_NotImplemented: The TCGOpcode is not supported by the backend. 9645500bd9eSRichard Henderson * C_Dynamic: Use @dynamic_constraint to select a constraint set 9655500bd9eSRichard Henderson * based on any of @type, @flags, or host isa. 9665500bd9eSRichard Henderson * Otherwise: The register allocation constrains for the TCGOpcode. 9675500bd9eSRichard Henderson * 9685500bd9eSRichard Henderson * Subclasses of TCGOutOp will define a set of output routines that may 9695500bd9eSRichard Henderson * be used. Such routines will often be selected by the set of registers 9705500bd9eSRichard Henderson * and constants that come out of register allocation. The set of 9715500bd9eSRichard Henderson * routines that are provided will guide the set of constraints that are 9725500bd9eSRichard Henderson * legal. In particular, assume that tcg_optimize() has done its job in 9735500bd9eSRichard Henderson * swapping commutative operands and folding operations for which all 9745500bd9eSRichard Henderson * operands are constant. 9755500bd9eSRichard Henderson */ 9765500bd9eSRichard Henderson typedef struct TCGOutOp { 9775500bd9eSRichard Henderson TCGConstraintSetIndex static_constraint; 9785500bd9eSRichard Henderson TCGConstraintSetIndex (*dynamic_constraint)(TCGType type, unsigned flags); 9795500bd9eSRichard Henderson } TCGOutOp; 9805500bd9eSRichard Henderson 981662cdbcfSRichard Henderson typedef struct TCGOutOpBinary { 982662cdbcfSRichard Henderson TCGOutOp base; 983662cdbcfSRichard Henderson void (*out_rrr)(TCGContext *s, TCGType type, 984662cdbcfSRichard Henderson TCGReg a0, TCGReg a1, TCGReg a2); 985662cdbcfSRichard Henderson void (*out_rri)(TCGContext *s, TCGType type, 986662cdbcfSRichard Henderson TCGReg a0, TCGReg a1, tcg_target_long a2); 987662cdbcfSRichard Henderson } TCGOutOpBinary; 988662cdbcfSRichard Henderson 989e126a91cSRichard Henderson typedef struct TCGOutOpUnary { 990e126a91cSRichard Henderson TCGOutOp base; 991e126a91cSRichard Henderson void (*out_rr)(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1); 992e126a91cSRichard Henderson } TCGOutOpUnary; 993e126a91cSRichard Henderson 9943f057e24SRichard Henderson typedef struct TCGOutOpSubtract { 9953f057e24SRichard Henderson TCGOutOp base; 9963f057e24SRichard Henderson void (*out_rrr)(TCGContext *s, TCGType type, 9973f057e24SRichard Henderson TCGReg a0, TCGReg a1, TCGReg a2); 9983f057e24SRichard Henderson void (*out_rir)(TCGContext *s, TCGType type, 9993f057e24SRichard Henderson TCGReg a0, tcg_target_long a1, TCGReg a2); 10003f057e24SRichard Henderson } TCGOutOpSubtract; 10013f057e24SRichard Henderson 1002139c1837SPaolo Bonzini #include "tcg-target.c.inc" 1003c896fe29Sbellard 10047857ee11SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 10057857ee11SRichard Henderson /* Validate CPUTLBDescFast placement. */ 10067857ee11SRichard Henderson QEMU_BUILD_BUG_ON((int)(offsetof(CPUNegativeOffsetState, tlb.f[0]) - 10077857ee11SRichard Henderson sizeof(CPUNegativeOffsetState)) 10087857ee11SRichard Henderson < MIN_TLB_MASK_TABLE_OFS); 10097857ee11SRichard Henderson #endif 10107857ee11SRichard Henderson 1011662cdbcfSRichard Henderson /* 1012662cdbcfSRichard Henderson * Register V as the TCGOutOp for O. 1013662cdbcfSRichard Henderson * This verifies that V is of type T, otherwise give a nice compiler error. 1014662cdbcfSRichard Henderson * This prevents trivial mistakes within each arch/tcg-target.c.inc. 1015662cdbcfSRichard Henderson */ 1016662cdbcfSRichard Henderson #define OUTOP(O, T, V) [O] = _Generic(V, T: &V.base) 1017662cdbcfSRichard Henderson 10185500bd9eSRichard Henderson /* Register allocation descriptions for every TCGOpcode. */ 10195500bd9eSRichard Henderson static const TCGOutOp * const all_outop[NB_OPS] = { 102079602f63SRichard Henderson OUTOP(INDEX_op_add, TCGOutOpBinary, outop_add), 1021c3b920b3SRichard Henderson OUTOP(INDEX_op_and, TCGOutOpBinary, outop_and), 102246f96bffSRichard Henderson OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), 10235c0968a7SRichard Henderson OUTOP(INDEX_op_eqv, TCGOutOpBinary, outop_eqv), 1024d2c3ecadSRichard Henderson OUTOP(INDEX_op_mul, TCGOutOpBinary, outop_mul), 1025*c742824dSRichard Henderson OUTOP(INDEX_op_mulsh, TCGOutOpBinary, outop_mulsh), 1026aa28c9efSRichard Henderson OUTOP(INDEX_op_muluh, TCGOutOpBinary, outop_muluh), 102759379a45SRichard Henderson OUTOP(INDEX_op_nand, TCGOutOpBinary, outop_nand), 102869713587SRichard Henderson OUTOP(INDEX_op_neg, TCGOutOpUnary, outop_neg), 10293a8c4e9eSRichard Henderson OUTOP(INDEX_op_nor, TCGOutOpBinary, outop_nor), 10305c62d377SRichard Henderson OUTOP(INDEX_op_not, TCGOutOpUnary, outop_not), 103149bd7514SRichard Henderson OUTOP(INDEX_op_or, TCGOutOpBinary, outop_or), 10326aba25ebSRichard Henderson OUTOP(INDEX_op_orc, TCGOutOpBinary, outop_orc), 103360f34f55SRichard Henderson OUTOP(INDEX_op_sub, TCGOutOpSubtract, outop_sub), 1034fffd3dc9SRichard Henderson OUTOP(INDEX_op_xor, TCGOutOpBinary, outop_xor), 10355500bd9eSRichard Henderson }; 10365500bd9eSRichard Henderson 1037662cdbcfSRichard Henderson #undef OUTOP 1038662cdbcfSRichard Henderson 1039e8feb96fSEmilio G. Cota /* 10403468b59eSEmilio G. Cota * All TCG threads except the parent (i.e. the one that called tcg_context_init 10413468b59eSEmilio G. Cota * and registered the target's TCG globals) must register with this function 10423468b59eSEmilio G. Cota * before initiating translation. 10433468b59eSEmilio G. Cota * 10443468b59eSEmilio G. Cota * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation 10453468b59eSEmilio G. Cota * of tcg_region_init() for the reasoning behind this. 10463468b59eSEmilio G. Cota * 10477893e42dSPhilippe Mathieu-Daudé * In system-mode each caller registers its context in tcg_ctxs[]. Note that in 10487893e42dSPhilippe Mathieu-Daudé * system-mode tcg_ctxs[] does not track tcg_ctx_init, since the initial context 10493468b59eSEmilio G. Cota * is not used anymore for translation once this function is called. 10503468b59eSEmilio G. Cota * 10517893e42dSPhilippe Mathieu-Daudé * Not tracking tcg_init_ctx in tcg_ctxs[] in system-mode keeps code that 10527893e42dSPhilippe Mathieu-Daudé * iterates over the array (e.g. tcg_code_size() the same for both system/user 10537893e42dSPhilippe Mathieu-Daudé * modes. 10543468b59eSEmilio G. Cota */ 10553468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY 10563468b59eSEmilio G. Cota void tcg_register_thread(void) 10573468b59eSEmilio G. Cota { 10583468b59eSEmilio G. Cota tcg_ctx = &tcg_init_ctx; 10593468b59eSEmilio G. Cota } 10603468b59eSEmilio G. Cota #else 10613468b59eSEmilio G. Cota void tcg_register_thread(void) 10623468b59eSEmilio G. Cota { 10633468b59eSEmilio G. Cota TCGContext *s = g_malloc(sizeof(*s)); 10643468b59eSEmilio G. Cota unsigned int i, n; 10653468b59eSEmilio G. Cota 10663468b59eSEmilio G. Cota *s = tcg_init_ctx; 10673468b59eSEmilio G. Cota 10683468b59eSEmilio G. Cota /* Relink mem_base. */ 10693468b59eSEmilio G. Cota for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) { 10703468b59eSEmilio G. Cota if (tcg_init_ctx.temps[i].mem_base) { 10713468b59eSEmilio G. Cota ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps; 10723468b59eSEmilio G. Cota tcg_debug_assert(b >= 0 && b < n); 10733468b59eSEmilio G. Cota s->temps[i].mem_base = &s->temps[b]; 10743468b59eSEmilio G. Cota } 10753468b59eSEmilio G. Cota } 10763468b59eSEmilio G. Cota 10773468b59eSEmilio G. Cota /* Claim an entry in tcg_ctxs */ 10780e2d61cfSRichard Henderson n = qatomic_fetch_inc(&tcg_cur_ctxs); 10790e2d61cfSRichard Henderson g_assert(n < tcg_max_ctxs); 1080d73415a3SStefan Hajnoczi qatomic_set(&tcg_ctxs[n], s); 10813468b59eSEmilio G. Cota 108238b47b19SEmilio G. Cota if (n > 0) { 1083bf042e8eSRichard Henderson tcg_region_initial_alloc(s); 108438b47b19SEmilio G. Cota } 108538b47b19SEmilio G. Cota 10863468b59eSEmilio G. Cota tcg_ctx = s; 10873468b59eSEmilio G. Cota } 10883468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */ 10893468b59eSEmilio G. Cota 1090c896fe29Sbellard /* pool based memory allocation */ 1091c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size) 1092c896fe29Sbellard { 1093c896fe29Sbellard TCGPool *p; 1094c896fe29Sbellard int pool_size; 1095c896fe29Sbellard 1096c896fe29Sbellard if (size > TCG_POOL_CHUNK_SIZE) { 1097c896fe29Sbellard /* big malloc: insert a new pool (XXX: could optimize) */ 10987267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + size); 1099c896fe29Sbellard p->size = size; 11004055299eSKirill Batuzov p->next = s->pool_first_large; 11014055299eSKirill Batuzov s->pool_first_large = p; 11024055299eSKirill Batuzov return p->data; 1103c896fe29Sbellard } else { 1104c896fe29Sbellard p = s->pool_current; 1105c896fe29Sbellard if (!p) { 1106c896fe29Sbellard p = s->pool_first; 1107c896fe29Sbellard if (!p) 1108c896fe29Sbellard goto new_pool; 1109c896fe29Sbellard } else { 1110c896fe29Sbellard if (!p->next) { 1111c896fe29Sbellard new_pool: 1112c896fe29Sbellard pool_size = TCG_POOL_CHUNK_SIZE; 11137267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + pool_size); 1114c896fe29Sbellard p->size = pool_size; 1115c896fe29Sbellard p->next = NULL; 1116a813e36fSRichard Henderson if (s->pool_current) { 1117c896fe29Sbellard s->pool_current->next = p; 1118a813e36fSRichard Henderson } else { 1119c896fe29Sbellard s->pool_first = p; 1120a813e36fSRichard Henderson } 1121c896fe29Sbellard } else { 1122c896fe29Sbellard p = p->next; 1123c896fe29Sbellard } 1124c896fe29Sbellard } 1125c896fe29Sbellard } 1126c896fe29Sbellard s->pool_current = p; 1127c896fe29Sbellard s->pool_cur = p->data + size; 1128c896fe29Sbellard s->pool_end = p->data + p->size; 1129c896fe29Sbellard return p->data; 1130c896fe29Sbellard } 1131c896fe29Sbellard 1132c896fe29Sbellard void tcg_pool_reset(TCGContext *s) 1133c896fe29Sbellard { 11344055299eSKirill Batuzov TCGPool *p, *t; 11354055299eSKirill Batuzov for (p = s->pool_first_large; p; p = t) { 11364055299eSKirill Batuzov t = p->next; 11374055299eSKirill Batuzov g_free(p); 11384055299eSKirill Batuzov } 11394055299eSKirill Batuzov s->pool_first_large = NULL; 1140c896fe29Sbellard s->pool_cur = s->pool_end = NULL; 1141c896fe29Sbellard s->pool_current = NULL; 1142c896fe29Sbellard } 1143c896fe29Sbellard 11448429a1caSRichard Henderson /* 11458429a1caSRichard Henderson * Create TCGHelperInfo structures for "tcg/tcg-ldst.h" functions, 11468429a1caSRichard Henderson * akin to what "exec/helper-tcg.h" does with DEF_HELPER_FLAGS_N. 11478429a1caSRichard Henderson * We only use these for layout in tcg_out_ld_helper_ret and 11488429a1caSRichard Henderson * tcg_out_st_helper_args, and share them between several of 11498429a1caSRichard Henderson * the helpers, with the end result that it's easier to build manually. 11508429a1caSRichard Henderson */ 11518429a1caSRichard Henderson 11528429a1caSRichard Henderson #if TCG_TARGET_REG_BITS == 32 11538429a1caSRichard Henderson # define dh_typecode_ttl dh_typecode_i32 11548429a1caSRichard Henderson #else 11558429a1caSRichard Henderson # define dh_typecode_ttl dh_typecode_i64 11568429a1caSRichard Henderson #endif 11578429a1caSRichard Henderson 11588429a1caSRichard Henderson static TCGHelperInfo info_helper_ld32_mmu = { 11598429a1caSRichard Henderson .flags = TCG_CALL_NO_WG, 11608429a1caSRichard Henderson .typemask = dh_typemask(ttl, 0) /* return tcg_target_ulong */ 11618429a1caSRichard Henderson | dh_typemask(env, 1) 116224e46e6cSRichard Henderson | dh_typemask(i64, 2) /* uint64_t addr */ 11638429a1caSRichard Henderson | dh_typemask(i32, 3) /* unsigned oi */ 11648429a1caSRichard Henderson | dh_typemask(ptr, 4) /* uintptr_t ra */ 11658429a1caSRichard Henderson }; 11668429a1caSRichard Henderson 11678429a1caSRichard Henderson static TCGHelperInfo info_helper_ld64_mmu = { 11688429a1caSRichard Henderson .flags = TCG_CALL_NO_WG, 11698429a1caSRichard Henderson .typemask = dh_typemask(i64, 0) /* return uint64_t */ 11708429a1caSRichard Henderson | dh_typemask(env, 1) 117124e46e6cSRichard Henderson | dh_typemask(i64, 2) /* uint64_t addr */ 11728429a1caSRichard Henderson | dh_typemask(i32, 3) /* unsigned oi */ 11738429a1caSRichard Henderson | dh_typemask(ptr, 4) /* uintptr_t ra */ 11748429a1caSRichard Henderson }; 11758429a1caSRichard Henderson 1176ebebea53SRichard Henderson static TCGHelperInfo info_helper_ld128_mmu = { 1177ebebea53SRichard Henderson .flags = TCG_CALL_NO_WG, 1178ebebea53SRichard Henderson .typemask = dh_typemask(i128, 0) /* return Int128 */ 1179ebebea53SRichard Henderson | dh_typemask(env, 1) 118024e46e6cSRichard Henderson | dh_typemask(i64, 2) /* uint64_t addr */ 1181ebebea53SRichard Henderson | dh_typemask(i32, 3) /* unsigned oi */ 1182ebebea53SRichard Henderson | dh_typemask(ptr, 4) /* uintptr_t ra */ 1183ebebea53SRichard Henderson }; 1184ebebea53SRichard Henderson 11858429a1caSRichard Henderson static TCGHelperInfo info_helper_st32_mmu = { 11868429a1caSRichard Henderson .flags = TCG_CALL_NO_WG, 11878429a1caSRichard Henderson .typemask = dh_typemask(void, 0) 11888429a1caSRichard Henderson | dh_typemask(env, 1) 118924e46e6cSRichard Henderson | dh_typemask(i64, 2) /* uint64_t addr */ 11908429a1caSRichard Henderson | dh_typemask(i32, 3) /* uint32_t data */ 11918429a1caSRichard Henderson | dh_typemask(i32, 4) /* unsigned oi */ 11928429a1caSRichard Henderson | dh_typemask(ptr, 5) /* uintptr_t ra */ 11938429a1caSRichard Henderson }; 11948429a1caSRichard Henderson 11958429a1caSRichard Henderson static TCGHelperInfo info_helper_st64_mmu = { 11968429a1caSRichard Henderson .flags = TCG_CALL_NO_WG, 11978429a1caSRichard Henderson .typemask = dh_typemask(void, 0) 11988429a1caSRichard Henderson | dh_typemask(env, 1) 119924e46e6cSRichard Henderson | dh_typemask(i64, 2) /* uint64_t addr */ 12008429a1caSRichard Henderson | dh_typemask(i64, 3) /* uint64_t data */ 12018429a1caSRichard Henderson | dh_typemask(i32, 4) /* unsigned oi */ 12028429a1caSRichard Henderson | dh_typemask(ptr, 5) /* uintptr_t ra */ 12038429a1caSRichard Henderson }; 12048429a1caSRichard Henderson 1205ebebea53SRichard Henderson static TCGHelperInfo info_helper_st128_mmu = { 1206ebebea53SRichard Henderson .flags = TCG_CALL_NO_WG, 1207ebebea53SRichard Henderson .typemask = dh_typemask(void, 0) 1208ebebea53SRichard Henderson | dh_typemask(env, 1) 120924e46e6cSRichard Henderson | dh_typemask(i64, 2) /* uint64_t addr */ 1210ebebea53SRichard Henderson | dh_typemask(i128, 3) /* Int128 data */ 1211ebebea53SRichard Henderson | dh_typemask(i32, 4) /* unsigned oi */ 1212ebebea53SRichard Henderson | dh_typemask(ptr, 5) /* uintptr_t ra */ 1213ebebea53SRichard Henderson }; 1214ebebea53SRichard Henderson 121522f15579SRichard Henderson #ifdef CONFIG_TCG_INTERPRETER 1216c6ef8c7bSPhilippe Mathieu-Daudé static ffi_type *typecode_to_ffi(int argmask) 1217c6ef8c7bSPhilippe Mathieu-Daudé { 1218e9709e17SRichard Henderson /* 1219e9709e17SRichard Henderson * libffi does not support __int128_t, so we have forced Int128 1220e9709e17SRichard Henderson * to use the structure definition instead of the builtin type. 1221e9709e17SRichard Henderson */ 1222e9709e17SRichard Henderson static ffi_type *ffi_type_i128_elements[3] = { 1223e9709e17SRichard Henderson &ffi_type_uint64, 1224e9709e17SRichard Henderson &ffi_type_uint64, 1225e9709e17SRichard Henderson NULL 1226e9709e17SRichard Henderson }; 1227e9709e17SRichard Henderson static ffi_type ffi_type_i128 = { 1228e9709e17SRichard Henderson .size = 16, 1229e9709e17SRichard Henderson .alignment = __alignof__(Int128), 1230e9709e17SRichard Henderson .type = FFI_TYPE_STRUCT, 1231e9709e17SRichard Henderson .elements = ffi_type_i128_elements, 1232e9709e17SRichard Henderson }; 1233e9709e17SRichard Henderson 1234c6ef8c7bSPhilippe Mathieu-Daudé switch (argmask) { 1235c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_void: 1236c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_void; 1237c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_i32: 1238c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_uint32; 1239c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_s32: 1240c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_sint32; 1241c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_i64: 1242c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_uint64; 1243c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_s64: 1244c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_sint64; 1245c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_ptr: 1246c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_pointer; 1247e9709e17SRichard Henderson case dh_typecode_i128: 1248e9709e17SRichard Henderson return &ffi_type_i128; 1249c6ef8c7bSPhilippe Mathieu-Daudé } 1250c6ef8c7bSPhilippe Mathieu-Daudé g_assert_not_reached(); 1251c6ef8c7bSPhilippe Mathieu-Daudé } 12520c22e176SPhilippe Mathieu-Daudé 1253d53106c9SRichard Henderson static ffi_cif *init_ffi_layout(TCGHelperInfo *info) 12540c22e176SPhilippe Mathieu-Daudé { 1255f9c4bb80SRichard Henderson unsigned typemask = info->typemask; 12560c22e176SPhilippe Mathieu-Daudé struct { 12570c22e176SPhilippe Mathieu-Daudé ffi_cif cif; 12580c22e176SPhilippe Mathieu-Daudé ffi_type *args[]; 12590c22e176SPhilippe Mathieu-Daudé } *ca; 12600c22e176SPhilippe Mathieu-Daudé ffi_status status; 12610c22e176SPhilippe Mathieu-Daudé int nargs; 12620c22e176SPhilippe Mathieu-Daudé 12630c22e176SPhilippe Mathieu-Daudé /* Ignoring the return type, find the last non-zero field. */ 12640c22e176SPhilippe Mathieu-Daudé nargs = 32 - clz32(typemask >> 3); 12650c22e176SPhilippe Mathieu-Daudé nargs = DIV_ROUND_UP(nargs, 3); 1266e9709e17SRichard Henderson assert(nargs <= MAX_CALL_IARGS); 12670c22e176SPhilippe Mathieu-Daudé 12680c22e176SPhilippe Mathieu-Daudé ca = g_malloc0(sizeof(*ca) + nargs * sizeof(ffi_type *)); 12690c22e176SPhilippe Mathieu-Daudé ca->cif.rtype = typecode_to_ffi(typemask & 7); 12700c22e176SPhilippe Mathieu-Daudé ca->cif.nargs = nargs; 12710c22e176SPhilippe Mathieu-Daudé 12720c22e176SPhilippe Mathieu-Daudé if (nargs != 0) { 12730c22e176SPhilippe Mathieu-Daudé ca->cif.arg_types = ca->args; 12740c22e176SPhilippe Mathieu-Daudé for (int j = 0; j < nargs; ++j) { 12750c22e176SPhilippe Mathieu-Daudé int typecode = extract32(typemask, (j + 1) * 3, 3); 12760c22e176SPhilippe Mathieu-Daudé ca->args[j] = typecode_to_ffi(typecode); 12770c22e176SPhilippe Mathieu-Daudé } 12780c22e176SPhilippe Mathieu-Daudé } 12790c22e176SPhilippe Mathieu-Daudé 12800c22e176SPhilippe Mathieu-Daudé status = ffi_prep_cif(&ca->cif, FFI_DEFAULT_ABI, nargs, 12810c22e176SPhilippe Mathieu-Daudé ca->cif.rtype, ca->cif.arg_types); 12820c22e176SPhilippe Mathieu-Daudé assert(status == FFI_OK); 12830c22e176SPhilippe Mathieu-Daudé 1284d53106c9SRichard Henderson return &ca->cif; 12850c22e176SPhilippe Mathieu-Daudé } 1286f9c4bb80SRichard Henderson 1287d53106c9SRichard Henderson #define HELPER_INFO_INIT(I) (&(I)->cif) 1288d53106c9SRichard Henderson #define HELPER_INFO_INIT_VAL(I) init_ffi_layout(I) 1289d53106c9SRichard Henderson #else 1290d53106c9SRichard Henderson #define HELPER_INFO_INIT(I) (&(I)->init) 1291d53106c9SRichard Henderson #define HELPER_INFO_INIT_VAL(I) 1 12920c22e176SPhilippe Mathieu-Daudé #endif /* CONFIG_TCG_INTERPRETER */ 129322f15579SRichard Henderson 1294338b61e9SRichard Henderson static inline bool arg_slot_reg_p(unsigned arg_slot) 1295338b61e9SRichard Henderson { 1296338b61e9SRichard Henderson /* 1297338b61e9SRichard Henderson * Split the sizeof away from the comparison to avoid Werror from 1298338b61e9SRichard Henderson * "unsigned < 0 is always false", when iarg_regs is empty. 1299338b61e9SRichard Henderson */ 1300338b61e9SRichard Henderson unsigned nreg = ARRAY_SIZE(tcg_target_call_iarg_regs); 1301338b61e9SRichard Henderson return arg_slot < nreg; 1302338b61e9SRichard Henderson } 1303338b61e9SRichard Henderson 1304d78e4a4fSRichard Henderson static inline int arg_slot_stk_ofs(unsigned arg_slot) 1305d78e4a4fSRichard Henderson { 1306d78e4a4fSRichard Henderson unsigned max = TCG_STATIC_CALL_ARGS_SIZE / sizeof(tcg_target_long); 1307d78e4a4fSRichard Henderson unsigned stk_slot = arg_slot - ARRAY_SIZE(tcg_target_call_iarg_regs); 1308d78e4a4fSRichard Henderson 1309d78e4a4fSRichard Henderson tcg_debug_assert(stk_slot < max); 1310d78e4a4fSRichard Henderson return TCG_TARGET_CALL_STACK_OFFSET + stk_slot * sizeof(tcg_target_long); 1311d78e4a4fSRichard Henderson } 1312d78e4a4fSRichard Henderson 131339004a71SRichard Henderson typedef struct TCGCumulativeArgs { 131439004a71SRichard Henderson int arg_idx; /* tcg_gen_callN args[] */ 131539004a71SRichard Henderson int info_in_idx; /* TCGHelperInfo in[] */ 131639004a71SRichard Henderson int arg_slot; /* regs+stack slot */ 131739004a71SRichard Henderson int ref_slot; /* stack slots for references */ 131839004a71SRichard Henderson } TCGCumulativeArgs; 131939004a71SRichard Henderson 132039004a71SRichard Henderson static void layout_arg_even(TCGCumulativeArgs *cum) 132139004a71SRichard Henderson { 132239004a71SRichard Henderson cum->arg_slot += cum->arg_slot & 1; 132339004a71SRichard Henderson } 132439004a71SRichard Henderson 132539004a71SRichard Henderson static void layout_arg_1(TCGCumulativeArgs *cum, TCGHelperInfo *info, 132639004a71SRichard Henderson TCGCallArgumentKind kind) 132739004a71SRichard Henderson { 132839004a71SRichard Henderson TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx]; 132939004a71SRichard Henderson 133039004a71SRichard Henderson *loc = (TCGCallArgumentLoc){ 133139004a71SRichard Henderson .kind = kind, 133239004a71SRichard Henderson .arg_idx = cum->arg_idx, 133339004a71SRichard Henderson .arg_slot = cum->arg_slot, 133439004a71SRichard Henderson }; 133539004a71SRichard Henderson cum->info_in_idx++; 133639004a71SRichard Henderson cum->arg_slot++; 133739004a71SRichard Henderson } 133839004a71SRichard Henderson 133939004a71SRichard Henderson static void layout_arg_normal_n(TCGCumulativeArgs *cum, 134039004a71SRichard Henderson TCGHelperInfo *info, int n) 134139004a71SRichard Henderson { 134239004a71SRichard Henderson TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx]; 134339004a71SRichard Henderson 134439004a71SRichard Henderson for (int i = 0; i < n; ++i) { 134539004a71SRichard Henderson /* Layout all using the same arg_idx, adjusting the subindex. */ 134639004a71SRichard Henderson loc[i] = (TCGCallArgumentLoc){ 134739004a71SRichard Henderson .kind = TCG_CALL_ARG_NORMAL, 134839004a71SRichard Henderson .arg_idx = cum->arg_idx, 134939004a71SRichard Henderson .tmp_subindex = i, 135039004a71SRichard Henderson .arg_slot = cum->arg_slot + i, 135139004a71SRichard Henderson }; 135239004a71SRichard Henderson } 135339004a71SRichard Henderson cum->info_in_idx += n; 135439004a71SRichard Henderson cum->arg_slot += n; 135539004a71SRichard Henderson } 135639004a71SRichard Henderson 1357313bdea8SRichard Henderson static void layout_arg_by_ref(TCGCumulativeArgs *cum, TCGHelperInfo *info) 1358313bdea8SRichard Henderson { 1359313bdea8SRichard Henderson TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx]; 1360313bdea8SRichard Henderson int n = 128 / TCG_TARGET_REG_BITS; 1361313bdea8SRichard Henderson 1362313bdea8SRichard Henderson /* The first subindex carries the pointer. */ 1363313bdea8SRichard Henderson layout_arg_1(cum, info, TCG_CALL_ARG_BY_REF); 1364313bdea8SRichard Henderson 1365313bdea8SRichard Henderson /* 1366313bdea8SRichard Henderson * The callee is allowed to clobber memory associated with 1367313bdea8SRichard Henderson * structure pass by-reference. Therefore we must make copies. 1368313bdea8SRichard Henderson * Allocate space from "ref_slot", which will be adjusted to 1369313bdea8SRichard Henderson * follow the parameters on the stack. 1370313bdea8SRichard Henderson */ 1371313bdea8SRichard Henderson loc[0].ref_slot = cum->ref_slot; 1372313bdea8SRichard Henderson 1373313bdea8SRichard Henderson /* 1374313bdea8SRichard Henderson * Subsequent words also go into the reference slot, but 1375313bdea8SRichard Henderson * do not accumulate into the regular arguments. 1376313bdea8SRichard Henderson */ 1377313bdea8SRichard Henderson for (int i = 1; i < n; ++i) { 1378313bdea8SRichard Henderson loc[i] = (TCGCallArgumentLoc){ 1379313bdea8SRichard Henderson .kind = TCG_CALL_ARG_BY_REF_N, 1380313bdea8SRichard Henderson .arg_idx = cum->arg_idx, 1381313bdea8SRichard Henderson .tmp_subindex = i, 1382313bdea8SRichard Henderson .ref_slot = cum->ref_slot + i, 1383313bdea8SRichard Henderson }; 1384313bdea8SRichard Henderson } 1385e18ed26cSRichard Henderson cum->info_in_idx += n - 1; /* i=0 accounted for in layout_arg_1 */ 1386313bdea8SRichard Henderson cum->ref_slot += n; 1387313bdea8SRichard Henderson } 1388313bdea8SRichard Henderson 138939004a71SRichard Henderson static void init_call_layout(TCGHelperInfo *info) 139039004a71SRichard Henderson { 139139004a71SRichard Henderson int max_reg_slots = ARRAY_SIZE(tcg_target_call_iarg_regs); 139239004a71SRichard Henderson int max_stk_slots = TCG_STATIC_CALL_ARGS_SIZE / sizeof(tcg_target_long); 139339004a71SRichard Henderson unsigned typemask = info->typemask; 139439004a71SRichard Henderson unsigned typecode; 139539004a71SRichard Henderson TCGCumulativeArgs cum = { }; 139639004a71SRichard Henderson 139739004a71SRichard Henderson /* 139839004a71SRichard Henderson * Parse and place any function return value. 139939004a71SRichard Henderson */ 140039004a71SRichard Henderson typecode = typemask & 7; 140139004a71SRichard Henderson switch (typecode) { 140239004a71SRichard Henderson case dh_typecode_void: 140339004a71SRichard Henderson info->nr_out = 0; 140439004a71SRichard Henderson break; 140539004a71SRichard Henderson case dh_typecode_i32: 140639004a71SRichard Henderson case dh_typecode_s32: 140739004a71SRichard Henderson case dh_typecode_ptr: 140839004a71SRichard Henderson info->nr_out = 1; 140939004a71SRichard Henderson info->out_kind = TCG_CALL_RET_NORMAL; 141039004a71SRichard Henderson break; 141139004a71SRichard Henderson case dh_typecode_i64: 141239004a71SRichard Henderson case dh_typecode_s64: 141339004a71SRichard Henderson info->nr_out = 64 / TCG_TARGET_REG_BITS; 141439004a71SRichard Henderson info->out_kind = TCG_CALL_RET_NORMAL; 14155e3d0c19SRichard Henderson /* Query the last register now to trigger any assert early. */ 14165e3d0c19SRichard Henderson tcg_target_call_oarg_reg(info->out_kind, info->nr_out - 1); 1417466d3759SRichard Henderson break; 1418466d3759SRichard Henderson case dh_typecode_i128: 1419466d3759SRichard Henderson info->nr_out = 128 / TCG_TARGET_REG_BITS; 14205427a9a7SRichard Henderson info->out_kind = TCG_TARGET_CALL_RET_I128; 14215427a9a7SRichard Henderson switch (TCG_TARGET_CALL_RET_I128) { 1422466d3759SRichard Henderson case TCG_CALL_RET_NORMAL: 14235e3d0c19SRichard Henderson /* Query the last register now to trigger any assert early. */ 14245e3d0c19SRichard Henderson tcg_target_call_oarg_reg(info->out_kind, info->nr_out - 1); 1425466d3759SRichard Henderson break; 1426c6556aa0SRichard Henderson case TCG_CALL_RET_BY_VEC: 1427c6556aa0SRichard Henderson /* Query the single register now to trigger any assert early. */ 1428c6556aa0SRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0); 1429c6556aa0SRichard Henderson break; 1430313bdea8SRichard Henderson case TCG_CALL_RET_BY_REF: 1431313bdea8SRichard Henderson /* 1432313bdea8SRichard Henderson * Allocate the first argument to the output. 1433313bdea8SRichard Henderson * We don't need to store this anywhere, just make it 1434313bdea8SRichard Henderson * unavailable for use in the input loop below. 1435313bdea8SRichard Henderson */ 1436313bdea8SRichard Henderson cum.arg_slot = 1; 1437313bdea8SRichard Henderson break; 1438466d3759SRichard Henderson default: 1439466d3759SRichard Henderson qemu_build_not_reached(); 1440466d3759SRichard Henderson } 144139004a71SRichard Henderson break; 144239004a71SRichard Henderson default: 144339004a71SRichard Henderson g_assert_not_reached(); 144439004a71SRichard Henderson } 144539004a71SRichard Henderson 144639004a71SRichard Henderson /* 144739004a71SRichard Henderson * Parse and place function arguments. 144839004a71SRichard Henderson */ 144939004a71SRichard Henderson for (typemask >>= 3; typemask; typemask >>= 3, cum.arg_idx++) { 145039004a71SRichard Henderson TCGCallArgumentKind kind; 145139004a71SRichard Henderson TCGType type; 145239004a71SRichard Henderson 145339004a71SRichard Henderson typecode = typemask & 7; 145439004a71SRichard Henderson switch (typecode) { 145539004a71SRichard Henderson case dh_typecode_i32: 145639004a71SRichard Henderson case dh_typecode_s32: 145739004a71SRichard Henderson type = TCG_TYPE_I32; 145839004a71SRichard Henderson break; 145939004a71SRichard Henderson case dh_typecode_i64: 146039004a71SRichard Henderson case dh_typecode_s64: 146139004a71SRichard Henderson type = TCG_TYPE_I64; 146239004a71SRichard Henderson break; 146339004a71SRichard Henderson case dh_typecode_ptr: 146439004a71SRichard Henderson type = TCG_TYPE_PTR; 146539004a71SRichard Henderson break; 1466466d3759SRichard Henderson case dh_typecode_i128: 1467466d3759SRichard Henderson type = TCG_TYPE_I128; 1468466d3759SRichard Henderson break; 146939004a71SRichard Henderson default: 147039004a71SRichard Henderson g_assert_not_reached(); 147139004a71SRichard Henderson } 147239004a71SRichard Henderson 147339004a71SRichard Henderson switch (type) { 147439004a71SRichard Henderson case TCG_TYPE_I32: 147539004a71SRichard Henderson switch (TCG_TARGET_CALL_ARG_I32) { 147639004a71SRichard Henderson case TCG_CALL_ARG_EVEN: 147739004a71SRichard Henderson layout_arg_even(&cum); 147839004a71SRichard Henderson /* fall through */ 147939004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 148039004a71SRichard Henderson layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL); 148139004a71SRichard Henderson break; 148239004a71SRichard Henderson case TCG_CALL_ARG_EXTEND: 148339004a71SRichard Henderson kind = TCG_CALL_ARG_EXTEND_U + (typecode & 1); 148439004a71SRichard Henderson layout_arg_1(&cum, info, kind); 148539004a71SRichard Henderson break; 148639004a71SRichard Henderson default: 148739004a71SRichard Henderson qemu_build_not_reached(); 148839004a71SRichard Henderson } 148939004a71SRichard Henderson break; 149039004a71SRichard Henderson 149139004a71SRichard Henderson case TCG_TYPE_I64: 149239004a71SRichard Henderson switch (TCG_TARGET_CALL_ARG_I64) { 149339004a71SRichard Henderson case TCG_CALL_ARG_EVEN: 149439004a71SRichard Henderson layout_arg_even(&cum); 149539004a71SRichard Henderson /* fall through */ 149639004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 149739004a71SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 149839004a71SRichard Henderson layout_arg_normal_n(&cum, info, 2); 149939004a71SRichard Henderson } else { 150039004a71SRichard Henderson layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL); 150139004a71SRichard Henderson } 150239004a71SRichard Henderson break; 150339004a71SRichard Henderson default: 150439004a71SRichard Henderson qemu_build_not_reached(); 150539004a71SRichard Henderson } 150639004a71SRichard Henderson break; 150739004a71SRichard Henderson 1508466d3759SRichard Henderson case TCG_TYPE_I128: 15095427a9a7SRichard Henderson switch (TCG_TARGET_CALL_ARG_I128) { 1510466d3759SRichard Henderson case TCG_CALL_ARG_EVEN: 1511466d3759SRichard Henderson layout_arg_even(&cum); 1512466d3759SRichard Henderson /* fall through */ 1513466d3759SRichard Henderson case TCG_CALL_ARG_NORMAL: 1514466d3759SRichard Henderson layout_arg_normal_n(&cum, info, 128 / TCG_TARGET_REG_BITS); 1515466d3759SRichard Henderson break; 1516313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF: 1517313bdea8SRichard Henderson layout_arg_by_ref(&cum, info); 1518313bdea8SRichard Henderson break; 1519466d3759SRichard Henderson default: 1520466d3759SRichard Henderson qemu_build_not_reached(); 1521466d3759SRichard Henderson } 1522466d3759SRichard Henderson break; 1523466d3759SRichard Henderson 152439004a71SRichard Henderson default: 152539004a71SRichard Henderson g_assert_not_reached(); 152639004a71SRichard Henderson } 152739004a71SRichard Henderson } 152839004a71SRichard Henderson info->nr_in = cum.info_in_idx; 152939004a71SRichard Henderson 153039004a71SRichard Henderson /* Validate that we didn't overrun the input array. */ 153139004a71SRichard Henderson assert(cum.info_in_idx <= ARRAY_SIZE(info->in)); 153239004a71SRichard Henderson /* Validate the backend has enough argument space. */ 153339004a71SRichard Henderson assert(cum.arg_slot <= max_reg_slots + max_stk_slots); 1534313bdea8SRichard Henderson 1535313bdea8SRichard Henderson /* 1536313bdea8SRichard Henderson * Relocate the "ref_slot" area to the end of the parameters. 1537313bdea8SRichard Henderson * Minimizing this stack offset helps code size for x86, 1538313bdea8SRichard Henderson * which has a signed 8-bit offset encoding. 1539313bdea8SRichard Henderson */ 1540313bdea8SRichard Henderson if (cum.ref_slot != 0) { 1541313bdea8SRichard Henderson int ref_base = 0; 1542313bdea8SRichard Henderson 1543313bdea8SRichard Henderson if (cum.arg_slot > max_reg_slots) { 1544313bdea8SRichard Henderson int align = __alignof(Int128) / sizeof(tcg_target_long); 1545313bdea8SRichard Henderson 1546313bdea8SRichard Henderson ref_base = cum.arg_slot - max_reg_slots; 1547313bdea8SRichard Henderson if (align > 1) { 1548313bdea8SRichard Henderson ref_base = ROUND_UP(ref_base, align); 1549313bdea8SRichard Henderson } 1550313bdea8SRichard Henderson } 1551313bdea8SRichard Henderson assert(ref_base + cum.ref_slot <= max_stk_slots); 1552d78e4a4fSRichard Henderson ref_base += max_reg_slots; 1553313bdea8SRichard Henderson 1554313bdea8SRichard Henderson if (ref_base != 0) { 1555313bdea8SRichard Henderson for (int i = cum.info_in_idx - 1; i >= 0; --i) { 1556313bdea8SRichard Henderson TCGCallArgumentLoc *loc = &info->in[i]; 1557313bdea8SRichard Henderson switch (loc->kind) { 1558313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF: 1559313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF_N: 1560313bdea8SRichard Henderson loc->ref_slot += ref_base; 1561313bdea8SRichard Henderson break; 1562313bdea8SRichard Henderson default: 1563313bdea8SRichard Henderson break; 1564313bdea8SRichard Henderson } 1565313bdea8SRichard Henderson } 1566313bdea8SRichard Henderson } 1567313bdea8SRichard Henderson } 156839004a71SRichard Henderson } 156939004a71SRichard Henderson 157091478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)]; 1571501fb3daSRichard Henderson static void process_constraint_sets(void); 15721c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type, 15731c2adb95SRichard Henderson TCGReg reg, const char *name); 157491478cefSRichard Henderson 1575a9d107faSRichard Henderson static void tcg_context_init(unsigned max_threads) 1576c896fe29Sbellard { 1577a76aabd3SRichard Henderson TCGContext *s = &tcg_init_ctx; 15783e80824eSRichard Henderson int n, i; 15791c2adb95SRichard Henderson TCGTemp *ts; 1580c896fe29Sbellard 1581c896fe29Sbellard memset(s, 0, sizeof(*s)); 1582c896fe29Sbellard s->nb_globals = 0; 1583c896fe29Sbellard 15848429a1caSRichard Henderson init_call_layout(&info_helper_ld32_mmu); 15858429a1caSRichard Henderson init_call_layout(&info_helper_ld64_mmu); 1586ebebea53SRichard Henderson init_call_layout(&info_helper_ld128_mmu); 15878429a1caSRichard Henderson init_call_layout(&info_helper_st32_mmu); 15888429a1caSRichard Henderson init_call_layout(&info_helper_st64_mmu); 1589ebebea53SRichard Henderson init_call_layout(&info_helper_st128_mmu); 15908429a1caSRichard Henderson 1591c896fe29Sbellard tcg_target_init(s); 1592501fb3daSRichard Henderson process_constraint_sets(); 159391478cefSRichard Henderson 159491478cefSRichard Henderson /* Reverse the order of the saved registers, assuming they're all at 159591478cefSRichard Henderson the start of tcg_target_reg_alloc_order. */ 159691478cefSRichard Henderson for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) { 159791478cefSRichard Henderson int r = tcg_target_reg_alloc_order[n]; 159891478cefSRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) { 159991478cefSRichard Henderson break; 160091478cefSRichard Henderson } 160191478cefSRichard Henderson } 160291478cefSRichard Henderson for (i = 0; i < n; ++i) { 160391478cefSRichard Henderson indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i]; 160491478cefSRichard Henderson } 160591478cefSRichard Henderson for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) { 160691478cefSRichard Henderson indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i]; 160791478cefSRichard Henderson } 1608b1311c4aSEmilio G. Cota 1609b1311c4aSEmilio G. Cota tcg_ctx = s; 16103468b59eSEmilio G. Cota /* 16113468b59eSEmilio G. Cota * In user-mode we simply share the init context among threads, since we 16123468b59eSEmilio G. Cota * use a single region. See the documentation tcg_region_init() for the 16133468b59eSEmilio G. Cota * reasoning behind this. 1614a9d107faSRichard Henderson * In system-mode we will have at most max_threads TCG threads. 16153468b59eSEmilio G. Cota */ 16163468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY 1617df2cce29SEmilio G. Cota tcg_ctxs = &tcg_ctx; 16180e2d61cfSRichard Henderson tcg_cur_ctxs = 1; 16190e2d61cfSRichard Henderson tcg_max_ctxs = 1; 16203468b59eSEmilio G. Cota #else 1621a9d107faSRichard Henderson tcg_max_ctxs = max_threads; 1622a9d107faSRichard Henderson tcg_ctxs = g_new0(TCGContext *, max_threads); 16233468b59eSEmilio G. Cota #endif 16241c2adb95SRichard Henderson 16251c2adb95SRichard Henderson tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0)); 16261c2adb95SRichard Henderson ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env"); 1627ad75a51eSRichard Henderson tcg_env = temp_tcgv_ptr(ts); 16289002ec79SRichard Henderson } 1629b03cce8eSbellard 1630a9d107faSRichard Henderson void tcg_init(size_t tb_size, int splitwx, unsigned max_threads) 1631a76aabd3SRichard Henderson { 1632a9d107faSRichard Henderson tcg_context_init(max_threads); 1633a9d107faSRichard Henderson tcg_region_init(tb_size, splitwx, max_threads); 1634a76aabd3SRichard Henderson } 1635a76aabd3SRichard Henderson 16366e3b2bfdSEmilio G. Cota /* 16376e3b2bfdSEmilio G. Cota * Allocate TBs right before their corresponding translated code, making 16386e3b2bfdSEmilio G. Cota * sure that TBs and code are on different cache lines. 16396e3b2bfdSEmilio G. Cota */ 16406e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s) 16416e3b2bfdSEmilio G. Cota { 16426e3b2bfdSEmilio G. Cota uintptr_t align = qemu_icache_linesize; 16436e3b2bfdSEmilio G. Cota TranslationBlock *tb; 16446e3b2bfdSEmilio G. Cota void *next; 16456e3b2bfdSEmilio G. Cota 1646e8feb96fSEmilio G. Cota retry: 16476e3b2bfdSEmilio G. Cota tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align); 16486e3b2bfdSEmilio G. Cota next = (void *)ROUND_UP((uintptr_t)(tb + 1), align); 16496e3b2bfdSEmilio G. Cota 16506e3b2bfdSEmilio G. Cota if (unlikely(next > s->code_gen_highwater)) { 1651e8feb96fSEmilio G. Cota if (tcg_region_alloc(s)) { 16526e3b2bfdSEmilio G. Cota return NULL; 16536e3b2bfdSEmilio G. Cota } 1654e8feb96fSEmilio G. Cota goto retry; 1655e8feb96fSEmilio G. Cota } 1656d73415a3SStefan Hajnoczi qatomic_set(&s->code_gen_ptr, next); 16576e3b2bfdSEmilio G. Cota return tb; 16586e3b2bfdSEmilio G. Cota } 16596e3b2bfdSEmilio G. Cota 1660935f75aeSRichard Henderson void tcg_prologue_init(void) 16619002ec79SRichard Henderson { 1662935f75aeSRichard Henderson TCGContext *s = tcg_ctx; 1663b0a0794aSRichard Henderson size_t prologue_size; 16648163b749SRichard Henderson 1665b0a0794aSRichard Henderson s->code_ptr = s->code_gen_ptr; 1666b0a0794aSRichard Henderson s->code_buf = s->code_gen_ptr; 16675b38ee31SRichard Henderson s->data_gen_ptr = NULL; 1668b91ccb31SRichard Henderson 1669b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 1670b0a0794aSRichard Henderson tcg_qemu_tb_exec = (tcg_prologue_fn *)tcg_splitwx_to_rx(s->code_ptr); 1671b91ccb31SRichard Henderson #endif 16728163b749SRichard Henderson 16735b38ee31SRichard Henderson s->pool_labels = NULL; 16745b38ee31SRichard Henderson 1675653b87ebSRoman Bolshakov qemu_thread_jit_write(); 16768163b749SRichard Henderson /* Generate the prologue. */ 1677b03cce8eSbellard tcg_target_qemu_prologue(s); 16785b38ee31SRichard Henderson 16795b38ee31SRichard Henderson /* Allow the prologue to put e.g. guest_base into a pool entry. */ 16805b38ee31SRichard Henderson { 16811768987bSRichard Henderson int result = tcg_out_pool_finalize(s); 16821768987bSRichard Henderson tcg_debug_assert(result == 0); 16835b38ee31SRichard Henderson } 16845b38ee31SRichard Henderson 1685b0a0794aSRichard Henderson prologue_size = tcg_current_code_size(s); 16865584e2dbSIlya Leoshkevich perf_report_prologue(s->code_gen_ptr, prologue_size); 1687b0a0794aSRichard Henderson 1688df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 1689b0a0794aSRichard Henderson flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf), 1690b0a0794aSRichard Henderson (uintptr_t)s->code_buf, prologue_size); 1691df5d2b16SRichard Henderson #endif 16928163b749SRichard Henderson 1693d6b64b2bSRichard Henderson if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) { 1694c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock(); 169578b54858SRichard Henderson if (logfile) { 169678b54858SRichard Henderson fprintf(logfile, "PROLOGUE: [size=%zu]\n", prologue_size); 16975b38ee31SRichard Henderson if (s->data_gen_ptr) { 1698b0a0794aSRichard Henderson size_t code_size = s->data_gen_ptr - s->code_gen_ptr; 16995b38ee31SRichard Henderson size_t data_size = prologue_size - code_size; 17005b38ee31SRichard Henderson size_t i; 17015b38ee31SRichard Henderson 170278b54858SRichard Henderson disas(logfile, s->code_gen_ptr, code_size); 17035b38ee31SRichard Henderson 17045b38ee31SRichard Henderson for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) { 17055b38ee31SRichard Henderson if (sizeof(tcg_target_ulong) == 8) { 170678b54858SRichard Henderson fprintf(logfile, 170778b54858SRichard Henderson "0x%08" PRIxPTR ": .quad 0x%016" PRIx64 "\n", 17085b38ee31SRichard Henderson (uintptr_t)s->data_gen_ptr + i, 17095b38ee31SRichard Henderson *(uint64_t *)(s->data_gen_ptr + i)); 17105b38ee31SRichard Henderson } else { 171178b54858SRichard Henderson fprintf(logfile, 171278b54858SRichard Henderson "0x%08" PRIxPTR ": .long 0x%08x\n", 17135b38ee31SRichard Henderson (uintptr_t)s->data_gen_ptr + i, 17145b38ee31SRichard Henderson *(uint32_t *)(s->data_gen_ptr + i)); 17155b38ee31SRichard Henderson } 17165b38ee31SRichard Henderson } 17175b38ee31SRichard Henderson } else { 171878b54858SRichard Henderson disas(logfile, s->code_gen_ptr, prologue_size); 17195b38ee31SRichard Henderson } 172078b54858SRichard Henderson fprintf(logfile, "\n"); 1721fc59d2d8SRobert Foley qemu_log_unlock(logfile); 1722d6b64b2bSRichard Henderson } 172378b54858SRichard Henderson } 1724cedbcb01SEmilio G. Cota 17256eea0434SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 17266eea0434SRichard Henderson /* 17276eea0434SRichard Henderson * Assert that goto_ptr is implemented completely, setting an epilogue. 17286eea0434SRichard Henderson * For tci, we use NULL as the signal to return from the interpreter, 17296eea0434SRichard Henderson * so skip this check. 17306eea0434SRichard Henderson */ 17318b5c2b62SRichard Henderson tcg_debug_assert(tcg_code_gen_epilogue != NULL); 17326eea0434SRichard Henderson #endif 1733d1c74ab3SRichard Henderson 1734d1c74ab3SRichard Henderson tcg_region_prologue_set(s); 1735c896fe29Sbellard } 1736c896fe29Sbellard 1737c896fe29Sbellard void tcg_func_start(TCGContext *s) 1738c896fe29Sbellard { 1739c896fe29Sbellard tcg_pool_reset(s); 1740c896fe29Sbellard s->nb_temps = s->nb_globals; 17410ec9eabcSRichard Henderson 17420ec9eabcSRichard Henderson /* No temps have been previously allocated for size or locality. */ 174304e006abSRichard Henderson tcg_temp_ebb_reset_freed(s); 17440ec9eabcSRichard Henderson 1745c0522136SRichard Henderson /* No constant temps have been previously allocated. */ 1746c0522136SRichard Henderson for (int i = 0; i < TCG_TYPE_COUNT; ++i) { 1747c0522136SRichard Henderson if (s->const_table[i]) { 1748c0522136SRichard Henderson g_hash_table_remove_all(s->const_table[i]); 1749c0522136SRichard Henderson } 1750c0522136SRichard Henderson } 1751c0522136SRichard Henderson 1752abebf925SRichard Henderson s->nb_ops = 0; 1753c896fe29Sbellard s->nb_labels = 0; 1754c896fe29Sbellard s->current_frame_offset = s->frame_start; 1755c896fe29Sbellard 17560a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG 17570a209d4bSRichard Henderson s->goto_tb_issue_mask = 0; 17580a209d4bSRichard Henderson #endif 17590a209d4bSRichard Henderson 176015fa08f8SRichard Henderson QTAILQ_INIT(&s->ops); 176115fa08f8SRichard Henderson QTAILQ_INIT(&s->free_ops); 176207843f75SRichard Henderson s->emit_before_op = NULL; 1763bef16ab4SRichard Henderson QSIMPLEQ_INIT(&s->labels); 17644baf3978SRichard Henderson 1765a0ecb8e4SRichard Henderson tcg_debug_assert(s->addr_type <= TCG_TYPE_REG); 1766747bd69dSRichard Henderson tcg_debug_assert(s->insn_start_words > 0); 1767c896fe29Sbellard } 1768c896fe29Sbellard 1769ae30e866SRichard Henderson static TCGTemp *tcg_temp_alloc(TCGContext *s) 17707ca4b752SRichard Henderson { 17717ca4b752SRichard Henderson int n = s->nb_temps++; 1772ae30e866SRichard Henderson 1773ae30e866SRichard Henderson if (n >= TCG_MAX_TEMPS) { 1774db6b7d0cSRichard Henderson tcg_raise_tb_overflow(s); 1775ae30e866SRichard Henderson } 17767ca4b752SRichard Henderson return memset(&s->temps[n], 0, sizeof(TCGTemp)); 17777ca4b752SRichard Henderson } 17787ca4b752SRichard Henderson 1779ae30e866SRichard Henderson static TCGTemp *tcg_global_alloc(TCGContext *s) 17807ca4b752SRichard Henderson { 1781fa477d25SRichard Henderson TCGTemp *ts; 1782fa477d25SRichard Henderson 17837ca4b752SRichard Henderson tcg_debug_assert(s->nb_globals == s->nb_temps); 1784ae30e866SRichard Henderson tcg_debug_assert(s->nb_globals < TCG_MAX_TEMPS); 17857ca4b752SRichard Henderson s->nb_globals++; 1786fa477d25SRichard Henderson ts = tcg_temp_alloc(s); 1787ee17db83SRichard Henderson ts->kind = TEMP_GLOBAL; 1788fa477d25SRichard Henderson 1789fa477d25SRichard Henderson return ts; 1790c896fe29Sbellard } 1791c896fe29Sbellard 1792085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type, 1793b6638662SRichard Henderson TCGReg reg, const char *name) 1794c896fe29Sbellard { 1795c896fe29Sbellard TCGTemp *ts; 1796c896fe29Sbellard 17971a057554SRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 64 || type == TCG_TYPE_I32); 17987ca4b752SRichard Henderson 17997ca4b752SRichard Henderson ts = tcg_global_alloc(s); 1800c896fe29Sbellard ts->base_type = type; 1801c896fe29Sbellard ts->type = type; 1802ee17db83SRichard Henderson ts->kind = TEMP_FIXED; 1803c896fe29Sbellard ts->reg = reg; 1804c896fe29Sbellard ts->name = name; 1805c896fe29Sbellard tcg_regset_set_reg(s->reserved_regs, reg); 18067ca4b752SRichard Henderson 1807085272b3SRichard Henderson return ts; 1808a7812ae4Spbrook } 1809a7812ae4Spbrook 1810b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size) 1811a7812ae4Spbrook { 1812b3a62939SRichard Henderson s->frame_start = start; 1813b3a62939SRichard Henderson s->frame_end = start + size; 1814085272b3SRichard Henderson s->frame_temp 1815085272b3SRichard Henderson = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame"); 1816b3a62939SRichard Henderson } 1817a7812ae4Spbrook 18184643f3e0SRichard Henderson static TCGTemp *tcg_global_mem_new_internal(TCGv_ptr base, intptr_t offset, 18194643f3e0SRichard Henderson const char *name, TCGType type) 1820c896fe29Sbellard { 1821b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1822dc41aa7dSRichard Henderson TCGTemp *base_ts = tcgv_ptr_temp(base); 18237ca4b752SRichard Henderson TCGTemp *ts = tcg_global_alloc(s); 1824aef85402SRichard Henderson int indirect_reg = 0; 1825c896fe29Sbellard 1826c0522136SRichard Henderson switch (base_ts->kind) { 1827c0522136SRichard Henderson case TEMP_FIXED: 1828c0522136SRichard Henderson break; 1829c0522136SRichard Henderson case TEMP_GLOBAL: 18305a18407fSRichard Henderson /* We do not support double-indirect registers. */ 18315a18407fSRichard Henderson tcg_debug_assert(!base_ts->indirect_reg); 1832b3915dbbSRichard Henderson base_ts->indirect_base = 1; 18335a18407fSRichard Henderson s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64 18345a18407fSRichard Henderson ? 2 : 1); 18355a18407fSRichard Henderson indirect_reg = 1; 1836c0522136SRichard Henderson break; 1837c0522136SRichard Henderson default: 1838c0522136SRichard Henderson g_assert_not_reached(); 1839b3915dbbSRichard Henderson } 1840b3915dbbSRichard Henderson 18417ca4b752SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { 18427ca4b752SRichard Henderson TCGTemp *ts2 = tcg_global_alloc(s); 1843c896fe29Sbellard char buf[64]; 18447ca4b752SRichard Henderson 18457ca4b752SRichard Henderson ts->base_type = TCG_TYPE_I64; 1846c896fe29Sbellard ts->type = TCG_TYPE_I32; 1847b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg; 1848c896fe29Sbellard ts->mem_allocated = 1; 1849b3a62939SRichard Henderson ts->mem_base = base_ts; 1850aef85402SRichard Henderson ts->mem_offset = offset; 1851c896fe29Sbellard pstrcpy(buf, sizeof(buf), name); 1852c896fe29Sbellard pstrcat(buf, sizeof(buf), "_0"); 1853c896fe29Sbellard ts->name = strdup(buf); 1854c896fe29Sbellard 18557ca4b752SRichard Henderson tcg_debug_assert(ts2 == ts + 1); 18567ca4b752SRichard Henderson ts2->base_type = TCG_TYPE_I64; 18577ca4b752SRichard Henderson ts2->type = TCG_TYPE_I32; 1858b3915dbbSRichard Henderson ts2->indirect_reg = indirect_reg; 18597ca4b752SRichard Henderson ts2->mem_allocated = 1; 18607ca4b752SRichard Henderson ts2->mem_base = base_ts; 1861aef85402SRichard Henderson ts2->mem_offset = offset + 4; 1862fac87bd2SRichard Henderson ts2->temp_subindex = 1; 1863c896fe29Sbellard pstrcpy(buf, sizeof(buf), name); 1864c896fe29Sbellard pstrcat(buf, sizeof(buf), "_1"); 1865120c1084SRichard Henderson ts2->name = strdup(buf); 18667ca4b752SRichard Henderson } else { 1867c896fe29Sbellard ts->base_type = type; 1868c896fe29Sbellard ts->type = type; 1869b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg; 1870c896fe29Sbellard ts->mem_allocated = 1; 1871b3a62939SRichard Henderson ts->mem_base = base_ts; 1872c896fe29Sbellard ts->mem_offset = offset; 1873c896fe29Sbellard ts->name = name; 1874c896fe29Sbellard } 1875085272b3SRichard Henderson return ts; 1876c896fe29Sbellard } 1877c896fe29Sbellard 18784643f3e0SRichard Henderson TCGv_i32 tcg_global_mem_new_i32(TCGv_ptr reg, intptr_t off, const char *name) 18794643f3e0SRichard Henderson { 18804643f3e0SRichard Henderson TCGTemp *ts = tcg_global_mem_new_internal(reg, off, name, TCG_TYPE_I32); 18814643f3e0SRichard Henderson return temp_tcgv_i32(ts); 18824643f3e0SRichard Henderson } 18834643f3e0SRichard Henderson 18844643f3e0SRichard Henderson TCGv_i64 tcg_global_mem_new_i64(TCGv_ptr reg, intptr_t off, const char *name) 18854643f3e0SRichard Henderson { 18864643f3e0SRichard Henderson TCGTemp *ts = tcg_global_mem_new_internal(reg, off, name, TCG_TYPE_I64); 18874643f3e0SRichard Henderson return temp_tcgv_i64(ts); 18884643f3e0SRichard Henderson } 18894643f3e0SRichard Henderson 18904643f3e0SRichard Henderson TCGv_ptr tcg_global_mem_new_ptr(TCGv_ptr reg, intptr_t off, const char *name) 18914643f3e0SRichard Henderson { 18924643f3e0SRichard Henderson TCGTemp *ts = tcg_global_mem_new_internal(reg, off, name, TCG_TYPE_PTR); 18934643f3e0SRichard Henderson return temp_tcgv_ptr(ts); 18944643f3e0SRichard Henderson } 18954643f3e0SRichard Henderson 1896fb04ab7dSRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, TCGTempKind kind) 1897c896fe29Sbellard { 1898b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1899c896fe29Sbellard TCGTemp *ts; 1900e1c08b00SRichard Henderson int n; 1901c896fe29Sbellard 1902e1c08b00SRichard Henderson if (kind == TEMP_EBB) { 1903e1c08b00SRichard Henderson int idx = find_first_bit(s->free_temps[type].l, TCG_MAX_TEMPS); 1904e1c08b00SRichard Henderson 19050ec9eabcSRichard Henderson if (idx < TCG_MAX_TEMPS) { 19060ec9eabcSRichard Henderson /* There is already an available temp with the right type. */ 1907e1c08b00SRichard Henderson clear_bit(idx, s->free_temps[type].l); 19080ec9eabcSRichard Henderson 1909e8996ee0Sbellard ts = &s->temps[idx]; 1910e8996ee0Sbellard ts->temp_allocated = 1; 19117ca4b752SRichard Henderson tcg_debug_assert(ts->base_type == type); 1912ee17db83SRichard Henderson tcg_debug_assert(ts->kind == kind); 19132f2e911dSRichard Henderson return ts; 1914e1c08b00SRichard Henderson } 1915e8996ee0Sbellard } else { 1916e1c08b00SRichard Henderson tcg_debug_assert(kind == TEMP_TB); 1917e1c08b00SRichard Henderson } 191843eef72fSRichard Henderson 191943eef72fSRichard Henderson switch (type) { 192043eef72fSRichard Henderson case TCG_TYPE_I32: 192143eef72fSRichard Henderson case TCG_TYPE_V64: 192243eef72fSRichard Henderson case TCG_TYPE_V128: 192343eef72fSRichard Henderson case TCG_TYPE_V256: 192443eef72fSRichard Henderson n = 1; 192543eef72fSRichard Henderson break; 192643eef72fSRichard Henderson case TCG_TYPE_I64: 192743eef72fSRichard Henderson n = 64 / TCG_TARGET_REG_BITS; 192843eef72fSRichard Henderson break; 192943eef72fSRichard Henderson case TCG_TYPE_I128: 193043eef72fSRichard Henderson n = 128 / TCG_TARGET_REG_BITS; 193143eef72fSRichard Henderson break; 193243eef72fSRichard Henderson default: 193343eef72fSRichard Henderson g_assert_not_reached(); 193443eef72fSRichard Henderson } 193543eef72fSRichard Henderson 19367ca4b752SRichard Henderson ts = tcg_temp_alloc(s); 193743eef72fSRichard Henderson ts->base_type = type; 193843eef72fSRichard Henderson ts->temp_allocated = 1; 193943eef72fSRichard Henderson ts->kind = kind; 194043eef72fSRichard Henderson 194143eef72fSRichard Henderson if (n == 1) { 194243eef72fSRichard Henderson ts->type = type; 194343eef72fSRichard Henderson } else { 194443eef72fSRichard Henderson ts->type = TCG_TYPE_REG; 194543eef72fSRichard Henderson 1946e1c08b00SRichard Henderson for (int i = 1; i < n; ++i) { 19477ca4b752SRichard Henderson TCGTemp *ts2 = tcg_temp_alloc(s); 19487ca4b752SRichard Henderson 194943eef72fSRichard Henderson tcg_debug_assert(ts2 == ts + i); 195043eef72fSRichard Henderson ts2->base_type = type; 195143eef72fSRichard Henderson ts2->type = TCG_TYPE_REG; 19527ca4b752SRichard Henderson ts2->temp_allocated = 1; 195343eef72fSRichard Henderson ts2->temp_subindex = i; 1954ee17db83SRichard Henderson ts2->kind = kind; 195543eef72fSRichard Henderson } 1956c896fe29Sbellard } 1957085272b3SRichard Henderson return ts; 1958c896fe29Sbellard } 1959c896fe29Sbellard 19604643f3e0SRichard Henderson TCGv_i32 tcg_temp_new_i32(void) 19614643f3e0SRichard Henderson { 19624643f3e0SRichard Henderson return temp_tcgv_i32(tcg_temp_new_internal(TCG_TYPE_I32, TEMP_TB)); 19634643f3e0SRichard Henderson } 19644643f3e0SRichard Henderson 19654643f3e0SRichard Henderson TCGv_i32 tcg_temp_ebb_new_i32(void) 19664643f3e0SRichard Henderson { 19674643f3e0SRichard Henderson return temp_tcgv_i32(tcg_temp_new_internal(TCG_TYPE_I32, TEMP_EBB)); 19684643f3e0SRichard Henderson } 19694643f3e0SRichard Henderson 19704643f3e0SRichard Henderson TCGv_i64 tcg_temp_new_i64(void) 19714643f3e0SRichard Henderson { 19724643f3e0SRichard Henderson return temp_tcgv_i64(tcg_temp_new_internal(TCG_TYPE_I64, TEMP_TB)); 19734643f3e0SRichard Henderson } 19744643f3e0SRichard Henderson 19754643f3e0SRichard Henderson TCGv_i64 tcg_temp_ebb_new_i64(void) 19764643f3e0SRichard Henderson { 19774643f3e0SRichard Henderson return temp_tcgv_i64(tcg_temp_new_internal(TCG_TYPE_I64, TEMP_EBB)); 19784643f3e0SRichard Henderson } 19794643f3e0SRichard Henderson 19804643f3e0SRichard Henderson TCGv_ptr tcg_temp_new_ptr(void) 19814643f3e0SRichard Henderson { 19824643f3e0SRichard Henderson return temp_tcgv_ptr(tcg_temp_new_internal(TCG_TYPE_PTR, TEMP_TB)); 19834643f3e0SRichard Henderson } 19844643f3e0SRichard Henderson 19854643f3e0SRichard Henderson TCGv_ptr tcg_temp_ebb_new_ptr(void) 19864643f3e0SRichard Henderson { 19874643f3e0SRichard Henderson return temp_tcgv_ptr(tcg_temp_new_internal(TCG_TYPE_PTR, TEMP_EBB)); 19884643f3e0SRichard Henderson } 19894643f3e0SRichard Henderson 19904643f3e0SRichard Henderson TCGv_i128 tcg_temp_new_i128(void) 19914643f3e0SRichard Henderson { 19924643f3e0SRichard Henderson return temp_tcgv_i128(tcg_temp_new_internal(TCG_TYPE_I128, TEMP_TB)); 19934643f3e0SRichard Henderson } 19944643f3e0SRichard Henderson 19954643f3e0SRichard Henderson TCGv_i128 tcg_temp_ebb_new_i128(void) 19964643f3e0SRichard Henderson { 19974643f3e0SRichard Henderson return temp_tcgv_i128(tcg_temp_new_internal(TCG_TYPE_I128, TEMP_EBB)); 19984643f3e0SRichard Henderson } 19994643f3e0SRichard Henderson 2000d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type) 2001d2fd745fSRichard Henderson { 2002d2fd745fSRichard Henderson TCGTemp *t; 2003d2fd745fSRichard Henderson 2004d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG 2005d2fd745fSRichard Henderson switch (type) { 2006d2fd745fSRichard Henderson case TCG_TYPE_V64: 2007d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v64); 2008d2fd745fSRichard Henderson break; 2009d2fd745fSRichard Henderson case TCG_TYPE_V128: 2010d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v128); 2011d2fd745fSRichard Henderson break; 2012d2fd745fSRichard Henderson case TCG_TYPE_V256: 2013d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v256); 2014d2fd745fSRichard Henderson break; 2015d2fd745fSRichard Henderson default: 2016d2fd745fSRichard Henderson g_assert_not_reached(); 2017d2fd745fSRichard Henderson } 2018d2fd745fSRichard Henderson #endif 2019d2fd745fSRichard Henderson 2020bbf989bfSRichard Henderson t = tcg_temp_new_internal(type, TEMP_EBB); 2021d2fd745fSRichard Henderson return temp_tcgv_vec(t); 2022d2fd745fSRichard Henderson } 2023d2fd745fSRichard Henderson 2024d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp. */ 2025d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match) 2026d2fd745fSRichard Henderson { 2027d2fd745fSRichard Henderson TCGTemp *t = tcgv_vec_temp(match); 2028d2fd745fSRichard Henderson 2029d2fd745fSRichard Henderson tcg_debug_assert(t->temp_allocated != 0); 2030d2fd745fSRichard Henderson 2031bbf989bfSRichard Henderson t = tcg_temp_new_internal(t->base_type, TEMP_EBB); 2032d2fd745fSRichard Henderson return temp_tcgv_vec(t); 2033d2fd745fSRichard Henderson } 2034d2fd745fSRichard Henderson 20355bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts) 2036c896fe29Sbellard { 2037b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 2038c896fe29Sbellard 2039c7482438SRichard Henderson switch (ts->kind) { 2040c7482438SRichard Henderson case TEMP_CONST: 2041f57c6915SRichard Henderson case TEMP_TB: 20422f2e911dSRichard Henderson /* Silently ignore free. */ 2043c7482438SRichard Henderson break; 20442f2e911dSRichard Henderson case TEMP_EBB: 2045eabb7b91SAurelien Jarno tcg_debug_assert(ts->temp_allocated != 0); 2046e8996ee0Sbellard ts->temp_allocated = 0; 20472f2e911dSRichard Henderson set_bit(temp_idx(ts), s->free_temps[ts->base_type].l); 20482f2e911dSRichard Henderson break; 20492f2e911dSRichard Henderson default: 20502f2e911dSRichard Henderson /* It never made sense to free TEMP_FIXED or TEMP_GLOBAL. */ 20512f2e911dSRichard Henderson g_assert_not_reached(); 2052e1c08b00SRichard Henderson } 2053e8996ee0Sbellard } 2054e8996ee0Sbellard 205558b79713SRichard Henderson void tcg_temp_free_i32(TCGv_i32 arg) 205658b79713SRichard Henderson { 205758b79713SRichard Henderson tcg_temp_free_internal(tcgv_i32_temp(arg)); 205858b79713SRichard Henderson } 205958b79713SRichard Henderson 206058b79713SRichard Henderson void tcg_temp_free_i64(TCGv_i64 arg) 206158b79713SRichard Henderson { 206258b79713SRichard Henderson tcg_temp_free_internal(tcgv_i64_temp(arg)); 206358b79713SRichard Henderson } 206458b79713SRichard Henderson 206558b79713SRichard Henderson void tcg_temp_free_i128(TCGv_i128 arg) 206658b79713SRichard Henderson { 206758b79713SRichard Henderson tcg_temp_free_internal(tcgv_i128_temp(arg)); 206858b79713SRichard Henderson } 206958b79713SRichard Henderson 207058b79713SRichard Henderson void tcg_temp_free_ptr(TCGv_ptr arg) 207158b79713SRichard Henderson { 207258b79713SRichard Henderson tcg_temp_free_internal(tcgv_ptr_temp(arg)); 207358b79713SRichard Henderson } 207458b79713SRichard Henderson 207558b79713SRichard Henderson void tcg_temp_free_vec(TCGv_vec arg) 207658b79713SRichard Henderson { 207758b79713SRichard Henderson tcg_temp_free_internal(tcgv_vec_temp(arg)); 207858b79713SRichard Henderson } 207958b79713SRichard Henderson 2080c0522136SRichard Henderson TCGTemp *tcg_constant_internal(TCGType type, int64_t val) 2081c0522136SRichard Henderson { 2082c0522136SRichard Henderson TCGContext *s = tcg_ctx; 2083c0522136SRichard Henderson GHashTable *h = s->const_table[type]; 2084c0522136SRichard Henderson TCGTemp *ts; 2085c0522136SRichard Henderson 2086c0522136SRichard Henderson if (h == NULL) { 2087c0522136SRichard Henderson h = g_hash_table_new(g_int64_hash, g_int64_equal); 2088c0522136SRichard Henderson s->const_table[type] = h; 2089c0522136SRichard Henderson } 2090c0522136SRichard Henderson 2091c0522136SRichard Henderson ts = g_hash_table_lookup(h, &val); 2092c0522136SRichard Henderson if (ts == NULL) { 2093aef85402SRichard Henderson int64_t *val_ptr; 2094aef85402SRichard Henderson 2095c0522136SRichard Henderson ts = tcg_temp_alloc(s); 2096c0522136SRichard Henderson 2097c0522136SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { 2098c0522136SRichard Henderson TCGTemp *ts2 = tcg_temp_alloc(s); 2099c0522136SRichard Henderson 2100aef85402SRichard Henderson tcg_debug_assert(ts2 == ts + 1); 2101aef85402SRichard Henderson 2102c0522136SRichard Henderson ts->base_type = TCG_TYPE_I64; 2103c0522136SRichard Henderson ts->type = TCG_TYPE_I32; 2104c0522136SRichard Henderson ts->kind = TEMP_CONST; 2105c0522136SRichard Henderson ts->temp_allocated = 1; 2106c0522136SRichard Henderson 2107c0522136SRichard Henderson ts2->base_type = TCG_TYPE_I64; 2108c0522136SRichard Henderson ts2->type = TCG_TYPE_I32; 2109c0522136SRichard Henderson ts2->kind = TEMP_CONST; 2110c0522136SRichard Henderson ts2->temp_allocated = 1; 2111fac87bd2SRichard Henderson ts2->temp_subindex = 1; 2112aef85402SRichard Henderson 2113aef85402SRichard Henderson /* 2114aef85402SRichard Henderson * Retain the full value of the 64-bit constant in the low 2115aef85402SRichard Henderson * part, so that the hash table works. Actual uses will 2116aef85402SRichard Henderson * truncate the value to the low part. 2117aef85402SRichard Henderson */ 2118aef85402SRichard Henderson ts[HOST_BIG_ENDIAN].val = val; 2119aef85402SRichard Henderson ts[!HOST_BIG_ENDIAN].val = val >> 32; 2120aef85402SRichard Henderson val_ptr = &ts[HOST_BIG_ENDIAN].val; 2121c0522136SRichard Henderson } else { 2122c0522136SRichard Henderson ts->base_type = type; 2123c0522136SRichard Henderson ts->type = type; 2124c0522136SRichard Henderson ts->kind = TEMP_CONST; 2125c0522136SRichard Henderson ts->temp_allocated = 1; 2126c0522136SRichard Henderson ts->val = val; 2127aef85402SRichard Henderson val_ptr = &ts->val; 2128c0522136SRichard Henderson } 2129aef85402SRichard Henderson g_hash_table_insert(h, val_ptr, ts); 2130c0522136SRichard Henderson } 2131c0522136SRichard Henderson 2132c0522136SRichard Henderson return ts; 2133c0522136SRichard Henderson } 2134c0522136SRichard Henderson 213516edaee7SRichard Henderson TCGv_i32 tcg_constant_i32(int32_t val) 213616edaee7SRichard Henderson { 213716edaee7SRichard Henderson return temp_tcgv_i32(tcg_constant_internal(TCG_TYPE_I32, val)); 213816edaee7SRichard Henderson } 213916edaee7SRichard Henderson 214016edaee7SRichard Henderson TCGv_i64 tcg_constant_i64(int64_t val) 214116edaee7SRichard Henderson { 214216edaee7SRichard Henderson return temp_tcgv_i64(tcg_constant_internal(TCG_TYPE_I64, val)); 214316edaee7SRichard Henderson } 214416edaee7SRichard Henderson 214516edaee7SRichard Henderson TCGv_ptr tcg_constant_ptr_int(intptr_t val) 214616edaee7SRichard Henderson { 214716edaee7SRichard Henderson return temp_tcgv_ptr(tcg_constant_internal(TCG_TYPE_PTR, val)); 214816edaee7SRichard Henderson } 214916edaee7SRichard Henderson 2150c0522136SRichard Henderson TCGv_vec tcg_constant_vec(TCGType type, unsigned vece, int64_t val) 2151c0522136SRichard Henderson { 2152c0522136SRichard Henderson val = dup_const(vece, val); 2153c0522136SRichard Henderson return temp_tcgv_vec(tcg_constant_internal(type, val)); 2154c0522136SRichard Henderson } 2155c0522136SRichard Henderson 215688d4005bSRichard Henderson TCGv_vec tcg_constant_vec_matching(TCGv_vec match, unsigned vece, int64_t val) 215788d4005bSRichard Henderson { 215888d4005bSRichard Henderson TCGTemp *t = tcgv_vec_temp(match); 215988d4005bSRichard Henderson 216088d4005bSRichard Henderson tcg_debug_assert(t->temp_allocated != 0); 216188d4005bSRichard Henderson return tcg_constant_vec(t->base_type, vece, val); 216288d4005bSRichard Henderson } 216388d4005bSRichard Henderson 2164177f648fSRichard Henderson #ifdef CONFIG_DEBUG_TCG 2165177f648fSRichard Henderson size_t temp_idx(TCGTemp *ts) 2166177f648fSRichard Henderson { 2167177f648fSRichard Henderson ptrdiff_t n = ts - tcg_ctx->temps; 2168177f648fSRichard Henderson assert(n >= 0 && n < tcg_ctx->nb_temps); 2169177f648fSRichard Henderson return n; 2170177f648fSRichard Henderson } 2171177f648fSRichard Henderson 2172177f648fSRichard Henderson TCGTemp *tcgv_i32_temp(TCGv_i32 v) 2173177f648fSRichard Henderson { 2174177f648fSRichard Henderson uintptr_t o = (uintptr_t)v - offsetof(TCGContext, temps); 2175177f648fSRichard Henderson 2176177f648fSRichard Henderson assert(o < sizeof(TCGTemp) * tcg_ctx->nb_temps); 2177177f648fSRichard Henderson assert(o % sizeof(TCGTemp) == 0); 2178177f648fSRichard Henderson 2179177f648fSRichard Henderson return (void *)tcg_ctx + (uintptr_t)v; 2180177f648fSRichard Henderson } 2181177f648fSRichard Henderson #endif /* CONFIG_DEBUG_TCG */ 2182177f648fSRichard Henderson 2183771a5925SRichard Henderson /* 2184771a5925SRichard Henderson * Return true if OP may appear in the opcode stream with TYPE. 2185771a5925SRichard Henderson * Test the runtime variable that controls each opcode. 2186771a5925SRichard Henderson */ 2187771a5925SRichard Henderson bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) 2188be0f34b5SRichard Henderson { 2189f44824ccSRichard Henderson bool has_type; 2190f44824ccSRichard Henderson 2191f44824ccSRichard Henderson switch (type) { 2192f44824ccSRichard Henderson case TCG_TYPE_I32: 2193f44824ccSRichard Henderson has_type = true; 2194f44824ccSRichard Henderson break; 2195f44824ccSRichard Henderson case TCG_TYPE_I64: 2196f44824ccSRichard Henderson has_type = TCG_TARGET_REG_BITS == 64; 2197f44824ccSRichard Henderson break; 2198f44824ccSRichard Henderson case TCG_TYPE_V64: 2199f44824ccSRichard Henderson has_type = TCG_TARGET_HAS_v64; 2200f44824ccSRichard Henderson break; 2201f44824ccSRichard Henderson case TCG_TYPE_V128: 2202f44824ccSRichard Henderson has_type = TCG_TARGET_HAS_v128; 2203f44824ccSRichard Henderson break; 2204f44824ccSRichard Henderson case TCG_TYPE_V256: 2205f44824ccSRichard Henderson has_type = TCG_TARGET_HAS_v256; 2206f44824ccSRichard Henderson break; 2207f44824ccSRichard Henderson default: 2208f44824ccSRichard Henderson has_type = false; 2209f44824ccSRichard Henderson break; 2210f44824ccSRichard Henderson } 2211d2fd745fSRichard Henderson 2212be0f34b5SRichard Henderson switch (op) { 2213be0f34b5SRichard Henderson case INDEX_op_discard: 2214be0f34b5SRichard Henderson case INDEX_op_set_label: 2215be0f34b5SRichard Henderson case INDEX_op_call: 2216be0f34b5SRichard Henderson case INDEX_op_br: 2217be0f34b5SRichard Henderson case INDEX_op_mb: 2218be0f34b5SRichard Henderson case INDEX_op_insn_start: 2219be0f34b5SRichard Henderson case INDEX_op_exit_tb: 2220be0f34b5SRichard Henderson case INDEX_op_goto_tb: 2221f4e01e30SRichard Henderson case INDEX_op_goto_ptr: 222250b7a197SRichard Henderson case INDEX_op_qemu_ld_i32: 222350b7a197SRichard Henderson case INDEX_op_qemu_st_i32: 222450b7a197SRichard Henderson case INDEX_op_qemu_ld_i64: 222550b7a197SRichard Henderson case INDEX_op_qemu_st_i64: 2226be0f34b5SRichard Henderson return true; 2227be0f34b5SRichard Henderson 222850b7a197SRichard Henderson case INDEX_op_qemu_st8_i32: 222907ce0b05SRichard Henderson return TCG_TARGET_HAS_qemu_st8_i32; 223007ce0b05SRichard Henderson 223150b7a197SRichard Henderson case INDEX_op_qemu_ld_i128: 223250b7a197SRichard Henderson case INDEX_op_qemu_st_i128: 223312fde9bcSRichard Henderson return TCG_TARGET_HAS_qemu_ldst_i128; 223412fde9bcSRichard Henderson 223579602f63SRichard Henderson case INDEX_op_add: 2236c3b920b3SRichard Henderson case INDEX_op_and: 2237b5701261SRichard Henderson case INDEX_op_mov: 223849bd7514SRichard Henderson case INDEX_op_or: 2239fffd3dc9SRichard Henderson case INDEX_op_xor: 2240b5701261SRichard Henderson return has_type; 2241b5701261SRichard Henderson 2242be0f34b5SRichard Henderson case INDEX_op_setcond_i32: 2243be0f34b5SRichard Henderson case INDEX_op_brcond_i32: 22443871be75SRichard Henderson case INDEX_op_movcond_i32: 2245be0f34b5SRichard Henderson case INDEX_op_ld8u_i32: 2246be0f34b5SRichard Henderson case INDEX_op_ld8s_i32: 2247be0f34b5SRichard Henderson case INDEX_op_ld16u_i32: 2248be0f34b5SRichard Henderson case INDEX_op_ld16s_i32: 2249be0f34b5SRichard Henderson case INDEX_op_ld_i32: 2250be0f34b5SRichard Henderson case INDEX_op_st8_i32: 2251be0f34b5SRichard Henderson case INDEX_op_st16_i32: 2252be0f34b5SRichard Henderson case INDEX_op_st_i32: 2253be0f34b5SRichard Henderson case INDEX_op_shl_i32: 2254be0f34b5SRichard Henderson case INDEX_op_shr_i32: 2255be0f34b5SRichard Henderson case INDEX_op_sar_i32: 2256c334de11SRichard Henderson case INDEX_op_extract_i32: 2257c334de11SRichard Henderson case INDEX_op_sextract_i32: 22586482e9d2SRichard Henderson case INDEX_op_deposit_i32: 2259be0f34b5SRichard Henderson return true; 2260be0f34b5SRichard Henderson 22613635502dSRichard Henderson case INDEX_op_negsetcond_i32: 22623635502dSRichard Henderson return TCG_TARGET_HAS_negsetcond_i32; 2263be0f34b5SRichard Henderson case INDEX_op_div_i32: 2264be0f34b5SRichard Henderson case INDEX_op_divu_i32: 2265be0f34b5SRichard Henderson return TCG_TARGET_HAS_div_i32; 2266be0f34b5SRichard Henderson case INDEX_op_rem_i32: 2267be0f34b5SRichard Henderson case INDEX_op_remu_i32: 2268be0f34b5SRichard Henderson return TCG_TARGET_HAS_rem_i32; 2269be0f34b5SRichard Henderson case INDEX_op_div2_i32: 2270be0f34b5SRichard Henderson case INDEX_op_divu2_i32: 2271be0f34b5SRichard Henderson return TCG_TARGET_HAS_div2_i32; 2272be0f34b5SRichard Henderson case INDEX_op_rotl_i32: 2273be0f34b5SRichard Henderson case INDEX_op_rotr_i32: 2274be0f34b5SRichard Henderson return TCG_TARGET_HAS_rot_i32; 2275fce1296fSRichard Henderson case INDEX_op_extract2_i32: 2276fce1296fSRichard Henderson return TCG_TARGET_HAS_extract2_i32; 2277be0f34b5SRichard Henderson case INDEX_op_add2_i32: 2278be0f34b5SRichard Henderson return TCG_TARGET_HAS_add2_i32; 2279be0f34b5SRichard Henderson case INDEX_op_sub2_i32: 2280be0f34b5SRichard Henderson return TCG_TARGET_HAS_sub2_i32; 2281be0f34b5SRichard Henderson case INDEX_op_mulu2_i32: 2282be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulu2_i32; 2283be0f34b5SRichard Henderson case INDEX_op_muls2_i32: 2284be0f34b5SRichard Henderson return TCG_TARGET_HAS_muls2_i32; 2285be0f34b5SRichard Henderson case INDEX_op_bswap16_i32: 2286be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap16_i32; 2287be0f34b5SRichard Henderson case INDEX_op_bswap32_i32: 2288be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap32_i32; 2289be0f34b5SRichard Henderson case INDEX_op_clz_i32: 2290be0f34b5SRichard Henderson return TCG_TARGET_HAS_clz_i32; 2291be0f34b5SRichard Henderson case INDEX_op_ctz_i32: 2292be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctz_i32; 2293be0f34b5SRichard Henderson case INDEX_op_ctpop_i32: 2294be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctpop_i32; 2295be0f34b5SRichard Henderson 2296be0f34b5SRichard Henderson case INDEX_op_brcond2_i32: 2297be0f34b5SRichard Henderson case INDEX_op_setcond2_i32: 2298be0f34b5SRichard Henderson return TCG_TARGET_REG_BITS == 32; 2299be0f34b5SRichard Henderson 2300be0f34b5SRichard Henderson case INDEX_op_setcond_i64: 2301be0f34b5SRichard Henderson case INDEX_op_brcond_i64: 23023871be75SRichard Henderson case INDEX_op_movcond_i64: 2303be0f34b5SRichard Henderson case INDEX_op_ld8u_i64: 2304be0f34b5SRichard Henderson case INDEX_op_ld8s_i64: 2305be0f34b5SRichard Henderson case INDEX_op_ld16u_i64: 2306be0f34b5SRichard Henderson case INDEX_op_ld16s_i64: 2307be0f34b5SRichard Henderson case INDEX_op_ld32u_i64: 2308be0f34b5SRichard Henderson case INDEX_op_ld32s_i64: 2309be0f34b5SRichard Henderson case INDEX_op_ld_i64: 2310be0f34b5SRichard Henderson case INDEX_op_st8_i64: 2311be0f34b5SRichard Henderson case INDEX_op_st16_i64: 2312be0f34b5SRichard Henderson case INDEX_op_st32_i64: 2313be0f34b5SRichard Henderson case INDEX_op_st_i64: 2314be0f34b5SRichard Henderson case INDEX_op_shl_i64: 2315be0f34b5SRichard Henderson case INDEX_op_shr_i64: 2316be0f34b5SRichard Henderson case INDEX_op_sar_i64: 2317be0f34b5SRichard Henderson case INDEX_op_ext_i32_i64: 2318be0f34b5SRichard Henderson case INDEX_op_extu_i32_i64: 2319c334de11SRichard Henderson case INDEX_op_extract_i64: 2320c334de11SRichard Henderson case INDEX_op_sextract_i64: 23216482e9d2SRichard Henderson case INDEX_op_deposit_i64: 2322be0f34b5SRichard Henderson return TCG_TARGET_REG_BITS == 64; 2323be0f34b5SRichard Henderson 23243635502dSRichard Henderson case INDEX_op_negsetcond_i64: 23253635502dSRichard Henderson return TCG_TARGET_HAS_negsetcond_i64; 2326be0f34b5SRichard Henderson case INDEX_op_div_i64: 2327be0f34b5SRichard Henderson case INDEX_op_divu_i64: 2328be0f34b5SRichard Henderson return TCG_TARGET_HAS_div_i64; 2329be0f34b5SRichard Henderson case INDEX_op_rem_i64: 2330be0f34b5SRichard Henderson case INDEX_op_remu_i64: 2331be0f34b5SRichard Henderson return TCG_TARGET_HAS_rem_i64; 2332be0f34b5SRichard Henderson case INDEX_op_div2_i64: 2333be0f34b5SRichard Henderson case INDEX_op_divu2_i64: 2334be0f34b5SRichard Henderson return TCG_TARGET_HAS_div2_i64; 2335be0f34b5SRichard Henderson case INDEX_op_rotl_i64: 2336be0f34b5SRichard Henderson case INDEX_op_rotr_i64: 2337be0f34b5SRichard Henderson return TCG_TARGET_HAS_rot_i64; 2338fce1296fSRichard Henderson case INDEX_op_extract2_i64: 2339fce1296fSRichard Henderson return TCG_TARGET_HAS_extract2_i64; 2340be0f34b5SRichard Henderson case INDEX_op_extrl_i64_i32: 2341be0f34b5SRichard Henderson case INDEX_op_extrh_i64_i32: 234213d885b0SRichard Henderson return TCG_TARGET_HAS_extr_i64_i32; 2343be0f34b5SRichard Henderson case INDEX_op_bswap16_i64: 2344be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap16_i64; 2345be0f34b5SRichard Henderson case INDEX_op_bswap32_i64: 2346be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap32_i64; 2347be0f34b5SRichard Henderson case INDEX_op_bswap64_i64: 2348be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap64_i64; 2349be0f34b5SRichard Henderson case INDEX_op_clz_i64: 2350be0f34b5SRichard Henderson return TCG_TARGET_HAS_clz_i64; 2351be0f34b5SRichard Henderson case INDEX_op_ctz_i64: 2352be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctz_i64; 2353be0f34b5SRichard Henderson case INDEX_op_ctpop_i64: 2354be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctpop_i64; 2355be0f34b5SRichard Henderson case INDEX_op_add2_i64: 2356be0f34b5SRichard Henderson return TCG_TARGET_HAS_add2_i64; 2357be0f34b5SRichard Henderson case INDEX_op_sub2_i64: 2358be0f34b5SRichard Henderson return TCG_TARGET_HAS_sub2_i64; 2359be0f34b5SRichard Henderson case INDEX_op_mulu2_i64: 2360be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulu2_i64; 2361be0f34b5SRichard Henderson case INDEX_op_muls2_i64: 2362be0f34b5SRichard Henderson return TCG_TARGET_HAS_muls2_i64; 2363be0f34b5SRichard Henderson 2364d2fd745fSRichard Henderson case INDEX_op_mov_vec: 2365d2fd745fSRichard Henderson case INDEX_op_dup_vec: 236637ee55a0SRichard Henderson case INDEX_op_dupm_vec: 2367d2fd745fSRichard Henderson case INDEX_op_ld_vec: 2368d2fd745fSRichard Henderson case INDEX_op_st_vec: 2369d2fd745fSRichard Henderson case INDEX_op_add_vec: 2370d2fd745fSRichard Henderson case INDEX_op_sub_vec: 2371d2fd745fSRichard Henderson case INDEX_op_and_vec: 2372d2fd745fSRichard Henderson case INDEX_op_or_vec: 2373d2fd745fSRichard Henderson case INDEX_op_xor_vec: 2374212be173SRichard Henderson case INDEX_op_cmp_vec: 2375f44824ccSRichard Henderson return has_type; 2376d2fd745fSRichard Henderson case INDEX_op_dup2_vec: 2377f44824ccSRichard Henderson return has_type && TCG_TARGET_REG_BITS == 32; 2378d2fd745fSRichard Henderson case INDEX_op_not_vec: 2379f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_not_vec; 2380d2fd745fSRichard Henderson case INDEX_op_neg_vec: 2381f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_neg_vec; 2382bcefc902SRichard Henderson case INDEX_op_abs_vec: 2383f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_abs_vec; 2384d2fd745fSRichard Henderson case INDEX_op_andc_vec: 2385f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_andc_vec; 2386d2fd745fSRichard Henderson case INDEX_op_orc_vec: 2387f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_orc_vec; 2388ed523473SRichard Henderson case INDEX_op_nand_vec: 2389f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_nand_vec; 2390ed523473SRichard Henderson case INDEX_op_nor_vec: 2391f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_nor_vec; 2392ed523473SRichard Henderson case INDEX_op_eqv_vec: 2393f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_eqv_vec; 23943774030aSRichard Henderson case INDEX_op_mul_vec: 2395f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_mul_vec; 2396d0ec9796SRichard Henderson case INDEX_op_shli_vec: 2397d0ec9796SRichard Henderson case INDEX_op_shri_vec: 2398d0ec9796SRichard Henderson case INDEX_op_sari_vec: 2399f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_shi_vec; 2400d0ec9796SRichard Henderson case INDEX_op_shls_vec: 2401d0ec9796SRichard Henderson case INDEX_op_shrs_vec: 2402d0ec9796SRichard Henderson case INDEX_op_sars_vec: 2403f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_shs_vec; 2404d0ec9796SRichard Henderson case INDEX_op_shlv_vec: 2405d0ec9796SRichard Henderson case INDEX_op_shrv_vec: 2406d0ec9796SRichard Henderson case INDEX_op_sarv_vec: 2407f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_shv_vec; 2408b0f7e744SRichard Henderson case INDEX_op_rotli_vec: 2409f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_roti_vec; 241023850a74SRichard Henderson case INDEX_op_rotls_vec: 2411f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_rots_vec; 24125d0ceda9SRichard Henderson case INDEX_op_rotlv_vec: 24135d0ceda9SRichard Henderson case INDEX_op_rotrv_vec: 2414f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_rotv_vec; 24158afaf050SRichard Henderson case INDEX_op_ssadd_vec: 24168afaf050SRichard Henderson case INDEX_op_usadd_vec: 24178afaf050SRichard Henderson case INDEX_op_sssub_vec: 24188afaf050SRichard Henderson case INDEX_op_ussub_vec: 2419f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_sat_vec; 2420dd0a0fcdSRichard Henderson case INDEX_op_smin_vec: 2421dd0a0fcdSRichard Henderson case INDEX_op_umin_vec: 2422dd0a0fcdSRichard Henderson case INDEX_op_smax_vec: 2423dd0a0fcdSRichard Henderson case INDEX_op_umax_vec: 2424f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_minmax_vec; 242538dc1294SRichard Henderson case INDEX_op_bitsel_vec: 2426f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_bitsel_vec; 2427f75da298SRichard Henderson case INDEX_op_cmpsel_vec: 2428f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_cmpsel_vec; 2429d2fd745fSRichard Henderson 2430db432672SRichard Henderson default: 24315500bd9eSRichard Henderson if (op < INDEX_op_last_generic) { 24325500bd9eSRichard Henderson const TCGOutOp *outop; 24335500bd9eSRichard Henderson TCGConstraintSetIndex con_set; 24345500bd9eSRichard Henderson 24355500bd9eSRichard Henderson if (!has_type) { 24365500bd9eSRichard Henderson return false; 24375500bd9eSRichard Henderson } 24385500bd9eSRichard Henderson 24395500bd9eSRichard Henderson outop = all_outop[op]; 24405500bd9eSRichard Henderson tcg_debug_assert(outop != NULL); 24415500bd9eSRichard Henderson 24425500bd9eSRichard Henderson con_set = outop->static_constraint; 24435500bd9eSRichard Henderson if (con_set == C_Dynamic) { 24445500bd9eSRichard Henderson con_set = outop->dynamic_constraint(type, flags); 24455500bd9eSRichard Henderson } 24465500bd9eSRichard Henderson if (con_set >= 0) { 2447db432672SRichard Henderson return true; 2448be0f34b5SRichard Henderson } 24495500bd9eSRichard Henderson tcg_debug_assert(con_set == C_NotImplemented); 24505500bd9eSRichard Henderson return false; 24515500bd9eSRichard Henderson } 24525500bd9eSRichard Henderson tcg_debug_assert(op < NB_OPS); 24535500bd9eSRichard Henderson return true; 24545500bd9eSRichard Henderson 24555500bd9eSRichard Henderson case INDEX_op_last_generic: 24565500bd9eSRichard Henderson g_assert_not_reached(); 24575500bd9eSRichard Henderson } 2458be0f34b5SRichard Henderson } 2459be0f34b5SRichard Henderson 24600e4c6424SRichard Henderson bool tcg_op_deposit_valid(TCGType type, unsigned ofs, unsigned len) 24610e4c6424SRichard Henderson { 24626482e9d2SRichard Henderson unsigned width; 24636482e9d2SRichard Henderson 24646482e9d2SRichard Henderson tcg_debug_assert(type == TCG_TYPE_I32 || type == TCG_TYPE_I64); 24656482e9d2SRichard Henderson width = (type == TCG_TYPE_I32 ? 32 : 64); 24666482e9d2SRichard Henderson 24676482e9d2SRichard Henderson tcg_debug_assert(ofs < width); 24680e4c6424SRichard Henderson tcg_debug_assert(len > 0); 24696482e9d2SRichard Henderson tcg_debug_assert(len <= width - ofs); 24706482e9d2SRichard Henderson 24716482e9d2SRichard Henderson return TCG_TARGET_deposit_valid(type, ofs, len); 24720e4c6424SRichard Henderson } 24730e4c6424SRichard Henderson 247439004a71SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs); 247539004a71SRichard Henderson 247683a0ad26SRichard Henderson static void tcg_gen_callN(void *func, TCGHelperInfo *info, 247783a0ad26SRichard Henderson TCGTemp *ret, TCGTemp **args) 2478c896fe29Sbellard { 247939004a71SRichard Henderson TCGv_i64 extend_free[MAX_CALL_IARGS]; 248039004a71SRichard Henderson int n_extend = 0; 248175e8b9b7SRichard Henderson TCGOp *op; 248239004a71SRichard Henderson int i, n, pi = 0, total_args; 2483afb49896SRichard Henderson 2484d53106c9SRichard Henderson if (unlikely(g_once_init_enter(HELPER_INFO_INIT(info)))) { 2485d53106c9SRichard Henderson init_call_layout(info); 2486d53106c9SRichard Henderson g_once_init_leave(HELPER_INFO_INIT(info), HELPER_INFO_INIT_VAL(info)); 2487d53106c9SRichard Henderson } 2488d53106c9SRichard Henderson 248939004a71SRichard Henderson total_args = info->nr_out + info->nr_in + 2; 249039004a71SRichard Henderson op = tcg_op_alloc(INDEX_op_call, total_args); 24912bece2c8SRichard Henderson 249238b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN 249317083f6fSEmilio Cota /* Flag helpers that may affect guest state */ 2494b0748975SRichard Henderson if (tcg_ctx->plugin_insn && !(info->flags & TCG_CALL_NO_SIDE_EFFECTS)) { 249538b47b19SEmilio G. Cota tcg_ctx->plugin_insn->calls_helpers = true; 249638b47b19SEmilio G. Cota } 249738b47b19SEmilio G. Cota #endif 249838b47b19SEmilio G. Cota 249939004a71SRichard Henderson TCGOP_CALLO(op) = n = info->nr_out; 250039004a71SRichard Henderson switch (n) { 250139004a71SRichard Henderson case 0: 250239004a71SRichard Henderson tcg_debug_assert(ret == NULL); 250339004a71SRichard Henderson break; 250439004a71SRichard Henderson case 1: 250539004a71SRichard Henderson tcg_debug_assert(ret != NULL); 250639004a71SRichard Henderson op->args[pi++] = temp_arg(ret); 250739004a71SRichard Henderson break; 250839004a71SRichard Henderson case 2: 2509466d3759SRichard Henderson case 4: 251039004a71SRichard Henderson tcg_debug_assert(ret != NULL); 2511466d3759SRichard Henderson tcg_debug_assert(ret->base_type == ret->type + ctz32(n)); 251239004a71SRichard Henderson tcg_debug_assert(ret->temp_subindex == 0); 2513466d3759SRichard Henderson for (i = 0; i < n; ++i) { 2514466d3759SRichard Henderson op->args[pi++] = temp_arg(ret + i); 2515466d3759SRichard Henderson } 251639004a71SRichard Henderson break; 251739004a71SRichard Henderson default: 251839004a71SRichard Henderson g_assert_not_reached(); 251939004a71SRichard Henderson } 25207319d83aSRichard Henderson 252139004a71SRichard Henderson TCGOP_CALLI(op) = n = info->nr_in; 252239004a71SRichard Henderson for (i = 0; i < n; i++) { 252339004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i]; 252439004a71SRichard Henderson TCGTemp *ts = args[loc->arg_idx] + loc->tmp_subindex; 252539004a71SRichard Henderson 252639004a71SRichard Henderson switch (loc->kind) { 252739004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 2528313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF: 2529313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF_N: 253039004a71SRichard Henderson op->args[pi++] = temp_arg(ts); 253139004a71SRichard Henderson break; 253239004a71SRichard Henderson 253339004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 253439004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 253539004a71SRichard Henderson { 25365dd48602SRichard Henderson TCGv_i64 temp = tcg_temp_ebb_new_i64(); 253739004a71SRichard Henderson TCGv_i32 orig = temp_tcgv_i32(ts); 253839004a71SRichard Henderson 253939004a71SRichard Henderson if (loc->kind == TCG_CALL_ARG_EXTEND_S) { 254018cf3d07SRichard Henderson tcg_gen_ext_i32_i64(temp, orig); 25412bece2c8SRichard Henderson } else { 254218cf3d07SRichard Henderson tcg_gen_extu_i32_i64(temp, orig); 25432bece2c8SRichard Henderson } 254439004a71SRichard Henderson op->args[pi++] = tcgv_i64_arg(temp); 254539004a71SRichard Henderson extend_free[n_extend++] = temp; 25462bece2c8SRichard Henderson } 254739004a71SRichard Henderson break; 25482bece2c8SRichard Henderson 2549e2a9dd6bSRichard Henderson default: 2550e2a9dd6bSRichard Henderson g_assert_not_reached(); 2551e2a9dd6bSRichard Henderson } 2552c896fe29Sbellard } 255383a0ad26SRichard Henderson op->args[pi++] = (uintptr_t)func; 25543e92aa34SRichard Henderson op->args[pi++] = (uintptr_t)info; 255539004a71SRichard Henderson tcg_debug_assert(pi == total_args); 2556a7812ae4Spbrook 255707843f75SRichard Henderson if (tcg_ctx->emit_before_op) { 255807843f75SRichard Henderson QTAILQ_INSERT_BEFORE(tcg_ctx->emit_before_op, op, link); 255907843f75SRichard Henderson } else { 256039004a71SRichard Henderson QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link); 256107843f75SRichard Henderson } 25622bece2c8SRichard Henderson 256339004a71SRichard Henderson tcg_debug_assert(n_extend < ARRAY_SIZE(extend_free)); 256439004a71SRichard Henderson for (i = 0; i < n_extend; ++i) { 256539004a71SRichard Henderson tcg_temp_free_i64(extend_free[i]); 2566eb8b0224SRichard Henderson } 2567a7812ae4Spbrook } 2568c896fe29Sbellard 256983a0ad26SRichard Henderson void tcg_gen_call0(void *func, TCGHelperInfo *info, TCGTemp *ret) 2570a3a692b8SRichard Henderson { 257183a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, NULL); 2572a3a692b8SRichard Henderson } 2573a3a692b8SRichard Henderson 257483a0ad26SRichard Henderson void tcg_gen_call1(void *func, TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1) 2575a3a692b8SRichard Henderson { 257683a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, &t1); 2577a3a692b8SRichard Henderson } 2578a3a692b8SRichard Henderson 257983a0ad26SRichard Henderson void tcg_gen_call2(void *func, TCGHelperInfo *info, TCGTemp *ret, 258083a0ad26SRichard Henderson TCGTemp *t1, TCGTemp *t2) 2581a3a692b8SRichard Henderson { 2582a3a692b8SRichard Henderson TCGTemp *args[2] = { t1, t2 }; 258383a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, args); 2584a3a692b8SRichard Henderson } 2585a3a692b8SRichard Henderson 258683a0ad26SRichard Henderson void tcg_gen_call3(void *func, TCGHelperInfo *info, TCGTemp *ret, 258783a0ad26SRichard Henderson TCGTemp *t1, TCGTemp *t2, TCGTemp *t3) 2588a3a692b8SRichard Henderson { 2589a3a692b8SRichard Henderson TCGTemp *args[3] = { t1, t2, t3 }; 259083a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, args); 2591a3a692b8SRichard Henderson } 2592a3a692b8SRichard Henderson 259383a0ad26SRichard Henderson void tcg_gen_call4(void *func, TCGHelperInfo *info, TCGTemp *ret, 259483a0ad26SRichard Henderson TCGTemp *t1, TCGTemp *t2, TCGTemp *t3, TCGTemp *t4) 2595a3a692b8SRichard Henderson { 2596a3a692b8SRichard Henderson TCGTemp *args[4] = { t1, t2, t3, t4 }; 259783a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, args); 2598a3a692b8SRichard Henderson } 2599a3a692b8SRichard Henderson 260083a0ad26SRichard Henderson void tcg_gen_call5(void *func, TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1, 2601a3a692b8SRichard Henderson TCGTemp *t2, TCGTemp *t3, TCGTemp *t4, TCGTemp *t5) 2602a3a692b8SRichard Henderson { 2603a3a692b8SRichard Henderson TCGTemp *args[5] = { t1, t2, t3, t4, t5 }; 260483a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, args); 2605a3a692b8SRichard Henderson } 2606a3a692b8SRichard Henderson 260783a0ad26SRichard Henderson void tcg_gen_call6(void *func, TCGHelperInfo *info, TCGTemp *ret, 260883a0ad26SRichard Henderson TCGTemp *t1, TCGTemp *t2, TCGTemp *t3, 260983a0ad26SRichard Henderson TCGTemp *t4, TCGTemp *t5, TCGTemp *t6) 2610a3a692b8SRichard Henderson { 2611a3a692b8SRichard Henderson TCGTemp *args[6] = { t1, t2, t3, t4, t5, t6 }; 261283a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, args); 2613a3a692b8SRichard Henderson } 2614a3a692b8SRichard Henderson 261583a0ad26SRichard Henderson void tcg_gen_call7(void *func, TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1, 2616a3a692b8SRichard Henderson TCGTemp *t2, TCGTemp *t3, TCGTemp *t4, 2617a3a692b8SRichard Henderson TCGTemp *t5, TCGTemp *t6, TCGTemp *t7) 2618a3a692b8SRichard Henderson { 2619a3a692b8SRichard Henderson TCGTemp *args[7] = { t1, t2, t3, t4, t5, t6, t7 }; 262083a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, args); 2621a3a692b8SRichard Henderson } 2622a3a692b8SRichard Henderson 26238fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s) 2624c896fe29Sbellard { 2625ac3b8891SRichard Henderson int i, n; 2626ac3b8891SRichard Henderson 2627ee17db83SRichard Henderson for (i = 0, n = s->nb_temps; i < n; i++) { 2628ee17db83SRichard Henderson TCGTemp *ts = &s->temps[i]; 2629ee17db83SRichard Henderson TCGTempVal val = TEMP_VAL_MEM; 2630ee17db83SRichard Henderson 2631ee17db83SRichard Henderson switch (ts->kind) { 2632c0522136SRichard Henderson case TEMP_CONST: 2633c0522136SRichard Henderson val = TEMP_VAL_CONST; 2634c0522136SRichard Henderson break; 2635ee17db83SRichard Henderson case TEMP_FIXED: 2636ee17db83SRichard Henderson val = TEMP_VAL_REG; 2637ee17db83SRichard Henderson break; 2638ee17db83SRichard Henderson case TEMP_GLOBAL: 2639ee17db83SRichard Henderson break; 2640c7482438SRichard Henderson case TEMP_EBB: 2641ee17db83SRichard Henderson val = TEMP_VAL_DEAD; 2642ee17db83SRichard Henderson /* fall through */ 2643f57c6915SRichard Henderson case TEMP_TB: 2644e8996ee0Sbellard ts->mem_allocated = 0; 2645ee17db83SRichard Henderson break; 2646ee17db83SRichard Henderson default: 2647ee17db83SRichard Henderson g_assert_not_reached(); 2648ee17db83SRichard Henderson } 2649ee17db83SRichard Henderson ts->val_type = val; 2650e8996ee0Sbellard } 2651f8b2f202SRichard Henderson 2652f8b2f202SRichard Henderson memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp)); 2653c896fe29Sbellard } 2654c896fe29Sbellard 2655f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size, 2656f8b2f202SRichard Henderson TCGTemp *ts) 2657c896fe29Sbellard { 26581807f4c4SRichard Henderson int idx = temp_idx(ts); 2659ac56dd48Spbrook 2660ee17db83SRichard Henderson switch (ts->kind) { 2661ee17db83SRichard Henderson case TEMP_FIXED: 2662ee17db83SRichard Henderson case TEMP_GLOBAL: 2663ac56dd48Spbrook pstrcpy(buf, buf_size, ts->name); 2664ee17db83SRichard Henderson break; 2665f57c6915SRichard Henderson case TEMP_TB: 2666641d5fbeSbellard snprintf(buf, buf_size, "loc%d", idx - s->nb_globals); 2667ee17db83SRichard Henderson break; 2668c7482438SRichard Henderson case TEMP_EBB: 2669ac56dd48Spbrook snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals); 2670ee17db83SRichard Henderson break; 2671c0522136SRichard Henderson case TEMP_CONST: 2672c0522136SRichard Henderson switch (ts->type) { 2673c0522136SRichard Henderson case TCG_TYPE_I32: 2674c0522136SRichard Henderson snprintf(buf, buf_size, "$0x%x", (int32_t)ts->val); 2675c0522136SRichard Henderson break; 2676c0522136SRichard Henderson #if TCG_TARGET_REG_BITS > 32 2677c0522136SRichard Henderson case TCG_TYPE_I64: 2678c0522136SRichard Henderson snprintf(buf, buf_size, "$0x%" PRIx64, ts->val); 2679c0522136SRichard Henderson break; 2680c0522136SRichard Henderson #endif 2681c0522136SRichard Henderson case TCG_TYPE_V64: 2682c0522136SRichard Henderson case TCG_TYPE_V128: 2683c0522136SRichard Henderson case TCG_TYPE_V256: 2684c0522136SRichard Henderson snprintf(buf, buf_size, "v%d$0x%" PRIx64, 2685c0522136SRichard Henderson 64 << (ts->type - TCG_TYPE_V64), ts->val); 2686c0522136SRichard Henderson break; 2687c0522136SRichard Henderson default: 2688c0522136SRichard Henderson g_assert_not_reached(); 2689c0522136SRichard Henderson } 2690c0522136SRichard Henderson break; 2691c896fe29Sbellard } 2692c896fe29Sbellard return buf; 2693c896fe29Sbellard } 2694c896fe29Sbellard 269543439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf, 269643439139SRichard Henderson int buf_size, TCGArg arg) 2697f8b2f202SRichard Henderson { 269843439139SRichard Henderson return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg)); 2699f8b2f202SRichard Henderson } 2700f8b2f202SRichard Henderson 2701f48f3edeSblueswir1 static const char * const cond_name[] = 2702f48f3edeSblueswir1 { 27030aed257fSRichard Henderson [TCG_COND_NEVER] = "never", 27040aed257fSRichard Henderson [TCG_COND_ALWAYS] = "always", 2705f48f3edeSblueswir1 [TCG_COND_EQ] = "eq", 2706f48f3edeSblueswir1 [TCG_COND_NE] = "ne", 2707f48f3edeSblueswir1 [TCG_COND_LT] = "lt", 2708f48f3edeSblueswir1 [TCG_COND_GE] = "ge", 2709f48f3edeSblueswir1 [TCG_COND_LE] = "le", 2710f48f3edeSblueswir1 [TCG_COND_GT] = "gt", 2711f48f3edeSblueswir1 [TCG_COND_LTU] = "ltu", 2712f48f3edeSblueswir1 [TCG_COND_GEU] = "geu", 2713f48f3edeSblueswir1 [TCG_COND_LEU] = "leu", 2714d48097d0SRichard Henderson [TCG_COND_GTU] = "gtu", 2715d48097d0SRichard Henderson [TCG_COND_TSTEQ] = "tsteq", 2716d48097d0SRichard Henderson [TCG_COND_TSTNE] = "tstne", 2717f48f3edeSblueswir1 }; 2718f48f3edeSblueswir1 271912fde9bcSRichard Henderson static const char * const ldst_name[(MO_BSWAP | MO_SSIZE) + 1] = 2720f713d6adSRichard Henderson { 2721f713d6adSRichard Henderson [MO_UB] = "ub", 2722f713d6adSRichard Henderson [MO_SB] = "sb", 2723f713d6adSRichard Henderson [MO_LEUW] = "leuw", 2724f713d6adSRichard Henderson [MO_LESW] = "lesw", 2725f713d6adSRichard Henderson [MO_LEUL] = "leul", 2726f713d6adSRichard Henderson [MO_LESL] = "lesl", 2727fc313c64SFrédéric Pétrot [MO_LEUQ] = "leq", 2728f713d6adSRichard Henderson [MO_BEUW] = "beuw", 2729f713d6adSRichard Henderson [MO_BESW] = "besw", 2730f713d6adSRichard Henderson [MO_BEUL] = "beul", 2731f713d6adSRichard Henderson [MO_BESL] = "besl", 2732fc313c64SFrédéric Pétrot [MO_BEUQ] = "beq", 273312fde9bcSRichard Henderson [MO_128 + MO_BE] = "beo", 273412fde9bcSRichard Henderson [MO_128 + MO_LE] = "leo", 2735f713d6adSRichard Henderson }; 2736f713d6adSRichard Henderson 27371f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = { 27381f00b27fSSergey Sorokin [MO_UNALN >> MO_ASHIFT] = "un+", 27391f00b27fSSergey Sorokin [MO_ALIGN >> MO_ASHIFT] = "al+", 27401f00b27fSSergey Sorokin [MO_ALIGN_2 >> MO_ASHIFT] = "al2+", 27411f00b27fSSergey Sorokin [MO_ALIGN_4 >> MO_ASHIFT] = "al4+", 27421f00b27fSSergey Sorokin [MO_ALIGN_8 >> MO_ASHIFT] = "al8+", 27431f00b27fSSergey Sorokin [MO_ALIGN_16 >> MO_ASHIFT] = "al16+", 27441f00b27fSSergey Sorokin [MO_ALIGN_32 >> MO_ASHIFT] = "al32+", 27451f00b27fSSergey Sorokin [MO_ALIGN_64 >> MO_ASHIFT] = "al64+", 27461f00b27fSSergey Sorokin }; 27471f00b27fSSergey Sorokin 274837031fefSRichard Henderson static const char * const atom_name[(MO_ATOM_MASK >> MO_ATOM_SHIFT) + 1] = { 274937031fefSRichard Henderson [MO_ATOM_IFALIGN >> MO_ATOM_SHIFT] = "", 275037031fefSRichard Henderson [MO_ATOM_IFALIGN_PAIR >> MO_ATOM_SHIFT] = "pair+", 275137031fefSRichard Henderson [MO_ATOM_WITHIN16 >> MO_ATOM_SHIFT] = "w16+", 275237031fefSRichard Henderson [MO_ATOM_WITHIN16_PAIR >> MO_ATOM_SHIFT] = "w16p+", 275337031fefSRichard Henderson [MO_ATOM_SUBALIGN >> MO_ATOM_SHIFT] = "sub+", 275437031fefSRichard Henderson [MO_ATOM_NONE >> MO_ATOM_SHIFT] = "noat+", 275537031fefSRichard Henderson }; 275637031fefSRichard Henderson 2757587195bdSRichard Henderson static const char bswap_flag_name[][6] = { 2758587195bdSRichard Henderson [TCG_BSWAP_IZ] = "iz", 2759587195bdSRichard Henderson [TCG_BSWAP_OZ] = "oz", 2760587195bdSRichard Henderson [TCG_BSWAP_OS] = "os", 2761587195bdSRichard Henderson [TCG_BSWAP_IZ | TCG_BSWAP_OZ] = "iz,oz", 2762587195bdSRichard Henderson [TCG_BSWAP_IZ | TCG_BSWAP_OS] = "iz,os", 2763587195bdSRichard Henderson }; 2764587195bdSRichard Henderson 2765b384c734SRichard Henderson #ifdef CONFIG_PLUGIN 2766b384c734SRichard Henderson static const char * const plugin_from_name[] = { 2767b384c734SRichard Henderson "from-tb", 2768b384c734SRichard Henderson "from-insn", 2769b384c734SRichard Henderson "after-insn", 2770b384c734SRichard Henderson "after-tb", 2771b384c734SRichard Henderson }; 2772b384c734SRichard Henderson #endif 2773b384c734SRichard Henderson 2774b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d) 2775b016486eSRichard Henderson { 2776b016486eSRichard Henderson return (d & (d - 1)) == 0; 2777b016486eSRichard Henderson } 2778b016486eSRichard Henderson 2779b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d) 2780b016486eSRichard Henderson { 2781b016486eSRichard Henderson if (TCG_TARGET_NB_REGS <= 32) { 2782b016486eSRichard Henderson return ctz32(d); 2783b016486eSRichard Henderson } else { 2784b016486eSRichard Henderson return ctz64(d); 2785b016486eSRichard Henderson } 2786b016486eSRichard Henderson } 2787b016486eSRichard Henderson 2788b7a83ff8SRichard Henderson /* Return only the number of characters output -- no error return. */ 2789b7a83ff8SRichard Henderson #define ne_fprintf(...) \ 2790b7a83ff8SRichard Henderson ({ int ret_ = fprintf(__VA_ARGS__); ret_ >= 0 ? ret_ : 0; }) 2791b7a83ff8SRichard Henderson 2792b384c734SRichard Henderson void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs) 2793c896fe29Sbellard { 2794c896fe29Sbellard char buf[128]; 2795c45cb8bbSRichard Henderson TCGOp *op; 2796c896fe29Sbellard 279715fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 2798c45cb8bbSRichard Henderson int i, k, nb_oargs, nb_iargs, nb_cargs; 2799c45cb8bbSRichard Henderson const TCGOpDef *def; 2800c45cb8bbSRichard Henderson TCGOpcode c; 2801bdfb460eSRichard Henderson int col = 0; 2802c45cb8bbSRichard Henderson 2803c45cb8bbSRichard Henderson c = op->opc; 2804c896fe29Sbellard def = &tcg_op_defs[c]; 2805c45cb8bbSRichard Henderson 2806765b842aSRichard Henderson if (c == INDEX_op_insn_start) { 2807b016486eSRichard Henderson nb_oargs = 0; 2808b7a83ff8SRichard Henderson col += ne_fprintf(f, "\n ----"); 28099aef40edSRichard Henderson 2810747bd69dSRichard Henderson for (i = 0, k = s->insn_start_words; i < k; ++i) { 2811c9ad8d27SRichard Henderson col += ne_fprintf(f, " %016" PRIx64, 2812c9ad8d27SRichard Henderson tcg_get_insn_start_param(op, i)); 2813eeacee4dSBlue Swirl } 28147e4597d7Sbellard } else if (c == INDEX_op_call) { 28153e92aa34SRichard Henderson const TCGHelperInfo *info = tcg_call_info(op); 2816fa52e660SRichard Henderson void *func = tcg_call_func(op); 28173e92aa34SRichard Henderson 2818c896fe29Sbellard /* variable number of arguments */ 2819cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 2820cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 2821c896fe29Sbellard nb_cargs = def->nb_cargs; 2822b03cce8eSbellard 2823b7a83ff8SRichard Henderson col += ne_fprintf(f, " %s ", def->name); 28243e92aa34SRichard Henderson 28253e92aa34SRichard Henderson /* 28263e92aa34SRichard Henderson * Print the function name from TCGHelperInfo, if available. 28273e92aa34SRichard Henderson * Note that plugins have a template function for the info, 28283e92aa34SRichard Henderson * but the actual function pointer comes from the plugin. 28293e92aa34SRichard Henderson */ 28303e92aa34SRichard Henderson if (func == info->func) { 2831b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s", info->name); 28323e92aa34SRichard Henderson } else { 2833b7a83ff8SRichard Henderson col += ne_fprintf(f, "plugin(%p)", func); 28343e92aa34SRichard Henderson } 28353e92aa34SRichard Henderson 2836b7a83ff8SRichard Henderson col += ne_fprintf(f, ",$0x%x,$%d", info->flags, nb_oargs); 2837b03cce8eSbellard for (i = 0; i < nb_oargs; i++) { 2838b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", tcg_get_arg_str(s, buf, sizeof(buf), 2839efee3746SRichard Henderson op->args[i])); 2840b03cce8eSbellard } 2841cf066674SRichard Henderson for (i = 0; i < nb_iargs; i++) { 2842efee3746SRichard Henderson TCGArg arg = op->args[nb_oargs + i]; 284339004a71SRichard Henderson const char *t = tcg_get_arg_str(s, buf, sizeof(buf), arg); 2844b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", t); 2845e8996ee0Sbellard } 2846b03cce8eSbellard } else { 2847b5701261SRichard Henderson if (def->flags & TCG_OPF_INT) { 2848b5701261SRichard Henderson col += ne_fprintf(f, " %s_i%d ", 2849b5701261SRichard Henderson def->name, 2850b5701261SRichard Henderson 8 * tcg_type_size(TCGOP_TYPE(op))); 2851b5701261SRichard Henderson } else if (def->flags & TCG_OPF_VECTOR) { 2852b5701261SRichard Henderson col += ne_fprintf(f, "%s v%d,e%d,", 2853b5701261SRichard Henderson def->name, 2854b5701261SRichard Henderson 8 * tcg_type_size(TCGOP_TYPE(op)), 2855b5701261SRichard Henderson 8 << TCGOP_VECE(op)); 2856b5701261SRichard Henderson } else { 2857b7a83ff8SRichard Henderson col += ne_fprintf(f, " %s ", def->name); 2858b5701261SRichard Henderson } 2859c45cb8bbSRichard Henderson 2860c896fe29Sbellard nb_oargs = def->nb_oargs; 2861c896fe29Sbellard nb_iargs = def->nb_iargs; 2862c896fe29Sbellard nb_cargs = def->nb_cargs; 2863c896fe29Sbellard 2864c896fe29Sbellard k = 0; 2865c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 2866b7a83ff8SRichard Henderson const char *sep = k ? "," : ""; 2867b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s%s", sep, 2868b7a83ff8SRichard Henderson tcg_get_arg_str(s, buf, sizeof(buf), 2869efee3746SRichard Henderson op->args[k++])); 2870c896fe29Sbellard } 2871c896fe29Sbellard for (i = 0; i < nb_iargs; i++) { 2872b7a83ff8SRichard Henderson const char *sep = k ? "," : ""; 2873b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s%s", sep, 2874b7a83ff8SRichard Henderson tcg_get_arg_str(s, buf, sizeof(buf), 2875efee3746SRichard Henderson op->args[k++])); 2876c896fe29Sbellard } 2877be210acbSRichard Henderson switch (c) { 2878be210acbSRichard Henderson case INDEX_op_brcond_i32: 2879ffc5ea09SRichard Henderson case INDEX_op_setcond_i32: 28803635502dSRichard Henderson case INDEX_op_negsetcond_i32: 2881ffc5ea09SRichard Henderson case INDEX_op_movcond_i32: 2882be210acbSRichard Henderson case INDEX_op_brcond2_i32: 2883be210acbSRichard Henderson case INDEX_op_setcond2_i32: 2884ffc5ea09SRichard Henderson case INDEX_op_brcond_i64: 2885be210acbSRichard Henderson case INDEX_op_setcond_i64: 28863635502dSRichard Henderson case INDEX_op_negsetcond_i64: 2887ffc5ea09SRichard Henderson case INDEX_op_movcond_i64: 2888212be173SRichard Henderson case INDEX_op_cmp_vec: 2889f75da298SRichard Henderson case INDEX_op_cmpsel_vec: 2890efee3746SRichard Henderson if (op->args[k] < ARRAY_SIZE(cond_name) 2891efee3746SRichard Henderson && cond_name[op->args[k]]) { 2892b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", cond_name[op->args[k++]]); 2893eeacee4dSBlue Swirl } else { 2894b7a83ff8SRichard Henderson col += ne_fprintf(f, ",$0x%" TCG_PRIlx, op->args[k++]); 2895eeacee4dSBlue Swirl } 2896f48f3edeSblueswir1 i = 1; 2897be210acbSRichard Henderson break; 289850b7a197SRichard Henderson case INDEX_op_qemu_ld_i32: 289950b7a197SRichard Henderson case INDEX_op_qemu_st_i32: 290050b7a197SRichard Henderson case INDEX_op_qemu_st8_i32: 290150b7a197SRichard Henderson case INDEX_op_qemu_ld_i64: 290250b7a197SRichard Henderson case INDEX_op_qemu_st_i64: 290350b7a197SRichard Henderson case INDEX_op_qemu_ld_i128: 290450b7a197SRichard Henderson case INDEX_op_qemu_st_i128: 290559227d5dSRichard Henderson { 290637031fefSRichard Henderson const char *s_al, *s_op, *s_at; 29079002ffcbSRichard Henderson MemOpIdx oi = op->args[k++]; 29089a239c6eSPhilippe Mathieu-Daudé MemOp mop = get_memop(oi); 290959227d5dSRichard Henderson unsigned ix = get_mmuidx(oi); 291059227d5dSRichard Henderson 29119a239c6eSPhilippe Mathieu-Daudé s_al = alignment_name[(mop & MO_AMASK) >> MO_ASHIFT]; 29129a239c6eSPhilippe Mathieu-Daudé s_op = ldst_name[mop & (MO_BSWAP | MO_SSIZE)]; 29139a239c6eSPhilippe Mathieu-Daudé s_at = atom_name[(mop & MO_ATOM_MASK) >> MO_ATOM_SHIFT]; 29149a239c6eSPhilippe Mathieu-Daudé mop &= ~(MO_AMASK | MO_BSWAP | MO_SSIZE | MO_ATOM_MASK); 291537031fefSRichard Henderson 291637031fefSRichard Henderson /* If all fields are accounted for, print symbolically. */ 29179a239c6eSPhilippe Mathieu-Daudé if (!mop && s_al && s_op && s_at) { 291837031fefSRichard Henderson col += ne_fprintf(f, ",%s%s%s,%u", 291937031fefSRichard Henderson s_at, s_al, s_op, ix); 292037031fefSRichard Henderson } else { 29219a239c6eSPhilippe Mathieu-Daudé mop = get_memop(oi); 29229a239c6eSPhilippe Mathieu-Daudé col += ne_fprintf(f, ",$0x%x,%u", mop, ix); 2923f713d6adSRichard Henderson } 2924f713d6adSRichard Henderson i = 1; 292559227d5dSRichard Henderson } 2926f713d6adSRichard Henderson break; 2927587195bdSRichard Henderson case INDEX_op_bswap16_i32: 2928587195bdSRichard Henderson case INDEX_op_bswap16_i64: 2929587195bdSRichard Henderson case INDEX_op_bswap32_i32: 2930587195bdSRichard Henderson case INDEX_op_bswap32_i64: 2931587195bdSRichard Henderson case INDEX_op_bswap64_i64: 2932587195bdSRichard Henderson { 2933587195bdSRichard Henderson TCGArg flags = op->args[k]; 2934587195bdSRichard Henderson const char *name = NULL; 2935587195bdSRichard Henderson 2936587195bdSRichard Henderson if (flags < ARRAY_SIZE(bswap_flag_name)) { 2937587195bdSRichard Henderson name = bswap_flag_name[flags]; 2938587195bdSRichard Henderson } 2939587195bdSRichard Henderson if (name) { 2940b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", name); 2941587195bdSRichard Henderson } else { 2942b7a83ff8SRichard Henderson col += ne_fprintf(f, ",$0x%" TCG_PRIlx, flags); 2943587195bdSRichard Henderson } 2944587195bdSRichard Henderson i = k = 1; 2945587195bdSRichard Henderson } 2946587195bdSRichard Henderson break; 2947b384c734SRichard Henderson #ifdef CONFIG_PLUGIN 2948b384c734SRichard Henderson case INDEX_op_plugin_cb: 2949b384c734SRichard Henderson { 2950b384c734SRichard Henderson TCGArg from = op->args[k++]; 2951b384c734SRichard Henderson const char *name = NULL; 2952b384c734SRichard Henderson 2953b384c734SRichard Henderson if (from < ARRAY_SIZE(plugin_from_name)) { 2954b384c734SRichard Henderson name = plugin_from_name[from]; 2955b384c734SRichard Henderson } 2956b384c734SRichard Henderson if (name) { 2957b384c734SRichard Henderson col += ne_fprintf(f, "%s", name); 2958b384c734SRichard Henderson } else { 2959b384c734SRichard Henderson col += ne_fprintf(f, "$0x%" TCG_PRIlx, from); 2960b384c734SRichard Henderson } 2961b384c734SRichard Henderson i = 1; 2962b384c734SRichard Henderson } 2963b384c734SRichard Henderson break; 2964b384c734SRichard Henderson #endif 2965be210acbSRichard Henderson default: 2966f48f3edeSblueswir1 i = 0; 2967be210acbSRichard Henderson break; 2968be210acbSRichard Henderson } 296951e3972cSRichard Henderson switch (c) { 297051e3972cSRichard Henderson case INDEX_op_set_label: 297151e3972cSRichard Henderson case INDEX_op_br: 297251e3972cSRichard Henderson case INDEX_op_brcond_i32: 297351e3972cSRichard Henderson case INDEX_op_brcond_i64: 297451e3972cSRichard Henderson case INDEX_op_brcond2_i32: 2975b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s$L%d", k ? "," : "", 2976efee3746SRichard Henderson arg_label(op->args[k])->id); 297751e3972cSRichard Henderson i++, k++; 297851e3972cSRichard Henderson break; 29793470867bSRichard Henderson case INDEX_op_mb: 29803470867bSRichard Henderson { 29813470867bSRichard Henderson TCGBar membar = op->args[k]; 29823470867bSRichard Henderson const char *b_op, *m_op; 29833470867bSRichard Henderson 29843470867bSRichard Henderson switch (membar & TCG_BAR_SC) { 29853470867bSRichard Henderson case 0: 29863470867bSRichard Henderson b_op = "none"; 29873470867bSRichard Henderson break; 29883470867bSRichard Henderson case TCG_BAR_LDAQ: 29893470867bSRichard Henderson b_op = "acq"; 29903470867bSRichard Henderson break; 29913470867bSRichard Henderson case TCG_BAR_STRL: 29923470867bSRichard Henderson b_op = "rel"; 29933470867bSRichard Henderson break; 29943470867bSRichard Henderson case TCG_BAR_SC: 29953470867bSRichard Henderson b_op = "seq"; 29963470867bSRichard Henderson break; 29973470867bSRichard Henderson default: 29983470867bSRichard Henderson g_assert_not_reached(); 29993470867bSRichard Henderson } 30003470867bSRichard Henderson 30013470867bSRichard Henderson switch (membar & TCG_MO_ALL) { 30023470867bSRichard Henderson case 0: 30033470867bSRichard Henderson m_op = "none"; 30043470867bSRichard Henderson break; 30053470867bSRichard Henderson case TCG_MO_LD_LD: 30063470867bSRichard Henderson m_op = "rr"; 30073470867bSRichard Henderson break; 30083470867bSRichard Henderson case TCG_MO_LD_ST: 30093470867bSRichard Henderson m_op = "rw"; 30103470867bSRichard Henderson break; 30113470867bSRichard Henderson case TCG_MO_ST_LD: 30123470867bSRichard Henderson m_op = "wr"; 30133470867bSRichard Henderson break; 30143470867bSRichard Henderson case TCG_MO_ST_ST: 30153470867bSRichard Henderson m_op = "ww"; 30163470867bSRichard Henderson break; 30173470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_LD_ST: 30183470867bSRichard Henderson m_op = "rr+rw"; 30193470867bSRichard Henderson break; 30203470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_ST_LD: 30213470867bSRichard Henderson m_op = "rr+wr"; 30223470867bSRichard Henderson break; 30233470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_ST_ST: 30243470867bSRichard Henderson m_op = "rr+ww"; 30253470867bSRichard Henderson break; 30263470867bSRichard Henderson case TCG_MO_LD_ST | TCG_MO_ST_LD: 30273470867bSRichard Henderson m_op = "rw+wr"; 30283470867bSRichard Henderson break; 30293470867bSRichard Henderson case TCG_MO_LD_ST | TCG_MO_ST_ST: 30303470867bSRichard Henderson m_op = "rw+ww"; 30313470867bSRichard Henderson break; 30323470867bSRichard Henderson case TCG_MO_ST_LD | TCG_MO_ST_ST: 30333470867bSRichard Henderson m_op = "wr+ww"; 30343470867bSRichard Henderson break; 30353470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_MO_ST_LD: 30363470867bSRichard Henderson m_op = "rr+rw+wr"; 30373470867bSRichard Henderson break; 30383470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_MO_ST_ST: 30393470867bSRichard Henderson m_op = "rr+rw+ww"; 30403470867bSRichard Henderson break; 30413470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_ST_LD | TCG_MO_ST_ST: 30423470867bSRichard Henderson m_op = "rr+wr+ww"; 30433470867bSRichard Henderson break; 30443470867bSRichard Henderson case TCG_MO_LD_ST | TCG_MO_ST_LD | TCG_MO_ST_ST: 30453470867bSRichard Henderson m_op = "rw+wr+ww"; 30463470867bSRichard Henderson break; 30473470867bSRichard Henderson case TCG_MO_ALL: 30483470867bSRichard Henderson m_op = "all"; 30493470867bSRichard Henderson break; 30503470867bSRichard Henderson default: 30513470867bSRichard Henderson g_assert_not_reached(); 30523470867bSRichard Henderson } 30533470867bSRichard Henderson 30543470867bSRichard Henderson col += ne_fprintf(f, "%s%s:%s", (k ? "," : ""), b_op, m_op); 30553470867bSRichard Henderson i++, k++; 30563470867bSRichard Henderson } 30573470867bSRichard Henderson break; 305851e3972cSRichard Henderson default: 305951e3972cSRichard Henderson break; 3060eeacee4dSBlue Swirl } 306151e3972cSRichard Henderson for (; i < nb_cargs; i++, k++) { 3062b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s$0x%" TCG_PRIlx, k ? "," : "", 3063b7a83ff8SRichard Henderson op->args[k]); 3064bdfb460eSRichard Henderson } 3065bdfb460eSRichard Henderson } 3066bdfb460eSRichard Henderson 30671894f69aSRichard Henderson if (have_prefs || op->life) { 30681894f69aSRichard Henderson for (; col < 40; ++col) { 3069b7a83ff8SRichard Henderson putc(' ', f); 3070bdfb460eSRichard Henderson } 30711894f69aSRichard Henderson } 30721894f69aSRichard Henderson 30731894f69aSRichard Henderson if (op->life) { 30741894f69aSRichard Henderson unsigned life = op->life; 3075bdfb460eSRichard Henderson 3076bdfb460eSRichard Henderson if (life & (SYNC_ARG * 3)) { 3077b7a83ff8SRichard Henderson ne_fprintf(f, " sync:"); 3078bdfb460eSRichard Henderson for (i = 0; i < 2; ++i) { 3079bdfb460eSRichard Henderson if (life & (SYNC_ARG << i)) { 3080b7a83ff8SRichard Henderson ne_fprintf(f, " %d", i); 3081bdfb460eSRichard Henderson } 3082bdfb460eSRichard Henderson } 3083bdfb460eSRichard Henderson } 3084bdfb460eSRichard Henderson life /= DEAD_ARG; 3085bdfb460eSRichard Henderson if (life) { 3086b7a83ff8SRichard Henderson ne_fprintf(f, " dead:"); 3087bdfb460eSRichard Henderson for (i = 0; life; ++i, life >>= 1) { 3088bdfb460eSRichard Henderson if (life & 1) { 3089b7a83ff8SRichard Henderson ne_fprintf(f, " %d", i); 3090bdfb460eSRichard Henderson } 3091bdfb460eSRichard Henderson } 3092c896fe29Sbellard } 3093b03cce8eSbellard } 30941894f69aSRichard Henderson 30951894f69aSRichard Henderson if (have_prefs) { 30961894f69aSRichard Henderson for (i = 0; i < nb_oargs; ++i) { 309731fd884bSRichard Henderson TCGRegSet set = output_pref(op, i); 30981894f69aSRichard Henderson 30991894f69aSRichard Henderson if (i == 0) { 3100b7a83ff8SRichard Henderson ne_fprintf(f, " pref="); 31011894f69aSRichard Henderson } else { 3102b7a83ff8SRichard Henderson ne_fprintf(f, ","); 31031894f69aSRichard Henderson } 31041894f69aSRichard Henderson if (set == 0) { 3105b7a83ff8SRichard Henderson ne_fprintf(f, "none"); 31061894f69aSRichard Henderson } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) { 3107b7a83ff8SRichard Henderson ne_fprintf(f, "all"); 31081894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG 31091894f69aSRichard Henderson } else if (tcg_regset_single(set)) { 31101894f69aSRichard Henderson TCGReg reg = tcg_regset_first(set); 3111b7a83ff8SRichard Henderson ne_fprintf(f, "%s", tcg_target_reg_names[reg]); 31121894f69aSRichard Henderson #endif 31131894f69aSRichard Henderson } else if (TCG_TARGET_NB_REGS <= 32) { 3114b7a83ff8SRichard Henderson ne_fprintf(f, "0x%x", (uint32_t)set); 31151894f69aSRichard Henderson } else { 3116b7a83ff8SRichard Henderson ne_fprintf(f, "0x%" PRIx64, (uint64_t)set); 31171894f69aSRichard Henderson } 31181894f69aSRichard Henderson } 31191894f69aSRichard Henderson } 31201894f69aSRichard Henderson 3121b7a83ff8SRichard Henderson putc('\n', f); 3122c896fe29Sbellard } 3123c896fe29Sbellard } 3124c896fe29Sbellard 3125c896fe29Sbellard /* we give more priority to constraints with less registers */ 31263e80824eSRichard Henderson static int get_constraint_priority(const TCGArgConstraint *arg_ct, int k) 3127c896fe29Sbellard { 31283e80824eSRichard Henderson int n; 31293e80824eSRichard Henderson 31303e80824eSRichard Henderson arg_ct += k; 31313e80824eSRichard Henderson n = ctpop64(arg_ct->regs); 3132c896fe29Sbellard 313329f5e925SRichard Henderson /* 313429f5e925SRichard Henderson * Sort constraints of a single register first, which includes output 313529f5e925SRichard Henderson * aliases (which must exactly match the input already allocated). 313629f5e925SRichard Henderson */ 313729f5e925SRichard Henderson if (n == 1 || arg_ct->oalias) { 313829f5e925SRichard Henderson return INT_MAX; 3139c896fe29Sbellard } 314029f5e925SRichard Henderson 314129f5e925SRichard Henderson /* 314229f5e925SRichard Henderson * Sort register pairs next, first then second immediately after. 314329f5e925SRichard Henderson * Arbitrarily sort multiple pairs by the index of the first reg; 314429f5e925SRichard Henderson * there shouldn't be many pairs. 314529f5e925SRichard Henderson */ 314629f5e925SRichard Henderson switch (arg_ct->pair) { 314729f5e925SRichard Henderson case 1: 314829f5e925SRichard Henderson case 3: 314929f5e925SRichard Henderson return (k + 1) * 2; 315029f5e925SRichard Henderson case 2: 315129f5e925SRichard Henderson return (arg_ct->pair_index + 1) * 2 - 1; 315229f5e925SRichard Henderson } 315329f5e925SRichard Henderson 315429f5e925SRichard Henderson /* Finally, sort by decreasing register count. */ 315529f5e925SRichard Henderson assert(n > 1); 315629f5e925SRichard Henderson return -n; 3157c896fe29Sbellard } 3158c896fe29Sbellard 3159c896fe29Sbellard /* sort from highest priority to lowest */ 31603e80824eSRichard Henderson static void sort_constraints(TCGArgConstraint *a, int start, int n) 3161c896fe29Sbellard { 316266792f90SRichard Henderson int i, j; 3163c896fe29Sbellard 316466792f90SRichard Henderson for (i = 0; i < n; i++) { 316566792f90SRichard Henderson a[start + i].sort_index = start + i; 316666792f90SRichard Henderson } 316766792f90SRichard Henderson if (n <= 1) { 3168c896fe29Sbellard return; 316966792f90SRichard Henderson } 3170c896fe29Sbellard for (i = 0; i < n - 1; i++) { 3171c896fe29Sbellard for (j = i + 1; j < n; j++) { 31723e80824eSRichard Henderson int p1 = get_constraint_priority(a, a[start + i].sort_index); 31733e80824eSRichard Henderson int p2 = get_constraint_priority(a, a[start + j].sort_index); 3174c896fe29Sbellard if (p1 < p2) { 317566792f90SRichard Henderson int tmp = a[start + i].sort_index; 317666792f90SRichard Henderson a[start + i].sort_index = a[start + j].sort_index; 317766792f90SRichard Henderson a[start + j].sort_index = tmp; 3178c896fe29Sbellard } 3179c896fe29Sbellard } 3180c896fe29Sbellard } 3181c896fe29Sbellard } 3182c896fe29Sbellard 31833e80824eSRichard Henderson static const TCGArgConstraint empty_cts[TCG_MAX_OP_ARGS]; 31843e80824eSRichard Henderson static TCGArgConstraint all_cts[ARRAY_SIZE(constraint_sets)][TCG_MAX_OP_ARGS]; 31853e80824eSRichard Henderson 3186501fb3daSRichard Henderson static void process_constraint_sets(void) 3187c896fe29Sbellard { 31883e80824eSRichard Henderson for (size_t c = 0; c < ARRAY_SIZE(constraint_sets); ++c) { 31893e80824eSRichard Henderson const TCGConstraintSet *tdefs = &constraint_sets[c]; 31903e80824eSRichard Henderson TCGArgConstraint *args_ct = all_cts[c]; 31913e80824eSRichard Henderson int nb_oargs = tdefs->nb_oargs; 31923e80824eSRichard Henderson int nb_iargs = tdefs->nb_iargs; 31933e80824eSRichard Henderson int nb_args = nb_oargs + nb_iargs; 319429f5e925SRichard Henderson bool saw_alias_pair = false; 3195f69d277eSRichard Henderson 31963e80824eSRichard Henderson for (int i = 0; i < nb_args; i++) { 3197f69d277eSRichard Henderson const char *ct_str = tdefs->args_ct_str[i]; 31983e80824eSRichard Henderson bool input_p = i >= nb_oargs; 31993e80824eSRichard Henderson int o; 3200f69d277eSRichard Henderson 320117280ff4SRichard Henderson switch (*ct_str) { 320217280ff4SRichard Henderson case '0' ... '9': 32038940ea0dSPhilippe Mathieu-Daudé o = *ct_str - '0'; 32048940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(input_p); 32053e80824eSRichard Henderson tcg_debug_assert(o < nb_oargs); 32063e80824eSRichard Henderson tcg_debug_assert(args_ct[o].regs != 0); 32073e80824eSRichard Henderson tcg_debug_assert(!args_ct[o].oalias); 32083e80824eSRichard Henderson args_ct[i] = args_ct[o]; 3209bc2b17e6SRichard Henderson /* The output sets oalias. */ 32103e80824eSRichard Henderson args_ct[o].oalias = 1; 32113e80824eSRichard Henderson args_ct[o].alias_index = i; 3212bc2b17e6SRichard Henderson /* The input sets ialias. */ 32133e80824eSRichard Henderson args_ct[i].ialias = 1; 32143e80824eSRichard Henderson args_ct[i].alias_index = o; 32153e80824eSRichard Henderson if (args_ct[i].pair) { 321629f5e925SRichard Henderson saw_alias_pair = true; 321729f5e925SRichard Henderson } 32188940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(ct_str[1] == '\0'); 32198940ea0dSPhilippe Mathieu-Daudé continue; 32208940ea0dSPhilippe Mathieu-Daudé 322182790a87SRichard Henderson case '&': 32228940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(!input_p); 32233e80824eSRichard Henderson args_ct[i].newreg = true; 322482790a87SRichard Henderson ct_str++; 322582790a87SRichard Henderson break; 322629f5e925SRichard Henderson 322729f5e925SRichard Henderson case 'p': /* plus */ 322829f5e925SRichard Henderson /* Allocate to the register after the previous. */ 32293e80824eSRichard Henderson tcg_debug_assert(i > (input_p ? nb_oargs : 0)); 323029f5e925SRichard Henderson o = i - 1; 32313e80824eSRichard Henderson tcg_debug_assert(!args_ct[o].pair); 32323e80824eSRichard Henderson tcg_debug_assert(!args_ct[o].ct); 32333e80824eSRichard Henderson args_ct[i] = (TCGArgConstraint){ 323429f5e925SRichard Henderson .pair = 2, 323529f5e925SRichard Henderson .pair_index = o, 32363e80824eSRichard Henderson .regs = args_ct[o].regs << 1, 32373e80824eSRichard Henderson .newreg = args_ct[o].newreg, 323829f5e925SRichard Henderson }; 32393e80824eSRichard Henderson args_ct[o].pair = 1; 32403e80824eSRichard Henderson args_ct[o].pair_index = i; 324129f5e925SRichard Henderson tcg_debug_assert(ct_str[1] == '\0'); 324229f5e925SRichard Henderson continue; 324329f5e925SRichard Henderson 324429f5e925SRichard Henderson case 'm': /* minus */ 324529f5e925SRichard Henderson /* Allocate to the register before the previous. */ 32463e80824eSRichard Henderson tcg_debug_assert(i > (input_p ? nb_oargs : 0)); 324729f5e925SRichard Henderson o = i - 1; 32483e80824eSRichard Henderson tcg_debug_assert(!args_ct[o].pair); 32493e80824eSRichard Henderson tcg_debug_assert(!args_ct[o].ct); 32503e80824eSRichard Henderson args_ct[i] = (TCGArgConstraint){ 325129f5e925SRichard Henderson .pair = 1, 325229f5e925SRichard Henderson .pair_index = o, 32533e80824eSRichard Henderson .regs = args_ct[o].regs >> 1, 32543e80824eSRichard Henderson .newreg = args_ct[o].newreg, 325529f5e925SRichard Henderson }; 32563e80824eSRichard Henderson args_ct[o].pair = 2; 32573e80824eSRichard Henderson args_ct[o].pair_index = i; 325829f5e925SRichard Henderson tcg_debug_assert(ct_str[1] == '\0'); 325929f5e925SRichard Henderson continue; 32608940ea0dSPhilippe Mathieu-Daudé } 32618940ea0dSPhilippe Mathieu-Daudé 32628940ea0dSPhilippe Mathieu-Daudé do { 32638940ea0dSPhilippe Mathieu-Daudé switch (*ct_str) { 3264c896fe29Sbellard case 'i': 32653e80824eSRichard Henderson args_ct[i].ct |= TCG_CT_CONST; 3266c896fe29Sbellard break; 32676b8abd24SRichard Henderson #ifdef TCG_REG_ZERO 32686b8abd24SRichard Henderson case 'z': 32696b8abd24SRichard Henderson args_ct[i].ct |= TCG_CT_REG_ZERO; 32706b8abd24SRichard Henderson break; 32716b8abd24SRichard Henderson #endif 3272358b4923SRichard Henderson 3273358b4923SRichard Henderson /* Include all of the target-specific constraints. */ 3274358b4923SRichard Henderson 3275358b4923SRichard Henderson #undef CONST 3276358b4923SRichard Henderson #define CONST(CASE, MASK) \ 32773e80824eSRichard Henderson case CASE: args_ct[i].ct |= MASK; break; 3278358b4923SRichard Henderson #define REGS(CASE, MASK) \ 32793e80824eSRichard Henderson case CASE: args_ct[i].regs |= MASK; break; 3280358b4923SRichard Henderson 3281358b4923SRichard Henderson #include "tcg-target-con-str.h" 3282358b4923SRichard Henderson 3283358b4923SRichard Henderson #undef REGS 3284358b4923SRichard Henderson #undef CONST 3285c896fe29Sbellard default: 32868940ea0dSPhilippe Mathieu-Daudé case '0' ... '9': 32878940ea0dSPhilippe Mathieu-Daudé case '&': 328829f5e925SRichard Henderson case 'p': 328929f5e925SRichard Henderson case 'm': 32903e80824eSRichard Henderson /* Typo in TCGConstraintSet constraint. */ 3291358b4923SRichard Henderson g_assert_not_reached(); 3292358b4923SRichard Henderson } 32938940ea0dSPhilippe Mathieu-Daudé } while (*++ct_str != '\0'); 3294c896fe29Sbellard } 3295c896fe29Sbellard 329629f5e925SRichard Henderson /* 329729f5e925SRichard Henderson * Fix up output pairs that are aliased with inputs. 329829f5e925SRichard Henderson * When we created the alias, we copied pair from the output. 329929f5e925SRichard Henderson * There are three cases: 330029f5e925SRichard Henderson * (1a) Pairs of inputs alias pairs of outputs. 330129f5e925SRichard Henderson * (1b) One input aliases the first of a pair of outputs. 330229f5e925SRichard Henderson * (2) One input aliases the second of a pair of outputs. 330329f5e925SRichard Henderson * 330429f5e925SRichard Henderson * Case 1a is handled by making sure that the pair_index'es are 330529f5e925SRichard Henderson * properly updated so that they appear the same as a pair of inputs. 330629f5e925SRichard Henderson * 330729f5e925SRichard Henderson * Case 1b is handled by setting the pair_index of the input to 330829f5e925SRichard Henderson * itself, simply so it doesn't point to an unrelated argument. 330929f5e925SRichard Henderson * Since we don't encounter the "second" during the input allocation 331029f5e925SRichard Henderson * phase, nothing happens with the second half of the input pair. 331129f5e925SRichard Henderson * 331229f5e925SRichard Henderson * Case 2 is handled by setting the second input to pair=3, the 331329f5e925SRichard Henderson * first output to pair=3, and the pair_index'es to match. 331429f5e925SRichard Henderson */ 331529f5e925SRichard Henderson if (saw_alias_pair) { 33163e80824eSRichard Henderson for (int i = nb_oargs; i < nb_args; i++) { 33173e80824eSRichard Henderson int o, o2, i2; 33183e80824eSRichard Henderson 331929f5e925SRichard Henderson /* 332029f5e925SRichard Henderson * Since [0-9pm] must be alone in the constraint string, 332129f5e925SRichard Henderson * the only way they can both be set is if the pair comes 332229f5e925SRichard Henderson * from the output alias. 332329f5e925SRichard Henderson */ 33243e80824eSRichard Henderson if (!args_ct[i].ialias) { 332529f5e925SRichard Henderson continue; 332629f5e925SRichard Henderson } 33273e80824eSRichard Henderson switch (args_ct[i].pair) { 332829f5e925SRichard Henderson case 0: 332929f5e925SRichard Henderson break; 333029f5e925SRichard Henderson case 1: 33313e80824eSRichard Henderson o = args_ct[i].alias_index; 33323e80824eSRichard Henderson o2 = args_ct[o].pair_index; 33333e80824eSRichard Henderson tcg_debug_assert(args_ct[o].pair == 1); 33343e80824eSRichard Henderson tcg_debug_assert(args_ct[o2].pair == 2); 33353e80824eSRichard Henderson if (args_ct[o2].oalias) { 333629f5e925SRichard Henderson /* Case 1a */ 33373e80824eSRichard Henderson i2 = args_ct[o2].alias_index; 33383e80824eSRichard Henderson tcg_debug_assert(args_ct[i2].pair == 2); 33393e80824eSRichard Henderson args_ct[i2].pair_index = i; 33403e80824eSRichard Henderson args_ct[i].pair_index = i2; 334129f5e925SRichard Henderson } else { 334229f5e925SRichard Henderson /* Case 1b */ 33433e80824eSRichard Henderson args_ct[i].pair_index = i; 334429f5e925SRichard Henderson } 334529f5e925SRichard Henderson break; 334629f5e925SRichard Henderson case 2: 33473e80824eSRichard Henderson o = args_ct[i].alias_index; 33483e80824eSRichard Henderson o2 = args_ct[o].pair_index; 33493e80824eSRichard Henderson tcg_debug_assert(args_ct[o].pair == 2); 33503e80824eSRichard Henderson tcg_debug_assert(args_ct[o2].pair == 1); 33513e80824eSRichard Henderson if (args_ct[o2].oalias) { 335229f5e925SRichard Henderson /* Case 1a */ 33533e80824eSRichard Henderson i2 = args_ct[o2].alias_index; 33543e80824eSRichard Henderson tcg_debug_assert(args_ct[i2].pair == 1); 33553e80824eSRichard Henderson args_ct[i2].pair_index = i; 33563e80824eSRichard Henderson args_ct[i].pair_index = i2; 335729f5e925SRichard Henderson } else { 335829f5e925SRichard Henderson /* Case 2 */ 33593e80824eSRichard Henderson args_ct[i].pair = 3; 33603e80824eSRichard Henderson args_ct[o2].pair = 3; 33613e80824eSRichard Henderson args_ct[i].pair_index = o2; 33623e80824eSRichard Henderson args_ct[o2].pair_index = i; 336329f5e925SRichard Henderson } 336429f5e925SRichard Henderson break; 336529f5e925SRichard Henderson default: 336629f5e925SRichard Henderson g_assert_not_reached(); 336729f5e925SRichard Henderson } 336829f5e925SRichard Henderson } 336929f5e925SRichard Henderson } 337029f5e925SRichard Henderson 3371c896fe29Sbellard /* sort the constraints (XXX: this is just an heuristic) */ 33723e80824eSRichard Henderson sort_constraints(args_ct, 0, nb_oargs); 33733e80824eSRichard Henderson sort_constraints(args_ct, nb_oargs, nb_iargs); 33743e80824eSRichard Henderson } 3375501fb3daSRichard Henderson } 33763e80824eSRichard Henderson 3377501fb3daSRichard Henderson static const TCGArgConstraint *opcode_args_ct(const TCGOp *op) 3378501fb3daSRichard Henderson { 33795500bd9eSRichard Henderson TCGOpcode opc = op->opc; 33805500bd9eSRichard Henderson TCGType type = TCGOP_TYPE(op); 33815500bd9eSRichard Henderson unsigned flags = TCGOP_FLAGS(op); 33825500bd9eSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 33835500bd9eSRichard Henderson const TCGOutOp *outop = all_outop[opc]; 33843e80824eSRichard Henderson TCGConstraintSetIndex con_set; 33853e80824eSRichard Henderson 33863e80824eSRichard Henderson if (def->flags & TCG_OPF_NOT_PRESENT) { 3387501fb3daSRichard Henderson return empty_cts; 33883e80824eSRichard Henderson } 33893e80824eSRichard Henderson 33905500bd9eSRichard Henderson if (outop) { 33915500bd9eSRichard Henderson con_set = outop->static_constraint; 33925500bd9eSRichard Henderson if (con_set == C_Dynamic) { 33935500bd9eSRichard Henderson con_set = outop->dynamic_constraint(type, flags); 33945500bd9eSRichard Henderson } 33955500bd9eSRichard Henderson } else { 33965500bd9eSRichard Henderson con_set = tcg_target_op_def(opc, type, flags); 33975500bd9eSRichard Henderson } 33985500bd9eSRichard Henderson tcg_debug_assert(con_set >= 0); 33995500bd9eSRichard Henderson tcg_debug_assert(con_set < ARRAY_SIZE(constraint_sets)); 34003e80824eSRichard Henderson 34013e80824eSRichard Henderson /* The constraint arguments must match TCGOpcode arguments. */ 3402501fb3daSRichard Henderson tcg_debug_assert(constraint_sets[con_set].nb_oargs == def->nb_oargs); 3403501fb3daSRichard Henderson tcg_debug_assert(constraint_sets[con_set].nb_iargs == def->nb_iargs); 34043e80824eSRichard Henderson 3405501fb3daSRichard Henderson return all_cts[con_set]; 3406c896fe29Sbellard } 3407c896fe29Sbellard 3408f85b1fc4SRichard Henderson static void remove_label_use(TCGOp *op, int idx) 3409f85b1fc4SRichard Henderson { 3410f85b1fc4SRichard Henderson TCGLabel *label = arg_label(op->args[idx]); 3411f85b1fc4SRichard Henderson TCGLabelUse *use; 3412f85b1fc4SRichard Henderson 3413f85b1fc4SRichard Henderson QSIMPLEQ_FOREACH(use, &label->branches, next) { 3414f85b1fc4SRichard Henderson if (use->op == op) { 3415f85b1fc4SRichard Henderson QSIMPLEQ_REMOVE(&label->branches, use, TCGLabelUse, next); 3416f85b1fc4SRichard Henderson return; 3417f85b1fc4SRichard Henderson } 3418f85b1fc4SRichard Henderson } 3419f85b1fc4SRichard Henderson g_assert_not_reached(); 3420f85b1fc4SRichard Henderson } 3421f85b1fc4SRichard Henderson 34220c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op) 34230c627cdcSRichard Henderson { 3424d88a117eSRichard Henderson switch (op->opc) { 3425d88a117eSRichard Henderson case INDEX_op_br: 3426f85b1fc4SRichard Henderson remove_label_use(op, 0); 3427d88a117eSRichard Henderson break; 3428d88a117eSRichard Henderson case INDEX_op_brcond_i32: 3429d88a117eSRichard Henderson case INDEX_op_brcond_i64: 3430f85b1fc4SRichard Henderson remove_label_use(op, 3); 3431d88a117eSRichard Henderson break; 3432d88a117eSRichard Henderson case INDEX_op_brcond2_i32: 3433f85b1fc4SRichard Henderson remove_label_use(op, 5); 3434d88a117eSRichard Henderson break; 3435d88a117eSRichard Henderson default: 3436d88a117eSRichard Henderson break; 3437d88a117eSRichard Henderson } 3438d88a117eSRichard Henderson 343915fa08f8SRichard Henderson QTAILQ_REMOVE(&s->ops, op, link); 344015fa08f8SRichard Henderson QTAILQ_INSERT_TAIL(&s->free_ops, op, link); 3441abebf925SRichard Henderson s->nb_ops--; 34420c627cdcSRichard Henderson } 34430c627cdcSRichard Henderson 3444a80cdd31SRichard Henderson void tcg_remove_ops_after(TCGOp *op) 3445a80cdd31SRichard Henderson { 3446a80cdd31SRichard Henderson TCGContext *s = tcg_ctx; 3447a80cdd31SRichard Henderson 3448a80cdd31SRichard Henderson while (true) { 3449a80cdd31SRichard Henderson TCGOp *last = tcg_last_op(); 3450a80cdd31SRichard Henderson if (last == op) { 3451a80cdd31SRichard Henderson return; 3452a80cdd31SRichard Henderson } 3453a80cdd31SRichard Henderson tcg_op_remove(s, last); 3454a80cdd31SRichard Henderson } 3455a80cdd31SRichard Henderson } 3456a80cdd31SRichard Henderson 3457d4478943SPhilippe Mathieu-Daudé static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs) 345815fa08f8SRichard Henderson { 345915fa08f8SRichard Henderson TCGContext *s = tcg_ctx; 3460cb10bc63SRichard Henderson TCGOp *op = NULL; 346115fa08f8SRichard Henderson 3462cb10bc63SRichard Henderson if (unlikely(!QTAILQ_EMPTY(&s->free_ops))) { 3463cb10bc63SRichard Henderson QTAILQ_FOREACH(op, &s->free_ops, link) { 3464cb10bc63SRichard Henderson if (nargs <= op->nargs) { 346515fa08f8SRichard Henderson QTAILQ_REMOVE(&s->free_ops, op, link); 3466cb10bc63SRichard Henderson nargs = op->nargs; 3467cb10bc63SRichard Henderson goto found; 346815fa08f8SRichard Henderson } 3469cb10bc63SRichard Henderson } 3470cb10bc63SRichard Henderson } 3471cb10bc63SRichard Henderson 3472cb10bc63SRichard Henderson /* Most opcodes have 3 or 4 operands: reduce fragmentation. */ 3473cb10bc63SRichard Henderson nargs = MAX(4, nargs); 3474cb10bc63SRichard Henderson op = tcg_malloc(sizeof(TCGOp) + sizeof(TCGArg) * nargs); 3475cb10bc63SRichard Henderson 3476cb10bc63SRichard Henderson found: 347715fa08f8SRichard Henderson memset(op, 0, offsetof(TCGOp, link)); 347815fa08f8SRichard Henderson op->opc = opc; 3479cb10bc63SRichard Henderson op->nargs = nargs; 348015fa08f8SRichard Henderson 3481cb10bc63SRichard Henderson /* Check for bitfield overflow. */ 3482cb10bc63SRichard Henderson tcg_debug_assert(op->nargs == nargs); 3483cb10bc63SRichard Henderson 3484cb10bc63SRichard Henderson s->nb_ops++; 348515fa08f8SRichard Henderson return op; 348615fa08f8SRichard Henderson } 348715fa08f8SRichard Henderson 3488d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_emit_op(TCGOpcode opc, unsigned nargs) 348915fa08f8SRichard Henderson { 3490d4478943SPhilippe Mathieu-Daudé TCGOp *op = tcg_op_alloc(opc, nargs); 349107843f75SRichard Henderson 349207843f75SRichard Henderson if (tcg_ctx->emit_before_op) { 349307843f75SRichard Henderson QTAILQ_INSERT_BEFORE(tcg_ctx->emit_before_op, op, link); 349407843f75SRichard Henderson } else { 349515fa08f8SRichard Henderson QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link); 349607843f75SRichard Henderson } 349715fa08f8SRichard Henderson return op; 349815fa08f8SRichard Henderson } 349915fa08f8SRichard Henderson 3500d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op, 3501cf5c9f69SRichard Henderson TCGOpcode opc, TCGType type, unsigned nargs) 35025a18407fSRichard Henderson { 3503d4478943SPhilippe Mathieu-Daudé TCGOp *new_op = tcg_op_alloc(opc, nargs); 3504fb744eceSRichard Henderson 3505cf5c9f69SRichard Henderson TCGOP_TYPE(new_op) = type; 350615fa08f8SRichard Henderson QTAILQ_INSERT_BEFORE(old_op, new_op, link); 35075a18407fSRichard Henderson return new_op; 35085a18407fSRichard Henderson } 35095a18407fSRichard Henderson 3510d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, 3511cf5c9f69SRichard Henderson TCGOpcode opc, TCGType type, unsigned nargs) 35125a18407fSRichard Henderson { 3513d4478943SPhilippe Mathieu-Daudé TCGOp *new_op = tcg_op_alloc(opc, nargs); 3514fb744eceSRichard Henderson 3515cf5c9f69SRichard Henderson TCGOP_TYPE(new_op) = type; 351615fa08f8SRichard Henderson QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link); 35175a18407fSRichard Henderson return new_op; 35185a18407fSRichard Henderson } 35195a18407fSRichard Henderson 3520968f305eSRichard Henderson static void move_label_uses(TCGLabel *to, TCGLabel *from) 3521968f305eSRichard Henderson { 3522968f305eSRichard Henderson TCGLabelUse *u; 3523968f305eSRichard Henderson 3524968f305eSRichard Henderson QSIMPLEQ_FOREACH(u, &from->branches, next) { 3525968f305eSRichard Henderson TCGOp *op = u->op; 3526968f305eSRichard Henderson switch (op->opc) { 3527968f305eSRichard Henderson case INDEX_op_br: 3528968f305eSRichard Henderson op->args[0] = label_arg(to); 3529968f305eSRichard Henderson break; 3530968f305eSRichard Henderson case INDEX_op_brcond_i32: 3531968f305eSRichard Henderson case INDEX_op_brcond_i64: 3532968f305eSRichard Henderson op->args[3] = label_arg(to); 3533968f305eSRichard Henderson break; 3534968f305eSRichard Henderson case INDEX_op_brcond2_i32: 3535968f305eSRichard Henderson op->args[5] = label_arg(to); 3536968f305eSRichard Henderson break; 3537968f305eSRichard Henderson default: 3538968f305eSRichard Henderson g_assert_not_reached(); 3539968f305eSRichard Henderson } 3540968f305eSRichard Henderson } 3541968f305eSRichard Henderson 3542968f305eSRichard Henderson QSIMPLEQ_CONCAT(&to->branches, &from->branches); 3543968f305eSRichard Henderson } 3544968f305eSRichard Henderson 3545b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code. */ 35469bbee4c0SRichard Henderson static void __attribute__((noinline)) 35479bbee4c0SRichard Henderson reachable_code_pass(TCGContext *s) 3548b4fc67c7SRichard Henderson { 35494d89d0bbSRichard Henderson TCGOp *op, *op_next, *op_prev; 3550b4fc67c7SRichard Henderson bool dead = false; 3551b4fc67c7SRichard Henderson 3552b4fc67c7SRichard Henderson QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) { 3553b4fc67c7SRichard Henderson bool remove = dead; 3554b4fc67c7SRichard Henderson TCGLabel *label; 3555b4fc67c7SRichard Henderson 3556b4fc67c7SRichard Henderson switch (op->opc) { 3557b4fc67c7SRichard Henderson case INDEX_op_set_label: 3558b4fc67c7SRichard Henderson label = arg_label(op->args[0]); 35594d89d0bbSRichard Henderson 35604d89d0bbSRichard Henderson /* 3561968f305eSRichard Henderson * Note that the first op in the TB is always a load, 3562968f305eSRichard Henderson * so there is always something before a label. 3563968f305eSRichard Henderson */ 3564968f305eSRichard Henderson op_prev = QTAILQ_PREV(op, link); 3565968f305eSRichard Henderson 3566968f305eSRichard Henderson /* 3567968f305eSRichard Henderson * If we find two sequential labels, move all branches to 3568968f305eSRichard Henderson * reference the second label and remove the first label. 3569968f305eSRichard Henderson * Do this before branch to next optimization, so that the 3570968f305eSRichard Henderson * middle label is out of the way. 3571968f305eSRichard Henderson */ 3572968f305eSRichard Henderson if (op_prev->opc == INDEX_op_set_label) { 3573968f305eSRichard Henderson move_label_uses(label, arg_label(op_prev->args[0])); 3574968f305eSRichard Henderson tcg_op_remove(s, op_prev); 3575968f305eSRichard Henderson op_prev = QTAILQ_PREV(op, link); 3576968f305eSRichard Henderson } 3577968f305eSRichard Henderson 3578968f305eSRichard Henderson /* 35794d89d0bbSRichard Henderson * Optimization can fold conditional branches to unconditional. 35804d89d0bbSRichard Henderson * If we find a label which is preceded by an unconditional 35814d89d0bbSRichard Henderson * branch to next, remove the branch. We couldn't do this when 35824d89d0bbSRichard Henderson * processing the branch because any dead code between the branch 35834d89d0bbSRichard Henderson * and label had not yet been removed. 35844d89d0bbSRichard Henderson */ 35854d89d0bbSRichard Henderson if (op_prev->opc == INDEX_op_br && 35864d89d0bbSRichard Henderson label == arg_label(op_prev->args[0])) { 35874d89d0bbSRichard Henderson tcg_op_remove(s, op_prev); 35884d89d0bbSRichard Henderson /* Fall through means insns become live again. */ 35894d89d0bbSRichard Henderson dead = false; 35904d89d0bbSRichard Henderson } 35914d89d0bbSRichard Henderson 3592f85b1fc4SRichard Henderson if (QSIMPLEQ_EMPTY(&label->branches)) { 3593b4fc67c7SRichard Henderson /* 3594b4fc67c7SRichard Henderson * While there is an occasional backward branch, virtually 3595b4fc67c7SRichard Henderson * all branches generated by the translators are forward. 3596b4fc67c7SRichard Henderson * Which means that generally we will have already removed 3597b4fc67c7SRichard Henderson * all references to the label that will be, and there is 3598b4fc67c7SRichard Henderson * little to be gained by iterating. 3599b4fc67c7SRichard Henderson */ 3600b4fc67c7SRichard Henderson remove = true; 3601b4fc67c7SRichard Henderson } else { 3602b4fc67c7SRichard Henderson /* Once we see a label, insns become live again. */ 3603b4fc67c7SRichard Henderson dead = false; 3604b4fc67c7SRichard Henderson remove = false; 3605b4fc67c7SRichard Henderson } 3606b4fc67c7SRichard Henderson break; 3607b4fc67c7SRichard Henderson 3608b4fc67c7SRichard Henderson case INDEX_op_br: 3609b4fc67c7SRichard Henderson case INDEX_op_exit_tb: 3610b4fc67c7SRichard Henderson case INDEX_op_goto_ptr: 3611b4fc67c7SRichard Henderson /* Unconditional branches; everything following is dead. */ 3612b4fc67c7SRichard Henderson dead = true; 3613b4fc67c7SRichard Henderson break; 3614b4fc67c7SRichard Henderson 3615b4fc67c7SRichard Henderson case INDEX_op_call: 3616b4fc67c7SRichard Henderson /* Notice noreturn helper calls, raising exceptions. */ 361790163900SRichard Henderson if (tcg_call_flags(op) & TCG_CALL_NO_RETURN) { 3618b4fc67c7SRichard Henderson dead = true; 3619b4fc67c7SRichard Henderson } 3620b4fc67c7SRichard Henderson break; 3621b4fc67c7SRichard Henderson 3622b4fc67c7SRichard Henderson case INDEX_op_insn_start: 3623b4fc67c7SRichard Henderson /* Never remove -- we need to keep these for unwind. */ 3624b4fc67c7SRichard Henderson remove = false; 3625b4fc67c7SRichard Henderson break; 3626b4fc67c7SRichard Henderson 3627b4fc67c7SRichard Henderson default: 3628b4fc67c7SRichard Henderson break; 3629b4fc67c7SRichard Henderson } 3630b4fc67c7SRichard Henderson 3631b4fc67c7SRichard Henderson if (remove) { 3632b4fc67c7SRichard Henderson tcg_op_remove(s, op); 3633b4fc67c7SRichard Henderson } 3634b4fc67c7SRichard Henderson } 3635b4fc67c7SRichard Henderson } 3636b4fc67c7SRichard Henderson 3637c70fbf0aSRichard Henderson #define TS_DEAD 1 3638c70fbf0aSRichard Henderson #define TS_MEM 2 3639c70fbf0aSRichard Henderson 36405a18407fSRichard Henderson #define IS_DEAD_ARG(n) (arg_life & (DEAD_ARG << (n))) 36415a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n))) 36425a18407fSRichard Henderson 364325f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp. */ 364425f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts) 364525f49c5fSRichard Henderson { 364625f49c5fSRichard Henderson return ts->state_ptr; 364725f49c5fSRichard Henderson } 364825f49c5fSRichard Henderson 364925f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the 365025f49c5fSRichard Henderson * maximal regset for its type. 365125f49c5fSRichard Henderson */ 365225f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts) 365325f49c5fSRichard Henderson { 365425f49c5fSRichard Henderson *la_temp_pref(ts) 365525f49c5fSRichard Henderson = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]); 365625f49c5fSRichard Henderson } 365725f49c5fSRichard Henderson 36589c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals 36599c43b68dSAurelien Jarno should be in memory. */ 36602616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt) 3661c896fe29Sbellard { 3662b83eabeaSRichard Henderson int i; 3663b83eabeaSRichard Henderson 3664b83eabeaSRichard Henderson for (i = 0; i < ng; ++i) { 3665b83eabeaSRichard Henderson s->temps[i].state = TS_DEAD | TS_MEM; 366625f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 3667b83eabeaSRichard Henderson } 3668b83eabeaSRichard Henderson for (i = ng; i < nt; ++i) { 3669b83eabeaSRichard Henderson s->temps[i].state = TS_DEAD; 367025f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 3671b83eabeaSRichard Henderson } 3672c896fe29Sbellard } 3673c896fe29Sbellard 36749c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals 36759c43b68dSAurelien Jarno and local temps should be in memory. */ 36762616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt) 3677641d5fbeSbellard { 3678b83eabeaSRichard Henderson int i; 3679641d5fbeSbellard 3680ee17db83SRichard Henderson for (i = 0; i < nt; ++i) { 3681ee17db83SRichard Henderson TCGTemp *ts = &s->temps[i]; 3682ee17db83SRichard Henderson int state; 3683ee17db83SRichard Henderson 3684ee17db83SRichard Henderson switch (ts->kind) { 3685ee17db83SRichard Henderson case TEMP_FIXED: 3686ee17db83SRichard Henderson case TEMP_GLOBAL: 3687f57c6915SRichard Henderson case TEMP_TB: 3688ee17db83SRichard Henderson state = TS_DEAD | TS_MEM; 3689ee17db83SRichard Henderson break; 3690c7482438SRichard Henderson case TEMP_EBB: 3691c0522136SRichard Henderson case TEMP_CONST: 3692ee17db83SRichard Henderson state = TS_DEAD; 3693ee17db83SRichard Henderson break; 3694ee17db83SRichard Henderson default: 3695ee17db83SRichard Henderson g_assert_not_reached(); 3696c70fbf0aSRichard Henderson } 3697ee17db83SRichard Henderson ts->state = state; 3698ee17db83SRichard Henderson la_reset_pref(ts); 3699641d5fbeSbellard } 3700641d5fbeSbellard } 3701641d5fbeSbellard 3702f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory. */ 3703f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng) 3704f65a061cSRichard Henderson { 3705f65a061cSRichard Henderson int i; 3706f65a061cSRichard Henderson 3707f65a061cSRichard Henderson for (i = 0; i < ng; ++i) { 370825f49c5fSRichard Henderson int state = s->temps[i].state; 370925f49c5fSRichard Henderson s->temps[i].state = state | TS_MEM; 371025f49c5fSRichard Henderson if (state == TS_DEAD) { 371125f49c5fSRichard Henderson /* If the global was previously dead, reset prefs. */ 371225f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 371325f49c5fSRichard Henderson } 3714f65a061cSRichard Henderson } 3715f65a061cSRichard Henderson } 3716f65a061cSRichard Henderson 3717b4cb76e6SRichard Henderson /* 3718c7482438SRichard Henderson * liveness analysis: conditional branch: all temps are dead unless 3719c7482438SRichard Henderson * explicitly live-across-conditional-branch, globals and local temps 3720c7482438SRichard Henderson * should be synced. 3721b4cb76e6SRichard Henderson */ 3722b4cb76e6SRichard Henderson static void la_bb_sync(TCGContext *s, int ng, int nt) 3723b4cb76e6SRichard Henderson { 3724b4cb76e6SRichard Henderson la_global_sync(s, ng); 3725b4cb76e6SRichard Henderson 3726b4cb76e6SRichard Henderson for (int i = ng; i < nt; ++i) { 3727c0522136SRichard Henderson TCGTemp *ts = &s->temps[i]; 3728c0522136SRichard Henderson int state; 3729c0522136SRichard Henderson 3730c0522136SRichard Henderson switch (ts->kind) { 3731f57c6915SRichard Henderson case TEMP_TB: 3732c0522136SRichard Henderson state = ts->state; 3733c0522136SRichard Henderson ts->state = state | TS_MEM; 3734b4cb76e6SRichard Henderson if (state != TS_DEAD) { 3735b4cb76e6SRichard Henderson continue; 3736b4cb76e6SRichard Henderson } 3737c0522136SRichard Henderson break; 3738c7482438SRichard Henderson case TEMP_EBB: 3739c0522136SRichard Henderson case TEMP_CONST: 3740c0522136SRichard Henderson continue; 3741c0522136SRichard Henderson default: 3742c0522136SRichard Henderson g_assert_not_reached(); 3743b4cb76e6SRichard Henderson } 3744b4cb76e6SRichard Henderson la_reset_pref(&s->temps[i]); 3745b4cb76e6SRichard Henderson } 3746b4cb76e6SRichard Henderson } 3747b4cb76e6SRichard Henderson 3748f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill. */ 3749f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng) 3750f65a061cSRichard Henderson { 3751f65a061cSRichard Henderson int i; 3752f65a061cSRichard Henderson 3753f65a061cSRichard Henderson for (i = 0; i < ng; i++) { 3754f65a061cSRichard Henderson s->temps[i].state = TS_DEAD | TS_MEM; 375525f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 375625f49c5fSRichard Henderson } 375725f49c5fSRichard Henderson } 375825f49c5fSRichard Henderson 375925f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls. */ 376025f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt) 376125f49c5fSRichard Henderson { 376225f49c5fSRichard Henderson TCGRegSet mask = ~tcg_target_call_clobber_regs; 376325f49c5fSRichard Henderson int i; 376425f49c5fSRichard Henderson 376525f49c5fSRichard Henderson for (i = 0; i < nt; i++) { 376625f49c5fSRichard Henderson TCGTemp *ts = &s->temps[i]; 376725f49c5fSRichard Henderson if (!(ts->state & TS_DEAD)) { 376825f49c5fSRichard Henderson TCGRegSet *pset = la_temp_pref(ts); 376925f49c5fSRichard Henderson TCGRegSet set = *pset; 377025f49c5fSRichard Henderson 377125f49c5fSRichard Henderson set &= mask; 377225f49c5fSRichard Henderson /* If the combination is not possible, restart. */ 377325f49c5fSRichard Henderson if (set == 0) { 377425f49c5fSRichard Henderson set = tcg_target_available_regs[ts->type] & mask; 377525f49c5fSRichard Henderson } 377625f49c5fSRichard Henderson *pset = set; 377725f49c5fSRichard Henderson } 3778f65a061cSRichard Henderson } 3779f65a061cSRichard Henderson } 3780f65a061cSRichard Henderson 3781874b8574SRichard Henderson /* 3782874b8574SRichard Henderson * Liveness analysis: Verify the lifetime of TEMP_TB, and reduce 3783874b8574SRichard Henderson * to TEMP_EBB, if possible. 3784874b8574SRichard Henderson */ 3785874b8574SRichard Henderson static void __attribute__((noinline)) 3786874b8574SRichard Henderson liveness_pass_0(TCGContext *s) 3787874b8574SRichard Henderson { 3788874b8574SRichard Henderson void * const multiple_ebb = (void *)(uintptr_t)-1; 3789874b8574SRichard Henderson int nb_temps = s->nb_temps; 3790874b8574SRichard Henderson TCGOp *op, *ebb; 3791874b8574SRichard Henderson 3792874b8574SRichard Henderson for (int i = s->nb_globals; i < nb_temps; ++i) { 3793874b8574SRichard Henderson s->temps[i].state_ptr = NULL; 3794874b8574SRichard Henderson } 3795874b8574SRichard Henderson 3796874b8574SRichard Henderson /* 3797874b8574SRichard Henderson * Represent each EBB by the op at which it begins. In the case of 3798874b8574SRichard Henderson * the first EBB, this is the first op, otherwise it is a label. 3799874b8574SRichard Henderson * Collect the uses of each TEMP_TB: NULL for unused, EBB for use 3800874b8574SRichard Henderson * within a single EBB, else MULTIPLE_EBB. 3801874b8574SRichard Henderson */ 3802874b8574SRichard Henderson ebb = QTAILQ_FIRST(&s->ops); 3803874b8574SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 3804874b8574SRichard Henderson const TCGOpDef *def; 3805874b8574SRichard Henderson int nb_oargs, nb_iargs; 3806874b8574SRichard Henderson 3807874b8574SRichard Henderson switch (op->opc) { 3808874b8574SRichard Henderson case INDEX_op_set_label: 3809874b8574SRichard Henderson ebb = op; 3810874b8574SRichard Henderson continue; 3811874b8574SRichard Henderson case INDEX_op_discard: 3812874b8574SRichard Henderson continue; 3813874b8574SRichard Henderson case INDEX_op_call: 3814874b8574SRichard Henderson nb_oargs = TCGOP_CALLO(op); 3815874b8574SRichard Henderson nb_iargs = TCGOP_CALLI(op); 3816874b8574SRichard Henderson break; 3817874b8574SRichard Henderson default: 3818874b8574SRichard Henderson def = &tcg_op_defs[op->opc]; 3819874b8574SRichard Henderson nb_oargs = def->nb_oargs; 3820874b8574SRichard Henderson nb_iargs = def->nb_iargs; 3821874b8574SRichard Henderson break; 3822874b8574SRichard Henderson } 3823874b8574SRichard Henderson 3824874b8574SRichard Henderson for (int i = 0; i < nb_oargs + nb_iargs; ++i) { 3825874b8574SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]); 3826874b8574SRichard Henderson 3827874b8574SRichard Henderson if (ts->kind != TEMP_TB) { 3828874b8574SRichard Henderson continue; 3829874b8574SRichard Henderson } 3830874b8574SRichard Henderson if (ts->state_ptr == NULL) { 3831874b8574SRichard Henderson ts->state_ptr = ebb; 3832874b8574SRichard Henderson } else if (ts->state_ptr != ebb) { 3833874b8574SRichard Henderson ts->state_ptr = multiple_ebb; 3834874b8574SRichard Henderson } 3835874b8574SRichard Henderson } 3836874b8574SRichard Henderson } 3837874b8574SRichard Henderson 3838874b8574SRichard Henderson /* 3839874b8574SRichard Henderson * For TEMP_TB that turned out not to be used beyond one EBB, 3840874b8574SRichard Henderson * reduce the liveness to TEMP_EBB. 3841874b8574SRichard Henderson */ 3842874b8574SRichard Henderson for (int i = s->nb_globals; i < nb_temps; ++i) { 3843874b8574SRichard Henderson TCGTemp *ts = &s->temps[i]; 3844874b8574SRichard Henderson if (ts->kind == TEMP_TB && ts->state_ptr != multiple_ebb) { 3845874b8574SRichard Henderson ts->kind = TEMP_EBB; 3846874b8574SRichard Henderson } 3847874b8574SRichard Henderson } 3848874b8574SRichard Henderson } 3849874b8574SRichard Henderson 3850a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a 3851c896fe29Sbellard given input arguments is dead. Instructions updating dead 3852c896fe29Sbellard temporaries are removed. */ 38539bbee4c0SRichard Henderson static void __attribute__((noinline)) 38549bbee4c0SRichard Henderson liveness_pass_1(TCGContext *s) 3855c896fe29Sbellard { 3856c70fbf0aSRichard Henderson int nb_globals = s->nb_globals; 38572616c808SRichard Henderson int nb_temps = s->nb_temps; 385815fa08f8SRichard Henderson TCGOp *op, *op_prev; 385925f49c5fSRichard Henderson TCGRegSet *prefs; 386025f49c5fSRichard Henderson int i; 386125f49c5fSRichard Henderson 386225f49c5fSRichard Henderson prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps); 386325f49c5fSRichard Henderson for (i = 0; i < nb_temps; ++i) { 386425f49c5fSRichard Henderson s->temps[i].state_ptr = prefs + i; 386525f49c5fSRichard Henderson } 3866c896fe29Sbellard 3867ae36a246SRichard Henderson /* ??? Should be redundant with the exit_tb that ends the TB. */ 38682616c808SRichard Henderson la_func_end(s, nb_globals, nb_temps); 3869c896fe29Sbellard 3870eae3eb3eSPaolo Bonzini QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) { 387125f49c5fSRichard Henderson int nb_iargs, nb_oargs; 3872c45cb8bbSRichard Henderson TCGOpcode opc_new, opc_new2; 3873a1b3c48dSRichard Henderson TCGLifeData arg_life = 0; 387425f49c5fSRichard Henderson TCGTemp *ts; 3875c45cb8bbSRichard Henderson TCGOpcode opc = op->opc; 3876c45cb8bbSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 3877501fb3daSRichard Henderson const TCGArgConstraint *args_ct; 3878c45cb8bbSRichard Henderson 3879c45cb8bbSRichard Henderson switch (opc) { 3880c896fe29Sbellard case INDEX_op_call: 3881c6e113f5Sbellard { 388239004a71SRichard Henderson const TCGHelperInfo *info = tcg_call_info(op); 388339004a71SRichard Henderson int call_flags = tcg_call_flags(op); 3884c6e113f5Sbellard 3885cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 3886cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 3887c6e113f5Sbellard 3888c45cb8bbSRichard Henderson /* pure functions can be removed if their result is unused */ 388978505279SAurelien Jarno if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) { 3890c6e113f5Sbellard for (i = 0; i < nb_oargs; i++) { 389125f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 389225f49c5fSRichard Henderson if (ts->state != TS_DEAD) { 3893c6e113f5Sbellard goto do_not_remove_call; 3894c6e113f5Sbellard } 38959c43b68dSAurelien Jarno } 3896c45cb8bbSRichard Henderson goto do_remove; 3897152c35aaSRichard Henderson } 3898c6e113f5Sbellard do_not_remove_call: 3899c896fe29Sbellard 390025f49c5fSRichard Henderson /* Output args are dead. */ 3901c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 390225f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 390325f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 3904a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 39056b64b624SAurelien Jarno } 390625f49c5fSRichard Henderson if (ts->state & TS_MEM) { 3907a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i; 39089c43b68dSAurelien Jarno } 390925f49c5fSRichard Henderson ts->state = TS_DEAD; 391025f49c5fSRichard Henderson la_reset_pref(ts); 3911c896fe29Sbellard } 3912c896fe29Sbellard 391331fd884bSRichard Henderson /* Not used -- it will be tcg_target_call_oarg_reg(). */ 391431fd884bSRichard Henderson memset(op->output_pref, 0, sizeof(op->output_pref)); 391531fd884bSRichard Henderson 391678505279SAurelien Jarno if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS | 391778505279SAurelien Jarno TCG_CALL_NO_READ_GLOBALS))) { 3918f65a061cSRichard Henderson la_global_kill(s, nb_globals); 3919c70fbf0aSRichard Henderson } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) { 3920f65a061cSRichard Henderson la_global_sync(s, nb_globals); 3921b9c18f56Saurel32 } 3922c896fe29Sbellard 392325f49c5fSRichard Henderson /* Record arguments that die in this helper. */ 3924866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 392525f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 392639004a71SRichard Henderson if (ts->state & TS_DEAD) { 3927a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 3928c896fe29Sbellard } 3929c896fe29Sbellard } 393025f49c5fSRichard Henderson 393125f49c5fSRichard Henderson /* For all live registers, remove call-clobbered prefs. */ 393225f49c5fSRichard Henderson la_cross_call(s, nb_temps); 393325f49c5fSRichard Henderson 393439004a71SRichard Henderson /* 393539004a71SRichard Henderson * Input arguments are live for preceding opcodes. 393639004a71SRichard Henderson * 393739004a71SRichard Henderson * For those arguments that die, and will be allocated in 393839004a71SRichard Henderson * registers, clear the register set for that arg, to be 393939004a71SRichard Henderson * filled in below. For args that will be on the stack, 394039004a71SRichard Henderson * reset to any available reg. Process arguments in reverse 394139004a71SRichard Henderson * order so that if a temp is used more than once, the stack 394239004a71SRichard Henderson * reset to max happens before the register reset to 0. 394325f49c5fSRichard Henderson */ 394439004a71SRichard Henderson for (i = nb_iargs - 1; i >= 0; i--) { 394539004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i]; 394639004a71SRichard Henderson ts = arg_temp(op->args[nb_oargs + i]); 394739004a71SRichard Henderson 394839004a71SRichard Henderson if (ts->state & TS_DEAD) { 394939004a71SRichard Henderson switch (loc->kind) { 395039004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 395139004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 395239004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 3953338b61e9SRichard Henderson if (arg_slot_reg_p(loc->arg_slot)) { 395439004a71SRichard Henderson *la_temp_pref(ts) = 0; 395539004a71SRichard Henderson break; 395639004a71SRichard Henderson } 395739004a71SRichard Henderson /* fall through */ 395839004a71SRichard Henderson default: 395939004a71SRichard Henderson *la_temp_pref(ts) = 396039004a71SRichard Henderson tcg_target_available_regs[ts->type]; 396139004a71SRichard Henderson break; 396239004a71SRichard Henderson } 396325f49c5fSRichard Henderson ts->state &= ~TS_DEAD; 396425f49c5fSRichard Henderson } 396525f49c5fSRichard Henderson } 396625f49c5fSRichard Henderson 396739004a71SRichard Henderson /* 396839004a71SRichard Henderson * For each input argument, add its input register to prefs. 396939004a71SRichard Henderson * If a temp is used once, this produces a single set bit; 397039004a71SRichard Henderson * if a temp is used multiple times, this produces a set. 397139004a71SRichard Henderson */ 397239004a71SRichard Henderson for (i = 0; i < nb_iargs; i++) { 397339004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i]; 397439004a71SRichard Henderson ts = arg_temp(op->args[nb_oargs + i]); 397539004a71SRichard Henderson 397639004a71SRichard Henderson switch (loc->kind) { 397739004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 397839004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 397939004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 3980338b61e9SRichard Henderson if (arg_slot_reg_p(loc->arg_slot)) { 398125f49c5fSRichard Henderson tcg_regset_set_reg(*la_temp_pref(ts), 398239004a71SRichard Henderson tcg_target_call_iarg_regs[loc->arg_slot]); 398339004a71SRichard Henderson } 398439004a71SRichard Henderson break; 398539004a71SRichard Henderson default: 398639004a71SRichard Henderson break; 3987c70fbf0aSRichard Henderson } 3988c19f47bfSAurelien Jarno } 3989c6e113f5Sbellard } 3990c896fe29Sbellard break; 3991765b842aSRichard Henderson case INDEX_op_insn_start: 3992c896fe29Sbellard break; 39935ff9d6a4Sbellard case INDEX_op_discard: 39945ff9d6a4Sbellard /* mark the temporary as dead */ 399525f49c5fSRichard Henderson ts = arg_temp(op->args[0]); 399625f49c5fSRichard Henderson ts->state = TS_DEAD; 399725f49c5fSRichard Henderson la_reset_pref(ts); 39985ff9d6a4Sbellard break; 39991305c451SRichard Henderson 40001305c451SRichard Henderson case INDEX_op_add2_i32: 400179602f63SRichard Henderson case INDEX_op_add2_i64: 400279602f63SRichard Henderson opc_new = INDEX_op_add; 4003f1fae40cSRichard Henderson goto do_addsub2; 40041305c451SRichard Henderson case INDEX_op_sub2_i32: 4005f1fae40cSRichard Henderson case INDEX_op_sub2_i64: 400660f34f55SRichard Henderson opc_new = INDEX_op_sub; 4007f1fae40cSRichard Henderson do_addsub2: 40081305c451SRichard Henderson nb_iargs = 4; 40091305c451SRichard Henderson nb_oargs = 2; 40101305c451SRichard Henderson /* Test if the high part of the operation is dead, but not 40111305c451SRichard Henderson the low part. The result can be optimized to a simple 40121305c451SRichard Henderson add or sub. This happens often for x86_64 guest when the 40131305c451SRichard Henderson cpu mode is set to 32 bit. */ 4014b83eabeaSRichard Henderson if (arg_temp(op->args[1])->state == TS_DEAD) { 4015b83eabeaSRichard Henderson if (arg_temp(op->args[0])->state == TS_DEAD) { 40161305c451SRichard Henderson goto do_remove; 40171305c451SRichard Henderson } 4018c45cb8bbSRichard Henderson /* Replace the opcode and adjust the args in place, 4019c45cb8bbSRichard Henderson leaving 3 unused args at the end. */ 4020c45cb8bbSRichard Henderson op->opc = opc = opc_new; 4021efee3746SRichard Henderson op->args[1] = op->args[2]; 4022efee3746SRichard Henderson op->args[2] = op->args[4]; 40231305c451SRichard Henderson /* Fall through and mark the single-word operation live. */ 40241305c451SRichard Henderson nb_iargs = 2; 40251305c451SRichard Henderson nb_oargs = 1; 40261305c451SRichard Henderson } 40271305c451SRichard Henderson goto do_not_remove; 40281305c451SRichard Henderson 4029f1fae40cSRichard Henderson case INDEX_op_muls2_i32: 4030*c742824dSRichard Henderson case INDEX_op_muls2_i64: 4031d2c3ecadSRichard Henderson opc_new = INDEX_op_mul; 4032*c742824dSRichard Henderson opc_new2 = INDEX_op_mulsh; 4033f1fae40cSRichard Henderson goto do_mul2; 4034aa28c9efSRichard Henderson case INDEX_op_mulu2_i32: 4035f1fae40cSRichard Henderson case INDEX_op_mulu2_i64: 4036d2c3ecadSRichard Henderson opc_new = INDEX_op_mul; 4037aa28c9efSRichard Henderson opc_new2 = INDEX_op_muluh; 4038f1fae40cSRichard Henderson do_mul2: 40391414968aSRichard Henderson nb_iargs = 2; 40401414968aSRichard Henderson nb_oargs = 2; 4041b83eabeaSRichard Henderson if (arg_temp(op->args[1])->state == TS_DEAD) { 4042b83eabeaSRichard Henderson if (arg_temp(op->args[0])->state == TS_DEAD) { 404303271524SRichard Henderson /* Both parts of the operation are dead. */ 40441414968aSRichard Henderson goto do_remove; 40451414968aSRichard Henderson } 404603271524SRichard Henderson /* The high part of the operation is dead; generate the low. */ 4047c45cb8bbSRichard Henderson op->opc = opc = opc_new; 4048efee3746SRichard Henderson op->args[1] = op->args[2]; 4049efee3746SRichard Henderson op->args[2] = op->args[3]; 4050937246f2SRichard Henderson } else if (arg_temp(op->args[0])->state == TS_DEAD && 4051937246f2SRichard Henderson tcg_op_supported(opc_new2, TCGOP_TYPE(op), 0)) { 405203271524SRichard Henderson /* The low part of the operation is dead; generate the high. */ 4053c45cb8bbSRichard Henderson op->opc = opc = opc_new2; 4054efee3746SRichard Henderson op->args[0] = op->args[1]; 4055efee3746SRichard Henderson op->args[1] = op->args[2]; 4056efee3746SRichard Henderson op->args[2] = op->args[3]; 405703271524SRichard Henderson } else { 405803271524SRichard Henderson goto do_not_remove; 405903271524SRichard Henderson } 406003271524SRichard Henderson /* Mark the single-word operation live. */ 40611414968aSRichard Henderson nb_oargs = 1; 40621414968aSRichard Henderson goto do_not_remove; 40631414968aSRichard Henderson 4064c896fe29Sbellard default: 40651305c451SRichard Henderson /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */ 4066c896fe29Sbellard nb_iargs = def->nb_iargs; 4067c896fe29Sbellard nb_oargs = def->nb_oargs; 4068c896fe29Sbellard 4069c896fe29Sbellard /* Test if the operation can be removed because all 40705ff9d6a4Sbellard its outputs are dead. We assume that nb_oargs == 0 40715ff9d6a4Sbellard implies side effects */ 40725ff9d6a4Sbellard if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) { 4073c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 4074b83eabeaSRichard Henderson if (arg_temp(op->args[i])->state != TS_DEAD) { 4075c896fe29Sbellard goto do_not_remove; 4076c896fe29Sbellard } 40779c43b68dSAurelien Jarno } 4078152c35aaSRichard Henderson goto do_remove; 4079152c35aaSRichard Henderson } 4080152c35aaSRichard Henderson goto do_not_remove; 4081152c35aaSRichard Henderson 40821305c451SRichard Henderson do_remove: 40830c627cdcSRichard Henderson tcg_op_remove(s, op); 4084152c35aaSRichard Henderson break; 4085152c35aaSRichard Henderson 4086c896fe29Sbellard do_not_remove: 4087c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 408825f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 408925f49c5fSRichard Henderson 409025f49c5fSRichard Henderson /* Remember the preference of the uses that followed. */ 409131fd884bSRichard Henderson if (i < ARRAY_SIZE(op->output_pref)) { 409225f49c5fSRichard Henderson op->output_pref[i] = *la_temp_pref(ts); 409331fd884bSRichard Henderson } 409425f49c5fSRichard Henderson 409525f49c5fSRichard Henderson /* Output args are dead. */ 409625f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 4097a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 40986b64b624SAurelien Jarno } 409925f49c5fSRichard Henderson if (ts->state & TS_MEM) { 4100a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i; 41019c43b68dSAurelien Jarno } 410225f49c5fSRichard Henderson ts->state = TS_DEAD; 410325f49c5fSRichard Henderson la_reset_pref(ts); 4104c896fe29Sbellard } 4105c896fe29Sbellard 410625f49c5fSRichard Henderson /* If end of basic block, update. */ 4107ae36a246SRichard Henderson if (def->flags & TCG_OPF_BB_EXIT) { 4108ae36a246SRichard Henderson la_func_end(s, nb_globals, nb_temps); 4109b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_COND_BRANCH) { 4110b4cb76e6SRichard Henderson la_bb_sync(s, nb_globals, nb_temps); 4111ae36a246SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 41122616c808SRichard Henderson la_bb_end(s, nb_globals, nb_temps); 41133d5c5f87SAurelien Jarno } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { 4114f65a061cSRichard Henderson la_global_sync(s, nb_globals); 411525f49c5fSRichard Henderson if (def->flags & TCG_OPF_CALL_CLOBBER) { 411625f49c5fSRichard Henderson la_cross_call(s, nb_temps); 411725f49c5fSRichard Henderson } 4118c896fe29Sbellard } 4119c896fe29Sbellard 412025f49c5fSRichard Henderson /* Record arguments that die in this opcode. */ 4121866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 412225f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 412325f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 4124a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 4125c896fe29Sbellard } 4126c19f47bfSAurelien Jarno } 412725f49c5fSRichard Henderson 412825f49c5fSRichard Henderson /* Input arguments are live for preceding opcodes. */ 4129c19f47bfSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 413025f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 413125f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 413225f49c5fSRichard Henderson /* For operands that were dead, initially allow 413325f49c5fSRichard Henderson all regs for the type. */ 413425f49c5fSRichard Henderson *la_temp_pref(ts) = tcg_target_available_regs[ts->type]; 413525f49c5fSRichard Henderson ts->state &= ~TS_DEAD; 413625f49c5fSRichard Henderson } 413725f49c5fSRichard Henderson } 413825f49c5fSRichard Henderson 413925f49c5fSRichard Henderson /* Incorporate constraints for this operand. */ 414025f49c5fSRichard Henderson switch (opc) { 4141b5701261SRichard Henderson case INDEX_op_mov: 414225f49c5fSRichard Henderson /* Note that these are TCG_OPF_NOT_PRESENT and do not 414325f49c5fSRichard Henderson have proper constraints. That said, special case 414425f49c5fSRichard Henderson moves to propagate preferences backward. */ 414525f49c5fSRichard Henderson if (IS_DEAD_ARG(1)) { 414625f49c5fSRichard Henderson *la_temp_pref(arg_temp(op->args[0])) 414725f49c5fSRichard Henderson = *la_temp_pref(arg_temp(op->args[1])); 414825f49c5fSRichard Henderson } 414925f49c5fSRichard Henderson break; 415025f49c5fSRichard Henderson 415125f49c5fSRichard Henderson default: 4152501fb3daSRichard Henderson args_ct = opcode_args_ct(op); 415325f49c5fSRichard Henderson for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 4154501fb3daSRichard Henderson const TCGArgConstraint *ct = &args_ct[i]; 415525f49c5fSRichard Henderson TCGRegSet set, *pset; 415625f49c5fSRichard Henderson 415725f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 415825f49c5fSRichard Henderson pset = la_temp_pref(ts); 415925f49c5fSRichard Henderson set = *pset; 416025f49c5fSRichard Henderson 41619be0d080SRichard Henderson set &= ct->regs; 4162bc2b17e6SRichard Henderson if (ct->ialias) { 416331fd884bSRichard Henderson set &= output_pref(op, ct->alias_index); 416425f49c5fSRichard Henderson } 416525f49c5fSRichard Henderson /* If the combination is not possible, restart. */ 416625f49c5fSRichard Henderson if (set == 0) { 41679be0d080SRichard Henderson set = ct->regs; 416825f49c5fSRichard Henderson } 416925f49c5fSRichard Henderson *pset = set; 417025f49c5fSRichard Henderson } 417125f49c5fSRichard Henderson break; 4172c896fe29Sbellard } 4173c896fe29Sbellard break; 4174c896fe29Sbellard } 4175bee158cbSRichard Henderson op->life = arg_life; 4176c896fe29Sbellard } 41771ff0a2c5SEvgeny Voevodin } 4178c896fe29Sbellard 41795a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries. */ 41809bbee4c0SRichard Henderson static bool __attribute__((noinline)) 41819bbee4c0SRichard Henderson liveness_pass_2(TCGContext *s) 41825a18407fSRichard Henderson { 41835a18407fSRichard Henderson int nb_globals = s->nb_globals; 418415fa08f8SRichard Henderson int nb_temps, i; 41855a18407fSRichard Henderson bool changes = false; 418615fa08f8SRichard Henderson TCGOp *op, *op_next; 41875a18407fSRichard Henderson 41885a18407fSRichard Henderson /* Create a temporary for each indirect global. */ 41895a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 41905a18407fSRichard Henderson TCGTemp *its = &s->temps[i]; 41915a18407fSRichard Henderson if (its->indirect_reg) { 41925a18407fSRichard Henderson TCGTemp *dts = tcg_temp_alloc(s); 41935a18407fSRichard Henderson dts->type = its->type; 41945a18407fSRichard Henderson dts->base_type = its->base_type; 4195e1e64652SRichard Henderson dts->temp_subindex = its->temp_subindex; 4196c7482438SRichard Henderson dts->kind = TEMP_EBB; 4197b83eabeaSRichard Henderson its->state_ptr = dts; 4198b83eabeaSRichard Henderson } else { 4199b83eabeaSRichard Henderson its->state_ptr = NULL; 42005a18407fSRichard Henderson } 4201b83eabeaSRichard Henderson /* All globals begin dead. */ 4202b83eabeaSRichard Henderson its->state = TS_DEAD; 42035a18407fSRichard Henderson } 4204b83eabeaSRichard Henderson for (nb_temps = s->nb_temps; i < nb_temps; ++i) { 4205b83eabeaSRichard Henderson TCGTemp *its = &s->temps[i]; 4206b83eabeaSRichard Henderson its->state_ptr = NULL; 4207b83eabeaSRichard Henderson its->state = TS_DEAD; 4208b83eabeaSRichard Henderson } 42095a18407fSRichard Henderson 421015fa08f8SRichard Henderson QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) { 42115a18407fSRichard Henderson TCGOpcode opc = op->opc; 42125a18407fSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 42135a18407fSRichard Henderson TCGLifeData arg_life = op->life; 42145a18407fSRichard Henderson int nb_iargs, nb_oargs, call_flags; 4215b83eabeaSRichard Henderson TCGTemp *arg_ts, *dir_ts; 42165a18407fSRichard Henderson 42175a18407fSRichard Henderson if (opc == INDEX_op_call) { 4218cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 4219cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 422090163900SRichard Henderson call_flags = tcg_call_flags(op); 42215a18407fSRichard Henderson } else { 42225a18407fSRichard Henderson nb_iargs = def->nb_iargs; 42235a18407fSRichard Henderson nb_oargs = def->nb_oargs; 42245a18407fSRichard Henderson 42255a18407fSRichard Henderson /* Set flags similar to how calls require. */ 4226b4cb76e6SRichard Henderson if (def->flags & TCG_OPF_COND_BRANCH) { 4227b4cb76e6SRichard Henderson /* Like reading globals: sync_globals */ 4228b4cb76e6SRichard Henderson call_flags = TCG_CALL_NO_WRITE_GLOBALS; 4229b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 42305a18407fSRichard Henderson /* Like writing globals: save_globals */ 42315a18407fSRichard Henderson call_flags = 0; 42325a18407fSRichard Henderson } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { 42335a18407fSRichard Henderson /* Like reading globals: sync_globals */ 42345a18407fSRichard Henderson call_flags = TCG_CALL_NO_WRITE_GLOBALS; 42355a18407fSRichard Henderson } else { 42365a18407fSRichard Henderson /* No effect on globals. */ 42375a18407fSRichard Henderson call_flags = (TCG_CALL_NO_READ_GLOBALS | 42385a18407fSRichard Henderson TCG_CALL_NO_WRITE_GLOBALS); 42395a18407fSRichard Henderson } 42405a18407fSRichard Henderson } 42415a18407fSRichard Henderson 42425a18407fSRichard Henderson /* Make sure that input arguments are available. */ 42435a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 4244b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 4245b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 4246b83eabeaSRichard Henderson if (dir_ts && arg_ts->state == TS_DEAD) { 4247b83eabeaSRichard Henderson TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32 42485a18407fSRichard Henderson ? INDEX_op_ld_i32 42495a18407fSRichard Henderson : INDEX_op_ld_i64); 4250cf5c9f69SRichard Henderson TCGOp *lop = tcg_op_insert_before(s, op, lopc, 4251cf5c9f69SRichard Henderson arg_ts->type, 3); 42525a18407fSRichard Henderson 4253b83eabeaSRichard Henderson lop->args[0] = temp_arg(dir_ts); 4254b83eabeaSRichard Henderson lop->args[1] = temp_arg(arg_ts->mem_base); 4255b83eabeaSRichard Henderson lop->args[2] = arg_ts->mem_offset; 42565a18407fSRichard Henderson 42575a18407fSRichard Henderson /* Loaded, but synced with memory. */ 4258b83eabeaSRichard Henderson arg_ts->state = TS_MEM; 42595a18407fSRichard Henderson } 42605a18407fSRichard Henderson } 42615a18407fSRichard Henderson 42625a18407fSRichard Henderson /* Perform input replacement, and mark inputs that became dead. 42635a18407fSRichard Henderson No action is required except keeping temp_state up to date 42645a18407fSRichard Henderson so that we reload when needed. */ 42655a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 4266b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 4267b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 4268b83eabeaSRichard Henderson if (dir_ts) { 4269b83eabeaSRichard Henderson op->args[i] = temp_arg(dir_ts); 42705a18407fSRichard Henderson changes = true; 42715a18407fSRichard Henderson if (IS_DEAD_ARG(i)) { 4272b83eabeaSRichard Henderson arg_ts->state = TS_DEAD; 42735a18407fSRichard Henderson } 42745a18407fSRichard Henderson } 42755a18407fSRichard Henderson } 42765a18407fSRichard Henderson 42775a18407fSRichard Henderson /* Liveness analysis should ensure that the following are 42785a18407fSRichard Henderson all correct, for call sites and basic block end points. */ 42795a18407fSRichard Henderson if (call_flags & TCG_CALL_NO_READ_GLOBALS) { 42805a18407fSRichard Henderson /* Nothing to do */ 42815a18407fSRichard Henderson } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) { 42825a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 42835a18407fSRichard Henderson /* Liveness should see that globals are synced back, 42845a18407fSRichard Henderson that is, either TS_DEAD or TS_MEM. */ 4285b83eabeaSRichard Henderson arg_ts = &s->temps[i]; 4286b83eabeaSRichard Henderson tcg_debug_assert(arg_ts->state_ptr == 0 4287b83eabeaSRichard Henderson || arg_ts->state != 0); 42885a18407fSRichard Henderson } 42895a18407fSRichard Henderson } else { 42905a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 42915a18407fSRichard Henderson /* Liveness should see that globals are saved back, 42925a18407fSRichard Henderson that is, TS_DEAD, waiting to be reloaded. */ 4293b83eabeaSRichard Henderson arg_ts = &s->temps[i]; 4294b83eabeaSRichard Henderson tcg_debug_assert(arg_ts->state_ptr == 0 4295b83eabeaSRichard Henderson || arg_ts->state == TS_DEAD); 42965a18407fSRichard Henderson } 42975a18407fSRichard Henderson } 42985a18407fSRichard Henderson 42995a18407fSRichard Henderson /* Outputs become available. */ 4300b5701261SRichard Henderson if (opc == INDEX_op_mov) { 430161f15c48SRichard Henderson arg_ts = arg_temp(op->args[0]); 430261f15c48SRichard Henderson dir_ts = arg_ts->state_ptr; 430361f15c48SRichard Henderson if (dir_ts) { 430461f15c48SRichard Henderson op->args[0] = temp_arg(dir_ts); 430561f15c48SRichard Henderson changes = true; 430661f15c48SRichard Henderson 430761f15c48SRichard Henderson /* The output is now live and modified. */ 430861f15c48SRichard Henderson arg_ts->state = 0; 430961f15c48SRichard Henderson 431061f15c48SRichard Henderson if (NEED_SYNC_ARG(0)) { 431161f15c48SRichard Henderson TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 431261f15c48SRichard Henderson ? INDEX_op_st_i32 431361f15c48SRichard Henderson : INDEX_op_st_i64); 4314cf5c9f69SRichard Henderson TCGOp *sop = tcg_op_insert_after(s, op, sopc, 4315cf5c9f69SRichard Henderson arg_ts->type, 3); 431661f15c48SRichard Henderson TCGTemp *out_ts = dir_ts; 431761f15c48SRichard Henderson 431861f15c48SRichard Henderson if (IS_DEAD_ARG(0)) { 431961f15c48SRichard Henderson out_ts = arg_temp(op->args[1]); 432061f15c48SRichard Henderson arg_ts->state = TS_DEAD; 432161f15c48SRichard Henderson tcg_op_remove(s, op); 432261f15c48SRichard Henderson } else { 432361f15c48SRichard Henderson arg_ts->state = TS_MEM; 432461f15c48SRichard Henderson } 432561f15c48SRichard Henderson 432661f15c48SRichard Henderson sop->args[0] = temp_arg(out_ts); 432761f15c48SRichard Henderson sop->args[1] = temp_arg(arg_ts->mem_base); 432861f15c48SRichard Henderson sop->args[2] = arg_ts->mem_offset; 432961f15c48SRichard Henderson } else { 433061f15c48SRichard Henderson tcg_debug_assert(!IS_DEAD_ARG(0)); 433161f15c48SRichard Henderson } 433261f15c48SRichard Henderson } 433361f15c48SRichard Henderson } else { 43345a18407fSRichard Henderson for (i = 0; i < nb_oargs; i++) { 4335b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 4336b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 4337b83eabeaSRichard Henderson if (!dir_ts) { 43385a18407fSRichard Henderson continue; 43395a18407fSRichard Henderson } 4340b83eabeaSRichard Henderson op->args[i] = temp_arg(dir_ts); 43415a18407fSRichard Henderson changes = true; 43425a18407fSRichard Henderson 43435a18407fSRichard Henderson /* The output is now live and modified. */ 4344b83eabeaSRichard Henderson arg_ts->state = 0; 43455a18407fSRichard Henderson 43465a18407fSRichard Henderson /* Sync outputs upon their last write. */ 43475a18407fSRichard Henderson if (NEED_SYNC_ARG(i)) { 4348b83eabeaSRichard Henderson TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 43495a18407fSRichard Henderson ? INDEX_op_st_i32 43505a18407fSRichard Henderson : INDEX_op_st_i64); 4351cf5c9f69SRichard Henderson TCGOp *sop = tcg_op_insert_after(s, op, sopc, 4352cf5c9f69SRichard Henderson arg_ts->type, 3); 43535a18407fSRichard Henderson 4354b83eabeaSRichard Henderson sop->args[0] = temp_arg(dir_ts); 4355b83eabeaSRichard Henderson sop->args[1] = temp_arg(arg_ts->mem_base); 4356b83eabeaSRichard Henderson sop->args[2] = arg_ts->mem_offset; 43575a18407fSRichard Henderson 4358b83eabeaSRichard Henderson arg_ts->state = TS_MEM; 43595a18407fSRichard Henderson } 43605a18407fSRichard Henderson /* Drop outputs that are dead. */ 43615a18407fSRichard Henderson if (IS_DEAD_ARG(i)) { 4362b83eabeaSRichard Henderson arg_ts->state = TS_DEAD; 43635a18407fSRichard Henderson } 43645a18407fSRichard Henderson } 43655a18407fSRichard Henderson } 436661f15c48SRichard Henderson } 43675a18407fSRichard Henderson 43685a18407fSRichard Henderson return changes; 43695a18407fSRichard Henderson } 43705a18407fSRichard Henderson 43712272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts) 4372c896fe29Sbellard { 437331c96417SRichard Henderson intptr_t off; 4374273eb50cSRichard Henderson int size, align; 4375c1c09194SRichard Henderson 4376273eb50cSRichard Henderson /* When allocating an object, look at the full type. */ 4377273eb50cSRichard Henderson size = tcg_type_size(ts->base_type); 4378273eb50cSRichard Henderson switch (ts->base_type) { 4379c1c09194SRichard Henderson case TCG_TYPE_I32: 438031c96417SRichard Henderson align = 4; 4381c1c09194SRichard Henderson break; 4382c1c09194SRichard Henderson case TCG_TYPE_I64: 4383c1c09194SRichard Henderson case TCG_TYPE_V64: 438431c96417SRichard Henderson align = 8; 4385c1c09194SRichard Henderson break; 438643eef72fSRichard Henderson case TCG_TYPE_I128: 4387c1c09194SRichard Henderson case TCG_TYPE_V128: 4388c1c09194SRichard Henderson case TCG_TYPE_V256: 438943eef72fSRichard Henderson /* 439043eef72fSRichard Henderson * Note that we do not require aligned storage for V256, 439143eef72fSRichard Henderson * and that we provide alignment for I128 to match V128, 439243eef72fSRichard Henderson * even if that's above what the host ABI requires. 439343eef72fSRichard Henderson */ 439431c96417SRichard Henderson align = 16; 4395c1c09194SRichard Henderson break; 4396c1c09194SRichard Henderson default: 4397c1c09194SRichard Henderson g_assert_not_reached(); 4398b591dc59SBlue Swirl } 4399c1c09194SRichard Henderson 4400b9537d59SRichard Henderson /* 4401b9537d59SRichard Henderson * Assume the stack is sufficiently aligned. 4402b9537d59SRichard Henderson * This affects e.g. ARM NEON, where we have 8 byte stack alignment 4403b9537d59SRichard Henderson * and do not require 16 byte vector alignment. This seems slightly 4404b9537d59SRichard Henderson * easier than fully parameterizing the above switch statement. 4405b9537d59SRichard Henderson */ 4406b9537d59SRichard Henderson align = MIN(TCG_TARGET_STACK_ALIGN, align); 4407c1c09194SRichard Henderson off = ROUND_UP(s->current_frame_offset, align); 4408732d5897SRichard Henderson 4409732d5897SRichard Henderson /* If we've exhausted the stack frame, restart with a smaller TB. */ 4410732d5897SRichard Henderson if (off + size > s->frame_end) { 4411732d5897SRichard Henderson tcg_raise_tb_overflow(s); 4412732d5897SRichard Henderson } 4413c1c09194SRichard Henderson s->current_frame_offset = off + size; 44149defd1bdSRichard Henderson #if defined(__sparc__) 4415273eb50cSRichard Henderson off += TCG_TARGET_STACK_BIAS; 44169defd1bdSRichard Henderson #endif 4417273eb50cSRichard Henderson 4418273eb50cSRichard Henderson /* If the object was subdivided, assign memory to all the parts. */ 4419273eb50cSRichard Henderson if (ts->base_type != ts->type) { 4420273eb50cSRichard Henderson int part_size = tcg_type_size(ts->type); 4421273eb50cSRichard Henderson int part_count = size / part_size; 4422273eb50cSRichard Henderson 4423273eb50cSRichard Henderson /* 4424273eb50cSRichard Henderson * Each part is allocated sequentially in tcg_temp_new_internal. 4425273eb50cSRichard Henderson * Jump back to the first part by subtracting the current index. 4426273eb50cSRichard Henderson */ 4427273eb50cSRichard Henderson ts -= ts->temp_subindex; 4428273eb50cSRichard Henderson for (int i = 0; i < part_count; ++i) { 4429273eb50cSRichard Henderson ts[i].mem_offset = off + i * part_size; 4430273eb50cSRichard Henderson ts[i].mem_base = s->frame_temp; 4431273eb50cSRichard Henderson ts[i].mem_allocated = 1; 4432273eb50cSRichard Henderson } 4433273eb50cSRichard Henderson } else { 4434273eb50cSRichard Henderson ts->mem_offset = off; 4435b3a62939SRichard Henderson ts->mem_base = s->frame_temp; 4436c896fe29Sbellard ts->mem_allocated = 1; 4437c896fe29Sbellard } 4438273eb50cSRichard Henderson } 4439c896fe29Sbellard 4440098859f1SRichard Henderson /* Assign @reg to @ts, and update reg_to_temp[]. */ 4441098859f1SRichard Henderson static void set_temp_val_reg(TCGContext *s, TCGTemp *ts, TCGReg reg) 4442098859f1SRichard Henderson { 4443098859f1SRichard Henderson if (ts->val_type == TEMP_VAL_REG) { 4444098859f1SRichard Henderson TCGReg old = ts->reg; 4445098859f1SRichard Henderson tcg_debug_assert(s->reg_to_temp[old] == ts); 4446098859f1SRichard Henderson if (old == reg) { 4447098859f1SRichard Henderson return; 4448098859f1SRichard Henderson } 4449098859f1SRichard Henderson s->reg_to_temp[old] = NULL; 4450098859f1SRichard Henderson } 4451098859f1SRichard Henderson tcg_debug_assert(s->reg_to_temp[reg] == NULL); 4452098859f1SRichard Henderson s->reg_to_temp[reg] = ts; 4453098859f1SRichard Henderson ts->val_type = TEMP_VAL_REG; 4454098859f1SRichard Henderson ts->reg = reg; 4455098859f1SRichard Henderson } 4456098859f1SRichard Henderson 4457098859f1SRichard Henderson /* Assign a non-register value type to @ts, and update reg_to_temp[]. */ 4458098859f1SRichard Henderson static void set_temp_val_nonreg(TCGContext *s, TCGTemp *ts, TCGTempVal type) 4459098859f1SRichard Henderson { 4460098859f1SRichard Henderson tcg_debug_assert(type != TEMP_VAL_REG); 4461098859f1SRichard Henderson if (ts->val_type == TEMP_VAL_REG) { 4462098859f1SRichard Henderson TCGReg reg = ts->reg; 4463098859f1SRichard Henderson tcg_debug_assert(s->reg_to_temp[reg] == ts); 4464098859f1SRichard Henderson s->reg_to_temp[reg] = NULL; 4465098859f1SRichard Henderson } 4466098859f1SRichard Henderson ts->val_type = type; 4467098859f1SRichard Henderson } 4468098859f1SRichard Henderson 4469b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet); 4470b3915dbbSRichard Henderson 447159d7c14eSRichard Henderson /* Mark a temporary as free or dead. If 'free_or_dead' is negative, 447259d7c14eSRichard Henderson mark it free; otherwise mark it dead. */ 447359d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead) 4474c896fe29Sbellard { 4475c0522136SRichard Henderson TCGTempVal new_type; 4476c0522136SRichard Henderson 4477c0522136SRichard Henderson switch (ts->kind) { 4478c0522136SRichard Henderson case TEMP_FIXED: 447959d7c14eSRichard Henderson return; 4480c0522136SRichard Henderson case TEMP_GLOBAL: 4481f57c6915SRichard Henderson case TEMP_TB: 4482c0522136SRichard Henderson new_type = TEMP_VAL_MEM; 4483c0522136SRichard Henderson break; 4484c7482438SRichard Henderson case TEMP_EBB: 4485c0522136SRichard Henderson new_type = free_or_dead < 0 ? TEMP_VAL_MEM : TEMP_VAL_DEAD; 4486c0522136SRichard Henderson break; 4487c0522136SRichard Henderson case TEMP_CONST: 4488c0522136SRichard Henderson new_type = TEMP_VAL_CONST; 4489c0522136SRichard Henderson break; 4490c0522136SRichard Henderson default: 4491c0522136SRichard Henderson g_assert_not_reached(); 449259d7c14eSRichard Henderson } 4493098859f1SRichard Henderson set_temp_val_nonreg(s, ts, new_type); 449459d7c14eSRichard Henderson } 4495c896fe29Sbellard 449659d7c14eSRichard Henderson /* Mark a temporary as dead. */ 449759d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts) 449859d7c14eSRichard Henderson { 449959d7c14eSRichard Henderson temp_free_or_dead(s, ts, 1); 450059d7c14eSRichard Henderson } 450159d7c14eSRichard Henderson 450259d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary 450359d7c14eSRichard Henderson registers needs to be allocated to store a constant. If 'free_or_dead' 450459d7c14eSRichard Henderson is non-zero, subsequently release the temporary; if it is positive, the 450559d7c14eSRichard Henderson temp is dead; if it is negative, the temp is free. */ 450698b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs, 450798b4e186SRichard Henderson TCGRegSet preferred_regs, int free_or_dead) 450859d7c14eSRichard Henderson { 4509c0522136SRichard Henderson if (!temp_readonly(ts) && !ts->mem_coherent) { 45107f6ceedfSAurelien Jarno if (!ts->mem_allocated) { 45112272e4a7SRichard Henderson temp_allocate_frame(s, ts); 451259d7c14eSRichard Henderson } 451359d7c14eSRichard Henderson switch (ts->val_type) { 451459d7c14eSRichard Henderson case TEMP_VAL_CONST: 451559d7c14eSRichard Henderson /* If we're going to free the temp immediately, then we won't 451659d7c14eSRichard Henderson require it later in a register, so attempt to store the 451759d7c14eSRichard Henderson constant to memory directly. */ 451859d7c14eSRichard Henderson if (free_or_dead 451959d7c14eSRichard Henderson && tcg_out_sti(s, ts->type, ts->val, 452059d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset)) { 452159d7c14eSRichard Henderson break; 452259d7c14eSRichard Henderson } 452359d7c14eSRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 452498b4e186SRichard Henderson allocated_regs, preferred_regs); 452559d7c14eSRichard Henderson /* fallthrough */ 452659d7c14eSRichard Henderson 452759d7c14eSRichard Henderson case TEMP_VAL_REG: 452859d7c14eSRichard Henderson tcg_out_st(s, ts->type, ts->reg, 452959d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset); 453059d7c14eSRichard Henderson break; 453159d7c14eSRichard Henderson 453259d7c14eSRichard Henderson case TEMP_VAL_MEM: 453359d7c14eSRichard Henderson break; 453459d7c14eSRichard Henderson 453559d7c14eSRichard Henderson case TEMP_VAL_DEAD: 453659d7c14eSRichard Henderson default: 4537732e89f4SRichard Henderson g_assert_not_reached(); 4538c896fe29Sbellard } 45397f6ceedfSAurelien Jarno ts->mem_coherent = 1; 45407f6ceedfSAurelien Jarno } 454159d7c14eSRichard Henderson if (free_or_dead) { 454259d7c14eSRichard Henderson temp_free_or_dead(s, ts, free_or_dead); 454359d7c14eSRichard Henderson } 454459d7c14eSRichard Henderson } 45457f6ceedfSAurelien Jarno 45467f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */ 4547b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs) 45487f6ceedfSAurelien Jarno { 4549f8b2f202SRichard Henderson TCGTemp *ts = s->reg_to_temp[reg]; 4550f8b2f202SRichard Henderson if (ts != NULL) { 455198b4e186SRichard Henderson temp_sync(s, ts, allocated_regs, 0, -1); 4552c896fe29Sbellard } 4553c896fe29Sbellard } 4554c896fe29Sbellard 4555b016486eSRichard Henderson /** 4556b016486eSRichard Henderson * tcg_reg_alloc: 4557b016486eSRichard Henderson * @required_regs: Set of registers in which we must allocate. 4558b016486eSRichard Henderson * @allocated_regs: Set of registers which must be avoided. 4559b016486eSRichard Henderson * @preferred_regs: Set of registers we should prefer. 4560b016486eSRichard Henderson * @rev: True if we search the registers in "indirect" order. 4561b016486eSRichard Henderson * 4562b016486eSRichard Henderson * The allocated register must be in @required_regs & ~@allocated_regs, 4563b016486eSRichard Henderson * but if we can put it in @preferred_regs we may save a move later. 4564b016486eSRichard Henderson */ 4565b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs, 4566b016486eSRichard Henderson TCGRegSet allocated_regs, 4567b016486eSRichard Henderson TCGRegSet preferred_regs, bool rev) 4568c896fe29Sbellard { 4569b016486eSRichard Henderson int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order); 4570b016486eSRichard Henderson TCGRegSet reg_ct[2]; 457191478cefSRichard Henderson const int *order; 4572c896fe29Sbellard 4573b016486eSRichard Henderson reg_ct[1] = required_regs & ~allocated_regs; 4574b016486eSRichard Henderson tcg_debug_assert(reg_ct[1] != 0); 4575b016486eSRichard Henderson reg_ct[0] = reg_ct[1] & preferred_regs; 4576b016486eSRichard Henderson 4577b016486eSRichard Henderson /* Skip the preferred_regs option if it cannot be satisfied, 4578b016486eSRichard Henderson or if the preference made no difference. */ 4579b016486eSRichard Henderson f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1]; 4580b016486eSRichard Henderson 458191478cefSRichard Henderson order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order; 4582c896fe29Sbellard 4583b016486eSRichard Henderson /* Try free registers, preferences first. */ 4584b016486eSRichard Henderson for (j = f; j < 2; j++) { 4585b016486eSRichard Henderson TCGRegSet set = reg_ct[j]; 4586b016486eSRichard Henderson 4587b016486eSRichard Henderson if (tcg_regset_single(set)) { 4588b016486eSRichard Henderson /* One register in the set. */ 4589b016486eSRichard Henderson TCGReg reg = tcg_regset_first(set); 4590b016486eSRichard Henderson if (s->reg_to_temp[reg] == NULL) { 4591c896fe29Sbellard return reg; 4592c896fe29Sbellard } 4593b016486eSRichard Henderson } else { 459491478cefSRichard Henderson for (i = 0; i < n; i++) { 4595b016486eSRichard Henderson TCGReg reg = order[i]; 4596b016486eSRichard Henderson if (s->reg_to_temp[reg] == NULL && 4597b016486eSRichard Henderson tcg_regset_test_reg(set, reg)) { 4598b016486eSRichard Henderson return reg; 4599b016486eSRichard Henderson } 4600b016486eSRichard Henderson } 4601b016486eSRichard Henderson } 4602b016486eSRichard Henderson } 4603b016486eSRichard Henderson 4604b016486eSRichard Henderson /* We must spill something. */ 4605b016486eSRichard Henderson for (j = f; j < 2; j++) { 4606b016486eSRichard Henderson TCGRegSet set = reg_ct[j]; 4607b016486eSRichard Henderson 4608b016486eSRichard Henderson if (tcg_regset_single(set)) { 4609b016486eSRichard Henderson /* One register in the set. */ 4610b016486eSRichard Henderson TCGReg reg = tcg_regset_first(set); 4611b3915dbbSRichard Henderson tcg_reg_free(s, reg, allocated_regs); 4612c896fe29Sbellard return reg; 4613b016486eSRichard Henderson } else { 4614b016486eSRichard Henderson for (i = 0; i < n; i++) { 4615b016486eSRichard Henderson TCGReg reg = order[i]; 4616b016486eSRichard Henderson if (tcg_regset_test_reg(set, reg)) { 4617b016486eSRichard Henderson tcg_reg_free(s, reg, allocated_regs); 4618b016486eSRichard Henderson return reg; 4619b016486eSRichard Henderson } 4620b016486eSRichard Henderson } 4621c896fe29Sbellard } 4622c896fe29Sbellard } 4623c896fe29Sbellard 4624732e89f4SRichard Henderson g_assert_not_reached(); 4625c896fe29Sbellard } 4626c896fe29Sbellard 462729f5e925SRichard Henderson static TCGReg tcg_reg_alloc_pair(TCGContext *s, TCGRegSet required_regs, 462829f5e925SRichard Henderson TCGRegSet allocated_regs, 462929f5e925SRichard Henderson TCGRegSet preferred_regs, bool rev) 463029f5e925SRichard Henderson { 463129f5e925SRichard Henderson int i, j, k, fmin, n = ARRAY_SIZE(tcg_target_reg_alloc_order); 463229f5e925SRichard Henderson TCGRegSet reg_ct[2]; 463329f5e925SRichard Henderson const int *order; 463429f5e925SRichard Henderson 463529f5e925SRichard Henderson /* Ensure that if I is not in allocated_regs, I+1 is not either. */ 463629f5e925SRichard Henderson reg_ct[1] = required_regs & ~(allocated_regs | (allocated_regs >> 1)); 463729f5e925SRichard Henderson tcg_debug_assert(reg_ct[1] != 0); 463829f5e925SRichard Henderson reg_ct[0] = reg_ct[1] & preferred_regs; 463929f5e925SRichard Henderson 464029f5e925SRichard Henderson order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order; 464129f5e925SRichard Henderson 464229f5e925SRichard Henderson /* 464329f5e925SRichard Henderson * Skip the preferred_regs option if it cannot be satisfied, 464429f5e925SRichard Henderson * or if the preference made no difference. 464529f5e925SRichard Henderson */ 464629f5e925SRichard Henderson k = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1]; 464729f5e925SRichard Henderson 464829f5e925SRichard Henderson /* 464929f5e925SRichard Henderson * Minimize the number of flushes by looking for 2 free registers first, 465029f5e925SRichard Henderson * then a single flush, then two flushes. 465129f5e925SRichard Henderson */ 465229f5e925SRichard Henderson for (fmin = 2; fmin >= 0; fmin--) { 465329f5e925SRichard Henderson for (j = k; j < 2; j++) { 465429f5e925SRichard Henderson TCGRegSet set = reg_ct[j]; 465529f5e925SRichard Henderson 465629f5e925SRichard Henderson for (i = 0; i < n; i++) { 465729f5e925SRichard Henderson TCGReg reg = order[i]; 465829f5e925SRichard Henderson 465929f5e925SRichard Henderson if (tcg_regset_test_reg(set, reg)) { 466029f5e925SRichard Henderson int f = !s->reg_to_temp[reg] + !s->reg_to_temp[reg + 1]; 466129f5e925SRichard Henderson if (f >= fmin) { 466229f5e925SRichard Henderson tcg_reg_free(s, reg, allocated_regs); 466329f5e925SRichard Henderson tcg_reg_free(s, reg + 1, allocated_regs); 466429f5e925SRichard Henderson return reg; 466529f5e925SRichard Henderson } 466629f5e925SRichard Henderson } 466729f5e925SRichard Henderson } 466829f5e925SRichard Henderson } 466929f5e925SRichard Henderson } 4670732e89f4SRichard Henderson g_assert_not_reached(); 467129f5e925SRichard Henderson } 467229f5e925SRichard Henderson 467340ae5c62SRichard Henderson /* Make sure the temporary is in a register. If needed, allocate the register 467440ae5c62SRichard Henderson from DESIRED while avoiding ALLOCATED. */ 467540ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs, 4676b722452aSRichard Henderson TCGRegSet allocated_regs, TCGRegSet preferred_regs) 467740ae5c62SRichard Henderson { 467840ae5c62SRichard Henderson TCGReg reg; 467940ae5c62SRichard Henderson 468040ae5c62SRichard Henderson switch (ts->val_type) { 468140ae5c62SRichard Henderson case TEMP_VAL_REG: 468240ae5c62SRichard Henderson return; 468340ae5c62SRichard Henderson case TEMP_VAL_CONST: 4684b016486eSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs, 4685b722452aSRichard Henderson preferred_regs, ts->indirect_base); 46860a6a8bc8SRichard Henderson if (ts->type <= TCG_TYPE_I64) { 468740ae5c62SRichard Henderson tcg_out_movi(s, ts->type, reg, ts->val); 46880a6a8bc8SRichard Henderson } else { 46894e186175SRichard Henderson uint64_t val = ts->val; 46904e186175SRichard Henderson MemOp vece = MO_64; 46914e186175SRichard Henderson 46924e186175SRichard Henderson /* 46934e186175SRichard Henderson * Find the minimal vector element that matches the constant. 46944e186175SRichard Henderson * The targets will, in general, have to do this search anyway, 46954e186175SRichard Henderson * do this generically. 46964e186175SRichard Henderson */ 46974e186175SRichard Henderson if (val == dup_const(MO_8, val)) { 46984e186175SRichard Henderson vece = MO_8; 46994e186175SRichard Henderson } else if (val == dup_const(MO_16, val)) { 47004e186175SRichard Henderson vece = MO_16; 47010b4286ddSRichard Henderson } else if (val == dup_const(MO_32, val)) { 47024e186175SRichard Henderson vece = MO_32; 47034e186175SRichard Henderson } 47044e186175SRichard Henderson 47054e186175SRichard Henderson tcg_out_dupi_vec(s, ts->type, vece, reg, ts->val); 47060a6a8bc8SRichard Henderson } 470740ae5c62SRichard Henderson ts->mem_coherent = 0; 470840ae5c62SRichard Henderson break; 470940ae5c62SRichard Henderson case TEMP_VAL_MEM: 4710e139bc4bSPhilippe Mathieu-Daudé if (!ts->mem_allocated) { 4711e139bc4bSPhilippe Mathieu-Daudé temp_allocate_frame(s, ts); 4712e139bc4bSPhilippe Mathieu-Daudé } 4713b016486eSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs, 4714b722452aSRichard Henderson preferred_regs, ts->indirect_base); 471540ae5c62SRichard Henderson tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset); 471640ae5c62SRichard Henderson ts->mem_coherent = 1; 471740ae5c62SRichard Henderson break; 471840ae5c62SRichard Henderson case TEMP_VAL_DEAD: 471940ae5c62SRichard Henderson default: 4720732e89f4SRichard Henderson g_assert_not_reached(); 472140ae5c62SRichard Henderson } 4722098859f1SRichard Henderson set_temp_val_reg(s, ts, reg); 472340ae5c62SRichard Henderson } 472440ae5c62SRichard Henderson 472559d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a 4726e8996ee0Sbellard temporary registers needs to be allocated to store a constant. */ 472759d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs) 47281ad80729SAurelien Jarno { 47292c0366f0SAurelien Jarno /* The liveness analysis already ensures that globals are back 4730eabb7b91SAurelien Jarno in memory. Keep an tcg_debug_assert for safety. */ 4731e01fa97dSRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || temp_readonly(ts)); 47321ad80729SAurelien Jarno } 47331ad80729SAurelien Jarno 47349814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be 4735641d5fbeSbellard modified be the following code. 'allocated_regs' is used in case a 4736641d5fbeSbellard temporary registers needs to be allocated to store a constant. */ 4737641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs) 4738641d5fbeSbellard { 4739ac3b8891SRichard Henderson int i, n; 4740641d5fbeSbellard 4741ac3b8891SRichard Henderson for (i = 0, n = s->nb_globals; i < n; i++) { 4742b13eb728SRichard Henderson temp_save(s, &s->temps[i], allocated_regs); 4743641d5fbeSbellard } 4744e5097dc8Sbellard } 4745e5097dc8Sbellard 47463d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be 47473d5c5f87SAurelien Jarno read by the following code. 'allocated_regs' is used in case a 47483d5c5f87SAurelien Jarno temporary registers needs to be allocated to store a constant. */ 47493d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs) 47503d5c5f87SAurelien Jarno { 4751ac3b8891SRichard Henderson int i, n; 47523d5c5f87SAurelien Jarno 4753ac3b8891SRichard Henderson for (i = 0, n = s->nb_globals; i < n; i++) { 475412b9b11aSRichard Henderson TCGTemp *ts = &s->temps[i]; 475512b9b11aSRichard Henderson tcg_debug_assert(ts->val_type != TEMP_VAL_REG 4756ee17db83SRichard Henderson || ts->kind == TEMP_FIXED 475712b9b11aSRichard Henderson || ts->mem_coherent); 47583d5c5f87SAurelien Jarno } 47593d5c5f87SAurelien Jarno } 47603d5c5f87SAurelien Jarno 4761e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and 4762e8996ee0Sbellard all globals are stored at their canonical location. */ 4763e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs) 4764e5097dc8Sbellard { 4765e5097dc8Sbellard int i; 4766e5097dc8Sbellard 4767c896fe29Sbellard for (i = s->nb_globals; i < s->nb_temps; i++) { 4768b13eb728SRichard Henderson TCGTemp *ts = &s->temps[i]; 4769c0522136SRichard Henderson 4770c0522136SRichard Henderson switch (ts->kind) { 4771f57c6915SRichard Henderson case TEMP_TB: 4772b13eb728SRichard Henderson temp_save(s, ts, allocated_regs); 4773c0522136SRichard Henderson break; 4774c7482438SRichard Henderson case TEMP_EBB: 47752c0366f0SAurelien Jarno /* The liveness analysis already ensures that temps are dead. 4776eabb7b91SAurelien Jarno Keep an tcg_debug_assert for safety. */ 4777eabb7b91SAurelien Jarno tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD); 4778c0522136SRichard Henderson break; 4779c0522136SRichard Henderson case TEMP_CONST: 4780c0522136SRichard Henderson /* Similarly, we should have freed any allocated register. */ 4781c0522136SRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_CONST); 4782c0522136SRichard Henderson break; 4783c0522136SRichard Henderson default: 4784c0522136SRichard Henderson g_assert_not_reached(); 4785c896fe29Sbellard } 4786641d5fbeSbellard } 4787e8996ee0Sbellard 4788e8996ee0Sbellard save_globals(s, allocated_regs); 4789c896fe29Sbellard } 4790c896fe29Sbellard 4791bab1671fSRichard Henderson /* 4792c7482438SRichard Henderson * At a conditional branch, we assume all temporaries are dead unless 4793c7482438SRichard Henderson * explicitly live-across-conditional-branch; all globals and local 4794c7482438SRichard Henderson * temps are synced to their location. 4795b4cb76e6SRichard Henderson */ 4796b4cb76e6SRichard Henderson static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs) 4797b4cb76e6SRichard Henderson { 4798b4cb76e6SRichard Henderson sync_globals(s, allocated_regs); 4799b4cb76e6SRichard Henderson 4800b4cb76e6SRichard Henderson for (int i = s->nb_globals; i < s->nb_temps; i++) { 4801b4cb76e6SRichard Henderson TCGTemp *ts = &s->temps[i]; 4802b4cb76e6SRichard Henderson /* 4803b4cb76e6SRichard Henderson * The liveness analysis already ensures that temps are dead. 4804b4cb76e6SRichard Henderson * Keep tcg_debug_asserts for safety. 4805b4cb76e6SRichard Henderson */ 4806c0522136SRichard Henderson switch (ts->kind) { 4807f57c6915SRichard Henderson case TEMP_TB: 4808b4cb76e6SRichard Henderson tcg_debug_assert(ts->val_type != TEMP_VAL_REG || ts->mem_coherent); 4809c0522136SRichard Henderson break; 4810c7482438SRichard Henderson case TEMP_EBB: 4811c0522136SRichard Henderson case TEMP_CONST: 4812c0522136SRichard Henderson break; 4813c0522136SRichard Henderson default: 4814c0522136SRichard Henderson g_assert_not_reached(); 4815b4cb76e6SRichard Henderson } 4816b4cb76e6SRichard Henderson } 4817b4cb76e6SRichard Henderson } 4818b4cb76e6SRichard Henderson 4819b4cb76e6SRichard Henderson /* 4820c58f4c97SRichard Henderson * Specialized code generation for INDEX_op_mov_* with a constant. 4821bab1671fSRichard Henderson */ 48220fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots, 4823ba87719cSRichard Henderson tcg_target_ulong val, TCGLifeData arg_life, 4824ba87719cSRichard Henderson TCGRegSet preferred_regs) 4825e8996ee0Sbellard { 4826d63e3b6eSRichard Henderson /* ENV should not be modified. */ 4827e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 482859d7c14eSRichard Henderson 482959d7c14eSRichard Henderson /* The movi is not explicitly generated here. */ 4830098859f1SRichard Henderson set_temp_val_nonreg(s, ots, TEMP_VAL_CONST); 4831e8996ee0Sbellard ots->val = val; 483259d7c14eSRichard Henderson ots->mem_coherent = 0; 4833ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) { 4834ba87719cSRichard Henderson temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0)); 483559d7c14eSRichard Henderson } else if (IS_DEAD_ARG(0)) { 4836f8bf00f1SRichard Henderson temp_dead(s, ots); 48374c4e1ab2SAurelien Jarno } 4838e8996ee0Sbellard } 4839e8996ee0Sbellard 4840bab1671fSRichard Henderson /* 4841bab1671fSRichard Henderson * Specialized code generation for INDEX_op_mov_*. 4842bab1671fSRichard Henderson */ 4843dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op) 4844c896fe29Sbellard { 4845dd186292SRichard Henderson const TCGLifeData arg_life = op->life; 484669e3706dSRichard Henderson TCGRegSet allocated_regs, preferred_regs; 4847c896fe29Sbellard TCGTemp *ts, *ots; 4848450445d5SRichard Henderson TCGType otype, itype; 4849098859f1SRichard Henderson TCGReg oreg, ireg; 4850c896fe29Sbellard 4851d21369f5SRichard Henderson allocated_regs = s->reserved_regs; 485231fd884bSRichard Henderson preferred_regs = output_pref(op, 0); 485343439139SRichard Henderson ots = arg_temp(op->args[0]); 485443439139SRichard Henderson ts = arg_temp(op->args[1]); 4855450445d5SRichard Henderson 4856d63e3b6eSRichard Henderson /* ENV should not be modified. */ 4857e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 4858d63e3b6eSRichard Henderson 4859450445d5SRichard Henderson /* Note that otype != itype for no-op truncation. */ 4860450445d5SRichard Henderson otype = ots->type; 4861450445d5SRichard Henderson itype = ts->type; 4862c896fe29Sbellard 48630fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_CONST) { 48640fe4fca4SPaolo Bonzini /* propagate constant or generate sti */ 48650fe4fca4SPaolo Bonzini tcg_target_ulong val = ts->val; 48660fe4fca4SPaolo Bonzini if (IS_DEAD_ARG(1)) { 48670fe4fca4SPaolo Bonzini temp_dead(s, ts); 48680fe4fca4SPaolo Bonzini } 486969e3706dSRichard Henderson tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs); 48700fe4fca4SPaolo Bonzini return; 48710fe4fca4SPaolo Bonzini } 48720fe4fca4SPaolo Bonzini 48730fe4fca4SPaolo Bonzini /* If the source value is in memory we're going to be forced 48740fe4fca4SPaolo Bonzini to have it in a register in order to perform the copy. Copy 48750fe4fca4SPaolo Bonzini the SOURCE value into its own register first, that way we 48760fe4fca4SPaolo Bonzini don't have to reload SOURCE the next time it is used. */ 48770fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_MEM) { 487869e3706dSRichard Henderson temp_load(s, ts, tcg_target_available_regs[itype], 487969e3706dSRichard Henderson allocated_regs, preferred_regs); 4880c29c1d7eSAurelien Jarno } 48810fe4fca4SPaolo Bonzini tcg_debug_assert(ts->val_type == TEMP_VAL_REG); 4882098859f1SRichard Henderson ireg = ts->reg; 4883098859f1SRichard Henderson 4884d63e3b6eSRichard Henderson if (IS_DEAD_ARG(0)) { 4885c29c1d7eSAurelien Jarno /* mov to a non-saved dead register makes no sense (even with 4886c29c1d7eSAurelien Jarno liveness analysis disabled). */ 4887eabb7b91SAurelien Jarno tcg_debug_assert(NEED_SYNC_ARG(0)); 4888c29c1d7eSAurelien Jarno if (!ots->mem_allocated) { 48892272e4a7SRichard Henderson temp_allocate_frame(s, ots); 4890c29c1d7eSAurelien Jarno } 4891098859f1SRichard Henderson tcg_out_st(s, otype, ireg, ots->mem_base->reg, ots->mem_offset); 4892c29c1d7eSAurelien Jarno if (IS_DEAD_ARG(1)) { 4893f8bf00f1SRichard Henderson temp_dead(s, ts); 4894c29c1d7eSAurelien Jarno } 4895f8bf00f1SRichard Henderson temp_dead(s, ots); 4896098859f1SRichard Henderson return; 4897098859f1SRichard Henderson } 4898098859f1SRichard Henderson 4899ee17db83SRichard Henderson if (IS_DEAD_ARG(1) && ts->kind != TEMP_FIXED) { 4900098859f1SRichard Henderson /* 4901098859f1SRichard Henderson * The mov can be suppressed. Kill input first, so that it 4902098859f1SRichard Henderson * is unlinked from reg_to_temp, then set the output to the 4903098859f1SRichard Henderson * reg that we saved from the input. 4904098859f1SRichard Henderson */ 4905f8bf00f1SRichard Henderson temp_dead(s, ts); 4906098859f1SRichard Henderson oreg = ireg; 4907c29c1d7eSAurelien Jarno } else { 4908098859f1SRichard Henderson if (ots->val_type == TEMP_VAL_REG) { 4909098859f1SRichard Henderson oreg = ots->reg; 4910098859f1SRichard Henderson } else { 4911098859f1SRichard Henderson /* Make sure to not spill the input register during allocation. */ 4912098859f1SRichard Henderson oreg = tcg_reg_alloc(s, tcg_target_available_regs[otype], 4913098859f1SRichard Henderson allocated_regs | ((TCGRegSet)1 << ireg), 4914098859f1SRichard Henderson preferred_regs, ots->indirect_base); 4915c29c1d7eSAurelien Jarno } 4916098859f1SRichard Henderson if (!tcg_out_mov(s, otype, oreg, ireg)) { 4917240c08d0SRichard Henderson /* 4918240c08d0SRichard Henderson * Cross register class move not supported. 4919240c08d0SRichard Henderson * Store the source register into the destination slot 4920240c08d0SRichard Henderson * and leave the destination temp as TEMP_VAL_MEM. 4921240c08d0SRichard Henderson */ 4922e01fa97dSRichard Henderson assert(!temp_readonly(ots)); 4923240c08d0SRichard Henderson if (!ts->mem_allocated) { 4924240c08d0SRichard Henderson temp_allocate_frame(s, ots); 4925240c08d0SRichard Henderson } 4926098859f1SRichard Henderson tcg_out_st(s, ts->type, ireg, ots->mem_base->reg, ots->mem_offset); 4927098859f1SRichard Henderson set_temp_val_nonreg(s, ts, TEMP_VAL_MEM); 4928240c08d0SRichard Henderson ots->mem_coherent = 1; 4929240c08d0SRichard Henderson return; 493078113e83SRichard Henderson } 4931c29c1d7eSAurelien Jarno } 4932098859f1SRichard Henderson set_temp_val_reg(s, ots, oreg); 4933c896fe29Sbellard ots->mem_coherent = 0; 4934098859f1SRichard Henderson 4935ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) { 493698b4e186SRichard Henderson temp_sync(s, ots, allocated_regs, 0, 0); 4937c29c1d7eSAurelien Jarno } 4938ec7a869dSAurelien Jarno } 4939c896fe29Sbellard 4940bab1671fSRichard Henderson /* 4941bab1671fSRichard Henderson * Specialized code generation for INDEX_op_dup_vec. 4942bab1671fSRichard Henderson */ 4943bab1671fSRichard Henderson static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op) 4944bab1671fSRichard Henderson { 4945bab1671fSRichard Henderson const TCGLifeData arg_life = op->life; 4946bab1671fSRichard Henderson TCGRegSet dup_out_regs, dup_in_regs; 4947501fb3daSRichard Henderson const TCGArgConstraint *dup_args_ct; 4948bab1671fSRichard Henderson TCGTemp *its, *ots; 4949bab1671fSRichard Henderson TCGType itype, vtype; 4950bab1671fSRichard Henderson unsigned vece; 495131c96417SRichard Henderson int lowpart_ofs; 4952bab1671fSRichard Henderson bool ok; 4953bab1671fSRichard Henderson 4954bab1671fSRichard Henderson ots = arg_temp(op->args[0]); 4955bab1671fSRichard Henderson its = arg_temp(op->args[1]); 4956bab1671fSRichard Henderson 4957bab1671fSRichard Henderson /* ENV should not be modified. */ 4958e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 4959bab1671fSRichard Henderson 4960bab1671fSRichard Henderson itype = its->type; 4961bab1671fSRichard Henderson vece = TCGOP_VECE(op); 49624d872218SRichard Henderson vtype = TCGOP_TYPE(op); 4963bab1671fSRichard Henderson 4964bab1671fSRichard Henderson if (its->val_type == TEMP_VAL_CONST) { 4965bab1671fSRichard Henderson /* Propagate constant via movi -> dupi. */ 4966bab1671fSRichard Henderson tcg_target_ulong val = its->val; 4967bab1671fSRichard Henderson if (IS_DEAD_ARG(1)) { 4968bab1671fSRichard Henderson temp_dead(s, its); 4969bab1671fSRichard Henderson } 497031fd884bSRichard Henderson tcg_reg_alloc_do_movi(s, ots, val, arg_life, output_pref(op, 0)); 4971bab1671fSRichard Henderson return; 4972bab1671fSRichard Henderson } 4973bab1671fSRichard Henderson 4974501fb3daSRichard Henderson dup_args_ct = opcode_args_ct(op); 4975501fb3daSRichard Henderson dup_out_regs = dup_args_ct[0].regs; 4976501fb3daSRichard Henderson dup_in_regs = dup_args_ct[1].regs; 4977bab1671fSRichard Henderson 4978bab1671fSRichard Henderson /* Allocate the output register now. */ 4979bab1671fSRichard Henderson if (ots->val_type != TEMP_VAL_REG) { 4980bab1671fSRichard Henderson TCGRegSet allocated_regs = s->reserved_regs; 4981098859f1SRichard Henderson TCGReg oreg; 4982bab1671fSRichard Henderson 4983bab1671fSRichard Henderson if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) { 4984bab1671fSRichard Henderson /* Make sure to not spill the input register. */ 4985bab1671fSRichard Henderson tcg_regset_set_reg(allocated_regs, its->reg); 4986bab1671fSRichard Henderson } 4987098859f1SRichard Henderson oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs, 498831fd884bSRichard Henderson output_pref(op, 0), ots->indirect_base); 4989098859f1SRichard Henderson set_temp_val_reg(s, ots, oreg); 4990bab1671fSRichard Henderson } 4991bab1671fSRichard Henderson 4992bab1671fSRichard Henderson switch (its->val_type) { 4993bab1671fSRichard Henderson case TEMP_VAL_REG: 4994bab1671fSRichard Henderson /* 4995bab1671fSRichard Henderson * The dup constriaints must be broad, covering all possible VECE. 4996bab1671fSRichard Henderson * However, tcg_op_dup_vec() gets to see the VECE and we allow it 4997bab1671fSRichard Henderson * to fail, indicating that extra moves are required for that case. 4998bab1671fSRichard Henderson */ 4999bab1671fSRichard Henderson if (tcg_regset_test_reg(dup_in_regs, its->reg)) { 5000bab1671fSRichard Henderson if (tcg_out_dup_vec(s, vtype, vece, ots->reg, its->reg)) { 5001bab1671fSRichard Henderson goto done; 5002bab1671fSRichard Henderson } 5003bab1671fSRichard Henderson /* Try again from memory or a vector input register. */ 5004bab1671fSRichard Henderson } 5005bab1671fSRichard Henderson if (!its->mem_coherent) { 5006bab1671fSRichard Henderson /* 5007bab1671fSRichard Henderson * The input register is not synced, and so an extra store 5008bab1671fSRichard Henderson * would be required to use memory. Attempt an integer-vector 5009bab1671fSRichard Henderson * register move first. We do not have a TCGRegSet for this. 5010bab1671fSRichard Henderson */ 5011bab1671fSRichard Henderson if (tcg_out_mov(s, itype, ots->reg, its->reg)) { 5012bab1671fSRichard Henderson break; 5013bab1671fSRichard Henderson } 5014bab1671fSRichard Henderson /* Sync the temp back to its slot and load from there. */ 5015bab1671fSRichard Henderson temp_sync(s, its, s->reserved_regs, 0, 0); 5016bab1671fSRichard Henderson } 5017bab1671fSRichard Henderson /* fall through */ 5018bab1671fSRichard Henderson 5019bab1671fSRichard Henderson case TEMP_VAL_MEM: 502031c96417SRichard Henderson lowpart_ofs = 0; 502131c96417SRichard Henderson if (HOST_BIG_ENDIAN) { 502231c96417SRichard Henderson lowpart_ofs = tcg_type_size(itype) - (1 << vece); 502331c96417SRichard Henderson } 5024d6ecb4a9SRichard Henderson if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg, 502531c96417SRichard Henderson its->mem_offset + lowpart_ofs)) { 5026d6ecb4a9SRichard Henderson goto done; 5027d6ecb4a9SRichard Henderson } 5028098859f1SRichard Henderson /* Load the input into the destination vector register. */ 5029bab1671fSRichard Henderson tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset); 5030bab1671fSRichard Henderson break; 5031bab1671fSRichard Henderson 5032bab1671fSRichard Henderson default: 5033bab1671fSRichard Henderson g_assert_not_reached(); 5034bab1671fSRichard Henderson } 5035bab1671fSRichard Henderson 5036bab1671fSRichard Henderson /* We now have a vector input register, so dup must succeed. */ 5037bab1671fSRichard Henderson ok = tcg_out_dup_vec(s, vtype, vece, ots->reg, ots->reg); 5038bab1671fSRichard Henderson tcg_debug_assert(ok); 5039bab1671fSRichard Henderson 5040bab1671fSRichard Henderson done: 504136f5539cSRichard Henderson ots->mem_coherent = 0; 5042bab1671fSRichard Henderson if (IS_DEAD_ARG(1)) { 5043bab1671fSRichard Henderson temp_dead(s, its); 5044bab1671fSRichard Henderson } 5045bab1671fSRichard Henderson if (NEED_SYNC_ARG(0)) { 5046bab1671fSRichard Henderson temp_sync(s, ots, s->reserved_regs, 0, 0); 5047bab1671fSRichard Henderson } 5048bab1671fSRichard Henderson if (IS_DEAD_ARG(0)) { 5049bab1671fSRichard Henderson temp_dead(s, ots); 5050bab1671fSRichard Henderson } 5051bab1671fSRichard Henderson } 5052bab1671fSRichard Henderson 5053dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) 5054c896fe29Sbellard { 5055dd186292SRichard Henderson const TCGLifeData arg_life = op->life; 5056dd186292SRichard Henderson const TCGOpDef * const def = &tcg_op_defs[op->opc]; 505782790a87SRichard Henderson TCGRegSet i_allocated_regs; 505882790a87SRichard Henderson TCGRegSet o_allocated_regs; 5059b6638662SRichard Henderson int i, k, nb_iargs, nb_oargs; 5060b6638662SRichard Henderson TCGReg reg; 5061c896fe29Sbellard TCGArg arg; 5062501fb3daSRichard Henderson const TCGArgConstraint *args_ct; 5063c896fe29Sbellard const TCGArgConstraint *arg_ct; 5064c896fe29Sbellard TCGTemp *ts; 5065c896fe29Sbellard TCGArg new_args[TCG_MAX_OP_ARGS]; 5066c896fe29Sbellard int const_args[TCG_MAX_OP_ARGS]; 506721e9a8aeSRichard Henderson TCGCond op_cond; 5068c896fe29Sbellard 5069c896fe29Sbellard nb_oargs = def->nb_oargs; 5070c896fe29Sbellard nb_iargs = def->nb_iargs; 5071c896fe29Sbellard 5072c896fe29Sbellard /* copy constants */ 5073c896fe29Sbellard memcpy(new_args + nb_oargs + nb_iargs, 5074dd186292SRichard Henderson op->args + nb_oargs + nb_iargs, 5075c896fe29Sbellard sizeof(TCGArg) * def->nb_cargs); 5076c896fe29Sbellard 5077d21369f5SRichard Henderson i_allocated_regs = s->reserved_regs; 5078d21369f5SRichard Henderson o_allocated_regs = s->reserved_regs; 507982790a87SRichard Henderson 508021e9a8aeSRichard Henderson switch (op->opc) { 508121e9a8aeSRichard Henderson case INDEX_op_brcond_i32: 508221e9a8aeSRichard Henderson case INDEX_op_brcond_i64: 508321e9a8aeSRichard Henderson op_cond = op->args[2]; 508421e9a8aeSRichard Henderson break; 508521e9a8aeSRichard Henderson case INDEX_op_setcond_i32: 508621e9a8aeSRichard Henderson case INDEX_op_setcond_i64: 508721e9a8aeSRichard Henderson case INDEX_op_negsetcond_i32: 508821e9a8aeSRichard Henderson case INDEX_op_negsetcond_i64: 508921e9a8aeSRichard Henderson case INDEX_op_cmp_vec: 509021e9a8aeSRichard Henderson op_cond = op->args[3]; 509121e9a8aeSRichard Henderson break; 509221e9a8aeSRichard Henderson case INDEX_op_brcond2_i32: 509321e9a8aeSRichard Henderson op_cond = op->args[4]; 509421e9a8aeSRichard Henderson break; 509521e9a8aeSRichard Henderson case INDEX_op_movcond_i32: 509621e9a8aeSRichard Henderson case INDEX_op_movcond_i64: 509721e9a8aeSRichard Henderson case INDEX_op_setcond2_i32: 509821e9a8aeSRichard Henderson case INDEX_op_cmpsel_vec: 509921e9a8aeSRichard Henderson op_cond = op->args[5]; 510021e9a8aeSRichard Henderson break; 510121e9a8aeSRichard Henderson default: 510221e9a8aeSRichard Henderson /* No condition within opcode. */ 510321e9a8aeSRichard Henderson op_cond = TCG_COND_ALWAYS; 510421e9a8aeSRichard Henderson break; 510521e9a8aeSRichard Henderson } 510621e9a8aeSRichard Henderson 5107501fb3daSRichard Henderson args_ct = opcode_args_ct(op); 5108501fb3daSRichard Henderson 5109c896fe29Sbellard /* satisfy input constraints */ 5110c896fe29Sbellard for (k = 0; k < nb_iargs; k++) { 511129f5e925SRichard Henderson TCGRegSet i_preferred_regs, i_required_regs; 511229f5e925SRichard Henderson bool allocate_new_reg, copyto_new_reg; 511329f5e925SRichard Henderson TCGTemp *ts2; 511429f5e925SRichard Henderson int i1, i2; 5115d62816f2SRichard Henderson 5116501fb3daSRichard Henderson i = args_ct[nb_oargs + k].sort_index; 5117dd186292SRichard Henderson arg = op->args[i]; 5118501fb3daSRichard Henderson arg_ct = &args_ct[i]; 511943439139SRichard Henderson ts = arg_temp(arg); 512040ae5c62SRichard Henderson 51216b8abd24SRichard Henderson if (ts->val_type == TEMP_VAL_CONST) { 51226b8abd24SRichard Henderson #ifdef TCG_REG_ZERO 51236b8abd24SRichard Henderson if (ts->val == 0 && (arg_ct->ct & TCG_CT_REG_ZERO)) { 51246b8abd24SRichard Henderson /* Hardware zero register: indicate register via non-const. */ 51256b8abd24SRichard Henderson const_args[i] = 0; 51266b8abd24SRichard Henderson new_args[i] = TCG_REG_ZERO; 51276b8abd24SRichard Henderson continue; 51286b8abd24SRichard Henderson } 51296b8abd24SRichard Henderson #endif 51306b8abd24SRichard Henderson 51316b8abd24SRichard Henderson if (tcg_target_const_match(ts->val, arg_ct->ct, ts->type, 513221e9a8aeSRichard Henderson op_cond, TCGOP_VECE(op))) { 5133c896fe29Sbellard /* constant is OK for instruction */ 5134c896fe29Sbellard const_args[i] = 1; 5135c896fe29Sbellard new_args[i] = ts->val; 5136d62816f2SRichard Henderson continue; 5137c896fe29Sbellard } 51386b8abd24SRichard Henderson } 513940ae5c62SRichard Henderson 51401c1824dcSRichard Henderson reg = ts->reg; 51411c1824dcSRichard Henderson i_preferred_regs = 0; 514229f5e925SRichard Henderson i_required_regs = arg_ct->regs; 51431c1824dcSRichard Henderson allocate_new_reg = false; 514429f5e925SRichard Henderson copyto_new_reg = false; 51451c1824dcSRichard Henderson 514629f5e925SRichard Henderson switch (arg_ct->pair) { 514729f5e925SRichard Henderson case 0: /* not paired */ 5148bc2b17e6SRichard Henderson if (arg_ct->ialias) { 514931fd884bSRichard Henderson i_preferred_regs = output_pref(op, arg_ct->alias_index); 5150c0522136SRichard Henderson 5151c0522136SRichard Henderson /* 5152c0522136SRichard Henderson * If the input is readonly, then it cannot also be an 5153c0522136SRichard Henderson * output and aliased to itself. If the input is not 5154c0522136SRichard Henderson * dead after the instruction, we must allocate a new 5155c0522136SRichard Henderson * register and move it. 5156c0522136SRichard Henderson */ 515722d2e535SIlya Leoshkevich if (temp_readonly(ts) || !IS_DEAD_ARG(i) 5158501fb3daSRichard Henderson || args_ct[arg_ct->alias_index].newreg) { 51591c1824dcSRichard Henderson allocate_new_reg = true; 51601c1824dcSRichard Henderson } else if (ts->val_type == TEMP_VAL_REG) { 5161c0522136SRichard Henderson /* 51621c1824dcSRichard Henderson * Check if the current register has already been 51631c1824dcSRichard Henderson * allocated for another input. 5164c0522136SRichard Henderson */ 516529f5e925SRichard Henderson allocate_new_reg = 516629f5e925SRichard Henderson tcg_regset_test_reg(i_allocated_regs, reg); 51677e1df267SAurelien Jarno } 51687e1df267SAurelien Jarno } 51691c1824dcSRichard Henderson if (!allocate_new_reg) { 517029f5e925SRichard Henderson temp_load(s, ts, i_required_regs, i_allocated_regs, 517129f5e925SRichard Henderson i_preferred_regs); 5172c896fe29Sbellard reg = ts->reg; 517329f5e925SRichard Henderson allocate_new_reg = !tcg_regset_test_reg(i_required_regs, reg); 51741c1824dcSRichard Henderson } 51751c1824dcSRichard Henderson if (allocate_new_reg) { 5176c0522136SRichard Henderson /* 5177c0522136SRichard Henderson * Allocate a new register matching the constraint 5178c0522136SRichard Henderson * and move the temporary register into it. 5179c0522136SRichard Henderson */ 5180d62816f2SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 5181d62816f2SRichard Henderson i_allocated_regs, 0); 518229f5e925SRichard Henderson reg = tcg_reg_alloc(s, i_required_regs, i_allocated_regs, 51831c1824dcSRichard Henderson i_preferred_regs, ts->indirect_base); 518429f5e925SRichard Henderson copyto_new_reg = true; 518529f5e925SRichard Henderson } 518629f5e925SRichard Henderson break; 518729f5e925SRichard Henderson 518829f5e925SRichard Henderson case 1: 518929f5e925SRichard Henderson /* First of an input pair; if i1 == i2, the second is an output. */ 519029f5e925SRichard Henderson i1 = i; 519129f5e925SRichard Henderson i2 = arg_ct->pair_index; 519229f5e925SRichard Henderson ts2 = i1 != i2 ? arg_temp(op->args[i2]) : NULL; 519329f5e925SRichard Henderson 519429f5e925SRichard Henderson /* 519529f5e925SRichard Henderson * It is easier to default to allocating a new pair 519629f5e925SRichard Henderson * and to identify a few cases where it's not required. 519729f5e925SRichard Henderson */ 519829f5e925SRichard Henderson if (arg_ct->ialias) { 519931fd884bSRichard Henderson i_preferred_regs = output_pref(op, arg_ct->alias_index); 520029f5e925SRichard Henderson if (IS_DEAD_ARG(i1) && 520129f5e925SRichard Henderson IS_DEAD_ARG(i2) && 520229f5e925SRichard Henderson !temp_readonly(ts) && 520329f5e925SRichard Henderson ts->val_type == TEMP_VAL_REG && 520429f5e925SRichard Henderson ts->reg < TCG_TARGET_NB_REGS - 1 && 520529f5e925SRichard Henderson tcg_regset_test_reg(i_required_regs, reg) && 520629f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg) && 520729f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg + 1) && 520829f5e925SRichard Henderson (ts2 520929f5e925SRichard Henderson ? ts2->val_type == TEMP_VAL_REG && 521029f5e925SRichard Henderson ts2->reg == reg + 1 && 521129f5e925SRichard Henderson !temp_readonly(ts2) 521229f5e925SRichard Henderson : s->reg_to_temp[reg + 1] == NULL)) { 521329f5e925SRichard Henderson break; 521429f5e925SRichard Henderson } 521529f5e925SRichard Henderson } else { 521629f5e925SRichard Henderson /* Without aliasing, the pair must also be an input. */ 521729f5e925SRichard Henderson tcg_debug_assert(ts2); 521829f5e925SRichard Henderson if (ts->val_type == TEMP_VAL_REG && 521929f5e925SRichard Henderson ts2->val_type == TEMP_VAL_REG && 522029f5e925SRichard Henderson ts2->reg == reg + 1 && 522129f5e925SRichard Henderson tcg_regset_test_reg(i_required_regs, reg)) { 522229f5e925SRichard Henderson break; 522329f5e925SRichard Henderson } 522429f5e925SRichard Henderson } 522529f5e925SRichard Henderson reg = tcg_reg_alloc_pair(s, i_required_regs, i_allocated_regs, 522629f5e925SRichard Henderson 0, ts->indirect_base); 522729f5e925SRichard Henderson goto do_pair; 522829f5e925SRichard Henderson 522929f5e925SRichard Henderson case 2: /* pair second */ 523029f5e925SRichard Henderson reg = new_args[arg_ct->pair_index] + 1; 523129f5e925SRichard Henderson goto do_pair; 523229f5e925SRichard Henderson 523329f5e925SRichard Henderson case 3: /* ialias with second output, no first input */ 523429f5e925SRichard Henderson tcg_debug_assert(arg_ct->ialias); 523531fd884bSRichard Henderson i_preferred_regs = output_pref(op, arg_ct->alias_index); 523629f5e925SRichard Henderson 523729f5e925SRichard Henderson if (IS_DEAD_ARG(i) && 523829f5e925SRichard Henderson !temp_readonly(ts) && 523929f5e925SRichard Henderson ts->val_type == TEMP_VAL_REG && 524029f5e925SRichard Henderson reg > 0 && 524129f5e925SRichard Henderson s->reg_to_temp[reg - 1] == NULL && 524229f5e925SRichard Henderson tcg_regset_test_reg(i_required_regs, reg) && 524329f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg) && 524429f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg - 1)) { 524529f5e925SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg - 1); 524629f5e925SRichard Henderson break; 524729f5e925SRichard Henderson } 524829f5e925SRichard Henderson reg = tcg_reg_alloc_pair(s, i_required_regs >> 1, 524929f5e925SRichard Henderson i_allocated_regs, 0, 525029f5e925SRichard Henderson ts->indirect_base); 525129f5e925SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg); 525229f5e925SRichard Henderson reg += 1; 525329f5e925SRichard Henderson goto do_pair; 525429f5e925SRichard Henderson 525529f5e925SRichard Henderson do_pair: 525629f5e925SRichard Henderson /* 525729f5e925SRichard Henderson * If an aliased input is not dead after the instruction, 525829f5e925SRichard Henderson * we must allocate a new register and move it. 525929f5e925SRichard Henderson */ 526029f5e925SRichard Henderson if (arg_ct->ialias && (!IS_DEAD_ARG(i) || temp_readonly(ts))) { 526129f5e925SRichard Henderson TCGRegSet t_allocated_regs = i_allocated_regs; 526229f5e925SRichard Henderson 526329f5e925SRichard Henderson /* 526429f5e925SRichard Henderson * Because of the alias, and the continued life, make sure 526529f5e925SRichard Henderson * that the temp is somewhere *other* than the reg pair, 526629f5e925SRichard Henderson * and we get a copy in reg. 526729f5e925SRichard Henderson */ 526829f5e925SRichard Henderson tcg_regset_set_reg(t_allocated_regs, reg); 526929f5e925SRichard Henderson tcg_regset_set_reg(t_allocated_regs, reg + 1); 527029f5e925SRichard Henderson if (ts->val_type == TEMP_VAL_REG && ts->reg == reg) { 527129f5e925SRichard Henderson /* If ts was already in reg, copy it somewhere else. */ 527229f5e925SRichard Henderson TCGReg nr; 527329f5e925SRichard Henderson bool ok; 527429f5e925SRichard Henderson 527529f5e925SRichard Henderson tcg_debug_assert(ts->kind != TEMP_FIXED); 527629f5e925SRichard Henderson nr = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], 527729f5e925SRichard Henderson t_allocated_regs, 0, ts->indirect_base); 527829f5e925SRichard Henderson ok = tcg_out_mov(s, ts->type, nr, reg); 527929f5e925SRichard Henderson tcg_debug_assert(ok); 528029f5e925SRichard Henderson 528129f5e925SRichard Henderson set_temp_val_reg(s, ts, nr); 528229f5e925SRichard Henderson } else { 528329f5e925SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 528429f5e925SRichard Henderson t_allocated_regs, 0); 528529f5e925SRichard Henderson copyto_new_reg = true; 528629f5e925SRichard Henderson } 528729f5e925SRichard Henderson } else { 528829f5e925SRichard Henderson /* Preferably allocate to reg, otherwise copy. */ 528929f5e925SRichard Henderson i_required_regs = (TCGRegSet)1 << reg; 529029f5e925SRichard Henderson temp_load(s, ts, i_required_regs, i_allocated_regs, 529129f5e925SRichard Henderson i_preferred_regs); 529229f5e925SRichard Henderson copyto_new_reg = ts->reg != reg; 529329f5e925SRichard Henderson } 529429f5e925SRichard Henderson break; 529529f5e925SRichard Henderson 529629f5e925SRichard Henderson default: 529729f5e925SRichard Henderson g_assert_not_reached(); 529829f5e925SRichard Henderson } 529929f5e925SRichard Henderson 530029f5e925SRichard Henderson if (copyto_new_reg) { 530178113e83SRichard Henderson if (!tcg_out_mov(s, ts->type, reg, ts->reg)) { 5302240c08d0SRichard Henderson /* 5303240c08d0SRichard Henderson * Cross register class move not supported. Sync the 5304240c08d0SRichard Henderson * temp back to its slot and load from there. 5305240c08d0SRichard Henderson */ 5306240c08d0SRichard Henderson temp_sync(s, ts, i_allocated_regs, 0, 0); 5307240c08d0SRichard Henderson tcg_out_ld(s, ts->type, reg, 5308240c08d0SRichard Henderson ts->mem_base->reg, ts->mem_offset); 530978113e83SRichard Henderson } 5310c896fe29Sbellard } 5311c896fe29Sbellard new_args[i] = reg; 5312c896fe29Sbellard const_args[i] = 0; 531382790a87SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg); 5314c896fe29Sbellard } 5315c896fe29Sbellard 5316c896fe29Sbellard /* mark dead temporaries and free the associated registers */ 5317866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 5318866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) { 531943439139SRichard Henderson temp_dead(s, arg_temp(op->args[i])); 5320c896fe29Sbellard } 5321c896fe29Sbellard } 5322c896fe29Sbellard 5323b4cb76e6SRichard Henderson if (def->flags & TCG_OPF_COND_BRANCH) { 5324b4cb76e6SRichard Henderson tcg_reg_alloc_cbranch(s, i_allocated_regs); 5325b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 532682790a87SRichard Henderson tcg_reg_alloc_bb_end(s, i_allocated_regs); 5327a52ad07eSAurelien Jarno } else { 5328c896fe29Sbellard if (def->flags & TCG_OPF_CALL_CLOBBER) { 5329b03cce8eSbellard /* XXX: permit generic clobber register list ? */ 5330c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) { 5331c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { 533282790a87SRichard Henderson tcg_reg_free(s, i, i_allocated_regs); 5333c896fe29Sbellard } 5334c896fe29Sbellard } 53353d5c5f87SAurelien Jarno } 53363d5c5f87SAurelien Jarno if (def->flags & TCG_OPF_SIDE_EFFECTS) { 53373d5c5f87SAurelien Jarno /* sync globals if the op has side effects and might trigger 53383d5c5f87SAurelien Jarno an exception. */ 533982790a87SRichard Henderson sync_globals(s, i_allocated_regs); 5340c896fe29Sbellard } 5341c896fe29Sbellard 5342c896fe29Sbellard /* satisfy the output constraints */ 5343c896fe29Sbellard for (k = 0; k < nb_oargs; k++) { 5344501fb3daSRichard Henderson i = args_ct[k].sort_index; 5345dd186292SRichard Henderson arg = op->args[i]; 5346501fb3daSRichard Henderson arg_ct = &args_ct[i]; 534743439139SRichard Henderson ts = arg_temp(arg); 5348d63e3b6eSRichard Henderson 5349d63e3b6eSRichard Henderson /* ENV should not be modified. */ 5350e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ts)); 5351d63e3b6eSRichard Henderson 535229f5e925SRichard Henderson switch (arg_ct->pair) { 535329f5e925SRichard Henderson case 0: /* not paired */ 5354bc2b17e6SRichard Henderson if (arg_ct->oalias && !const_args[arg_ct->alias_index]) { 53555ff9d6a4Sbellard reg = new_args[arg_ct->alias_index]; 5356bc2b17e6SRichard Henderson } else if (arg_ct->newreg) { 53579be0d080SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->regs, 535882790a87SRichard Henderson i_allocated_regs | o_allocated_regs, 535931fd884bSRichard Henderson output_pref(op, k), ts->indirect_base); 5360c896fe29Sbellard } else { 53619be0d080SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs, 536231fd884bSRichard Henderson output_pref(op, k), ts->indirect_base); 5363c896fe29Sbellard } 536429f5e925SRichard Henderson break; 536529f5e925SRichard Henderson 536629f5e925SRichard Henderson case 1: /* first of pair */ 536729f5e925SRichard Henderson if (arg_ct->oalias) { 536829f5e925SRichard Henderson reg = new_args[arg_ct->alias_index]; 5369ca5bed07SRichard Henderson } else if (arg_ct->newreg) { 5370ca5bed07SRichard Henderson reg = tcg_reg_alloc_pair(s, arg_ct->regs, 5371ca5bed07SRichard Henderson i_allocated_regs | o_allocated_regs, 5372ca5bed07SRichard Henderson output_pref(op, k), 5373ca5bed07SRichard Henderson ts->indirect_base); 5374ca5bed07SRichard Henderson } else { 537529f5e925SRichard Henderson reg = tcg_reg_alloc_pair(s, arg_ct->regs, o_allocated_regs, 5376ca5bed07SRichard Henderson output_pref(op, k), 5377ca5bed07SRichard Henderson ts->indirect_base); 5378ca5bed07SRichard Henderson } 537929f5e925SRichard Henderson break; 538029f5e925SRichard Henderson 538129f5e925SRichard Henderson case 2: /* second of pair */ 538229f5e925SRichard Henderson if (arg_ct->oalias) { 538329f5e925SRichard Henderson reg = new_args[arg_ct->alias_index]; 538429f5e925SRichard Henderson } else { 538529f5e925SRichard Henderson reg = new_args[arg_ct->pair_index] + 1; 538629f5e925SRichard Henderson } 538729f5e925SRichard Henderson break; 538829f5e925SRichard Henderson 538929f5e925SRichard Henderson case 3: /* first of pair, aliasing with a second input */ 539029f5e925SRichard Henderson tcg_debug_assert(!arg_ct->newreg); 539129f5e925SRichard Henderson reg = new_args[arg_ct->pair_index] - 1; 539229f5e925SRichard Henderson break; 539329f5e925SRichard Henderson 539429f5e925SRichard Henderson default: 539529f5e925SRichard Henderson g_assert_not_reached(); 539629f5e925SRichard Henderson } 539782790a87SRichard Henderson tcg_regset_set_reg(o_allocated_regs, reg); 5398098859f1SRichard Henderson set_temp_val_reg(s, ts, reg); 5399c896fe29Sbellard ts->mem_coherent = 0; 5400c896fe29Sbellard new_args[i] = reg; 5401c896fe29Sbellard } 5402e8996ee0Sbellard } 5403c896fe29Sbellard 5404c896fe29Sbellard /* emit instruction */ 5405662cdbcfSRichard Henderson TCGType type = TCGOP_TYPE(op); 5406678155b2SRichard Henderson switch (op->opc) { 54079c6aa274SRichard Henderson case INDEX_op_ext_i32_i64: 54089c6aa274SRichard Henderson tcg_out_exts_i32_i64(s, new_args[0], new_args[1]); 54099c6aa274SRichard Henderson break; 5410b9bfe000SRichard Henderson case INDEX_op_extu_i32_i64: 5411b9bfe000SRichard Henderson tcg_out_extu_i32_i64(s, new_args[0], new_args[1]); 5412b9bfe000SRichard Henderson break; 5413b8b94ac6SRichard Henderson case INDEX_op_extrl_i64_i32: 5414b8b94ac6SRichard Henderson tcg_out_extrl_i64_i32(s, new_args[0], new_args[1]); 5415b8b94ac6SRichard Henderson break; 5416662cdbcfSRichard Henderson 541779602f63SRichard Henderson case INDEX_op_add: 5418c3b920b3SRichard Henderson case INDEX_op_and: 541946f96bffSRichard Henderson case INDEX_op_andc: 54205c0968a7SRichard Henderson case INDEX_op_eqv: 5421d2c3ecadSRichard Henderson case INDEX_op_mul: 5422*c742824dSRichard Henderson case INDEX_op_mulsh: 5423aa28c9efSRichard Henderson case INDEX_op_muluh: 542459379a45SRichard Henderson case INDEX_op_nand: 54253a8c4e9eSRichard Henderson case INDEX_op_nor: 542649bd7514SRichard Henderson case INDEX_op_or: 54276aba25ebSRichard Henderson case INDEX_op_orc: 5428fffd3dc9SRichard Henderson case INDEX_op_xor: 5429662cdbcfSRichard Henderson { 5430662cdbcfSRichard Henderson const TCGOutOpBinary *out = 5431662cdbcfSRichard Henderson container_of(all_outop[op->opc], TCGOutOpBinary, base); 5432662cdbcfSRichard Henderson 5433662cdbcfSRichard Henderson /* Constants should never appear in the first source operand. */ 5434662cdbcfSRichard Henderson tcg_debug_assert(!const_args[1]); 5435662cdbcfSRichard Henderson if (const_args[2]) { 5436662cdbcfSRichard Henderson out->out_rri(s, type, new_args[0], new_args[1], new_args[2]); 5437662cdbcfSRichard Henderson } else { 5438662cdbcfSRichard Henderson out->out_rrr(s, type, new_args[0], new_args[1], new_args[2]); 5439662cdbcfSRichard Henderson } 5440662cdbcfSRichard Henderson } 5441662cdbcfSRichard Henderson break; 5442662cdbcfSRichard Henderson 544360f34f55SRichard Henderson case INDEX_op_sub: 54443f057e24SRichard Henderson { 54453f057e24SRichard Henderson const TCGOutOpSubtract *out = &outop_sub; 54463f057e24SRichard Henderson 54473f057e24SRichard Henderson /* 54483f057e24SRichard Henderson * Constants should never appear in the second source operand. 54493f057e24SRichard Henderson * These are folded to add with negative constant. 54503f057e24SRichard Henderson */ 54513f057e24SRichard Henderson tcg_debug_assert(!const_args[2]); 54523f057e24SRichard Henderson if (const_args[1]) { 54533f057e24SRichard Henderson out->out_rir(s, type, new_args[0], new_args[1], new_args[2]); 54543f057e24SRichard Henderson } else { 54553f057e24SRichard Henderson out->out_rrr(s, type, new_args[0], new_args[1], new_args[2]); 54563f057e24SRichard Henderson } 54573f057e24SRichard Henderson } 54583f057e24SRichard Henderson break; 54593f057e24SRichard Henderson 546069713587SRichard Henderson case INDEX_op_neg: 54615c62d377SRichard Henderson case INDEX_op_not: 5462e126a91cSRichard Henderson { 5463e126a91cSRichard Henderson const TCGOutOpUnary *out = 5464e126a91cSRichard Henderson container_of(all_outop[op->opc], TCGOutOpUnary, base); 5465e126a91cSRichard Henderson 5466e126a91cSRichard Henderson /* Constants should have been folded. */ 5467e126a91cSRichard Henderson tcg_debug_assert(!const_args[1]); 5468e126a91cSRichard Henderson out->out_rr(s, type, new_args[0], new_args[1]); 5469e126a91cSRichard Henderson } 5470e126a91cSRichard Henderson break; 5471e126a91cSRichard Henderson 5472678155b2SRichard Henderson default: 5473d2fd745fSRichard Henderson if (def->flags & TCG_OPF_VECTOR) { 5474662cdbcfSRichard Henderson tcg_out_vec_op(s, op->opc, type - TCG_TYPE_V64, 54754d872218SRichard Henderson TCGOP_VECE(op), new_args, const_args); 5476d2fd745fSRichard Henderson } else { 5477662cdbcfSRichard Henderson tcg_out_op(s, op->opc, type, new_args, const_args); 5478d2fd745fSRichard Henderson } 5479678155b2SRichard Henderson break; 5480678155b2SRichard Henderson } 5481c896fe29Sbellard 5482c896fe29Sbellard /* move the outputs in the correct register if needed */ 5483c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 548443439139SRichard Henderson ts = arg_temp(op->args[i]); 5485d63e3b6eSRichard Henderson 5486d63e3b6eSRichard Henderson /* ENV should not be modified. */ 5487e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ts)); 5488d63e3b6eSRichard Henderson 5489ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) { 549098b4e186SRichard Henderson temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i)); 549159d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) { 5492f8bf00f1SRichard Henderson temp_dead(s, ts); 5493ec7a869dSAurelien Jarno } 5494c896fe29Sbellard } 5495c896fe29Sbellard } 5496c896fe29Sbellard 5497efe86b21SRichard Henderson static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op) 5498efe86b21SRichard Henderson { 5499efe86b21SRichard Henderson const TCGLifeData arg_life = op->life; 5500efe86b21SRichard Henderson TCGTemp *ots, *itsl, *itsh; 55014d872218SRichard Henderson TCGType vtype = TCGOP_TYPE(op); 5502efe86b21SRichard Henderson 5503efe86b21SRichard Henderson /* This opcode is only valid for 32-bit hosts, for 64-bit elements. */ 5504efe86b21SRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 32); 5505efe86b21SRichard Henderson tcg_debug_assert(TCGOP_VECE(op) == MO_64); 5506efe86b21SRichard Henderson 5507efe86b21SRichard Henderson ots = arg_temp(op->args[0]); 5508efe86b21SRichard Henderson itsl = arg_temp(op->args[1]); 5509efe86b21SRichard Henderson itsh = arg_temp(op->args[2]); 5510efe86b21SRichard Henderson 5511efe86b21SRichard Henderson /* ENV should not be modified. */ 5512efe86b21SRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 5513efe86b21SRichard Henderson 5514efe86b21SRichard Henderson /* Allocate the output register now. */ 5515efe86b21SRichard Henderson if (ots->val_type != TEMP_VAL_REG) { 5516efe86b21SRichard Henderson TCGRegSet allocated_regs = s->reserved_regs; 5517501fb3daSRichard Henderson TCGRegSet dup_out_regs = opcode_args_ct(op)[0].regs; 5518098859f1SRichard Henderson TCGReg oreg; 5519efe86b21SRichard Henderson 5520efe86b21SRichard Henderson /* Make sure to not spill the input registers. */ 5521efe86b21SRichard Henderson if (!IS_DEAD_ARG(1) && itsl->val_type == TEMP_VAL_REG) { 5522efe86b21SRichard Henderson tcg_regset_set_reg(allocated_regs, itsl->reg); 5523efe86b21SRichard Henderson } 5524efe86b21SRichard Henderson if (!IS_DEAD_ARG(2) && itsh->val_type == TEMP_VAL_REG) { 5525efe86b21SRichard Henderson tcg_regset_set_reg(allocated_regs, itsh->reg); 5526efe86b21SRichard Henderson } 5527efe86b21SRichard Henderson 5528098859f1SRichard Henderson oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs, 552931fd884bSRichard Henderson output_pref(op, 0), ots->indirect_base); 5530098859f1SRichard Henderson set_temp_val_reg(s, ots, oreg); 5531efe86b21SRichard Henderson } 5532efe86b21SRichard Henderson 5533efe86b21SRichard Henderson /* Promote dup2 of immediates to dupi_vec. */ 5534efe86b21SRichard Henderson if (itsl->val_type == TEMP_VAL_CONST && itsh->val_type == TEMP_VAL_CONST) { 5535efe86b21SRichard Henderson uint64_t val = deposit64(itsl->val, 32, 32, itsh->val); 5536efe86b21SRichard Henderson MemOp vece = MO_64; 5537efe86b21SRichard Henderson 5538efe86b21SRichard Henderson if (val == dup_const(MO_8, val)) { 5539efe86b21SRichard Henderson vece = MO_8; 5540efe86b21SRichard Henderson } else if (val == dup_const(MO_16, val)) { 5541efe86b21SRichard Henderson vece = MO_16; 5542efe86b21SRichard Henderson } else if (val == dup_const(MO_32, val)) { 5543efe86b21SRichard Henderson vece = MO_32; 5544efe86b21SRichard Henderson } 5545efe86b21SRichard Henderson 5546efe86b21SRichard Henderson tcg_out_dupi_vec(s, vtype, vece, ots->reg, val); 5547efe86b21SRichard Henderson goto done; 5548efe86b21SRichard Henderson } 5549efe86b21SRichard Henderson 5550efe86b21SRichard Henderson /* If the two inputs form one 64-bit value, try dupm_vec. */ 5551aef85402SRichard Henderson if (itsl->temp_subindex == HOST_BIG_ENDIAN && 5552aef85402SRichard Henderson itsh->temp_subindex == !HOST_BIG_ENDIAN && 5553aef85402SRichard Henderson itsl == itsh + (HOST_BIG_ENDIAN ? 1 : -1)) { 5554aef85402SRichard Henderson TCGTemp *its = itsl - HOST_BIG_ENDIAN; 5555aef85402SRichard Henderson 5556aef85402SRichard Henderson temp_sync(s, its + 0, s->reserved_regs, 0, 0); 5557aef85402SRichard Henderson temp_sync(s, its + 1, s->reserved_regs, 0, 0); 5558aef85402SRichard Henderson 5559efe86b21SRichard Henderson if (tcg_out_dupm_vec(s, vtype, MO_64, ots->reg, 5560efe86b21SRichard Henderson its->mem_base->reg, its->mem_offset)) { 5561efe86b21SRichard Henderson goto done; 5562efe86b21SRichard Henderson } 5563efe86b21SRichard Henderson } 5564efe86b21SRichard Henderson 5565efe86b21SRichard Henderson /* Fall back to generic expansion. */ 5566efe86b21SRichard Henderson return false; 5567efe86b21SRichard Henderson 5568efe86b21SRichard Henderson done: 556936f5539cSRichard Henderson ots->mem_coherent = 0; 5570efe86b21SRichard Henderson if (IS_DEAD_ARG(1)) { 5571efe86b21SRichard Henderson temp_dead(s, itsl); 5572efe86b21SRichard Henderson } 5573efe86b21SRichard Henderson if (IS_DEAD_ARG(2)) { 5574efe86b21SRichard Henderson temp_dead(s, itsh); 5575efe86b21SRichard Henderson } 5576efe86b21SRichard Henderson if (NEED_SYNC_ARG(0)) { 5577efe86b21SRichard Henderson temp_sync(s, ots, s->reserved_regs, 0, IS_DEAD_ARG(0)); 5578efe86b21SRichard Henderson } else if (IS_DEAD_ARG(0)) { 5579efe86b21SRichard Henderson temp_dead(s, ots); 5580efe86b21SRichard Henderson } 5581efe86b21SRichard Henderson return true; 5582efe86b21SRichard Henderson } 5583efe86b21SRichard Henderson 558439004a71SRichard Henderson static void load_arg_reg(TCGContext *s, TCGReg reg, TCGTemp *ts, 558539004a71SRichard Henderson TCGRegSet allocated_regs) 5586c896fe29Sbellard { 5587c896fe29Sbellard if (ts->val_type == TEMP_VAL_REG) { 5588c896fe29Sbellard if (ts->reg != reg) { 55894250da10SRichard Henderson tcg_reg_free(s, reg, allocated_regs); 559078113e83SRichard Henderson if (!tcg_out_mov(s, ts->type, reg, ts->reg)) { 5591240c08d0SRichard Henderson /* 5592240c08d0SRichard Henderson * Cross register class move not supported. Sync the 5593240c08d0SRichard Henderson * temp back to its slot and load from there. 5594240c08d0SRichard Henderson */ 5595240c08d0SRichard Henderson temp_sync(s, ts, allocated_regs, 0, 0); 5596240c08d0SRichard Henderson tcg_out_ld(s, ts->type, reg, 5597240c08d0SRichard Henderson ts->mem_base->reg, ts->mem_offset); 559878113e83SRichard Henderson } 5599c896fe29Sbellard } 5600c896fe29Sbellard } else { 5601ccb1bb66SRichard Henderson TCGRegSet arg_set = 0; 560240ae5c62SRichard Henderson 56034250da10SRichard Henderson tcg_reg_free(s, reg, allocated_regs); 560440ae5c62SRichard Henderson tcg_regset_set_reg(arg_set, reg); 5605b722452aSRichard Henderson temp_load(s, ts, arg_set, allocated_regs, 0); 5606c896fe29Sbellard } 560739004a71SRichard Henderson } 560840ae5c62SRichard Henderson 5609d78e4a4fSRichard Henderson static void load_arg_stk(TCGContext *s, unsigned arg_slot, TCGTemp *ts, 561039004a71SRichard Henderson TCGRegSet allocated_regs) 561139004a71SRichard Henderson { 561239004a71SRichard Henderson /* 561339004a71SRichard Henderson * When the destination is on the stack, load up the temp and store. 561439004a71SRichard Henderson * If there are many call-saved registers, the temp might live to 561539004a71SRichard Henderson * see another use; otherwise it'll be discarded. 561639004a71SRichard Henderson */ 561739004a71SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], allocated_regs, 0); 561839004a71SRichard Henderson tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, 5619d78e4a4fSRichard Henderson arg_slot_stk_ofs(arg_slot)); 562039004a71SRichard Henderson } 562139004a71SRichard Henderson 562239004a71SRichard Henderson static void load_arg_normal(TCGContext *s, const TCGCallArgumentLoc *l, 562339004a71SRichard Henderson TCGTemp *ts, TCGRegSet *allocated_regs) 562439004a71SRichard Henderson { 5625338b61e9SRichard Henderson if (arg_slot_reg_p(l->arg_slot)) { 562639004a71SRichard Henderson TCGReg reg = tcg_target_call_iarg_regs[l->arg_slot]; 562739004a71SRichard Henderson load_arg_reg(s, reg, ts, *allocated_regs); 562839004a71SRichard Henderson tcg_regset_set_reg(*allocated_regs, reg); 562939004a71SRichard Henderson } else { 5630d78e4a4fSRichard Henderson load_arg_stk(s, l->arg_slot, ts, *allocated_regs); 5631c896fe29Sbellard } 563239cf05d3Sbellard } 5633c896fe29Sbellard 5634d78e4a4fSRichard Henderson static void load_arg_ref(TCGContext *s, unsigned arg_slot, TCGReg ref_base, 5635313bdea8SRichard Henderson intptr_t ref_off, TCGRegSet *allocated_regs) 5636313bdea8SRichard Henderson { 5637313bdea8SRichard Henderson TCGReg reg; 5638313bdea8SRichard Henderson 5639d78e4a4fSRichard Henderson if (arg_slot_reg_p(arg_slot)) { 5640313bdea8SRichard Henderson reg = tcg_target_call_iarg_regs[arg_slot]; 5641313bdea8SRichard Henderson tcg_reg_free(s, reg, *allocated_regs); 5642313bdea8SRichard Henderson tcg_out_addi_ptr(s, reg, ref_base, ref_off); 5643313bdea8SRichard Henderson tcg_regset_set_reg(*allocated_regs, reg); 5644313bdea8SRichard Henderson } else { 5645313bdea8SRichard Henderson reg = tcg_reg_alloc(s, tcg_target_available_regs[TCG_TYPE_PTR], 5646313bdea8SRichard Henderson *allocated_regs, 0, false); 5647313bdea8SRichard Henderson tcg_out_addi_ptr(s, reg, ref_base, ref_off); 5648313bdea8SRichard Henderson tcg_out_st(s, TCG_TYPE_PTR, reg, TCG_REG_CALL_STACK, 5649d78e4a4fSRichard Henderson arg_slot_stk_ofs(arg_slot)); 5650313bdea8SRichard Henderson } 5651313bdea8SRichard Henderson } 5652313bdea8SRichard Henderson 565339004a71SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op) 565439004a71SRichard Henderson { 565539004a71SRichard Henderson const int nb_oargs = TCGOP_CALLO(op); 565639004a71SRichard Henderson const int nb_iargs = TCGOP_CALLI(op); 565739004a71SRichard Henderson const TCGLifeData arg_life = op->life; 565839004a71SRichard Henderson const TCGHelperInfo *info = tcg_call_info(op); 565939004a71SRichard Henderson TCGRegSet allocated_regs = s->reserved_regs; 566039004a71SRichard Henderson int i; 566139004a71SRichard Henderson 566239004a71SRichard Henderson /* 566339004a71SRichard Henderson * Move inputs into place in reverse order, 566439004a71SRichard Henderson * so that we place stacked arguments first. 566539004a71SRichard Henderson */ 566639004a71SRichard Henderson for (i = nb_iargs - 1; i >= 0; --i) { 566739004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i]; 566839004a71SRichard Henderson TCGTemp *ts = arg_temp(op->args[nb_oargs + i]); 566939004a71SRichard Henderson 567039004a71SRichard Henderson switch (loc->kind) { 567139004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 567239004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 567339004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 567439004a71SRichard Henderson load_arg_normal(s, loc, ts, &allocated_regs); 567539004a71SRichard Henderson break; 5676313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF: 5677313bdea8SRichard Henderson load_arg_stk(s, loc->ref_slot, ts, allocated_regs); 5678313bdea8SRichard Henderson load_arg_ref(s, loc->arg_slot, TCG_REG_CALL_STACK, 5679d78e4a4fSRichard Henderson arg_slot_stk_ofs(loc->ref_slot), 5680313bdea8SRichard Henderson &allocated_regs); 5681313bdea8SRichard Henderson break; 5682313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF_N: 5683313bdea8SRichard Henderson load_arg_stk(s, loc->ref_slot, ts, allocated_regs); 5684313bdea8SRichard Henderson break; 568539004a71SRichard Henderson default: 568639004a71SRichard Henderson g_assert_not_reached(); 568739004a71SRichard Henderson } 568839004a71SRichard Henderson } 568939004a71SRichard Henderson 569039004a71SRichard Henderson /* Mark dead temporaries and free the associated registers. */ 5691866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 5692866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) { 569343439139SRichard Henderson temp_dead(s, arg_temp(op->args[i])); 5694c896fe29Sbellard } 5695c896fe29Sbellard } 5696c896fe29Sbellard 569739004a71SRichard Henderson /* Clobber call registers. */ 5698c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) { 5699c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { 5700b3915dbbSRichard Henderson tcg_reg_free(s, i, allocated_regs); 5701c896fe29Sbellard } 5702c896fe29Sbellard } 5703c896fe29Sbellard 570439004a71SRichard Henderson /* 570539004a71SRichard Henderson * Save globals if they might be written by the helper, 570639004a71SRichard Henderson * sync them if they might be read. 570739004a71SRichard Henderson */ 570839004a71SRichard Henderson if (info->flags & TCG_CALL_NO_READ_GLOBALS) { 570978505279SAurelien Jarno /* Nothing to do */ 571039004a71SRichard Henderson } else if (info->flags & TCG_CALL_NO_WRITE_GLOBALS) { 571178505279SAurelien Jarno sync_globals(s, allocated_regs); 571278505279SAurelien Jarno } else { 5713e8996ee0Sbellard save_globals(s, allocated_regs); 5714b9c18f56Saurel32 } 5715c896fe29Sbellard 5716313bdea8SRichard Henderson /* 5717313bdea8SRichard Henderson * If the ABI passes a pointer to the returned struct as the first 5718313bdea8SRichard Henderson * argument, load that now. Pass a pointer to the output home slot. 5719313bdea8SRichard Henderson */ 5720313bdea8SRichard Henderson if (info->out_kind == TCG_CALL_RET_BY_REF) { 5721313bdea8SRichard Henderson TCGTemp *ts = arg_temp(op->args[0]); 5722313bdea8SRichard Henderson 5723313bdea8SRichard Henderson if (!ts->mem_allocated) { 5724313bdea8SRichard Henderson temp_allocate_frame(s, ts); 5725313bdea8SRichard Henderson } 5726313bdea8SRichard Henderson load_arg_ref(s, 0, ts->mem_base->reg, ts->mem_offset, &allocated_regs); 5727313bdea8SRichard Henderson } 5728313bdea8SRichard Henderson 5729cee44b03SRichard Henderson tcg_out_call(s, tcg_call_func(op), info); 5730c896fe29Sbellard 573139004a71SRichard Henderson /* Assign output registers and emit moves if needed. */ 573239004a71SRichard Henderson switch (info->out_kind) { 573339004a71SRichard Henderson case TCG_CALL_RET_NORMAL: 5734c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 573539004a71SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]); 57365e3d0c19SRichard Henderson TCGReg reg = tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, i); 5737d63e3b6eSRichard Henderson 5738d63e3b6eSRichard Henderson /* ENV should not be modified. */ 5739e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ts)); 5740d63e3b6eSRichard Henderson 5741098859f1SRichard Henderson set_temp_val_reg(s, ts, reg); 5742c896fe29Sbellard ts->mem_coherent = 0; 574339004a71SRichard Henderson } 574439004a71SRichard Henderson break; 5745313bdea8SRichard Henderson 5746c6556aa0SRichard Henderson case TCG_CALL_RET_BY_VEC: 5747c6556aa0SRichard Henderson { 5748c6556aa0SRichard Henderson TCGTemp *ts = arg_temp(op->args[0]); 5749c6556aa0SRichard Henderson 5750c6556aa0SRichard Henderson tcg_debug_assert(ts->base_type == TCG_TYPE_I128); 5751c6556aa0SRichard Henderson tcg_debug_assert(ts->temp_subindex == 0); 5752c6556aa0SRichard Henderson if (!ts->mem_allocated) { 5753c6556aa0SRichard Henderson temp_allocate_frame(s, ts); 5754c6556aa0SRichard Henderson } 5755c6556aa0SRichard Henderson tcg_out_st(s, TCG_TYPE_V128, 5756c6556aa0SRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0), 5757c6556aa0SRichard Henderson ts->mem_base->reg, ts->mem_offset); 5758c6556aa0SRichard Henderson } 5759c6556aa0SRichard Henderson /* fall through to mark all parts in memory */ 5760c6556aa0SRichard Henderson 5761313bdea8SRichard Henderson case TCG_CALL_RET_BY_REF: 5762313bdea8SRichard Henderson /* The callee has performed a write through the reference. */ 5763313bdea8SRichard Henderson for (i = 0; i < nb_oargs; i++) { 5764313bdea8SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]); 5765313bdea8SRichard Henderson ts->val_type = TEMP_VAL_MEM; 5766313bdea8SRichard Henderson } 5767313bdea8SRichard Henderson break; 5768313bdea8SRichard Henderson 576939004a71SRichard Henderson default: 577039004a71SRichard Henderson g_assert_not_reached(); 577139004a71SRichard Henderson } 577239004a71SRichard Henderson 577339004a71SRichard Henderson /* Flush or discard output registers as needed. */ 577439004a71SRichard Henderson for (i = 0; i < nb_oargs; i++) { 577539004a71SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]); 5776ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) { 577739004a71SRichard Henderson temp_sync(s, ts, s->reserved_regs, 0, IS_DEAD_ARG(i)); 577859d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) { 5779f8bf00f1SRichard Henderson temp_dead(s, ts); 5780c896fe29Sbellard } 5781c896fe29Sbellard } 57828c11ad25SAurelien Jarno } 5783c896fe29Sbellard 5784e63b8a29SRichard Henderson /** 5785e63b8a29SRichard Henderson * atom_and_align_for_opc: 5786e63b8a29SRichard Henderson * @s: tcg context 5787e63b8a29SRichard Henderson * @opc: memory operation code 5788e63b8a29SRichard Henderson * @host_atom: MO_ATOM_{IFALIGN,WITHIN16,SUBALIGN} for host operations 5789e63b8a29SRichard Henderson * @allow_two_ops: true if we are prepared to issue two operations 5790e63b8a29SRichard Henderson * 5791e63b8a29SRichard Henderson * Return the alignment and atomicity to use for the inline fast path 5792e63b8a29SRichard Henderson * for the given memory operation. The alignment may be larger than 5793e63b8a29SRichard Henderson * that specified in @opc, and the correct alignment will be diagnosed 5794e63b8a29SRichard Henderson * by the slow path helper. 5795e63b8a29SRichard Henderson * 5796e63b8a29SRichard Henderson * If @allow_two_ops, the host is prepared to test for 2x alignment, 5797e63b8a29SRichard Henderson * and issue two loads or stores for subalignment. 5798e63b8a29SRichard Henderson */ 5799e63b8a29SRichard Henderson static TCGAtomAlign atom_and_align_for_opc(TCGContext *s, MemOp opc, 5800e63b8a29SRichard Henderson MemOp host_atom, bool allow_two_ops) 5801e63b8a29SRichard Henderson { 5802c5809eeeSRichard Henderson MemOp align = memop_alignment_bits(opc); 5803e63b8a29SRichard Henderson MemOp size = opc & MO_SIZE; 5804e63b8a29SRichard Henderson MemOp half = size ? size - 1 : 0; 5805cbb14556SRichard Henderson MemOp atom = opc & MO_ATOM_MASK; 5806e63b8a29SRichard Henderson MemOp atmax; 5807e63b8a29SRichard Henderson 5808e63b8a29SRichard Henderson switch (atom) { 5809e63b8a29SRichard Henderson case MO_ATOM_NONE: 5810e63b8a29SRichard Henderson /* The operation requires no specific atomicity. */ 5811e63b8a29SRichard Henderson atmax = MO_8; 5812e63b8a29SRichard Henderson break; 5813e63b8a29SRichard Henderson 5814e63b8a29SRichard Henderson case MO_ATOM_IFALIGN: 5815e63b8a29SRichard Henderson atmax = size; 5816e63b8a29SRichard Henderson break; 5817e63b8a29SRichard Henderson 5818e63b8a29SRichard Henderson case MO_ATOM_IFALIGN_PAIR: 5819e63b8a29SRichard Henderson atmax = half; 5820e63b8a29SRichard Henderson break; 5821e63b8a29SRichard Henderson 5822e63b8a29SRichard Henderson case MO_ATOM_WITHIN16: 5823e63b8a29SRichard Henderson atmax = size; 5824e63b8a29SRichard Henderson if (size == MO_128) { 5825e63b8a29SRichard Henderson /* Misalignment implies !within16, and therefore no atomicity. */ 5826e63b8a29SRichard Henderson } else if (host_atom != MO_ATOM_WITHIN16) { 5827e63b8a29SRichard Henderson /* The host does not implement within16, so require alignment. */ 5828e63b8a29SRichard Henderson align = MAX(align, size); 5829e63b8a29SRichard Henderson } 5830e63b8a29SRichard Henderson break; 5831e63b8a29SRichard Henderson 5832e63b8a29SRichard Henderson case MO_ATOM_WITHIN16_PAIR: 5833e63b8a29SRichard Henderson atmax = size; 5834e63b8a29SRichard Henderson /* 5835e63b8a29SRichard Henderson * Misalignment implies !within16, and therefore half atomicity. 5836e63b8a29SRichard Henderson * Any host prepared for two operations can implement this with 5837e63b8a29SRichard Henderson * half alignment. 5838e63b8a29SRichard Henderson */ 5839e63b8a29SRichard Henderson if (host_atom != MO_ATOM_WITHIN16 && allow_two_ops) { 5840e63b8a29SRichard Henderson align = MAX(align, half); 5841e63b8a29SRichard Henderson } 5842e63b8a29SRichard Henderson break; 5843e63b8a29SRichard Henderson 5844e63b8a29SRichard Henderson case MO_ATOM_SUBALIGN: 5845e63b8a29SRichard Henderson atmax = size; 5846e63b8a29SRichard Henderson if (host_atom != MO_ATOM_SUBALIGN) { 5847e63b8a29SRichard Henderson /* If unaligned but not odd, there are subobjects up to half. */ 5848e63b8a29SRichard Henderson if (allow_two_ops) { 5849e63b8a29SRichard Henderson align = MAX(align, half); 5850e63b8a29SRichard Henderson } else { 5851e63b8a29SRichard Henderson align = MAX(align, size); 5852e63b8a29SRichard Henderson } 5853e63b8a29SRichard Henderson } 5854e63b8a29SRichard Henderson break; 5855e63b8a29SRichard Henderson 5856e63b8a29SRichard Henderson default: 5857e63b8a29SRichard Henderson g_assert_not_reached(); 5858e63b8a29SRichard Henderson } 5859e63b8a29SRichard Henderson 5860e63b8a29SRichard Henderson return (TCGAtomAlign){ .atom = atmax, .align = align }; 5861e63b8a29SRichard Henderson } 5862e63b8a29SRichard Henderson 58638429a1caSRichard Henderson /* 58648429a1caSRichard Henderson * Similarly for qemu_ld/st slow path helpers. 58658429a1caSRichard Henderson * We must re-implement tcg_gen_callN and tcg_reg_alloc_call simultaneously, 58668429a1caSRichard Henderson * using only the provided backend tcg_out_* functions. 58678429a1caSRichard Henderson */ 58688429a1caSRichard Henderson 58698429a1caSRichard Henderson static int tcg_out_helper_stk_ofs(TCGType type, unsigned slot) 58708429a1caSRichard Henderson { 58718429a1caSRichard Henderson int ofs = arg_slot_stk_ofs(slot); 58728429a1caSRichard Henderson 58738429a1caSRichard Henderson /* 58748429a1caSRichard Henderson * Each stack slot is TCG_TARGET_LONG_BITS. If the host does not 58758429a1caSRichard Henderson * require extension to uint64_t, adjust the address for uint32_t. 58768429a1caSRichard Henderson */ 58778429a1caSRichard Henderson if (HOST_BIG_ENDIAN && 58788429a1caSRichard Henderson TCG_TARGET_REG_BITS == 64 && 58798429a1caSRichard Henderson type == TCG_TYPE_I32) { 58808429a1caSRichard Henderson ofs += 4; 58818429a1caSRichard Henderson } 58828429a1caSRichard Henderson return ofs; 58838429a1caSRichard Henderson } 58848429a1caSRichard Henderson 58858d314041SRichard Henderson static void tcg_out_helper_load_slots(TCGContext *s, 58868429a1caSRichard Henderson unsigned nmov, TCGMovExtend *mov, 58872462e30eSRichard Henderson const TCGLdstHelperParam *parm) 58888429a1caSRichard Henderson { 58898d314041SRichard Henderson unsigned i; 58902462e30eSRichard Henderson TCGReg dst3; 58912462e30eSRichard Henderson 58928d314041SRichard Henderson /* 58938d314041SRichard Henderson * Start from the end, storing to the stack first. 58948d314041SRichard Henderson * This frees those registers, so we need not consider overlap. 58958d314041SRichard Henderson */ 58968d314041SRichard Henderson for (i = nmov; i-- > 0; ) { 58978d314041SRichard Henderson unsigned slot = mov[i].dst; 58988d314041SRichard Henderson 58998d314041SRichard Henderson if (arg_slot_reg_p(slot)) { 59008d314041SRichard Henderson goto found_reg; 59018d314041SRichard Henderson } 59028d314041SRichard Henderson 59038d314041SRichard Henderson TCGReg src = mov[i].src; 59048d314041SRichard Henderson TCGType dst_type = mov[i].dst_type; 59058d314041SRichard Henderson MemOp dst_mo = dst_type == TCG_TYPE_I32 ? MO_32 : MO_64; 59068d314041SRichard Henderson 59078d314041SRichard Henderson /* The argument is going onto the stack; extend into scratch. */ 59088d314041SRichard Henderson if ((mov[i].src_ext & MO_SIZE) != dst_mo) { 59098d314041SRichard Henderson tcg_debug_assert(parm->ntmp != 0); 59108d314041SRichard Henderson mov[i].dst = src = parm->tmp[0]; 59118d314041SRichard Henderson tcg_out_movext1(s, &mov[i]); 59128d314041SRichard Henderson } 59138d314041SRichard Henderson 59148d314041SRichard Henderson tcg_out_st(s, dst_type, src, TCG_REG_CALL_STACK, 59158d314041SRichard Henderson tcg_out_helper_stk_ofs(dst_type, slot)); 59168d314041SRichard Henderson } 59178d314041SRichard Henderson return; 59188d314041SRichard Henderson 59198d314041SRichard Henderson found_reg: 59208d314041SRichard Henderson /* 59218d314041SRichard Henderson * The remaining arguments are in registers. 59228d314041SRichard Henderson * Convert slot numbers to argument registers. 59238d314041SRichard Henderson */ 59248d314041SRichard Henderson nmov = i + 1; 59258d314041SRichard Henderson for (i = 0; i < nmov; ++i) { 59268d314041SRichard Henderson mov[i].dst = tcg_target_call_iarg_regs[mov[i].dst]; 59278d314041SRichard Henderson } 59288d314041SRichard Henderson 59298429a1caSRichard Henderson switch (nmov) { 59302462e30eSRichard Henderson case 4: 59318429a1caSRichard Henderson /* The backend must have provided enough temps for the worst case. */ 59322462e30eSRichard Henderson tcg_debug_assert(parm->ntmp >= 2); 59338429a1caSRichard Henderson 59342462e30eSRichard Henderson dst3 = mov[3].dst; 59352462e30eSRichard Henderson for (unsigned j = 0; j < 3; ++j) { 59362462e30eSRichard Henderson if (dst3 == mov[j].src) { 59378429a1caSRichard Henderson /* 59382462e30eSRichard Henderson * Conflict. Copy the source to a temporary, perform the 59392462e30eSRichard Henderson * remaining moves, then the extension from our scratch 59402462e30eSRichard Henderson * on the way out. 59418429a1caSRichard Henderson */ 59422462e30eSRichard Henderson TCGReg scratch = parm->tmp[1]; 59438429a1caSRichard Henderson 59442462e30eSRichard Henderson tcg_out_mov(s, mov[3].src_type, scratch, mov[3].src); 59452462e30eSRichard Henderson tcg_out_movext3(s, mov, mov + 1, mov + 2, parm->tmp[0]); 59462462e30eSRichard Henderson tcg_out_movext1_new_src(s, &mov[3], scratch); 59472462e30eSRichard Henderson break; 59488429a1caSRichard Henderson } 59498429a1caSRichard Henderson } 59508429a1caSRichard Henderson 59518429a1caSRichard Henderson /* No conflicts: perform this move and continue. */ 59522462e30eSRichard Henderson tcg_out_movext1(s, &mov[3]); 59532462e30eSRichard Henderson /* fall through */ 59548429a1caSRichard Henderson 59552462e30eSRichard Henderson case 3: 59562462e30eSRichard Henderson tcg_out_movext3(s, mov, mov + 1, mov + 2, 59572462e30eSRichard Henderson parm->ntmp ? parm->tmp[0] : -1); 59582462e30eSRichard Henderson break; 59598429a1caSRichard Henderson case 2: 59602462e30eSRichard Henderson tcg_out_movext2(s, mov, mov + 1, 59612462e30eSRichard Henderson parm->ntmp ? parm->tmp[0] : -1); 59622462e30eSRichard Henderson break; 59638429a1caSRichard Henderson case 1: 59648429a1caSRichard Henderson tcg_out_movext1(s, mov); 59652462e30eSRichard Henderson break; 59662462e30eSRichard Henderson default: 59678429a1caSRichard Henderson g_assert_not_reached(); 59688429a1caSRichard Henderson } 59698429a1caSRichard Henderson } 59708429a1caSRichard Henderson 59718429a1caSRichard Henderson static void tcg_out_helper_load_imm(TCGContext *s, unsigned slot, 59728429a1caSRichard Henderson TCGType type, tcg_target_long imm, 59738429a1caSRichard Henderson const TCGLdstHelperParam *parm) 59748429a1caSRichard Henderson { 59758429a1caSRichard Henderson if (arg_slot_reg_p(slot)) { 59768429a1caSRichard Henderson tcg_out_movi(s, type, tcg_target_call_iarg_regs[slot], imm); 59778429a1caSRichard Henderson } else { 59788429a1caSRichard Henderson int ofs = tcg_out_helper_stk_ofs(type, slot); 59798429a1caSRichard Henderson if (!tcg_out_sti(s, type, imm, TCG_REG_CALL_STACK, ofs)) { 59808429a1caSRichard Henderson tcg_debug_assert(parm->ntmp != 0); 59818429a1caSRichard Henderson tcg_out_movi(s, type, parm->tmp[0], imm); 59828429a1caSRichard Henderson tcg_out_st(s, type, parm->tmp[0], TCG_REG_CALL_STACK, ofs); 59838429a1caSRichard Henderson } 59848429a1caSRichard Henderson } 59858429a1caSRichard Henderson } 59868429a1caSRichard Henderson 59878429a1caSRichard Henderson static void tcg_out_helper_load_common_args(TCGContext *s, 59888429a1caSRichard Henderson const TCGLabelQemuLdst *ldst, 59898429a1caSRichard Henderson const TCGLdstHelperParam *parm, 59908429a1caSRichard Henderson const TCGHelperInfo *info, 59918429a1caSRichard Henderson unsigned next_arg) 59928429a1caSRichard Henderson { 59938429a1caSRichard Henderson TCGMovExtend ptr_mov = { 59948429a1caSRichard Henderson .dst_type = TCG_TYPE_PTR, 59958429a1caSRichard Henderson .src_type = TCG_TYPE_PTR, 59968429a1caSRichard Henderson .src_ext = sizeof(void *) == 4 ? MO_32 : MO_64 59978429a1caSRichard Henderson }; 59988429a1caSRichard Henderson const TCGCallArgumentLoc *loc = &info->in[0]; 59998429a1caSRichard Henderson TCGType type; 60008429a1caSRichard Henderson unsigned slot; 60018429a1caSRichard Henderson tcg_target_ulong imm; 60028429a1caSRichard Henderson 60038429a1caSRichard Henderson /* 60048429a1caSRichard Henderson * Handle env, which is always first. 60058429a1caSRichard Henderson */ 60068429a1caSRichard Henderson ptr_mov.dst = loc->arg_slot; 60078429a1caSRichard Henderson ptr_mov.src = TCG_AREG0; 60088429a1caSRichard Henderson tcg_out_helper_load_slots(s, 1, &ptr_mov, parm); 60098429a1caSRichard Henderson 60108429a1caSRichard Henderson /* 60118429a1caSRichard Henderson * Handle oi. 60128429a1caSRichard Henderson */ 60138429a1caSRichard Henderson imm = ldst->oi; 60148429a1caSRichard Henderson loc = &info->in[next_arg]; 60158429a1caSRichard Henderson type = TCG_TYPE_I32; 60168429a1caSRichard Henderson switch (loc->kind) { 60178429a1caSRichard Henderson case TCG_CALL_ARG_NORMAL: 60188429a1caSRichard Henderson break; 60198429a1caSRichard Henderson case TCG_CALL_ARG_EXTEND_U: 60208429a1caSRichard Henderson case TCG_CALL_ARG_EXTEND_S: 60218429a1caSRichard Henderson /* No extension required for MemOpIdx. */ 60228429a1caSRichard Henderson tcg_debug_assert(imm <= INT32_MAX); 60238429a1caSRichard Henderson type = TCG_TYPE_REG; 60248429a1caSRichard Henderson break; 60258429a1caSRichard Henderson default: 60268429a1caSRichard Henderson g_assert_not_reached(); 60278429a1caSRichard Henderson } 60288429a1caSRichard Henderson tcg_out_helper_load_imm(s, loc->arg_slot, type, imm, parm); 60298429a1caSRichard Henderson next_arg++; 60308429a1caSRichard Henderson 60318429a1caSRichard Henderson /* 60328429a1caSRichard Henderson * Handle ra. 60338429a1caSRichard Henderson */ 60348429a1caSRichard Henderson loc = &info->in[next_arg]; 60358429a1caSRichard Henderson slot = loc->arg_slot; 60368429a1caSRichard Henderson if (parm->ra_gen) { 60378429a1caSRichard Henderson int arg_reg = -1; 60388429a1caSRichard Henderson TCGReg ra_reg; 60398429a1caSRichard Henderson 60408429a1caSRichard Henderson if (arg_slot_reg_p(slot)) { 60418429a1caSRichard Henderson arg_reg = tcg_target_call_iarg_regs[slot]; 60428429a1caSRichard Henderson } 60438429a1caSRichard Henderson ra_reg = parm->ra_gen(s, ldst, arg_reg); 60448429a1caSRichard Henderson 60458429a1caSRichard Henderson ptr_mov.dst = slot; 60468429a1caSRichard Henderson ptr_mov.src = ra_reg; 60478429a1caSRichard Henderson tcg_out_helper_load_slots(s, 1, &ptr_mov, parm); 60488429a1caSRichard Henderson } else { 60498429a1caSRichard Henderson imm = (uintptr_t)ldst->raddr; 60508429a1caSRichard Henderson tcg_out_helper_load_imm(s, slot, TCG_TYPE_PTR, imm, parm); 60518429a1caSRichard Henderson } 60528429a1caSRichard Henderson } 60538429a1caSRichard Henderson 60548429a1caSRichard Henderson static unsigned tcg_out_helper_add_mov(TCGMovExtend *mov, 60558429a1caSRichard Henderson const TCGCallArgumentLoc *loc, 60568429a1caSRichard Henderson TCGType dst_type, TCGType src_type, 60578429a1caSRichard Henderson TCGReg lo, TCGReg hi) 60588429a1caSRichard Henderson { 6059ebebea53SRichard Henderson MemOp reg_mo; 6060ebebea53SRichard Henderson 60618429a1caSRichard Henderson if (dst_type <= TCG_TYPE_REG) { 60628429a1caSRichard Henderson MemOp src_ext; 60638429a1caSRichard Henderson 60648429a1caSRichard Henderson switch (loc->kind) { 60658429a1caSRichard Henderson case TCG_CALL_ARG_NORMAL: 60668429a1caSRichard Henderson src_ext = src_type == TCG_TYPE_I32 ? MO_32 : MO_64; 60678429a1caSRichard Henderson break; 60688429a1caSRichard Henderson case TCG_CALL_ARG_EXTEND_U: 60698429a1caSRichard Henderson dst_type = TCG_TYPE_REG; 60708429a1caSRichard Henderson src_ext = MO_UL; 60718429a1caSRichard Henderson break; 60728429a1caSRichard Henderson case TCG_CALL_ARG_EXTEND_S: 60738429a1caSRichard Henderson dst_type = TCG_TYPE_REG; 60748429a1caSRichard Henderson src_ext = MO_SL; 60758429a1caSRichard Henderson break; 60768429a1caSRichard Henderson default: 60778429a1caSRichard Henderson g_assert_not_reached(); 60788429a1caSRichard Henderson } 60798429a1caSRichard Henderson 60808429a1caSRichard Henderson mov[0].dst = loc->arg_slot; 60818429a1caSRichard Henderson mov[0].dst_type = dst_type; 60828429a1caSRichard Henderson mov[0].src = lo; 60838429a1caSRichard Henderson mov[0].src_type = src_type; 60848429a1caSRichard Henderson mov[0].src_ext = src_ext; 60858429a1caSRichard Henderson return 1; 60868429a1caSRichard Henderson } 60878429a1caSRichard Henderson 6088ebebea53SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 6089ebebea53SRichard Henderson assert(dst_type == TCG_TYPE_I64); 6090ebebea53SRichard Henderson reg_mo = MO_32; 6091ebebea53SRichard Henderson } else { 6092ebebea53SRichard Henderson assert(dst_type == TCG_TYPE_I128); 6093ebebea53SRichard Henderson reg_mo = MO_64; 6094ebebea53SRichard Henderson } 60958429a1caSRichard Henderson 60968429a1caSRichard Henderson mov[0].dst = loc[HOST_BIG_ENDIAN].arg_slot; 60978429a1caSRichard Henderson mov[0].src = lo; 6098ebebea53SRichard Henderson mov[0].dst_type = TCG_TYPE_REG; 6099ebebea53SRichard Henderson mov[0].src_type = TCG_TYPE_REG; 6100ebebea53SRichard Henderson mov[0].src_ext = reg_mo; 61018429a1caSRichard Henderson 61028429a1caSRichard Henderson mov[1].dst = loc[!HOST_BIG_ENDIAN].arg_slot; 61038429a1caSRichard Henderson mov[1].src = hi; 6104ebebea53SRichard Henderson mov[1].dst_type = TCG_TYPE_REG; 6105ebebea53SRichard Henderson mov[1].src_type = TCG_TYPE_REG; 6106ebebea53SRichard Henderson mov[1].src_ext = reg_mo; 61078429a1caSRichard Henderson 61088429a1caSRichard Henderson return 2; 61098429a1caSRichard Henderson } 61108429a1caSRichard Henderson 61118429a1caSRichard Henderson static void tcg_out_ld_helper_args(TCGContext *s, const TCGLabelQemuLdst *ldst, 61128429a1caSRichard Henderson const TCGLdstHelperParam *parm) 61138429a1caSRichard Henderson { 61148429a1caSRichard Henderson const TCGHelperInfo *info; 61158429a1caSRichard Henderson const TCGCallArgumentLoc *loc; 61168429a1caSRichard Henderson TCGMovExtend mov[2]; 61178429a1caSRichard Henderson unsigned next_arg, nmov; 61188429a1caSRichard Henderson MemOp mop = get_memop(ldst->oi); 61198429a1caSRichard Henderson 61208429a1caSRichard Henderson switch (mop & MO_SIZE) { 61218429a1caSRichard Henderson case MO_8: 61228429a1caSRichard Henderson case MO_16: 61238429a1caSRichard Henderson case MO_32: 61248429a1caSRichard Henderson info = &info_helper_ld32_mmu; 61258429a1caSRichard Henderson break; 61268429a1caSRichard Henderson case MO_64: 61278429a1caSRichard Henderson info = &info_helper_ld64_mmu; 61288429a1caSRichard Henderson break; 6129ebebea53SRichard Henderson case MO_128: 6130ebebea53SRichard Henderson info = &info_helper_ld128_mmu; 6131ebebea53SRichard Henderson break; 61328429a1caSRichard Henderson default: 61338429a1caSRichard Henderson g_assert_not_reached(); 61348429a1caSRichard Henderson } 61358429a1caSRichard Henderson 61368429a1caSRichard Henderson /* Defer env argument. */ 61378429a1caSRichard Henderson next_arg = 1; 61388429a1caSRichard Henderson 61398429a1caSRichard Henderson loc = &info->in[next_arg]; 6140c31e5fa4SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && s->addr_type == TCG_TYPE_I32) { 614124e46e6cSRichard Henderson /* 614224e46e6cSRichard Henderson * 32-bit host with 32-bit guest: zero-extend the guest address 614324e46e6cSRichard Henderson * to 64-bits for the helper by storing the low part, then 614424e46e6cSRichard Henderson * load a zero for the high part. 614524e46e6cSRichard Henderson */ 614624e46e6cSRichard Henderson tcg_out_helper_add_mov(mov, loc + HOST_BIG_ENDIAN, 614724e46e6cSRichard Henderson TCG_TYPE_I32, TCG_TYPE_I32, 61480cd38379SRichard Henderson ldst->addr_reg, -1); 614924e46e6cSRichard Henderson tcg_out_helper_load_slots(s, 1, mov, parm); 615024e46e6cSRichard Henderson 615124e46e6cSRichard Henderson tcg_out_helper_load_imm(s, loc[!HOST_BIG_ENDIAN].arg_slot, 615224e46e6cSRichard Henderson TCG_TYPE_I32, 0, parm); 615324e46e6cSRichard Henderson next_arg += 2; 6154c31e5fa4SRichard Henderson } else { 6155c31e5fa4SRichard Henderson nmov = tcg_out_helper_add_mov(mov, loc, TCG_TYPE_I64, s->addr_type, 61560cd38379SRichard Henderson ldst->addr_reg, -1); 6157c31e5fa4SRichard Henderson tcg_out_helper_load_slots(s, nmov, mov, parm); 6158c31e5fa4SRichard Henderson next_arg += nmov; 615924e46e6cSRichard Henderson } 61608429a1caSRichard Henderson 6161ebebea53SRichard Henderson switch (info->out_kind) { 6162ebebea53SRichard Henderson case TCG_CALL_RET_NORMAL: 6163ebebea53SRichard Henderson case TCG_CALL_RET_BY_VEC: 6164ebebea53SRichard Henderson break; 6165ebebea53SRichard Henderson case TCG_CALL_RET_BY_REF: 6166ebebea53SRichard Henderson /* 6167ebebea53SRichard Henderson * The return reference is in the first argument slot. 6168ebebea53SRichard Henderson * We need memory in which to return: re-use the top of stack. 6169ebebea53SRichard Henderson */ 6170ebebea53SRichard Henderson { 6171ebebea53SRichard Henderson int ofs_slot0 = TCG_TARGET_CALL_STACK_OFFSET; 6172ebebea53SRichard Henderson 6173ebebea53SRichard Henderson if (arg_slot_reg_p(0)) { 6174ebebea53SRichard Henderson tcg_out_addi_ptr(s, tcg_target_call_iarg_regs[0], 6175ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0); 6176ebebea53SRichard Henderson } else { 6177ebebea53SRichard Henderson tcg_debug_assert(parm->ntmp != 0); 6178ebebea53SRichard Henderson tcg_out_addi_ptr(s, parm->tmp[0], 6179ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0); 6180ebebea53SRichard Henderson tcg_out_st(s, TCG_TYPE_PTR, parm->tmp[0], 6181ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0); 6182ebebea53SRichard Henderson } 6183ebebea53SRichard Henderson } 6184ebebea53SRichard Henderson break; 6185ebebea53SRichard Henderson default: 6186ebebea53SRichard Henderson g_assert_not_reached(); 6187ebebea53SRichard Henderson } 61888429a1caSRichard Henderson 61898429a1caSRichard Henderson tcg_out_helper_load_common_args(s, ldst, parm, info, next_arg); 61908429a1caSRichard Henderson } 61918429a1caSRichard Henderson 61928429a1caSRichard Henderson static void tcg_out_ld_helper_ret(TCGContext *s, const TCGLabelQemuLdst *ldst, 61938429a1caSRichard Henderson bool load_sign, 61948429a1caSRichard Henderson const TCGLdstHelperParam *parm) 61958429a1caSRichard Henderson { 61968429a1caSRichard Henderson MemOp mop = get_memop(ldst->oi); 6197ebebea53SRichard Henderson TCGMovExtend mov[2]; 6198ebebea53SRichard Henderson int ofs_slot0; 61998429a1caSRichard Henderson 6200ebebea53SRichard Henderson switch (ldst->type) { 6201ebebea53SRichard Henderson case TCG_TYPE_I64: 6202ebebea53SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 6203ebebea53SRichard Henderson break; 6204ebebea53SRichard Henderson } 6205ebebea53SRichard Henderson /* fall through */ 6206ebebea53SRichard Henderson 6207ebebea53SRichard Henderson case TCG_TYPE_I32: 62088429a1caSRichard Henderson mov[0].dst = ldst->datalo_reg; 62098429a1caSRichard Henderson mov[0].src = tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, 0); 62108429a1caSRichard Henderson mov[0].dst_type = ldst->type; 62118429a1caSRichard Henderson mov[0].src_type = TCG_TYPE_REG; 62128429a1caSRichard Henderson 62138429a1caSRichard Henderson /* 62148429a1caSRichard Henderson * If load_sign, then we allowed the helper to perform the 62158429a1caSRichard Henderson * appropriate sign extension to tcg_target_ulong, and all 62168429a1caSRichard Henderson * we need now is a plain move. 62178429a1caSRichard Henderson * 62188429a1caSRichard Henderson * If they do not, then we expect the relevant extension 62198429a1caSRichard Henderson * instruction to be no more expensive than a move, and 62208429a1caSRichard Henderson * we thus save the icache etc by only using one of two 62218429a1caSRichard Henderson * helper functions. 62228429a1caSRichard Henderson */ 62238429a1caSRichard Henderson if (load_sign || !(mop & MO_SIGN)) { 62248429a1caSRichard Henderson if (TCG_TARGET_REG_BITS == 32 || ldst->type == TCG_TYPE_I32) { 62258429a1caSRichard Henderson mov[0].src_ext = MO_32; 62268429a1caSRichard Henderson } else { 62278429a1caSRichard Henderson mov[0].src_ext = MO_64; 62288429a1caSRichard Henderson } 62298429a1caSRichard Henderson } else { 62308429a1caSRichard Henderson mov[0].src_ext = mop & MO_SSIZE; 62318429a1caSRichard Henderson } 62328429a1caSRichard Henderson tcg_out_movext1(s, mov); 6233ebebea53SRichard Henderson return; 6234ebebea53SRichard Henderson 6235ebebea53SRichard Henderson case TCG_TYPE_I128: 6236ebebea53SRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 64); 6237ebebea53SRichard Henderson ofs_slot0 = TCG_TARGET_CALL_STACK_OFFSET; 6238ebebea53SRichard Henderson switch (TCG_TARGET_CALL_RET_I128) { 6239ebebea53SRichard Henderson case TCG_CALL_RET_NORMAL: 6240ebebea53SRichard Henderson break; 6241ebebea53SRichard Henderson case TCG_CALL_RET_BY_VEC: 6242ebebea53SRichard Henderson tcg_out_st(s, TCG_TYPE_V128, 6243ebebea53SRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0), 6244ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0); 6245ebebea53SRichard Henderson /* fall through */ 6246ebebea53SRichard Henderson case TCG_CALL_RET_BY_REF: 6247ebebea53SRichard Henderson tcg_out_ld(s, TCG_TYPE_I64, ldst->datalo_reg, 6248ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0 + 8 * HOST_BIG_ENDIAN); 6249ebebea53SRichard Henderson tcg_out_ld(s, TCG_TYPE_I64, ldst->datahi_reg, 6250ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0 + 8 * !HOST_BIG_ENDIAN); 6251ebebea53SRichard Henderson return; 6252ebebea53SRichard Henderson default: 6253ebebea53SRichard Henderson g_assert_not_reached(); 6254ebebea53SRichard Henderson } 6255ebebea53SRichard Henderson break; 6256ebebea53SRichard Henderson 6257ebebea53SRichard Henderson default: 6258ebebea53SRichard Henderson g_assert_not_reached(); 6259ebebea53SRichard Henderson } 62608429a1caSRichard Henderson 62618429a1caSRichard Henderson mov[0].dst = ldst->datalo_reg; 62628429a1caSRichard Henderson mov[0].src = 62638429a1caSRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, HOST_BIG_ENDIAN); 6264723d3a27SRichard Henderson mov[0].dst_type = TCG_TYPE_REG; 6265723d3a27SRichard Henderson mov[0].src_type = TCG_TYPE_REG; 6266ebebea53SRichard Henderson mov[0].src_ext = TCG_TARGET_REG_BITS == 32 ? MO_32 : MO_64; 62678429a1caSRichard Henderson 62688429a1caSRichard Henderson mov[1].dst = ldst->datahi_reg; 62698429a1caSRichard Henderson mov[1].src = 62708429a1caSRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, !HOST_BIG_ENDIAN); 62718429a1caSRichard Henderson mov[1].dst_type = TCG_TYPE_REG; 62728429a1caSRichard Henderson mov[1].src_type = TCG_TYPE_REG; 6273ebebea53SRichard Henderson mov[1].src_ext = TCG_TARGET_REG_BITS == 32 ? MO_32 : MO_64; 62748429a1caSRichard Henderson 62758429a1caSRichard Henderson tcg_out_movext2(s, mov, mov + 1, parm->ntmp ? parm->tmp[0] : -1); 62768429a1caSRichard Henderson } 62778429a1caSRichard Henderson 62788429a1caSRichard Henderson static void tcg_out_st_helper_args(TCGContext *s, const TCGLabelQemuLdst *ldst, 62798429a1caSRichard Henderson const TCGLdstHelperParam *parm) 62808429a1caSRichard Henderson { 62818429a1caSRichard Henderson const TCGHelperInfo *info; 62828429a1caSRichard Henderson const TCGCallArgumentLoc *loc; 62838429a1caSRichard Henderson TCGMovExtend mov[4]; 62848429a1caSRichard Henderson TCGType data_type; 62858429a1caSRichard Henderson unsigned next_arg, nmov, n; 62868429a1caSRichard Henderson MemOp mop = get_memop(ldst->oi); 62878429a1caSRichard Henderson 62888429a1caSRichard Henderson switch (mop & MO_SIZE) { 62898429a1caSRichard Henderson case MO_8: 62908429a1caSRichard Henderson case MO_16: 62918429a1caSRichard Henderson case MO_32: 62928429a1caSRichard Henderson info = &info_helper_st32_mmu; 62938429a1caSRichard Henderson data_type = TCG_TYPE_I32; 62948429a1caSRichard Henderson break; 62958429a1caSRichard Henderson case MO_64: 62968429a1caSRichard Henderson info = &info_helper_st64_mmu; 62978429a1caSRichard Henderson data_type = TCG_TYPE_I64; 62988429a1caSRichard Henderson break; 6299ebebea53SRichard Henderson case MO_128: 6300ebebea53SRichard Henderson info = &info_helper_st128_mmu; 6301ebebea53SRichard Henderson data_type = TCG_TYPE_I128; 6302ebebea53SRichard Henderson break; 63038429a1caSRichard Henderson default: 63048429a1caSRichard Henderson g_assert_not_reached(); 63058429a1caSRichard Henderson } 63068429a1caSRichard Henderson 63078429a1caSRichard Henderson /* Defer env argument. */ 63088429a1caSRichard Henderson next_arg = 1; 63098429a1caSRichard Henderson nmov = 0; 63108429a1caSRichard Henderson 63118429a1caSRichard Henderson /* Handle addr argument. */ 63128429a1caSRichard Henderson loc = &info->in[next_arg]; 63130cd38379SRichard Henderson tcg_debug_assert(s->addr_type <= TCG_TYPE_REG); 63140cd38379SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 631524e46e6cSRichard Henderson /* 63160cd38379SRichard Henderson * 32-bit host (and thus 32-bit guest): zero-extend the guest address 631724e46e6cSRichard Henderson * to 64-bits for the helper by storing the low part. Later, 631824e46e6cSRichard Henderson * after we have processed the register inputs, we will load a 631924e46e6cSRichard Henderson * zero for the high part. 632024e46e6cSRichard Henderson */ 632124e46e6cSRichard Henderson tcg_out_helper_add_mov(mov, loc + HOST_BIG_ENDIAN, 632224e46e6cSRichard Henderson TCG_TYPE_I32, TCG_TYPE_I32, 63230cd38379SRichard Henderson ldst->addr_reg, -1); 632424e46e6cSRichard Henderson next_arg += 2; 632524e46e6cSRichard Henderson nmov += 1; 6326c31e5fa4SRichard Henderson } else { 6327c31e5fa4SRichard Henderson n = tcg_out_helper_add_mov(mov, loc, TCG_TYPE_I64, s->addr_type, 63280cd38379SRichard Henderson ldst->addr_reg, -1); 6329c31e5fa4SRichard Henderson next_arg += n; 6330c31e5fa4SRichard Henderson nmov += n; 633124e46e6cSRichard Henderson } 63328429a1caSRichard Henderson 63338429a1caSRichard Henderson /* Handle data argument. */ 63348429a1caSRichard Henderson loc = &info->in[next_arg]; 6335ebebea53SRichard Henderson switch (loc->kind) { 6336ebebea53SRichard Henderson case TCG_CALL_ARG_NORMAL: 6337ebebea53SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 6338ebebea53SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 63398429a1caSRichard Henderson n = tcg_out_helper_add_mov(mov + nmov, loc, data_type, ldst->type, 63408429a1caSRichard Henderson ldst->datalo_reg, ldst->datahi_reg); 63418429a1caSRichard Henderson next_arg += n; 63428429a1caSRichard Henderson nmov += n; 6343ebebea53SRichard Henderson tcg_out_helper_load_slots(s, nmov, mov, parm); 6344ebebea53SRichard Henderson break; 6345ebebea53SRichard Henderson 6346ebebea53SRichard Henderson case TCG_CALL_ARG_BY_REF: 6347ebebea53SRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 64); 6348ebebea53SRichard Henderson tcg_debug_assert(data_type == TCG_TYPE_I128); 6349ebebea53SRichard Henderson tcg_out_st(s, TCG_TYPE_I64, 6350ebebea53SRichard Henderson HOST_BIG_ENDIAN ? ldst->datahi_reg : ldst->datalo_reg, 6351ebebea53SRichard Henderson TCG_REG_CALL_STACK, arg_slot_stk_ofs(loc[0].ref_slot)); 6352ebebea53SRichard Henderson tcg_out_st(s, TCG_TYPE_I64, 6353ebebea53SRichard Henderson HOST_BIG_ENDIAN ? ldst->datalo_reg : ldst->datahi_reg, 6354ebebea53SRichard Henderson TCG_REG_CALL_STACK, arg_slot_stk_ofs(loc[1].ref_slot)); 63558429a1caSRichard Henderson 63568429a1caSRichard Henderson tcg_out_helper_load_slots(s, nmov, mov, parm); 6357ebebea53SRichard Henderson 6358ebebea53SRichard Henderson if (arg_slot_reg_p(loc->arg_slot)) { 6359ebebea53SRichard Henderson tcg_out_addi_ptr(s, tcg_target_call_iarg_regs[loc->arg_slot], 6360ebebea53SRichard Henderson TCG_REG_CALL_STACK, 6361ebebea53SRichard Henderson arg_slot_stk_ofs(loc->ref_slot)); 6362ebebea53SRichard Henderson } else { 6363ebebea53SRichard Henderson tcg_debug_assert(parm->ntmp != 0); 6364ebebea53SRichard Henderson tcg_out_addi_ptr(s, parm->tmp[0], TCG_REG_CALL_STACK, 6365ebebea53SRichard Henderson arg_slot_stk_ofs(loc->ref_slot)); 6366ebebea53SRichard Henderson tcg_out_st(s, TCG_TYPE_PTR, parm->tmp[0], 6367ebebea53SRichard Henderson TCG_REG_CALL_STACK, arg_slot_stk_ofs(loc->arg_slot)); 6368ebebea53SRichard Henderson } 6369ebebea53SRichard Henderson next_arg += 2; 6370ebebea53SRichard Henderson break; 6371ebebea53SRichard Henderson 6372ebebea53SRichard Henderson default: 6373ebebea53SRichard Henderson g_assert_not_reached(); 6374ebebea53SRichard Henderson } 6375ebebea53SRichard Henderson 63760cd38379SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 6377c31e5fa4SRichard Henderson /* Zero extend the address by loading a zero for the high part. */ 637824e46e6cSRichard Henderson loc = &info->in[1 + !HOST_BIG_ENDIAN]; 637924e46e6cSRichard Henderson tcg_out_helper_load_imm(s, loc->arg_slot, TCG_TYPE_I32, 0, parm); 638024e46e6cSRichard Henderson } 638124e46e6cSRichard Henderson 63828429a1caSRichard Henderson tcg_out_helper_load_common_args(s, ldst, parm, info, next_arg); 63838429a1caSRichard Henderson } 63848429a1caSRichard Henderson 638576cef4b2SRichard Henderson int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start) 6386c896fe29Sbellard { 6387747bd69dSRichard Henderson int i, start_words, num_insns; 638815fa08f8SRichard Henderson TCGOp *op; 6389c896fe29Sbellard 6390d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP) 6391fbf59aadSRichard Henderson && qemu_log_in_addr_range(pc_start))) { 6392c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock(); 639378b54858SRichard Henderson if (logfile) { 639478b54858SRichard Henderson fprintf(logfile, "OP:\n"); 6395b7a83ff8SRichard Henderson tcg_dump_ops(s, logfile, false); 639678b54858SRichard Henderson fprintf(logfile, "\n"); 6397fc59d2d8SRobert Foley qemu_log_unlock(logfile); 6398c896fe29Sbellard } 639978b54858SRichard Henderson } 6400c896fe29Sbellard 6401bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG 6402bef16ab4SRichard Henderson /* Ensure all labels referenced have been emitted. */ 6403bef16ab4SRichard Henderson { 6404bef16ab4SRichard Henderson TCGLabel *l; 6405bef16ab4SRichard Henderson bool error = false; 6406bef16ab4SRichard Henderson 6407bef16ab4SRichard Henderson QSIMPLEQ_FOREACH(l, &s->labels, next) { 6408f85b1fc4SRichard Henderson if (unlikely(!l->present) && !QSIMPLEQ_EMPTY(&l->branches)) { 6409bef16ab4SRichard Henderson qemu_log_mask(CPU_LOG_TB_OP, 6410bef16ab4SRichard Henderson "$L%d referenced but not present.\n", l->id); 6411bef16ab4SRichard Henderson error = true; 6412bef16ab4SRichard Henderson } 6413bef16ab4SRichard Henderson } 6414bef16ab4SRichard Henderson assert(!error); 6415bef16ab4SRichard Henderson } 6416bef16ab4SRichard Henderson #endif 6417bef16ab4SRichard Henderson 641804e006abSRichard Henderson /* Do not reuse any EBB that may be allocated within the TB. */ 641904e006abSRichard Henderson tcg_temp_ebb_reset_freed(s); 642004e006abSRichard Henderson 6421c45cb8bbSRichard Henderson tcg_optimize(s); 64228f2e8c07SKirill Batuzov 6423b4fc67c7SRichard Henderson reachable_code_pass(s); 6424874b8574SRichard Henderson liveness_pass_0(s); 6425b83eabeaSRichard Henderson liveness_pass_1(s); 64265a18407fSRichard Henderson 64275a18407fSRichard Henderson if (s->nb_indirects > 0) { 64285a18407fSRichard Henderson if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND) 6429fbf59aadSRichard Henderson && qemu_log_in_addr_range(pc_start))) { 6430c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock(); 643178b54858SRichard Henderson if (logfile) { 643278b54858SRichard Henderson fprintf(logfile, "OP before indirect lowering:\n"); 6433b7a83ff8SRichard Henderson tcg_dump_ops(s, logfile, false); 643478b54858SRichard Henderson fprintf(logfile, "\n"); 6435fc59d2d8SRobert Foley qemu_log_unlock(logfile); 64365a18407fSRichard Henderson } 643778b54858SRichard Henderson } 6438645e3a81SRichard Henderson 64395a18407fSRichard Henderson /* Replace indirect temps with direct temps. */ 6440b83eabeaSRichard Henderson if (liveness_pass_2(s)) { 64415a18407fSRichard Henderson /* If changes were made, re-run liveness. */ 6442b83eabeaSRichard Henderson liveness_pass_1(s); 64435a18407fSRichard Henderson } 64445a18407fSRichard Henderson } 6445c5cc28ffSAurelien Jarno 6446d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT) 6447fbf59aadSRichard Henderson && qemu_log_in_addr_range(pc_start))) { 6448c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock(); 644978b54858SRichard Henderson if (logfile) { 645078b54858SRichard Henderson fprintf(logfile, "OP after optimization and liveness analysis:\n"); 6451b7a83ff8SRichard Henderson tcg_dump_ops(s, logfile, true); 645278b54858SRichard Henderson fprintf(logfile, "\n"); 6453fc59d2d8SRobert Foley qemu_log_unlock(logfile); 6454c896fe29Sbellard } 645578b54858SRichard Henderson } 6456c896fe29Sbellard 645735abb009SRichard Henderson /* Initialize goto_tb jump offsets. */ 64583a50f424SRichard Henderson tb->jmp_reset_offset[0] = TB_JMP_OFFSET_INVALID; 64593a50f424SRichard Henderson tb->jmp_reset_offset[1] = TB_JMP_OFFSET_INVALID; 64609da6079bSRichard Henderson tb->jmp_insn_offset[0] = TB_JMP_OFFSET_INVALID; 64619da6079bSRichard Henderson tb->jmp_insn_offset[1] = TB_JMP_OFFSET_INVALID; 646235abb009SRichard Henderson 6463c896fe29Sbellard tcg_reg_alloc_start(s); 6464c896fe29Sbellard 6465db0c51a3SRichard Henderson /* 6466db0c51a3SRichard Henderson * Reset the buffer pointers when restarting after overflow. 6467db0c51a3SRichard Henderson * TODO: Move this into translate-all.c with the rest of the 6468db0c51a3SRichard Henderson * buffer management. Having only this done here is confusing. 6469db0c51a3SRichard Henderson */ 6470db0c51a3SRichard Henderson s->code_buf = tcg_splitwx_to_rw(tb->tc.ptr); 6471db0c51a3SRichard Henderson s->code_ptr = s->code_buf; 6472a7cfd751SRichard Henderson s->data_gen_ptr = NULL; 6473c896fe29Sbellard 64746001f772SLaurent Vivier QSIMPLEQ_INIT(&s->ldst_labels); 647557a26946SRichard Henderson s->pool_labels = NULL; 64769ecefc84SRichard Henderson 6477747bd69dSRichard Henderson start_words = s->insn_start_words; 6478747bd69dSRichard Henderson s->gen_insn_data = 6479747bd69dSRichard Henderson tcg_malloc(sizeof(uint64_t) * s->gen_tb->icount * start_words); 6480747bd69dSRichard Henderson 64819358fbbfSRichard Henderson tcg_out_tb_start(s); 64829358fbbfSRichard Henderson 6483fca8a500SRichard Henderson num_insns = -1; 648415fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 6485c45cb8bbSRichard Henderson TCGOpcode opc = op->opc; 6486b3db8758Sblueswir1 6487c896fe29Sbellard switch (opc) { 6488b5701261SRichard Henderson case INDEX_op_mov: 6489d2fd745fSRichard Henderson case INDEX_op_mov_vec: 6490dd186292SRichard Henderson tcg_reg_alloc_mov(s, op); 6491c896fe29Sbellard break; 6492bab1671fSRichard Henderson case INDEX_op_dup_vec: 6493bab1671fSRichard Henderson tcg_reg_alloc_dup(s, op); 6494bab1671fSRichard Henderson break; 6495765b842aSRichard Henderson case INDEX_op_insn_start: 6496fca8a500SRichard Henderson if (num_insns >= 0) { 64979f754620SRichard Henderson size_t off = tcg_current_code_size(s); 64989f754620SRichard Henderson s->gen_insn_end_off[num_insns] = off; 64999f754620SRichard Henderson /* Assert that we do not overflow our stored offset. */ 65009f754620SRichard Henderson assert(s->gen_insn_end_off[num_insns] == off); 6501fca8a500SRichard Henderson } 6502fca8a500SRichard Henderson num_insns++; 6503747bd69dSRichard Henderson for (i = 0; i < start_words; ++i) { 6504747bd69dSRichard Henderson s->gen_insn_data[num_insns * start_words + i] = 6505c9ad8d27SRichard Henderson tcg_get_insn_start_param(op, i); 6506bad729e2SRichard Henderson } 6507c896fe29Sbellard break; 65085ff9d6a4Sbellard case INDEX_op_discard: 650943439139SRichard Henderson temp_dead(s, arg_temp(op->args[0])); 65105ff9d6a4Sbellard break; 6511c896fe29Sbellard case INDEX_op_set_label: 6512e8996ee0Sbellard tcg_reg_alloc_bb_end(s, s->reserved_regs); 651392ab8e7dSRichard Henderson tcg_out_label(s, arg_label(op->args[0])); 6514c896fe29Sbellard break; 6515c896fe29Sbellard case INDEX_op_call: 6516dd186292SRichard Henderson tcg_reg_alloc_call(s, op); 6517c45cb8bbSRichard Henderson break; 6518b55a8d9dSRichard Henderson case INDEX_op_exit_tb: 6519b55a8d9dSRichard Henderson tcg_out_exit_tb(s, op->args[0]); 6520b55a8d9dSRichard Henderson break; 6521cf7d6b8eSRichard Henderson case INDEX_op_goto_tb: 6522cf7d6b8eSRichard Henderson tcg_out_goto_tb(s, op->args[0]); 6523cf7d6b8eSRichard Henderson break; 6524efe86b21SRichard Henderson case INDEX_op_dup2_vec: 6525efe86b21SRichard Henderson if (tcg_reg_alloc_dup2(s, op)) { 6526efe86b21SRichard Henderson break; 6527efe86b21SRichard Henderson } 6528efe86b21SRichard Henderson /* fall through */ 6529c896fe29Sbellard default: 653025c4d9ccSRichard Henderson /* Sanity check that we've not introduced any unhandled opcodes. */ 6531771a5925SRichard Henderson tcg_debug_assert(tcg_op_supported(opc, TCGOP_TYPE(op), 6532771a5925SRichard Henderson TCGOP_FLAGS(op))); 6533c896fe29Sbellard /* Note: in order to speed up the code, it would be much 6534c896fe29Sbellard faster to have specialized register allocator functions for 6535c896fe29Sbellard some common argument patterns */ 6536dd186292SRichard Henderson tcg_reg_alloc_op(s, op); 6537c896fe29Sbellard break; 6538c896fe29Sbellard } 6539b125f9dcSRichard Henderson /* Test for (pending) buffer overflow. The assumption is that any 6540b125f9dcSRichard Henderson one operation beginning below the high water mark cannot overrun 6541b125f9dcSRichard Henderson the buffer completely. Thus we can test for overflow after 6542b125f9dcSRichard Henderson generating code without having to check during generation. */ 6543644da9b3SJohn Clarke if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) { 6544b125f9dcSRichard Henderson return -1; 6545b125f9dcSRichard Henderson } 65466e6c4efeSRichard Henderson /* Test for TB overflow, as seen by gen_insn_end_off. */ 65476e6c4efeSRichard Henderson if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) { 65486e6c4efeSRichard Henderson return -2; 65496e6c4efeSRichard Henderson } 6550c896fe29Sbellard } 6551747bd69dSRichard Henderson tcg_debug_assert(num_insns + 1 == s->gen_tb->icount); 6552fca8a500SRichard Henderson s->gen_insn_end_off[num_insns] = tcg_current_code_size(s); 6553c45cb8bbSRichard Henderson 6554b76f0d8cSYeongkyoon Lee /* Generate TB finalization at the end of block */ 6555aeee05f5SRichard Henderson i = tcg_out_ldst_finalize(s); 6556aeee05f5SRichard Henderson if (i < 0) { 6557aeee05f5SRichard Henderson return i; 655823dceda6SRichard Henderson } 65591768987bSRichard Henderson i = tcg_out_pool_finalize(s); 65601768987bSRichard Henderson if (i < 0) { 65611768987bSRichard Henderson return i; 656257a26946SRichard Henderson } 65637ecd02a0SRichard Henderson if (!tcg_resolve_relocs(s)) { 65647ecd02a0SRichard Henderson return -2; 65657ecd02a0SRichard Henderson } 6566c896fe29Sbellard 6567df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 6568c896fe29Sbellard /* flush instruction cache */ 6569db0c51a3SRichard Henderson flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf), 6570db0c51a3SRichard Henderson (uintptr_t)s->code_buf, 65711da8de39SRichard Henderson tcg_ptr_byte_diff(s->code_ptr, s->code_buf)); 6572df5d2b16SRichard Henderson #endif 65732aeabc08SStefan Weil 65741813e175SRichard Henderson return tcg_current_code_size(s); 6575c896fe29Sbellard } 6576c896fe29Sbellard 6577813da627SRichard Henderson #ifdef ELF_HOST_MACHINE 65785872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things: 65795872bbf2SRichard Henderson 65805872bbf2SRichard Henderson (1) Define ELF_HOST_MACHINE to indicate both what value to 65815872bbf2SRichard Henderson put into the ELF image and to indicate support for the feature. 65825872bbf2SRichard Henderson 65835872bbf2SRichard Henderson (2) Define tcg_register_jit. This should create a buffer containing 65845872bbf2SRichard Henderson the contents of a .debug_frame section that describes the post- 65855872bbf2SRichard Henderson prologue unwind info for the tcg machine. 65865872bbf2SRichard Henderson 65875872bbf2SRichard Henderson (3) Call tcg_register_jit_int, with the constructed .debug_frame. 65885872bbf2SRichard Henderson */ 6589813da627SRichard Henderson 6590813da627SRichard Henderson /* Begin GDB interface. THE FOLLOWING MUST MATCH GDB DOCS. */ 6591813da627SRichard Henderson typedef enum { 6592813da627SRichard Henderson JIT_NOACTION = 0, 6593813da627SRichard Henderson JIT_REGISTER_FN, 6594813da627SRichard Henderson JIT_UNREGISTER_FN 6595813da627SRichard Henderson } jit_actions_t; 6596813da627SRichard Henderson 6597813da627SRichard Henderson struct jit_code_entry { 6598813da627SRichard Henderson struct jit_code_entry *next_entry; 6599813da627SRichard Henderson struct jit_code_entry *prev_entry; 6600813da627SRichard Henderson const void *symfile_addr; 6601813da627SRichard Henderson uint64_t symfile_size; 6602813da627SRichard Henderson }; 6603813da627SRichard Henderson 6604813da627SRichard Henderson struct jit_descriptor { 6605813da627SRichard Henderson uint32_t version; 6606813da627SRichard Henderson uint32_t action_flag; 6607813da627SRichard Henderson struct jit_code_entry *relevant_entry; 6608813da627SRichard Henderson struct jit_code_entry *first_entry; 6609813da627SRichard Henderson }; 6610813da627SRichard Henderson 6611813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline)); 6612813da627SRichard Henderson void __jit_debug_register_code(void) 6613813da627SRichard Henderson { 6614813da627SRichard Henderson asm(""); 6615813da627SRichard Henderson } 6616813da627SRichard Henderson 6617813da627SRichard Henderson /* Must statically initialize the version, because GDB may check 6618813da627SRichard Henderson the version before we can set it. */ 6619813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 }; 6620813da627SRichard Henderson 6621813da627SRichard Henderson /* End GDB interface. */ 6622813da627SRichard Henderson 6623813da627SRichard Henderson static int find_string(const char *strtab, const char *str) 6624813da627SRichard Henderson { 6625813da627SRichard Henderson const char *p = strtab + 1; 6626813da627SRichard Henderson 6627813da627SRichard Henderson while (1) { 6628813da627SRichard Henderson if (strcmp(p, str) == 0) { 6629813da627SRichard Henderson return p - strtab; 6630813da627SRichard Henderson } 6631813da627SRichard Henderson p += strlen(p) + 1; 6632813da627SRichard Henderson } 6633813da627SRichard Henderson } 6634813da627SRichard Henderson 6635755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf_ptr, size_t buf_size, 66362c90784aSRichard Henderson const void *debug_frame, 66372c90784aSRichard Henderson size_t debug_frame_size) 6638813da627SRichard Henderson { 66395872bbf2SRichard Henderson struct __attribute__((packed)) DebugInfo { 66405872bbf2SRichard Henderson uint32_t len; 66415872bbf2SRichard Henderson uint16_t version; 66425872bbf2SRichard Henderson uint32_t abbrev; 66435872bbf2SRichard Henderson uint8_t ptr_size; 66445872bbf2SRichard Henderson uint8_t cu_die; 66455872bbf2SRichard Henderson uint16_t cu_lang; 66465872bbf2SRichard Henderson uintptr_t cu_low_pc; 66475872bbf2SRichard Henderson uintptr_t cu_high_pc; 66485872bbf2SRichard Henderson uint8_t fn_die; 66495872bbf2SRichard Henderson char fn_name[16]; 66505872bbf2SRichard Henderson uintptr_t fn_low_pc; 66515872bbf2SRichard Henderson uintptr_t fn_high_pc; 66525872bbf2SRichard Henderson uint8_t cu_eoc; 66535872bbf2SRichard Henderson }; 6654813da627SRichard Henderson 6655813da627SRichard Henderson struct ElfImage { 6656813da627SRichard Henderson ElfW(Ehdr) ehdr; 6657813da627SRichard Henderson ElfW(Phdr) phdr; 66585872bbf2SRichard Henderson ElfW(Shdr) shdr[7]; 66595872bbf2SRichard Henderson ElfW(Sym) sym[2]; 66605872bbf2SRichard Henderson struct DebugInfo di; 66615872bbf2SRichard Henderson uint8_t da[24]; 66625872bbf2SRichard Henderson char str[80]; 66635872bbf2SRichard Henderson }; 66645872bbf2SRichard Henderson 66655872bbf2SRichard Henderson struct ElfImage *img; 66665872bbf2SRichard Henderson 66675872bbf2SRichard Henderson static const struct ElfImage img_template = { 66685872bbf2SRichard Henderson .ehdr = { 66695872bbf2SRichard Henderson .e_ident[EI_MAG0] = ELFMAG0, 66705872bbf2SRichard Henderson .e_ident[EI_MAG1] = ELFMAG1, 66715872bbf2SRichard Henderson .e_ident[EI_MAG2] = ELFMAG2, 66725872bbf2SRichard Henderson .e_ident[EI_MAG3] = ELFMAG3, 66735872bbf2SRichard Henderson .e_ident[EI_CLASS] = ELF_CLASS, 66745872bbf2SRichard Henderson .e_ident[EI_DATA] = ELF_DATA, 66755872bbf2SRichard Henderson .e_ident[EI_VERSION] = EV_CURRENT, 66765872bbf2SRichard Henderson .e_type = ET_EXEC, 66775872bbf2SRichard Henderson .e_machine = ELF_HOST_MACHINE, 66785872bbf2SRichard Henderson .e_version = EV_CURRENT, 66795872bbf2SRichard Henderson .e_phoff = offsetof(struct ElfImage, phdr), 66805872bbf2SRichard Henderson .e_shoff = offsetof(struct ElfImage, shdr), 66815872bbf2SRichard Henderson .e_ehsize = sizeof(ElfW(Shdr)), 66825872bbf2SRichard Henderson .e_phentsize = sizeof(ElfW(Phdr)), 66835872bbf2SRichard Henderson .e_phnum = 1, 66845872bbf2SRichard Henderson .e_shentsize = sizeof(ElfW(Shdr)), 66855872bbf2SRichard Henderson .e_shnum = ARRAY_SIZE(img->shdr), 66865872bbf2SRichard Henderson .e_shstrndx = ARRAY_SIZE(img->shdr) - 1, 6687abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS 6688abbb3eaeSRichard Henderson .e_flags = ELF_HOST_FLAGS, 6689abbb3eaeSRichard Henderson #endif 6690abbb3eaeSRichard Henderson #ifdef ELF_OSABI 6691abbb3eaeSRichard Henderson .e_ident[EI_OSABI] = ELF_OSABI, 6692abbb3eaeSRichard Henderson #endif 66935872bbf2SRichard Henderson }, 66945872bbf2SRichard Henderson .phdr = { 66955872bbf2SRichard Henderson .p_type = PT_LOAD, 66965872bbf2SRichard Henderson .p_flags = PF_X, 66975872bbf2SRichard Henderson }, 66985872bbf2SRichard Henderson .shdr = { 66995872bbf2SRichard Henderson [0] = { .sh_type = SHT_NULL }, 67005872bbf2SRichard Henderson /* Trick: The contents of code_gen_buffer are not present in 67015872bbf2SRichard Henderson this fake ELF file; that got allocated elsewhere. Therefore 67025872bbf2SRichard Henderson we mark .text as SHT_NOBITS (similar to .bss) so that readers 67035872bbf2SRichard Henderson will not look for contents. We can record any address. */ 67045872bbf2SRichard Henderson [1] = { /* .text */ 67055872bbf2SRichard Henderson .sh_type = SHT_NOBITS, 67065872bbf2SRichard Henderson .sh_flags = SHF_EXECINSTR | SHF_ALLOC, 67075872bbf2SRichard Henderson }, 67085872bbf2SRichard Henderson [2] = { /* .debug_info */ 67095872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 67105872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, di), 67115872bbf2SRichard Henderson .sh_size = sizeof(struct DebugInfo), 67125872bbf2SRichard Henderson }, 67135872bbf2SRichard Henderson [3] = { /* .debug_abbrev */ 67145872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 67155872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, da), 67165872bbf2SRichard Henderson .sh_size = sizeof(img->da), 67175872bbf2SRichard Henderson }, 67185872bbf2SRichard Henderson [4] = { /* .debug_frame */ 67195872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 67205872bbf2SRichard Henderson .sh_offset = sizeof(struct ElfImage), 67215872bbf2SRichard Henderson }, 67225872bbf2SRichard Henderson [5] = { /* .symtab */ 67235872bbf2SRichard Henderson .sh_type = SHT_SYMTAB, 67245872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, sym), 67255872bbf2SRichard Henderson .sh_size = sizeof(img->sym), 67265872bbf2SRichard Henderson .sh_info = 1, 67275872bbf2SRichard Henderson .sh_link = ARRAY_SIZE(img->shdr) - 1, 67285872bbf2SRichard Henderson .sh_entsize = sizeof(ElfW(Sym)), 67295872bbf2SRichard Henderson }, 67305872bbf2SRichard Henderson [6] = { /* .strtab */ 67315872bbf2SRichard Henderson .sh_type = SHT_STRTAB, 67325872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, str), 67335872bbf2SRichard Henderson .sh_size = sizeof(img->str), 67345872bbf2SRichard Henderson } 67355872bbf2SRichard Henderson }, 67365872bbf2SRichard Henderson .sym = { 67375872bbf2SRichard Henderson [1] = { /* code_gen_buffer */ 67385872bbf2SRichard Henderson .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC), 67395872bbf2SRichard Henderson .st_shndx = 1, 67405872bbf2SRichard Henderson } 67415872bbf2SRichard Henderson }, 67425872bbf2SRichard Henderson .di = { 67435872bbf2SRichard Henderson .len = sizeof(struct DebugInfo) - 4, 67445872bbf2SRichard Henderson .version = 2, 67455872bbf2SRichard Henderson .ptr_size = sizeof(void *), 67465872bbf2SRichard Henderson .cu_die = 1, 67475872bbf2SRichard Henderson .cu_lang = 0x8001, /* DW_LANG_Mips_Assembler */ 67485872bbf2SRichard Henderson .fn_die = 2, 67495872bbf2SRichard Henderson .fn_name = "code_gen_buffer" 67505872bbf2SRichard Henderson }, 67515872bbf2SRichard Henderson .da = { 67525872bbf2SRichard Henderson 1, /* abbrev number (the cu) */ 67535872bbf2SRichard Henderson 0x11, 1, /* DW_TAG_compile_unit, has children */ 67545872bbf2SRichard Henderson 0x13, 0x5, /* DW_AT_language, DW_FORM_data2 */ 67555872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */ 67565872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */ 67575872bbf2SRichard Henderson 0, 0, /* end of abbrev */ 67585872bbf2SRichard Henderson 2, /* abbrev number (the fn) */ 67595872bbf2SRichard Henderson 0x2e, 0, /* DW_TAG_subprogram, no children */ 67605872bbf2SRichard Henderson 0x3, 0x8, /* DW_AT_name, DW_FORM_string */ 67615872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */ 67625872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */ 67635872bbf2SRichard Henderson 0, 0, /* end of abbrev */ 67645872bbf2SRichard Henderson 0 /* no more abbrev */ 67655872bbf2SRichard Henderson }, 67665872bbf2SRichard Henderson .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0" 67675872bbf2SRichard Henderson ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer", 6768813da627SRichard Henderson }; 6769813da627SRichard Henderson 6770813da627SRichard Henderson /* We only need a single jit entry; statically allocate it. */ 6771813da627SRichard Henderson static struct jit_code_entry one_entry; 6772813da627SRichard Henderson 67735872bbf2SRichard Henderson uintptr_t buf = (uintptr_t)buf_ptr; 6774813da627SRichard Henderson size_t img_size = sizeof(struct ElfImage) + debug_frame_size; 67752c90784aSRichard Henderson DebugFrameHeader *dfh; 6776813da627SRichard Henderson 67775872bbf2SRichard Henderson img = g_malloc(img_size); 67785872bbf2SRichard Henderson *img = img_template; 6779813da627SRichard Henderson 67805872bbf2SRichard Henderson img->phdr.p_vaddr = buf; 67815872bbf2SRichard Henderson img->phdr.p_paddr = buf; 67825872bbf2SRichard Henderson img->phdr.p_memsz = buf_size; 6783813da627SRichard Henderson 67845872bbf2SRichard Henderson img->shdr[1].sh_name = find_string(img->str, ".text"); 67855872bbf2SRichard Henderson img->shdr[1].sh_addr = buf; 67865872bbf2SRichard Henderson img->shdr[1].sh_size = buf_size; 6787813da627SRichard Henderson 67885872bbf2SRichard Henderson img->shdr[2].sh_name = find_string(img->str, ".debug_info"); 67895872bbf2SRichard Henderson img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev"); 67905872bbf2SRichard Henderson 67915872bbf2SRichard Henderson img->shdr[4].sh_name = find_string(img->str, ".debug_frame"); 67925872bbf2SRichard Henderson img->shdr[4].sh_size = debug_frame_size; 67935872bbf2SRichard Henderson 67945872bbf2SRichard Henderson img->shdr[5].sh_name = find_string(img->str, ".symtab"); 67955872bbf2SRichard Henderson img->shdr[6].sh_name = find_string(img->str, ".strtab"); 67965872bbf2SRichard Henderson 67975872bbf2SRichard Henderson img->sym[1].st_name = find_string(img->str, "code_gen_buffer"); 67985872bbf2SRichard Henderson img->sym[1].st_value = buf; 67995872bbf2SRichard Henderson img->sym[1].st_size = buf_size; 68005872bbf2SRichard Henderson 68015872bbf2SRichard Henderson img->di.cu_low_pc = buf; 680245aba097SRichard Henderson img->di.cu_high_pc = buf + buf_size; 68035872bbf2SRichard Henderson img->di.fn_low_pc = buf; 680445aba097SRichard Henderson img->di.fn_high_pc = buf + buf_size; 6805813da627SRichard Henderson 68062c90784aSRichard Henderson dfh = (DebugFrameHeader *)(img + 1); 68072c90784aSRichard Henderson memcpy(dfh, debug_frame, debug_frame_size); 68082c90784aSRichard Henderson dfh->fde.func_start = buf; 68092c90784aSRichard Henderson dfh->fde.func_len = buf_size; 68102c90784aSRichard Henderson 6811813da627SRichard Henderson #ifdef DEBUG_JIT 6812813da627SRichard Henderson /* Enable this block to be able to debug the ELF image file creation. 6813813da627SRichard Henderson One can use readelf, objdump, or other inspection utilities. */ 6814813da627SRichard Henderson { 6815eb6b2edfSBin Meng g_autofree char *jit = g_strdup_printf("%s/qemu.jit", g_get_tmp_dir()); 6816eb6b2edfSBin Meng FILE *f = fopen(jit, "w+b"); 6817813da627SRichard Henderson if (f) { 68185872bbf2SRichard Henderson if (fwrite(img, img_size, 1, f) != img_size) { 6819813da627SRichard Henderson /* Avoid stupid unused return value warning for fwrite. */ 6820813da627SRichard Henderson } 6821813da627SRichard Henderson fclose(f); 6822813da627SRichard Henderson } 6823813da627SRichard Henderson } 6824813da627SRichard Henderson #endif 6825813da627SRichard Henderson 6826813da627SRichard Henderson one_entry.symfile_addr = img; 6827813da627SRichard Henderson one_entry.symfile_size = img_size; 6828813da627SRichard Henderson 6829813da627SRichard Henderson __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; 6830813da627SRichard Henderson __jit_debug_descriptor.relevant_entry = &one_entry; 6831813da627SRichard Henderson __jit_debug_descriptor.first_entry = &one_entry; 6832813da627SRichard Henderson __jit_debug_register_code(); 6833813da627SRichard Henderson } 6834813da627SRichard Henderson #else 68355872bbf2SRichard Henderson /* No support for the feature. Provide the entry point expected by exec.c, 68365872bbf2SRichard Henderson and implement the internal function we declared earlier. */ 6837813da627SRichard Henderson 6838755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size, 68392c90784aSRichard Henderson const void *debug_frame, 68402c90784aSRichard Henderson size_t debug_frame_size) 6841813da627SRichard Henderson { 6842813da627SRichard Henderson } 6843813da627SRichard Henderson 6844755bf9e5SRichard Henderson void tcg_register_jit(const void *buf, size_t buf_size) 6845813da627SRichard Henderson { 6846813da627SRichard Henderson } 6847813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */ 6848db432672SRichard Henderson 6849db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec 6850db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...) 6851db432672SRichard Henderson { 6852db432672SRichard Henderson g_assert_not_reached(); 6853db432672SRichard Henderson } 6854db432672SRichard Henderson #endif 6855