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 98999ac4706SRichard Henderson typedef struct TCGOutOpBrcond { 99099ac4706SRichard Henderson TCGOutOp base; 99199ac4706SRichard Henderson void (*out_rr)(TCGContext *s, TCGType type, TCGCond cond, 99299ac4706SRichard Henderson TCGReg a1, TCGReg a2, TCGLabel *label); 99399ac4706SRichard Henderson void (*out_ri)(TCGContext *s, TCGType type, TCGCond cond, 99499ac4706SRichard Henderson TCGReg a1, tcg_target_long a2, TCGLabel *label); 99599ac4706SRichard Henderson } TCGOutOpBrcond; 99699ac4706SRichard Henderson 997f408df58SRichard Henderson typedef struct TCGOutOpBrcond2 { 998f408df58SRichard Henderson TCGOutOp base; 999f408df58SRichard Henderson void (*out)(TCGContext *s, TCGCond cond, TCGReg al, TCGReg ah, 1000f408df58SRichard Henderson TCGArg bl, bool const_bl, 1001f408df58SRichard Henderson TCGArg bh, bool const_bh, TCGLabel *l); 1002f408df58SRichard Henderson } TCGOutOpBrcond2; 1003f408df58SRichard Henderson 10045fa8e138SRichard Henderson typedef struct TCGOutOpBswap { 10055fa8e138SRichard Henderson TCGOutOp base; 10065fa8e138SRichard Henderson void (*out_rr)(TCGContext *s, TCGType type, 10075fa8e138SRichard Henderson TCGReg a0, TCGReg a1, unsigned flags); 10085fa8e138SRichard Henderson } TCGOutOpBswap; 10095fa8e138SRichard Henderson 1010d6cad9c9SRichard Henderson typedef struct TCGOutOpDivRem { 1011d6cad9c9SRichard Henderson TCGOutOp base; 1012d6cad9c9SRichard Henderson void (*out_rr01r)(TCGContext *s, TCGType type, 1013d6cad9c9SRichard Henderson TCGReg a0, TCGReg a1, TCGReg a4); 1014d6cad9c9SRichard Henderson } TCGOutOpDivRem; 1015d6cad9c9SRichard Henderson 10165a4d034fSRichard Henderson typedef struct TCGOutOpExtract { 10175a4d034fSRichard Henderson TCGOutOp base; 10185a4d034fSRichard Henderson void (*out_rr)(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, 10195a4d034fSRichard Henderson unsigned ofs, unsigned len); 10205a4d034fSRichard Henderson } TCGOutOpExtract; 10215a4d034fSRichard Henderson 10221f406e46SRichard Henderson typedef struct TCGOutOpMovcond { 10231f406e46SRichard Henderson TCGOutOp base; 10241f406e46SRichard Henderson void (*out)(TCGContext *s, TCGType type, TCGCond cond, 10251f406e46SRichard Henderson TCGReg ret, TCGReg c1, TCGArg c2, bool const_c2, 10261f406e46SRichard Henderson TCGArg vt, bool const_vt, TCGArg vf, bool consf_vf); 10271f406e46SRichard Henderson } TCGOutOpMovcond; 10281f406e46SRichard Henderson 10295641afdfSRichard Henderson typedef struct TCGOutOpMul2 { 10305641afdfSRichard Henderson TCGOutOp base; 10315641afdfSRichard Henderson void (*out_rrrr)(TCGContext *s, TCGType type, 10325641afdfSRichard Henderson TCGReg a0, TCGReg a1, TCGReg a2, TCGReg a3); 10335641afdfSRichard Henderson } TCGOutOpMul2; 10345641afdfSRichard Henderson 1035e126a91cSRichard Henderson typedef struct TCGOutOpUnary { 1036e126a91cSRichard Henderson TCGOutOp base; 1037e126a91cSRichard Henderson void (*out_rr)(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1); 1038e126a91cSRichard Henderson } TCGOutOpUnary; 1039e126a91cSRichard Henderson 10405a7b38c8SRichard Henderson typedef struct TCGOutOpSetcond { 10415a7b38c8SRichard Henderson TCGOutOp base; 10425a7b38c8SRichard Henderson void (*out_rrr)(TCGContext *s, TCGType type, TCGCond cond, 10435a7b38c8SRichard Henderson TCGReg ret, TCGReg a1, TCGReg a2); 10445a7b38c8SRichard Henderson void (*out_rri)(TCGContext *s, TCGType type, TCGCond cond, 10455a7b38c8SRichard Henderson TCGReg ret, TCGReg a1, tcg_target_long a2); 10465a7b38c8SRichard Henderson } TCGOutOpSetcond; 10475a7b38c8SRichard Henderson 1048e579c717SRichard Henderson typedef struct TCGOutOpSetcond2 { 1049e579c717SRichard Henderson TCGOutOp base; 1050e579c717SRichard Henderson void (*out)(TCGContext *s, TCGCond cond, TCGReg ret, TCGReg al, TCGReg ah, 1051e579c717SRichard Henderson TCGArg bl, bool const_bl, TCGArg bh, bool const_bh); 1052e579c717SRichard Henderson } TCGOutOpSetcond2; 1053e579c717SRichard Henderson 10543f057e24SRichard Henderson typedef struct TCGOutOpSubtract { 10553f057e24SRichard Henderson TCGOutOp base; 10563f057e24SRichard Henderson void (*out_rrr)(TCGContext *s, TCGType type, 10573f057e24SRichard Henderson TCGReg a0, TCGReg a1, TCGReg a2); 10583f057e24SRichard Henderson void (*out_rir)(TCGContext *s, TCGType type, 10593f057e24SRichard Henderson TCGReg a0, tcg_target_long a1, TCGReg a2); 10603f057e24SRichard Henderson } TCGOutOpSubtract; 10613f057e24SRichard Henderson 1062139c1837SPaolo Bonzini #include "tcg-target.c.inc" 1063c896fe29Sbellard 10647857ee11SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 10657857ee11SRichard Henderson /* Validate CPUTLBDescFast placement. */ 10667857ee11SRichard Henderson QEMU_BUILD_BUG_ON((int)(offsetof(CPUNegativeOffsetState, tlb.f[0]) - 10677857ee11SRichard Henderson sizeof(CPUNegativeOffsetState)) 10687857ee11SRichard Henderson < MIN_TLB_MASK_TABLE_OFS); 10697857ee11SRichard Henderson #endif 10707857ee11SRichard Henderson 1071662cdbcfSRichard Henderson /* 1072662cdbcfSRichard Henderson * Register V as the TCGOutOp for O. 1073662cdbcfSRichard Henderson * This verifies that V is of type T, otherwise give a nice compiler error. 1074662cdbcfSRichard Henderson * This prevents trivial mistakes within each arch/tcg-target.c.inc. 1075662cdbcfSRichard Henderson */ 1076662cdbcfSRichard Henderson #define OUTOP(O, T, V) [O] = _Generic(V, T: &V.base) 1077662cdbcfSRichard Henderson 10785500bd9eSRichard Henderson /* Register allocation descriptions for every TCGOpcode. */ 10795500bd9eSRichard Henderson static const TCGOutOp * const all_outop[NB_OPS] = { 108079602f63SRichard Henderson OUTOP(INDEX_op_add, TCGOutOpBinary, outop_add), 1081c3b920b3SRichard Henderson OUTOP(INDEX_op_and, TCGOutOpBinary, outop_and), 108246f96bffSRichard Henderson OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), 1083b6d69fceSRichard Henderson OUTOP(INDEX_op_brcond, TCGOutOpBrcond, outop_brcond), 10840dd07ee1SRichard Henderson OUTOP(INDEX_op_bswap16, TCGOutOpBswap, outop_bswap16), 10857498d882SRichard Henderson OUTOP(INDEX_op_bswap32, TCGOutOpBswap, outop_bswap32), 10865a5bb0a5SRichard Henderson OUTOP(INDEX_op_clz, TCGOutOpBinary, outop_clz), 108797218ae9SRichard Henderson OUTOP(INDEX_op_ctpop, TCGOutOpUnary, outop_ctpop), 1088c96447d8SRichard Henderson OUTOP(INDEX_op_ctz, TCGOutOpBinary, outop_ctz), 1089b2c514f9SRichard Henderson OUTOP(INDEX_op_divs, TCGOutOpBinary, outop_divs), 1090961b80aeSRichard Henderson OUTOP(INDEX_op_divu, TCGOutOpBinary, outop_divu), 1091ee1805b9SRichard Henderson OUTOP(INDEX_op_divs2, TCGOutOpDivRem, outop_divs2), 10928109598bSRichard Henderson OUTOP(INDEX_op_divu2, TCGOutOpDivRem, outop_divu2), 10935c0968a7SRichard Henderson OUTOP(INDEX_op_eqv, TCGOutOpBinary, outop_eqv), 1094*07d5d502SRichard Henderson OUTOP(INDEX_op_extract, TCGOutOpExtract, outop_extract), 1095ea46c4bcSRichard Henderson OUTOP(INDEX_op_movcond, TCGOutOpMovcond, outop_movcond), 1096d2c3ecadSRichard Henderson OUTOP(INDEX_op_mul, TCGOutOpBinary, outop_mul), 1097bfe96480SRichard Henderson OUTOP(INDEX_op_muls2, TCGOutOpMul2, outop_muls2), 1098c742824dSRichard Henderson OUTOP(INDEX_op_mulsh, TCGOutOpBinary, outop_mulsh), 1099d776198cSRichard Henderson OUTOP(INDEX_op_mulu2, TCGOutOpMul2, outop_mulu2), 1100aa28c9efSRichard Henderson OUTOP(INDEX_op_muluh, TCGOutOpBinary, outop_muluh), 110159379a45SRichard Henderson OUTOP(INDEX_op_nand, TCGOutOpBinary, outop_nand), 110269713587SRichard Henderson OUTOP(INDEX_op_neg, TCGOutOpUnary, outop_neg), 1103a363e1e1SRichard Henderson OUTOP(INDEX_op_negsetcond, TCGOutOpSetcond, outop_negsetcond), 11043a8c4e9eSRichard Henderson OUTOP(INDEX_op_nor, TCGOutOpBinary, outop_nor), 11055c62d377SRichard Henderson OUTOP(INDEX_op_not, TCGOutOpUnary, outop_not), 110649bd7514SRichard Henderson OUTOP(INDEX_op_or, TCGOutOpBinary, outop_or), 11076aba25ebSRichard Henderson OUTOP(INDEX_op_orc, TCGOutOpBinary, outop_orc), 11089a6bc184SRichard Henderson OUTOP(INDEX_op_rems, TCGOutOpBinary, outop_rems), 1109cd9acd20SRichard Henderson OUTOP(INDEX_op_remu, TCGOutOpBinary, outop_remu), 1110005a87e1SRichard Henderson OUTOP(INDEX_op_rotl, TCGOutOpBinary, outop_rotl), 1111005a87e1SRichard Henderson OUTOP(INDEX_op_rotr, TCGOutOpBinary, outop_rotr), 11123949f365SRichard Henderson OUTOP(INDEX_op_sar, TCGOutOpBinary, outop_sar), 1113a363e1e1SRichard Henderson OUTOP(INDEX_op_setcond, TCGOutOpSetcond, outop_setcond), 11146ca59451SRichard Henderson OUTOP(INDEX_op_shl, TCGOutOpBinary, outop_shl), 111574dbd36fSRichard Henderson OUTOP(INDEX_op_shr, TCGOutOpBinary, outop_shr), 111660f34f55SRichard Henderson OUTOP(INDEX_op_sub, TCGOutOpSubtract, outop_sub), 1117fffd3dc9SRichard Henderson OUTOP(INDEX_op_xor, TCGOutOpBinary, outop_xor), 1118f408df58SRichard Henderson 1119f408df58SRichard Henderson #if TCG_TARGET_REG_BITS == 32 1120f408df58SRichard Henderson OUTOP(INDEX_op_brcond2_i32, TCGOutOpBrcond2, outop_brcond2), 1121e579c717SRichard Henderson OUTOP(INDEX_op_setcond2_i32, TCGOutOpSetcond2, outop_setcond2), 1122613b571cSRichard Henderson #else 11233ad5d4ccSRichard Henderson OUTOP(INDEX_op_bswap64, TCGOutOpUnary, outop_bswap64), 1124f408df58SRichard Henderson #endif 11255500bd9eSRichard Henderson }; 11265500bd9eSRichard Henderson 1127662cdbcfSRichard Henderson #undef OUTOP 1128662cdbcfSRichard Henderson 1129e8feb96fSEmilio G. Cota /* 11303468b59eSEmilio G. Cota * All TCG threads except the parent (i.e. the one that called tcg_context_init 11313468b59eSEmilio G. Cota * and registered the target's TCG globals) must register with this function 11323468b59eSEmilio G. Cota * before initiating translation. 11333468b59eSEmilio G. Cota * 11343468b59eSEmilio G. Cota * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation 11353468b59eSEmilio G. Cota * of tcg_region_init() for the reasoning behind this. 11363468b59eSEmilio G. Cota * 11377893e42dSPhilippe Mathieu-Daudé * In system-mode each caller registers its context in tcg_ctxs[]. Note that in 11387893e42dSPhilippe Mathieu-Daudé * system-mode tcg_ctxs[] does not track tcg_ctx_init, since the initial context 11393468b59eSEmilio G. Cota * is not used anymore for translation once this function is called. 11403468b59eSEmilio G. Cota * 11417893e42dSPhilippe Mathieu-Daudé * Not tracking tcg_init_ctx in tcg_ctxs[] in system-mode keeps code that 11427893e42dSPhilippe Mathieu-Daudé * iterates over the array (e.g. tcg_code_size() the same for both system/user 11437893e42dSPhilippe Mathieu-Daudé * modes. 11443468b59eSEmilio G. Cota */ 11453468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY 11463468b59eSEmilio G. Cota void tcg_register_thread(void) 11473468b59eSEmilio G. Cota { 11483468b59eSEmilio G. Cota tcg_ctx = &tcg_init_ctx; 11493468b59eSEmilio G. Cota } 11503468b59eSEmilio G. Cota #else 11513468b59eSEmilio G. Cota void tcg_register_thread(void) 11523468b59eSEmilio G. Cota { 11533468b59eSEmilio G. Cota TCGContext *s = g_malloc(sizeof(*s)); 11543468b59eSEmilio G. Cota unsigned int i, n; 11553468b59eSEmilio G. Cota 11563468b59eSEmilio G. Cota *s = tcg_init_ctx; 11573468b59eSEmilio G. Cota 11583468b59eSEmilio G. Cota /* Relink mem_base. */ 11593468b59eSEmilio G. Cota for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) { 11603468b59eSEmilio G. Cota if (tcg_init_ctx.temps[i].mem_base) { 11613468b59eSEmilio G. Cota ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps; 11623468b59eSEmilio G. Cota tcg_debug_assert(b >= 0 && b < n); 11633468b59eSEmilio G. Cota s->temps[i].mem_base = &s->temps[b]; 11643468b59eSEmilio G. Cota } 11653468b59eSEmilio G. Cota } 11663468b59eSEmilio G. Cota 11673468b59eSEmilio G. Cota /* Claim an entry in tcg_ctxs */ 11680e2d61cfSRichard Henderson n = qatomic_fetch_inc(&tcg_cur_ctxs); 11690e2d61cfSRichard Henderson g_assert(n < tcg_max_ctxs); 1170d73415a3SStefan Hajnoczi qatomic_set(&tcg_ctxs[n], s); 11713468b59eSEmilio G. Cota 117238b47b19SEmilio G. Cota if (n > 0) { 1173bf042e8eSRichard Henderson tcg_region_initial_alloc(s); 117438b47b19SEmilio G. Cota } 117538b47b19SEmilio G. Cota 11763468b59eSEmilio G. Cota tcg_ctx = s; 11773468b59eSEmilio G. Cota } 11783468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */ 11793468b59eSEmilio G. Cota 1180c896fe29Sbellard /* pool based memory allocation */ 1181c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size) 1182c896fe29Sbellard { 1183c896fe29Sbellard TCGPool *p; 1184c896fe29Sbellard int pool_size; 1185c896fe29Sbellard 1186c896fe29Sbellard if (size > TCG_POOL_CHUNK_SIZE) { 1187c896fe29Sbellard /* big malloc: insert a new pool (XXX: could optimize) */ 11887267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + size); 1189c896fe29Sbellard p->size = size; 11904055299eSKirill Batuzov p->next = s->pool_first_large; 11914055299eSKirill Batuzov s->pool_first_large = p; 11924055299eSKirill Batuzov return p->data; 1193c896fe29Sbellard } else { 1194c896fe29Sbellard p = s->pool_current; 1195c896fe29Sbellard if (!p) { 1196c896fe29Sbellard p = s->pool_first; 1197c896fe29Sbellard if (!p) 1198c896fe29Sbellard goto new_pool; 1199c896fe29Sbellard } else { 1200c896fe29Sbellard if (!p->next) { 1201c896fe29Sbellard new_pool: 1202c896fe29Sbellard pool_size = TCG_POOL_CHUNK_SIZE; 12037267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + pool_size); 1204c896fe29Sbellard p->size = pool_size; 1205c896fe29Sbellard p->next = NULL; 1206a813e36fSRichard Henderson if (s->pool_current) { 1207c896fe29Sbellard s->pool_current->next = p; 1208a813e36fSRichard Henderson } else { 1209c896fe29Sbellard s->pool_first = p; 1210a813e36fSRichard Henderson } 1211c896fe29Sbellard } else { 1212c896fe29Sbellard p = p->next; 1213c896fe29Sbellard } 1214c896fe29Sbellard } 1215c896fe29Sbellard } 1216c896fe29Sbellard s->pool_current = p; 1217c896fe29Sbellard s->pool_cur = p->data + size; 1218c896fe29Sbellard s->pool_end = p->data + p->size; 1219c896fe29Sbellard return p->data; 1220c896fe29Sbellard } 1221c896fe29Sbellard 1222c896fe29Sbellard void tcg_pool_reset(TCGContext *s) 1223c896fe29Sbellard { 12244055299eSKirill Batuzov TCGPool *p, *t; 12254055299eSKirill Batuzov for (p = s->pool_first_large; p; p = t) { 12264055299eSKirill Batuzov t = p->next; 12274055299eSKirill Batuzov g_free(p); 12284055299eSKirill Batuzov } 12294055299eSKirill Batuzov s->pool_first_large = NULL; 1230c896fe29Sbellard s->pool_cur = s->pool_end = NULL; 1231c896fe29Sbellard s->pool_current = NULL; 1232c896fe29Sbellard } 1233c896fe29Sbellard 12348429a1caSRichard Henderson /* 12358429a1caSRichard Henderson * Create TCGHelperInfo structures for "tcg/tcg-ldst.h" functions, 12368429a1caSRichard Henderson * akin to what "exec/helper-tcg.h" does with DEF_HELPER_FLAGS_N. 12378429a1caSRichard Henderson * We only use these for layout in tcg_out_ld_helper_ret and 12388429a1caSRichard Henderson * tcg_out_st_helper_args, and share them between several of 12398429a1caSRichard Henderson * the helpers, with the end result that it's easier to build manually. 12408429a1caSRichard Henderson */ 12418429a1caSRichard Henderson 12428429a1caSRichard Henderson #if TCG_TARGET_REG_BITS == 32 12438429a1caSRichard Henderson # define dh_typecode_ttl dh_typecode_i32 12448429a1caSRichard Henderson #else 12458429a1caSRichard Henderson # define dh_typecode_ttl dh_typecode_i64 12468429a1caSRichard Henderson #endif 12478429a1caSRichard Henderson 12488429a1caSRichard Henderson static TCGHelperInfo info_helper_ld32_mmu = { 12498429a1caSRichard Henderson .flags = TCG_CALL_NO_WG, 12508429a1caSRichard Henderson .typemask = dh_typemask(ttl, 0) /* return tcg_target_ulong */ 12518429a1caSRichard Henderson | dh_typemask(env, 1) 125224e46e6cSRichard Henderson | dh_typemask(i64, 2) /* uint64_t addr */ 12538429a1caSRichard Henderson | dh_typemask(i32, 3) /* unsigned oi */ 12548429a1caSRichard Henderson | dh_typemask(ptr, 4) /* uintptr_t ra */ 12558429a1caSRichard Henderson }; 12568429a1caSRichard Henderson 12578429a1caSRichard Henderson static TCGHelperInfo info_helper_ld64_mmu = { 12588429a1caSRichard Henderson .flags = TCG_CALL_NO_WG, 12598429a1caSRichard Henderson .typemask = dh_typemask(i64, 0) /* return uint64_t */ 12608429a1caSRichard Henderson | dh_typemask(env, 1) 126124e46e6cSRichard Henderson | dh_typemask(i64, 2) /* uint64_t addr */ 12628429a1caSRichard Henderson | dh_typemask(i32, 3) /* unsigned oi */ 12638429a1caSRichard Henderson | dh_typemask(ptr, 4) /* uintptr_t ra */ 12648429a1caSRichard Henderson }; 12658429a1caSRichard Henderson 1266ebebea53SRichard Henderson static TCGHelperInfo info_helper_ld128_mmu = { 1267ebebea53SRichard Henderson .flags = TCG_CALL_NO_WG, 1268ebebea53SRichard Henderson .typemask = dh_typemask(i128, 0) /* return Int128 */ 1269ebebea53SRichard Henderson | dh_typemask(env, 1) 127024e46e6cSRichard Henderson | dh_typemask(i64, 2) /* uint64_t addr */ 1271ebebea53SRichard Henderson | dh_typemask(i32, 3) /* unsigned oi */ 1272ebebea53SRichard Henderson | dh_typemask(ptr, 4) /* uintptr_t ra */ 1273ebebea53SRichard Henderson }; 1274ebebea53SRichard Henderson 12758429a1caSRichard Henderson static TCGHelperInfo info_helper_st32_mmu = { 12768429a1caSRichard Henderson .flags = TCG_CALL_NO_WG, 12778429a1caSRichard Henderson .typemask = dh_typemask(void, 0) 12788429a1caSRichard Henderson | dh_typemask(env, 1) 127924e46e6cSRichard Henderson | dh_typemask(i64, 2) /* uint64_t addr */ 12808429a1caSRichard Henderson | dh_typemask(i32, 3) /* uint32_t data */ 12818429a1caSRichard Henderson | dh_typemask(i32, 4) /* unsigned oi */ 12828429a1caSRichard Henderson | dh_typemask(ptr, 5) /* uintptr_t ra */ 12838429a1caSRichard Henderson }; 12848429a1caSRichard Henderson 12858429a1caSRichard Henderson static TCGHelperInfo info_helper_st64_mmu = { 12868429a1caSRichard Henderson .flags = TCG_CALL_NO_WG, 12878429a1caSRichard Henderson .typemask = dh_typemask(void, 0) 12888429a1caSRichard Henderson | dh_typemask(env, 1) 128924e46e6cSRichard Henderson | dh_typemask(i64, 2) /* uint64_t addr */ 12908429a1caSRichard Henderson | dh_typemask(i64, 3) /* uint64_t data */ 12918429a1caSRichard Henderson | dh_typemask(i32, 4) /* unsigned oi */ 12928429a1caSRichard Henderson | dh_typemask(ptr, 5) /* uintptr_t ra */ 12938429a1caSRichard Henderson }; 12948429a1caSRichard Henderson 1295ebebea53SRichard Henderson static TCGHelperInfo info_helper_st128_mmu = { 1296ebebea53SRichard Henderson .flags = TCG_CALL_NO_WG, 1297ebebea53SRichard Henderson .typemask = dh_typemask(void, 0) 1298ebebea53SRichard Henderson | dh_typemask(env, 1) 129924e46e6cSRichard Henderson | dh_typemask(i64, 2) /* uint64_t addr */ 1300ebebea53SRichard Henderson | dh_typemask(i128, 3) /* Int128 data */ 1301ebebea53SRichard Henderson | dh_typemask(i32, 4) /* unsigned oi */ 1302ebebea53SRichard Henderson | dh_typemask(ptr, 5) /* uintptr_t ra */ 1303ebebea53SRichard Henderson }; 1304ebebea53SRichard Henderson 130522f15579SRichard Henderson #ifdef CONFIG_TCG_INTERPRETER 1306c6ef8c7bSPhilippe Mathieu-Daudé static ffi_type *typecode_to_ffi(int argmask) 1307c6ef8c7bSPhilippe Mathieu-Daudé { 1308e9709e17SRichard Henderson /* 1309e9709e17SRichard Henderson * libffi does not support __int128_t, so we have forced Int128 1310e9709e17SRichard Henderson * to use the structure definition instead of the builtin type. 1311e9709e17SRichard Henderson */ 1312e9709e17SRichard Henderson static ffi_type *ffi_type_i128_elements[3] = { 1313e9709e17SRichard Henderson &ffi_type_uint64, 1314e9709e17SRichard Henderson &ffi_type_uint64, 1315e9709e17SRichard Henderson NULL 1316e9709e17SRichard Henderson }; 1317e9709e17SRichard Henderson static ffi_type ffi_type_i128 = { 1318e9709e17SRichard Henderson .size = 16, 1319e9709e17SRichard Henderson .alignment = __alignof__(Int128), 1320e9709e17SRichard Henderson .type = FFI_TYPE_STRUCT, 1321e9709e17SRichard Henderson .elements = ffi_type_i128_elements, 1322e9709e17SRichard Henderson }; 1323e9709e17SRichard Henderson 1324c6ef8c7bSPhilippe Mathieu-Daudé switch (argmask) { 1325c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_void: 1326c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_void; 1327c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_i32: 1328c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_uint32; 1329c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_s32: 1330c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_sint32; 1331c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_i64: 1332c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_uint64; 1333c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_s64: 1334c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_sint64; 1335c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_ptr: 1336c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_pointer; 1337e9709e17SRichard Henderson case dh_typecode_i128: 1338e9709e17SRichard Henderson return &ffi_type_i128; 1339c6ef8c7bSPhilippe Mathieu-Daudé } 1340c6ef8c7bSPhilippe Mathieu-Daudé g_assert_not_reached(); 1341c6ef8c7bSPhilippe Mathieu-Daudé } 13420c22e176SPhilippe Mathieu-Daudé 1343d53106c9SRichard Henderson static ffi_cif *init_ffi_layout(TCGHelperInfo *info) 13440c22e176SPhilippe Mathieu-Daudé { 1345f9c4bb80SRichard Henderson unsigned typemask = info->typemask; 13460c22e176SPhilippe Mathieu-Daudé struct { 13470c22e176SPhilippe Mathieu-Daudé ffi_cif cif; 13480c22e176SPhilippe Mathieu-Daudé ffi_type *args[]; 13490c22e176SPhilippe Mathieu-Daudé } *ca; 13500c22e176SPhilippe Mathieu-Daudé ffi_status status; 13510c22e176SPhilippe Mathieu-Daudé int nargs; 13520c22e176SPhilippe Mathieu-Daudé 13530c22e176SPhilippe Mathieu-Daudé /* Ignoring the return type, find the last non-zero field. */ 13540c22e176SPhilippe Mathieu-Daudé nargs = 32 - clz32(typemask >> 3); 13550c22e176SPhilippe Mathieu-Daudé nargs = DIV_ROUND_UP(nargs, 3); 1356e9709e17SRichard Henderson assert(nargs <= MAX_CALL_IARGS); 13570c22e176SPhilippe Mathieu-Daudé 13580c22e176SPhilippe Mathieu-Daudé ca = g_malloc0(sizeof(*ca) + nargs * sizeof(ffi_type *)); 13590c22e176SPhilippe Mathieu-Daudé ca->cif.rtype = typecode_to_ffi(typemask & 7); 13600c22e176SPhilippe Mathieu-Daudé ca->cif.nargs = nargs; 13610c22e176SPhilippe Mathieu-Daudé 13620c22e176SPhilippe Mathieu-Daudé if (nargs != 0) { 13630c22e176SPhilippe Mathieu-Daudé ca->cif.arg_types = ca->args; 13640c22e176SPhilippe Mathieu-Daudé for (int j = 0; j < nargs; ++j) { 13650c22e176SPhilippe Mathieu-Daudé int typecode = extract32(typemask, (j + 1) * 3, 3); 13660c22e176SPhilippe Mathieu-Daudé ca->args[j] = typecode_to_ffi(typecode); 13670c22e176SPhilippe Mathieu-Daudé } 13680c22e176SPhilippe Mathieu-Daudé } 13690c22e176SPhilippe Mathieu-Daudé 13700c22e176SPhilippe Mathieu-Daudé status = ffi_prep_cif(&ca->cif, FFI_DEFAULT_ABI, nargs, 13710c22e176SPhilippe Mathieu-Daudé ca->cif.rtype, ca->cif.arg_types); 13720c22e176SPhilippe Mathieu-Daudé assert(status == FFI_OK); 13730c22e176SPhilippe Mathieu-Daudé 1374d53106c9SRichard Henderson return &ca->cif; 13750c22e176SPhilippe Mathieu-Daudé } 1376f9c4bb80SRichard Henderson 1377d53106c9SRichard Henderson #define HELPER_INFO_INIT(I) (&(I)->cif) 1378d53106c9SRichard Henderson #define HELPER_INFO_INIT_VAL(I) init_ffi_layout(I) 1379d53106c9SRichard Henderson #else 1380d53106c9SRichard Henderson #define HELPER_INFO_INIT(I) (&(I)->init) 1381d53106c9SRichard Henderson #define HELPER_INFO_INIT_VAL(I) 1 13820c22e176SPhilippe Mathieu-Daudé #endif /* CONFIG_TCG_INTERPRETER */ 138322f15579SRichard Henderson 1384338b61e9SRichard Henderson static inline bool arg_slot_reg_p(unsigned arg_slot) 1385338b61e9SRichard Henderson { 1386338b61e9SRichard Henderson /* 1387338b61e9SRichard Henderson * Split the sizeof away from the comparison to avoid Werror from 1388338b61e9SRichard Henderson * "unsigned < 0 is always false", when iarg_regs is empty. 1389338b61e9SRichard Henderson */ 1390338b61e9SRichard Henderson unsigned nreg = ARRAY_SIZE(tcg_target_call_iarg_regs); 1391338b61e9SRichard Henderson return arg_slot < nreg; 1392338b61e9SRichard Henderson } 1393338b61e9SRichard Henderson 1394d78e4a4fSRichard Henderson static inline int arg_slot_stk_ofs(unsigned arg_slot) 1395d78e4a4fSRichard Henderson { 1396d78e4a4fSRichard Henderson unsigned max = TCG_STATIC_CALL_ARGS_SIZE / sizeof(tcg_target_long); 1397d78e4a4fSRichard Henderson unsigned stk_slot = arg_slot - ARRAY_SIZE(tcg_target_call_iarg_regs); 1398d78e4a4fSRichard Henderson 1399d78e4a4fSRichard Henderson tcg_debug_assert(stk_slot < max); 1400d78e4a4fSRichard Henderson return TCG_TARGET_CALL_STACK_OFFSET + stk_slot * sizeof(tcg_target_long); 1401d78e4a4fSRichard Henderson } 1402d78e4a4fSRichard Henderson 140339004a71SRichard Henderson typedef struct TCGCumulativeArgs { 140439004a71SRichard Henderson int arg_idx; /* tcg_gen_callN args[] */ 140539004a71SRichard Henderson int info_in_idx; /* TCGHelperInfo in[] */ 140639004a71SRichard Henderson int arg_slot; /* regs+stack slot */ 140739004a71SRichard Henderson int ref_slot; /* stack slots for references */ 140839004a71SRichard Henderson } TCGCumulativeArgs; 140939004a71SRichard Henderson 141039004a71SRichard Henderson static void layout_arg_even(TCGCumulativeArgs *cum) 141139004a71SRichard Henderson { 141239004a71SRichard Henderson cum->arg_slot += cum->arg_slot & 1; 141339004a71SRichard Henderson } 141439004a71SRichard Henderson 141539004a71SRichard Henderson static void layout_arg_1(TCGCumulativeArgs *cum, TCGHelperInfo *info, 141639004a71SRichard Henderson TCGCallArgumentKind kind) 141739004a71SRichard Henderson { 141839004a71SRichard Henderson TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx]; 141939004a71SRichard Henderson 142039004a71SRichard Henderson *loc = (TCGCallArgumentLoc){ 142139004a71SRichard Henderson .kind = kind, 142239004a71SRichard Henderson .arg_idx = cum->arg_idx, 142339004a71SRichard Henderson .arg_slot = cum->arg_slot, 142439004a71SRichard Henderson }; 142539004a71SRichard Henderson cum->info_in_idx++; 142639004a71SRichard Henderson cum->arg_slot++; 142739004a71SRichard Henderson } 142839004a71SRichard Henderson 142939004a71SRichard Henderson static void layout_arg_normal_n(TCGCumulativeArgs *cum, 143039004a71SRichard Henderson TCGHelperInfo *info, int n) 143139004a71SRichard Henderson { 143239004a71SRichard Henderson TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx]; 143339004a71SRichard Henderson 143439004a71SRichard Henderson for (int i = 0; i < n; ++i) { 143539004a71SRichard Henderson /* Layout all using the same arg_idx, adjusting the subindex. */ 143639004a71SRichard Henderson loc[i] = (TCGCallArgumentLoc){ 143739004a71SRichard Henderson .kind = TCG_CALL_ARG_NORMAL, 143839004a71SRichard Henderson .arg_idx = cum->arg_idx, 143939004a71SRichard Henderson .tmp_subindex = i, 144039004a71SRichard Henderson .arg_slot = cum->arg_slot + i, 144139004a71SRichard Henderson }; 144239004a71SRichard Henderson } 144339004a71SRichard Henderson cum->info_in_idx += n; 144439004a71SRichard Henderson cum->arg_slot += n; 144539004a71SRichard Henderson } 144639004a71SRichard Henderson 1447313bdea8SRichard Henderson static void layout_arg_by_ref(TCGCumulativeArgs *cum, TCGHelperInfo *info) 1448313bdea8SRichard Henderson { 1449313bdea8SRichard Henderson TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx]; 1450313bdea8SRichard Henderson int n = 128 / TCG_TARGET_REG_BITS; 1451313bdea8SRichard Henderson 1452313bdea8SRichard Henderson /* The first subindex carries the pointer. */ 1453313bdea8SRichard Henderson layout_arg_1(cum, info, TCG_CALL_ARG_BY_REF); 1454313bdea8SRichard Henderson 1455313bdea8SRichard Henderson /* 1456313bdea8SRichard Henderson * The callee is allowed to clobber memory associated with 1457313bdea8SRichard Henderson * structure pass by-reference. Therefore we must make copies. 1458313bdea8SRichard Henderson * Allocate space from "ref_slot", which will be adjusted to 1459313bdea8SRichard Henderson * follow the parameters on the stack. 1460313bdea8SRichard Henderson */ 1461313bdea8SRichard Henderson loc[0].ref_slot = cum->ref_slot; 1462313bdea8SRichard Henderson 1463313bdea8SRichard Henderson /* 1464313bdea8SRichard Henderson * Subsequent words also go into the reference slot, but 1465313bdea8SRichard Henderson * do not accumulate into the regular arguments. 1466313bdea8SRichard Henderson */ 1467313bdea8SRichard Henderson for (int i = 1; i < n; ++i) { 1468313bdea8SRichard Henderson loc[i] = (TCGCallArgumentLoc){ 1469313bdea8SRichard Henderson .kind = TCG_CALL_ARG_BY_REF_N, 1470313bdea8SRichard Henderson .arg_idx = cum->arg_idx, 1471313bdea8SRichard Henderson .tmp_subindex = i, 1472313bdea8SRichard Henderson .ref_slot = cum->ref_slot + i, 1473313bdea8SRichard Henderson }; 1474313bdea8SRichard Henderson } 1475e18ed26cSRichard Henderson cum->info_in_idx += n - 1; /* i=0 accounted for in layout_arg_1 */ 1476313bdea8SRichard Henderson cum->ref_slot += n; 1477313bdea8SRichard Henderson } 1478313bdea8SRichard Henderson 147939004a71SRichard Henderson static void init_call_layout(TCGHelperInfo *info) 148039004a71SRichard Henderson { 148139004a71SRichard Henderson int max_reg_slots = ARRAY_SIZE(tcg_target_call_iarg_regs); 148239004a71SRichard Henderson int max_stk_slots = TCG_STATIC_CALL_ARGS_SIZE / sizeof(tcg_target_long); 148339004a71SRichard Henderson unsigned typemask = info->typemask; 148439004a71SRichard Henderson unsigned typecode; 148539004a71SRichard Henderson TCGCumulativeArgs cum = { }; 148639004a71SRichard Henderson 148739004a71SRichard Henderson /* 148839004a71SRichard Henderson * Parse and place any function return value. 148939004a71SRichard Henderson */ 149039004a71SRichard Henderson typecode = typemask & 7; 149139004a71SRichard Henderson switch (typecode) { 149239004a71SRichard Henderson case dh_typecode_void: 149339004a71SRichard Henderson info->nr_out = 0; 149439004a71SRichard Henderson break; 149539004a71SRichard Henderson case dh_typecode_i32: 149639004a71SRichard Henderson case dh_typecode_s32: 149739004a71SRichard Henderson case dh_typecode_ptr: 149839004a71SRichard Henderson info->nr_out = 1; 149939004a71SRichard Henderson info->out_kind = TCG_CALL_RET_NORMAL; 150039004a71SRichard Henderson break; 150139004a71SRichard Henderson case dh_typecode_i64: 150239004a71SRichard Henderson case dh_typecode_s64: 150339004a71SRichard Henderson info->nr_out = 64 / TCG_TARGET_REG_BITS; 150439004a71SRichard Henderson info->out_kind = TCG_CALL_RET_NORMAL; 15055e3d0c19SRichard Henderson /* Query the last register now to trigger any assert early. */ 15065e3d0c19SRichard Henderson tcg_target_call_oarg_reg(info->out_kind, info->nr_out - 1); 1507466d3759SRichard Henderson break; 1508466d3759SRichard Henderson case dh_typecode_i128: 1509466d3759SRichard Henderson info->nr_out = 128 / TCG_TARGET_REG_BITS; 15105427a9a7SRichard Henderson info->out_kind = TCG_TARGET_CALL_RET_I128; 15115427a9a7SRichard Henderson switch (TCG_TARGET_CALL_RET_I128) { 1512466d3759SRichard Henderson case TCG_CALL_RET_NORMAL: 15135e3d0c19SRichard Henderson /* Query the last register now to trigger any assert early. */ 15145e3d0c19SRichard Henderson tcg_target_call_oarg_reg(info->out_kind, info->nr_out - 1); 1515466d3759SRichard Henderson break; 1516c6556aa0SRichard Henderson case TCG_CALL_RET_BY_VEC: 1517c6556aa0SRichard Henderson /* Query the single register now to trigger any assert early. */ 1518c6556aa0SRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0); 1519c6556aa0SRichard Henderson break; 1520313bdea8SRichard Henderson case TCG_CALL_RET_BY_REF: 1521313bdea8SRichard Henderson /* 1522313bdea8SRichard Henderson * Allocate the first argument to the output. 1523313bdea8SRichard Henderson * We don't need to store this anywhere, just make it 1524313bdea8SRichard Henderson * unavailable for use in the input loop below. 1525313bdea8SRichard Henderson */ 1526313bdea8SRichard Henderson cum.arg_slot = 1; 1527313bdea8SRichard Henderson break; 1528466d3759SRichard Henderson default: 1529466d3759SRichard Henderson qemu_build_not_reached(); 1530466d3759SRichard Henderson } 153139004a71SRichard Henderson break; 153239004a71SRichard Henderson default: 153339004a71SRichard Henderson g_assert_not_reached(); 153439004a71SRichard Henderson } 153539004a71SRichard Henderson 153639004a71SRichard Henderson /* 153739004a71SRichard Henderson * Parse and place function arguments. 153839004a71SRichard Henderson */ 153939004a71SRichard Henderson for (typemask >>= 3; typemask; typemask >>= 3, cum.arg_idx++) { 154039004a71SRichard Henderson TCGCallArgumentKind kind; 154139004a71SRichard Henderson TCGType type; 154239004a71SRichard Henderson 154339004a71SRichard Henderson typecode = typemask & 7; 154439004a71SRichard Henderson switch (typecode) { 154539004a71SRichard Henderson case dh_typecode_i32: 154639004a71SRichard Henderson case dh_typecode_s32: 154739004a71SRichard Henderson type = TCG_TYPE_I32; 154839004a71SRichard Henderson break; 154939004a71SRichard Henderson case dh_typecode_i64: 155039004a71SRichard Henderson case dh_typecode_s64: 155139004a71SRichard Henderson type = TCG_TYPE_I64; 155239004a71SRichard Henderson break; 155339004a71SRichard Henderson case dh_typecode_ptr: 155439004a71SRichard Henderson type = TCG_TYPE_PTR; 155539004a71SRichard Henderson break; 1556466d3759SRichard Henderson case dh_typecode_i128: 1557466d3759SRichard Henderson type = TCG_TYPE_I128; 1558466d3759SRichard Henderson break; 155939004a71SRichard Henderson default: 156039004a71SRichard Henderson g_assert_not_reached(); 156139004a71SRichard Henderson } 156239004a71SRichard Henderson 156339004a71SRichard Henderson switch (type) { 156439004a71SRichard Henderson case TCG_TYPE_I32: 156539004a71SRichard Henderson switch (TCG_TARGET_CALL_ARG_I32) { 156639004a71SRichard Henderson case TCG_CALL_ARG_EVEN: 156739004a71SRichard Henderson layout_arg_even(&cum); 156839004a71SRichard Henderson /* fall through */ 156939004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 157039004a71SRichard Henderson layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL); 157139004a71SRichard Henderson break; 157239004a71SRichard Henderson case TCG_CALL_ARG_EXTEND: 157339004a71SRichard Henderson kind = TCG_CALL_ARG_EXTEND_U + (typecode & 1); 157439004a71SRichard Henderson layout_arg_1(&cum, info, kind); 157539004a71SRichard Henderson break; 157639004a71SRichard Henderson default: 157739004a71SRichard Henderson qemu_build_not_reached(); 157839004a71SRichard Henderson } 157939004a71SRichard Henderson break; 158039004a71SRichard Henderson 158139004a71SRichard Henderson case TCG_TYPE_I64: 158239004a71SRichard Henderson switch (TCG_TARGET_CALL_ARG_I64) { 158339004a71SRichard Henderson case TCG_CALL_ARG_EVEN: 158439004a71SRichard Henderson layout_arg_even(&cum); 158539004a71SRichard Henderson /* fall through */ 158639004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 158739004a71SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 158839004a71SRichard Henderson layout_arg_normal_n(&cum, info, 2); 158939004a71SRichard Henderson } else { 159039004a71SRichard Henderson layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL); 159139004a71SRichard Henderson } 159239004a71SRichard Henderson break; 159339004a71SRichard Henderson default: 159439004a71SRichard Henderson qemu_build_not_reached(); 159539004a71SRichard Henderson } 159639004a71SRichard Henderson break; 159739004a71SRichard Henderson 1598466d3759SRichard Henderson case TCG_TYPE_I128: 15995427a9a7SRichard Henderson switch (TCG_TARGET_CALL_ARG_I128) { 1600466d3759SRichard Henderson case TCG_CALL_ARG_EVEN: 1601466d3759SRichard Henderson layout_arg_even(&cum); 1602466d3759SRichard Henderson /* fall through */ 1603466d3759SRichard Henderson case TCG_CALL_ARG_NORMAL: 1604466d3759SRichard Henderson layout_arg_normal_n(&cum, info, 128 / TCG_TARGET_REG_BITS); 1605466d3759SRichard Henderson break; 1606313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF: 1607313bdea8SRichard Henderson layout_arg_by_ref(&cum, info); 1608313bdea8SRichard Henderson break; 1609466d3759SRichard Henderson default: 1610466d3759SRichard Henderson qemu_build_not_reached(); 1611466d3759SRichard Henderson } 1612466d3759SRichard Henderson break; 1613466d3759SRichard Henderson 161439004a71SRichard Henderson default: 161539004a71SRichard Henderson g_assert_not_reached(); 161639004a71SRichard Henderson } 161739004a71SRichard Henderson } 161839004a71SRichard Henderson info->nr_in = cum.info_in_idx; 161939004a71SRichard Henderson 162039004a71SRichard Henderson /* Validate that we didn't overrun the input array. */ 162139004a71SRichard Henderson assert(cum.info_in_idx <= ARRAY_SIZE(info->in)); 162239004a71SRichard Henderson /* Validate the backend has enough argument space. */ 162339004a71SRichard Henderson assert(cum.arg_slot <= max_reg_slots + max_stk_slots); 1624313bdea8SRichard Henderson 1625313bdea8SRichard Henderson /* 1626313bdea8SRichard Henderson * Relocate the "ref_slot" area to the end of the parameters. 1627313bdea8SRichard Henderson * Minimizing this stack offset helps code size for x86, 1628313bdea8SRichard Henderson * which has a signed 8-bit offset encoding. 1629313bdea8SRichard Henderson */ 1630313bdea8SRichard Henderson if (cum.ref_slot != 0) { 1631313bdea8SRichard Henderson int ref_base = 0; 1632313bdea8SRichard Henderson 1633313bdea8SRichard Henderson if (cum.arg_slot > max_reg_slots) { 1634313bdea8SRichard Henderson int align = __alignof(Int128) / sizeof(tcg_target_long); 1635313bdea8SRichard Henderson 1636313bdea8SRichard Henderson ref_base = cum.arg_slot - max_reg_slots; 1637313bdea8SRichard Henderson if (align > 1) { 1638313bdea8SRichard Henderson ref_base = ROUND_UP(ref_base, align); 1639313bdea8SRichard Henderson } 1640313bdea8SRichard Henderson } 1641313bdea8SRichard Henderson assert(ref_base + cum.ref_slot <= max_stk_slots); 1642d78e4a4fSRichard Henderson ref_base += max_reg_slots; 1643313bdea8SRichard Henderson 1644313bdea8SRichard Henderson if (ref_base != 0) { 1645313bdea8SRichard Henderson for (int i = cum.info_in_idx - 1; i >= 0; --i) { 1646313bdea8SRichard Henderson TCGCallArgumentLoc *loc = &info->in[i]; 1647313bdea8SRichard Henderson switch (loc->kind) { 1648313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF: 1649313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF_N: 1650313bdea8SRichard Henderson loc->ref_slot += ref_base; 1651313bdea8SRichard Henderson break; 1652313bdea8SRichard Henderson default: 1653313bdea8SRichard Henderson break; 1654313bdea8SRichard Henderson } 1655313bdea8SRichard Henderson } 1656313bdea8SRichard Henderson } 1657313bdea8SRichard Henderson } 165839004a71SRichard Henderson } 165939004a71SRichard Henderson 166091478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)]; 1661501fb3daSRichard Henderson static void process_constraint_sets(void); 16621c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type, 16631c2adb95SRichard Henderson TCGReg reg, const char *name); 166491478cefSRichard Henderson 1665a9d107faSRichard Henderson static void tcg_context_init(unsigned max_threads) 1666c896fe29Sbellard { 1667a76aabd3SRichard Henderson TCGContext *s = &tcg_init_ctx; 16683e80824eSRichard Henderson int n, i; 16691c2adb95SRichard Henderson TCGTemp *ts; 1670c896fe29Sbellard 1671c896fe29Sbellard memset(s, 0, sizeof(*s)); 1672c896fe29Sbellard s->nb_globals = 0; 1673c896fe29Sbellard 16748429a1caSRichard Henderson init_call_layout(&info_helper_ld32_mmu); 16758429a1caSRichard Henderson init_call_layout(&info_helper_ld64_mmu); 1676ebebea53SRichard Henderson init_call_layout(&info_helper_ld128_mmu); 16778429a1caSRichard Henderson init_call_layout(&info_helper_st32_mmu); 16788429a1caSRichard Henderson init_call_layout(&info_helper_st64_mmu); 1679ebebea53SRichard Henderson init_call_layout(&info_helper_st128_mmu); 16808429a1caSRichard Henderson 1681c896fe29Sbellard tcg_target_init(s); 1682501fb3daSRichard Henderson process_constraint_sets(); 168391478cefSRichard Henderson 168491478cefSRichard Henderson /* Reverse the order of the saved registers, assuming they're all at 168591478cefSRichard Henderson the start of tcg_target_reg_alloc_order. */ 168691478cefSRichard Henderson for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) { 168791478cefSRichard Henderson int r = tcg_target_reg_alloc_order[n]; 168891478cefSRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) { 168991478cefSRichard Henderson break; 169091478cefSRichard Henderson } 169191478cefSRichard Henderson } 169291478cefSRichard Henderson for (i = 0; i < n; ++i) { 169391478cefSRichard Henderson indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i]; 169491478cefSRichard Henderson } 169591478cefSRichard Henderson for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) { 169691478cefSRichard Henderson indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i]; 169791478cefSRichard Henderson } 1698b1311c4aSEmilio G. Cota 1699b1311c4aSEmilio G. Cota tcg_ctx = s; 17003468b59eSEmilio G. Cota /* 17013468b59eSEmilio G. Cota * In user-mode we simply share the init context among threads, since we 17023468b59eSEmilio G. Cota * use a single region. See the documentation tcg_region_init() for the 17033468b59eSEmilio G. Cota * reasoning behind this. 1704a9d107faSRichard Henderson * In system-mode we will have at most max_threads TCG threads. 17053468b59eSEmilio G. Cota */ 17063468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY 1707df2cce29SEmilio G. Cota tcg_ctxs = &tcg_ctx; 17080e2d61cfSRichard Henderson tcg_cur_ctxs = 1; 17090e2d61cfSRichard Henderson tcg_max_ctxs = 1; 17103468b59eSEmilio G. Cota #else 1711a9d107faSRichard Henderson tcg_max_ctxs = max_threads; 1712a9d107faSRichard Henderson tcg_ctxs = g_new0(TCGContext *, max_threads); 17133468b59eSEmilio G. Cota #endif 17141c2adb95SRichard Henderson 17151c2adb95SRichard Henderson tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0)); 17161c2adb95SRichard Henderson ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env"); 1717ad75a51eSRichard Henderson tcg_env = temp_tcgv_ptr(ts); 17189002ec79SRichard Henderson } 1719b03cce8eSbellard 1720a9d107faSRichard Henderson void tcg_init(size_t tb_size, int splitwx, unsigned max_threads) 1721a76aabd3SRichard Henderson { 1722a9d107faSRichard Henderson tcg_context_init(max_threads); 1723a9d107faSRichard Henderson tcg_region_init(tb_size, splitwx, max_threads); 1724a76aabd3SRichard Henderson } 1725a76aabd3SRichard Henderson 17266e3b2bfdSEmilio G. Cota /* 17276e3b2bfdSEmilio G. Cota * Allocate TBs right before their corresponding translated code, making 17286e3b2bfdSEmilio G. Cota * sure that TBs and code are on different cache lines. 17296e3b2bfdSEmilio G. Cota */ 17306e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s) 17316e3b2bfdSEmilio G. Cota { 17326e3b2bfdSEmilio G. Cota uintptr_t align = qemu_icache_linesize; 17336e3b2bfdSEmilio G. Cota TranslationBlock *tb; 17346e3b2bfdSEmilio G. Cota void *next; 17356e3b2bfdSEmilio G. Cota 1736e8feb96fSEmilio G. Cota retry: 17376e3b2bfdSEmilio G. Cota tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align); 17386e3b2bfdSEmilio G. Cota next = (void *)ROUND_UP((uintptr_t)(tb + 1), align); 17396e3b2bfdSEmilio G. Cota 17406e3b2bfdSEmilio G. Cota if (unlikely(next > s->code_gen_highwater)) { 1741e8feb96fSEmilio G. Cota if (tcg_region_alloc(s)) { 17426e3b2bfdSEmilio G. Cota return NULL; 17436e3b2bfdSEmilio G. Cota } 1744e8feb96fSEmilio G. Cota goto retry; 1745e8feb96fSEmilio G. Cota } 1746d73415a3SStefan Hajnoczi qatomic_set(&s->code_gen_ptr, next); 17476e3b2bfdSEmilio G. Cota return tb; 17486e3b2bfdSEmilio G. Cota } 17496e3b2bfdSEmilio G. Cota 1750935f75aeSRichard Henderson void tcg_prologue_init(void) 17519002ec79SRichard Henderson { 1752935f75aeSRichard Henderson TCGContext *s = tcg_ctx; 1753b0a0794aSRichard Henderson size_t prologue_size; 17548163b749SRichard Henderson 1755b0a0794aSRichard Henderson s->code_ptr = s->code_gen_ptr; 1756b0a0794aSRichard Henderson s->code_buf = s->code_gen_ptr; 17575b38ee31SRichard Henderson s->data_gen_ptr = NULL; 1758b91ccb31SRichard Henderson 1759b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 1760b0a0794aSRichard Henderson tcg_qemu_tb_exec = (tcg_prologue_fn *)tcg_splitwx_to_rx(s->code_ptr); 1761b91ccb31SRichard Henderson #endif 17628163b749SRichard Henderson 17635b38ee31SRichard Henderson s->pool_labels = NULL; 17645b38ee31SRichard Henderson 1765653b87ebSRoman Bolshakov qemu_thread_jit_write(); 17668163b749SRichard Henderson /* Generate the prologue. */ 1767b03cce8eSbellard tcg_target_qemu_prologue(s); 17685b38ee31SRichard Henderson 17695b38ee31SRichard Henderson /* Allow the prologue to put e.g. guest_base into a pool entry. */ 17705b38ee31SRichard Henderson { 17711768987bSRichard Henderson int result = tcg_out_pool_finalize(s); 17721768987bSRichard Henderson tcg_debug_assert(result == 0); 17735b38ee31SRichard Henderson } 17745b38ee31SRichard Henderson 1775b0a0794aSRichard Henderson prologue_size = tcg_current_code_size(s); 17765584e2dbSIlya Leoshkevich perf_report_prologue(s->code_gen_ptr, prologue_size); 1777b0a0794aSRichard Henderson 1778df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 1779b0a0794aSRichard Henderson flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf), 1780b0a0794aSRichard Henderson (uintptr_t)s->code_buf, prologue_size); 1781df5d2b16SRichard Henderson #endif 17828163b749SRichard Henderson 1783d6b64b2bSRichard Henderson if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) { 1784c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock(); 178578b54858SRichard Henderson if (logfile) { 178678b54858SRichard Henderson fprintf(logfile, "PROLOGUE: [size=%zu]\n", prologue_size); 17875b38ee31SRichard Henderson if (s->data_gen_ptr) { 1788b0a0794aSRichard Henderson size_t code_size = s->data_gen_ptr - s->code_gen_ptr; 17895b38ee31SRichard Henderson size_t data_size = prologue_size - code_size; 17905b38ee31SRichard Henderson size_t i; 17915b38ee31SRichard Henderson 179278b54858SRichard Henderson disas(logfile, s->code_gen_ptr, code_size); 17935b38ee31SRichard Henderson 17945b38ee31SRichard Henderson for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) { 17955b38ee31SRichard Henderson if (sizeof(tcg_target_ulong) == 8) { 179678b54858SRichard Henderson fprintf(logfile, 179778b54858SRichard Henderson "0x%08" PRIxPTR ": .quad 0x%016" PRIx64 "\n", 17985b38ee31SRichard Henderson (uintptr_t)s->data_gen_ptr + i, 17995b38ee31SRichard Henderson *(uint64_t *)(s->data_gen_ptr + i)); 18005b38ee31SRichard Henderson } else { 180178b54858SRichard Henderson fprintf(logfile, 180278b54858SRichard Henderson "0x%08" PRIxPTR ": .long 0x%08x\n", 18035b38ee31SRichard Henderson (uintptr_t)s->data_gen_ptr + i, 18045b38ee31SRichard Henderson *(uint32_t *)(s->data_gen_ptr + i)); 18055b38ee31SRichard Henderson } 18065b38ee31SRichard Henderson } 18075b38ee31SRichard Henderson } else { 180878b54858SRichard Henderson disas(logfile, s->code_gen_ptr, prologue_size); 18095b38ee31SRichard Henderson } 181078b54858SRichard Henderson fprintf(logfile, "\n"); 1811fc59d2d8SRobert Foley qemu_log_unlock(logfile); 1812d6b64b2bSRichard Henderson } 181378b54858SRichard Henderson } 1814cedbcb01SEmilio G. Cota 18156eea0434SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 18166eea0434SRichard Henderson /* 18176eea0434SRichard Henderson * Assert that goto_ptr is implemented completely, setting an epilogue. 18186eea0434SRichard Henderson * For tci, we use NULL as the signal to return from the interpreter, 18196eea0434SRichard Henderson * so skip this check. 18206eea0434SRichard Henderson */ 18218b5c2b62SRichard Henderson tcg_debug_assert(tcg_code_gen_epilogue != NULL); 18226eea0434SRichard Henderson #endif 1823d1c74ab3SRichard Henderson 1824d1c74ab3SRichard Henderson tcg_region_prologue_set(s); 1825c896fe29Sbellard } 1826c896fe29Sbellard 1827c896fe29Sbellard void tcg_func_start(TCGContext *s) 1828c896fe29Sbellard { 1829c896fe29Sbellard tcg_pool_reset(s); 1830c896fe29Sbellard s->nb_temps = s->nb_globals; 18310ec9eabcSRichard Henderson 18320ec9eabcSRichard Henderson /* No temps have been previously allocated for size or locality. */ 183304e006abSRichard Henderson tcg_temp_ebb_reset_freed(s); 18340ec9eabcSRichard Henderson 1835c0522136SRichard Henderson /* No constant temps have been previously allocated. */ 1836c0522136SRichard Henderson for (int i = 0; i < TCG_TYPE_COUNT; ++i) { 1837c0522136SRichard Henderson if (s->const_table[i]) { 1838c0522136SRichard Henderson g_hash_table_remove_all(s->const_table[i]); 1839c0522136SRichard Henderson } 1840c0522136SRichard Henderson } 1841c0522136SRichard Henderson 1842abebf925SRichard Henderson s->nb_ops = 0; 1843c896fe29Sbellard s->nb_labels = 0; 1844c896fe29Sbellard s->current_frame_offset = s->frame_start; 1845c896fe29Sbellard 18460a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG 18470a209d4bSRichard Henderson s->goto_tb_issue_mask = 0; 18480a209d4bSRichard Henderson #endif 18490a209d4bSRichard Henderson 185015fa08f8SRichard Henderson QTAILQ_INIT(&s->ops); 185115fa08f8SRichard Henderson QTAILQ_INIT(&s->free_ops); 185207843f75SRichard Henderson s->emit_before_op = NULL; 1853bef16ab4SRichard Henderson QSIMPLEQ_INIT(&s->labels); 18544baf3978SRichard Henderson 1855a0ecb8e4SRichard Henderson tcg_debug_assert(s->addr_type <= TCG_TYPE_REG); 1856747bd69dSRichard Henderson tcg_debug_assert(s->insn_start_words > 0); 1857c896fe29Sbellard } 1858c896fe29Sbellard 1859ae30e866SRichard Henderson static TCGTemp *tcg_temp_alloc(TCGContext *s) 18607ca4b752SRichard Henderson { 18617ca4b752SRichard Henderson int n = s->nb_temps++; 1862ae30e866SRichard Henderson 1863ae30e866SRichard Henderson if (n >= TCG_MAX_TEMPS) { 1864db6b7d0cSRichard Henderson tcg_raise_tb_overflow(s); 1865ae30e866SRichard Henderson } 18667ca4b752SRichard Henderson return memset(&s->temps[n], 0, sizeof(TCGTemp)); 18677ca4b752SRichard Henderson } 18687ca4b752SRichard Henderson 1869ae30e866SRichard Henderson static TCGTemp *tcg_global_alloc(TCGContext *s) 18707ca4b752SRichard Henderson { 1871fa477d25SRichard Henderson TCGTemp *ts; 1872fa477d25SRichard Henderson 18737ca4b752SRichard Henderson tcg_debug_assert(s->nb_globals == s->nb_temps); 1874ae30e866SRichard Henderson tcg_debug_assert(s->nb_globals < TCG_MAX_TEMPS); 18757ca4b752SRichard Henderson s->nb_globals++; 1876fa477d25SRichard Henderson ts = tcg_temp_alloc(s); 1877ee17db83SRichard Henderson ts->kind = TEMP_GLOBAL; 1878fa477d25SRichard Henderson 1879fa477d25SRichard Henderson return ts; 1880c896fe29Sbellard } 1881c896fe29Sbellard 1882085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type, 1883b6638662SRichard Henderson TCGReg reg, const char *name) 1884c896fe29Sbellard { 1885c896fe29Sbellard TCGTemp *ts; 1886c896fe29Sbellard 18871a057554SRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 64 || type == TCG_TYPE_I32); 18887ca4b752SRichard Henderson 18897ca4b752SRichard Henderson ts = tcg_global_alloc(s); 1890c896fe29Sbellard ts->base_type = type; 1891c896fe29Sbellard ts->type = type; 1892ee17db83SRichard Henderson ts->kind = TEMP_FIXED; 1893c896fe29Sbellard ts->reg = reg; 1894c896fe29Sbellard ts->name = name; 1895c896fe29Sbellard tcg_regset_set_reg(s->reserved_regs, reg); 18967ca4b752SRichard Henderson 1897085272b3SRichard Henderson return ts; 1898a7812ae4Spbrook } 1899a7812ae4Spbrook 1900b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size) 1901a7812ae4Spbrook { 1902b3a62939SRichard Henderson s->frame_start = start; 1903b3a62939SRichard Henderson s->frame_end = start + size; 1904085272b3SRichard Henderson s->frame_temp 1905085272b3SRichard Henderson = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame"); 1906b3a62939SRichard Henderson } 1907a7812ae4Spbrook 19084643f3e0SRichard Henderson static TCGTemp *tcg_global_mem_new_internal(TCGv_ptr base, intptr_t offset, 19094643f3e0SRichard Henderson const char *name, TCGType type) 1910c896fe29Sbellard { 1911b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1912dc41aa7dSRichard Henderson TCGTemp *base_ts = tcgv_ptr_temp(base); 19137ca4b752SRichard Henderson TCGTemp *ts = tcg_global_alloc(s); 1914aef85402SRichard Henderson int indirect_reg = 0; 1915c896fe29Sbellard 1916c0522136SRichard Henderson switch (base_ts->kind) { 1917c0522136SRichard Henderson case TEMP_FIXED: 1918c0522136SRichard Henderson break; 1919c0522136SRichard Henderson case TEMP_GLOBAL: 19205a18407fSRichard Henderson /* We do not support double-indirect registers. */ 19215a18407fSRichard Henderson tcg_debug_assert(!base_ts->indirect_reg); 1922b3915dbbSRichard Henderson base_ts->indirect_base = 1; 19235a18407fSRichard Henderson s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64 19245a18407fSRichard Henderson ? 2 : 1); 19255a18407fSRichard Henderson indirect_reg = 1; 1926c0522136SRichard Henderson break; 1927c0522136SRichard Henderson default: 1928c0522136SRichard Henderson g_assert_not_reached(); 1929b3915dbbSRichard Henderson } 1930b3915dbbSRichard Henderson 19317ca4b752SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { 19327ca4b752SRichard Henderson TCGTemp *ts2 = tcg_global_alloc(s); 1933c896fe29Sbellard char buf[64]; 19347ca4b752SRichard Henderson 19357ca4b752SRichard Henderson ts->base_type = TCG_TYPE_I64; 1936c896fe29Sbellard ts->type = TCG_TYPE_I32; 1937b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg; 1938c896fe29Sbellard ts->mem_allocated = 1; 1939b3a62939SRichard Henderson ts->mem_base = base_ts; 1940aef85402SRichard Henderson ts->mem_offset = offset; 1941c896fe29Sbellard pstrcpy(buf, sizeof(buf), name); 1942c896fe29Sbellard pstrcat(buf, sizeof(buf), "_0"); 1943c896fe29Sbellard ts->name = strdup(buf); 1944c896fe29Sbellard 19457ca4b752SRichard Henderson tcg_debug_assert(ts2 == ts + 1); 19467ca4b752SRichard Henderson ts2->base_type = TCG_TYPE_I64; 19477ca4b752SRichard Henderson ts2->type = TCG_TYPE_I32; 1948b3915dbbSRichard Henderson ts2->indirect_reg = indirect_reg; 19497ca4b752SRichard Henderson ts2->mem_allocated = 1; 19507ca4b752SRichard Henderson ts2->mem_base = base_ts; 1951aef85402SRichard Henderson ts2->mem_offset = offset + 4; 1952fac87bd2SRichard Henderson ts2->temp_subindex = 1; 1953c896fe29Sbellard pstrcpy(buf, sizeof(buf), name); 1954c896fe29Sbellard pstrcat(buf, sizeof(buf), "_1"); 1955120c1084SRichard Henderson ts2->name = strdup(buf); 19567ca4b752SRichard Henderson } else { 1957c896fe29Sbellard ts->base_type = type; 1958c896fe29Sbellard ts->type = type; 1959b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg; 1960c896fe29Sbellard ts->mem_allocated = 1; 1961b3a62939SRichard Henderson ts->mem_base = base_ts; 1962c896fe29Sbellard ts->mem_offset = offset; 1963c896fe29Sbellard ts->name = name; 1964c896fe29Sbellard } 1965085272b3SRichard Henderson return ts; 1966c896fe29Sbellard } 1967c896fe29Sbellard 19684643f3e0SRichard Henderson TCGv_i32 tcg_global_mem_new_i32(TCGv_ptr reg, intptr_t off, const char *name) 19694643f3e0SRichard Henderson { 19704643f3e0SRichard Henderson TCGTemp *ts = tcg_global_mem_new_internal(reg, off, name, TCG_TYPE_I32); 19714643f3e0SRichard Henderson return temp_tcgv_i32(ts); 19724643f3e0SRichard Henderson } 19734643f3e0SRichard Henderson 19744643f3e0SRichard Henderson TCGv_i64 tcg_global_mem_new_i64(TCGv_ptr reg, intptr_t off, const char *name) 19754643f3e0SRichard Henderson { 19764643f3e0SRichard Henderson TCGTemp *ts = tcg_global_mem_new_internal(reg, off, name, TCG_TYPE_I64); 19774643f3e0SRichard Henderson return temp_tcgv_i64(ts); 19784643f3e0SRichard Henderson } 19794643f3e0SRichard Henderson 19804643f3e0SRichard Henderson TCGv_ptr tcg_global_mem_new_ptr(TCGv_ptr reg, intptr_t off, const char *name) 19814643f3e0SRichard Henderson { 19824643f3e0SRichard Henderson TCGTemp *ts = tcg_global_mem_new_internal(reg, off, name, TCG_TYPE_PTR); 19834643f3e0SRichard Henderson return temp_tcgv_ptr(ts); 19844643f3e0SRichard Henderson } 19854643f3e0SRichard Henderson 1986fb04ab7dSRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, TCGTempKind kind) 1987c896fe29Sbellard { 1988b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1989c896fe29Sbellard TCGTemp *ts; 1990e1c08b00SRichard Henderson int n; 1991c896fe29Sbellard 1992e1c08b00SRichard Henderson if (kind == TEMP_EBB) { 1993e1c08b00SRichard Henderson int idx = find_first_bit(s->free_temps[type].l, TCG_MAX_TEMPS); 1994e1c08b00SRichard Henderson 19950ec9eabcSRichard Henderson if (idx < TCG_MAX_TEMPS) { 19960ec9eabcSRichard Henderson /* There is already an available temp with the right type. */ 1997e1c08b00SRichard Henderson clear_bit(idx, s->free_temps[type].l); 19980ec9eabcSRichard Henderson 1999e8996ee0Sbellard ts = &s->temps[idx]; 2000e8996ee0Sbellard ts->temp_allocated = 1; 20017ca4b752SRichard Henderson tcg_debug_assert(ts->base_type == type); 2002ee17db83SRichard Henderson tcg_debug_assert(ts->kind == kind); 20032f2e911dSRichard Henderson return ts; 2004e1c08b00SRichard Henderson } 2005e8996ee0Sbellard } else { 2006e1c08b00SRichard Henderson tcg_debug_assert(kind == TEMP_TB); 2007e1c08b00SRichard Henderson } 200843eef72fSRichard Henderson 200943eef72fSRichard Henderson switch (type) { 201043eef72fSRichard Henderson case TCG_TYPE_I32: 201143eef72fSRichard Henderson case TCG_TYPE_V64: 201243eef72fSRichard Henderson case TCG_TYPE_V128: 201343eef72fSRichard Henderson case TCG_TYPE_V256: 201443eef72fSRichard Henderson n = 1; 201543eef72fSRichard Henderson break; 201643eef72fSRichard Henderson case TCG_TYPE_I64: 201743eef72fSRichard Henderson n = 64 / TCG_TARGET_REG_BITS; 201843eef72fSRichard Henderson break; 201943eef72fSRichard Henderson case TCG_TYPE_I128: 202043eef72fSRichard Henderson n = 128 / TCG_TARGET_REG_BITS; 202143eef72fSRichard Henderson break; 202243eef72fSRichard Henderson default: 202343eef72fSRichard Henderson g_assert_not_reached(); 202443eef72fSRichard Henderson } 202543eef72fSRichard Henderson 20267ca4b752SRichard Henderson ts = tcg_temp_alloc(s); 202743eef72fSRichard Henderson ts->base_type = type; 202843eef72fSRichard Henderson ts->temp_allocated = 1; 202943eef72fSRichard Henderson ts->kind = kind; 203043eef72fSRichard Henderson 203143eef72fSRichard Henderson if (n == 1) { 203243eef72fSRichard Henderson ts->type = type; 203343eef72fSRichard Henderson } else { 203443eef72fSRichard Henderson ts->type = TCG_TYPE_REG; 203543eef72fSRichard Henderson 2036e1c08b00SRichard Henderson for (int i = 1; i < n; ++i) { 20377ca4b752SRichard Henderson TCGTemp *ts2 = tcg_temp_alloc(s); 20387ca4b752SRichard Henderson 203943eef72fSRichard Henderson tcg_debug_assert(ts2 == ts + i); 204043eef72fSRichard Henderson ts2->base_type = type; 204143eef72fSRichard Henderson ts2->type = TCG_TYPE_REG; 20427ca4b752SRichard Henderson ts2->temp_allocated = 1; 204343eef72fSRichard Henderson ts2->temp_subindex = i; 2044ee17db83SRichard Henderson ts2->kind = kind; 204543eef72fSRichard Henderson } 2046c896fe29Sbellard } 2047085272b3SRichard Henderson return ts; 2048c896fe29Sbellard } 2049c896fe29Sbellard 20504643f3e0SRichard Henderson TCGv_i32 tcg_temp_new_i32(void) 20514643f3e0SRichard Henderson { 20524643f3e0SRichard Henderson return temp_tcgv_i32(tcg_temp_new_internal(TCG_TYPE_I32, TEMP_TB)); 20534643f3e0SRichard Henderson } 20544643f3e0SRichard Henderson 20554643f3e0SRichard Henderson TCGv_i32 tcg_temp_ebb_new_i32(void) 20564643f3e0SRichard Henderson { 20574643f3e0SRichard Henderson return temp_tcgv_i32(tcg_temp_new_internal(TCG_TYPE_I32, TEMP_EBB)); 20584643f3e0SRichard Henderson } 20594643f3e0SRichard Henderson 20604643f3e0SRichard Henderson TCGv_i64 tcg_temp_new_i64(void) 20614643f3e0SRichard Henderson { 20624643f3e0SRichard Henderson return temp_tcgv_i64(tcg_temp_new_internal(TCG_TYPE_I64, TEMP_TB)); 20634643f3e0SRichard Henderson } 20644643f3e0SRichard Henderson 20654643f3e0SRichard Henderson TCGv_i64 tcg_temp_ebb_new_i64(void) 20664643f3e0SRichard Henderson { 20674643f3e0SRichard Henderson return temp_tcgv_i64(tcg_temp_new_internal(TCG_TYPE_I64, TEMP_EBB)); 20684643f3e0SRichard Henderson } 20694643f3e0SRichard Henderson 20704643f3e0SRichard Henderson TCGv_ptr tcg_temp_new_ptr(void) 20714643f3e0SRichard Henderson { 20724643f3e0SRichard Henderson return temp_tcgv_ptr(tcg_temp_new_internal(TCG_TYPE_PTR, TEMP_TB)); 20734643f3e0SRichard Henderson } 20744643f3e0SRichard Henderson 20754643f3e0SRichard Henderson TCGv_ptr tcg_temp_ebb_new_ptr(void) 20764643f3e0SRichard Henderson { 20774643f3e0SRichard Henderson return temp_tcgv_ptr(tcg_temp_new_internal(TCG_TYPE_PTR, TEMP_EBB)); 20784643f3e0SRichard Henderson } 20794643f3e0SRichard Henderson 20804643f3e0SRichard Henderson TCGv_i128 tcg_temp_new_i128(void) 20814643f3e0SRichard Henderson { 20824643f3e0SRichard Henderson return temp_tcgv_i128(tcg_temp_new_internal(TCG_TYPE_I128, TEMP_TB)); 20834643f3e0SRichard Henderson } 20844643f3e0SRichard Henderson 20854643f3e0SRichard Henderson TCGv_i128 tcg_temp_ebb_new_i128(void) 20864643f3e0SRichard Henderson { 20874643f3e0SRichard Henderson return temp_tcgv_i128(tcg_temp_new_internal(TCG_TYPE_I128, TEMP_EBB)); 20884643f3e0SRichard Henderson } 20894643f3e0SRichard Henderson 2090d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type) 2091d2fd745fSRichard Henderson { 2092d2fd745fSRichard Henderson TCGTemp *t; 2093d2fd745fSRichard Henderson 2094d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG 2095d2fd745fSRichard Henderson switch (type) { 2096d2fd745fSRichard Henderson case TCG_TYPE_V64: 2097d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v64); 2098d2fd745fSRichard Henderson break; 2099d2fd745fSRichard Henderson case TCG_TYPE_V128: 2100d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v128); 2101d2fd745fSRichard Henderson break; 2102d2fd745fSRichard Henderson case TCG_TYPE_V256: 2103d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v256); 2104d2fd745fSRichard Henderson break; 2105d2fd745fSRichard Henderson default: 2106d2fd745fSRichard Henderson g_assert_not_reached(); 2107d2fd745fSRichard Henderson } 2108d2fd745fSRichard Henderson #endif 2109d2fd745fSRichard Henderson 2110bbf989bfSRichard Henderson t = tcg_temp_new_internal(type, TEMP_EBB); 2111d2fd745fSRichard Henderson return temp_tcgv_vec(t); 2112d2fd745fSRichard Henderson } 2113d2fd745fSRichard Henderson 2114d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp. */ 2115d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match) 2116d2fd745fSRichard Henderson { 2117d2fd745fSRichard Henderson TCGTemp *t = tcgv_vec_temp(match); 2118d2fd745fSRichard Henderson 2119d2fd745fSRichard Henderson tcg_debug_assert(t->temp_allocated != 0); 2120d2fd745fSRichard Henderson 2121bbf989bfSRichard Henderson t = tcg_temp_new_internal(t->base_type, TEMP_EBB); 2122d2fd745fSRichard Henderson return temp_tcgv_vec(t); 2123d2fd745fSRichard Henderson } 2124d2fd745fSRichard Henderson 21255bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts) 2126c896fe29Sbellard { 2127b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 2128c896fe29Sbellard 2129c7482438SRichard Henderson switch (ts->kind) { 2130c7482438SRichard Henderson case TEMP_CONST: 2131f57c6915SRichard Henderson case TEMP_TB: 21322f2e911dSRichard Henderson /* Silently ignore free. */ 2133c7482438SRichard Henderson break; 21342f2e911dSRichard Henderson case TEMP_EBB: 2135eabb7b91SAurelien Jarno tcg_debug_assert(ts->temp_allocated != 0); 2136e8996ee0Sbellard ts->temp_allocated = 0; 21372f2e911dSRichard Henderson set_bit(temp_idx(ts), s->free_temps[ts->base_type].l); 21382f2e911dSRichard Henderson break; 21392f2e911dSRichard Henderson default: 21402f2e911dSRichard Henderson /* It never made sense to free TEMP_FIXED or TEMP_GLOBAL. */ 21412f2e911dSRichard Henderson g_assert_not_reached(); 2142e1c08b00SRichard Henderson } 2143e8996ee0Sbellard } 2144e8996ee0Sbellard 214558b79713SRichard Henderson void tcg_temp_free_i32(TCGv_i32 arg) 214658b79713SRichard Henderson { 214758b79713SRichard Henderson tcg_temp_free_internal(tcgv_i32_temp(arg)); 214858b79713SRichard Henderson } 214958b79713SRichard Henderson 215058b79713SRichard Henderson void tcg_temp_free_i64(TCGv_i64 arg) 215158b79713SRichard Henderson { 215258b79713SRichard Henderson tcg_temp_free_internal(tcgv_i64_temp(arg)); 215358b79713SRichard Henderson } 215458b79713SRichard Henderson 215558b79713SRichard Henderson void tcg_temp_free_i128(TCGv_i128 arg) 215658b79713SRichard Henderson { 215758b79713SRichard Henderson tcg_temp_free_internal(tcgv_i128_temp(arg)); 215858b79713SRichard Henderson } 215958b79713SRichard Henderson 216058b79713SRichard Henderson void tcg_temp_free_ptr(TCGv_ptr arg) 216158b79713SRichard Henderson { 216258b79713SRichard Henderson tcg_temp_free_internal(tcgv_ptr_temp(arg)); 216358b79713SRichard Henderson } 216458b79713SRichard Henderson 216558b79713SRichard Henderson void tcg_temp_free_vec(TCGv_vec arg) 216658b79713SRichard Henderson { 216758b79713SRichard Henderson tcg_temp_free_internal(tcgv_vec_temp(arg)); 216858b79713SRichard Henderson } 216958b79713SRichard Henderson 2170c0522136SRichard Henderson TCGTemp *tcg_constant_internal(TCGType type, int64_t val) 2171c0522136SRichard Henderson { 2172c0522136SRichard Henderson TCGContext *s = tcg_ctx; 2173c0522136SRichard Henderson GHashTable *h = s->const_table[type]; 2174c0522136SRichard Henderson TCGTemp *ts; 2175c0522136SRichard Henderson 2176c0522136SRichard Henderson if (h == NULL) { 2177c0522136SRichard Henderson h = g_hash_table_new(g_int64_hash, g_int64_equal); 2178c0522136SRichard Henderson s->const_table[type] = h; 2179c0522136SRichard Henderson } 2180c0522136SRichard Henderson 2181c0522136SRichard Henderson ts = g_hash_table_lookup(h, &val); 2182c0522136SRichard Henderson if (ts == NULL) { 2183aef85402SRichard Henderson int64_t *val_ptr; 2184aef85402SRichard Henderson 2185c0522136SRichard Henderson ts = tcg_temp_alloc(s); 2186c0522136SRichard Henderson 2187c0522136SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { 2188c0522136SRichard Henderson TCGTemp *ts2 = tcg_temp_alloc(s); 2189c0522136SRichard Henderson 2190aef85402SRichard Henderson tcg_debug_assert(ts2 == ts + 1); 2191aef85402SRichard Henderson 2192c0522136SRichard Henderson ts->base_type = TCG_TYPE_I64; 2193c0522136SRichard Henderson ts->type = TCG_TYPE_I32; 2194c0522136SRichard Henderson ts->kind = TEMP_CONST; 2195c0522136SRichard Henderson ts->temp_allocated = 1; 2196c0522136SRichard Henderson 2197c0522136SRichard Henderson ts2->base_type = TCG_TYPE_I64; 2198c0522136SRichard Henderson ts2->type = TCG_TYPE_I32; 2199c0522136SRichard Henderson ts2->kind = TEMP_CONST; 2200c0522136SRichard Henderson ts2->temp_allocated = 1; 2201fac87bd2SRichard Henderson ts2->temp_subindex = 1; 2202aef85402SRichard Henderson 2203aef85402SRichard Henderson /* 2204aef85402SRichard Henderson * Retain the full value of the 64-bit constant in the low 2205aef85402SRichard Henderson * part, so that the hash table works. Actual uses will 2206aef85402SRichard Henderson * truncate the value to the low part. 2207aef85402SRichard Henderson */ 2208aef85402SRichard Henderson ts[HOST_BIG_ENDIAN].val = val; 2209aef85402SRichard Henderson ts[!HOST_BIG_ENDIAN].val = val >> 32; 2210aef85402SRichard Henderson val_ptr = &ts[HOST_BIG_ENDIAN].val; 2211c0522136SRichard Henderson } else { 2212c0522136SRichard Henderson ts->base_type = type; 2213c0522136SRichard Henderson ts->type = type; 2214c0522136SRichard Henderson ts->kind = TEMP_CONST; 2215c0522136SRichard Henderson ts->temp_allocated = 1; 2216c0522136SRichard Henderson ts->val = val; 2217aef85402SRichard Henderson val_ptr = &ts->val; 2218c0522136SRichard Henderson } 2219aef85402SRichard Henderson g_hash_table_insert(h, val_ptr, ts); 2220c0522136SRichard Henderson } 2221c0522136SRichard Henderson 2222c0522136SRichard Henderson return ts; 2223c0522136SRichard Henderson } 2224c0522136SRichard Henderson 222516edaee7SRichard Henderson TCGv_i32 tcg_constant_i32(int32_t val) 222616edaee7SRichard Henderson { 222716edaee7SRichard Henderson return temp_tcgv_i32(tcg_constant_internal(TCG_TYPE_I32, val)); 222816edaee7SRichard Henderson } 222916edaee7SRichard Henderson 223016edaee7SRichard Henderson TCGv_i64 tcg_constant_i64(int64_t val) 223116edaee7SRichard Henderson { 223216edaee7SRichard Henderson return temp_tcgv_i64(tcg_constant_internal(TCG_TYPE_I64, val)); 223316edaee7SRichard Henderson } 223416edaee7SRichard Henderson 223516edaee7SRichard Henderson TCGv_ptr tcg_constant_ptr_int(intptr_t val) 223616edaee7SRichard Henderson { 223716edaee7SRichard Henderson return temp_tcgv_ptr(tcg_constant_internal(TCG_TYPE_PTR, val)); 223816edaee7SRichard Henderson } 223916edaee7SRichard Henderson 2240c0522136SRichard Henderson TCGv_vec tcg_constant_vec(TCGType type, unsigned vece, int64_t val) 2241c0522136SRichard Henderson { 2242c0522136SRichard Henderson val = dup_const(vece, val); 2243c0522136SRichard Henderson return temp_tcgv_vec(tcg_constant_internal(type, val)); 2244c0522136SRichard Henderson } 2245c0522136SRichard Henderson 224688d4005bSRichard Henderson TCGv_vec tcg_constant_vec_matching(TCGv_vec match, unsigned vece, int64_t val) 224788d4005bSRichard Henderson { 224888d4005bSRichard Henderson TCGTemp *t = tcgv_vec_temp(match); 224988d4005bSRichard Henderson 225088d4005bSRichard Henderson tcg_debug_assert(t->temp_allocated != 0); 225188d4005bSRichard Henderson return tcg_constant_vec(t->base_type, vece, val); 225288d4005bSRichard Henderson } 225388d4005bSRichard Henderson 2254177f648fSRichard Henderson #ifdef CONFIG_DEBUG_TCG 2255177f648fSRichard Henderson size_t temp_idx(TCGTemp *ts) 2256177f648fSRichard Henderson { 2257177f648fSRichard Henderson ptrdiff_t n = ts - tcg_ctx->temps; 2258177f648fSRichard Henderson assert(n >= 0 && n < tcg_ctx->nb_temps); 2259177f648fSRichard Henderson return n; 2260177f648fSRichard Henderson } 2261177f648fSRichard Henderson 2262177f648fSRichard Henderson TCGTemp *tcgv_i32_temp(TCGv_i32 v) 2263177f648fSRichard Henderson { 2264177f648fSRichard Henderson uintptr_t o = (uintptr_t)v - offsetof(TCGContext, temps); 2265177f648fSRichard Henderson 2266177f648fSRichard Henderson assert(o < sizeof(TCGTemp) * tcg_ctx->nb_temps); 2267177f648fSRichard Henderson assert(o % sizeof(TCGTemp) == 0); 2268177f648fSRichard Henderson 2269177f648fSRichard Henderson return (void *)tcg_ctx + (uintptr_t)v; 2270177f648fSRichard Henderson } 2271177f648fSRichard Henderson #endif /* CONFIG_DEBUG_TCG */ 2272177f648fSRichard Henderson 2273771a5925SRichard Henderson /* 2274771a5925SRichard Henderson * Return true if OP may appear in the opcode stream with TYPE. 2275771a5925SRichard Henderson * Test the runtime variable that controls each opcode. 2276771a5925SRichard Henderson */ 2277771a5925SRichard Henderson bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) 2278be0f34b5SRichard Henderson { 2279f44824ccSRichard Henderson bool has_type; 2280f44824ccSRichard Henderson 2281f44824ccSRichard Henderson switch (type) { 2282f44824ccSRichard Henderson case TCG_TYPE_I32: 2283f44824ccSRichard Henderson has_type = true; 2284f44824ccSRichard Henderson break; 2285f44824ccSRichard Henderson case TCG_TYPE_I64: 2286f44824ccSRichard Henderson has_type = TCG_TARGET_REG_BITS == 64; 2287f44824ccSRichard Henderson break; 2288f44824ccSRichard Henderson case TCG_TYPE_V64: 2289f44824ccSRichard Henderson has_type = TCG_TARGET_HAS_v64; 2290f44824ccSRichard Henderson break; 2291f44824ccSRichard Henderson case TCG_TYPE_V128: 2292f44824ccSRichard Henderson has_type = TCG_TARGET_HAS_v128; 2293f44824ccSRichard Henderson break; 2294f44824ccSRichard Henderson case TCG_TYPE_V256: 2295f44824ccSRichard Henderson has_type = TCG_TARGET_HAS_v256; 2296f44824ccSRichard Henderson break; 2297f44824ccSRichard Henderson default: 2298f44824ccSRichard Henderson has_type = false; 2299f44824ccSRichard Henderson break; 2300f44824ccSRichard Henderson } 2301d2fd745fSRichard Henderson 2302be0f34b5SRichard Henderson switch (op) { 2303be0f34b5SRichard Henderson case INDEX_op_discard: 2304be0f34b5SRichard Henderson case INDEX_op_set_label: 2305be0f34b5SRichard Henderson case INDEX_op_call: 2306be0f34b5SRichard Henderson case INDEX_op_br: 2307be0f34b5SRichard Henderson case INDEX_op_mb: 2308be0f34b5SRichard Henderson case INDEX_op_insn_start: 2309be0f34b5SRichard Henderson case INDEX_op_exit_tb: 2310be0f34b5SRichard Henderson case INDEX_op_goto_tb: 2311f4e01e30SRichard Henderson case INDEX_op_goto_ptr: 231250b7a197SRichard Henderson case INDEX_op_qemu_ld_i32: 231350b7a197SRichard Henderson case INDEX_op_qemu_st_i32: 231450b7a197SRichard Henderson case INDEX_op_qemu_ld_i64: 231550b7a197SRichard Henderson case INDEX_op_qemu_st_i64: 2316be0f34b5SRichard Henderson return true; 2317be0f34b5SRichard Henderson 231850b7a197SRichard Henderson case INDEX_op_qemu_st8_i32: 231907ce0b05SRichard Henderson return TCG_TARGET_HAS_qemu_st8_i32; 232007ce0b05SRichard Henderson 232150b7a197SRichard Henderson case INDEX_op_qemu_ld_i128: 232250b7a197SRichard Henderson case INDEX_op_qemu_st_i128: 232312fde9bcSRichard Henderson return TCG_TARGET_HAS_qemu_ldst_i128; 232412fde9bcSRichard Henderson 232579602f63SRichard Henderson case INDEX_op_add: 2326c3b920b3SRichard Henderson case INDEX_op_and: 2327b6d69fceSRichard Henderson case INDEX_op_brcond: 2328*07d5d502SRichard Henderson case INDEX_op_extract: 2329b5701261SRichard Henderson case INDEX_op_mov: 2330ea46c4bcSRichard Henderson case INDEX_op_movcond: 2331a363e1e1SRichard Henderson case INDEX_op_negsetcond: 233249bd7514SRichard Henderson case INDEX_op_or: 2333a363e1e1SRichard Henderson case INDEX_op_setcond: 2334fffd3dc9SRichard Henderson case INDEX_op_xor: 2335b5701261SRichard Henderson return has_type; 2336b5701261SRichard Henderson 2337be0f34b5SRichard Henderson case INDEX_op_ld8u_i32: 2338be0f34b5SRichard Henderson case INDEX_op_ld8s_i32: 2339be0f34b5SRichard Henderson case INDEX_op_ld16u_i32: 2340be0f34b5SRichard Henderson case INDEX_op_ld16s_i32: 2341be0f34b5SRichard Henderson case INDEX_op_ld_i32: 2342be0f34b5SRichard Henderson case INDEX_op_st8_i32: 2343be0f34b5SRichard Henderson case INDEX_op_st16_i32: 2344be0f34b5SRichard Henderson case INDEX_op_st_i32: 2345c334de11SRichard Henderson case INDEX_op_sextract_i32: 23466482e9d2SRichard Henderson case INDEX_op_deposit_i32: 2347be0f34b5SRichard Henderson return true; 2348be0f34b5SRichard Henderson 2349fce1296fSRichard Henderson case INDEX_op_extract2_i32: 2350fce1296fSRichard Henderson return TCG_TARGET_HAS_extract2_i32; 2351be0f34b5SRichard Henderson case INDEX_op_add2_i32: 2352be0f34b5SRichard Henderson return TCG_TARGET_HAS_add2_i32; 2353be0f34b5SRichard Henderson case INDEX_op_sub2_i32: 2354be0f34b5SRichard Henderson return TCG_TARGET_HAS_sub2_i32; 2355be0f34b5SRichard Henderson 2356be0f34b5SRichard Henderson case INDEX_op_brcond2_i32: 2357be0f34b5SRichard Henderson case INDEX_op_setcond2_i32: 2358be0f34b5SRichard Henderson return TCG_TARGET_REG_BITS == 32; 2359be0f34b5SRichard Henderson 2360be0f34b5SRichard Henderson case INDEX_op_ld8u_i64: 2361be0f34b5SRichard Henderson case INDEX_op_ld8s_i64: 2362be0f34b5SRichard Henderson case INDEX_op_ld16u_i64: 2363be0f34b5SRichard Henderson case INDEX_op_ld16s_i64: 2364be0f34b5SRichard Henderson case INDEX_op_ld32u_i64: 2365be0f34b5SRichard Henderson case INDEX_op_ld32s_i64: 2366be0f34b5SRichard Henderson case INDEX_op_ld_i64: 2367be0f34b5SRichard Henderson case INDEX_op_st8_i64: 2368be0f34b5SRichard Henderson case INDEX_op_st16_i64: 2369be0f34b5SRichard Henderson case INDEX_op_st32_i64: 2370be0f34b5SRichard Henderson case INDEX_op_st_i64: 2371be0f34b5SRichard Henderson case INDEX_op_ext_i32_i64: 2372be0f34b5SRichard Henderson case INDEX_op_extu_i32_i64: 2373c334de11SRichard Henderson case INDEX_op_sextract_i64: 23746482e9d2SRichard Henderson case INDEX_op_deposit_i64: 2375be0f34b5SRichard Henderson return TCG_TARGET_REG_BITS == 64; 2376be0f34b5SRichard Henderson 2377fce1296fSRichard Henderson case INDEX_op_extract2_i64: 2378fce1296fSRichard Henderson return TCG_TARGET_HAS_extract2_i64; 2379be0f34b5SRichard Henderson case INDEX_op_extrl_i64_i32: 2380be0f34b5SRichard Henderson case INDEX_op_extrh_i64_i32: 238113d885b0SRichard Henderson return TCG_TARGET_HAS_extr_i64_i32; 2382be0f34b5SRichard Henderson case INDEX_op_add2_i64: 2383be0f34b5SRichard Henderson return TCG_TARGET_HAS_add2_i64; 2384be0f34b5SRichard Henderson case INDEX_op_sub2_i64: 2385be0f34b5SRichard Henderson return TCG_TARGET_HAS_sub2_i64; 2386be0f34b5SRichard Henderson 2387d2fd745fSRichard Henderson case INDEX_op_mov_vec: 2388d2fd745fSRichard Henderson case INDEX_op_dup_vec: 238937ee55a0SRichard Henderson case INDEX_op_dupm_vec: 2390d2fd745fSRichard Henderson case INDEX_op_ld_vec: 2391d2fd745fSRichard Henderson case INDEX_op_st_vec: 2392d2fd745fSRichard Henderson case INDEX_op_add_vec: 2393d2fd745fSRichard Henderson case INDEX_op_sub_vec: 2394d2fd745fSRichard Henderson case INDEX_op_and_vec: 2395d2fd745fSRichard Henderson case INDEX_op_or_vec: 2396d2fd745fSRichard Henderson case INDEX_op_xor_vec: 2397212be173SRichard Henderson case INDEX_op_cmp_vec: 2398f44824ccSRichard Henderson return has_type; 2399d2fd745fSRichard Henderson case INDEX_op_dup2_vec: 2400f44824ccSRichard Henderson return has_type && TCG_TARGET_REG_BITS == 32; 2401d2fd745fSRichard Henderson case INDEX_op_not_vec: 2402f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_not_vec; 2403d2fd745fSRichard Henderson case INDEX_op_neg_vec: 2404f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_neg_vec; 2405bcefc902SRichard Henderson case INDEX_op_abs_vec: 2406f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_abs_vec; 2407d2fd745fSRichard Henderson case INDEX_op_andc_vec: 2408f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_andc_vec; 2409d2fd745fSRichard Henderson case INDEX_op_orc_vec: 2410f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_orc_vec; 2411ed523473SRichard Henderson case INDEX_op_nand_vec: 2412f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_nand_vec; 2413ed523473SRichard Henderson case INDEX_op_nor_vec: 2414f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_nor_vec; 2415ed523473SRichard Henderson case INDEX_op_eqv_vec: 2416f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_eqv_vec; 24173774030aSRichard Henderson case INDEX_op_mul_vec: 2418f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_mul_vec; 2419d0ec9796SRichard Henderson case INDEX_op_shli_vec: 2420d0ec9796SRichard Henderson case INDEX_op_shri_vec: 2421d0ec9796SRichard Henderson case INDEX_op_sari_vec: 2422f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_shi_vec; 2423d0ec9796SRichard Henderson case INDEX_op_shls_vec: 2424d0ec9796SRichard Henderson case INDEX_op_shrs_vec: 2425d0ec9796SRichard Henderson case INDEX_op_sars_vec: 2426f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_shs_vec; 2427d0ec9796SRichard Henderson case INDEX_op_shlv_vec: 2428d0ec9796SRichard Henderson case INDEX_op_shrv_vec: 2429d0ec9796SRichard Henderson case INDEX_op_sarv_vec: 2430f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_shv_vec; 2431b0f7e744SRichard Henderson case INDEX_op_rotli_vec: 2432f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_roti_vec; 243323850a74SRichard Henderson case INDEX_op_rotls_vec: 2434f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_rots_vec; 24355d0ceda9SRichard Henderson case INDEX_op_rotlv_vec: 24365d0ceda9SRichard Henderson case INDEX_op_rotrv_vec: 2437f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_rotv_vec; 24388afaf050SRichard Henderson case INDEX_op_ssadd_vec: 24398afaf050SRichard Henderson case INDEX_op_usadd_vec: 24408afaf050SRichard Henderson case INDEX_op_sssub_vec: 24418afaf050SRichard Henderson case INDEX_op_ussub_vec: 2442f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_sat_vec; 2443dd0a0fcdSRichard Henderson case INDEX_op_smin_vec: 2444dd0a0fcdSRichard Henderson case INDEX_op_umin_vec: 2445dd0a0fcdSRichard Henderson case INDEX_op_smax_vec: 2446dd0a0fcdSRichard Henderson case INDEX_op_umax_vec: 2447f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_minmax_vec; 244838dc1294SRichard Henderson case INDEX_op_bitsel_vec: 2449f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_bitsel_vec; 2450f75da298SRichard Henderson case INDEX_op_cmpsel_vec: 2451f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_cmpsel_vec; 2452d2fd745fSRichard Henderson 2453db432672SRichard Henderson default: 24545500bd9eSRichard Henderson if (op < INDEX_op_last_generic) { 24555500bd9eSRichard Henderson const TCGOutOp *outop; 24565500bd9eSRichard Henderson TCGConstraintSetIndex con_set; 24575500bd9eSRichard Henderson 24585500bd9eSRichard Henderson if (!has_type) { 24595500bd9eSRichard Henderson return false; 24605500bd9eSRichard Henderson } 24615500bd9eSRichard Henderson 24625500bd9eSRichard Henderson outop = all_outop[op]; 24635500bd9eSRichard Henderson tcg_debug_assert(outop != NULL); 24645500bd9eSRichard Henderson 24655500bd9eSRichard Henderson con_set = outop->static_constraint; 24665500bd9eSRichard Henderson if (con_set == C_Dynamic) { 24675500bd9eSRichard Henderson con_set = outop->dynamic_constraint(type, flags); 24685500bd9eSRichard Henderson } 24695500bd9eSRichard Henderson if (con_set >= 0) { 2470db432672SRichard Henderson return true; 2471be0f34b5SRichard Henderson } 24725500bd9eSRichard Henderson tcg_debug_assert(con_set == C_NotImplemented); 24735500bd9eSRichard Henderson return false; 24745500bd9eSRichard Henderson } 24755500bd9eSRichard Henderson tcg_debug_assert(op < NB_OPS); 24765500bd9eSRichard Henderson return true; 24775500bd9eSRichard Henderson 24785500bd9eSRichard Henderson case INDEX_op_last_generic: 24795500bd9eSRichard Henderson g_assert_not_reached(); 24805500bd9eSRichard Henderson } 2481be0f34b5SRichard Henderson } 2482be0f34b5SRichard Henderson 24830e4c6424SRichard Henderson bool tcg_op_deposit_valid(TCGType type, unsigned ofs, unsigned len) 24840e4c6424SRichard Henderson { 24856482e9d2SRichard Henderson unsigned width; 24866482e9d2SRichard Henderson 24876482e9d2SRichard Henderson tcg_debug_assert(type == TCG_TYPE_I32 || type == TCG_TYPE_I64); 24886482e9d2SRichard Henderson width = (type == TCG_TYPE_I32 ? 32 : 64); 24896482e9d2SRichard Henderson 24906482e9d2SRichard Henderson tcg_debug_assert(ofs < width); 24910e4c6424SRichard Henderson tcg_debug_assert(len > 0); 24926482e9d2SRichard Henderson tcg_debug_assert(len <= width - ofs); 24936482e9d2SRichard Henderson 24946482e9d2SRichard Henderson return TCG_TARGET_deposit_valid(type, ofs, len); 24950e4c6424SRichard Henderson } 24960e4c6424SRichard Henderson 249739004a71SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs); 249839004a71SRichard Henderson 249983a0ad26SRichard Henderson static void tcg_gen_callN(void *func, TCGHelperInfo *info, 250083a0ad26SRichard Henderson TCGTemp *ret, TCGTemp **args) 2501c896fe29Sbellard { 250239004a71SRichard Henderson TCGv_i64 extend_free[MAX_CALL_IARGS]; 250339004a71SRichard Henderson int n_extend = 0; 250475e8b9b7SRichard Henderson TCGOp *op; 250539004a71SRichard Henderson int i, n, pi = 0, total_args; 2506afb49896SRichard Henderson 2507d53106c9SRichard Henderson if (unlikely(g_once_init_enter(HELPER_INFO_INIT(info)))) { 2508d53106c9SRichard Henderson init_call_layout(info); 2509d53106c9SRichard Henderson g_once_init_leave(HELPER_INFO_INIT(info), HELPER_INFO_INIT_VAL(info)); 2510d53106c9SRichard Henderson } 2511d53106c9SRichard Henderson 251239004a71SRichard Henderson total_args = info->nr_out + info->nr_in + 2; 251339004a71SRichard Henderson op = tcg_op_alloc(INDEX_op_call, total_args); 25142bece2c8SRichard Henderson 251538b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN 251617083f6fSEmilio Cota /* Flag helpers that may affect guest state */ 2517b0748975SRichard Henderson if (tcg_ctx->plugin_insn && !(info->flags & TCG_CALL_NO_SIDE_EFFECTS)) { 251838b47b19SEmilio G. Cota tcg_ctx->plugin_insn->calls_helpers = true; 251938b47b19SEmilio G. Cota } 252038b47b19SEmilio G. Cota #endif 252138b47b19SEmilio G. Cota 252239004a71SRichard Henderson TCGOP_CALLO(op) = n = info->nr_out; 252339004a71SRichard Henderson switch (n) { 252439004a71SRichard Henderson case 0: 252539004a71SRichard Henderson tcg_debug_assert(ret == NULL); 252639004a71SRichard Henderson break; 252739004a71SRichard Henderson case 1: 252839004a71SRichard Henderson tcg_debug_assert(ret != NULL); 252939004a71SRichard Henderson op->args[pi++] = temp_arg(ret); 253039004a71SRichard Henderson break; 253139004a71SRichard Henderson case 2: 2532466d3759SRichard Henderson case 4: 253339004a71SRichard Henderson tcg_debug_assert(ret != NULL); 2534466d3759SRichard Henderson tcg_debug_assert(ret->base_type == ret->type + ctz32(n)); 253539004a71SRichard Henderson tcg_debug_assert(ret->temp_subindex == 0); 2536466d3759SRichard Henderson for (i = 0; i < n; ++i) { 2537466d3759SRichard Henderson op->args[pi++] = temp_arg(ret + i); 2538466d3759SRichard Henderson } 253939004a71SRichard Henderson break; 254039004a71SRichard Henderson default: 254139004a71SRichard Henderson g_assert_not_reached(); 254239004a71SRichard Henderson } 25437319d83aSRichard Henderson 254439004a71SRichard Henderson TCGOP_CALLI(op) = n = info->nr_in; 254539004a71SRichard Henderson for (i = 0; i < n; i++) { 254639004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i]; 254739004a71SRichard Henderson TCGTemp *ts = args[loc->arg_idx] + loc->tmp_subindex; 254839004a71SRichard Henderson 254939004a71SRichard Henderson switch (loc->kind) { 255039004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 2551313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF: 2552313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF_N: 255339004a71SRichard Henderson op->args[pi++] = temp_arg(ts); 255439004a71SRichard Henderson break; 255539004a71SRichard Henderson 255639004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 255739004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 255839004a71SRichard Henderson { 25595dd48602SRichard Henderson TCGv_i64 temp = tcg_temp_ebb_new_i64(); 256039004a71SRichard Henderson TCGv_i32 orig = temp_tcgv_i32(ts); 256139004a71SRichard Henderson 256239004a71SRichard Henderson if (loc->kind == TCG_CALL_ARG_EXTEND_S) { 256318cf3d07SRichard Henderson tcg_gen_ext_i32_i64(temp, orig); 25642bece2c8SRichard Henderson } else { 256518cf3d07SRichard Henderson tcg_gen_extu_i32_i64(temp, orig); 25662bece2c8SRichard Henderson } 256739004a71SRichard Henderson op->args[pi++] = tcgv_i64_arg(temp); 256839004a71SRichard Henderson extend_free[n_extend++] = temp; 25692bece2c8SRichard Henderson } 257039004a71SRichard Henderson break; 25712bece2c8SRichard Henderson 2572e2a9dd6bSRichard Henderson default: 2573e2a9dd6bSRichard Henderson g_assert_not_reached(); 2574e2a9dd6bSRichard Henderson } 2575c896fe29Sbellard } 257683a0ad26SRichard Henderson op->args[pi++] = (uintptr_t)func; 25773e92aa34SRichard Henderson op->args[pi++] = (uintptr_t)info; 257839004a71SRichard Henderson tcg_debug_assert(pi == total_args); 2579a7812ae4Spbrook 258007843f75SRichard Henderson if (tcg_ctx->emit_before_op) { 258107843f75SRichard Henderson QTAILQ_INSERT_BEFORE(tcg_ctx->emit_before_op, op, link); 258207843f75SRichard Henderson } else { 258339004a71SRichard Henderson QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link); 258407843f75SRichard Henderson } 25852bece2c8SRichard Henderson 258639004a71SRichard Henderson tcg_debug_assert(n_extend < ARRAY_SIZE(extend_free)); 258739004a71SRichard Henderson for (i = 0; i < n_extend; ++i) { 258839004a71SRichard Henderson tcg_temp_free_i64(extend_free[i]); 2589eb8b0224SRichard Henderson } 2590a7812ae4Spbrook } 2591c896fe29Sbellard 259283a0ad26SRichard Henderson void tcg_gen_call0(void *func, TCGHelperInfo *info, TCGTemp *ret) 2593a3a692b8SRichard Henderson { 259483a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, NULL); 2595a3a692b8SRichard Henderson } 2596a3a692b8SRichard Henderson 259783a0ad26SRichard Henderson void tcg_gen_call1(void *func, TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1) 2598a3a692b8SRichard Henderson { 259983a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, &t1); 2600a3a692b8SRichard Henderson } 2601a3a692b8SRichard Henderson 260283a0ad26SRichard Henderson void tcg_gen_call2(void *func, TCGHelperInfo *info, TCGTemp *ret, 260383a0ad26SRichard Henderson TCGTemp *t1, TCGTemp *t2) 2604a3a692b8SRichard Henderson { 2605a3a692b8SRichard Henderson TCGTemp *args[2] = { t1, t2 }; 260683a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, args); 2607a3a692b8SRichard Henderson } 2608a3a692b8SRichard Henderson 260983a0ad26SRichard Henderson void tcg_gen_call3(void *func, TCGHelperInfo *info, TCGTemp *ret, 261083a0ad26SRichard Henderson TCGTemp *t1, TCGTemp *t2, TCGTemp *t3) 2611a3a692b8SRichard Henderson { 2612a3a692b8SRichard Henderson TCGTemp *args[3] = { t1, t2, t3 }; 261383a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, args); 2614a3a692b8SRichard Henderson } 2615a3a692b8SRichard Henderson 261683a0ad26SRichard Henderson void tcg_gen_call4(void *func, TCGHelperInfo *info, TCGTemp *ret, 261783a0ad26SRichard Henderson TCGTemp *t1, TCGTemp *t2, TCGTemp *t3, TCGTemp *t4) 2618a3a692b8SRichard Henderson { 2619a3a692b8SRichard Henderson TCGTemp *args[4] = { t1, t2, t3, t4 }; 262083a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, args); 2621a3a692b8SRichard Henderson } 2622a3a692b8SRichard Henderson 262383a0ad26SRichard Henderson void tcg_gen_call5(void *func, TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1, 2624a3a692b8SRichard Henderson TCGTemp *t2, TCGTemp *t3, TCGTemp *t4, TCGTemp *t5) 2625a3a692b8SRichard Henderson { 2626a3a692b8SRichard Henderson TCGTemp *args[5] = { t1, t2, t3, t4, t5 }; 262783a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, args); 2628a3a692b8SRichard Henderson } 2629a3a692b8SRichard Henderson 263083a0ad26SRichard Henderson void tcg_gen_call6(void *func, TCGHelperInfo *info, TCGTemp *ret, 263183a0ad26SRichard Henderson TCGTemp *t1, TCGTemp *t2, TCGTemp *t3, 263283a0ad26SRichard Henderson TCGTemp *t4, TCGTemp *t5, TCGTemp *t6) 2633a3a692b8SRichard Henderson { 2634a3a692b8SRichard Henderson TCGTemp *args[6] = { t1, t2, t3, t4, t5, t6 }; 263583a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, args); 2636a3a692b8SRichard Henderson } 2637a3a692b8SRichard Henderson 263883a0ad26SRichard Henderson void tcg_gen_call7(void *func, TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1, 2639a3a692b8SRichard Henderson TCGTemp *t2, TCGTemp *t3, TCGTemp *t4, 2640a3a692b8SRichard Henderson TCGTemp *t5, TCGTemp *t6, TCGTemp *t7) 2641a3a692b8SRichard Henderson { 2642a3a692b8SRichard Henderson TCGTemp *args[7] = { t1, t2, t3, t4, t5, t6, t7 }; 264383a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, args); 2644a3a692b8SRichard Henderson } 2645a3a692b8SRichard Henderson 26468fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s) 2647c896fe29Sbellard { 2648ac3b8891SRichard Henderson int i, n; 2649ac3b8891SRichard Henderson 2650ee17db83SRichard Henderson for (i = 0, n = s->nb_temps; i < n; i++) { 2651ee17db83SRichard Henderson TCGTemp *ts = &s->temps[i]; 2652ee17db83SRichard Henderson TCGTempVal val = TEMP_VAL_MEM; 2653ee17db83SRichard Henderson 2654ee17db83SRichard Henderson switch (ts->kind) { 2655c0522136SRichard Henderson case TEMP_CONST: 2656c0522136SRichard Henderson val = TEMP_VAL_CONST; 2657c0522136SRichard Henderson break; 2658ee17db83SRichard Henderson case TEMP_FIXED: 2659ee17db83SRichard Henderson val = TEMP_VAL_REG; 2660ee17db83SRichard Henderson break; 2661ee17db83SRichard Henderson case TEMP_GLOBAL: 2662ee17db83SRichard Henderson break; 2663c7482438SRichard Henderson case TEMP_EBB: 2664ee17db83SRichard Henderson val = TEMP_VAL_DEAD; 2665ee17db83SRichard Henderson /* fall through */ 2666f57c6915SRichard Henderson case TEMP_TB: 2667e8996ee0Sbellard ts->mem_allocated = 0; 2668ee17db83SRichard Henderson break; 2669ee17db83SRichard Henderson default: 2670ee17db83SRichard Henderson g_assert_not_reached(); 2671ee17db83SRichard Henderson } 2672ee17db83SRichard Henderson ts->val_type = val; 2673e8996ee0Sbellard } 2674f8b2f202SRichard Henderson 2675f8b2f202SRichard Henderson memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp)); 2676c896fe29Sbellard } 2677c896fe29Sbellard 2678f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size, 2679f8b2f202SRichard Henderson TCGTemp *ts) 2680c896fe29Sbellard { 26811807f4c4SRichard Henderson int idx = temp_idx(ts); 2682ac56dd48Spbrook 2683ee17db83SRichard Henderson switch (ts->kind) { 2684ee17db83SRichard Henderson case TEMP_FIXED: 2685ee17db83SRichard Henderson case TEMP_GLOBAL: 2686ac56dd48Spbrook pstrcpy(buf, buf_size, ts->name); 2687ee17db83SRichard Henderson break; 2688f57c6915SRichard Henderson case TEMP_TB: 2689641d5fbeSbellard snprintf(buf, buf_size, "loc%d", idx - s->nb_globals); 2690ee17db83SRichard Henderson break; 2691c7482438SRichard Henderson case TEMP_EBB: 2692ac56dd48Spbrook snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals); 2693ee17db83SRichard Henderson break; 2694c0522136SRichard Henderson case TEMP_CONST: 2695c0522136SRichard Henderson switch (ts->type) { 2696c0522136SRichard Henderson case TCG_TYPE_I32: 2697c0522136SRichard Henderson snprintf(buf, buf_size, "$0x%x", (int32_t)ts->val); 2698c0522136SRichard Henderson break; 2699c0522136SRichard Henderson #if TCG_TARGET_REG_BITS > 32 2700c0522136SRichard Henderson case TCG_TYPE_I64: 2701c0522136SRichard Henderson snprintf(buf, buf_size, "$0x%" PRIx64, ts->val); 2702c0522136SRichard Henderson break; 2703c0522136SRichard Henderson #endif 2704c0522136SRichard Henderson case TCG_TYPE_V64: 2705c0522136SRichard Henderson case TCG_TYPE_V128: 2706c0522136SRichard Henderson case TCG_TYPE_V256: 2707c0522136SRichard Henderson snprintf(buf, buf_size, "v%d$0x%" PRIx64, 2708c0522136SRichard Henderson 64 << (ts->type - TCG_TYPE_V64), ts->val); 2709c0522136SRichard Henderson break; 2710c0522136SRichard Henderson default: 2711c0522136SRichard Henderson g_assert_not_reached(); 2712c0522136SRichard Henderson } 2713c0522136SRichard Henderson break; 2714c896fe29Sbellard } 2715c896fe29Sbellard return buf; 2716c896fe29Sbellard } 2717c896fe29Sbellard 271843439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf, 271943439139SRichard Henderson int buf_size, TCGArg arg) 2720f8b2f202SRichard Henderson { 272143439139SRichard Henderson return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg)); 2722f8b2f202SRichard Henderson } 2723f8b2f202SRichard Henderson 2724f48f3edeSblueswir1 static const char * const cond_name[] = 2725f48f3edeSblueswir1 { 27260aed257fSRichard Henderson [TCG_COND_NEVER] = "never", 27270aed257fSRichard Henderson [TCG_COND_ALWAYS] = "always", 2728f48f3edeSblueswir1 [TCG_COND_EQ] = "eq", 2729f48f3edeSblueswir1 [TCG_COND_NE] = "ne", 2730f48f3edeSblueswir1 [TCG_COND_LT] = "lt", 2731f48f3edeSblueswir1 [TCG_COND_GE] = "ge", 2732f48f3edeSblueswir1 [TCG_COND_LE] = "le", 2733f48f3edeSblueswir1 [TCG_COND_GT] = "gt", 2734f48f3edeSblueswir1 [TCG_COND_LTU] = "ltu", 2735f48f3edeSblueswir1 [TCG_COND_GEU] = "geu", 2736f48f3edeSblueswir1 [TCG_COND_LEU] = "leu", 2737d48097d0SRichard Henderson [TCG_COND_GTU] = "gtu", 2738d48097d0SRichard Henderson [TCG_COND_TSTEQ] = "tsteq", 2739d48097d0SRichard Henderson [TCG_COND_TSTNE] = "tstne", 2740f48f3edeSblueswir1 }; 2741f48f3edeSblueswir1 274212fde9bcSRichard Henderson static const char * const ldst_name[(MO_BSWAP | MO_SSIZE) + 1] = 2743f713d6adSRichard Henderson { 2744f713d6adSRichard Henderson [MO_UB] = "ub", 2745f713d6adSRichard Henderson [MO_SB] = "sb", 2746f713d6adSRichard Henderson [MO_LEUW] = "leuw", 2747f713d6adSRichard Henderson [MO_LESW] = "lesw", 2748f713d6adSRichard Henderson [MO_LEUL] = "leul", 2749f713d6adSRichard Henderson [MO_LESL] = "lesl", 2750fc313c64SFrédéric Pétrot [MO_LEUQ] = "leq", 2751f713d6adSRichard Henderson [MO_BEUW] = "beuw", 2752f713d6adSRichard Henderson [MO_BESW] = "besw", 2753f713d6adSRichard Henderson [MO_BEUL] = "beul", 2754f713d6adSRichard Henderson [MO_BESL] = "besl", 2755fc313c64SFrédéric Pétrot [MO_BEUQ] = "beq", 275612fde9bcSRichard Henderson [MO_128 + MO_BE] = "beo", 275712fde9bcSRichard Henderson [MO_128 + MO_LE] = "leo", 2758f713d6adSRichard Henderson }; 2759f713d6adSRichard Henderson 27601f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = { 27611f00b27fSSergey Sorokin [MO_UNALN >> MO_ASHIFT] = "un+", 27621f00b27fSSergey Sorokin [MO_ALIGN >> MO_ASHIFT] = "al+", 27631f00b27fSSergey Sorokin [MO_ALIGN_2 >> MO_ASHIFT] = "al2+", 27641f00b27fSSergey Sorokin [MO_ALIGN_4 >> MO_ASHIFT] = "al4+", 27651f00b27fSSergey Sorokin [MO_ALIGN_8 >> MO_ASHIFT] = "al8+", 27661f00b27fSSergey Sorokin [MO_ALIGN_16 >> MO_ASHIFT] = "al16+", 27671f00b27fSSergey Sorokin [MO_ALIGN_32 >> MO_ASHIFT] = "al32+", 27681f00b27fSSergey Sorokin [MO_ALIGN_64 >> MO_ASHIFT] = "al64+", 27691f00b27fSSergey Sorokin }; 27701f00b27fSSergey Sorokin 277137031fefSRichard Henderson static const char * const atom_name[(MO_ATOM_MASK >> MO_ATOM_SHIFT) + 1] = { 277237031fefSRichard Henderson [MO_ATOM_IFALIGN >> MO_ATOM_SHIFT] = "", 277337031fefSRichard Henderson [MO_ATOM_IFALIGN_PAIR >> MO_ATOM_SHIFT] = "pair+", 277437031fefSRichard Henderson [MO_ATOM_WITHIN16 >> MO_ATOM_SHIFT] = "w16+", 277537031fefSRichard Henderson [MO_ATOM_WITHIN16_PAIR >> MO_ATOM_SHIFT] = "w16p+", 277637031fefSRichard Henderson [MO_ATOM_SUBALIGN >> MO_ATOM_SHIFT] = "sub+", 277737031fefSRichard Henderson [MO_ATOM_NONE >> MO_ATOM_SHIFT] = "noat+", 277837031fefSRichard Henderson }; 277937031fefSRichard Henderson 2780587195bdSRichard Henderson static const char bswap_flag_name[][6] = { 2781587195bdSRichard Henderson [TCG_BSWAP_IZ] = "iz", 2782587195bdSRichard Henderson [TCG_BSWAP_OZ] = "oz", 2783587195bdSRichard Henderson [TCG_BSWAP_OS] = "os", 2784587195bdSRichard Henderson [TCG_BSWAP_IZ | TCG_BSWAP_OZ] = "iz,oz", 2785587195bdSRichard Henderson [TCG_BSWAP_IZ | TCG_BSWAP_OS] = "iz,os", 2786587195bdSRichard Henderson }; 2787587195bdSRichard Henderson 2788b384c734SRichard Henderson #ifdef CONFIG_PLUGIN 2789b384c734SRichard Henderson static const char * const plugin_from_name[] = { 2790b384c734SRichard Henderson "from-tb", 2791b384c734SRichard Henderson "from-insn", 2792b384c734SRichard Henderson "after-insn", 2793b384c734SRichard Henderson "after-tb", 2794b384c734SRichard Henderson }; 2795b384c734SRichard Henderson #endif 2796b384c734SRichard Henderson 2797b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d) 2798b016486eSRichard Henderson { 2799b016486eSRichard Henderson return (d & (d - 1)) == 0; 2800b016486eSRichard Henderson } 2801b016486eSRichard Henderson 2802b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d) 2803b016486eSRichard Henderson { 2804b016486eSRichard Henderson if (TCG_TARGET_NB_REGS <= 32) { 2805b016486eSRichard Henderson return ctz32(d); 2806b016486eSRichard Henderson } else { 2807b016486eSRichard Henderson return ctz64(d); 2808b016486eSRichard Henderson } 2809b016486eSRichard Henderson } 2810b016486eSRichard Henderson 2811b7a83ff8SRichard Henderson /* Return only the number of characters output -- no error return. */ 2812b7a83ff8SRichard Henderson #define ne_fprintf(...) \ 2813b7a83ff8SRichard Henderson ({ int ret_ = fprintf(__VA_ARGS__); ret_ >= 0 ? ret_ : 0; }) 2814b7a83ff8SRichard Henderson 2815b384c734SRichard Henderson void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs) 2816c896fe29Sbellard { 2817c896fe29Sbellard char buf[128]; 2818c45cb8bbSRichard Henderson TCGOp *op; 2819c896fe29Sbellard 282015fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 2821c45cb8bbSRichard Henderson int i, k, nb_oargs, nb_iargs, nb_cargs; 2822c45cb8bbSRichard Henderson const TCGOpDef *def; 2823c45cb8bbSRichard Henderson TCGOpcode c; 2824bdfb460eSRichard Henderson int col = 0; 2825c45cb8bbSRichard Henderson 2826c45cb8bbSRichard Henderson c = op->opc; 2827c896fe29Sbellard def = &tcg_op_defs[c]; 2828c45cb8bbSRichard Henderson 2829765b842aSRichard Henderson if (c == INDEX_op_insn_start) { 2830b016486eSRichard Henderson nb_oargs = 0; 2831b7a83ff8SRichard Henderson col += ne_fprintf(f, "\n ----"); 28329aef40edSRichard Henderson 2833747bd69dSRichard Henderson for (i = 0, k = s->insn_start_words; i < k; ++i) { 2834c9ad8d27SRichard Henderson col += ne_fprintf(f, " %016" PRIx64, 2835c9ad8d27SRichard Henderson tcg_get_insn_start_param(op, i)); 2836eeacee4dSBlue Swirl } 28377e4597d7Sbellard } else if (c == INDEX_op_call) { 28383e92aa34SRichard Henderson const TCGHelperInfo *info = tcg_call_info(op); 2839fa52e660SRichard Henderson void *func = tcg_call_func(op); 28403e92aa34SRichard Henderson 2841c896fe29Sbellard /* variable number of arguments */ 2842cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 2843cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 2844c896fe29Sbellard nb_cargs = def->nb_cargs; 2845b03cce8eSbellard 2846b7a83ff8SRichard Henderson col += ne_fprintf(f, " %s ", def->name); 28473e92aa34SRichard Henderson 28483e92aa34SRichard Henderson /* 28493e92aa34SRichard Henderson * Print the function name from TCGHelperInfo, if available. 28503e92aa34SRichard Henderson * Note that plugins have a template function for the info, 28513e92aa34SRichard Henderson * but the actual function pointer comes from the plugin. 28523e92aa34SRichard Henderson */ 28533e92aa34SRichard Henderson if (func == info->func) { 2854b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s", info->name); 28553e92aa34SRichard Henderson } else { 2856b7a83ff8SRichard Henderson col += ne_fprintf(f, "plugin(%p)", func); 28573e92aa34SRichard Henderson } 28583e92aa34SRichard Henderson 2859b7a83ff8SRichard Henderson col += ne_fprintf(f, ",$0x%x,$%d", info->flags, nb_oargs); 2860b03cce8eSbellard for (i = 0; i < nb_oargs; i++) { 2861b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", tcg_get_arg_str(s, buf, sizeof(buf), 2862efee3746SRichard Henderson op->args[i])); 2863b03cce8eSbellard } 2864cf066674SRichard Henderson for (i = 0; i < nb_iargs; i++) { 2865efee3746SRichard Henderson TCGArg arg = op->args[nb_oargs + i]; 286639004a71SRichard Henderson const char *t = tcg_get_arg_str(s, buf, sizeof(buf), arg); 2867b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", t); 2868e8996ee0Sbellard } 2869b03cce8eSbellard } else { 2870b5701261SRichard Henderson if (def->flags & TCG_OPF_INT) { 2871b5701261SRichard Henderson col += ne_fprintf(f, " %s_i%d ", 2872b5701261SRichard Henderson def->name, 2873b5701261SRichard Henderson 8 * tcg_type_size(TCGOP_TYPE(op))); 2874b5701261SRichard Henderson } else if (def->flags & TCG_OPF_VECTOR) { 2875b5701261SRichard Henderson col += ne_fprintf(f, "%s v%d,e%d,", 2876b5701261SRichard Henderson def->name, 2877b5701261SRichard Henderson 8 * tcg_type_size(TCGOP_TYPE(op)), 2878b5701261SRichard Henderson 8 << TCGOP_VECE(op)); 2879b5701261SRichard Henderson } else { 2880b7a83ff8SRichard Henderson col += ne_fprintf(f, " %s ", def->name); 2881b5701261SRichard Henderson } 2882c45cb8bbSRichard Henderson 2883c896fe29Sbellard nb_oargs = def->nb_oargs; 2884c896fe29Sbellard nb_iargs = def->nb_iargs; 2885c896fe29Sbellard nb_cargs = def->nb_cargs; 2886c896fe29Sbellard 2887c896fe29Sbellard k = 0; 2888c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 2889b7a83ff8SRichard Henderson const char *sep = k ? "," : ""; 2890b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s%s", sep, 2891b7a83ff8SRichard Henderson tcg_get_arg_str(s, buf, sizeof(buf), 2892efee3746SRichard Henderson op->args[k++])); 2893c896fe29Sbellard } 2894c896fe29Sbellard for (i = 0; i < nb_iargs; i++) { 2895b7a83ff8SRichard Henderson const char *sep = k ? "," : ""; 2896b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s%s", sep, 2897b7a83ff8SRichard Henderson tcg_get_arg_str(s, buf, sizeof(buf), 2898efee3746SRichard Henderson op->args[k++])); 2899c896fe29Sbellard } 2900be210acbSRichard Henderson switch (c) { 2901b6d69fceSRichard Henderson case INDEX_op_brcond: 2902a363e1e1SRichard Henderson case INDEX_op_setcond: 2903a363e1e1SRichard Henderson case INDEX_op_negsetcond: 2904ea46c4bcSRichard Henderson case INDEX_op_movcond: 2905be210acbSRichard Henderson case INDEX_op_brcond2_i32: 2906be210acbSRichard Henderson case INDEX_op_setcond2_i32: 2907212be173SRichard Henderson case INDEX_op_cmp_vec: 2908f75da298SRichard Henderson case INDEX_op_cmpsel_vec: 2909efee3746SRichard Henderson if (op->args[k] < ARRAY_SIZE(cond_name) 2910efee3746SRichard Henderson && cond_name[op->args[k]]) { 2911b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", cond_name[op->args[k++]]); 2912eeacee4dSBlue Swirl } else { 2913b7a83ff8SRichard Henderson col += ne_fprintf(f, ",$0x%" TCG_PRIlx, op->args[k++]); 2914eeacee4dSBlue Swirl } 2915f48f3edeSblueswir1 i = 1; 2916be210acbSRichard Henderson break; 291750b7a197SRichard Henderson case INDEX_op_qemu_ld_i32: 291850b7a197SRichard Henderson case INDEX_op_qemu_st_i32: 291950b7a197SRichard Henderson case INDEX_op_qemu_st8_i32: 292050b7a197SRichard Henderson case INDEX_op_qemu_ld_i64: 292150b7a197SRichard Henderson case INDEX_op_qemu_st_i64: 292250b7a197SRichard Henderson case INDEX_op_qemu_ld_i128: 292350b7a197SRichard Henderson case INDEX_op_qemu_st_i128: 292459227d5dSRichard Henderson { 292537031fefSRichard Henderson const char *s_al, *s_op, *s_at; 29269002ffcbSRichard Henderson MemOpIdx oi = op->args[k++]; 29279a239c6eSPhilippe Mathieu-Daudé MemOp mop = get_memop(oi); 292859227d5dSRichard Henderson unsigned ix = get_mmuidx(oi); 292959227d5dSRichard Henderson 29309a239c6eSPhilippe Mathieu-Daudé s_al = alignment_name[(mop & MO_AMASK) >> MO_ASHIFT]; 29319a239c6eSPhilippe Mathieu-Daudé s_op = ldst_name[mop & (MO_BSWAP | MO_SSIZE)]; 29329a239c6eSPhilippe Mathieu-Daudé s_at = atom_name[(mop & MO_ATOM_MASK) >> MO_ATOM_SHIFT]; 29339a239c6eSPhilippe Mathieu-Daudé mop &= ~(MO_AMASK | MO_BSWAP | MO_SSIZE | MO_ATOM_MASK); 293437031fefSRichard Henderson 293537031fefSRichard Henderson /* If all fields are accounted for, print symbolically. */ 29369a239c6eSPhilippe Mathieu-Daudé if (!mop && s_al && s_op && s_at) { 293737031fefSRichard Henderson col += ne_fprintf(f, ",%s%s%s,%u", 293837031fefSRichard Henderson s_at, s_al, s_op, ix); 293937031fefSRichard Henderson } else { 29409a239c6eSPhilippe Mathieu-Daudé mop = get_memop(oi); 29419a239c6eSPhilippe Mathieu-Daudé col += ne_fprintf(f, ",$0x%x,%u", mop, ix); 2942f713d6adSRichard Henderson } 2943f713d6adSRichard Henderson i = 1; 294459227d5dSRichard Henderson } 2945f713d6adSRichard Henderson break; 29460dd07ee1SRichard Henderson case INDEX_op_bswap16: 29477498d882SRichard Henderson case INDEX_op_bswap32: 29483ad5d4ccSRichard Henderson case INDEX_op_bswap64: 2949587195bdSRichard Henderson { 2950587195bdSRichard Henderson TCGArg flags = op->args[k]; 2951587195bdSRichard Henderson const char *name = NULL; 2952587195bdSRichard Henderson 2953587195bdSRichard Henderson if (flags < ARRAY_SIZE(bswap_flag_name)) { 2954587195bdSRichard Henderson name = bswap_flag_name[flags]; 2955587195bdSRichard Henderson } 2956587195bdSRichard Henderson if (name) { 2957b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", name); 2958587195bdSRichard Henderson } else { 2959b7a83ff8SRichard Henderson col += ne_fprintf(f, ",$0x%" TCG_PRIlx, flags); 2960587195bdSRichard Henderson } 2961587195bdSRichard Henderson i = k = 1; 2962587195bdSRichard Henderson } 2963587195bdSRichard Henderson break; 2964b384c734SRichard Henderson #ifdef CONFIG_PLUGIN 2965b384c734SRichard Henderson case INDEX_op_plugin_cb: 2966b384c734SRichard Henderson { 2967b384c734SRichard Henderson TCGArg from = op->args[k++]; 2968b384c734SRichard Henderson const char *name = NULL; 2969b384c734SRichard Henderson 2970b384c734SRichard Henderson if (from < ARRAY_SIZE(plugin_from_name)) { 2971b384c734SRichard Henderson name = plugin_from_name[from]; 2972b384c734SRichard Henderson } 2973b384c734SRichard Henderson if (name) { 2974b384c734SRichard Henderson col += ne_fprintf(f, "%s", name); 2975b384c734SRichard Henderson } else { 2976b384c734SRichard Henderson col += ne_fprintf(f, "$0x%" TCG_PRIlx, from); 2977b384c734SRichard Henderson } 2978b384c734SRichard Henderson i = 1; 2979b384c734SRichard Henderson } 2980b384c734SRichard Henderson break; 2981b384c734SRichard Henderson #endif 2982be210acbSRichard Henderson default: 2983f48f3edeSblueswir1 i = 0; 2984be210acbSRichard Henderson break; 2985be210acbSRichard Henderson } 298651e3972cSRichard Henderson switch (c) { 298751e3972cSRichard Henderson case INDEX_op_set_label: 298851e3972cSRichard Henderson case INDEX_op_br: 2989b6d69fceSRichard Henderson case INDEX_op_brcond: 299051e3972cSRichard Henderson case INDEX_op_brcond2_i32: 2991b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s$L%d", k ? "," : "", 2992efee3746SRichard Henderson arg_label(op->args[k])->id); 299351e3972cSRichard Henderson i++, k++; 299451e3972cSRichard Henderson break; 29953470867bSRichard Henderson case INDEX_op_mb: 29963470867bSRichard Henderson { 29973470867bSRichard Henderson TCGBar membar = op->args[k]; 29983470867bSRichard Henderson const char *b_op, *m_op; 29993470867bSRichard Henderson 30003470867bSRichard Henderson switch (membar & TCG_BAR_SC) { 30013470867bSRichard Henderson case 0: 30023470867bSRichard Henderson b_op = "none"; 30033470867bSRichard Henderson break; 30043470867bSRichard Henderson case TCG_BAR_LDAQ: 30053470867bSRichard Henderson b_op = "acq"; 30063470867bSRichard Henderson break; 30073470867bSRichard Henderson case TCG_BAR_STRL: 30083470867bSRichard Henderson b_op = "rel"; 30093470867bSRichard Henderson break; 30103470867bSRichard Henderson case TCG_BAR_SC: 30113470867bSRichard Henderson b_op = "seq"; 30123470867bSRichard Henderson break; 30133470867bSRichard Henderson default: 30143470867bSRichard Henderson g_assert_not_reached(); 30153470867bSRichard Henderson } 30163470867bSRichard Henderson 30173470867bSRichard Henderson switch (membar & TCG_MO_ALL) { 30183470867bSRichard Henderson case 0: 30193470867bSRichard Henderson m_op = "none"; 30203470867bSRichard Henderson break; 30213470867bSRichard Henderson case TCG_MO_LD_LD: 30223470867bSRichard Henderson m_op = "rr"; 30233470867bSRichard Henderson break; 30243470867bSRichard Henderson case TCG_MO_LD_ST: 30253470867bSRichard Henderson m_op = "rw"; 30263470867bSRichard Henderson break; 30273470867bSRichard Henderson case TCG_MO_ST_LD: 30283470867bSRichard Henderson m_op = "wr"; 30293470867bSRichard Henderson break; 30303470867bSRichard Henderson case TCG_MO_ST_ST: 30313470867bSRichard Henderson m_op = "ww"; 30323470867bSRichard Henderson break; 30333470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_LD_ST: 30343470867bSRichard Henderson m_op = "rr+rw"; 30353470867bSRichard Henderson break; 30363470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_ST_LD: 30373470867bSRichard Henderson m_op = "rr+wr"; 30383470867bSRichard Henderson break; 30393470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_ST_ST: 30403470867bSRichard Henderson m_op = "rr+ww"; 30413470867bSRichard Henderson break; 30423470867bSRichard Henderson case TCG_MO_LD_ST | TCG_MO_ST_LD: 30433470867bSRichard Henderson m_op = "rw+wr"; 30443470867bSRichard Henderson break; 30453470867bSRichard Henderson case TCG_MO_LD_ST | TCG_MO_ST_ST: 30463470867bSRichard Henderson m_op = "rw+ww"; 30473470867bSRichard Henderson break; 30483470867bSRichard Henderson case TCG_MO_ST_LD | TCG_MO_ST_ST: 30493470867bSRichard Henderson m_op = "wr+ww"; 30503470867bSRichard Henderson break; 30513470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_MO_ST_LD: 30523470867bSRichard Henderson m_op = "rr+rw+wr"; 30533470867bSRichard Henderson break; 30543470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_MO_ST_ST: 30553470867bSRichard Henderson m_op = "rr+rw+ww"; 30563470867bSRichard Henderson break; 30573470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_ST_LD | TCG_MO_ST_ST: 30583470867bSRichard Henderson m_op = "rr+wr+ww"; 30593470867bSRichard Henderson break; 30603470867bSRichard Henderson case TCG_MO_LD_ST | TCG_MO_ST_LD | TCG_MO_ST_ST: 30613470867bSRichard Henderson m_op = "rw+wr+ww"; 30623470867bSRichard Henderson break; 30633470867bSRichard Henderson case TCG_MO_ALL: 30643470867bSRichard Henderson m_op = "all"; 30653470867bSRichard Henderson break; 30663470867bSRichard Henderson default: 30673470867bSRichard Henderson g_assert_not_reached(); 30683470867bSRichard Henderson } 30693470867bSRichard Henderson 30703470867bSRichard Henderson col += ne_fprintf(f, "%s%s:%s", (k ? "," : ""), b_op, m_op); 30713470867bSRichard Henderson i++, k++; 30723470867bSRichard Henderson } 30733470867bSRichard Henderson break; 307451e3972cSRichard Henderson default: 307551e3972cSRichard Henderson break; 3076eeacee4dSBlue Swirl } 307751e3972cSRichard Henderson for (; i < nb_cargs; i++, k++) { 3078b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s$0x%" TCG_PRIlx, k ? "," : "", 3079b7a83ff8SRichard Henderson op->args[k]); 3080bdfb460eSRichard Henderson } 3081bdfb460eSRichard Henderson } 3082bdfb460eSRichard Henderson 30831894f69aSRichard Henderson if (have_prefs || op->life) { 30841894f69aSRichard Henderson for (; col < 40; ++col) { 3085b7a83ff8SRichard Henderson putc(' ', f); 3086bdfb460eSRichard Henderson } 30871894f69aSRichard Henderson } 30881894f69aSRichard Henderson 30891894f69aSRichard Henderson if (op->life) { 30901894f69aSRichard Henderson unsigned life = op->life; 3091bdfb460eSRichard Henderson 3092bdfb460eSRichard Henderson if (life & (SYNC_ARG * 3)) { 3093b7a83ff8SRichard Henderson ne_fprintf(f, " sync:"); 3094bdfb460eSRichard Henderson for (i = 0; i < 2; ++i) { 3095bdfb460eSRichard Henderson if (life & (SYNC_ARG << i)) { 3096b7a83ff8SRichard Henderson ne_fprintf(f, " %d", i); 3097bdfb460eSRichard Henderson } 3098bdfb460eSRichard Henderson } 3099bdfb460eSRichard Henderson } 3100bdfb460eSRichard Henderson life /= DEAD_ARG; 3101bdfb460eSRichard Henderson if (life) { 3102b7a83ff8SRichard Henderson ne_fprintf(f, " dead:"); 3103bdfb460eSRichard Henderson for (i = 0; life; ++i, life >>= 1) { 3104bdfb460eSRichard Henderson if (life & 1) { 3105b7a83ff8SRichard Henderson ne_fprintf(f, " %d", i); 3106bdfb460eSRichard Henderson } 3107bdfb460eSRichard Henderson } 3108c896fe29Sbellard } 3109b03cce8eSbellard } 31101894f69aSRichard Henderson 31111894f69aSRichard Henderson if (have_prefs) { 31121894f69aSRichard Henderson for (i = 0; i < nb_oargs; ++i) { 311331fd884bSRichard Henderson TCGRegSet set = output_pref(op, i); 31141894f69aSRichard Henderson 31151894f69aSRichard Henderson if (i == 0) { 3116b7a83ff8SRichard Henderson ne_fprintf(f, " pref="); 31171894f69aSRichard Henderson } else { 3118b7a83ff8SRichard Henderson ne_fprintf(f, ","); 31191894f69aSRichard Henderson } 31201894f69aSRichard Henderson if (set == 0) { 3121b7a83ff8SRichard Henderson ne_fprintf(f, "none"); 31221894f69aSRichard Henderson } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) { 3123b7a83ff8SRichard Henderson ne_fprintf(f, "all"); 31241894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG 31251894f69aSRichard Henderson } else if (tcg_regset_single(set)) { 31261894f69aSRichard Henderson TCGReg reg = tcg_regset_first(set); 3127b7a83ff8SRichard Henderson ne_fprintf(f, "%s", tcg_target_reg_names[reg]); 31281894f69aSRichard Henderson #endif 31291894f69aSRichard Henderson } else if (TCG_TARGET_NB_REGS <= 32) { 3130b7a83ff8SRichard Henderson ne_fprintf(f, "0x%x", (uint32_t)set); 31311894f69aSRichard Henderson } else { 3132b7a83ff8SRichard Henderson ne_fprintf(f, "0x%" PRIx64, (uint64_t)set); 31331894f69aSRichard Henderson } 31341894f69aSRichard Henderson } 31351894f69aSRichard Henderson } 31361894f69aSRichard Henderson 3137b7a83ff8SRichard Henderson putc('\n', f); 3138c896fe29Sbellard } 3139c896fe29Sbellard } 3140c896fe29Sbellard 3141c896fe29Sbellard /* we give more priority to constraints with less registers */ 31423e80824eSRichard Henderson static int get_constraint_priority(const TCGArgConstraint *arg_ct, int k) 3143c896fe29Sbellard { 31443e80824eSRichard Henderson int n; 31453e80824eSRichard Henderson 31463e80824eSRichard Henderson arg_ct += k; 31473e80824eSRichard Henderson n = ctpop64(arg_ct->regs); 3148c896fe29Sbellard 314929f5e925SRichard Henderson /* 315029f5e925SRichard Henderson * Sort constraints of a single register first, which includes output 315129f5e925SRichard Henderson * aliases (which must exactly match the input already allocated). 315229f5e925SRichard Henderson */ 315329f5e925SRichard Henderson if (n == 1 || arg_ct->oalias) { 315429f5e925SRichard Henderson return INT_MAX; 3155c896fe29Sbellard } 315629f5e925SRichard Henderson 315729f5e925SRichard Henderson /* 315829f5e925SRichard Henderson * Sort register pairs next, first then second immediately after. 315929f5e925SRichard Henderson * Arbitrarily sort multiple pairs by the index of the first reg; 316029f5e925SRichard Henderson * there shouldn't be many pairs. 316129f5e925SRichard Henderson */ 316229f5e925SRichard Henderson switch (arg_ct->pair) { 316329f5e925SRichard Henderson case 1: 316429f5e925SRichard Henderson case 3: 316529f5e925SRichard Henderson return (k + 1) * 2; 316629f5e925SRichard Henderson case 2: 316729f5e925SRichard Henderson return (arg_ct->pair_index + 1) * 2 - 1; 316829f5e925SRichard Henderson } 316929f5e925SRichard Henderson 317029f5e925SRichard Henderson /* Finally, sort by decreasing register count. */ 317129f5e925SRichard Henderson assert(n > 1); 317229f5e925SRichard Henderson return -n; 3173c896fe29Sbellard } 3174c896fe29Sbellard 3175c896fe29Sbellard /* sort from highest priority to lowest */ 31763e80824eSRichard Henderson static void sort_constraints(TCGArgConstraint *a, int start, int n) 3177c896fe29Sbellard { 317866792f90SRichard Henderson int i, j; 3179c896fe29Sbellard 318066792f90SRichard Henderson for (i = 0; i < n; i++) { 318166792f90SRichard Henderson a[start + i].sort_index = start + i; 318266792f90SRichard Henderson } 318366792f90SRichard Henderson if (n <= 1) { 3184c896fe29Sbellard return; 318566792f90SRichard Henderson } 3186c896fe29Sbellard for (i = 0; i < n - 1; i++) { 3187c896fe29Sbellard for (j = i + 1; j < n; j++) { 31883e80824eSRichard Henderson int p1 = get_constraint_priority(a, a[start + i].sort_index); 31893e80824eSRichard Henderson int p2 = get_constraint_priority(a, a[start + j].sort_index); 3190c896fe29Sbellard if (p1 < p2) { 319166792f90SRichard Henderson int tmp = a[start + i].sort_index; 319266792f90SRichard Henderson a[start + i].sort_index = a[start + j].sort_index; 319366792f90SRichard Henderson a[start + j].sort_index = tmp; 3194c896fe29Sbellard } 3195c896fe29Sbellard } 3196c896fe29Sbellard } 3197c896fe29Sbellard } 3198c896fe29Sbellard 31993e80824eSRichard Henderson static const TCGArgConstraint empty_cts[TCG_MAX_OP_ARGS]; 32003e80824eSRichard Henderson static TCGArgConstraint all_cts[ARRAY_SIZE(constraint_sets)][TCG_MAX_OP_ARGS]; 32013e80824eSRichard Henderson 3202501fb3daSRichard Henderson static void process_constraint_sets(void) 3203c896fe29Sbellard { 32043e80824eSRichard Henderson for (size_t c = 0; c < ARRAY_SIZE(constraint_sets); ++c) { 32053e80824eSRichard Henderson const TCGConstraintSet *tdefs = &constraint_sets[c]; 32063e80824eSRichard Henderson TCGArgConstraint *args_ct = all_cts[c]; 32073e80824eSRichard Henderson int nb_oargs = tdefs->nb_oargs; 32083e80824eSRichard Henderson int nb_iargs = tdefs->nb_iargs; 32093e80824eSRichard Henderson int nb_args = nb_oargs + nb_iargs; 321029f5e925SRichard Henderson bool saw_alias_pair = false; 3211f69d277eSRichard Henderson 32123e80824eSRichard Henderson for (int i = 0; i < nb_args; i++) { 3213f69d277eSRichard Henderson const char *ct_str = tdefs->args_ct_str[i]; 32143e80824eSRichard Henderson bool input_p = i >= nb_oargs; 32153e80824eSRichard Henderson int o; 3216f69d277eSRichard Henderson 321717280ff4SRichard Henderson switch (*ct_str) { 321817280ff4SRichard Henderson case '0' ... '9': 32198940ea0dSPhilippe Mathieu-Daudé o = *ct_str - '0'; 32208940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(input_p); 32213e80824eSRichard Henderson tcg_debug_assert(o < nb_oargs); 32223e80824eSRichard Henderson tcg_debug_assert(args_ct[o].regs != 0); 32233e80824eSRichard Henderson tcg_debug_assert(!args_ct[o].oalias); 32243e80824eSRichard Henderson args_ct[i] = args_ct[o]; 3225bc2b17e6SRichard Henderson /* The output sets oalias. */ 32263e80824eSRichard Henderson args_ct[o].oalias = 1; 32273e80824eSRichard Henderson args_ct[o].alias_index = i; 3228bc2b17e6SRichard Henderson /* The input sets ialias. */ 32293e80824eSRichard Henderson args_ct[i].ialias = 1; 32303e80824eSRichard Henderson args_ct[i].alias_index = o; 32313e80824eSRichard Henderson if (args_ct[i].pair) { 323229f5e925SRichard Henderson saw_alias_pair = true; 323329f5e925SRichard Henderson } 32348940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(ct_str[1] == '\0'); 32358940ea0dSPhilippe Mathieu-Daudé continue; 32368940ea0dSPhilippe Mathieu-Daudé 323782790a87SRichard Henderson case '&': 32388940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(!input_p); 32393e80824eSRichard Henderson args_ct[i].newreg = true; 324082790a87SRichard Henderson ct_str++; 324182790a87SRichard Henderson break; 324229f5e925SRichard Henderson 324329f5e925SRichard Henderson case 'p': /* plus */ 324429f5e925SRichard Henderson /* Allocate to the register after the previous. */ 32453e80824eSRichard Henderson tcg_debug_assert(i > (input_p ? nb_oargs : 0)); 324629f5e925SRichard Henderson o = i - 1; 32473e80824eSRichard Henderson tcg_debug_assert(!args_ct[o].pair); 32483e80824eSRichard Henderson tcg_debug_assert(!args_ct[o].ct); 32493e80824eSRichard Henderson args_ct[i] = (TCGArgConstraint){ 325029f5e925SRichard Henderson .pair = 2, 325129f5e925SRichard Henderson .pair_index = o, 32523e80824eSRichard Henderson .regs = args_ct[o].regs << 1, 32533e80824eSRichard Henderson .newreg = args_ct[o].newreg, 325429f5e925SRichard Henderson }; 32553e80824eSRichard Henderson args_ct[o].pair = 1; 32563e80824eSRichard Henderson args_ct[o].pair_index = i; 325729f5e925SRichard Henderson tcg_debug_assert(ct_str[1] == '\0'); 325829f5e925SRichard Henderson continue; 325929f5e925SRichard Henderson 326029f5e925SRichard Henderson case 'm': /* minus */ 326129f5e925SRichard Henderson /* Allocate to the register before the previous. */ 32623e80824eSRichard Henderson tcg_debug_assert(i > (input_p ? nb_oargs : 0)); 326329f5e925SRichard Henderson o = i - 1; 32643e80824eSRichard Henderson tcg_debug_assert(!args_ct[o].pair); 32653e80824eSRichard Henderson tcg_debug_assert(!args_ct[o].ct); 32663e80824eSRichard Henderson args_ct[i] = (TCGArgConstraint){ 326729f5e925SRichard Henderson .pair = 1, 326829f5e925SRichard Henderson .pair_index = o, 32693e80824eSRichard Henderson .regs = args_ct[o].regs >> 1, 32703e80824eSRichard Henderson .newreg = args_ct[o].newreg, 327129f5e925SRichard Henderson }; 32723e80824eSRichard Henderson args_ct[o].pair = 2; 32733e80824eSRichard Henderson args_ct[o].pair_index = i; 327429f5e925SRichard Henderson tcg_debug_assert(ct_str[1] == '\0'); 327529f5e925SRichard Henderson continue; 32768940ea0dSPhilippe Mathieu-Daudé } 32778940ea0dSPhilippe Mathieu-Daudé 32788940ea0dSPhilippe Mathieu-Daudé do { 32798940ea0dSPhilippe Mathieu-Daudé switch (*ct_str) { 3280c896fe29Sbellard case 'i': 32813e80824eSRichard Henderson args_ct[i].ct |= TCG_CT_CONST; 3282c896fe29Sbellard break; 32836b8abd24SRichard Henderson #ifdef TCG_REG_ZERO 32846b8abd24SRichard Henderson case 'z': 32856b8abd24SRichard Henderson args_ct[i].ct |= TCG_CT_REG_ZERO; 32866b8abd24SRichard Henderson break; 32876b8abd24SRichard Henderson #endif 3288358b4923SRichard Henderson 3289358b4923SRichard Henderson /* Include all of the target-specific constraints. */ 3290358b4923SRichard Henderson 3291358b4923SRichard Henderson #undef CONST 3292358b4923SRichard Henderson #define CONST(CASE, MASK) \ 32933e80824eSRichard Henderson case CASE: args_ct[i].ct |= MASK; break; 3294358b4923SRichard Henderson #define REGS(CASE, MASK) \ 32953e80824eSRichard Henderson case CASE: args_ct[i].regs |= MASK; break; 3296358b4923SRichard Henderson 3297358b4923SRichard Henderson #include "tcg-target-con-str.h" 3298358b4923SRichard Henderson 3299358b4923SRichard Henderson #undef REGS 3300358b4923SRichard Henderson #undef CONST 3301c896fe29Sbellard default: 33028940ea0dSPhilippe Mathieu-Daudé case '0' ... '9': 33038940ea0dSPhilippe Mathieu-Daudé case '&': 330429f5e925SRichard Henderson case 'p': 330529f5e925SRichard Henderson case 'm': 33063e80824eSRichard Henderson /* Typo in TCGConstraintSet constraint. */ 3307358b4923SRichard Henderson g_assert_not_reached(); 3308358b4923SRichard Henderson } 33098940ea0dSPhilippe Mathieu-Daudé } while (*++ct_str != '\0'); 3310c896fe29Sbellard } 3311c896fe29Sbellard 331229f5e925SRichard Henderson /* 331329f5e925SRichard Henderson * Fix up output pairs that are aliased with inputs. 331429f5e925SRichard Henderson * When we created the alias, we copied pair from the output. 331529f5e925SRichard Henderson * There are three cases: 331629f5e925SRichard Henderson * (1a) Pairs of inputs alias pairs of outputs. 331729f5e925SRichard Henderson * (1b) One input aliases the first of a pair of outputs. 331829f5e925SRichard Henderson * (2) One input aliases the second of a pair of outputs. 331929f5e925SRichard Henderson * 332029f5e925SRichard Henderson * Case 1a is handled by making sure that the pair_index'es are 332129f5e925SRichard Henderson * properly updated so that they appear the same as a pair of inputs. 332229f5e925SRichard Henderson * 332329f5e925SRichard Henderson * Case 1b is handled by setting the pair_index of the input to 332429f5e925SRichard Henderson * itself, simply so it doesn't point to an unrelated argument. 332529f5e925SRichard Henderson * Since we don't encounter the "second" during the input allocation 332629f5e925SRichard Henderson * phase, nothing happens with the second half of the input pair. 332729f5e925SRichard Henderson * 332829f5e925SRichard Henderson * Case 2 is handled by setting the second input to pair=3, the 332929f5e925SRichard Henderson * first output to pair=3, and the pair_index'es to match. 333029f5e925SRichard Henderson */ 333129f5e925SRichard Henderson if (saw_alias_pair) { 33323e80824eSRichard Henderson for (int i = nb_oargs; i < nb_args; i++) { 33333e80824eSRichard Henderson int o, o2, i2; 33343e80824eSRichard Henderson 333529f5e925SRichard Henderson /* 333629f5e925SRichard Henderson * Since [0-9pm] must be alone in the constraint string, 333729f5e925SRichard Henderson * the only way they can both be set is if the pair comes 333829f5e925SRichard Henderson * from the output alias. 333929f5e925SRichard Henderson */ 33403e80824eSRichard Henderson if (!args_ct[i].ialias) { 334129f5e925SRichard Henderson continue; 334229f5e925SRichard Henderson } 33433e80824eSRichard Henderson switch (args_ct[i].pair) { 334429f5e925SRichard Henderson case 0: 334529f5e925SRichard Henderson break; 334629f5e925SRichard Henderson case 1: 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 == 1); 33503e80824eSRichard Henderson tcg_debug_assert(args_ct[o2].pair == 2); 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 == 2); 33553e80824eSRichard Henderson args_ct[i2].pair_index = i; 33563e80824eSRichard Henderson args_ct[i].pair_index = i2; 335729f5e925SRichard Henderson } else { 335829f5e925SRichard Henderson /* Case 1b */ 33593e80824eSRichard Henderson args_ct[i].pair_index = i; 336029f5e925SRichard Henderson } 336129f5e925SRichard Henderson break; 336229f5e925SRichard Henderson case 2: 33633e80824eSRichard Henderson o = args_ct[i].alias_index; 33643e80824eSRichard Henderson o2 = args_ct[o].pair_index; 33653e80824eSRichard Henderson tcg_debug_assert(args_ct[o].pair == 2); 33663e80824eSRichard Henderson tcg_debug_assert(args_ct[o2].pair == 1); 33673e80824eSRichard Henderson if (args_ct[o2].oalias) { 336829f5e925SRichard Henderson /* Case 1a */ 33693e80824eSRichard Henderson i2 = args_ct[o2].alias_index; 33703e80824eSRichard Henderson tcg_debug_assert(args_ct[i2].pair == 1); 33713e80824eSRichard Henderson args_ct[i2].pair_index = i; 33723e80824eSRichard Henderson args_ct[i].pair_index = i2; 337329f5e925SRichard Henderson } else { 337429f5e925SRichard Henderson /* Case 2 */ 33753e80824eSRichard Henderson args_ct[i].pair = 3; 33763e80824eSRichard Henderson args_ct[o2].pair = 3; 33773e80824eSRichard Henderson args_ct[i].pair_index = o2; 33783e80824eSRichard Henderson args_ct[o2].pair_index = i; 337929f5e925SRichard Henderson } 338029f5e925SRichard Henderson break; 338129f5e925SRichard Henderson default: 338229f5e925SRichard Henderson g_assert_not_reached(); 338329f5e925SRichard Henderson } 338429f5e925SRichard Henderson } 338529f5e925SRichard Henderson } 338629f5e925SRichard Henderson 3387c896fe29Sbellard /* sort the constraints (XXX: this is just an heuristic) */ 33883e80824eSRichard Henderson sort_constraints(args_ct, 0, nb_oargs); 33893e80824eSRichard Henderson sort_constraints(args_ct, nb_oargs, nb_iargs); 33903e80824eSRichard Henderson } 3391501fb3daSRichard Henderson } 33923e80824eSRichard Henderson 3393501fb3daSRichard Henderson static const TCGArgConstraint *opcode_args_ct(const TCGOp *op) 3394501fb3daSRichard Henderson { 33955500bd9eSRichard Henderson TCGOpcode opc = op->opc; 33965500bd9eSRichard Henderson TCGType type = TCGOP_TYPE(op); 33975500bd9eSRichard Henderson unsigned flags = TCGOP_FLAGS(op); 33985500bd9eSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 33995500bd9eSRichard Henderson const TCGOutOp *outop = all_outop[opc]; 34003e80824eSRichard Henderson TCGConstraintSetIndex con_set; 34013e80824eSRichard Henderson 34023e80824eSRichard Henderson if (def->flags & TCG_OPF_NOT_PRESENT) { 3403501fb3daSRichard Henderson return empty_cts; 34043e80824eSRichard Henderson } 34053e80824eSRichard Henderson 34065500bd9eSRichard Henderson if (outop) { 34075500bd9eSRichard Henderson con_set = outop->static_constraint; 34085500bd9eSRichard Henderson if (con_set == C_Dynamic) { 34095500bd9eSRichard Henderson con_set = outop->dynamic_constraint(type, flags); 34105500bd9eSRichard Henderson } 34115500bd9eSRichard Henderson } else { 34125500bd9eSRichard Henderson con_set = tcg_target_op_def(opc, type, flags); 34135500bd9eSRichard Henderson } 34145500bd9eSRichard Henderson tcg_debug_assert(con_set >= 0); 34155500bd9eSRichard Henderson tcg_debug_assert(con_set < ARRAY_SIZE(constraint_sets)); 34163e80824eSRichard Henderson 34173e80824eSRichard Henderson /* The constraint arguments must match TCGOpcode arguments. */ 3418501fb3daSRichard Henderson tcg_debug_assert(constraint_sets[con_set].nb_oargs == def->nb_oargs); 3419501fb3daSRichard Henderson tcg_debug_assert(constraint_sets[con_set].nb_iargs == def->nb_iargs); 34203e80824eSRichard Henderson 3421501fb3daSRichard Henderson return all_cts[con_set]; 3422c896fe29Sbellard } 3423c896fe29Sbellard 3424f85b1fc4SRichard Henderson static void remove_label_use(TCGOp *op, int idx) 3425f85b1fc4SRichard Henderson { 3426f85b1fc4SRichard Henderson TCGLabel *label = arg_label(op->args[idx]); 3427f85b1fc4SRichard Henderson TCGLabelUse *use; 3428f85b1fc4SRichard Henderson 3429f85b1fc4SRichard Henderson QSIMPLEQ_FOREACH(use, &label->branches, next) { 3430f85b1fc4SRichard Henderson if (use->op == op) { 3431f85b1fc4SRichard Henderson QSIMPLEQ_REMOVE(&label->branches, use, TCGLabelUse, next); 3432f85b1fc4SRichard Henderson return; 3433f85b1fc4SRichard Henderson } 3434f85b1fc4SRichard Henderson } 3435f85b1fc4SRichard Henderson g_assert_not_reached(); 3436f85b1fc4SRichard Henderson } 3437f85b1fc4SRichard Henderson 34380c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op) 34390c627cdcSRichard Henderson { 3440d88a117eSRichard Henderson switch (op->opc) { 3441d88a117eSRichard Henderson case INDEX_op_br: 3442f85b1fc4SRichard Henderson remove_label_use(op, 0); 3443d88a117eSRichard Henderson break; 3444b6d69fceSRichard Henderson case INDEX_op_brcond: 3445f85b1fc4SRichard Henderson remove_label_use(op, 3); 3446d88a117eSRichard Henderson break; 3447d88a117eSRichard Henderson case INDEX_op_brcond2_i32: 3448f85b1fc4SRichard Henderson remove_label_use(op, 5); 3449d88a117eSRichard Henderson break; 3450d88a117eSRichard Henderson default: 3451d88a117eSRichard Henderson break; 3452d88a117eSRichard Henderson } 3453d88a117eSRichard Henderson 345415fa08f8SRichard Henderson QTAILQ_REMOVE(&s->ops, op, link); 345515fa08f8SRichard Henderson QTAILQ_INSERT_TAIL(&s->free_ops, op, link); 3456abebf925SRichard Henderson s->nb_ops--; 34570c627cdcSRichard Henderson } 34580c627cdcSRichard Henderson 3459a80cdd31SRichard Henderson void tcg_remove_ops_after(TCGOp *op) 3460a80cdd31SRichard Henderson { 3461a80cdd31SRichard Henderson TCGContext *s = tcg_ctx; 3462a80cdd31SRichard Henderson 3463a80cdd31SRichard Henderson while (true) { 3464a80cdd31SRichard Henderson TCGOp *last = tcg_last_op(); 3465a80cdd31SRichard Henderson if (last == op) { 3466a80cdd31SRichard Henderson return; 3467a80cdd31SRichard Henderson } 3468a80cdd31SRichard Henderson tcg_op_remove(s, last); 3469a80cdd31SRichard Henderson } 3470a80cdd31SRichard Henderson } 3471a80cdd31SRichard Henderson 3472d4478943SPhilippe Mathieu-Daudé static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs) 347315fa08f8SRichard Henderson { 347415fa08f8SRichard Henderson TCGContext *s = tcg_ctx; 3475cb10bc63SRichard Henderson TCGOp *op = NULL; 347615fa08f8SRichard Henderson 3477cb10bc63SRichard Henderson if (unlikely(!QTAILQ_EMPTY(&s->free_ops))) { 3478cb10bc63SRichard Henderson QTAILQ_FOREACH(op, &s->free_ops, link) { 3479cb10bc63SRichard Henderson if (nargs <= op->nargs) { 348015fa08f8SRichard Henderson QTAILQ_REMOVE(&s->free_ops, op, link); 3481cb10bc63SRichard Henderson nargs = op->nargs; 3482cb10bc63SRichard Henderson goto found; 348315fa08f8SRichard Henderson } 3484cb10bc63SRichard Henderson } 3485cb10bc63SRichard Henderson } 3486cb10bc63SRichard Henderson 3487cb10bc63SRichard Henderson /* Most opcodes have 3 or 4 operands: reduce fragmentation. */ 3488cb10bc63SRichard Henderson nargs = MAX(4, nargs); 3489cb10bc63SRichard Henderson op = tcg_malloc(sizeof(TCGOp) + sizeof(TCGArg) * nargs); 3490cb10bc63SRichard Henderson 3491cb10bc63SRichard Henderson found: 349215fa08f8SRichard Henderson memset(op, 0, offsetof(TCGOp, link)); 349315fa08f8SRichard Henderson op->opc = opc; 3494cb10bc63SRichard Henderson op->nargs = nargs; 349515fa08f8SRichard Henderson 3496cb10bc63SRichard Henderson /* Check for bitfield overflow. */ 3497cb10bc63SRichard Henderson tcg_debug_assert(op->nargs == nargs); 3498cb10bc63SRichard Henderson 3499cb10bc63SRichard Henderson s->nb_ops++; 350015fa08f8SRichard Henderson return op; 350115fa08f8SRichard Henderson } 350215fa08f8SRichard Henderson 3503d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_emit_op(TCGOpcode opc, unsigned nargs) 350415fa08f8SRichard Henderson { 3505d4478943SPhilippe Mathieu-Daudé TCGOp *op = tcg_op_alloc(opc, nargs); 350607843f75SRichard Henderson 350707843f75SRichard Henderson if (tcg_ctx->emit_before_op) { 350807843f75SRichard Henderson QTAILQ_INSERT_BEFORE(tcg_ctx->emit_before_op, op, link); 350907843f75SRichard Henderson } else { 351015fa08f8SRichard Henderson QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link); 351107843f75SRichard Henderson } 351215fa08f8SRichard Henderson return op; 351315fa08f8SRichard Henderson } 351415fa08f8SRichard Henderson 3515d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op, 3516cf5c9f69SRichard Henderson TCGOpcode opc, TCGType type, unsigned nargs) 35175a18407fSRichard Henderson { 3518d4478943SPhilippe Mathieu-Daudé TCGOp *new_op = tcg_op_alloc(opc, nargs); 3519fb744eceSRichard Henderson 3520cf5c9f69SRichard Henderson TCGOP_TYPE(new_op) = type; 352115fa08f8SRichard Henderson QTAILQ_INSERT_BEFORE(old_op, new_op, link); 35225a18407fSRichard Henderson return new_op; 35235a18407fSRichard Henderson } 35245a18407fSRichard Henderson 3525d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, 3526cf5c9f69SRichard Henderson TCGOpcode opc, TCGType type, unsigned nargs) 35275a18407fSRichard Henderson { 3528d4478943SPhilippe Mathieu-Daudé TCGOp *new_op = tcg_op_alloc(opc, nargs); 3529fb744eceSRichard Henderson 3530cf5c9f69SRichard Henderson TCGOP_TYPE(new_op) = type; 353115fa08f8SRichard Henderson QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link); 35325a18407fSRichard Henderson return new_op; 35335a18407fSRichard Henderson } 35345a18407fSRichard Henderson 3535968f305eSRichard Henderson static void move_label_uses(TCGLabel *to, TCGLabel *from) 3536968f305eSRichard Henderson { 3537968f305eSRichard Henderson TCGLabelUse *u; 3538968f305eSRichard Henderson 3539968f305eSRichard Henderson QSIMPLEQ_FOREACH(u, &from->branches, next) { 3540968f305eSRichard Henderson TCGOp *op = u->op; 3541968f305eSRichard Henderson switch (op->opc) { 3542968f305eSRichard Henderson case INDEX_op_br: 3543968f305eSRichard Henderson op->args[0] = label_arg(to); 3544968f305eSRichard Henderson break; 3545b6d69fceSRichard Henderson case INDEX_op_brcond: 3546968f305eSRichard Henderson op->args[3] = label_arg(to); 3547968f305eSRichard Henderson break; 3548968f305eSRichard Henderson case INDEX_op_brcond2_i32: 3549968f305eSRichard Henderson op->args[5] = label_arg(to); 3550968f305eSRichard Henderson break; 3551968f305eSRichard Henderson default: 3552968f305eSRichard Henderson g_assert_not_reached(); 3553968f305eSRichard Henderson } 3554968f305eSRichard Henderson } 3555968f305eSRichard Henderson 3556968f305eSRichard Henderson QSIMPLEQ_CONCAT(&to->branches, &from->branches); 3557968f305eSRichard Henderson } 3558968f305eSRichard Henderson 3559b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code. */ 35609bbee4c0SRichard Henderson static void __attribute__((noinline)) 35619bbee4c0SRichard Henderson reachable_code_pass(TCGContext *s) 3562b4fc67c7SRichard Henderson { 35634d89d0bbSRichard Henderson TCGOp *op, *op_next, *op_prev; 3564b4fc67c7SRichard Henderson bool dead = false; 3565b4fc67c7SRichard Henderson 3566b4fc67c7SRichard Henderson QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) { 3567b4fc67c7SRichard Henderson bool remove = dead; 3568b4fc67c7SRichard Henderson TCGLabel *label; 3569b4fc67c7SRichard Henderson 3570b4fc67c7SRichard Henderson switch (op->opc) { 3571b4fc67c7SRichard Henderson case INDEX_op_set_label: 3572b4fc67c7SRichard Henderson label = arg_label(op->args[0]); 35734d89d0bbSRichard Henderson 35744d89d0bbSRichard Henderson /* 3575968f305eSRichard Henderson * Note that the first op in the TB is always a load, 3576968f305eSRichard Henderson * so there is always something before a label. 3577968f305eSRichard Henderson */ 3578968f305eSRichard Henderson op_prev = QTAILQ_PREV(op, link); 3579968f305eSRichard Henderson 3580968f305eSRichard Henderson /* 3581968f305eSRichard Henderson * If we find two sequential labels, move all branches to 3582968f305eSRichard Henderson * reference the second label and remove the first label. 3583968f305eSRichard Henderson * Do this before branch to next optimization, so that the 3584968f305eSRichard Henderson * middle label is out of the way. 3585968f305eSRichard Henderson */ 3586968f305eSRichard Henderson if (op_prev->opc == INDEX_op_set_label) { 3587968f305eSRichard Henderson move_label_uses(label, arg_label(op_prev->args[0])); 3588968f305eSRichard Henderson tcg_op_remove(s, op_prev); 3589968f305eSRichard Henderson op_prev = QTAILQ_PREV(op, link); 3590968f305eSRichard Henderson } 3591968f305eSRichard Henderson 3592968f305eSRichard Henderson /* 35934d89d0bbSRichard Henderson * Optimization can fold conditional branches to unconditional. 35944d89d0bbSRichard Henderson * If we find a label which is preceded by an unconditional 35954d89d0bbSRichard Henderson * branch to next, remove the branch. We couldn't do this when 35964d89d0bbSRichard Henderson * processing the branch because any dead code between the branch 35974d89d0bbSRichard Henderson * and label had not yet been removed. 35984d89d0bbSRichard Henderson */ 35994d89d0bbSRichard Henderson if (op_prev->opc == INDEX_op_br && 36004d89d0bbSRichard Henderson label == arg_label(op_prev->args[0])) { 36014d89d0bbSRichard Henderson tcg_op_remove(s, op_prev); 36024d89d0bbSRichard Henderson /* Fall through means insns become live again. */ 36034d89d0bbSRichard Henderson dead = false; 36044d89d0bbSRichard Henderson } 36054d89d0bbSRichard Henderson 3606f85b1fc4SRichard Henderson if (QSIMPLEQ_EMPTY(&label->branches)) { 3607b4fc67c7SRichard Henderson /* 3608b4fc67c7SRichard Henderson * While there is an occasional backward branch, virtually 3609b4fc67c7SRichard Henderson * all branches generated by the translators are forward. 3610b4fc67c7SRichard Henderson * Which means that generally we will have already removed 3611b4fc67c7SRichard Henderson * all references to the label that will be, and there is 3612b4fc67c7SRichard Henderson * little to be gained by iterating. 3613b4fc67c7SRichard Henderson */ 3614b4fc67c7SRichard Henderson remove = true; 3615b4fc67c7SRichard Henderson } else { 3616b4fc67c7SRichard Henderson /* Once we see a label, insns become live again. */ 3617b4fc67c7SRichard Henderson dead = false; 3618b4fc67c7SRichard Henderson remove = false; 3619b4fc67c7SRichard Henderson } 3620b4fc67c7SRichard Henderson break; 3621b4fc67c7SRichard Henderson 3622b4fc67c7SRichard Henderson case INDEX_op_br: 3623b4fc67c7SRichard Henderson case INDEX_op_exit_tb: 3624b4fc67c7SRichard Henderson case INDEX_op_goto_ptr: 3625b4fc67c7SRichard Henderson /* Unconditional branches; everything following is dead. */ 3626b4fc67c7SRichard Henderson dead = true; 3627b4fc67c7SRichard Henderson break; 3628b4fc67c7SRichard Henderson 3629b4fc67c7SRichard Henderson case INDEX_op_call: 3630b4fc67c7SRichard Henderson /* Notice noreturn helper calls, raising exceptions. */ 363190163900SRichard Henderson if (tcg_call_flags(op) & TCG_CALL_NO_RETURN) { 3632b4fc67c7SRichard Henderson dead = true; 3633b4fc67c7SRichard Henderson } 3634b4fc67c7SRichard Henderson break; 3635b4fc67c7SRichard Henderson 3636b4fc67c7SRichard Henderson case INDEX_op_insn_start: 3637b4fc67c7SRichard Henderson /* Never remove -- we need to keep these for unwind. */ 3638b4fc67c7SRichard Henderson remove = false; 3639b4fc67c7SRichard Henderson break; 3640b4fc67c7SRichard Henderson 3641b4fc67c7SRichard Henderson default: 3642b4fc67c7SRichard Henderson break; 3643b4fc67c7SRichard Henderson } 3644b4fc67c7SRichard Henderson 3645b4fc67c7SRichard Henderson if (remove) { 3646b4fc67c7SRichard Henderson tcg_op_remove(s, op); 3647b4fc67c7SRichard Henderson } 3648b4fc67c7SRichard Henderson } 3649b4fc67c7SRichard Henderson } 3650b4fc67c7SRichard Henderson 3651c70fbf0aSRichard Henderson #define TS_DEAD 1 3652c70fbf0aSRichard Henderson #define TS_MEM 2 3653c70fbf0aSRichard Henderson 36545a18407fSRichard Henderson #define IS_DEAD_ARG(n) (arg_life & (DEAD_ARG << (n))) 36555a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n))) 36565a18407fSRichard Henderson 365725f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp. */ 365825f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts) 365925f49c5fSRichard Henderson { 366025f49c5fSRichard Henderson return ts->state_ptr; 366125f49c5fSRichard Henderson } 366225f49c5fSRichard Henderson 366325f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the 366425f49c5fSRichard Henderson * maximal regset for its type. 366525f49c5fSRichard Henderson */ 366625f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts) 366725f49c5fSRichard Henderson { 366825f49c5fSRichard Henderson *la_temp_pref(ts) 366925f49c5fSRichard Henderson = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]); 367025f49c5fSRichard Henderson } 367125f49c5fSRichard Henderson 36729c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals 36739c43b68dSAurelien Jarno should be in memory. */ 36742616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt) 3675c896fe29Sbellard { 3676b83eabeaSRichard Henderson int i; 3677b83eabeaSRichard Henderson 3678b83eabeaSRichard Henderson for (i = 0; i < ng; ++i) { 3679b83eabeaSRichard Henderson s->temps[i].state = TS_DEAD | TS_MEM; 368025f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 3681b83eabeaSRichard Henderson } 3682b83eabeaSRichard Henderson for (i = ng; i < nt; ++i) { 3683b83eabeaSRichard Henderson s->temps[i].state = TS_DEAD; 368425f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 3685b83eabeaSRichard Henderson } 3686c896fe29Sbellard } 3687c896fe29Sbellard 36889c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals 36899c43b68dSAurelien Jarno and local temps should be in memory. */ 36902616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt) 3691641d5fbeSbellard { 3692b83eabeaSRichard Henderson int i; 3693641d5fbeSbellard 3694ee17db83SRichard Henderson for (i = 0; i < nt; ++i) { 3695ee17db83SRichard Henderson TCGTemp *ts = &s->temps[i]; 3696ee17db83SRichard Henderson int state; 3697ee17db83SRichard Henderson 3698ee17db83SRichard Henderson switch (ts->kind) { 3699ee17db83SRichard Henderson case TEMP_FIXED: 3700ee17db83SRichard Henderson case TEMP_GLOBAL: 3701f57c6915SRichard Henderson case TEMP_TB: 3702ee17db83SRichard Henderson state = TS_DEAD | TS_MEM; 3703ee17db83SRichard Henderson break; 3704c7482438SRichard Henderson case TEMP_EBB: 3705c0522136SRichard Henderson case TEMP_CONST: 3706ee17db83SRichard Henderson state = TS_DEAD; 3707ee17db83SRichard Henderson break; 3708ee17db83SRichard Henderson default: 3709ee17db83SRichard Henderson g_assert_not_reached(); 3710c70fbf0aSRichard Henderson } 3711ee17db83SRichard Henderson ts->state = state; 3712ee17db83SRichard Henderson la_reset_pref(ts); 3713641d5fbeSbellard } 3714641d5fbeSbellard } 3715641d5fbeSbellard 3716f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory. */ 3717f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng) 3718f65a061cSRichard Henderson { 3719f65a061cSRichard Henderson int i; 3720f65a061cSRichard Henderson 3721f65a061cSRichard Henderson for (i = 0; i < ng; ++i) { 372225f49c5fSRichard Henderson int state = s->temps[i].state; 372325f49c5fSRichard Henderson s->temps[i].state = state | TS_MEM; 372425f49c5fSRichard Henderson if (state == TS_DEAD) { 372525f49c5fSRichard Henderson /* If the global was previously dead, reset prefs. */ 372625f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 372725f49c5fSRichard Henderson } 3728f65a061cSRichard Henderson } 3729f65a061cSRichard Henderson } 3730f65a061cSRichard Henderson 3731b4cb76e6SRichard Henderson /* 3732c7482438SRichard Henderson * liveness analysis: conditional branch: all temps are dead unless 3733c7482438SRichard Henderson * explicitly live-across-conditional-branch, globals and local temps 3734c7482438SRichard Henderson * should be synced. 3735b4cb76e6SRichard Henderson */ 3736b4cb76e6SRichard Henderson static void la_bb_sync(TCGContext *s, int ng, int nt) 3737b4cb76e6SRichard Henderson { 3738b4cb76e6SRichard Henderson la_global_sync(s, ng); 3739b4cb76e6SRichard Henderson 3740b4cb76e6SRichard Henderson for (int i = ng; i < nt; ++i) { 3741c0522136SRichard Henderson TCGTemp *ts = &s->temps[i]; 3742c0522136SRichard Henderson int state; 3743c0522136SRichard Henderson 3744c0522136SRichard Henderson switch (ts->kind) { 3745f57c6915SRichard Henderson case TEMP_TB: 3746c0522136SRichard Henderson state = ts->state; 3747c0522136SRichard Henderson ts->state = state | TS_MEM; 3748b4cb76e6SRichard Henderson if (state != TS_DEAD) { 3749b4cb76e6SRichard Henderson continue; 3750b4cb76e6SRichard Henderson } 3751c0522136SRichard Henderson break; 3752c7482438SRichard Henderson case TEMP_EBB: 3753c0522136SRichard Henderson case TEMP_CONST: 3754c0522136SRichard Henderson continue; 3755c0522136SRichard Henderson default: 3756c0522136SRichard Henderson g_assert_not_reached(); 3757b4cb76e6SRichard Henderson } 3758b4cb76e6SRichard Henderson la_reset_pref(&s->temps[i]); 3759b4cb76e6SRichard Henderson } 3760b4cb76e6SRichard Henderson } 3761b4cb76e6SRichard Henderson 3762f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill. */ 3763f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng) 3764f65a061cSRichard Henderson { 3765f65a061cSRichard Henderson int i; 3766f65a061cSRichard Henderson 3767f65a061cSRichard Henderson for (i = 0; i < ng; i++) { 3768f65a061cSRichard Henderson s->temps[i].state = TS_DEAD | TS_MEM; 376925f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 377025f49c5fSRichard Henderson } 377125f49c5fSRichard Henderson } 377225f49c5fSRichard Henderson 377325f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls. */ 377425f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt) 377525f49c5fSRichard Henderson { 377625f49c5fSRichard Henderson TCGRegSet mask = ~tcg_target_call_clobber_regs; 377725f49c5fSRichard Henderson int i; 377825f49c5fSRichard Henderson 377925f49c5fSRichard Henderson for (i = 0; i < nt; i++) { 378025f49c5fSRichard Henderson TCGTemp *ts = &s->temps[i]; 378125f49c5fSRichard Henderson if (!(ts->state & TS_DEAD)) { 378225f49c5fSRichard Henderson TCGRegSet *pset = la_temp_pref(ts); 378325f49c5fSRichard Henderson TCGRegSet set = *pset; 378425f49c5fSRichard Henderson 378525f49c5fSRichard Henderson set &= mask; 378625f49c5fSRichard Henderson /* If the combination is not possible, restart. */ 378725f49c5fSRichard Henderson if (set == 0) { 378825f49c5fSRichard Henderson set = tcg_target_available_regs[ts->type] & mask; 378925f49c5fSRichard Henderson } 379025f49c5fSRichard Henderson *pset = set; 379125f49c5fSRichard Henderson } 3792f65a061cSRichard Henderson } 3793f65a061cSRichard Henderson } 3794f65a061cSRichard Henderson 3795874b8574SRichard Henderson /* 3796874b8574SRichard Henderson * Liveness analysis: Verify the lifetime of TEMP_TB, and reduce 3797874b8574SRichard Henderson * to TEMP_EBB, if possible. 3798874b8574SRichard Henderson */ 3799874b8574SRichard Henderson static void __attribute__((noinline)) 3800874b8574SRichard Henderson liveness_pass_0(TCGContext *s) 3801874b8574SRichard Henderson { 3802874b8574SRichard Henderson void * const multiple_ebb = (void *)(uintptr_t)-1; 3803874b8574SRichard Henderson int nb_temps = s->nb_temps; 3804874b8574SRichard Henderson TCGOp *op, *ebb; 3805874b8574SRichard Henderson 3806874b8574SRichard Henderson for (int i = s->nb_globals; i < nb_temps; ++i) { 3807874b8574SRichard Henderson s->temps[i].state_ptr = NULL; 3808874b8574SRichard Henderson } 3809874b8574SRichard Henderson 3810874b8574SRichard Henderson /* 3811874b8574SRichard Henderson * Represent each EBB by the op at which it begins. In the case of 3812874b8574SRichard Henderson * the first EBB, this is the first op, otherwise it is a label. 3813874b8574SRichard Henderson * Collect the uses of each TEMP_TB: NULL for unused, EBB for use 3814874b8574SRichard Henderson * within a single EBB, else MULTIPLE_EBB. 3815874b8574SRichard Henderson */ 3816874b8574SRichard Henderson ebb = QTAILQ_FIRST(&s->ops); 3817874b8574SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 3818874b8574SRichard Henderson const TCGOpDef *def; 3819874b8574SRichard Henderson int nb_oargs, nb_iargs; 3820874b8574SRichard Henderson 3821874b8574SRichard Henderson switch (op->opc) { 3822874b8574SRichard Henderson case INDEX_op_set_label: 3823874b8574SRichard Henderson ebb = op; 3824874b8574SRichard Henderson continue; 3825874b8574SRichard Henderson case INDEX_op_discard: 3826874b8574SRichard Henderson continue; 3827874b8574SRichard Henderson case INDEX_op_call: 3828874b8574SRichard Henderson nb_oargs = TCGOP_CALLO(op); 3829874b8574SRichard Henderson nb_iargs = TCGOP_CALLI(op); 3830874b8574SRichard Henderson break; 3831874b8574SRichard Henderson default: 3832874b8574SRichard Henderson def = &tcg_op_defs[op->opc]; 3833874b8574SRichard Henderson nb_oargs = def->nb_oargs; 3834874b8574SRichard Henderson nb_iargs = def->nb_iargs; 3835874b8574SRichard Henderson break; 3836874b8574SRichard Henderson } 3837874b8574SRichard Henderson 3838874b8574SRichard Henderson for (int i = 0; i < nb_oargs + nb_iargs; ++i) { 3839874b8574SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]); 3840874b8574SRichard Henderson 3841874b8574SRichard Henderson if (ts->kind != TEMP_TB) { 3842874b8574SRichard Henderson continue; 3843874b8574SRichard Henderson } 3844874b8574SRichard Henderson if (ts->state_ptr == NULL) { 3845874b8574SRichard Henderson ts->state_ptr = ebb; 3846874b8574SRichard Henderson } else if (ts->state_ptr != ebb) { 3847874b8574SRichard Henderson ts->state_ptr = multiple_ebb; 3848874b8574SRichard Henderson } 3849874b8574SRichard Henderson } 3850874b8574SRichard Henderson } 3851874b8574SRichard Henderson 3852874b8574SRichard Henderson /* 3853874b8574SRichard Henderson * For TEMP_TB that turned out not to be used beyond one EBB, 3854874b8574SRichard Henderson * reduce the liveness to TEMP_EBB. 3855874b8574SRichard Henderson */ 3856874b8574SRichard Henderson for (int i = s->nb_globals; i < nb_temps; ++i) { 3857874b8574SRichard Henderson TCGTemp *ts = &s->temps[i]; 3858874b8574SRichard Henderson if (ts->kind == TEMP_TB && ts->state_ptr != multiple_ebb) { 3859874b8574SRichard Henderson ts->kind = TEMP_EBB; 3860874b8574SRichard Henderson } 3861874b8574SRichard Henderson } 3862874b8574SRichard Henderson } 3863874b8574SRichard Henderson 3864a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a 3865c896fe29Sbellard given input arguments is dead. Instructions updating dead 3866c896fe29Sbellard temporaries are removed. */ 38679bbee4c0SRichard Henderson static void __attribute__((noinline)) 38689bbee4c0SRichard Henderson liveness_pass_1(TCGContext *s) 3869c896fe29Sbellard { 3870c70fbf0aSRichard Henderson int nb_globals = s->nb_globals; 38712616c808SRichard Henderson int nb_temps = s->nb_temps; 387215fa08f8SRichard Henderson TCGOp *op, *op_prev; 387325f49c5fSRichard Henderson TCGRegSet *prefs; 387425f49c5fSRichard Henderson int i; 387525f49c5fSRichard Henderson 387625f49c5fSRichard Henderson prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps); 387725f49c5fSRichard Henderson for (i = 0; i < nb_temps; ++i) { 387825f49c5fSRichard Henderson s->temps[i].state_ptr = prefs + i; 387925f49c5fSRichard Henderson } 3880c896fe29Sbellard 3881ae36a246SRichard Henderson /* ??? Should be redundant with the exit_tb that ends the TB. */ 38822616c808SRichard Henderson la_func_end(s, nb_globals, nb_temps); 3883c896fe29Sbellard 3884eae3eb3eSPaolo Bonzini QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) { 388525f49c5fSRichard Henderson int nb_iargs, nb_oargs; 3886c45cb8bbSRichard Henderson TCGOpcode opc_new, opc_new2; 3887a1b3c48dSRichard Henderson TCGLifeData arg_life = 0; 388825f49c5fSRichard Henderson TCGTemp *ts; 3889c45cb8bbSRichard Henderson TCGOpcode opc = op->opc; 3890c45cb8bbSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 3891501fb3daSRichard Henderson const TCGArgConstraint *args_ct; 3892c45cb8bbSRichard Henderson 3893c45cb8bbSRichard Henderson switch (opc) { 3894c896fe29Sbellard case INDEX_op_call: 3895c6e113f5Sbellard { 389639004a71SRichard Henderson const TCGHelperInfo *info = tcg_call_info(op); 389739004a71SRichard Henderson int call_flags = tcg_call_flags(op); 3898c6e113f5Sbellard 3899cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 3900cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 3901c6e113f5Sbellard 3902c45cb8bbSRichard Henderson /* pure functions can be removed if their result is unused */ 390378505279SAurelien Jarno if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) { 3904c6e113f5Sbellard for (i = 0; i < nb_oargs; i++) { 390525f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 390625f49c5fSRichard Henderson if (ts->state != TS_DEAD) { 3907c6e113f5Sbellard goto do_not_remove_call; 3908c6e113f5Sbellard } 39099c43b68dSAurelien Jarno } 3910c45cb8bbSRichard Henderson goto do_remove; 3911152c35aaSRichard Henderson } 3912c6e113f5Sbellard do_not_remove_call: 3913c896fe29Sbellard 391425f49c5fSRichard Henderson /* Output args are dead. */ 3915c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 391625f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 391725f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 3918a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 39196b64b624SAurelien Jarno } 392025f49c5fSRichard Henderson if (ts->state & TS_MEM) { 3921a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i; 39229c43b68dSAurelien Jarno } 392325f49c5fSRichard Henderson ts->state = TS_DEAD; 392425f49c5fSRichard Henderson la_reset_pref(ts); 3925c896fe29Sbellard } 3926c896fe29Sbellard 392731fd884bSRichard Henderson /* Not used -- it will be tcg_target_call_oarg_reg(). */ 392831fd884bSRichard Henderson memset(op->output_pref, 0, sizeof(op->output_pref)); 392931fd884bSRichard Henderson 393078505279SAurelien Jarno if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS | 393178505279SAurelien Jarno TCG_CALL_NO_READ_GLOBALS))) { 3932f65a061cSRichard Henderson la_global_kill(s, nb_globals); 3933c70fbf0aSRichard Henderson } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) { 3934f65a061cSRichard Henderson la_global_sync(s, nb_globals); 3935b9c18f56Saurel32 } 3936c896fe29Sbellard 393725f49c5fSRichard Henderson /* Record arguments that die in this helper. */ 3938866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 393925f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 394039004a71SRichard Henderson if (ts->state & TS_DEAD) { 3941a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 3942c896fe29Sbellard } 3943c896fe29Sbellard } 394425f49c5fSRichard Henderson 394525f49c5fSRichard Henderson /* For all live registers, remove call-clobbered prefs. */ 394625f49c5fSRichard Henderson la_cross_call(s, nb_temps); 394725f49c5fSRichard Henderson 394839004a71SRichard Henderson /* 394939004a71SRichard Henderson * Input arguments are live for preceding opcodes. 395039004a71SRichard Henderson * 395139004a71SRichard Henderson * For those arguments that die, and will be allocated in 395239004a71SRichard Henderson * registers, clear the register set for that arg, to be 395339004a71SRichard Henderson * filled in below. For args that will be on the stack, 395439004a71SRichard Henderson * reset to any available reg. Process arguments in reverse 395539004a71SRichard Henderson * order so that if a temp is used more than once, the stack 395639004a71SRichard Henderson * reset to max happens before the register reset to 0. 395725f49c5fSRichard Henderson */ 395839004a71SRichard Henderson for (i = nb_iargs - 1; i >= 0; i--) { 395939004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i]; 396039004a71SRichard Henderson ts = arg_temp(op->args[nb_oargs + i]); 396139004a71SRichard Henderson 396239004a71SRichard Henderson if (ts->state & TS_DEAD) { 396339004a71SRichard Henderson switch (loc->kind) { 396439004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 396539004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 396639004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 3967338b61e9SRichard Henderson if (arg_slot_reg_p(loc->arg_slot)) { 396839004a71SRichard Henderson *la_temp_pref(ts) = 0; 396939004a71SRichard Henderson break; 397039004a71SRichard Henderson } 397139004a71SRichard Henderson /* fall through */ 397239004a71SRichard Henderson default: 397339004a71SRichard Henderson *la_temp_pref(ts) = 397439004a71SRichard Henderson tcg_target_available_regs[ts->type]; 397539004a71SRichard Henderson break; 397639004a71SRichard Henderson } 397725f49c5fSRichard Henderson ts->state &= ~TS_DEAD; 397825f49c5fSRichard Henderson } 397925f49c5fSRichard Henderson } 398025f49c5fSRichard Henderson 398139004a71SRichard Henderson /* 398239004a71SRichard Henderson * For each input argument, add its input register to prefs. 398339004a71SRichard Henderson * If a temp is used once, this produces a single set bit; 398439004a71SRichard Henderson * if a temp is used multiple times, this produces a set. 398539004a71SRichard Henderson */ 398639004a71SRichard Henderson for (i = 0; i < nb_iargs; i++) { 398739004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i]; 398839004a71SRichard Henderson ts = arg_temp(op->args[nb_oargs + i]); 398939004a71SRichard Henderson 399039004a71SRichard Henderson switch (loc->kind) { 399139004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 399239004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 399339004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 3994338b61e9SRichard Henderson if (arg_slot_reg_p(loc->arg_slot)) { 399525f49c5fSRichard Henderson tcg_regset_set_reg(*la_temp_pref(ts), 399639004a71SRichard Henderson tcg_target_call_iarg_regs[loc->arg_slot]); 399739004a71SRichard Henderson } 399839004a71SRichard Henderson break; 399939004a71SRichard Henderson default: 400039004a71SRichard Henderson break; 4001c70fbf0aSRichard Henderson } 4002c19f47bfSAurelien Jarno } 4003c6e113f5Sbellard } 4004c896fe29Sbellard break; 4005765b842aSRichard Henderson case INDEX_op_insn_start: 4006c896fe29Sbellard break; 40075ff9d6a4Sbellard case INDEX_op_discard: 40085ff9d6a4Sbellard /* mark the temporary as dead */ 400925f49c5fSRichard Henderson ts = arg_temp(op->args[0]); 401025f49c5fSRichard Henderson ts->state = TS_DEAD; 401125f49c5fSRichard Henderson la_reset_pref(ts); 40125ff9d6a4Sbellard break; 40131305c451SRichard Henderson 40141305c451SRichard Henderson case INDEX_op_add2_i32: 401579602f63SRichard Henderson case INDEX_op_add2_i64: 401679602f63SRichard Henderson opc_new = INDEX_op_add; 4017f1fae40cSRichard Henderson goto do_addsub2; 40181305c451SRichard Henderson case INDEX_op_sub2_i32: 4019f1fae40cSRichard Henderson case INDEX_op_sub2_i64: 402060f34f55SRichard Henderson opc_new = INDEX_op_sub; 4021f1fae40cSRichard Henderson do_addsub2: 40221305c451SRichard Henderson nb_iargs = 4; 40231305c451SRichard Henderson nb_oargs = 2; 40241305c451SRichard Henderson /* Test if the high part of the operation is dead, but not 40251305c451SRichard Henderson the low part. The result can be optimized to a simple 40261305c451SRichard Henderson add or sub. This happens often for x86_64 guest when the 40271305c451SRichard Henderson cpu mode is set to 32 bit. */ 4028b83eabeaSRichard Henderson if (arg_temp(op->args[1])->state == TS_DEAD) { 4029b83eabeaSRichard Henderson if (arg_temp(op->args[0])->state == TS_DEAD) { 40301305c451SRichard Henderson goto do_remove; 40311305c451SRichard Henderson } 4032c45cb8bbSRichard Henderson /* Replace the opcode and adjust the args in place, 4033c45cb8bbSRichard Henderson leaving 3 unused args at the end. */ 4034c45cb8bbSRichard Henderson op->opc = opc = opc_new; 4035efee3746SRichard Henderson op->args[1] = op->args[2]; 4036efee3746SRichard Henderson op->args[2] = op->args[4]; 40371305c451SRichard Henderson /* Fall through and mark the single-word operation live. */ 40381305c451SRichard Henderson nb_iargs = 2; 40391305c451SRichard Henderson nb_oargs = 1; 40401305c451SRichard Henderson } 40411305c451SRichard Henderson goto do_not_remove; 40421305c451SRichard Henderson 4043bfe96480SRichard Henderson case INDEX_op_muls2: 4044d2c3ecadSRichard Henderson opc_new = INDEX_op_mul; 4045c742824dSRichard Henderson opc_new2 = INDEX_op_mulsh; 4046f1fae40cSRichard Henderson goto do_mul2; 4047d776198cSRichard Henderson case INDEX_op_mulu2: 4048d2c3ecadSRichard Henderson opc_new = INDEX_op_mul; 4049aa28c9efSRichard Henderson opc_new2 = INDEX_op_muluh; 4050f1fae40cSRichard Henderson do_mul2: 40511414968aSRichard Henderson nb_iargs = 2; 40521414968aSRichard Henderson nb_oargs = 2; 4053b83eabeaSRichard Henderson if (arg_temp(op->args[1])->state == TS_DEAD) { 4054b83eabeaSRichard Henderson if (arg_temp(op->args[0])->state == TS_DEAD) { 405503271524SRichard Henderson /* Both parts of the operation are dead. */ 40561414968aSRichard Henderson goto do_remove; 40571414968aSRichard Henderson } 405803271524SRichard Henderson /* The high part of the operation is dead; generate the low. */ 4059c45cb8bbSRichard Henderson op->opc = opc = opc_new; 4060efee3746SRichard Henderson op->args[1] = op->args[2]; 4061efee3746SRichard Henderson op->args[2] = op->args[3]; 4062937246f2SRichard Henderson } else if (arg_temp(op->args[0])->state == TS_DEAD && 4063937246f2SRichard Henderson tcg_op_supported(opc_new2, TCGOP_TYPE(op), 0)) { 406403271524SRichard Henderson /* The low part of the operation is dead; generate the high. */ 4065c45cb8bbSRichard Henderson op->opc = opc = opc_new2; 4066efee3746SRichard Henderson op->args[0] = op->args[1]; 4067efee3746SRichard Henderson op->args[1] = op->args[2]; 4068efee3746SRichard Henderson op->args[2] = op->args[3]; 406903271524SRichard Henderson } else { 407003271524SRichard Henderson goto do_not_remove; 407103271524SRichard Henderson } 407203271524SRichard Henderson /* Mark the single-word operation live. */ 40731414968aSRichard Henderson nb_oargs = 1; 40741414968aSRichard Henderson goto do_not_remove; 40751414968aSRichard Henderson 4076c896fe29Sbellard default: 40771305c451SRichard Henderson /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */ 4078c896fe29Sbellard nb_iargs = def->nb_iargs; 4079c896fe29Sbellard nb_oargs = def->nb_oargs; 4080c896fe29Sbellard 4081c896fe29Sbellard /* Test if the operation can be removed because all 40825ff9d6a4Sbellard its outputs are dead. We assume that nb_oargs == 0 40835ff9d6a4Sbellard implies side effects */ 40845ff9d6a4Sbellard if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) { 4085c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 4086b83eabeaSRichard Henderson if (arg_temp(op->args[i])->state != TS_DEAD) { 4087c896fe29Sbellard goto do_not_remove; 4088c896fe29Sbellard } 40899c43b68dSAurelien Jarno } 4090152c35aaSRichard Henderson goto do_remove; 4091152c35aaSRichard Henderson } 4092152c35aaSRichard Henderson goto do_not_remove; 4093152c35aaSRichard Henderson 40941305c451SRichard Henderson do_remove: 40950c627cdcSRichard Henderson tcg_op_remove(s, op); 4096152c35aaSRichard Henderson break; 4097152c35aaSRichard Henderson 4098c896fe29Sbellard do_not_remove: 4099c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 410025f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 410125f49c5fSRichard Henderson 410225f49c5fSRichard Henderson /* Remember the preference of the uses that followed. */ 410331fd884bSRichard Henderson if (i < ARRAY_SIZE(op->output_pref)) { 410425f49c5fSRichard Henderson op->output_pref[i] = *la_temp_pref(ts); 410531fd884bSRichard Henderson } 410625f49c5fSRichard Henderson 410725f49c5fSRichard Henderson /* Output args are dead. */ 410825f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 4109a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 41106b64b624SAurelien Jarno } 411125f49c5fSRichard Henderson if (ts->state & TS_MEM) { 4112a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i; 41139c43b68dSAurelien Jarno } 411425f49c5fSRichard Henderson ts->state = TS_DEAD; 411525f49c5fSRichard Henderson la_reset_pref(ts); 4116c896fe29Sbellard } 4117c896fe29Sbellard 411825f49c5fSRichard Henderson /* If end of basic block, update. */ 4119ae36a246SRichard Henderson if (def->flags & TCG_OPF_BB_EXIT) { 4120ae36a246SRichard Henderson la_func_end(s, nb_globals, nb_temps); 4121b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_COND_BRANCH) { 4122b4cb76e6SRichard Henderson la_bb_sync(s, nb_globals, nb_temps); 4123ae36a246SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 41242616c808SRichard Henderson la_bb_end(s, nb_globals, nb_temps); 41253d5c5f87SAurelien Jarno } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { 4126f65a061cSRichard Henderson la_global_sync(s, nb_globals); 412725f49c5fSRichard Henderson if (def->flags & TCG_OPF_CALL_CLOBBER) { 412825f49c5fSRichard Henderson la_cross_call(s, nb_temps); 412925f49c5fSRichard Henderson } 4130c896fe29Sbellard } 4131c896fe29Sbellard 413225f49c5fSRichard Henderson /* Record arguments that die in this opcode. */ 4133866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 413425f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 413525f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 4136a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 4137c896fe29Sbellard } 4138c19f47bfSAurelien Jarno } 413925f49c5fSRichard Henderson 414025f49c5fSRichard Henderson /* Input arguments are live for preceding opcodes. */ 4141c19f47bfSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 414225f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 414325f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 414425f49c5fSRichard Henderson /* For operands that were dead, initially allow 414525f49c5fSRichard Henderson all regs for the type. */ 414625f49c5fSRichard Henderson *la_temp_pref(ts) = tcg_target_available_regs[ts->type]; 414725f49c5fSRichard Henderson ts->state &= ~TS_DEAD; 414825f49c5fSRichard Henderson } 414925f49c5fSRichard Henderson } 415025f49c5fSRichard Henderson 415125f49c5fSRichard Henderson /* Incorporate constraints for this operand. */ 415225f49c5fSRichard Henderson switch (opc) { 4153b5701261SRichard Henderson case INDEX_op_mov: 415425f49c5fSRichard Henderson /* Note that these are TCG_OPF_NOT_PRESENT and do not 415525f49c5fSRichard Henderson have proper constraints. That said, special case 415625f49c5fSRichard Henderson moves to propagate preferences backward. */ 415725f49c5fSRichard Henderson if (IS_DEAD_ARG(1)) { 415825f49c5fSRichard Henderson *la_temp_pref(arg_temp(op->args[0])) 415925f49c5fSRichard Henderson = *la_temp_pref(arg_temp(op->args[1])); 416025f49c5fSRichard Henderson } 416125f49c5fSRichard Henderson break; 416225f49c5fSRichard Henderson 416325f49c5fSRichard Henderson default: 4164501fb3daSRichard Henderson args_ct = opcode_args_ct(op); 416525f49c5fSRichard Henderson for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 4166501fb3daSRichard Henderson const TCGArgConstraint *ct = &args_ct[i]; 416725f49c5fSRichard Henderson TCGRegSet set, *pset; 416825f49c5fSRichard Henderson 416925f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 417025f49c5fSRichard Henderson pset = la_temp_pref(ts); 417125f49c5fSRichard Henderson set = *pset; 417225f49c5fSRichard Henderson 41739be0d080SRichard Henderson set &= ct->regs; 4174bc2b17e6SRichard Henderson if (ct->ialias) { 417531fd884bSRichard Henderson set &= output_pref(op, ct->alias_index); 417625f49c5fSRichard Henderson } 417725f49c5fSRichard Henderson /* If the combination is not possible, restart. */ 417825f49c5fSRichard Henderson if (set == 0) { 41799be0d080SRichard Henderson set = ct->regs; 418025f49c5fSRichard Henderson } 418125f49c5fSRichard Henderson *pset = set; 418225f49c5fSRichard Henderson } 418325f49c5fSRichard Henderson break; 4184c896fe29Sbellard } 4185c896fe29Sbellard break; 4186c896fe29Sbellard } 4187bee158cbSRichard Henderson op->life = arg_life; 4188c896fe29Sbellard } 41891ff0a2c5SEvgeny Voevodin } 4190c896fe29Sbellard 41915a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries. */ 41929bbee4c0SRichard Henderson static bool __attribute__((noinline)) 41939bbee4c0SRichard Henderson liveness_pass_2(TCGContext *s) 41945a18407fSRichard Henderson { 41955a18407fSRichard Henderson int nb_globals = s->nb_globals; 419615fa08f8SRichard Henderson int nb_temps, i; 41975a18407fSRichard Henderson bool changes = false; 419815fa08f8SRichard Henderson TCGOp *op, *op_next; 41995a18407fSRichard Henderson 42005a18407fSRichard Henderson /* Create a temporary for each indirect global. */ 42015a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 42025a18407fSRichard Henderson TCGTemp *its = &s->temps[i]; 42035a18407fSRichard Henderson if (its->indirect_reg) { 42045a18407fSRichard Henderson TCGTemp *dts = tcg_temp_alloc(s); 42055a18407fSRichard Henderson dts->type = its->type; 42065a18407fSRichard Henderson dts->base_type = its->base_type; 4207e1e64652SRichard Henderson dts->temp_subindex = its->temp_subindex; 4208c7482438SRichard Henderson dts->kind = TEMP_EBB; 4209b83eabeaSRichard Henderson its->state_ptr = dts; 4210b83eabeaSRichard Henderson } else { 4211b83eabeaSRichard Henderson its->state_ptr = NULL; 42125a18407fSRichard Henderson } 4213b83eabeaSRichard Henderson /* All globals begin dead. */ 4214b83eabeaSRichard Henderson its->state = TS_DEAD; 42155a18407fSRichard Henderson } 4216b83eabeaSRichard Henderson for (nb_temps = s->nb_temps; i < nb_temps; ++i) { 4217b83eabeaSRichard Henderson TCGTemp *its = &s->temps[i]; 4218b83eabeaSRichard Henderson its->state_ptr = NULL; 4219b83eabeaSRichard Henderson its->state = TS_DEAD; 4220b83eabeaSRichard Henderson } 42215a18407fSRichard Henderson 422215fa08f8SRichard Henderson QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) { 42235a18407fSRichard Henderson TCGOpcode opc = op->opc; 42245a18407fSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 42255a18407fSRichard Henderson TCGLifeData arg_life = op->life; 42265a18407fSRichard Henderson int nb_iargs, nb_oargs, call_flags; 4227b83eabeaSRichard Henderson TCGTemp *arg_ts, *dir_ts; 42285a18407fSRichard Henderson 42295a18407fSRichard Henderson if (opc == INDEX_op_call) { 4230cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 4231cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 423290163900SRichard Henderson call_flags = tcg_call_flags(op); 42335a18407fSRichard Henderson } else { 42345a18407fSRichard Henderson nb_iargs = def->nb_iargs; 42355a18407fSRichard Henderson nb_oargs = def->nb_oargs; 42365a18407fSRichard Henderson 42375a18407fSRichard Henderson /* Set flags similar to how calls require. */ 4238b4cb76e6SRichard Henderson if (def->flags & TCG_OPF_COND_BRANCH) { 4239b4cb76e6SRichard Henderson /* Like reading globals: sync_globals */ 4240b4cb76e6SRichard Henderson call_flags = TCG_CALL_NO_WRITE_GLOBALS; 4241b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 42425a18407fSRichard Henderson /* Like writing globals: save_globals */ 42435a18407fSRichard Henderson call_flags = 0; 42445a18407fSRichard Henderson } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { 42455a18407fSRichard Henderson /* Like reading globals: sync_globals */ 42465a18407fSRichard Henderson call_flags = TCG_CALL_NO_WRITE_GLOBALS; 42475a18407fSRichard Henderson } else { 42485a18407fSRichard Henderson /* No effect on globals. */ 42495a18407fSRichard Henderson call_flags = (TCG_CALL_NO_READ_GLOBALS | 42505a18407fSRichard Henderson TCG_CALL_NO_WRITE_GLOBALS); 42515a18407fSRichard Henderson } 42525a18407fSRichard Henderson } 42535a18407fSRichard Henderson 42545a18407fSRichard Henderson /* Make sure that input arguments are available. */ 42555a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 4256b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 4257b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 4258b83eabeaSRichard Henderson if (dir_ts && arg_ts->state == TS_DEAD) { 4259b83eabeaSRichard Henderson TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32 42605a18407fSRichard Henderson ? INDEX_op_ld_i32 42615a18407fSRichard Henderson : INDEX_op_ld_i64); 4262cf5c9f69SRichard Henderson TCGOp *lop = tcg_op_insert_before(s, op, lopc, 4263cf5c9f69SRichard Henderson arg_ts->type, 3); 42645a18407fSRichard Henderson 4265b83eabeaSRichard Henderson lop->args[0] = temp_arg(dir_ts); 4266b83eabeaSRichard Henderson lop->args[1] = temp_arg(arg_ts->mem_base); 4267b83eabeaSRichard Henderson lop->args[2] = arg_ts->mem_offset; 42685a18407fSRichard Henderson 42695a18407fSRichard Henderson /* Loaded, but synced with memory. */ 4270b83eabeaSRichard Henderson arg_ts->state = TS_MEM; 42715a18407fSRichard Henderson } 42725a18407fSRichard Henderson } 42735a18407fSRichard Henderson 42745a18407fSRichard Henderson /* Perform input replacement, and mark inputs that became dead. 42755a18407fSRichard Henderson No action is required except keeping temp_state up to date 42765a18407fSRichard Henderson so that we reload when needed. */ 42775a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 4278b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 4279b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 4280b83eabeaSRichard Henderson if (dir_ts) { 4281b83eabeaSRichard Henderson op->args[i] = temp_arg(dir_ts); 42825a18407fSRichard Henderson changes = true; 42835a18407fSRichard Henderson if (IS_DEAD_ARG(i)) { 4284b83eabeaSRichard Henderson arg_ts->state = TS_DEAD; 42855a18407fSRichard Henderson } 42865a18407fSRichard Henderson } 42875a18407fSRichard Henderson } 42885a18407fSRichard Henderson 42895a18407fSRichard Henderson /* Liveness analysis should ensure that the following are 42905a18407fSRichard Henderson all correct, for call sites and basic block end points. */ 42915a18407fSRichard Henderson if (call_flags & TCG_CALL_NO_READ_GLOBALS) { 42925a18407fSRichard Henderson /* Nothing to do */ 42935a18407fSRichard Henderson } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) { 42945a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 42955a18407fSRichard Henderson /* Liveness should see that globals are synced back, 42965a18407fSRichard Henderson that is, either TS_DEAD or TS_MEM. */ 4297b83eabeaSRichard Henderson arg_ts = &s->temps[i]; 4298b83eabeaSRichard Henderson tcg_debug_assert(arg_ts->state_ptr == 0 4299b83eabeaSRichard Henderson || arg_ts->state != 0); 43005a18407fSRichard Henderson } 43015a18407fSRichard Henderson } else { 43025a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 43035a18407fSRichard Henderson /* Liveness should see that globals are saved back, 43045a18407fSRichard Henderson that is, TS_DEAD, waiting to be reloaded. */ 4305b83eabeaSRichard Henderson arg_ts = &s->temps[i]; 4306b83eabeaSRichard Henderson tcg_debug_assert(arg_ts->state_ptr == 0 4307b83eabeaSRichard Henderson || arg_ts->state == TS_DEAD); 43085a18407fSRichard Henderson } 43095a18407fSRichard Henderson } 43105a18407fSRichard Henderson 43115a18407fSRichard Henderson /* Outputs become available. */ 4312b5701261SRichard Henderson if (opc == INDEX_op_mov) { 431361f15c48SRichard Henderson arg_ts = arg_temp(op->args[0]); 431461f15c48SRichard Henderson dir_ts = arg_ts->state_ptr; 431561f15c48SRichard Henderson if (dir_ts) { 431661f15c48SRichard Henderson op->args[0] = temp_arg(dir_ts); 431761f15c48SRichard Henderson changes = true; 431861f15c48SRichard Henderson 431961f15c48SRichard Henderson /* The output is now live and modified. */ 432061f15c48SRichard Henderson arg_ts->state = 0; 432161f15c48SRichard Henderson 432261f15c48SRichard Henderson if (NEED_SYNC_ARG(0)) { 432361f15c48SRichard Henderson TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 432461f15c48SRichard Henderson ? INDEX_op_st_i32 432561f15c48SRichard Henderson : INDEX_op_st_i64); 4326cf5c9f69SRichard Henderson TCGOp *sop = tcg_op_insert_after(s, op, sopc, 4327cf5c9f69SRichard Henderson arg_ts->type, 3); 432861f15c48SRichard Henderson TCGTemp *out_ts = dir_ts; 432961f15c48SRichard Henderson 433061f15c48SRichard Henderson if (IS_DEAD_ARG(0)) { 433161f15c48SRichard Henderson out_ts = arg_temp(op->args[1]); 433261f15c48SRichard Henderson arg_ts->state = TS_DEAD; 433361f15c48SRichard Henderson tcg_op_remove(s, op); 433461f15c48SRichard Henderson } else { 433561f15c48SRichard Henderson arg_ts->state = TS_MEM; 433661f15c48SRichard Henderson } 433761f15c48SRichard Henderson 433861f15c48SRichard Henderson sop->args[0] = temp_arg(out_ts); 433961f15c48SRichard Henderson sop->args[1] = temp_arg(arg_ts->mem_base); 434061f15c48SRichard Henderson sop->args[2] = arg_ts->mem_offset; 434161f15c48SRichard Henderson } else { 434261f15c48SRichard Henderson tcg_debug_assert(!IS_DEAD_ARG(0)); 434361f15c48SRichard Henderson } 434461f15c48SRichard Henderson } 434561f15c48SRichard Henderson } else { 43465a18407fSRichard Henderson for (i = 0; i < nb_oargs; i++) { 4347b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 4348b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 4349b83eabeaSRichard Henderson if (!dir_ts) { 43505a18407fSRichard Henderson continue; 43515a18407fSRichard Henderson } 4352b83eabeaSRichard Henderson op->args[i] = temp_arg(dir_ts); 43535a18407fSRichard Henderson changes = true; 43545a18407fSRichard Henderson 43555a18407fSRichard Henderson /* The output is now live and modified. */ 4356b83eabeaSRichard Henderson arg_ts->state = 0; 43575a18407fSRichard Henderson 43585a18407fSRichard Henderson /* Sync outputs upon their last write. */ 43595a18407fSRichard Henderson if (NEED_SYNC_ARG(i)) { 4360b83eabeaSRichard Henderson TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 43615a18407fSRichard Henderson ? INDEX_op_st_i32 43625a18407fSRichard Henderson : INDEX_op_st_i64); 4363cf5c9f69SRichard Henderson TCGOp *sop = tcg_op_insert_after(s, op, sopc, 4364cf5c9f69SRichard Henderson arg_ts->type, 3); 43655a18407fSRichard Henderson 4366b83eabeaSRichard Henderson sop->args[0] = temp_arg(dir_ts); 4367b83eabeaSRichard Henderson sop->args[1] = temp_arg(arg_ts->mem_base); 4368b83eabeaSRichard Henderson sop->args[2] = arg_ts->mem_offset; 43695a18407fSRichard Henderson 4370b83eabeaSRichard Henderson arg_ts->state = TS_MEM; 43715a18407fSRichard Henderson } 43725a18407fSRichard Henderson /* Drop outputs that are dead. */ 43735a18407fSRichard Henderson if (IS_DEAD_ARG(i)) { 4374b83eabeaSRichard Henderson arg_ts->state = TS_DEAD; 43755a18407fSRichard Henderson } 43765a18407fSRichard Henderson } 43775a18407fSRichard Henderson } 437861f15c48SRichard Henderson } 43795a18407fSRichard Henderson 43805a18407fSRichard Henderson return changes; 43815a18407fSRichard Henderson } 43825a18407fSRichard Henderson 43832272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts) 4384c896fe29Sbellard { 438531c96417SRichard Henderson intptr_t off; 4386273eb50cSRichard Henderson int size, align; 4387c1c09194SRichard Henderson 4388273eb50cSRichard Henderson /* When allocating an object, look at the full type. */ 4389273eb50cSRichard Henderson size = tcg_type_size(ts->base_type); 4390273eb50cSRichard Henderson switch (ts->base_type) { 4391c1c09194SRichard Henderson case TCG_TYPE_I32: 439231c96417SRichard Henderson align = 4; 4393c1c09194SRichard Henderson break; 4394c1c09194SRichard Henderson case TCG_TYPE_I64: 4395c1c09194SRichard Henderson case TCG_TYPE_V64: 439631c96417SRichard Henderson align = 8; 4397c1c09194SRichard Henderson break; 439843eef72fSRichard Henderson case TCG_TYPE_I128: 4399c1c09194SRichard Henderson case TCG_TYPE_V128: 4400c1c09194SRichard Henderson case TCG_TYPE_V256: 440143eef72fSRichard Henderson /* 440243eef72fSRichard Henderson * Note that we do not require aligned storage for V256, 440343eef72fSRichard Henderson * and that we provide alignment for I128 to match V128, 440443eef72fSRichard Henderson * even if that's above what the host ABI requires. 440543eef72fSRichard Henderson */ 440631c96417SRichard Henderson align = 16; 4407c1c09194SRichard Henderson break; 4408c1c09194SRichard Henderson default: 4409c1c09194SRichard Henderson g_assert_not_reached(); 4410b591dc59SBlue Swirl } 4411c1c09194SRichard Henderson 4412b9537d59SRichard Henderson /* 4413b9537d59SRichard Henderson * Assume the stack is sufficiently aligned. 4414b9537d59SRichard Henderson * This affects e.g. ARM NEON, where we have 8 byte stack alignment 4415b9537d59SRichard Henderson * and do not require 16 byte vector alignment. This seems slightly 4416b9537d59SRichard Henderson * easier than fully parameterizing the above switch statement. 4417b9537d59SRichard Henderson */ 4418b9537d59SRichard Henderson align = MIN(TCG_TARGET_STACK_ALIGN, align); 4419c1c09194SRichard Henderson off = ROUND_UP(s->current_frame_offset, align); 4420732d5897SRichard Henderson 4421732d5897SRichard Henderson /* If we've exhausted the stack frame, restart with a smaller TB. */ 4422732d5897SRichard Henderson if (off + size > s->frame_end) { 4423732d5897SRichard Henderson tcg_raise_tb_overflow(s); 4424732d5897SRichard Henderson } 4425c1c09194SRichard Henderson s->current_frame_offset = off + size; 44269defd1bdSRichard Henderson #if defined(__sparc__) 4427273eb50cSRichard Henderson off += TCG_TARGET_STACK_BIAS; 44289defd1bdSRichard Henderson #endif 4429273eb50cSRichard Henderson 4430273eb50cSRichard Henderson /* If the object was subdivided, assign memory to all the parts. */ 4431273eb50cSRichard Henderson if (ts->base_type != ts->type) { 4432273eb50cSRichard Henderson int part_size = tcg_type_size(ts->type); 4433273eb50cSRichard Henderson int part_count = size / part_size; 4434273eb50cSRichard Henderson 4435273eb50cSRichard Henderson /* 4436273eb50cSRichard Henderson * Each part is allocated sequentially in tcg_temp_new_internal. 4437273eb50cSRichard Henderson * Jump back to the first part by subtracting the current index. 4438273eb50cSRichard Henderson */ 4439273eb50cSRichard Henderson ts -= ts->temp_subindex; 4440273eb50cSRichard Henderson for (int i = 0; i < part_count; ++i) { 4441273eb50cSRichard Henderson ts[i].mem_offset = off + i * part_size; 4442273eb50cSRichard Henderson ts[i].mem_base = s->frame_temp; 4443273eb50cSRichard Henderson ts[i].mem_allocated = 1; 4444273eb50cSRichard Henderson } 4445273eb50cSRichard Henderson } else { 4446273eb50cSRichard Henderson ts->mem_offset = off; 4447b3a62939SRichard Henderson ts->mem_base = s->frame_temp; 4448c896fe29Sbellard ts->mem_allocated = 1; 4449c896fe29Sbellard } 4450273eb50cSRichard Henderson } 4451c896fe29Sbellard 4452098859f1SRichard Henderson /* Assign @reg to @ts, and update reg_to_temp[]. */ 4453098859f1SRichard Henderson static void set_temp_val_reg(TCGContext *s, TCGTemp *ts, TCGReg reg) 4454098859f1SRichard Henderson { 4455098859f1SRichard Henderson if (ts->val_type == TEMP_VAL_REG) { 4456098859f1SRichard Henderson TCGReg old = ts->reg; 4457098859f1SRichard Henderson tcg_debug_assert(s->reg_to_temp[old] == ts); 4458098859f1SRichard Henderson if (old == reg) { 4459098859f1SRichard Henderson return; 4460098859f1SRichard Henderson } 4461098859f1SRichard Henderson s->reg_to_temp[old] = NULL; 4462098859f1SRichard Henderson } 4463098859f1SRichard Henderson tcg_debug_assert(s->reg_to_temp[reg] == NULL); 4464098859f1SRichard Henderson s->reg_to_temp[reg] = ts; 4465098859f1SRichard Henderson ts->val_type = TEMP_VAL_REG; 4466098859f1SRichard Henderson ts->reg = reg; 4467098859f1SRichard Henderson } 4468098859f1SRichard Henderson 4469098859f1SRichard Henderson /* Assign a non-register value type to @ts, and update reg_to_temp[]. */ 4470098859f1SRichard Henderson static void set_temp_val_nonreg(TCGContext *s, TCGTemp *ts, TCGTempVal type) 4471098859f1SRichard Henderson { 4472098859f1SRichard Henderson tcg_debug_assert(type != TEMP_VAL_REG); 4473098859f1SRichard Henderson if (ts->val_type == TEMP_VAL_REG) { 4474098859f1SRichard Henderson TCGReg reg = ts->reg; 4475098859f1SRichard Henderson tcg_debug_assert(s->reg_to_temp[reg] == ts); 4476098859f1SRichard Henderson s->reg_to_temp[reg] = NULL; 4477098859f1SRichard Henderson } 4478098859f1SRichard Henderson ts->val_type = type; 4479098859f1SRichard Henderson } 4480098859f1SRichard Henderson 4481b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet); 4482b3915dbbSRichard Henderson 448359d7c14eSRichard Henderson /* Mark a temporary as free or dead. If 'free_or_dead' is negative, 448459d7c14eSRichard Henderson mark it free; otherwise mark it dead. */ 448559d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead) 4486c896fe29Sbellard { 4487c0522136SRichard Henderson TCGTempVal new_type; 4488c0522136SRichard Henderson 4489c0522136SRichard Henderson switch (ts->kind) { 4490c0522136SRichard Henderson case TEMP_FIXED: 449159d7c14eSRichard Henderson return; 4492c0522136SRichard Henderson case TEMP_GLOBAL: 4493f57c6915SRichard Henderson case TEMP_TB: 4494c0522136SRichard Henderson new_type = TEMP_VAL_MEM; 4495c0522136SRichard Henderson break; 4496c7482438SRichard Henderson case TEMP_EBB: 4497c0522136SRichard Henderson new_type = free_or_dead < 0 ? TEMP_VAL_MEM : TEMP_VAL_DEAD; 4498c0522136SRichard Henderson break; 4499c0522136SRichard Henderson case TEMP_CONST: 4500c0522136SRichard Henderson new_type = TEMP_VAL_CONST; 4501c0522136SRichard Henderson break; 4502c0522136SRichard Henderson default: 4503c0522136SRichard Henderson g_assert_not_reached(); 450459d7c14eSRichard Henderson } 4505098859f1SRichard Henderson set_temp_val_nonreg(s, ts, new_type); 450659d7c14eSRichard Henderson } 4507c896fe29Sbellard 450859d7c14eSRichard Henderson /* Mark a temporary as dead. */ 450959d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts) 451059d7c14eSRichard Henderson { 451159d7c14eSRichard Henderson temp_free_or_dead(s, ts, 1); 451259d7c14eSRichard Henderson } 451359d7c14eSRichard Henderson 451459d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary 451559d7c14eSRichard Henderson registers needs to be allocated to store a constant. If 'free_or_dead' 451659d7c14eSRichard Henderson is non-zero, subsequently release the temporary; if it is positive, the 451759d7c14eSRichard Henderson temp is dead; if it is negative, the temp is free. */ 451898b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs, 451998b4e186SRichard Henderson TCGRegSet preferred_regs, int free_or_dead) 452059d7c14eSRichard Henderson { 4521c0522136SRichard Henderson if (!temp_readonly(ts) && !ts->mem_coherent) { 45227f6ceedfSAurelien Jarno if (!ts->mem_allocated) { 45232272e4a7SRichard Henderson temp_allocate_frame(s, ts); 452459d7c14eSRichard Henderson } 452559d7c14eSRichard Henderson switch (ts->val_type) { 452659d7c14eSRichard Henderson case TEMP_VAL_CONST: 452759d7c14eSRichard Henderson /* If we're going to free the temp immediately, then we won't 452859d7c14eSRichard Henderson require it later in a register, so attempt to store the 452959d7c14eSRichard Henderson constant to memory directly. */ 453059d7c14eSRichard Henderson if (free_or_dead 453159d7c14eSRichard Henderson && tcg_out_sti(s, ts->type, ts->val, 453259d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset)) { 453359d7c14eSRichard Henderson break; 453459d7c14eSRichard Henderson } 453559d7c14eSRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 453698b4e186SRichard Henderson allocated_regs, preferred_regs); 453759d7c14eSRichard Henderson /* fallthrough */ 453859d7c14eSRichard Henderson 453959d7c14eSRichard Henderson case TEMP_VAL_REG: 454059d7c14eSRichard Henderson tcg_out_st(s, ts->type, ts->reg, 454159d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset); 454259d7c14eSRichard Henderson break; 454359d7c14eSRichard Henderson 454459d7c14eSRichard Henderson case TEMP_VAL_MEM: 454559d7c14eSRichard Henderson break; 454659d7c14eSRichard Henderson 454759d7c14eSRichard Henderson case TEMP_VAL_DEAD: 454859d7c14eSRichard Henderson default: 4549732e89f4SRichard Henderson g_assert_not_reached(); 4550c896fe29Sbellard } 45517f6ceedfSAurelien Jarno ts->mem_coherent = 1; 45527f6ceedfSAurelien Jarno } 455359d7c14eSRichard Henderson if (free_or_dead) { 455459d7c14eSRichard Henderson temp_free_or_dead(s, ts, free_or_dead); 455559d7c14eSRichard Henderson } 455659d7c14eSRichard Henderson } 45577f6ceedfSAurelien Jarno 45587f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */ 4559b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs) 45607f6ceedfSAurelien Jarno { 4561f8b2f202SRichard Henderson TCGTemp *ts = s->reg_to_temp[reg]; 4562f8b2f202SRichard Henderson if (ts != NULL) { 456398b4e186SRichard Henderson temp_sync(s, ts, allocated_regs, 0, -1); 4564c896fe29Sbellard } 4565c896fe29Sbellard } 4566c896fe29Sbellard 4567b016486eSRichard Henderson /** 4568b016486eSRichard Henderson * tcg_reg_alloc: 4569b016486eSRichard Henderson * @required_regs: Set of registers in which we must allocate. 4570b016486eSRichard Henderson * @allocated_regs: Set of registers which must be avoided. 4571b016486eSRichard Henderson * @preferred_regs: Set of registers we should prefer. 4572b016486eSRichard Henderson * @rev: True if we search the registers in "indirect" order. 4573b016486eSRichard Henderson * 4574b016486eSRichard Henderson * The allocated register must be in @required_regs & ~@allocated_regs, 4575b016486eSRichard Henderson * but if we can put it in @preferred_regs we may save a move later. 4576b016486eSRichard Henderson */ 4577b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs, 4578b016486eSRichard Henderson TCGRegSet allocated_regs, 4579b016486eSRichard Henderson TCGRegSet preferred_regs, bool rev) 4580c896fe29Sbellard { 4581b016486eSRichard Henderson int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order); 4582b016486eSRichard Henderson TCGRegSet reg_ct[2]; 458391478cefSRichard Henderson const int *order; 4584c896fe29Sbellard 4585b016486eSRichard Henderson reg_ct[1] = required_regs & ~allocated_regs; 4586b016486eSRichard Henderson tcg_debug_assert(reg_ct[1] != 0); 4587b016486eSRichard Henderson reg_ct[0] = reg_ct[1] & preferred_regs; 4588b016486eSRichard Henderson 4589b016486eSRichard Henderson /* Skip the preferred_regs option if it cannot be satisfied, 4590b016486eSRichard Henderson or if the preference made no difference. */ 4591b016486eSRichard Henderson f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1]; 4592b016486eSRichard Henderson 459391478cefSRichard Henderson order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order; 4594c896fe29Sbellard 4595b016486eSRichard Henderson /* Try free registers, preferences first. */ 4596b016486eSRichard Henderson for (j = f; j < 2; j++) { 4597b016486eSRichard Henderson TCGRegSet set = reg_ct[j]; 4598b016486eSRichard Henderson 4599b016486eSRichard Henderson if (tcg_regset_single(set)) { 4600b016486eSRichard Henderson /* One register in the set. */ 4601b016486eSRichard Henderson TCGReg reg = tcg_regset_first(set); 4602b016486eSRichard Henderson if (s->reg_to_temp[reg] == NULL) { 4603c896fe29Sbellard return reg; 4604c896fe29Sbellard } 4605b016486eSRichard Henderson } else { 460691478cefSRichard Henderson for (i = 0; i < n; i++) { 4607b016486eSRichard Henderson TCGReg reg = order[i]; 4608b016486eSRichard Henderson if (s->reg_to_temp[reg] == NULL && 4609b016486eSRichard Henderson tcg_regset_test_reg(set, reg)) { 4610b016486eSRichard Henderson return reg; 4611b016486eSRichard Henderson } 4612b016486eSRichard Henderson } 4613b016486eSRichard Henderson } 4614b016486eSRichard Henderson } 4615b016486eSRichard Henderson 4616b016486eSRichard Henderson /* We must spill something. */ 4617b016486eSRichard Henderson for (j = f; j < 2; j++) { 4618b016486eSRichard Henderson TCGRegSet set = reg_ct[j]; 4619b016486eSRichard Henderson 4620b016486eSRichard Henderson if (tcg_regset_single(set)) { 4621b016486eSRichard Henderson /* One register in the set. */ 4622b016486eSRichard Henderson TCGReg reg = tcg_regset_first(set); 4623b3915dbbSRichard Henderson tcg_reg_free(s, reg, allocated_regs); 4624c896fe29Sbellard return reg; 4625b016486eSRichard Henderson } else { 4626b016486eSRichard Henderson for (i = 0; i < n; i++) { 4627b016486eSRichard Henderson TCGReg reg = order[i]; 4628b016486eSRichard Henderson if (tcg_regset_test_reg(set, reg)) { 4629b016486eSRichard Henderson tcg_reg_free(s, reg, allocated_regs); 4630b016486eSRichard Henderson return reg; 4631b016486eSRichard Henderson } 4632b016486eSRichard Henderson } 4633c896fe29Sbellard } 4634c896fe29Sbellard } 4635c896fe29Sbellard 4636732e89f4SRichard Henderson g_assert_not_reached(); 4637c896fe29Sbellard } 4638c896fe29Sbellard 463929f5e925SRichard Henderson static TCGReg tcg_reg_alloc_pair(TCGContext *s, TCGRegSet required_regs, 464029f5e925SRichard Henderson TCGRegSet allocated_regs, 464129f5e925SRichard Henderson TCGRegSet preferred_regs, bool rev) 464229f5e925SRichard Henderson { 464329f5e925SRichard Henderson int i, j, k, fmin, n = ARRAY_SIZE(tcg_target_reg_alloc_order); 464429f5e925SRichard Henderson TCGRegSet reg_ct[2]; 464529f5e925SRichard Henderson const int *order; 464629f5e925SRichard Henderson 464729f5e925SRichard Henderson /* Ensure that if I is not in allocated_regs, I+1 is not either. */ 464829f5e925SRichard Henderson reg_ct[1] = required_regs & ~(allocated_regs | (allocated_regs >> 1)); 464929f5e925SRichard Henderson tcg_debug_assert(reg_ct[1] != 0); 465029f5e925SRichard Henderson reg_ct[0] = reg_ct[1] & preferred_regs; 465129f5e925SRichard Henderson 465229f5e925SRichard Henderson order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order; 465329f5e925SRichard Henderson 465429f5e925SRichard Henderson /* 465529f5e925SRichard Henderson * Skip the preferred_regs option if it cannot be satisfied, 465629f5e925SRichard Henderson * or if the preference made no difference. 465729f5e925SRichard Henderson */ 465829f5e925SRichard Henderson k = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1]; 465929f5e925SRichard Henderson 466029f5e925SRichard Henderson /* 466129f5e925SRichard Henderson * Minimize the number of flushes by looking for 2 free registers first, 466229f5e925SRichard Henderson * then a single flush, then two flushes. 466329f5e925SRichard Henderson */ 466429f5e925SRichard Henderson for (fmin = 2; fmin >= 0; fmin--) { 466529f5e925SRichard Henderson for (j = k; j < 2; j++) { 466629f5e925SRichard Henderson TCGRegSet set = reg_ct[j]; 466729f5e925SRichard Henderson 466829f5e925SRichard Henderson for (i = 0; i < n; i++) { 466929f5e925SRichard Henderson TCGReg reg = order[i]; 467029f5e925SRichard Henderson 467129f5e925SRichard Henderson if (tcg_regset_test_reg(set, reg)) { 467229f5e925SRichard Henderson int f = !s->reg_to_temp[reg] + !s->reg_to_temp[reg + 1]; 467329f5e925SRichard Henderson if (f >= fmin) { 467429f5e925SRichard Henderson tcg_reg_free(s, reg, allocated_regs); 467529f5e925SRichard Henderson tcg_reg_free(s, reg + 1, allocated_regs); 467629f5e925SRichard Henderson return reg; 467729f5e925SRichard Henderson } 467829f5e925SRichard Henderson } 467929f5e925SRichard Henderson } 468029f5e925SRichard Henderson } 468129f5e925SRichard Henderson } 4682732e89f4SRichard Henderson g_assert_not_reached(); 468329f5e925SRichard Henderson } 468429f5e925SRichard Henderson 468540ae5c62SRichard Henderson /* Make sure the temporary is in a register. If needed, allocate the register 468640ae5c62SRichard Henderson from DESIRED while avoiding ALLOCATED. */ 468740ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs, 4688b722452aSRichard Henderson TCGRegSet allocated_regs, TCGRegSet preferred_regs) 468940ae5c62SRichard Henderson { 469040ae5c62SRichard Henderson TCGReg reg; 469140ae5c62SRichard Henderson 469240ae5c62SRichard Henderson switch (ts->val_type) { 469340ae5c62SRichard Henderson case TEMP_VAL_REG: 469440ae5c62SRichard Henderson return; 469540ae5c62SRichard Henderson case TEMP_VAL_CONST: 4696b016486eSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs, 4697b722452aSRichard Henderson preferred_regs, ts->indirect_base); 46980a6a8bc8SRichard Henderson if (ts->type <= TCG_TYPE_I64) { 469940ae5c62SRichard Henderson tcg_out_movi(s, ts->type, reg, ts->val); 47000a6a8bc8SRichard Henderson } else { 47014e186175SRichard Henderson uint64_t val = ts->val; 47024e186175SRichard Henderson MemOp vece = MO_64; 47034e186175SRichard Henderson 47044e186175SRichard Henderson /* 47054e186175SRichard Henderson * Find the minimal vector element that matches the constant. 47064e186175SRichard Henderson * The targets will, in general, have to do this search anyway, 47074e186175SRichard Henderson * do this generically. 47084e186175SRichard Henderson */ 47094e186175SRichard Henderson if (val == dup_const(MO_8, val)) { 47104e186175SRichard Henderson vece = MO_8; 47114e186175SRichard Henderson } else if (val == dup_const(MO_16, val)) { 47124e186175SRichard Henderson vece = MO_16; 47130b4286ddSRichard Henderson } else if (val == dup_const(MO_32, val)) { 47144e186175SRichard Henderson vece = MO_32; 47154e186175SRichard Henderson } 47164e186175SRichard Henderson 47174e186175SRichard Henderson tcg_out_dupi_vec(s, ts->type, vece, reg, ts->val); 47180a6a8bc8SRichard Henderson } 471940ae5c62SRichard Henderson ts->mem_coherent = 0; 472040ae5c62SRichard Henderson break; 472140ae5c62SRichard Henderson case TEMP_VAL_MEM: 4722e139bc4bSPhilippe Mathieu-Daudé if (!ts->mem_allocated) { 4723e139bc4bSPhilippe Mathieu-Daudé temp_allocate_frame(s, ts); 4724e139bc4bSPhilippe Mathieu-Daudé } 4725b016486eSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs, 4726b722452aSRichard Henderson preferred_regs, ts->indirect_base); 472740ae5c62SRichard Henderson tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset); 472840ae5c62SRichard Henderson ts->mem_coherent = 1; 472940ae5c62SRichard Henderson break; 473040ae5c62SRichard Henderson case TEMP_VAL_DEAD: 473140ae5c62SRichard Henderson default: 4732732e89f4SRichard Henderson g_assert_not_reached(); 473340ae5c62SRichard Henderson } 4734098859f1SRichard Henderson set_temp_val_reg(s, ts, reg); 473540ae5c62SRichard Henderson } 473640ae5c62SRichard Henderson 473759d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a 4738e8996ee0Sbellard temporary registers needs to be allocated to store a constant. */ 473959d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs) 47401ad80729SAurelien Jarno { 47412c0366f0SAurelien Jarno /* The liveness analysis already ensures that globals are back 4742eabb7b91SAurelien Jarno in memory. Keep an tcg_debug_assert for safety. */ 4743e01fa97dSRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || temp_readonly(ts)); 47441ad80729SAurelien Jarno } 47451ad80729SAurelien Jarno 47469814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be 4747641d5fbeSbellard modified be the following code. 'allocated_regs' is used in case a 4748641d5fbeSbellard temporary registers needs to be allocated to store a constant. */ 4749641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs) 4750641d5fbeSbellard { 4751ac3b8891SRichard Henderson int i, n; 4752641d5fbeSbellard 4753ac3b8891SRichard Henderson for (i = 0, n = s->nb_globals; i < n; i++) { 4754b13eb728SRichard Henderson temp_save(s, &s->temps[i], allocated_regs); 4755641d5fbeSbellard } 4756e5097dc8Sbellard } 4757e5097dc8Sbellard 47583d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be 47593d5c5f87SAurelien Jarno read by the following code. 'allocated_regs' is used in case a 47603d5c5f87SAurelien Jarno temporary registers needs to be allocated to store a constant. */ 47613d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs) 47623d5c5f87SAurelien Jarno { 4763ac3b8891SRichard Henderson int i, n; 47643d5c5f87SAurelien Jarno 4765ac3b8891SRichard Henderson for (i = 0, n = s->nb_globals; i < n; i++) { 476612b9b11aSRichard Henderson TCGTemp *ts = &s->temps[i]; 476712b9b11aSRichard Henderson tcg_debug_assert(ts->val_type != TEMP_VAL_REG 4768ee17db83SRichard Henderson || ts->kind == TEMP_FIXED 476912b9b11aSRichard Henderson || ts->mem_coherent); 47703d5c5f87SAurelien Jarno } 47713d5c5f87SAurelien Jarno } 47723d5c5f87SAurelien Jarno 4773e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and 4774e8996ee0Sbellard all globals are stored at their canonical location. */ 4775e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs) 4776e5097dc8Sbellard { 4777e5097dc8Sbellard int i; 4778e5097dc8Sbellard 4779c896fe29Sbellard for (i = s->nb_globals; i < s->nb_temps; i++) { 4780b13eb728SRichard Henderson TCGTemp *ts = &s->temps[i]; 4781c0522136SRichard Henderson 4782c0522136SRichard Henderson switch (ts->kind) { 4783f57c6915SRichard Henderson case TEMP_TB: 4784b13eb728SRichard Henderson temp_save(s, ts, allocated_regs); 4785c0522136SRichard Henderson break; 4786c7482438SRichard Henderson case TEMP_EBB: 47872c0366f0SAurelien Jarno /* The liveness analysis already ensures that temps are dead. 4788eabb7b91SAurelien Jarno Keep an tcg_debug_assert for safety. */ 4789eabb7b91SAurelien Jarno tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD); 4790c0522136SRichard Henderson break; 4791c0522136SRichard Henderson case TEMP_CONST: 4792c0522136SRichard Henderson /* Similarly, we should have freed any allocated register. */ 4793c0522136SRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_CONST); 4794c0522136SRichard Henderson break; 4795c0522136SRichard Henderson default: 4796c0522136SRichard Henderson g_assert_not_reached(); 4797c896fe29Sbellard } 4798641d5fbeSbellard } 4799e8996ee0Sbellard 4800e8996ee0Sbellard save_globals(s, allocated_regs); 4801c896fe29Sbellard } 4802c896fe29Sbellard 4803bab1671fSRichard Henderson /* 4804c7482438SRichard Henderson * At a conditional branch, we assume all temporaries are dead unless 4805c7482438SRichard Henderson * explicitly live-across-conditional-branch; all globals and local 4806c7482438SRichard Henderson * temps are synced to their location. 4807b4cb76e6SRichard Henderson */ 4808b4cb76e6SRichard Henderson static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs) 4809b4cb76e6SRichard Henderson { 4810b4cb76e6SRichard Henderson sync_globals(s, allocated_regs); 4811b4cb76e6SRichard Henderson 4812b4cb76e6SRichard Henderson for (int i = s->nb_globals; i < s->nb_temps; i++) { 4813b4cb76e6SRichard Henderson TCGTemp *ts = &s->temps[i]; 4814b4cb76e6SRichard Henderson /* 4815b4cb76e6SRichard Henderson * The liveness analysis already ensures that temps are dead. 4816b4cb76e6SRichard Henderson * Keep tcg_debug_asserts for safety. 4817b4cb76e6SRichard Henderson */ 4818c0522136SRichard Henderson switch (ts->kind) { 4819f57c6915SRichard Henderson case TEMP_TB: 4820b4cb76e6SRichard Henderson tcg_debug_assert(ts->val_type != TEMP_VAL_REG || ts->mem_coherent); 4821c0522136SRichard Henderson break; 4822c7482438SRichard Henderson case TEMP_EBB: 4823c0522136SRichard Henderson case TEMP_CONST: 4824c0522136SRichard Henderson break; 4825c0522136SRichard Henderson default: 4826c0522136SRichard Henderson g_assert_not_reached(); 4827b4cb76e6SRichard Henderson } 4828b4cb76e6SRichard Henderson } 4829b4cb76e6SRichard Henderson } 4830b4cb76e6SRichard Henderson 4831b4cb76e6SRichard Henderson /* 4832c58f4c97SRichard Henderson * Specialized code generation for INDEX_op_mov_* with a constant. 4833bab1671fSRichard Henderson */ 48340fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots, 4835ba87719cSRichard Henderson tcg_target_ulong val, TCGLifeData arg_life, 4836ba87719cSRichard Henderson TCGRegSet preferred_regs) 4837e8996ee0Sbellard { 4838d63e3b6eSRichard Henderson /* ENV should not be modified. */ 4839e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 484059d7c14eSRichard Henderson 484159d7c14eSRichard Henderson /* The movi is not explicitly generated here. */ 4842098859f1SRichard Henderson set_temp_val_nonreg(s, ots, TEMP_VAL_CONST); 4843e8996ee0Sbellard ots->val = val; 484459d7c14eSRichard Henderson ots->mem_coherent = 0; 4845ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) { 4846ba87719cSRichard Henderson temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0)); 484759d7c14eSRichard Henderson } else if (IS_DEAD_ARG(0)) { 4848f8bf00f1SRichard Henderson temp_dead(s, ots); 48494c4e1ab2SAurelien Jarno } 4850e8996ee0Sbellard } 4851e8996ee0Sbellard 4852bab1671fSRichard Henderson /* 4853bab1671fSRichard Henderson * Specialized code generation for INDEX_op_mov_*. 4854bab1671fSRichard Henderson */ 4855dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op) 4856c896fe29Sbellard { 4857dd186292SRichard Henderson const TCGLifeData arg_life = op->life; 485869e3706dSRichard Henderson TCGRegSet allocated_regs, preferred_regs; 4859c896fe29Sbellard TCGTemp *ts, *ots; 4860450445d5SRichard Henderson TCGType otype, itype; 4861098859f1SRichard Henderson TCGReg oreg, ireg; 4862c896fe29Sbellard 4863d21369f5SRichard Henderson allocated_regs = s->reserved_regs; 486431fd884bSRichard Henderson preferred_regs = output_pref(op, 0); 486543439139SRichard Henderson ots = arg_temp(op->args[0]); 486643439139SRichard Henderson ts = arg_temp(op->args[1]); 4867450445d5SRichard Henderson 4868d63e3b6eSRichard Henderson /* ENV should not be modified. */ 4869e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 4870d63e3b6eSRichard Henderson 4871450445d5SRichard Henderson /* Note that otype != itype for no-op truncation. */ 4872450445d5SRichard Henderson otype = ots->type; 4873450445d5SRichard Henderson itype = ts->type; 4874c896fe29Sbellard 48750fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_CONST) { 48760fe4fca4SPaolo Bonzini /* propagate constant or generate sti */ 48770fe4fca4SPaolo Bonzini tcg_target_ulong val = ts->val; 48780fe4fca4SPaolo Bonzini if (IS_DEAD_ARG(1)) { 48790fe4fca4SPaolo Bonzini temp_dead(s, ts); 48800fe4fca4SPaolo Bonzini } 488169e3706dSRichard Henderson tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs); 48820fe4fca4SPaolo Bonzini return; 48830fe4fca4SPaolo Bonzini } 48840fe4fca4SPaolo Bonzini 48850fe4fca4SPaolo Bonzini /* If the source value is in memory we're going to be forced 48860fe4fca4SPaolo Bonzini to have it in a register in order to perform the copy. Copy 48870fe4fca4SPaolo Bonzini the SOURCE value into its own register first, that way we 48880fe4fca4SPaolo Bonzini don't have to reload SOURCE the next time it is used. */ 48890fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_MEM) { 489069e3706dSRichard Henderson temp_load(s, ts, tcg_target_available_regs[itype], 489169e3706dSRichard Henderson allocated_regs, preferred_regs); 4892c29c1d7eSAurelien Jarno } 48930fe4fca4SPaolo Bonzini tcg_debug_assert(ts->val_type == TEMP_VAL_REG); 4894098859f1SRichard Henderson ireg = ts->reg; 4895098859f1SRichard Henderson 4896d63e3b6eSRichard Henderson if (IS_DEAD_ARG(0)) { 4897c29c1d7eSAurelien Jarno /* mov to a non-saved dead register makes no sense (even with 4898c29c1d7eSAurelien Jarno liveness analysis disabled). */ 4899eabb7b91SAurelien Jarno tcg_debug_assert(NEED_SYNC_ARG(0)); 4900c29c1d7eSAurelien Jarno if (!ots->mem_allocated) { 49012272e4a7SRichard Henderson temp_allocate_frame(s, ots); 4902c29c1d7eSAurelien Jarno } 4903098859f1SRichard Henderson tcg_out_st(s, otype, ireg, ots->mem_base->reg, ots->mem_offset); 4904c29c1d7eSAurelien Jarno if (IS_DEAD_ARG(1)) { 4905f8bf00f1SRichard Henderson temp_dead(s, ts); 4906c29c1d7eSAurelien Jarno } 4907f8bf00f1SRichard Henderson temp_dead(s, ots); 4908098859f1SRichard Henderson return; 4909098859f1SRichard Henderson } 4910098859f1SRichard Henderson 4911ee17db83SRichard Henderson if (IS_DEAD_ARG(1) && ts->kind != TEMP_FIXED) { 4912098859f1SRichard Henderson /* 4913098859f1SRichard Henderson * The mov can be suppressed. Kill input first, so that it 4914098859f1SRichard Henderson * is unlinked from reg_to_temp, then set the output to the 4915098859f1SRichard Henderson * reg that we saved from the input. 4916098859f1SRichard Henderson */ 4917f8bf00f1SRichard Henderson temp_dead(s, ts); 4918098859f1SRichard Henderson oreg = ireg; 4919c29c1d7eSAurelien Jarno } else { 4920098859f1SRichard Henderson if (ots->val_type == TEMP_VAL_REG) { 4921098859f1SRichard Henderson oreg = ots->reg; 4922098859f1SRichard Henderson } else { 4923098859f1SRichard Henderson /* Make sure to not spill the input register during allocation. */ 4924098859f1SRichard Henderson oreg = tcg_reg_alloc(s, tcg_target_available_regs[otype], 4925098859f1SRichard Henderson allocated_regs | ((TCGRegSet)1 << ireg), 4926098859f1SRichard Henderson preferred_regs, ots->indirect_base); 4927c29c1d7eSAurelien Jarno } 4928098859f1SRichard Henderson if (!tcg_out_mov(s, otype, oreg, ireg)) { 4929240c08d0SRichard Henderson /* 4930240c08d0SRichard Henderson * Cross register class move not supported. 4931240c08d0SRichard Henderson * Store the source register into the destination slot 4932240c08d0SRichard Henderson * and leave the destination temp as TEMP_VAL_MEM. 4933240c08d0SRichard Henderson */ 4934e01fa97dSRichard Henderson assert(!temp_readonly(ots)); 4935240c08d0SRichard Henderson if (!ts->mem_allocated) { 4936240c08d0SRichard Henderson temp_allocate_frame(s, ots); 4937240c08d0SRichard Henderson } 4938098859f1SRichard Henderson tcg_out_st(s, ts->type, ireg, ots->mem_base->reg, ots->mem_offset); 4939098859f1SRichard Henderson set_temp_val_nonreg(s, ts, TEMP_VAL_MEM); 4940240c08d0SRichard Henderson ots->mem_coherent = 1; 4941240c08d0SRichard Henderson return; 494278113e83SRichard Henderson } 4943c29c1d7eSAurelien Jarno } 4944098859f1SRichard Henderson set_temp_val_reg(s, ots, oreg); 4945c896fe29Sbellard ots->mem_coherent = 0; 4946098859f1SRichard Henderson 4947ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) { 494898b4e186SRichard Henderson temp_sync(s, ots, allocated_regs, 0, 0); 4949c29c1d7eSAurelien Jarno } 4950ec7a869dSAurelien Jarno } 4951c896fe29Sbellard 4952bab1671fSRichard Henderson /* 4953bab1671fSRichard Henderson * Specialized code generation for INDEX_op_dup_vec. 4954bab1671fSRichard Henderson */ 4955bab1671fSRichard Henderson static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op) 4956bab1671fSRichard Henderson { 4957bab1671fSRichard Henderson const TCGLifeData arg_life = op->life; 4958bab1671fSRichard Henderson TCGRegSet dup_out_regs, dup_in_regs; 4959501fb3daSRichard Henderson const TCGArgConstraint *dup_args_ct; 4960bab1671fSRichard Henderson TCGTemp *its, *ots; 4961bab1671fSRichard Henderson TCGType itype, vtype; 4962bab1671fSRichard Henderson unsigned vece; 496331c96417SRichard Henderson int lowpart_ofs; 4964bab1671fSRichard Henderson bool ok; 4965bab1671fSRichard Henderson 4966bab1671fSRichard Henderson ots = arg_temp(op->args[0]); 4967bab1671fSRichard Henderson its = arg_temp(op->args[1]); 4968bab1671fSRichard Henderson 4969bab1671fSRichard Henderson /* ENV should not be modified. */ 4970e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 4971bab1671fSRichard Henderson 4972bab1671fSRichard Henderson itype = its->type; 4973bab1671fSRichard Henderson vece = TCGOP_VECE(op); 49744d872218SRichard Henderson vtype = TCGOP_TYPE(op); 4975bab1671fSRichard Henderson 4976bab1671fSRichard Henderson if (its->val_type == TEMP_VAL_CONST) { 4977bab1671fSRichard Henderson /* Propagate constant via movi -> dupi. */ 4978bab1671fSRichard Henderson tcg_target_ulong val = its->val; 4979bab1671fSRichard Henderson if (IS_DEAD_ARG(1)) { 4980bab1671fSRichard Henderson temp_dead(s, its); 4981bab1671fSRichard Henderson } 498231fd884bSRichard Henderson tcg_reg_alloc_do_movi(s, ots, val, arg_life, output_pref(op, 0)); 4983bab1671fSRichard Henderson return; 4984bab1671fSRichard Henderson } 4985bab1671fSRichard Henderson 4986501fb3daSRichard Henderson dup_args_ct = opcode_args_ct(op); 4987501fb3daSRichard Henderson dup_out_regs = dup_args_ct[0].regs; 4988501fb3daSRichard Henderson dup_in_regs = dup_args_ct[1].regs; 4989bab1671fSRichard Henderson 4990bab1671fSRichard Henderson /* Allocate the output register now. */ 4991bab1671fSRichard Henderson if (ots->val_type != TEMP_VAL_REG) { 4992bab1671fSRichard Henderson TCGRegSet allocated_regs = s->reserved_regs; 4993098859f1SRichard Henderson TCGReg oreg; 4994bab1671fSRichard Henderson 4995bab1671fSRichard Henderson if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) { 4996bab1671fSRichard Henderson /* Make sure to not spill the input register. */ 4997bab1671fSRichard Henderson tcg_regset_set_reg(allocated_regs, its->reg); 4998bab1671fSRichard Henderson } 4999098859f1SRichard Henderson oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs, 500031fd884bSRichard Henderson output_pref(op, 0), ots->indirect_base); 5001098859f1SRichard Henderson set_temp_val_reg(s, ots, oreg); 5002bab1671fSRichard Henderson } 5003bab1671fSRichard Henderson 5004bab1671fSRichard Henderson switch (its->val_type) { 5005bab1671fSRichard Henderson case TEMP_VAL_REG: 5006bab1671fSRichard Henderson /* 5007bab1671fSRichard Henderson * The dup constriaints must be broad, covering all possible VECE. 5008bab1671fSRichard Henderson * However, tcg_op_dup_vec() gets to see the VECE and we allow it 5009bab1671fSRichard Henderson * to fail, indicating that extra moves are required for that case. 5010bab1671fSRichard Henderson */ 5011bab1671fSRichard Henderson if (tcg_regset_test_reg(dup_in_regs, its->reg)) { 5012bab1671fSRichard Henderson if (tcg_out_dup_vec(s, vtype, vece, ots->reg, its->reg)) { 5013bab1671fSRichard Henderson goto done; 5014bab1671fSRichard Henderson } 5015bab1671fSRichard Henderson /* Try again from memory or a vector input register. */ 5016bab1671fSRichard Henderson } 5017bab1671fSRichard Henderson if (!its->mem_coherent) { 5018bab1671fSRichard Henderson /* 5019bab1671fSRichard Henderson * The input register is not synced, and so an extra store 5020bab1671fSRichard Henderson * would be required to use memory. Attempt an integer-vector 5021bab1671fSRichard Henderson * register move first. We do not have a TCGRegSet for this. 5022bab1671fSRichard Henderson */ 5023bab1671fSRichard Henderson if (tcg_out_mov(s, itype, ots->reg, its->reg)) { 5024bab1671fSRichard Henderson break; 5025bab1671fSRichard Henderson } 5026bab1671fSRichard Henderson /* Sync the temp back to its slot and load from there. */ 5027bab1671fSRichard Henderson temp_sync(s, its, s->reserved_regs, 0, 0); 5028bab1671fSRichard Henderson } 5029bab1671fSRichard Henderson /* fall through */ 5030bab1671fSRichard Henderson 5031bab1671fSRichard Henderson case TEMP_VAL_MEM: 503231c96417SRichard Henderson lowpart_ofs = 0; 503331c96417SRichard Henderson if (HOST_BIG_ENDIAN) { 503431c96417SRichard Henderson lowpart_ofs = tcg_type_size(itype) - (1 << vece); 503531c96417SRichard Henderson } 5036d6ecb4a9SRichard Henderson if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg, 503731c96417SRichard Henderson its->mem_offset + lowpart_ofs)) { 5038d6ecb4a9SRichard Henderson goto done; 5039d6ecb4a9SRichard Henderson } 5040098859f1SRichard Henderson /* Load the input into the destination vector register. */ 5041bab1671fSRichard Henderson tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset); 5042bab1671fSRichard Henderson break; 5043bab1671fSRichard Henderson 5044bab1671fSRichard Henderson default: 5045bab1671fSRichard Henderson g_assert_not_reached(); 5046bab1671fSRichard Henderson } 5047bab1671fSRichard Henderson 5048bab1671fSRichard Henderson /* We now have a vector input register, so dup must succeed. */ 5049bab1671fSRichard Henderson ok = tcg_out_dup_vec(s, vtype, vece, ots->reg, ots->reg); 5050bab1671fSRichard Henderson tcg_debug_assert(ok); 5051bab1671fSRichard Henderson 5052bab1671fSRichard Henderson done: 505336f5539cSRichard Henderson ots->mem_coherent = 0; 5054bab1671fSRichard Henderson if (IS_DEAD_ARG(1)) { 5055bab1671fSRichard Henderson temp_dead(s, its); 5056bab1671fSRichard Henderson } 5057bab1671fSRichard Henderson if (NEED_SYNC_ARG(0)) { 5058bab1671fSRichard Henderson temp_sync(s, ots, s->reserved_regs, 0, 0); 5059bab1671fSRichard Henderson } 5060bab1671fSRichard Henderson if (IS_DEAD_ARG(0)) { 5061bab1671fSRichard Henderson temp_dead(s, ots); 5062bab1671fSRichard Henderson } 5063bab1671fSRichard Henderson } 5064bab1671fSRichard Henderson 5065dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) 5066c896fe29Sbellard { 5067dd186292SRichard Henderson const TCGLifeData arg_life = op->life; 5068dd186292SRichard Henderson const TCGOpDef * const def = &tcg_op_defs[op->opc]; 506982790a87SRichard Henderson TCGRegSet i_allocated_regs; 507082790a87SRichard Henderson TCGRegSet o_allocated_regs; 5071b6638662SRichard Henderson int i, k, nb_iargs, nb_oargs; 5072b6638662SRichard Henderson TCGReg reg; 5073c896fe29Sbellard TCGArg arg; 5074501fb3daSRichard Henderson const TCGArgConstraint *args_ct; 5075c896fe29Sbellard const TCGArgConstraint *arg_ct; 5076c896fe29Sbellard TCGTemp *ts; 5077c896fe29Sbellard TCGArg new_args[TCG_MAX_OP_ARGS]; 5078c896fe29Sbellard int const_args[TCG_MAX_OP_ARGS]; 507921e9a8aeSRichard Henderson TCGCond op_cond; 5080c896fe29Sbellard 5081c896fe29Sbellard nb_oargs = def->nb_oargs; 5082c896fe29Sbellard nb_iargs = def->nb_iargs; 5083c896fe29Sbellard 5084c896fe29Sbellard /* copy constants */ 5085c896fe29Sbellard memcpy(new_args + nb_oargs + nb_iargs, 5086dd186292SRichard Henderson op->args + nb_oargs + nb_iargs, 5087c896fe29Sbellard sizeof(TCGArg) * def->nb_cargs); 5088c896fe29Sbellard 5089d21369f5SRichard Henderson i_allocated_regs = s->reserved_regs; 5090d21369f5SRichard Henderson o_allocated_regs = s->reserved_regs; 509182790a87SRichard Henderson 509221e9a8aeSRichard Henderson switch (op->opc) { 5093b6d69fceSRichard Henderson case INDEX_op_brcond: 509421e9a8aeSRichard Henderson op_cond = op->args[2]; 509521e9a8aeSRichard Henderson break; 5096a363e1e1SRichard Henderson case INDEX_op_setcond: 5097a363e1e1SRichard Henderson case INDEX_op_negsetcond: 509821e9a8aeSRichard Henderson case INDEX_op_cmp_vec: 509921e9a8aeSRichard Henderson op_cond = op->args[3]; 510021e9a8aeSRichard Henderson break; 510121e9a8aeSRichard Henderson case INDEX_op_brcond2_i32: 510221e9a8aeSRichard Henderson op_cond = op->args[4]; 510321e9a8aeSRichard Henderson break; 5104ea46c4bcSRichard Henderson case INDEX_op_movcond: 510521e9a8aeSRichard Henderson case INDEX_op_setcond2_i32: 510621e9a8aeSRichard Henderson case INDEX_op_cmpsel_vec: 510721e9a8aeSRichard Henderson op_cond = op->args[5]; 510821e9a8aeSRichard Henderson break; 510921e9a8aeSRichard Henderson default: 511021e9a8aeSRichard Henderson /* No condition within opcode. */ 511121e9a8aeSRichard Henderson op_cond = TCG_COND_ALWAYS; 511221e9a8aeSRichard Henderson break; 511321e9a8aeSRichard Henderson } 511421e9a8aeSRichard Henderson 5115501fb3daSRichard Henderson args_ct = opcode_args_ct(op); 5116501fb3daSRichard Henderson 5117c896fe29Sbellard /* satisfy input constraints */ 5118c896fe29Sbellard for (k = 0; k < nb_iargs; k++) { 511929f5e925SRichard Henderson TCGRegSet i_preferred_regs, i_required_regs; 512029f5e925SRichard Henderson bool allocate_new_reg, copyto_new_reg; 512129f5e925SRichard Henderson TCGTemp *ts2; 512229f5e925SRichard Henderson int i1, i2; 5123d62816f2SRichard Henderson 5124501fb3daSRichard Henderson i = args_ct[nb_oargs + k].sort_index; 5125dd186292SRichard Henderson arg = op->args[i]; 5126501fb3daSRichard Henderson arg_ct = &args_ct[i]; 512743439139SRichard Henderson ts = arg_temp(arg); 512840ae5c62SRichard Henderson 51296b8abd24SRichard Henderson if (ts->val_type == TEMP_VAL_CONST) { 51306b8abd24SRichard Henderson #ifdef TCG_REG_ZERO 51316b8abd24SRichard Henderson if (ts->val == 0 && (arg_ct->ct & TCG_CT_REG_ZERO)) { 51326b8abd24SRichard Henderson /* Hardware zero register: indicate register via non-const. */ 51336b8abd24SRichard Henderson const_args[i] = 0; 51346b8abd24SRichard Henderson new_args[i] = TCG_REG_ZERO; 51356b8abd24SRichard Henderson continue; 51366b8abd24SRichard Henderson } 51376b8abd24SRichard Henderson #endif 51386b8abd24SRichard Henderson 51396b8abd24SRichard Henderson if (tcg_target_const_match(ts->val, arg_ct->ct, ts->type, 514021e9a8aeSRichard Henderson op_cond, TCGOP_VECE(op))) { 5141c896fe29Sbellard /* constant is OK for instruction */ 5142c896fe29Sbellard const_args[i] = 1; 5143c896fe29Sbellard new_args[i] = ts->val; 5144d62816f2SRichard Henderson continue; 5145c896fe29Sbellard } 51466b8abd24SRichard Henderson } 514740ae5c62SRichard Henderson 51481c1824dcSRichard Henderson reg = ts->reg; 51491c1824dcSRichard Henderson i_preferred_regs = 0; 515029f5e925SRichard Henderson i_required_regs = arg_ct->regs; 51511c1824dcSRichard Henderson allocate_new_reg = false; 515229f5e925SRichard Henderson copyto_new_reg = false; 51531c1824dcSRichard Henderson 515429f5e925SRichard Henderson switch (arg_ct->pair) { 515529f5e925SRichard Henderson case 0: /* not paired */ 5156bc2b17e6SRichard Henderson if (arg_ct->ialias) { 515731fd884bSRichard Henderson i_preferred_regs = output_pref(op, arg_ct->alias_index); 5158c0522136SRichard Henderson 5159c0522136SRichard Henderson /* 5160c0522136SRichard Henderson * If the input is readonly, then it cannot also be an 5161c0522136SRichard Henderson * output and aliased to itself. If the input is not 5162c0522136SRichard Henderson * dead after the instruction, we must allocate a new 5163c0522136SRichard Henderson * register and move it. 5164c0522136SRichard Henderson */ 516522d2e535SIlya Leoshkevich if (temp_readonly(ts) || !IS_DEAD_ARG(i) 5166501fb3daSRichard Henderson || args_ct[arg_ct->alias_index].newreg) { 51671c1824dcSRichard Henderson allocate_new_reg = true; 51681c1824dcSRichard Henderson } else if (ts->val_type == TEMP_VAL_REG) { 5169c0522136SRichard Henderson /* 51701c1824dcSRichard Henderson * Check if the current register has already been 51711c1824dcSRichard Henderson * allocated for another input. 5172c0522136SRichard Henderson */ 517329f5e925SRichard Henderson allocate_new_reg = 517429f5e925SRichard Henderson tcg_regset_test_reg(i_allocated_regs, reg); 51757e1df267SAurelien Jarno } 51767e1df267SAurelien Jarno } 51771c1824dcSRichard Henderson if (!allocate_new_reg) { 517829f5e925SRichard Henderson temp_load(s, ts, i_required_regs, i_allocated_regs, 517929f5e925SRichard Henderson i_preferred_regs); 5180c896fe29Sbellard reg = ts->reg; 518129f5e925SRichard Henderson allocate_new_reg = !tcg_regset_test_reg(i_required_regs, reg); 51821c1824dcSRichard Henderson } 51831c1824dcSRichard Henderson if (allocate_new_reg) { 5184c0522136SRichard Henderson /* 5185c0522136SRichard Henderson * Allocate a new register matching the constraint 5186c0522136SRichard Henderson * and move the temporary register into it. 5187c0522136SRichard Henderson */ 5188d62816f2SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 5189d62816f2SRichard Henderson i_allocated_regs, 0); 519029f5e925SRichard Henderson reg = tcg_reg_alloc(s, i_required_regs, i_allocated_regs, 51911c1824dcSRichard Henderson i_preferred_regs, ts->indirect_base); 519229f5e925SRichard Henderson copyto_new_reg = true; 519329f5e925SRichard Henderson } 519429f5e925SRichard Henderson break; 519529f5e925SRichard Henderson 519629f5e925SRichard Henderson case 1: 519729f5e925SRichard Henderson /* First of an input pair; if i1 == i2, the second is an output. */ 519829f5e925SRichard Henderson i1 = i; 519929f5e925SRichard Henderson i2 = arg_ct->pair_index; 520029f5e925SRichard Henderson ts2 = i1 != i2 ? arg_temp(op->args[i2]) : NULL; 520129f5e925SRichard Henderson 520229f5e925SRichard Henderson /* 520329f5e925SRichard Henderson * It is easier to default to allocating a new pair 520429f5e925SRichard Henderson * and to identify a few cases where it's not required. 520529f5e925SRichard Henderson */ 520629f5e925SRichard Henderson if (arg_ct->ialias) { 520731fd884bSRichard Henderson i_preferred_regs = output_pref(op, arg_ct->alias_index); 520829f5e925SRichard Henderson if (IS_DEAD_ARG(i1) && 520929f5e925SRichard Henderson IS_DEAD_ARG(i2) && 521029f5e925SRichard Henderson !temp_readonly(ts) && 521129f5e925SRichard Henderson ts->val_type == TEMP_VAL_REG && 521229f5e925SRichard Henderson ts->reg < TCG_TARGET_NB_REGS - 1 && 521329f5e925SRichard Henderson tcg_regset_test_reg(i_required_regs, reg) && 521429f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg) && 521529f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg + 1) && 521629f5e925SRichard Henderson (ts2 521729f5e925SRichard Henderson ? ts2->val_type == TEMP_VAL_REG && 521829f5e925SRichard Henderson ts2->reg == reg + 1 && 521929f5e925SRichard Henderson !temp_readonly(ts2) 522029f5e925SRichard Henderson : s->reg_to_temp[reg + 1] == NULL)) { 522129f5e925SRichard Henderson break; 522229f5e925SRichard Henderson } 522329f5e925SRichard Henderson } else { 522429f5e925SRichard Henderson /* Without aliasing, the pair must also be an input. */ 522529f5e925SRichard Henderson tcg_debug_assert(ts2); 522629f5e925SRichard Henderson if (ts->val_type == TEMP_VAL_REG && 522729f5e925SRichard Henderson ts2->val_type == TEMP_VAL_REG && 522829f5e925SRichard Henderson ts2->reg == reg + 1 && 522929f5e925SRichard Henderson tcg_regset_test_reg(i_required_regs, reg)) { 523029f5e925SRichard Henderson break; 523129f5e925SRichard Henderson } 523229f5e925SRichard Henderson } 523329f5e925SRichard Henderson reg = tcg_reg_alloc_pair(s, i_required_regs, i_allocated_regs, 523429f5e925SRichard Henderson 0, ts->indirect_base); 523529f5e925SRichard Henderson goto do_pair; 523629f5e925SRichard Henderson 523729f5e925SRichard Henderson case 2: /* pair second */ 523829f5e925SRichard Henderson reg = new_args[arg_ct->pair_index] + 1; 523929f5e925SRichard Henderson goto do_pair; 524029f5e925SRichard Henderson 524129f5e925SRichard Henderson case 3: /* ialias with second output, no first input */ 524229f5e925SRichard Henderson tcg_debug_assert(arg_ct->ialias); 524331fd884bSRichard Henderson i_preferred_regs = output_pref(op, arg_ct->alias_index); 524429f5e925SRichard Henderson 524529f5e925SRichard Henderson if (IS_DEAD_ARG(i) && 524629f5e925SRichard Henderson !temp_readonly(ts) && 524729f5e925SRichard Henderson ts->val_type == TEMP_VAL_REG && 524829f5e925SRichard Henderson reg > 0 && 524929f5e925SRichard Henderson s->reg_to_temp[reg - 1] == NULL && 525029f5e925SRichard Henderson tcg_regset_test_reg(i_required_regs, reg) && 525129f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg) && 525229f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg - 1)) { 525329f5e925SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg - 1); 525429f5e925SRichard Henderson break; 525529f5e925SRichard Henderson } 525629f5e925SRichard Henderson reg = tcg_reg_alloc_pair(s, i_required_regs >> 1, 525729f5e925SRichard Henderson i_allocated_regs, 0, 525829f5e925SRichard Henderson ts->indirect_base); 525929f5e925SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg); 526029f5e925SRichard Henderson reg += 1; 526129f5e925SRichard Henderson goto do_pair; 526229f5e925SRichard Henderson 526329f5e925SRichard Henderson do_pair: 526429f5e925SRichard Henderson /* 526529f5e925SRichard Henderson * If an aliased input is not dead after the instruction, 526629f5e925SRichard Henderson * we must allocate a new register and move it. 526729f5e925SRichard Henderson */ 526829f5e925SRichard Henderson if (arg_ct->ialias && (!IS_DEAD_ARG(i) || temp_readonly(ts))) { 526929f5e925SRichard Henderson TCGRegSet t_allocated_regs = i_allocated_regs; 527029f5e925SRichard Henderson 527129f5e925SRichard Henderson /* 527229f5e925SRichard Henderson * Because of the alias, and the continued life, make sure 527329f5e925SRichard Henderson * that the temp is somewhere *other* than the reg pair, 527429f5e925SRichard Henderson * and we get a copy in reg. 527529f5e925SRichard Henderson */ 527629f5e925SRichard Henderson tcg_regset_set_reg(t_allocated_regs, reg); 527729f5e925SRichard Henderson tcg_regset_set_reg(t_allocated_regs, reg + 1); 527829f5e925SRichard Henderson if (ts->val_type == TEMP_VAL_REG && ts->reg == reg) { 527929f5e925SRichard Henderson /* If ts was already in reg, copy it somewhere else. */ 528029f5e925SRichard Henderson TCGReg nr; 528129f5e925SRichard Henderson bool ok; 528229f5e925SRichard Henderson 528329f5e925SRichard Henderson tcg_debug_assert(ts->kind != TEMP_FIXED); 528429f5e925SRichard Henderson nr = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], 528529f5e925SRichard Henderson t_allocated_regs, 0, ts->indirect_base); 528629f5e925SRichard Henderson ok = tcg_out_mov(s, ts->type, nr, reg); 528729f5e925SRichard Henderson tcg_debug_assert(ok); 528829f5e925SRichard Henderson 528929f5e925SRichard Henderson set_temp_val_reg(s, ts, nr); 529029f5e925SRichard Henderson } else { 529129f5e925SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 529229f5e925SRichard Henderson t_allocated_regs, 0); 529329f5e925SRichard Henderson copyto_new_reg = true; 529429f5e925SRichard Henderson } 529529f5e925SRichard Henderson } else { 529629f5e925SRichard Henderson /* Preferably allocate to reg, otherwise copy. */ 529729f5e925SRichard Henderson i_required_regs = (TCGRegSet)1 << reg; 529829f5e925SRichard Henderson temp_load(s, ts, i_required_regs, i_allocated_regs, 529929f5e925SRichard Henderson i_preferred_regs); 530029f5e925SRichard Henderson copyto_new_reg = ts->reg != reg; 530129f5e925SRichard Henderson } 530229f5e925SRichard Henderson break; 530329f5e925SRichard Henderson 530429f5e925SRichard Henderson default: 530529f5e925SRichard Henderson g_assert_not_reached(); 530629f5e925SRichard Henderson } 530729f5e925SRichard Henderson 530829f5e925SRichard Henderson if (copyto_new_reg) { 530978113e83SRichard Henderson if (!tcg_out_mov(s, ts->type, reg, ts->reg)) { 5310240c08d0SRichard Henderson /* 5311240c08d0SRichard Henderson * Cross register class move not supported. Sync the 5312240c08d0SRichard Henderson * temp back to its slot and load from there. 5313240c08d0SRichard Henderson */ 5314240c08d0SRichard Henderson temp_sync(s, ts, i_allocated_regs, 0, 0); 5315240c08d0SRichard Henderson tcg_out_ld(s, ts->type, reg, 5316240c08d0SRichard Henderson ts->mem_base->reg, ts->mem_offset); 531778113e83SRichard Henderson } 5318c896fe29Sbellard } 5319c896fe29Sbellard new_args[i] = reg; 5320c896fe29Sbellard const_args[i] = 0; 532182790a87SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg); 5322c896fe29Sbellard } 5323c896fe29Sbellard 5324c896fe29Sbellard /* mark dead temporaries and free the associated registers */ 5325866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 5326866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) { 532743439139SRichard Henderson temp_dead(s, arg_temp(op->args[i])); 5328c896fe29Sbellard } 5329c896fe29Sbellard } 5330c896fe29Sbellard 5331b4cb76e6SRichard Henderson if (def->flags & TCG_OPF_COND_BRANCH) { 5332b4cb76e6SRichard Henderson tcg_reg_alloc_cbranch(s, i_allocated_regs); 5333b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 533482790a87SRichard Henderson tcg_reg_alloc_bb_end(s, i_allocated_regs); 5335a52ad07eSAurelien Jarno } else { 5336c896fe29Sbellard if (def->flags & TCG_OPF_CALL_CLOBBER) { 5337b03cce8eSbellard /* XXX: permit generic clobber register list ? */ 5338c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) { 5339c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { 534082790a87SRichard Henderson tcg_reg_free(s, i, i_allocated_regs); 5341c896fe29Sbellard } 5342c896fe29Sbellard } 53433d5c5f87SAurelien Jarno } 53443d5c5f87SAurelien Jarno if (def->flags & TCG_OPF_SIDE_EFFECTS) { 53453d5c5f87SAurelien Jarno /* sync globals if the op has side effects and might trigger 53463d5c5f87SAurelien Jarno an exception. */ 534782790a87SRichard Henderson sync_globals(s, i_allocated_regs); 5348c896fe29Sbellard } 5349c896fe29Sbellard 5350c896fe29Sbellard /* satisfy the output constraints */ 5351c896fe29Sbellard for (k = 0; k < nb_oargs; k++) { 5352501fb3daSRichard Henderson i = args_ct[k].sort_index; 5353dd186292SRichard Henderson arg = op->args[i]; 5354501fb3daSRichard Henderson arg_ct = &args_ct[i]; 535543439139SRichard Henderson ts = arg_temp(arg); 5356d63e3b6eSRichard Henderson 5357d63e3b6eSRichard Henderson /* ENV should not be modified. */ 5358e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ts)); 5359d63e3b6eSRichard Henderson 536029f5e925SRichard Henderson switch (arg_ct->pair) { 536129f5e925SRichard Henderson case 0: /* not paired */ 5362bc2b17e6SRichard Henderson if (arg_ct->oalias && !const_args[arg_ct->alias_index]) { 53635ff9d6a4Sbellard reg = new_args[arg_ct->alias_index]; 5364bc2b17e6SRichard Henderson } else if (arg_ct->newreg) { 53659be0d080SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->regs, 536682790a87SRichard Henderson i_allocated_regs | o_allocated_regs, 536731fd884bSRichard Henderson output_pref(op, k), ts->indirect_base); 5368c896fe29Sbellard } else { 53699be0d080SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs, 537031fd884bSRichard Henderson output_pref(op, k), ts->indirect_base); 5371c896fe29Sbellard } 537229f5e925SRichard Henderson break; 537329f5e925SRichard Henderson 537429f5e925SRichard Henderson case 1: /* first of pair */ 537529f5e925SRichard Henderson if (arg_ct->oalias) { 537629f5e925SRichard Henderson reg = new_args[arg_ct->alias_index]; 5377ca5bed07SRichard Henderson } else if (arg_ct->newreg) { 5378ca5bed07SRichard Henderson reg = tcg_reg_alloc_pair(s, arg_ct->regs, 5379ca5bed07SRichard Henderson i_allocated_regs | o_allocated_regs, 5380ca5bed07SRichard Henderson output_pref(op, k), 5381ca5bed07SRichard Henderson ts->indirect_base); 5382ca5bed07SRichard Henderson } else { 538329f5e925SRichard Henderson reg = tcg_reg_alloc_pair(s, arg_ct->regs, o_allocated_regs, 5384ca5bed07SRichard Henderson output_pref(op, k), 5385ca5bed07SRichard Henderson ts->indirect_base); 5386ca5bed07SRichard Henderson } 538729f5e925SRichard Henderson break; 538829f5e925SRichard Henderson 538929f5e925SRichard Henderson case 2: /* second of pair */ 539029f5e925SRichard Henderson if (arg_ct->oalias) { 539129f5e925SRichard Henderson reg = new_args[arg_ct->alias_index]; 539229f5e925SRichard Henderson } else { 539329f5e925SRichard Henderson reg = new_args[arg_ct->pair_index] + 1; 539429f5e925SRichard Henderson } 539529f5e925SRichard Henderson break; 539629f5e925SRichard Henderson 539729f5e925SRichard Henderson case 3: /* first of pair, aliasing with a second input */ 539829f5e925SRichard Henderson tcg_debug_assert(!arg_ct->newreg); 539929f5e925SRichard Henderson reg = new_args[arg_ct->pair_index] - 1; 540029f5e925SRichard Henderson break; 540129f5e925SRichard Henderson 540229f5e925SRichard Henderson default: 540329f5e925SRichard Henderson g_assert_not_reached(); 540429f5e925SRichard Henderson } 540582790a87SRichard Henderson tcg_regset_set_reg(o_allocated_regs, reg); 5406098859f1SRichard Henderson set_temp_val_reg(s, ts, reg); 5407c896fe29Sbellard ts->mem_coherent = 0; 5408c896fe29Sbellard new_args[i] = reg; 5409c896fe29Sbellard } 5410e8996ee0Sbellard } 5411c896fe29Sbellard 5412c896fe29Sbellard /* emit instruction */ 5413662cdbcfSRichard Henderson TCGType type = TCGOP_TYPE(op); 5414678155b2SRichard Henderson switch (op->opc) { 54159c6aa274SRichard Henderson case INDEX_op_ext_i32_i64: 54169c6aa274SRichard Henderson tcg_out_exts_i32_i64(s, new_args[0], new_args[1]); 54179c6aa274SRichard Henderson break; 5418b9bfe000SRichard Henderson case INDEX_op_extu_i32_i64: 5419b9bfe000SRichard Henderson tcg_out_extu_i32_i64(s, new_args[0], new_args[1]); 5420b9bfe000SRichard Henderson break; 5421b8b94ac6SRichard Henderson case INDEX_op_extrl_i64_i32: 5422b8b94ac6SRichard Henderson tcg_out_extrl_i64_i32(s, new_args[0], new_args[1]); 5423b8b94ac6SRichard Henderson break; 5424662cdbcfSRichard Henderson 542579602f63SRichard Henderson case INDEX_op_add: 5426c3b920b3SRichard Henderson case INDEX_op_and: 542746f96bffSRichard Henderson case INDEX_op_andc: 54285a5bb0a5SRichard Henderson case INDEX_op_clz: 5429c96447d8SRichard Henderson case INDEX_op_ctz: 5430b2c514f9SRichard Henderson case INDEX_op_divs: 5431961b80aeSRichard Henderson case INDEX_op_divu: 54325c0968a7SRichard Henderson case INDEX_op_eqv: 5433d2c3ecadSRichard Henderson case INDEX_op_mul: 5434c742824dSRichard Henderson case INDEX_op_mulsh: 5435aa28c9efSRichard Henderson case INDEX_op_muluh: 543659379a45SRichard Henderson case INDEX_op_nand: 54373a8c4e9eSRichard Henderson case INDEX_op_nor: 543849bd7514SRichard Henderson case INDEX_op_or: 54396aba25ebSRichard Henderson case INDEX_op_orc: 54409a6bc184SRichard Henderson case INDEX_op_rems: 5441cd9acd20SRichard Henderson case INDEX_op_remu: 5442005a87e1SRichard Henderson case INDEX_op_rotl: 5443005a87e1SRichard Henderson case INDEX_op_rotr: 54443949f365SRichard Henderson case INDEX_op_sar: 54456ca59451SRichard Henderson case INDEX_op_shl: 544674dbd36fSRichard Henderson case INDEX_op_shr: 5447fffd3dc9SRichard Henderson case INDEX_op_xor: 5448662cdbcfSRichard Henderson { 5449662cdbcfSRichard Henderson const TCGOutOpBinary *out = 5450662cdbcfSRichard Henderson container_of(all_outop[op->opc], TCGOutOpBinary, base); 5451662cdbcfSRichard Henderson 5452662cdbcfSRichard Henderson /* Constants should never appear in the first source operand. */ 5453662cdbcfSRichard Henderson tcg_debug_assert(!const_args[1]); 5454662cdbcfSRichard Henderson if (const_args[2]) { 5455662cdbcfSRichard Henderson out->out_rri(s, type, new_args[0], new_args[1], new_args[2]); 5456662cdbcfSRichard Henderson } else { 5457662cdbcfSRichard Henderson out->out_rrr(s, type, new_args[0], new_args[1], new_args[2]); 5458662cdbcfSRichard Henderson } 5459662cdbcfSRichard Henderson } 5460662cdbcfSRichard Henderson break; 5461662cdbcfSRichard Henderson 546260f34f55SRichard Henderson case INDEX_op_sub: 54633f057e24SRichard Henderson { 54643f057e24SRichard Henderson const TCGOutOpSubtract *out = &outop_sub; 54653f057e24SRichard Henderson 54663f057e24SRichard Henderson /* 54673f057e24SRichard Henderson * Constants should never appear in the second source operand. 54683f057e24SRichard Henderson * These are folded to add with negative constant. 54693f057e24SRichard Henderson */ 54703f057e24SRichard Henderson tcg_debug_assert(!const_args[2]); 54713f057e24SRichard Henderson if (const_args[1]) { 54723f057e24SRichard Henderson out->out_rir(s, type, new_args[0], new_args[1], new_args[2]); 54733f057e24SRichard Henderson } else { 54743f057e24SRichard Henderson out->out_rrr(s, type, new_args[0], new_args[1], new_args[2]); 54753f057e24SRichard Henderson } 54763f057e24SRichard Henderson } 54773f057e24SRichard Henderson break; 54783f057e24SRichard Henderson 54793ad5d4ccSRichard Henderson case INDEX_op_bswap64: 5480613b571cSRichard Henderson assert(TCG_TARGET_REG_BITS == 64); 5481613b571cSRichard Henderson /* fall through */ 548297218ae9SRichard Henderson case INDEX_op_ctpop: 548369713587SRichard Henderson case INDEX_op_neg: 54845c62d377SRichard Henderson case INDEX_op_not: 5485e126a91cSRichard Henderson { 5486e126a91cSRichard Henderson const TCGOutOpUnary *out = 5487e126a91cSRichard Henderson container_of(all_outop[op->opc], TCGOutOpUnary, base); 5488e126a91cSRichard Henderson 5489e126a91cSRichard Henderson /* Constants should have been folded. */ 5490e126a91cSRichard Henderson tcg_debug_assert(!const_args[1]); 5491e126a91cSRichard Henderson out->out_rr(s, type, new_args[0], new_args[1]); 5492e126a91cSRichard Henderson } 5493e126a91cSRichard Henderson break; 5494e126a91cSRichard Henderson 54950dd07ee1SRichard Henderson case INDEX_op_bswap16: 54967498d882SRichard Henderson case INDEX_op_bswap32: 54975fa8e138SRichard Henderson { 54985fa8e138SRichard Henderson const TCGOutOpBswap *out = 54995fa8e138SRichard Henderson container_of(all_outop[op->opc], TCGOutOpBswap, base); 55005fa8e138SRichard Henderson 55015fa8e138SRichard Henderson tcg_debug_assert(!const_args[1]); 55025fa8e138SRichard Henderson out->out_rr(s, type, new_args[0], new_args[1], new_args[2]); 55035fa8e138SRichard Henderson } 55045fa8e138SRichard Henderson break; 55055fa8e138SRichard Henderson 5506ee1805b9SRichard Henderson case INDEX_op_divs2: 55078109598bSRichard Henderson case INDEX_op_divu2: 5508d6cad9c9SRichard Henderson { 5509d6cad9c9SRichard Henderson const TCGOutOpDivRem *out = 5510d6cad9c9SRichard Henderson container_of(all_outop[op->opc], TCGOutOpDivRem, base); 5511d6cad9c9SRichard Henderson 5512d6cad9c9SRichard Henderson /* Only used by x86 and s390x, which use matching constraints. */ 5513d6cad9c9SRichard Henderson tcg_debug_assert(new_args[0] == new_args[2]); 5514d6cad9c9SRichard Henderson tcg_debug_assert(new_args[1] == new_args[3]); 5515d6cad9c9SRichard Henderson tcg_debug_assert(!const_args[4]); 5516d6cad9c9SRichard Henderson out->out_rr01r(s, type, new_args[0], new_args[1], new_args[4]); 5517d6cad9c9SRichard Henderson } 5518d6cad9c9SRichard Henderson break; 5519d6cad9c9SRichard Henderson 5520*07d5d502SRichard Henderson case INDEX_op_extract: 55215a4d034fSRichard Henderson { 55225a4d034fSRichard Henderson const TCGOutOpExtract *out = 55235a4d034fSRichard Henderson container_of(all_outop[op->opc], TCGOutOpExtract, base); 55245a4d034fSRichard Henderson 55255a4d034fSRichard Henderson tcg_debug_assert(!const_args[1]); 55265a4d034fSRichard Henderson out->out_rr(s, type, new_args[0], new_args[1], 55275a4d034fSRichard Henderson new_args[2], new_args[3]); 55285a4d034fSRichard Henderson } 55295a4d034fSRichard Henderson break; 55305a4d034fSRichard Henderson 5531bfe96480SRichard Henderson case INDEX_op_muls2: 5532d776198cSRichard Henderson case INDEX_op_mulu2: 55335641afdfSRichard Henderson { 55345641afdfSRichard Henderson const TCGOutOpMul2 *out = 55355641afdfSRichard Henderson container_of(all_outop[op->opc], TCGOutOpMul2, base); 55365641afdfSRichard Henderson 55375641afdfSRichard Henderson tcg_debug_assert(!const_args[2]); 55385641afdfSRichard Henderson tcg_debug_assert(!const_args[3]); 55395641afdfSRichard Henderson out->out_rrrr(s, type, new_args[0], new_args[1], 55405641afdfSRichard Henderson new_args[2], new_args[3]); 55415641afdfSRichard Henderson } 55425641afdfSRichard Henderson break; 55435641afdfSRichard Henderson 5544b6d69fceSRichard Henderson case INDEX_op_brcond: 554599ac4706SRichard Henderson { 554699ac4706SRichard Henderson const TCGOutOpBrcond *out = &outop_brcond; 554799ac4706SRichard Henderson TCGCond cond = new_args[2]; 554899ac4706SRichard Henderson TCGLabel *label = arg_label(new_args[3]); 554999ac4706SRichard Henderson 555099ac4706SRichard Henderson tcg_debug_assert(!const_args[0]); 555199ac4706SRichard Henderson if (const_args[1]) { 555299ac4706SRichard Henderson out->out_ri(s, type, cond, new_args[0], new_args[1], label); 555399ac4706SRichard Henderson } else { 555499ac4706SRichard Henderson out->out_rr(s, type, cond, new_args[0], new_args[1], label); 555599ac4706SRichard Henderson } 555699ac4706SRichard Henderson } 555799ac4706SRichard Henderson break; 555899ac4706SRichard Henderson 5559ea46c4bcSRichard Henderson case INDEX_op_movcond: 55601f406e46SRichard Henderson { 55611f406e46SRichard Henderson const TCGOutOpMovcond *out = &outop_movcond; 55621f406e46SRichard Henderson TCGCond cond = new_args[5]; 55631f406e46SRichard Henderson 55641f406e46SRichard Henderson tcg_debug_assert(!const_args[1]); 55651f406e46SRichard Henderson out->out(s, type, cond, new_args[0], 55661f406e46SRichard Henderson new_args[1], new_args[2], const_args[2], 55671f406e46SRichard Henderson new_args[3], const_args[3], 55681f406e46SRichard Henderson new_args[4], const_args[4]); 55691f406e46SRichard Henderson } 55701f406e46SRichard Henderson break; 55711f406e46SRichard Henderson 5572a363e1e1SRichard Henderson case INDEX_op_setcond: 5573a363e1e1SRichard Henderson case INDEX_op_negsetcond: 55745a7b38c8SRichard Henderson { 55755a7b38c8SRichard Henderson const TCGOutOpSetcond *out = 55765a7b38c8SRichard Henderson container_of(all_outop[op->opc], TCGOutOpSetcond, base); 55775a7b38c8SRichard Henderson TCGCond cond = new_args[3]; 55785a7b38c8SRichard Henderson 55795a7b38c8SRichard Henderson tcg_debug_assert(!const_args[1]); 55805a7b38c8SRichard Henderson if (const_args[2]) { 55815a7b38c8SRichard Henderson out->out_rri(s, type, cond, 55825a7b38c8SRichard Henderson new_args[0], new_args[1], new_args[2]); 55835a7b38c8SRichard Henderson } else { 55845a7b38c8SRichard Henderson out->out_rrr(s, type, cond, 55855a7b38c8SRichard Henderson new_args[0], new_args[1], new_args[2]); 55865a7b38c8SRichard Henderson } 55875a7b38c8SRichard Henderson } 55885a7b38c8SRichard Henderson break; 55895641afdfSRichard Henderson 5590f408df58SRichard Henderson #if TCG_TARGET_REG_BITS == 32 5591f408df58SRichard Henderson case INDEX_op_brcond2_i32: 5592f408df58SRichard Henderson { 5593f408df58SRichard Henderson const TCGOutOpBrcond2 *out = &outop_brcond2; 5594f408df58SRichard Henderson TCGCond cond = new_args[4]; 5595f408df58SRichard Henderson TCGLabel *label = arg_label(new_args[5]); 5596f408df58SRichard Henderson 5597f408df58SRichard Henderson tcg_debug_assert(!const_args[0]); 5598f408df58SRichard Henderson tcg_debug_assert(!const_args[1]); 5599f408df58SRichard Henderson out->out(s, cond, new_args[0], new_args[1], 5600f408df58SRichard Henderson new_args[2], const_args[2], 5601f408df58SRichard Henderson new_args[3], const_args[3], label); 5602f408df58SRichard Henderson } 5603f408df58SRichard Henderson break; 5604e579c717SRichard Henderson case INDEX_op_setcond2_i32: 5605e579c717SRichard Henderson { 5606e579c717SRichard Henderson const TCGOutOpSetcond2 *out = &outop_setcond2; 5607e579c717SRichard Henderson TCGCond cond = new_args[5]; 5608e579c717SRichard Henderson 5609e579c717SRichard Henderson tcg_debug_assert(!const_args[1]); 5610e579c717SRichard Henderson tcg_debug_assert(!const_args[2]); 5611e579c717SRichard Henderson out->out(s, cond, new_args[0], new_args[1], new_args[2], 5612e579c717SRichard Henderson new_args[3], const_args[3], new_args[4], const_args[4]); 5613e579c717SRichard Henderson } 5614e579c717SRichard Henderson break; 5615f408df58SRichard Henderson #else 5616f408df58SRichard Henderson case INDEX_op_brcond2_i32: 5617e579c717SRichard Henderson case INDEX_op_setcond2_i32: 5618f408df58SRichard Henderson g_assert_not_reached(); 5619f408df58SRichard Henderson #endif 5620f408df58SRichard Henderson 5621678155b2SRichard Henderson default: 5622d2fd745fSRichard Henderson if (def->flags & TCG_OPF_VECTOR) { 5623662cdbcfSRichard Henderson tcg_out_vec_op(s, op->opc, type - TCG_TYPE_V64, 56244d872218SRichard Henderson TCGOP_VECE(op), new_args, const_args); 5625d2fd745fSRichard Henderson } else { 5626662cdbcfSRichard Henderson tcg_out_op(s, op->opc, type, new_args, const_args); 5627d2fd745fSRichard Henderson } 5628678155b2SRichard Henderson break; 5629678155b2SRichard Henderson } 5630c896fe29Sbellard 5631c896fe29Sbellard /* move the outputs in the correct register if needed */ 5632c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 563343439139SRichard Henderson ts = arg_temp(op->args[i]); 5634d63e3b6eSRichard Henderson 5635d63e3b6eSRichard Henderson /* ENV should not be modified. */ 5636e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ts)); 5637d63e3b6eSRichard Henderson 5638ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) { 563998b4e186SRichard Henderson temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i)); 564059d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) { 5641f8bf00f1SRichard Henderson temp_dead(s, ts); 5642ec7a869dSAurelien Jarno } 5643c896fe29Sbellard } 5644c896fe29Sbellard } 5645c896fe29Sbellard 5646efe86b21SRichard Henderson static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op) 5647efe86b21SRichard Henderson { 5648efe86b21SRichard Henderson const TCGLifeData arg_life = op->life; 5649efe86b21SRichard Henderson TCGTemp *ots, *itsl, *itsh; 56504d872218SRichard Henderson TCGType vtype = TCGOP_TYPE(op); 5651efe86b21SRichard Henderson 5652efe86b21SRichard Henderson /* This opcode is only valid for 32-bit hosts, for 64-bit elements. */ 5653efe86b21SRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 32); 5654efe86b21SRichard Henderson tcg_debug_assert(TCGOP_VECE(op) == MO_64); 5655efe86b21SRichard Henderson 5656efe86b21SRichard Henderson ots = arg_temp(op->args[0]); 5657efe86b21SRichard Henderson itsl = arg_temp(op->args[1]); 5658efe86b21SRichard Henderson itsh = arg_temp(op->args[2]); 5659efe86b21SRichard Henderson 5660efe86b21SRichard Henderson /* ENV should not be modified. */ 5661efe86b21SRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 5662efe86b21SRichard Henderson 5663efe86b21SRichard Henderson /* Allocate the output register now. */ 5664efe86b21SRichard Henderson if (ots->val_type != TEMP_VAL_REG) { 5665efe86b21SRichard Henderson TCGRegSet allocated_regs = s->reserved_regs; 5666501fb3daSRichard Henderson TCGRegSet dup_out_regs = opcode_args_ct(op)[0].regs; 5667098859f1SRichard Henderson TCGReg oreg; 5668efe86b21SRichard Henderson 5669efe86b21SRichard Henderson /* Make sure to not spill the input registers. */ 5670efe86b21SRichard Henderson if (!IS_DEAD_ARG(1) && itsl->val_type == TEMP_VAL_REG) { 5671efe86b21SRichard Henderson tcg_regset_set_reg(allocated_regs, itsl->reg); 5672efe86b21SRichard Henderson } 5673efe86b21SRichard Henderson if (!IS_DEAD_ARG(2) && itsh->val_type == TEMP_VAL_REG) { 5674efe86b21SRichard Henderson tcg_regset_set_reg(allocated_regs, itsh->reg); 5675efe86b21SRichard Henderson } 5676efe86b21SRichard Henderson 5677098859f1SRichard Henderson oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs, 567831fd884bSRichard Henderson output_pref(op, 0), ots->indirect_base); 5679098859f1SRichard Henderson set_temp_val_reg(s, ots, oreg); 5680efe86b21SRichard Henderson } 5681efe86b21SRichard Henderson 5682efe86b21SRichard Henderson /* Promote dup2 of immediates to dupi_vec. */ 5683efe86b21SRichard Henderson if (itsl->val_type == TEMP_VAL_CONST && itsh->val_type == TEMP_VAL_CONST) { 5684efe86b21SRichard Henderson uint64_t val = deposit64(itsl->val, 32, 32, itsh->val); 5685efe86b21SRichard Henderson MemOp vece = MO_64; 5686efe86b21SRichard Henderson 5687efe86b21SRichard Henderson if (val == dup_const(MO_8, val)) { 5688efe86b21SRichard Henderson vece = MO_8; 5689efe86b21SRichard Henderson } else if (val == dup_const(MO_16, val)) { 5690efe86b21SRichard Henderson vece = MO_16; 5691efe86b21SRichard Henderson } else if (val == dup_const(MO_32, val)) { 5692efe86b21SRichard Henderson vece = MO_32; 5693efe86b21SRichard Henderson } 5694efe86b21SRichard Henderson 5695efe86b21SRichard Henderson tcg_out_dupi_vec(s, vtype, vece, ots->reg, val); 5696efe86b21SRichard Henderson goto done; 5697efe86b21SRichard Henderson } 5698efe86b21SRichard Henderson 5699efe86b21SRichard Henderson /* If the two inputs form one 64-bit value, try dupm_vec. */ 5700aef85402SRichard Henderson if (itsl->temp_subindex == HOST_BIG_ENDIAN && 5701aef85402SRichard Henderson itsh->temp_subindex == !HOST_BIG_ENDIAN && 5702aef85402SRichard Henderson itsl == itsh + (HOST_BIG_ENDIAN ? 1 : -1)) { 5703aef85402SRichard Henderson TCGTemp *its = itsl - HOST_BIG_ENDIAN; 5704aef85402SRichard Henderson 5705aef85402SRichard Henderson temp_sync(s, its + 0, s->reserved_regs, 0, 0); 5706aef85402SRichard Henderson temp_sync(s, its + 1, s->reserved_regs, 0, 0); 5707aef85402SRichard Henderson 5708efe86b21SRichard Henderson if (tcg_out_dupm_vec(s, vtype, MO_64, ots->reg, 5709efe86b21SRichard Henderson its->mem_base->reg, its->mem_offset)) { 5710efe86b21SRichard Henderson goto done; 5711efe86b21SRichard Henderson } 5712efe86b21SRichard Henderson } 5713efe86b21SRichard Henderson 5714efe86b21SRichard Henderson /* Fall back to generic expansion. */ 5715efe86b21SRichard Henderson return false; 5716efe86b21SRichard Henderson 5717efe86b21SRichard Henderson done: 571836f5539cSRichard Henderson ots->mem_coherent = 0; 5719efe86b21SRichard Henderson if (IS_DEAD_ARG(1)) { 5720efe86b21SRichard Henderson temp_dead(s, itsl); 5721efe86b21SRichard Henderson } 5722efe86b21SRichard Henderson if (IS_DEAD_ARG(2)) { 5723efe86b21SRichard Henderson temp_dead(s, itsh); 5724efe86b21SRichard Henderson } 5725efe86b21SRichard Henderson if (NEED_SYNC_ARG(0)) { 5726efe86b21SRichard Henderson temp_sync(s, ots, s->reserved_regs, 0, IS_DEAD_ARG(0)); 5727efe86b21SRichard Henderson } else if (IS_DEAD_ARG(0)) { 5728efe86b21SRichard Henderson temp_dead(s, ots); 5729efe86b21SRichard Henderson } 5730efe86b21SRichard Henderson return true; 5731efe86b21SRichard Henderson } 5732efe86b21SRichard Henderson 573339004a71SRichard Henderson static void load_arg_reg(TCGContext *s, TCGReg reg, TCGTemp *ts, 573439004a71SRichard Henderson TCGRegSet allocated_regs) 5735c896fe29Sbellard { 5736c896fe29Sbellard if (ts->val_type == TEMP_VAL_REG) { 5737c896fe29Sbellard if (ts->reg != reg) { 57384250da10SRichard Henderson tcg_reg_free(s, reg, allocated_regs); 573978113e83SRichard Henderson if (!tcg_out_mov(s, ts->type, reg, ts->reg)) { 5740240c08d0SRichard Henderson /* 5741240c08d0SRichard Henderson * Cross register class move not supported. Sync the 5742240c08d0SRichard Henderson * temp back to its slot and load from there. 5743240c08d0SRichard Henderson */ 5744240c08d0SRichard Henderson temp_sync(s, ts, allocated_regs, 0, 0); 5745240c08d0SRichard Henderson tcg_out_ld(s, ts->type, reg, 5746240c08d0SRichard Henderson ts->mem_base->reg, ts->mem_offset); 574778113e83SRichard Henderson } 5748c896fe29Sbellard } 5749c896fe29Sbellard } else { 5750ccb1bb66SRichard Henderson TCGRegSet arg_set = 0; 575140ae5c62SRichard Henderson 57524250da10SRichard Henderson tcg_reg_free(s, reg, allocated_regs); 575340ae5c62SRichard Henderson tcg_regset_set_reg(arg_set, reg); 5754b722452aSRichard Henderson temp_load(s, ts, arg_set, allocated_regs, 0); 5755c896fe29Sbellard } 575639004a71SRichard Henderson } 575740ae5c62SRichard Henderson 5758d78e4a4fSRichard Henderson static void load_arg_stk(TCGContext *s, unsigned arg_slot, TCGTemp *ts, 575939004a71SRichard Henderson TCGRegSet allocated_regs) 576039004a71SRichard Henderson { 576139004a71SRichard Henderson /* 576239004a71SRichard Henderson * When the destination is on the stack, load up the temp and store. 576339004a71SRichard Henderson * If there are many call-saved registers, the temp might live to 576439004a71SRichard Henderson * see another use; otherwise it'll be discarded. 576539004a71SRichard Henderson */ 576639004a71SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], allocated_regs, 0); 576739004a71SRichard Henderson tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, 5768d78e4a4fSRichard Henderson arg_slot_stk_ofs(arg_slot)); 576939004a71SRichard Henderson } 577039004a71SRichard Henderson 577139004a71SRichard Henderson static void load_arg_normal(TCGContext *s, const TCGCallArgumentLoc *l, 577239004a71SRichard Henderson TCGTemp *ts, TCGRegSet *allocated_regs) 577339004a71SRichard Henderson { 5774338b61e9SRichard Henderson if (arg_slot_reg_p(l->arg_slot)) { 577539004a71SRichard Henderson TCGReg reg = tcg_target_call_iarg_regs[l->arg_slot]; 577639004a71SRichard Henderson load_arg_reg(s, reg, ts, *allocated_regs); 577739004a71SRichard Henderson tcg_regset_set_reg(*allocated_regs, reg); 577839004a71SRichard Henderson } else { 5779d78e4a4fSRichard Henderson load_arg_stk(s, l->arg_slot, ts, *allocated_regs); 5780c896fe29Sbellard } 578139cf05d3Sbellard } 5782c896fe29Sbellard 5783d78e4a4fSRichard Henderson static void load_arg_ref(TCGContext *s, unsigned arg_slot, TCGReg ref_base, 5784313bdea8SRichard Henderson intptr_t ref_off, TCGRegSet *allocated_regs) 5785313bdea8SRichard Henderson { 5786313bdea8SRichard Henderson TCGReg reg; 5787313bdea8SRichard Henderson 5788d78e4a4fSRichard Henderson if (arg_slot_reg_p(arg_slot)) { 5789313bdea8SRichard Henderson reg = tcg_target_call_iarg_regs[arg_slot]; 5790313bdea8SRichard Henderson tcg_reg_free(s, reg, *allocated_regs); 5791313bdea8SRichard Henderson tcg_out_addi_ptr(s, reg, ref_base, ref_off); 5792313bdea8SRichard Henderson tcg_regset_set_reg(*allocated_regs, reg); 5793313bdea8SRichard Henderson } else { 5794313bdea8SRichard Henderson reg = tcg_reg_alloc(s, tcg_target_available_regs[TCG_TYPE_PTR], 5795313bdea8SRichard Henderson *allocated_regs, 0, false); 5796313bdea8SRichard Henderson tcg_out_addi_ptr(s, reg, ref_base, ref_off); 5797313bdea8SRichard Henderson tcg_out_st(s, TCG_TYPE_PTR, reg, TCG_REG_CALL_STACK, 5798d78e4a4fSRichard Henderson arg_slot_stk_ofs(arg_slot)); 5799313bdea8SRichard Henderson } 5800313bdea8SRichard Henderson } 5801313bdea8SRichard Henderson 580239004a71SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op) 580339004a71SRichard Henderson { 580439004a71SRichard Henderson const int nb_oargs = TCGOP_CALLO(op); 580539004a71SRichard Henderson const int nb_iargs = TCGOP_CALLI(op); 580639004a71SRichard Henderson const TCGLifeData arg_life = op->life; 580739004a71SRichard Henderson const TCGHelperInfo *info = tcg_call_info(op); 580839004a71SRichard Henderson TCGRegSet allocated_regs = s->reserved_regs; 580939004a71SRichard Henderson int i; 581039004a71SRichard Henderson 581139004a71SRichard Henderson /* 581239004a71SRichard Henderson * Move inputs into place in reverse order, 581339004a71SRichard Henderson * so that we place stacked arguments first. 581439004a71SRichard Henderson */ 581539004a71SRichard Henderson for (i = nb_iargs - 1; i >= 0; --i) { 581639004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i]; 581739004a71SRichard Henderson TCGTemp *ts = arg_temp(op->args[nb_oargs + i]); 581839004a71SRichard Henderson 581939004a71SRichard Henderson switch (loc->kind) { 582039004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 582139004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 582239004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 582339004a71SRichard Henderson load_arg_normal(s, loc, ts, &allocated_regs); 582439004a71SRichard Henderson break; 5825313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF: 5826313bdea8SRichard Henderson load_arg_stk(s, loc->ref_slot, ts, allocated_regs); 5827313bdea8SRichard Henderson load_arg_ref(s, loc->arg_slot, TCG_REG_CALL_STACK, 5828d78e4a4fSRichard Henderson arg_slot_stk_ofs(loc->ref_slot), 5829313bdea8SRichard Henderson &allocated_regs); 5830313bdea8SRichard Henderson break; 5831313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF_N: 5832313bdea8SRichard Henderson load_arg_stk(s, loc->ref_slot, ts, allocated_regs); 5833313bdea8SRichard Henderson break; 583439004a71SRichard Henderson default: 583539004a71SRichard Henderson g_assert_not_reached(); 583639004a71SRichard Henderson } 583739004a71SRichard Henderson } 583839004a71SRichard Henderson 583939004a71SRichard Henderson /* Mark dead temporaries and free the associated registers. */ 5840866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 5841866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) { 584243439139SRichard Henderson temp_dead(s, arg_temp(op->args[i])); 5843c896fe29Sbellard } 5844c896fe29Sbellard } 5845c896fe29Sbellard 584639004a71SRichard Henderson /* Clobber call registers. */ 5847c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) { 5848c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { 5849b3915dbbSRichard Henderson tcg_reg_free(s, i, allocated_regs); 5850c896fe29Sbellard } 5851c896fe29Sbellard } 5852c896fe29Sbellard 585339004a71SRichard Henderson /* 585439004a71SRichard Henderson * Save globals if they might be written by the helper, 585539004a71SRichard Henderson * sync them if they might be read. 585639004a71SRichard Henderson */ 585739004a71SRichard Henderson if (info->flags & TCG_CALL_NO_READ_GLOBALS) { 585878505279SAurelien Jarno /* Nothing to do */ 585939004a71SRichard Henderson } else if (info->flags & TCG_CALL_NO_WRITE_GLOBALS) { 586078505279SAurelien Jarno sync_globals(s, allocated_regs); 586178505279SAurelien Jarno } else { 5862e8996ee0Sbellard save_globals(s, allocated_regs); 5863b9c18f56Saurel32 } 5864c896fe29Sbellard 5865313bdea8SRichard Henderson /* 5866313bdea8SRichard Henderson * If the ABI passes a pointer to the returned struct as the first 5867313bdea8SRichard Henderson * argument, load that now. Pass a pointer to the output home slot. 5868313bdea8SRichard Henderson */ 5869313bdea8SRichard Henderson if (info->out_kind == TCG_CALL_RET_BY_REF) { 5870313bdea8SRichard Henderson TCGTemp *ts = arg_temp(op->args[0]); 5871313bdea8SRichard Henderson 5872313bdea8SRichard Henderson if (!ts->mem_allocated) { 5873313bdea8SRichard Henderson temp_allocate_frame(s, ts); 5874313bdea8SRichard Henderson } 5875313bdea8SRichard Henderson load_arg_ref(s, 0, ts->mem_base->reg, ts->mem_offset, &allocated_regs); 5876313bdea8SRichard Henderson } 5877313bdea8SRichard Henderson 5878cee44b03SRichard Henderson tcg_out_call(s, tcg_call_func(op), info); 5879c896fe29Sbellard 588039004a71SRichard Henderson /* Assign output registers and emit moves if needed. */ 588139004a71SRichard Henderson switch (info->out_kind) { 588239004a71SRichard Henderson case TCG_CALL_RET_NORMAL: 5883c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 588439004a71SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]); 58855e3d0c19SRichard Henderson TCGReg reg = tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, i); 5886d63e3b6eSRichard Henderson 5887d63e3b6eSRichard Henderson /* ENV should not be modified. */ 5888e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ts)); 5889d63e3b6eSRichard Henderson 5890098859f1SRichard Henderson set_temp_val_reg(s, ts, reg); 5891c896fe29Sbellard ts->mem_coherent = 0; 589239004a71SRichard Henderson } 589339004a71SRichard Henderson break; 5894313bdea8SRichard Henderson 5895c6556aa0SRichard Henderson case TCG_CALL_RET_BY_VEC: 5896c6556aa0SRichard Henderson { 5897c6556aa0SRichard Henderson TCGTemp *ts = arg_temp(op->args[0]); 5898c6556aa0SRichard Henderson 5899c6556aa0SRichard Henderson tcg_debug_assert(ts->base_type == TCG_TYPE_I128); 5900c6556aa0SRichard Henderson tcg_debug_assert(ts->temp_subindex == 0); 5901c6556aa0SRichard Henderson if (!ts->mem_allocated) { 5902c6556aa0SRichard Henderson temp_allocate_frame(s, ts); 5903c6556aa0SRichard Henderson } 5904c6556aa0SRichard Henderson tcg_out_st(s, TCG_TYPE_V128, 5905c6556aa0SRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0), 5906c6556aa0SRichard Henderson ts->mem_base->reg, ts->mem_offset); 5907c6556aa0SRichard Henderson } 5908c6556aa0SRichard Henderson /* fall through to mark all parts in memory */ 5909c6556aa0SRichard Henderson 5910313bdea8SRichard Henderson case TCG_CALL_RET_BY_REF: 5911313bdea8SRichard Henderson /* The callee has performed a write through the reference. */ 5912313bdea8SRichard Henderson for (i = 0; i < nb_oargs; i++) { 5913313bdea8SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]); 5914313bdea8SRichard Henderson ts->val_type = TEMP_VAL_MEM; 5915313bdea8SRichard Henderson } 5916313bdea8SRichard Henderson break; 5917313bdea8SRichard Henderson 591839004a71SRichard Henderson default: 591939004a71SRichard Henderson g_assert_not_reached(); 592039004a71SRichard Henderson } 592139004a71SRichard Henderson 592239004a71SRichard Henderson /* Flush or discard output registers as needed. */ 592339004a71SRichard Henderson for (i = 0; i < nb_oargs; i++) { 592439004a71SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]); 5925ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) { 592639004a71SRichard Henderson temp_sync(s, ts, s->reserved_regs, 0, IS_DEAD_ARG(i)); 592759d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) { 5928f8bf00f1SRichard Henderson temp_dead(s, ts); 5929c896fe29Sbellard } 5930c896fe29Sbellard } 59318c11ad25SAurelien Jarno } 5932c896fe29Sbellard 5933e63b8a29SRichard Henderson /** 5934e63b8a29SRichard Henderson * atom_and_align_for_opc: 5935e63b8a29SRichard Henderson * @s: tcg context 5936e63b8a29SRichard Henderson * @opc: memory operation code 5937e63b8a29SRichard Henderson * @host_atom: MO_ATOM_{IFALIGN,WITHIN16,SUBALIGN} for host operations 5938e63b8a29SRichard Henderson * @allow_two_ops: true if we are prepared to issue two operations 5939e63b8a29SRichard Henderson * 5940e63b8a29SRichard Henderson * Return the alignment and atomicity to use for the inline fast path 5941e63b8a29SRichard Henderson * for the given memory operation. The alignment may be larger than 5942e63b8a29SRichard Henderson * that specified in @opc, and the correct alignment will be diagnosed 5943e63b8a29SRichard Henderson * by the slow path helper. 5944e63b8a29SRichard Henderson * 5945e63b8a29SRichard Henderson * If @allow_two_ops, the host is prepared to test for 2x alignment, 5946e63b8a29SRichard Henderson * and issue two loads or stores for subalignment. 5947e63b8a29SRichard Henderson */ 5948e63b8a29SRichard Henderson static TCGAtomAlign atom_and_align_for_opc(TCGContext *s, MemOp opc, 5949e63b8a29SRichard Henderson MemOp host_atom, bool allow_two_ops) 5950e63b8a29SRichard Henderson { 5951c5809eeeSRichard Henderson MemOp align = memop_alignment_bits(opc); 5952e63b8a29SRichard Henderson MemOp size = opc & MO_SIZE; 5953e63b8a29SRichard Henderson MemOp half = size ? size - 1 : 0; 5954cbb14556SRichard Henderson MemOp atom = opc & MO_ATOM_MASK; 5955e63b8a29SRichard Henderson MemOp atmax; 5956e63b8a29SRichard Henderson 5957e63b8a29SRichard Henderson switch (atom) { 5958e63b8a29SRichard Henderson case MO_ATOM_NONE: 5959e63b8a29SRichard Henderson /* The operation requires no specific atomicity. */ 5960e63b8a29SRichard Henderson atmax = MO_8; 5961e63b8a29SRichard Henderson break; 5962e63b8a29SRichard Henderson 5963e63b8a29SRichard Henderson case MO_ATOM_IFALIGN: 5964e63b8a29SRichard Henderson atmax = size; 5965e63b8a29SRichard Henderson break; 5966e63b8a29SRichard Henderson 5967e63b8a29SRichard Henderson case MO_ATOM_IFALIGN_PAIR: 5968e63b8a29SRichard Henderson atmax = half; 5969e63b8a29SRichard Henderson break; 5970e63b8a29SRichard Henderson 5971e63b8a29SRichard Henderson case MO_ATOM_WITHIN16: 5972e63b8a29SRichard Henderson atmax = size; 5973e63b8a29SRichard Henderson if (size == MO_128) { 5974e63b8a29SRichard Henderson /* Misalignment implies !within16, and therefore no atomicity. */ 5975e63b8a29SRichard Henderson } else if (host_atom != MO_ATOM_WITHIN16) { 5976e63b8a29SRichard Henderson /* The host does not implement within16, so require alignment. */ 5977e63b8a29SRichard Henderson align = MAX(align, size); 5978e63b8a29SRichard Henderson } 5979e63b8a29SRichard Henderson break; 5980e63b8a29SRichard Henderson 5981e63b8a29SRichard Henderson case MO_ATOM_WITHIN16_PAIR: 5982e63b8a29SRichard Henderson atmax = size; 5983e63b8a29SRichard Henderson /* 5984e63b8a29SRichard Henderson * Misalignment implies !within16, and therefore half atomicity. 5985e63b8a29SRichard Henderson * Any host prepared for two operations can implement this with 5986e63b8a29SRichard Henderson * half alignment. 5987e63b8a29SRichard Henderson */ 5988e63b8a29SRichard Henderson if (host_atom != MO_ATOM_WITHIN16 && allow_two_ops) { 5989e63b8a29SRichard Henderson align = MAX(align, half); 5990e63b8a29SRichard Henderson } 5991e63b8a29SRichard Henderson break; 5992e63b8a29SRichard Henderson 5993e63b8a29SRichard Henderson case MO_ATOM_SUBALIGN: 5994e63b8a29SRichard Henderson atmax = size; 5995e63b8a29SRichard Henderson if (host_atom != MO_ATOM_SUBALIGN) { 5996e63b8a29SRichard Henderson /* If unaligned but not odd, there are subobjects up to half. */ 5997e63b8a29SRichard Henderson if (allow_two_ops) { 5998e63b8a29SRichard Henderson align = MAX(align, half); 5999e63b8a29SRichard Henderson } else { 6000e63b8a29SRichard Henderson align = MAX(align, size); 6001e63b8a29SRichard Henderson } 6002e63b8a29SRichard Henderson } 6003e63b8a29SRichard Henderson break; 6004e63b8a29SRichard Henderson 6005e63b8a29SRichard Henderson default: 6006e63b8a29SRichard Henderson g_assert_not_reached(); 6007e63b8a29SRichard Henderson } 6008e63b8a29SRichard Henderson 6009e63b8a29SRichard Henderson return (TCGAtomAlign){ .atom = atmax, .align = align }; 6010e63b8a29SRichard Henderson } 6011e63b8a29SRichard Henderson 60128429a1caSRichard Henderson /* 60138429a1caSRichard Henderson * Similarly for qemu_ld/st slow path helpers. 60148429a1caSRichard Henderson * We must re-implement tcg_gen_callN and tcg_reg_alloc_call simultaneously, 60158429a1caSRichard Henderson * using only the provided backend tcg_out_* functions. 60168429a1caSRichard Henderson */ 60178429a1caSRichard Henderson 60188429a1caSRichard Henderson static int tcg_out_helper_stk_ofs(TCGType type, unsigned slot) 60198429a1caSRichard Henderson { 60208429a1caSRichard Henderson int ofs = arg_slot_stk_ofs(slot); 60218429a1caSRichard Henderson 60228429a1caSRichard Henderson /* 60238429a1caSRichard Henderson * Each stack slot is TCG_TARGET_LONG_BITS. If the host does not 60248429a1caSRichard Henderson * require extension to uint64_t, adjust the address for uint32_t. 60258429a1caSRichard Henderson */ 60268429a1caSRichard Henderson if (HOST_BIG_ENDIAN && 60278429a1caSRichard Henderson TCG_TARGET_REG_BITS == 64 && 60288429a1caSRichard Henderson type == TCG_TYPE_I32) { 60298429a1caSRichard Henderson ofs += 4; 60308429a1caSRichard Henderson } 60318429a1caSRichard Henderson return ofs; 60328429a1caSRichard Henderson } 60338429a1caSRichard Henderson 60348d314041SRichard Henderson static void tcg_out_helper_load_slots(TCGContext *s, 60358429a1caSRichard Henderson unsigned nmov, TCGMovExtend *mov, 60362462e30eSRichard Henderson const TCGLdstHelperParam *parm) 60378429a1caSRichard Henderson { 60388d314041SRichard Henderson unsigned i; 60392462e30eSRichard Henderson TCGReg dst3; 60402462e30eSRichard Henderson 60418d314041SRichard Henderson /* 60428d314041SRichard Henderson * Start from the end, storing to the stack first. 60438d314041SRichard Henderson * This frees those registers, so we need not consider overlap. 60448d314041SRichard Henderson */ 60458d314041SRichard Henderson for (i = nmov; i-- > 0; ) { 60468d314041SRichard Henderson unsigned slot = mov[i].dst; 60478d314041SRichard Henderson 60488d314041SRichard Henderson if (arg_slot_reg_p(slot)) { 60498d314041SRichard Henderson goto found_reg; 60508d314041SRichard Henderson } 60518d314041SRichard Henderson 60528d314041SRichard Henderson TCGReg src = mov[i].src; 60538d314041SRichard Henderson TCGType dst_type = mov[i].dst_type; 60548d314041SRichard Henderson MemOp dst_mo = dst_type == TCG_TYPE_I32 ? MO_32 : MO_64; 60558d314041SRichard Henderson 60568d314041SRichard Henderson /* The argument is going onto the stack; extend into scratch. */ 60578d314041SRichard Henderson if ((mov[i].src_ext & MO_SIZE) != dst_mo) { 60588d314041SRichard Henderson tcg_debug_assert(parm->ntmp != 0); 60598d314041SRichard Henderson mov[i].dst = src = parm->tmp[0]; 60608d314041SRichard Henderson tcg_out_movext1(s, &mov[i]); 60618d314041SRichard Henderson } 60628d314041SRichard Henderson 60638d314041SRichard Henderson tcg_out_st(s, dst_type, src, TCG_REG_CALL_STACK, 60648d314041SRichard Henderson tcg_out_helper_stk_ofs(dst_type, slot)); 60658d314041SRichard Henderson } 60668d314041SRichard Henderson return; 60678d314041SRichard Henderson 60688d314041SRichard Henderson found_reg: 60698d314041SRichard Henderson /* 60708d314041SRichard Henderson * The remaining arguments are in registers. 60718d314041SRichard Henderson * Convert slot numbers to argument registers. 60728d314041SRichard Henderson */ 60738d314041SRichard Henderson nmov = i + 1; 60748d314041SRichard Henderson for (i = 0; i < nmov; ++i) { 60758d314041SRichard Henderson mov[i].dst = tcg_target_call_iarg_regs[mov[i].dst]; 60768d314041SRichard Henderson } 60778d314041SRichard Henderson 60788429a1caSRichard Henderson switch (nmov) { 60792462e30eSRichard Henderson case 4: 60808429a1caSRichard Henderson /* The backend must have provided enough temps for the worst case. */ 60812462e30eSRichard Henderson tcg_debug_assert(parm->ntmp >= 2); 60828429a1caSRichard Henderson 60832462e30eSRichard Henderson dst3 = mov[3].dst; 60842462e30eSRichard Henderson for (unsigned j = 0; j < 3; ++j) { 60852462e30eSRichard Henderson if (dst3 == mov[j].src) { 60868429a1caSRichard Henderson /* 60872462e30eSRichard Henderson * Conflict. Copy the source to a temporary, perform the 60882462e30eSRichard Henderson * remaining moves, then the extension from our scratch 60892462e30eSRichard Henderson * on the way out. 60908429a1caSRichard Henderson */ 60912462e30eSRichard Henderson TCGReg scratch = parm->tmp[1]; 60928429a1caSRichard Henderson 60932462e30eSRichard Henderson tcg_out_mov(s, mov[3].src_type, scratch, mov[3].src); 60942462e30eSRichard Henderson tcg_out_movext3(s, mov, mov + 1, mov + 2, parm->tmp[0]); 60952462e30eSRichard Henderson tcg_out_movext1_new_src(s, &mov[3], scratch); 60962462e30eSRichard Henderson break; 60978429a1caSRichard Henderson } 60988429a1caSRichard Henderson } 60998429a1caSRichard Henderson 61008429a1caSRichard Henderson /* No conflicts: perform this move and continue. */ 61012462e30eSRichard Henderson tcg_out_movext1(s, &mov[3]); 61022462e30eSRichard Henderson /* fall through */ 61038429a1caSRichard Henderson 61042462e30eSRichard Henderson case 3: 61052462e30eSRichard Henderson tcg_out_movext3(s, mov, mov + 1, mov + 2, 61062462e30eSRichard Henderson parm->ntmp ? parm->tmp[0] : -1); 61072462e30eSRichard Henderson break; 61088429a1caSRichard Henderson case 2: 61092462e30eSRichard Henderson tcg_out_movext2(s, mov, mov + 1, 61102462e30eSRichard Henderson parm->ntmp ? parm->tmp[0] : -1); 61112462e30eSRichard Henderson break; 61128429a1caSRichard Henderson case 1: 61138429a1caSRichard Henderson tcg_out_movext1(s, mov); 61142462e30eSRichard Henderson break; 61152462e30eSRichard Henderson default: 61168429a1caSRichard Henderson g_assert_not_reached(); 61178429a1caSRichard Henderson } 61188429a1caSRichard Henderson } 61198429a1caSRichard Henderson 61208429a1caSRichard Henderson static void tcg_out_helper_load_imm(TCGContext *s, unsigned slot, 61218429a1caSRichard Henderson TCGType type, tcg_target_long imm, 61228429a1caSRichard Henderson const TCGLdstHelperParam *parm) 61238429a1caSRichard Henderson { 61248429a1caSRichard Henderson if (arg_slot_reg_p(slot)) { 61258429a1caSRichard Henderson tcg_out_movi(s, type, tcg_target_call_iarg_regs[slot], imm); 61268429a1caSRichard Henderson } else { 61278429a1caSRichard Henderson int ofs = tcg_out_helper_stk_ofs(type, slot); 61288429a1caSRichard Henderson if (!tcg_out_sti(s, type, imm, TCG_REG_CALL_STACK, ofs)) { 61298429a1caSRichard Henderson tcg_debug_assert(parm->ntmp != 0); 61308429a1caSRichard Henderson tcg_out_movi(s, type, parm->tmp[0], imm); 61318429a1caSRichard Henderson tcg_out_st(s, type, parm->tmp[0], TCG_REG_CALL_STACK, ofs); 61328429a1caSRichard Henderson } 61338429a1caSRichard Henderson } 61348429a1caSRichard Henderson } 61358429a1caSRichard Henderson 61368429a1caSRichard Henderson static void tcg_out_helper_load_common_args(TCGContext *s, 61378429a1caSRichard Henderson const TCGLabelQemuLdst *ldst, 61388429a1caSRichard Henderson const TCGLdstHelperParam *parm, 61398429a1caSRichard Henderson const TCGHelperInfo *info, 61408429a1caSRichard Henderson unsigned next_arg) 61418429a1caSRichard Henderson { 61428429a1caSRichard Henderson TCGMovExtend ptr_mov = { 61438429a1caSRichard Henderson .dst_type = TCG_TYPE_PTR, 61448429a1caSRichard Henderson .src_type = TCG_TYPE_PTR, 61458429a1caSRichard Henderson .src_ext = sizeof(void *) == 4 ? MO_32 : MO_64 61468429a1caSRichard Henderson }; 61478429a1caSRichard Henderson const TCGCallArgumentLoc *loc = &info->in[0]; 61488429a1caSRichard Henderson TCGType type; 61498429a1caSRichard Henderson unsigned slot; 61508429a1caSRichard Henderson tcg_target_ulong imm; 61518429a1caSRichard Henderson 61528429a1caSRichard Henderson /* 61538429a1caSRichard Henderson * Handle env, which is always first. 61548429a1caSRichard Henderson */ 61558429a1caSRichard Henderson ptr_mov.dst = loc->arg_slot; 61568429a1caSRichard Henderson ptr_mov.src = TCG_AREG0; 61578429a1caSRichard Henderson tcg_out_helper_load_slots(s, 1, &ptr_mov, parm); 61588429a1caSRichard Henderson 61598429a1caSRichard Henderson /* 61608429a1caSRichard Henderson * Handle oi. 61618429a1caSRichard Henderson */ 61628429a1caSRichard Henderson imm = ldst->oi; 61638429a1caSRichard Henderson loc = &info->in[next_arg]; 61648429a1caSRichard Henderson type = TCG_TYPE_I32; 61658429a1caSRichard Henderson switch (loc->kind) { 61668429a1caSRichard Henderson case TCG_CALL_ARG_NORMAL: 61678429a1caSRichard Henderson break; 61688429a1caSRichard Henderson case TCG_CALL_ARG_EXTEND_U: 61698429a1caSRichard Henderson case TCG_CALL_ARG_EXTEND_S: 61708429a1caSRichard Henderson /* No extension required for MemOpIdx. */ 61718429a1caSRichard Henderson tcg_debug_assert(imm <= INT32_MAX); 61728429a1caSRichard Henderson type = TCG_TYPE_REG; 61738429a1caSRichard Henderson break; 61748429a1caSRichard Henderson default: 61758429a1caSRichard Henderson g_assert_not_reached(); 61768429a1caSRichard Henderson } 61778429a1caSRichard Henderson tcg_out_helper_load_imm(s, loc->arg_slot, type, imm, parm); 61788429a1caSRichard Henderson next_arg++; 61798429a1caSRichard Henderson 61808429a1caSRichard Henderson /* 61818429a1caSRichard Henderson * Handle ra. 61828429a1caSRichard Henderson */ 61838429a1caSRichard Henderson loc = &info->in[next_arg]; 61848429a1caSRichard Henderson slot = loc->arg_slot; 61858429a1caSRichard Henderson if (parm->ra_gen) { 61868429a1caSRichard Henderson int arg_reg = -1; 61878429a1caSRichard Henderson TCGReg ra_reg; 61888429a1caSRichard Henderson 61898429a1caSRichard Henderson if (arg_slot_reg_p(slot)) { 61908429a1caSRichard Henderson arg_reg = tcg_target_call_iarg_regs[slot]; 61918429a1caSRichard Henderson } 61928429a1caSRichard Henderson ra_reg = parm->ra_gen(s, ldst, arg_reg); 61938429a1caSRichard Henderson 61948429a1caSRichard Henderson ptr_mov.dst = slot; 61958429a1caSRichard Henderson ptr_mov.src = ra_reg; 61968429a1caSRichard Henderson tcg_out_helper_load_slots(s, 1, &ptr_mov, parm); 61978429a1caSRichard Henderson } else { 61988429a1caSRichard Henderson imm = (uintptr_t)ldst->raddr; 61998429a1caSRichard Henderson tcg_out_helper_load_imm(s, slot, TCG_TYPE_PTR, imm, parm); 62008429a1caSRichard Henderson } 62018429a1caSRichard Henderson } 62028429a1caSRichard Henderson 62038429a1caSRichard Henderson static unsigned tcg_out_helper_add_mov(TCGMovExtend *mov, 62048429a1caSRichard Henderson const TCGCallArgumentLoc *loc, 62058429a1caSRichard Henderson TCGType dst_type, TCGType src_type, 62068429a1caSRichard Henderson TCGReg lo, TCGReg hi) 62078429a1caSRichard Henderson { 6208ebebea53SRichard Henderson MemOp reg_mo; 6209ebebea53SRichard Henderson 62108429a1caSRichard Henderson if (dst_type <= TCG_TYPE_REG) { 62118429a1caSRichard Henderson MemOp src_ext; 62128429a1caSRichard Henderson 62138429a1caSRichard Henderson switch (loc->kind) { 62148429a1caSRichard Henderson case TCG_CALL_ARG_NORMAL: 62158429a1caSRichard Henderson src_ext = src_type == TCG_TYPE_I32 ? MO_32 : MO_64; 62168429a1caSRichard Henderson break; 62178429a1caSRichard Henderson case TCG_CALL_ARG_EXTEND_U: 62188429a1caSRichard Henderson dst_type = TCG_TYPE_REG; 62198429a1caSRichard Henderson src_ext = MO_UL; 62208429a1caSRichard Henderson break; 62218429a1caSRichard Henderson case TCG_CALL_ARG_EXTEND_S: 62228429a1caSRichard Henderson dst_type = TCG_TYPE_REG; 62238429a1caSRichard Henderson src_ext = MO_SL; 62248429a1caSRichard Henderson break; 62258429a1caSRichard Henderson default: 62268429a1caSRichard Henderson g_assert_not_reached(); 62278429a1caSRichard Henderson } 62288429a1caSRichard Henderson 62298429a1caSRichard Henderson mov[0].dst = loc->arg_slot; 62308429a1caSRichard Henderson mov[0].dst_type = dst_type; 62318429a1caSRichard Henderson mov[0].src = lo; 62328429a1caSRichard Henderson mov[0].src_type = src_type; 62338429a1caSRichard Henderson mov[0].src_ext = src_ext; 62348429a1caSRichard Henderson return 1; 62358429a1caSRichard Henderson } 62368429a1caSRichard Henderson 6237ebebea53SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 6238ebebea53SRichard Henderson assert(dst_type == TCG_TYPE_I64); 6239ebebea53SRichard Henderson reg_mo = MO_32; 6240ebebea53SRichard Henderson } else { 6241ebebea53SRichard Henderson assert(dst_type == TCG_TYPE_I128); 6242ebebea53SRichard Henderson reg_mo = MO_64; 6243ebebea53SRichard Henderson } 62448429a1caSRichard Henderson 62458429a1caSRichard Henderson mov[0].dst = loc[HOST_BIG_ENDIAN].arg_slot; 62468429a1caSRichard Henderson mov[0].src = lo; 6247ebebea53SRichard Henderson mov[0].dst_type = TCG_TYPE_REG; 6248ebebea53SRichard Henderson mov[0].src_type = TCG_TYPE_REG; 6249ebebea53SRichard Henderson mov[0].src_ext = reg_mo; 62508429a1caSRichard Henderson 62518429a1caSRichard Henderson mov[1].dst = loc[!HOST_BIG_ENDIAN].arg_slot; 62528429a1caSRichard Henderson mov[1].src = hi; 6253ebebea53SRichard Henderson mov[1].dst_type = TCG_TYPE_REG; 6254ebebea53SRichard Henderson mov[1].src_type = TCG_TYPE_REG; 6255ebebea53SRichard Henderson mov[1].src_ext = reg_mo; 62568429a1caSRichard Henderson 62578429a1caSRichard Henderson return 2; 62588429a1caSRichard Henderson } 62598429a1caSRichard Henderson 62608429a1caSRichard Henderson static void tcg_out_ld_helper_args(TCGContext *s, const TCGLabelQemuLdst *ldst, 62618429a1caSRichard Henderson const TCGLdstHelperParam *parm) 62628429a1caSRichard Henderson { 62638429a1caSRichard Henderson const TCGHelperInfo *info; 62648429a1caSRichard Henderson const TCGCallArgumentLoc *loc; 62658429a1caSRichard Henderson TCGMovExtend mov[2]; 62668429a1caSRichard Henderson unsigned next_arg, nmov; 62678429a1caSRichard Henderson MemOp mop = get_memop(ldst->oi); 62688429a1caSRichard Henderson 62698429a1caSRichard Henderson switch (mop & MO_SIZE) { 62708429a1caSRichard Henderson case MO_8: 62718429a1caSRichard Henderson case MO_16: 62728429a1caSRichard Henderson case MO_32: 62738429a1caSRichard Henderson info = &info_helper_ld32_mmu; 62748429a1caSRichard Henderson break; 62758429a1caSRichard Henderson case MO_64: 62768429a1caSRichard Henderson info = &info_helper_ld64_mmu; 62778429a1caSRichard Henderson break; 6278ebebea53SRichard Henderson case MO_128: 6279ebebea53SRichard Henderson info = &info_helper_ld128_mmu; 6280ebebea53SRichard Henderson break; 62818429a1caSRichard Henderson default: 62828429a1caSRichard Henderson g_assert_not_reached(); 62838429a1caSRichard Henderson } 62848429a1caSRichard Henderson 62858429a1caSRichard Henderson /* Defer env argument. */ 62868429a1caSRichard Henderson next_arg = 1; 62878429a1caSRichard Henderson 62888429a1caSRichard Henderson loc = &info->in[next_arg]; 6289c31e5fa4SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && s->addr_type == TCG_TYPE_I32) { 629024e46e6cSRichard Henderson /* 629124e46e6cSRichard Henderson * 32-bit host with 32-bit guest: zero-extend the guest address 629224e46e6cSRichard Henderson * to 64-bits for the helper by storing the low part, then 629324e46e6cSRichard Henderson * load a zero for the high part. 629424e46e6cSRichard Henderson */ 629524e46e6cSRichard Henderson tcg_out_helper_add_mov(mov, loc + HOST_BIG_ENDIAN, 629624e46e6cSRichard Henderson TCG_TYPE_I32, TCG_TYPE_I32, 62970cd38379SRichard Henderson ldst->addr_reg, -1); 629824e46e6cSRichard Henderson tcg_out_helper_load_slots(s, 1, mov, parm); 629924e46e6cSRichard Henderson 630024e46e6cSRichard Henderson tcg_out_helper_load_imm(s, loc[!HOST_BIG_ENDIAN].arg_slot, 630124e46e6cSRichard Henderson TCG_TYPE_I32, 0, parm); 630224e46e6cSRichard Henderson next_arg += 2; 6303c31e5fa4SRichard Henderson } else { 6304c31e5fa4SRichard Henderson nmov = tcg_out_helper_add_mov(mov, loc, TCG_TYPE_I64, s->addr_type, 63050cd38379SRichard Henderson ldst->addr_reg, -1); 6306c31e5fa4SRichard Henderson tcg_out_helper_load_slots(s, nmov, mov, parm); 6307c31e5fa4SRichard Henderson next_arg += nmov; 630824e46e6cSRichard Henderson } 63098429a1caSRichard Henderson 6310ebebea53SRichard Henderson switch (info->out_kind) { 6311ebebea53SRichard Henderson case TCG_CALL_RET_NORMAL: 6312ebebea53SRichard Henderson case TCG_CALL_RET_BY_VEC: 6313ebebea53SRichard Henderson break; 6314ebebea53SRichard Henderson case TCG_CALL_RET_BY_REF: 6315ebebea53SRichard Henderson /* 6316ebebea53SRichard Henderson * The return reference is in the first argument slot. 6317ebebea53SRichard Henderson * We need memory in which to return: re-use the top of stack. 6318ebebea53SRichard Henderson */ 6319ebebea53SRichard Henderson { 6320ebebea53SRichard Henderson int ofs_slot0 = TCG_TARGET_CALL_STACK_OFFSET; 6321ebebea53SRichard Henderson 6322ebebea53SRichard Henderson if (arg_slot_reg_p(0)) { 6323ebebea53SRichard Henderson tcg_out_addi_ptr(s, tcg_target_call_iarg_regs[0], 6324ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0); 6325ebebea53SRichard Henderson } else { 6326ebebea53SRichard Henderson tcg_debug_assert(parm->ntmp != 0); 6327ebebea53SRichard Henderson tcg_out_addi_ptr(s, parm->tmp[0], 6328ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0); 6329ebebea53SRichard Henderson tcg_out_st(s, TCG_TYPE_PTR, parm->tmp[0], 6330ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0); 6331ebebea53SRichard Henderson } 6332ebebea53SRichard Henderson } 6333ebebea53SRichard Henderson break; 6334ebebea53SRichard Henderson default: 6335ebebea53SRichard Henderson g_assert_not_reached(); 6336ebebea53SRichard Henderson } 63378429a1caSRichard Henderson 63388429a1caSRichard Henderson tcg_out_helper_load_common_args(s, ldst, parm, info, next_arg); 63398429a1caSRichard Henderson } 63408429a1caSRichard Henderson 63418429a1caSRichard Henderson static void tcg_out_ld_helper_ret(TCGContext *s, const TCGLabelQemuLdst *ldst, 63428429a1caSRichard Henderson bool load_sign, 63438429a1caSRichard Henderson const TCGLdstHelperParam *parm) 63448429a1caSRichard Henderson { 63458429a1caSRichard Henderson MemOp mop = get_memop(ldst->oi); 6346ebebea53SRichard Henderson TCGMovExtend mov[2]; 6347ebebea53SRichard Henderson int ofs_slot0; 63488429a1caSRichard Henderson 6349ebebea53SRichard Henderson switch (ldst->type) { 6350ebebea53SRichard Henderson case TCG_TYPE_I64: 6351ebebea53SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 6352ebebea53SRichard Henderson break; 6353ebebea53SRichard Henderson } 6354ebebea53SRichard Henderson /* fall through */ 6355ebebea53SRichard Henderson 6356ebebea53SRichard Henderson case TCG_TYPE_I32: 63578429a1caSRichard Henderson mov[0].dst = ldst->datalo_reg; 63588429a1caSRichard Henderson mov[0].src = tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, 0); 63598429a1caSRichard Henderson mov[0].dst_type = ldst->type; 63608429a1caSRichard Henderson mov[0].src_type = TCG_TYPE_REG; 63618429a1caSRichard Henderson 63628429a1caSRichard Henderson /* 63638429a1caSRichard Henderson * If load_sign, then we allowed the helper to perform the 63648429a1caSRichard Henderson * appropriate sign extension to tcg_target_ulong, and all 63658429a1caSRichard Henderson * we need now is a plain move. 63668429a1caSRichard Henderson * 63678429a1caSRichard Henderson * If they do not, then we expect the relevant extension 63688429a1caSRichard Henderson * instruction to be no more expensive than a move, and 63698429a1caSRichard Henderson * we thus save the icache etc by only using one of two 63708429a1caSRichard Henderson * helper functions. 63718429a1caSRichard Henderson */ 63728429a1caSRichard Henderson if (load_sign || !(mop & MO_SIGN)) { 63738429a1caSRichard Henderson if (TCG_TARGET_REG_BITS == 32 || ldst->type == TCG_TYPE_I32) { 63748429a1caSRichard Henderson mov[0].src_ext = MO_32; 63758429a1caSRichard Henderson } else { 63768429a1caSRichard Henderson mov[0].src_ext = MO_64; 63778429a1caSRichard Henderson } 63788429a1caSRichard Henderson } else { 63798429a1caSRichard Henderson mov[0].src_ext = mop & MO_SSIZE; 63808429a1caSRichard Henderson } 63818429a1caSRichard Henderson tcg_out_movext1(s, mov); 6382ebebea53SRichard Henderson return; 6383ebebea53SRichard Henderson 6384ebebea53SRichard Henderson case TCG_TYPE_I128: 6385ebebea53SRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 64); 6386ebebea53SRichard Henderson ofs_slot0 = TCG_TARGET_CALL_STACK_OFFSET; 6387ebebea53SRichard Henderson switch (TCG_TARGET_CALL_RET_I128) { 6388ebebea53SRichard Henderson case TCG_CALL_RET_NORMAL: 6389ebebea53SRichard Henderson break; 6390ebebea53SRichard Henderson case TCG_CALL_RET_BY_VEC: 6391ebebea53SRichard Henderson tcg_out_st(s, TCG_TYPE_V128, 6392ebebea53SRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0), 6393ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0); 6394ebebea53SRichard Henderson /* fall through */ 6395ebebea53SRichard Henderson case TCG_CALL_RET_BY_REF: 6396ebebea53SRichard Henderson tcg_out_ld(s, TCG_TYPE_I64, ldst->datalo_reg, 6397ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0 + 8 * HOST_BIG_ENDIAN); 6398ebebea53SRichard Henderson tcg_out_ld(s, TCG_TYPE_I64, ldst->datahi_reg, 6399ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0 + 8 * !HOST_BIG_ENDIAN); 6400ebebea53SRichard Henderson return; 6401ebebea53SRichard Henderson default: 6402ebebea53SRichard Henderson g_assert_not_reached(); 6403ebebea53SRichard Henderson } 6404ebebea53SRichard Henderson break; 6405ebebea53SRichard Henderson 6406ebebea53SRichard Henderson default: 6407ebebea53SRichard Henderson g_assert_not_reached(); 6408ebebea53SRichard Henderson } 64098429a1caSRichard Henderson 64108429a1caSRichard Henderson mov[0].dst = ldst->datalo_reg; 64118429a1caSRichard Henderson mov[0].src = 64128429a1caSRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, HOST_BIG_ENDIAN); 6413723d3a27SRichard Henderson mov[0].dst_type = TCG_TYPE_REG; 6414723d3a27SRichard Henderson mov[0].src_type = TCG_TYPE_REG; 6415ebebea53SRichard Henderson mov[0].src_ext = TCG_TARGET_REG_BITS == 32 ? MO_32 : MO_64; 64168429a1caSRichard Henderson 64178429a1caSRichard Henderson mov[1].dst = ldst->datahi_reg; 64188429a1caSRichard Henderson mov[1].src = 64198429a1caSRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, !HOST_BIG_ENDIAN); 64208429a1caSRichard Henderson mov[1].dst_type = TCG_TYPE_REG; 64218429a1caSRichard Henderson mov[1].src_type = TCG_TYPE_REG; 6422ebebea53SRichard Henderson mov[1].src_ext = TCG_TARGET_REG_BITS == 32 ? MO_32 : MO_64; 64238429a1caSRichard Henderson 64248429a1caSRichard Henderson tcg_out_movext2(s, mov, mov + 1, parm->ntmp ? parm->tmp[0] : -1); 64258429a1caSRichard Henderson } 64268429a1caSRichard Henderson 64278429a1caSRichard Henderson static void tcg_out_st_helper_args(TCGContext *s, const TCGLabelQemuLdst *ldst, 64288429a1caSRichard Henderson const TCGLdstHelperParam *parm) 64298429a1caSRichard Henderson { 64308429a1caSRichard Henderson const TCGHelperInfo *info; 64318429a1caSRichard Henderson const TCGCallArgumentLoc *loc; 64328429a1caSRichard Henderson TCGMovExtend mov[4]; 64338429a1caSRichard Henderson TCGType data_type; 64348429a1caSRichard Henderson unsigned next_arg, nmov, n; 64358429a1caSRichard Henderson MemOp mop = get_memop(ldst->oi); 64368429a1caSRichard Henderson 64378429a1caSRichard Henderson switch (mop & MO_SIZE) { 64388429a1caSRichard Henderson case MO_8: 64398429a1caSRichard Henderson case MO_16: 64408429a1caSRichard Henderson case MO_32: 64418429a1caSRichard Henderson info = &info_helper_st32_mmu; 64428429a1caSRichard Henderson data_type = TCG_TYPE_I32; 64438429a1caSRichard Henderson break; 64448429a1caSRichard Henderson case MO_64: 64458429a1caSRichard Henderson info = &info_helper_st64_mmu; 64468429a1caSRichard Henderson data_type = TCG_TYPE_I64; 64478429a1caSRichard Henderson break; 6448ebebea53SRichard Henderson case MO_128: 6449ebebea53SRichard Henderson info = &info_helper_st128_mmu; 6450ebebea53SRichard Henderson data_type = TCG_TYPE_I128; 6451ebebea53SRichard Henderson break; 64528429a1caSRichard Henderson default: 64538429a1caSRichard Henderson g_assert_not_reached(); 64548429a1caSRichard Henderson } 64558429a1caSRichard Henderson 64568429a1caSRichard Henderson /* Defer env argument. */ 64578429a1caSRichard Henderson next_arg = 1; 64588429a1caSRichard Henderson nmov = 0; 64598429a1caSRichard Henderson 64608429a1caSRichard Henderson /* Handle addr argument. */ 64618429a1caSRichard Henderson loc = &info->in[next_arg]; 64620cd38379SRichard Henderson tcg_debug_assert(s->addr_type <= TCG_TYPE_REG); 64630cd38379SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 646424e46e6cSRichard Henderson /* 64650cd38379SRichard Henderson * 32-bit host (and thus 32-bit guest): zero-extend the guest address 646624e46e6cSRichard Henderson * to 64-bits for the helper by storing the low part. Later, 646724e46e6cSRichard Henderson * after we have processed the register inputs, we will load a 646824e46e6cSRichard Henderson * zero for the high part. 646924e46e6cSRichard Henderson */ 647024e46e6cSRichard Henderson tcg_out_helper_add_mov(mov, loc + HOST_BIG_ENDIAN, 647124e46e6cSRichard Henderson TCG_TYPE_I32, TCG_TYPE_I32, 64720cd38379SRichard Henderson ldst->addr_reg, -1); 647324e46e6cSRichard Henderson next_arg += 2; 647424e46e6cSRichard Henderson nmov += 1; 6475c31e5fa4SRichard Henderson } else { 6476c31e5fa4SRichard Henderson n = tcg_out_helper_add_mov(mov, loc, TCG_TYPE_I64, s->addr_type, 64770cd38379SRichard Henderson ldst->addr_reg, -1); 6478c31e5fa4SRichard Henderson next_arg += n; 6479c31e5fa4SRichard Henderson nmov += n; 648024e46e6cSRichard Henderson } 64818429a1caSRichard Henderson 64828429a1caSRichard Henderson /* Handle data argument. */ 64838429a1caSRichard Henderson loc = &info->in[next_arg]; 6484ebebea53SRichard Henderson switch (loc->kind) { 6485ebebea53SRichard Henderson case TCG_CALL_ARG_NORMAL: 6486ebebea53SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 6487ebebea53SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 64888429a1caSRichard Henderson n = tcg_out_helper_add_mov(mov + nmov, loc, data_type, ldst->type, 64898429a1caSRichard Henderson ldst->datalo_reg, ldst->datahi_reg); 64908429a1caSRichard Henderson next_arg += n; 64918429a1caSRichard Henderson nmov += n; 6492ebebea53SRichard Henderson tcg_out_helper_load_slots(s, nmov, mov, parm); 6493ebebea53SRichard Henderson break; 6494ebebea53SRichard Henderson 6495ebebea53SRichard Henderson case TCG_CALL_ARG_BY_REF: 6496ebebea53SRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 64); 6497ebebea53SRichard Henderson tcg_debug_assert(data_type == TCG_TYPE_I128); 6498ebebea53SRichard Henderson tcg_out_st(s, TCG_TYPE_I64, 6499ebebea53SRichard Henderson HOST_BIG_ENDIAN ? ldst->datahi_reg : ldst->datalo_reg, 6500ebebea53SRichard Henderson TCG_REG_CALL_STACK, arg_slot_stk_ofs(loc[0].ref_slot)); 6501ebebea53SRichard Henderson tcg_out_st(s, TCG_TYPE_I64, 6502ebebea53SRichard Henderson HOST_BIG_ENDIAN ? ldst->datalo_reg : ldst->datahi_reg, 6503ebebea53SRichard Henderson TCG_REG_CALL_STACK, arg_slot_stk_ofs(loc[1].ref_slot)); 65048429a1caSRichard Henderson 65058429a1caSRichard Henderson tcg_out_helper_load_slots(s, nmov, mov, parm); 6506ebebea53SRichard Henderson 6507ebebea53SRichard Henderson if (arg_slot_reg_p(loc->arg_slot)) { 6508ebebea53SRichard Henderson tcg_out_addi_ptr(s, tcg_target_call_iarg_regs[loc->arg_slot], 6509ebebea53SRichard Henderson TCG_REG_CALL_STACK, 6510ebebea53SRichard Henderson arg_slot_stk_ofs(loc->ref_slot)); 6511ebebea53SRichard Henderson } else { 6512ebebea53SRichard Henderson tcg_debug_assert(parm->ntmp != 0); 6513ebebea53SRichard Henderson tcg_out_addi_ptr(s, parm->tmp[0], TCG_REG_CALL_STACK, 6514ebebea53SRichard Henderson arg_slot_stk_ofs(loc->ref_slot)); 6515ebebea53SRichard Henderson tcg_out_st(s, TCG_TYPE_PTR, parm->tmp[0], 6516ebebea53SRichard Henderson TCG_REG_CALL_STACK, arg_slot_stk_ofs(loc->arg_slot)); 6517ebebea53SRichard Henderson } 6518ebebea53SRichard Henderson next_arg += 2; 6519ebebea53SRichard Henderson break; 6520ebebea53SRichard Henderson 6521ebebea53SRichard Henderson default: 6522ebebea53SRichard Henderson g_assert_not_reached(); 6523ebebea53SRichard Henderson } 6524ebebea53SRichard Henderson 65250cd38379SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 6526c31e5fa4SRichard Henderson /* Zero extend the address by loading a zero for the high part. */ 652724e46e6cSRichard Henderson loc = &info->in[1 + !HOST_BIG_ENDIAN]; 652824e46e6cSRichard Henderson tcg_out_helper_load_imm(s, loc->arg_slot, TCG_TYPE_I32, 0, parm); 652924e46e6cSRichard Henderson } 653024e46e6cSRichard Henderson 65318429a1caSRichard Henderson tcg_out_helper_load_common_args(s, ldst, parm, info, next_arg); 65328429a1caSRichard Henderson } 65338429a1caSRichard Henderson 653476cef4b2SRichard Henderson int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start) 6535c896fe29Sbellard { 6536747bd69dSRichard Henderson int i, start_words, num_insns; 653715fa08f8SRichard Henderson TCGOp *op; 6538c896fe29Sbellard 6539d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP) 6540fbf59aadSRichard Henderson && qemu_log_in_addr_range(pc_start))) { 6541c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock(); 654278b54858SRichard Henderson if (logfile) { 654378b54858SRichard Henderson fprintf(logfile, "OP:\n"); 6544b7a83ff8SRichard Henderson tcg_dump_ops(s, logfile, false); 654578b54858SRichard Henderson fprintf(logfile, "\n"); 6546fc59d2d8SRobert Foley qemu_log_unlock(logfile); 6547c896fe29Sbellard } 654878b54858SRichard Henderson } 6549c896fe29Sbellard 6550bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG 6551bef16ab4SRichard Henderson /* Ensure all labels referenced have been emitted. */ 6552bef16ab4SRichard Henderson { 6553bef16ab4SRichard Henderson TCGLabel *l; 6554bef16ab4SRichard Henderson bool error = false; 6555bef16ab4SRichard Henderson 6556bef16ab4SRichard Henderson QSIMPLEQ_FOREACH(l, &s->labels, next) { 6557f85b1fc4SRichard Henderson if (unlikely(!l->present) && !QSIMPLEQ_EMPTY(&l->branches)) { 6558bef16ab4SRichard Henderson qemu_log_mask(CPU_LOG_TB_OP, 6559bef16ab4SRichard Henderson "$L%d referenced but not present.\n", l->id); 6560bef16ab4SRichard Henderson error = true; 6561bef16ab4SRichard Henderson } 6562bef16ab4SRichard Henderson } 6563bef16ab4SRichard Henderson assert(!error); 6564bef16ab4SRichard Henderson } 6565bef16ab4SRichard Henderson #endif 6566bef16ab4SRichard Henderson 656704e006abSRichard Henderson /* Do not reuse any EBB that may be allocated within the TB. */ 656804e006abSRichard Henderson tcg_temp_ebb_reset_freed(s); 656904e006abSRichard Henderson 6570c45cb8bbSRichard Henderson tcg_optimize(s); 65718f2e8c07SKirill Batuzov 6572b4fc67c7SRichard Henderson reachable_code_pass(s); 6573874b8574SRichard Henderson liveness_pass_0(s); 6574b83eabeaSRichard Henderson liveness_pass_1(s); 65755a18407fSRichard Henderson 65765a18407fSRichard Henderson if (s->nb_indirects > 0) { 65775a18407fSRichard Henderson if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND) 6578fbf59aadSRichard Henderson && qemu_log_in_addr_range(pc_start))) { 6579c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock(); 658078b54858SRichard Henderson if (logfile) { 658178b54858SRichard Henderson fprintf(logfile, "OP before indirect lowering:\n"); 6582b7a83ff8SRichard Henderson tcg_dump_ops(s, logfile, false); 658378b54858SRichard Henderson fprintf(logfile, "\n"); 6584fc59d2d8SRobert Foley qemu_log_unlock(logfile); 65855a18407fSRichard Henderson } 658678b54858SRichard Henderson } 6587645e3a81SRichard Henderson 65885a18407fSRichard Henderson /* Replace indirect temps with direct temps. */ 6589b83eabeaSRichard Henderson if (liveness_pass_2(s)) { 65905a18407fSRichard Henderson /* If changes were made, re-run liveness. */ 6591b83eabeaSRichard Henderson liveness_pass_1(s); 65925a18407fSRichard Henderson } 65935a18407fSRichard Henderson } 6594c5cc28ffSAurelien Jarno 6595d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT) 6596fbf59aadSRichard Henderson && qemu_log_in_addr_range(pc_start))) { 6597c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock(); 659878b54858SRichard Henderson if (logfile) { 659978b54858SRichard Henderson fprintf(logfile, "OP after optimization and liveness analysis:\n"); 6600b7a83ff8SRichard Henderson tcg_dump_ops(s, logfile, true); 660178b54858SRichard Henderson fprintf(logfile, "\n"); 6602fc59d2d8SRobert Foley qemu_log_unlock(logfile); 6603c896fe29Sbellard } 660478b54858SRichard Henderson } 6605c896fe29Sbellard 660635abb009SRichard Henderson /* Initialize goto_tb jump offsets. */ 66073a50f424SRichard Henderson tb->jmp_reset_offset[0] = TB_JMP_OFFSET_INVALID; 66083a50f424SRichard Henderson tb->jmp_reset_offset[1] = TB_JMP_OFFSET_INVALID; 66099da6079bSRichard Henderson tb->jmp_insn_offset[0] = TB_JMP_OFFSET_INVALID; 66109da6079bSRichard Henderson tb->jmp_insn_offset[1] = TB_JMP_OFFSET_INVALID; 661135abb009SRichard Henderson 6612c896fe29Sbellard tcg_reg_alloc_start(s); 6613c896fe29Sbellard 6614db0c51a3SRichard Henderson /* 6615db0c51a3SRichard Henderson * Reset the buffer pointers when restarting after overflow. 6616db0c51a3SRichard Henderson * TODO: Move this into translate-all.c with the rest of the 6617db0c51a3SRichard Henderson * buffer management. Having only this done here is confusing. 6618db0c51a3SRichard Henderson */ 6619db0c51a3SRichard Henderson s->code_buf = tcg_splitwx_to_rw(tb->tc.ptr); 6620db0c51a3SRichard Henderson s->code_ptr = s->code_buf; 6621a7cfd751SRichard Henderson s->data_gen_ptr = NULL; 6622c896fe29Sbellard 66236001f772SLaurent Vivier QSIMPLEQ_INIT(&s->ldst_labels); 662457a26946SRichard Henderson s->pool_labels = NULL; 66259ecefc84SRichard Henderson 6626747bd69dSRichard Henderson start_words = s->insn_start_words; 6627747bd69dSRichard Henderson s->gen_insn_data = 6628747bd69dSRichard Henderson tcg_malloc(sizeof(uint64_t) * s->gen_tb->icount * start_words); 6629747bd69dSRichard Henderson 66309358fbbfSRichard Henderson tcg_out_tb_start(s); 66319358fbbfSRichard Henderson 6632fca8a500SRichard Henderson num_insns = -1; 663315fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 6634c45cb8bbSRichard Henderson TCGOpcode opc = op->opc; 6635b3db8758Sblueswir1 6636c896fe29Sbellard switch (opc) { 6637b5701261SRichard Henderson case INDEX_op_mov: 6638d2fd745fSRichard Henderson case INDEX_op_mov_vec: 6639dd186292SRichard Henderson tcg_reg_alloc_mov(s, op); 6640c896fe29Sbellard break; 6641bab1671fSRichard Henderson case INDEX_op_dup_vec: 6642bab1671fSRichard Henderson tcg_reg_alloc_dup(s, op); 6643bab1671fSRichard Henderson break; 6644765b842aSRichard Henderson case INDEX_op_insn_start: 6645fca8a500SRichard Henderson if (num_insns >= 0) { 66469f754620SRichard Henderson size_t off = tcg_current_code_size(s); 66479f754620SRichard Henderson s->gen_insn_end_off[num_insns] = off; 66489f754620SRichard Henderson /* Assert that we do not overflow our stored offset. */ 66499f754620SRichard Henderson assert(s->gen_insn_end_off[num_insns] == off); 6650fca8a500SRichard Henderson } 6651fca8a500SRichard Henderson num_insns++; 6652747bd69dSRichard Henderson for (i = 0; i < start_words; ++i) { 6653747bd69dSRichard Henderson s->gen_insn_data[num_insns * start_words + i] = 6654c9ad8d27SRichard Henderson tcg_get_insn_start_param(op, i); 6655bad729e2SRichard Henderson } 6656c896fe29Sbellard break; 66575ff9d6a4Sbellard case INDEX_op_discard: 665843439139SRichard Henderson temp_dead(s, arg_temp(op->args[0])); 66595ff9d6a4Sbellard break; 6660c896fe29Sbellard case INDEX_op_set_label: 6661e8996ee0Sbellard tcg_reg_alloc_bb_end(s, s->reserved_regs); 666292ab8e7dSRichard Henderson tcg_out_label(s, arg_label(op->args[0])); 6663c896fe29Sbellard break; 6664c896fe29Sbellard case INDEX_op_call: 6665dd186292SRichard Henderson tcg_reg_alloc_call(s, op); 6666c45cb8bbSRichard Henderson break; 6667b55a8d9dSRichard Henderson case INDEX_op_exit_tb: 6668b55a8d9dSRichard Henderson tcg_out_exit_tb(s, op->args[0]); 6669b55a8d9dSRichard Henderson break; 6670cf7d6b8eSRichard Henderson case INDEX_op_goto_tb: 6671cf7d6b8eSRichard Henderson tcg_out_goto_tb(s, op->args[0]); 6672cf7d6b8eSRichard Henderson break; 6673efe86b21SRichard Henderson case INDEX_op_dup2_vec: 6674efe86b21SRichard Henderson if (tcg_reg_alloc_dup2(s, op)) { 6675efe86b21SRichard Henderson break; 6676efe86b21SRichard Henderson } 6677efe86b21SRichard Henderson /* fall through */ 6678c896fe29Sbellard default: 667925c4d9ccSRichard Henderson /* Sanity check that we've not introduced any unhandled opcodes. */ 6680771a5925SRichard Henderson tcg_debug_assert(tcg_op_supported(opc, TCGOP_TYPE(op), 6681771a5925SRichard Henderson TCGOP_FLAGS(op))); 6682c896fe29Sbellard /* Note: in order to speed up the code, it would be much 6683c896fe29Sbellard faster to have specialized register allocator functions for 6684c896fe29Sbellard some common argument patterns */ 6685dd186292SRichard Henderson tcg_reg_alloc_op(s, op); 6686c896fe29Sbellard break; 6687c896fe29Sbellard } 6688b125f9dcSRichard Henderson /* Test for (pending) buffer overflow. The assumption is that any 6689b125f9dcSRichard Henderson one operation beginning below the high water mark cannot overrun 6690b125f9dcSRichard Henderson the buffer completely. Thus we can test for overflow after 6691b125f9dcSRichard Henderson generating code without having to check during generation. */ 6692644da9b3SJohn Clarke if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) { 6693b125f9dcSRichard Henderson return -1; 6694b125f9dcSRichard Henderson } 66956e6c4efeSRichard Henderson /* Test for TB overflow, as seen by gen_insn_end_off. */ 66966e6c4efeSRichard Henderson if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) { 66976e6c4efeSRichard Henderson return -2; 66986e6c4efeSRichard Henderson } 6699c896fe29Sbellard } 6700747bd69dSRichard Henderson tcg_debug_assert(num_insns + 1 == s->gen_tb->icount); 6701fca8a500SRichard Henderson s->gen_insn_end_off[num_insns] = tcg_current_code_size(s); 6702c45cb8bbSRichard Henderson 6703b76f0d8cSYeongkyoon Lee /* Generate TB finalization at the end of block */ 6704aeee05f5SRichard Henderson i = tcg_out_ldst_finalize(s); 6705aeee05f5SRichard Henderson if (i < 0) { 6706aeee05f5SRichard Henderson return i; 670723dceda6SRichard Henderson } 67081768987bSRichard Henderson i = tcg_out_pool_finalize(s); 67091768987bSRichard Henderson if (i < 0) { 67101768987bSRichard Henderson return i; 671157a26946SRichard Henderson } 67127ecd02a0SRichard Henderson if (!tcg_resolve_relocs(s)) { 67137ecd02a0SRichard Henderson return -2; 67147ecd02a0SRichard Henderson } 6715c896fe29Sbellard 6716df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 6717c896fe29Sbellard /* flush instruction cache */ 6718db0c51a3SRichard Henderson flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf), 6719db0c51a3SRichard Henderson (uintptr_t)s->code_buf, 67201da8de39SRichard Henderson tcg_ptr_byte_diff(s->code_ptr, s->code_buf)); 6721df5d2b16SRichard Henderson #endif 67222aeabc08SStefan Weil 67231813e175SRichard Henderson return tcg_current_code_size(s); 6724c896fe29Sbellard } 6725c896fe29Sbellard 6726813da627SRichard Henderson #ifdef ELF_HOST_MACHINE 67275872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things: 67285872bbf2SRichard Henderson 67295872bbf2SRichard Henderson (1) Define ELF_HOST_MACHINE to indicate both what value to 67305872bbf2SRichard Henderson put into the ELF image and to indicate support for the feature. 67315872bbf2SRichard Henderson 67325872bbf2SRichard Henderson (2) Define tcg_register_jit. This should create a buffer containing 67335872bbf2SRichard Henderson the contents of a .debug_frame section that describes the post- 67345872bbf2SRichard Henderson prologue unwind info for the tcg machine. 67355872bbf2SRichard Henderson 67365872bbf2SRichard Henderson (3) Call tcg_register_jit_int, with the constructed .debug_frame. 67375872bbf2SRichard Henderson */ 6738813da627SRichard Henderson 6739813da627SRichard Henderson /* Begin GDB interface. THE FOLLOWING MUST MATCH GDB DOCS. */ 6740813da627SRichard Henderson typedef enum { 6741813da627SRichard Henderson JIT_NOACTION = 0, 6742813da627SRichard Henderson JIT_REGISTER_FN, 6743813da627SRichard Henderson JIT_UNREGISTER_FN 6744813da627SRichard Henderson } jit_actions_t; 6745813da627SRichard Henderson 6746813da627SRichard Henderson struct jit_code_entry { 6747813da627SRichard Henderson struct jit_code_entry *next_entry; 6748813da627SRichard Henderson struct jit_code_entry *prev_entry; 6749813da627SRichard Henderson const void *symfile_addr; 6750813da627SRichard Henderson uint64_t symfile_size; 6751813da627SRichard Henderson }; 6752813da627SRichard Henderson 6753813da627SRichard Henderson struct jit_descriptor { 6754813da627SRichard Henderson uint32_t version; 6755813da627SRichard Henderson uint32_t action_flag; 6756813da627SRichard Henderson struct jit_code_entry *relevant_entry; 6757813da627SRichard Henderson struct jit_code_entry *first_entry; 6758813da627SRichard Henderson }; 6759813da627SRichard Henderson 6760813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline)); 6761813da627SRichard Henderson void __jit_debug_register_code(void) 6762813da627SRichard Henderson { 6763813da627SRichard Henderson asm(""); 6764813da627SRichard Henderson } 6765813da627SRichard Henderson 6766813da627SRichard Henderson /* Must statically initialize the version, because GDB may check 6767813da627SRichard Henderson the version before we can set it. */ 6768813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 }; 6769813da627SRichard Henderson 6770813da627SRichard Henderson /* End GDB interface. */ 6771813da627SRichard Henderson 6772813da627SRichard Henderson static int find_string(const char *strtab, const char *str) 6773813da627SRichard Henderson { 6774813da627SRichard Henderson const char *p = strtab + 1; 6775813da627SRichard Henderson 6776813da627SRichard Henderson while (1) { 6777813da627SRichard Henderson if (strcmp(p, str) == 0) { 6778813da627SRichard Henderson return p - strtab; 6779813da627SRichard Henderson } 6780813da627SRichard Henderson p += strlen(p) + 1; 6781813da627SRichard Henderson } 6782813da627SRichard Henderson } 6783813da627SRichard Henderson 6784755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf_ptr, size_t buf_size, 67852c90784aSRichard Henderson const void *debug_frame, 67862c90784aSRichard Henderson size_t debug_frame_size) 6787813da627SRichard Henderson { 67885872bbf2SRichard Henderson struct __attribute__((packed)) DebugInfo { 67895872bbf2SRichard Henderson uint32_t len; 67905872bbf2SRichard Henderson uint16_t version; 67915872bbf2SRichard Henderson uint32_t abbrev; 67925872bbf2SRichard Henderson uint8_t ptr_size; 67935872bbf2SRichard Henderson uint8_t cu_die; 67945872bbf2SRichard Henderson uint16_t cu_lang; 67955872bbf2SRichard Henderson uintptr_t cu_low_pc; 67965872bbf2SRichard Henderson uintptr_t cu_high_pc; 67975872bbf2SRichard Henderson uint8_t fn_die; 67985872bbf2SRichard Henderson char fn_name[16]; 67995872bbf2SRichard Henderson uintptr_t fn_low_pc; 68005872bbf2SRichard Henderson uintptr_t fn_high_pc; 68015872bbf2SRichard Henderson uint8_t cu_eoc; 68025872bbf2SRichard Henderson }; 6803813da627SRichard Henderson 6804813da627SRichard Henderson struct ElfImage { 6805813da627SRichard Henderson ElfW(Ehdr) ehdr; 6806813da627SRichard Henderson ElfW(Phdr) phdr; 68075872bbf2SRichard Henderson ElfW(Shdr) shdr[7]; 68085872bbf2SRichard Henderson ElfW(Sym) sym[2]; 68095872bbf2SRichard Henderson struct DebugInfo di; 68105872bbf2SRichard Henderson uint8_t da[24]; 68115872bbf2SRichard Henderson char str[80]; 68125872bbf2SRichard Henderson }; 68135872bbf2SRichard Henderson 68145872bbf2SRichard Henderson struct ElfImage *img; 68155872bbf2SRichard Henderson 68165872bbf2SRichard Henderson static const struct ElfImage img_template = { 68175872bbf2SRichard Henderson .ehdr = { 68185872bbf2SRichard Henderson .e_ident[EI_MAG0] = ELFMAG0, 68195872bbf2SRichard Henderson .e_ident[EI_MAG1] = ELFMAG1, 68205872bbf2SRichard Henderson .e_ident[EI_MAG2] = ELFMAG2, 68215872bbf2SRichard Henderson .e_ident[EI_MAG3] = ELFMAG3, 68225872bbf2SRichard Henderson .e_ident[EI_CLASS] = ELF_CLASS, 68235872bbf2SRichard Henderson .e_ident[EI_DATA] = ELF_DATA, 68245872bbf2SRichard Henderson .e_ident[EI_VERSION] = EV_CURRENT, 68255872bbf2SRichard Henderson .e_type = ET_EXEC, 68265872bbf2SRichard Henderson .e_machine = ELF_HOST_MACHINE, 68275872bbf2SRichard Henderson .e_version = EV_CURRENT, 68285872bbf2SRichard Henderson .e_phoff = offsetof(struct ElfImage, phdr), 68295872bbf2SRichard Henderson .e_shoff = offsetof(struct ElfImage, shdr), 68305872bbf2SRichard Henderson .e_ehsize = sizeof(ElfW(Shdr)), 68315872bbf2SRichard Henderson .e_phentsize = sizeof(ElfW(Phdr)), 68325872bbf2SRichard Henderson .e_phnum = 1, 68335872bbf2SRichard Henderson .e_shentsize = sizeof(ElfW(Shdr)), 68345872bbf2SRichard Henderson .e_shnum = ARRAY_SIZE(img->shdr), 68355872bbf2SRichard Henderson .e_shstrndx = ARRAY_SIZE(img->shdr) - 1, 6836abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS 6837abbb3eaeSRichard Henderson .e_flags = ELF_HOST_FLAGS, 6838abbb3eaeSRichard Henderson #endif 6839abbb3eaeSRichard Henderson #ifdef ELF_OSABI 6840abbb3eaeSRichard Henderson .e_ident[EI_OSABI] = ELF_OSABI, 6841abbb3eaeSRichard Henderson #endif 68425872bbf2SRichard Henderson }, 68435872bbf2SRichard Henderson .phdr = { 68445872bbf2SRichard Henderson .p_type = PT_LOAD, 68455872bbf2SRichard Henderson .p_flags = PF_X, 68465872bbf2SRichard Henderson }, 68475872bbf2SRichard Henderson .shdr = { 68485872bbf2SRichard Henderson [0] = { .sh_type = SHT_NULL }, 68495872bbf2SRichard Henderson /* Trick: The contents of code_gen_buffer are not present in 68505872bbf2SRichard Henderson this fake ELF file; that got allocated elsewhere. Therefore 68515872bbf2SRichard Henderson we mark .text as SHT_NOBITS (similar to .bss) so that readers 68525872bbf2SRichard Henderson will not look for contents. We can record any address. */ 68535872bbf2SRichard Henderson [1] = { /* .text */ 68545872bbf2SRichard Henderson .sh_type = SHT_NOBITS, 68555872bbf2SRichard Henderson .sh_flags = SHF_EXECINSTR | SHF_ALLOC, 68565872bbf2SRichard Henderson }, 68575872bbf2SRichard Henderson [2] = { /* .debug_info */ 68585872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 68595872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, di), 68605872bbf2SRichard Henderson .sh_size = sizeof(struct DebugInfo), 68615872bbf2SRichard Henderson }, 68625872bbf2SRichard Henderson [3] = { /* .debug_abbrev */ 68635872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 68645872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, da), 68655872bbf2SRichard Henderson .sh_size = sizeof(img->da), 68665872bbf2SRichard Henderson }, 68675872bbf2SRichard Henderson [4] = { /* .debug_frame */ 68685872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 68695872bbf2SRichard Henderson .sh_offset = sizeof(struct ElfImage), 68705872bbf2SRichard Henderson }, 68715872bbf2SRichard Henderson [5] = { /* .symtab */ 68725872bbf2SRichard Henderson .sh_type = SHT_SYMTAB, 68735872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, sym), 68745872bbf2SRichard Henderson .sh_size = sizeof(img->sym), 68755872bbf2SRichard Henderson .sh_info = 1, 68765872bbf2SRichard Henderson .sh_link = ARRAY_SIZE(img->shdr) - 1, 68775872bbf2SRichard Henderson .sh_entsize = sizeof(ElfW(Sym)), 68785872bbf2SRichard Henderson }, 68795872bbf2SRichard Henderson [6] = { /* .strtab */ 68805872bbf2SRichard Henderson .sh_type = SHT_STRTAB, 68815872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, str), 68825872bbf2SRichard Henderson .sh_size = sizeof(img->str), 68835872bbf2SRichard Henderson } 68845872bbf2SRichard Henderson }, 68855872bbf2SRichard Henderson .sym = { 68865872bbf2SRichard Henderson [1] = { /* code_gen_buffer */ 68875872bbf2SRichard Henderson .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC), 68885872bbf2SRichard Henderson .st_shndx = 1, 68895872bbf2SRichard Henderson } 68905872bbf2SRichard Henderson }, 68915872bbf2SRichard Henderson .di = { 68925872bbf2SRichard Henderson .len = sizeof(struct DebugInfo) - 4, 68935872bbf2SRichard Henderson .version = 2, 68945872bbf2SRichard Henderson .ptr_size = sizeof(void *), 68955872bbf2SRichard Henderson .cu_die = 1, 68965872bbf2SRichard Henderson .cu_lang = 0x8001, /* DW_LANG_Mips_Assembler */ 68975872bbf2SRichard Henderson .fn_die = 2, 68985872bbf2SRichard Henderson .fn_name = "code_gen_buffer" 68995872bbf2SRichard Henderson }, 69005872bbf2SRichard Henderson .da = { 69015872bbf2SRichard Henderson 1, /* abbrev number (the cu) */ 69025872bbf2SRichard Henderson 0x11, 1, /* DW_TAG_compile_unit, has children */ 69035872bbf2SRichard Henderson 0x13, 0x5, /* DW_AT_language, DW_FORM_data2 */ 69045872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */ 69055872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */ 69065872bbf2SRichard Henderson 0, 0, /* end of abbrev */ 69075872bbf2SRichard Henderson 2, /* abbrev number (the fn) */ 69085872bbf2SRichard Henderson 0x2e, 0, /* DW_TAG_subprogram, no children */ 69095872bbf2SRichard Henderson 0x3, 0x8, /* DW_AT_name, DW_FORM_string */ 69105872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */ 69115872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */ 69125872bbf2SRichard Henderson 0, 0, /* end of abbrev */ 69135872bbf2SRichard Henderson 0 /* no more abbrev */ 69145872bbf2SRichard Henderson }, 69155872bbf2SRichard Henderson .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0" 69165872bbf2SRichard Henderson ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer", 6917813da627SRichard Henderson }; 6918813da627SRichard Henderson 6919813da627SRichard Henderson /* We only need a single jit entry; statically allocate it. */ 6920813da627SRichard Henderson static struct jit_code_entry one_entry; 6921813da627SRichard Henderson 69225872bbf2SRichard Henderson uintptr_t buf = (uintptr_t)buf_ptr; 6923813da627SRichard Henderson size_t img_size = sizeof(struct ElfImage) + debug_frame_size; 69242c90784aSRichard Henderson DebugFrameHeader *dfh; 6925813da627SRichard Henderson 69265872bbf2SRichard Henderson img = g_malloc(img_size); 69275872bbf2SRichard Henderson *img = img_template; 6928813da627SRichard Henderson 69295872bbf2SRichard Henderson img->phdr.p_vaddr = buf; 69305872bbf2SRichard Henderson img->phdr.p_paddr = buf; 69315872bbf2SRichard Henderson img->phdr.p_memsz = buf_size; 6932813da627SRichard Henderson 69335872bbf2SRichard Henderson img->shdr[1].sh_name = find_string(img->str, ".text"); 69345872bbf2SRichard Henderson img->shdr[1].sh_addr = buf; 69355872bbf2SRichard Henderson img->shdr[1].sh_size = buf_size; 6936813da627SRichard Henderson 69375872bbf2SRichard Henderson img->shdr[2].sh_name = find_string(img->str, ".debug_info"); 69385872bbf2SRichard Henderson img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev"); 69395872bbf2SRichard Henderson 69405872bbf2SRichard Henderson img->shdr[4].sh_name = find_string(img->str, ".debug_frame"); 69415872bbf2SRichard Henderson img->shdr[4].sh_size = debug_frame_size; 69425872bbf2SRichard Henderson 69435872bbf2SRichard Henderson img->shdr[5].sh_name = find_string(img->str, ".symtab"); 69445872bbf2SRichard Henderson img->shdr[6].sh_name = find_string(img->str, ".strtab"); 69455872bbf2SRichard Henderson 69465872bbf2SRichard Henderson img->sym[1].st_name = find_string(img->str, "code_gen_buffer"); 69475872bbf2SRichard Henderson img->sym[1].st_value = buf; 69485872bbf2SRichard Henderson img->sym[1].st_size = buf_size; 69495872bbf2SRichard Henderson 69505872bbf2SRichard Henderson img->di.cu_low_pc = buf; 695145aba097SRichard Henderson img->di.cu_high_pc = buf + buf_size; 69525872bbf2SRichard Henderson img->di.fn_low_pc = buf; 695345aba097SRichard Henderson img->di.fn_high_pc = buf + buf_size; 6954813da627SRichard Henderson 69552c90784aSRichard Henderson dfh = (DebugFrameHeader *)(img + 1); 69562c90784aSRichard Henderson memcpy(dfh, debug_frame, debug_frame_size); 69572c90784aSRichard Henderson dfh->fde.func_start = buf; 69582c90784aSRichard Henderson dfh->fde.func_len = buf_size; 69592c90784aSRichard Henderson 6960813da627SRichard Henderson #ifdef DEBUG_JIT 6961813da627SRichard Henderson /* Enable this block to be able to debug the ELF image file creation. 6962813da627SRichard Henderson One can use readelf, objdump, or other inspection utilities. */ 6963813da627SRichard Henderson { 6964eb6b2edfSBin Meng g_autofree char *jit = g_strdup_printf("%s/qemu.jit", g_get_tmp_dir()); 6965eb6b2edfSBin Meng FILE *f = fopen(jit, "w+b"); 6966813da627SRichard Henderson if (f) { 69675872bbf2SRichard Henderson if (fwrite(img, img_size, 1, f) != img_size) { 6968813da627SRichard Henderson /* Avoid stupid unused return value warning for fwrite. */ 6969813da627SRichard Henderson } 6970813da627SRichard Henderson fclose(f); 6971813da627SRichard Henderson } 6972813da627SRichard Henderson } 6973813da627SRichard Henderson #endif 6974813da627SRichard Henderson 6975813da627SRichard Henderson one_entry.symfile_addr = img; 6976813da627SRichard Henderson one_entry.symfile_size = img_size; 6977813da627SRichard Henderson 6978813da627SRichard Henderson __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; 6979813da627SRichard Henderson __jit_debug_descriptor.relevant_entry = &one_entry; 6980813da627SRichard Henderson __jit_debug_descriptor.first_entry = &one_entry; 6981813da627SRichard Henderson __jit_debug_register_code(); 6982813da627SRichard Henderson } 6983813da627SRichard Henderson #else 69845872bbf2SRichard Henderson /* No support for the feature. Provide the entry point expected by exec.c, 69855872bbf2SRichard Henderson and implement the internal function we declared earlier. */ 6986813da627SRichard Henderson 6987755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size, 69882c90784aSRichard Henderson const void *debug_frame, 69892c90784aSRichard Henderson size_t debug_frame_size) 6990813da627SRichard Henderson { 6991813da627SRichard Henderson } 6992813da627SRichard Henderson 6993755bf9e5SRichard Henderson void tcg_register_jit(const void *buf, size_t buf_size) 6994813da627SRichard Henderson { 6995813da627SRichard Henderson } 6996813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */ 6997db432672SRichard Henderson 6998db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec 6999db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...) 7000db432672SRichard Henderson { 7001db432672SRichard Henderson g_assert_not_reached(); 7002db432672SRichard Henderson } 7003db432672SRichard Henderson #endif 7004