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" 39ad3d0e4dSRichard Henderson #include "tcg/tcg-op-common.h" 40813da627SRichard Henderson 41edee2579SRichard Henderson #if UINTPTR_MAX == UINT32_MAX 42813da627SRichard Henderson # define ELF_CLASS ELFCLASS32 43edee2579SRichard Henderson #else 44edee2579SRichard Henderson # define ELF_CLASS ELFCLASS64 45813da627SRichard Henderson #endif 46e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN 47813da627SRichard Henderson # define ELF_DATA ELFDATA2MSB 48813da627SRichard Henderson #else 49813da627SRichard Henderson # define ELF_DATA ELFDATA2LSB 50813da627SRichard Henderson #endif 51813da627SRichard Henderson 52c896fe29Sbellard #include "elf.h" 53508127e2SPaolo Bonzini #include "exec/log.h" 54d2ba8026SRichard Henderson #include "tcg/tcg-ldst.h" 5547f7313dSRichard Henderson #include "tcg/tcg-temp-internal.h" 565ff7258cSRichard Henderson #include "tcg-internal.h" 575584e2dbSIlya Leoshkevich #include "accel/tcg/perf.h" 587d478306SRichard Henderson #ifdef CONFIG_USER_ONLY 597d478306SRichard Henderson #include "exec/user/guest-base.h" 607d478306SRichard Henderson #endif 61c896fe29Sbellard 62139c1837SPaolo Bonzini /* Forward declarations for functions declared in tcg-target.c.inc and 63ce151109SPeter Maydell used here. */ 64e4d58b41SRichard Henderson static void tcg_target_init(TCGContext *s); 65e4d58b41SRichard Henderson static void tcg_target_qemu_prologue(TCGContext *s); 666ac17786SRichard Henderson static bool patch_reloc(tcg_insn_unit *code_ptr, int type, 672ba7fae2SRichard Henderson intptr_t value, intptr_t addend); 68c896fe29Sbellard 69497a22ebSRichard Henderson /* The CIE and FDE header definitions will be common to all hosts. */ 70497a22ebSRichard Henderson typedef struct { 71497a22ebSRichard Henderson uint32_t len __attribute__((aligned((sizeof(void *))))); 72497a22ebSRichard Henderson uint32_t id; 73497a22ebSRichard Henderson uint8_t version; 74497a22ebSRichard Henderson char augmentation[1]; 75497a22ebSRichard Henderson uint8_t code_align; 76497a22ebSRichard Henderson uint8_t data_align; 77497a22ebSRichard Henderson uint8_t return_column; 78497a22ebSRichard Henderson } DebugFrameCIE; 79497a22ebSRichard Henderson 80497a22ebSRichard Henderson typedef struct QEMU_PACKED { 81497a22ebSRichard Henderson uint32_t len __attribute__((aligned((sizeof(void *))))); 82497a22ebSRichard Henderson uint32_t cie_offset; 83edee2579SRichard Henderson uintptr_t func_start; 84edee2579SRichard Henderson uintptr_t func_len; 85497a22ebSRichard Henderson } DebugFrameFDEHeader; 86497a22ebSRichard Henderson 872c90784aSRichard Henderson typedef struct QEMU_PACKED { 882c90784aSRichard Henderson DebugFrameCIE cie; 892c90784aSRichard Henderson DebugFrameFDEHeader fde; 902c90784aSRichard Henderson } DebugFrameHeader; 912c90784aSRichard Henderson 922528f771SRichard Henderson typedef struct TCGLabelQemuLdst { 932528f771SRichard Henderson bool is_ld; /* qemu_ld: true, qemu_st: false */ 942528f771SRichard Henderson MemOpIdx oi; 952528f771SRichard Henderson TCGType type; /* result type of a load */ 962528f771SRichard Henderson TCGReg addrlo_reg; /* reg index for low word of guest virtual addr */ 972528f771SRichard Henderson TCGReg addrhi_reg; /* reg index for high word of guest virtual addr */ 982528f771SRichard Henderson TCGReg datalo_reg; /* reg index for low word to be loaded or stored */ 992528f771SRichard Henderson TCGReg datahi_reg; /* reg index for high word to be loaded or stored */ 1002528f771SRichard Henderson const tcg_insn_unit *raddr; /* addr of the next IR of qemu_ld/st IR */ 1012528f771SRichard Henderson tcg_insn_unit *label_ptr[2]; /* label pointers to be updated */ 1022528f771SRichard Henderson QSIMPLEQ_ENTRY(TCGLabelQemuLdst) next; 1032528f771SRichard Henderson } TCGLabelQemuLdst; 1042528f771SRichard Henderson 105755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size, 1062c90784aSRichard Henderson const void *debug_frame, 1072c90784aSRichard Henderson size_t debug_frame_size) 108813da627SRichard Henderson __attribute__((unused)); 109813da627SRichard Henderson 110139c1837SPaolo Bonzini /* Forward declarations for functions declared and used in tcg-target.c.inc. */ 1119358fbbfSRichard Henderson static void tcg_out_tb_start(TCGContext *s); 1122a534affSRichard Henderson static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1, 113a05b5b9bSRichard Henderson intptr_t arg2); 11478113e83SRichard Henderson static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg); 115c0ad3001SStefan Weil static void tcg_out_movi(TCGContext *s, TCGType type, 1162a534affSRichard Henderson TCGReg ret, tcg_target_long arg); 117678155b2SRichard Henderson static void tcg_out_ext8s(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg); 118753e42eaSRichard Henderson static void tcg_out_ext16s(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg); 119d0e66c89SRichard Henderson static void tcg_out_ext8u(TCGContext *s, TCGReg ret, TCGReg arg); 120379afdffSRichard Henderson static void tcg_out_ext16u(TCGContext *s, TCGReg ret, TCGReg arg); 12152bf3398SRichard Henderson static void tcg_out_ext32s(TCGContext *s, TCGReg ret, TCGReg arg); 1229ecf5f61SRichard Henderson static void tcg_out_ext32u(TCGContext *s, TCGReg ret, TCGReg arg); 1239c6aa274SRichard Henderson static void tcg_out_exts_i32_i64(TCGContext *s, TCGReg ret, TCGReg arg); 124b9bfe000SRichard Henderson static void tcg_out_extu_i32_i64(TCGContext *s, TCGReg ret, TCGReg arg); 125b8b94ac6SRichard Henderson static void tcg_out_extrl_i64_i32(TCGContext *s, TCGReg ret, TCGReg arg); 126313bdea8SRichard Henderson static void tcg_out_addi_ptr(TCGContext *s, TCGReg, TCGReg, tcg_target_long); 127129f1f9eSRichard Henderson static bool tcg_out_xchg(TCGContext *s, TCGType type, TCGReg r1, TCGReg r2); 128b55a8d9dSRichard Henderson static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg); 129cf7d6b8eSRichard Henderson static void tcg_out_goto_tb(TCGContext *s, int which); 1305e8892dbSMiroslav Rezanina static void tcg_out_op(TCGContext *s, TCGOpcode opc, 1315e8892dbSMiroslav Rezanina const TCGArg args[TCG_MAX_OP_ARGS], 1325e8892dbSMiroslav Rezanina const int const_args[TCG_MAX_OP_ARGS]); 133d2fd745fSRichard Henderson #if TCG_TARGET_MAYBE_vec 134e7632cfaSRichard Henderson static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece, 135e7632cfaSRichard Henderson TCGReg dst, TCGReg src); 136d6ecb4a9SRichard Henderson static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece, 137d6ecb4a9SRichard Henderson TCGReg dst, TCGReg base, intptr_t offset); 1384e186175SRichard Henderson static void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece, 1394e186175SRichard Henderson TCGReg dst, int64_t arg); 1405e8892dbSMiroslav Rezanina static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, 1415e8892dbSMiroslav Rezanina unsigned vecl, unsigned vece, 1425e8892dbSMiroslav Rezanina const TCGArg args[TCG_MAX_OP_ARGS], 1435e8892dbSMiroslav Rezanina const int const_args[TCG_MAX_OP_ARGS]); 144d2fd745fSRichard Henderson #else 145e7632cfaSRichard Henderson static inline bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece, 146e7632cfaSRichard Henderson TCGReg dst, TCGReg src) 147e7632cfaSRichard Henderson { 148e7632cfaSRichard Henderson g_assert_not_reached(); 149e7632cfaSRichard Henderson } 150d6ecb4a9SRichard Henderson static inline bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece, 151d6ecb4a9SRichard Henderson TCGReg dst, TCGReg base, intptr_t offset) 152d6ecb4a9SRichard Henderson { 153d6ecb4a9SRichard Henderson g_assert_not_reached(); 154d6ecb4a9SRichard Henderson } 1554e186175SRichard Henderson static inline void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece, 1564e186175SRichard Henderson TCGReg dst, int64_t arg) 157e7632cfaSRichard Henderson { 158e7632cfaSRichard Henderson g_assert_not_reached(); 159e7632cfaSRichard Henderson } 1605e8892dbSMiroslav Rezanina static inline void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, 1615e8892dbSMiroslav Rezanina unsigned vecl, unsigned vece, 1625e8892dbSMiroslav Rezanina const TCGArg args[TCG_MAX_OP_ARGS], 1635e8892dbSMiroslav Rezanina const int const_args[TCG_MAX_OP_ARGS]) 164d2fd745fSRichard Henderson { 165d2fd745fSRichard Henderson g_assert_not_reached(); 166d2fd745fSRichard Henderson } 167d2fd745fSRichard Henderson #endif 1682a534affSRichard Henderson static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1, 169a05b5b9bSRichard Henderson intptr_t arg2); 17059d7c14eSRichard Henderson static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val, 17159d7c14eSRichard Henderson TCGReg base, intptr_t ofs); 1727b7d8b2dSRichard Henderson static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target, 173cee44b03SRichard Henderson const TCGHelperInfo *info); 1745e3d0c19SRichard Henderson static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot); 175ebe92db2SJiajie Chen static bool tcg_target_const_match(int64_t val, TCGType type, int ct, int vece); 176659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS 177aeee05f5SRichard Henderson static int tcg_out_ldst_finalize(TCGContext *s); 178659ef5cbSRichard Henderson #endif 179c896fe29Sbellard 1808429a1caSRichard Henderson typedef struct TCGLdstHelperParam { 1818429a1caSRichard Henderson TCGReg (*ra_gen)(TCGContext *s, const TCGLabelQemuLdst *l, int arg_reg); 1828429a1caSRichard Henderson unsigned ntmp; 1838429a1caSRichard Henderson int tmp[3]; 1848429a1caSRichard Henderson } TCGLdstHelperParam; 1858429a1caSRichard Henderson 1868429a1caSRichard Henderson static void tcg_out_ld_helper_args(TCGContext *s, const TCGLabelQemuLdst *l, 1878429a1caSRichard Henderson const TCGLdstHelperParam *p) 1888429a1caSRichard Henderson __attribute__((unused)); 1898429a1caSRichard Henderson static void tcg_out_ld_helper_ret(TCGContext *s, const TCGLabelQemuLdst *l, 1908429a1caSRichard Henderson bool load_sign, const TCGLdstHelperParam *p) 1918429a1caSRichard Henderson __attribute__((unused)); 1928429a1caSRichard Henderson static void tcg_out_st_helper_args(TCGContext *s, const TCGLabelQemuLdst *l, 1938429a1caSRichard Henderson const TCGLdstHelperParam *p) 1948429a1caSRichard Henderson __attribute__((unused)); 1958429a1caSRichard Henderson 196de95016dSRichard Henderson static void * const qemu_ld_helpers[MO_SSIZE + 1] __attribute__((unused)) = { 1970cadc1edSRichard Henderson [MO_UB] = helper_ldub_mmu, 1980cadc1edSRichard Henderson [MO_SB] = helper_ldsb_mmu, 1990cadc1edSRichard Henderson [MO_UW] = helper_lduw_mmu, 2000cadc1edSRichard Henderson [MO_SW] = helper_ldsw_mmu, 2010cadc1edSRichard Henderson [MO_UL] = helper_ldul_mmu, 2020cadc1edSRichard Henderson [MO_UQ] = helper_ldq_mmu, 2030cadc1edSRichard Henderson #if TCG_TARGET_REG_BITS == 64 2040cadc1edSRichard Henderson [MO_SL] = helper_ldsl_mmu, 205ebebea53SRichard Henderson [MO_128] = helper_ld16_mmu, 2060cadc1edSRichard Henderson #endif 2070cadc1edSRichard Henderson }; 2080cadc1edSRichard Henderson 209de95016dSRichard Henderson static void * const qemu_st_helpers[MO_SIZE + 1] __attribute__((unused)) = { 2100cadc1edSRichard Henderson [MO_8] = helper_stb_mmu, 2110cadc1edSRichard Henderson [MO_16] = helper_stw_mmu, 2120cadc1edSRichard Henderson [MO_32] = helper_stl_mmu, 2130cadc1edSRichard Henderson [MO_64] = helper_stq_mmu, 214ebebea53SRichard Henderson #if TCG_TARGET_REG_BITS == 64 215ebebea53SRichard Henderson [MO_128] = helper_st16_mmu, 216ebebea53SRichard Henderson #endif 2170cadc1edSRichard Henderson }; 2180cadc1edSRichard Henderson 219e63b8a29SRichard Henderson typedef struct { 220e63b8a29SRichard Henderson MemOp atom; /* lg2 bits of atomicity required */ 221e63b8a29SRichard Henderson MemOp align; /* lg2 bits of alignment to use */ 222e63b8a29SRichard Henderson } TCGAtomAlign; 223e63b8a29SRichard Henderson 224e63b8a29SRichard Henderson static TCGAtomAlign atom_and_align_for_opc(TCGContext *s, MemOp opc, 225e63b8a29SRichard Henderson MemOp host_atom, bool allow_two_ops) 226e63b8a29SRichard Henderson __attribute__((unused)); 227e63b8a29SRichard Henderson 22842eb6dfcSRichard Henderson TCGContext tcg_init_ctx; 22942eb6dfcSRichard Henderson __thread TCGContext *tcg_ctx; 23042eb6dfcSRichard Henderson 2315ff7258cSRichard Henderson TCGContext **tcg_ctxs; 2320e2d61cfSRichard Henderson unsigned int tcg_cur_ctxs; 2330e2d61cfSRichard Henderson unsigned int tcg_max_ctxs; 234ad75a51eSRichard Henderson TCGv_env tcg_env; 235c8bc1168SRichard Henderson const void *tcg_code_gen_epilogue; 236db0c51a3SRichard Henderson uintptr_t tcg_splitwx_diff; 237df2cce29SEmilio G. Cota 238b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 239b91ccb31SRichard Henderson tcg_prologue_fn *tcg_qemu_tb_exec; 240b91ccb31SRichard Henderson #endif 241b91ccb31SRichard Henderson 242d2fd745fSRichard Henderson static TCGRegSet tcg_target_available_regs[TCG_TYPE_COUNT]; 243b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs; 244c896fe29Sbellard 2451813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1 2464196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v) 247c896fe29Sbellard { 248c896fe29Sbellard *s->code_ptr++ = v; 249c896fe29Sbellard } 250c896fe29Sbellard 2514196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p, 2524196dca6SPeter Maydell uint8_t v) 2535c53bb81SPeter Maydell { 2541813e175SRichard Henderson *p = v; 2555c53bb81SPeter Maydell } 2561813e175SRichard Henderson #endif 2575c53bb81SPeter Maydell 2581813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2 2594196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v) 260c896fe29Sbellard { 2611813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 2) { 2621813e175SRichard Henderson *s->code_ptr++ = v; 2631813e175SRichard Henderson } else { 2641813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 2654387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 2661813e175SRichard Henderson s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE); 2671813e175SRichard Henderson } 268c896fe29Sbellard } 269c896fe29Sbellard 2704196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p, 2714196dca6SPeter Maydell uint16_t v) 2725c53bb81SPeter Maydell { 2731813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 2) { 2741813e175SRichard Henderson *p = v; 2751813e175SRichard Henderson } else { 2765c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 2775c53bb81SPeter Maydell } 2781813e175SRichard Henderson } 2791813e175SRichard Henderson #endif 2805c53bb81SPeter Maydell 2811813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4 2824196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v) 283c896fe29Sbellard { 2841813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 4) { 2851813e175SRichard Henderson *s->code_ptr++ = v; 2861813e175SRichard Henderson } else { 2871813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 2884387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 2891813e175SRichard Henderson s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE); 2901813e175SRichard Henderson } 291c896fe29Sbellard } 292c896fe29Sbellard 2934196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p, 2944196dca6SPeter Maydell uint32_t v) 2955c53bb81SPeter Maydell { 2961813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 4) { 2971813e175SRichard Henderson *p = v; 2981813e175SRichard Henderson } else { 2995c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 3005c53bb81SPeter Maydell } 3011813e175SRichard Henderson } 3021813e175SRichard Henderson #endif 3035c53bb81SPeter Maydell 3041813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 8 3054196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v) 306ac26eb69SRichard Henderson { 3071813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 8) { 3081813e175SRichard Henderson *s->code_ptr++ = v; 3091813e175SRichard Henderson } else { 3101813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 3114387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 3121813e175SRichard Henderson s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE); 3131813e175SRichard Henderson } 314ac26eb69SRichard Henderson } 315ac26eb69SRichard Henderson 3164196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p, 3174196dca6SPeter Maydell uint64_t v) 3185c53bb81SPeter Maydell { 3191813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 8) { 3201813e175SRichard Henderson *p = v; 3211813e175SRichard Henderson } else { 3225c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 3235c53bb81SPeter Maydell } 3241813e175SRichard Henderson } 3251813e175SRichard Henderson #endif 3265c53bb81SPeter Maydell 327c896fe29Sbellard /* label relocation processing */ 328c896fe29Sbellard 3291813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type, 330bec16311SRichard Henderson TCGLabel *l, intptr_t addend) 331c896fe29Sbellard { 3327ecd02a0SRichard Henderson TCGRelocation *r = tcg_malloc(sizeof(TCGRelocation)); 333c896fe29Sbellard 334c896fe29Sbellard r->type = type; 335c896fe29Sbellard r->ptr = code_ptr; 336c896fe29Sbellard r->addend = addend; 3377ecd02a0SRichard Henderson QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next); 338c896fe29Sbellard } 339c896fe29Sbellard 34092ab8e7dSRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l) 341c896fe29Sbellard { 342eabb7b91SAurelien Jarno tcg_debug_assert(!l->has_value); 343c896fe29Sbellard l->has_value = 1; 34492ab8e7dSRichard Henderson l->u.value_ptr = tcg_splitwx_to_rx(s->code_ptr); 345c896fe29Sbellard } 346c896fe29Sbellard 34742a268c2SRichard Henderson TCGLabel *gen_new_label(void) 348c896fe29Sbellard { 349b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 35051e3972cSRichard Henderson TCGLabel *l = tcg_malloc(sizeof(TCGLabel)); 351c896fe29Sbellard 3527ecd02a0SRichard Henderson memset(l, 0, sizeof(TCGLabel)); 3537ecd02a0SRichard Henderson l->id = s->nb_labels++; 354f85b1fc4SRichard Henderson QSIMPLEQ_INIT(&l->branches); 3557ecd02a0SRichard Henderson QSIMPLEQ_INIT(&l->relocs); 3567ecd02a0SRichard Henderson 357bef16ab4SRichard Henderson QSIMPLEQ_INSERT_TAIL(&s->labels, l, next); 35842a268c2SRichard Henderson 35942a268c2SRichard Henderson return l; 360c896fe29Sbellard } 361c896fe29Sbellard 3627ecd02a0SRichard Henderson static bool tcg_resolve_relocs(TCGContext *s) 3637ecd02a0SRichard Henderson { 3647ecd02a0SRichard Henderson TCGLabel *l; 3657ecd02a0SRichard Henderson 3667ecd02a0SRichard Henderson QSIMPLEQ_FOREACH(l, &s->labels, next) { 3677ecd02a0SRichard Henderson TCGRelocation *r; 3687ecd02a0SRichard Henderson uintptr_t value = l->u.value; 3697ecd02a0SRichard Henderson 3707ecd02a0SRichard Henderson QSIMPLEQ_FOREACH(r, &l->relocs, next) { 3717ecd02a0SRichard Henderson if (!patch_reloc(r->ptr, r->type, value, r->addend)) { 3727ecd02a0SRichard Henderson return false; 3737ecd02a0SRichard Henderson } 3747ecd02a0SRichard Henderson } 3757ecd02a0SRichard Henderson } 3767ecd02a0SRichard Henderson return true; 3777ecd02a0SRichard Henderson } 3787ecd02a0SRichard Henderson 3799f754620SRichard Henderson static void set_jmp_reset_offset(TCGContext *s, int which) 3809f754620SRichard Henderson { 381f14bed3fSRichard Henderson /* 382f14bed3fSRichard Henderson * We will check for overflow at the end of the opcode loop in 383f14bed3fSRichard Henderson * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX. 384f14bed3fSRichard Henderson */ 385b7e4afbdSRichard Henderson s->gen_tb->jmp_reset_offset[which] = tcg_current_code_size(s); 3869f754620SRichard Henderson } 3879f754620SRichard Henderson 388b52a2c03SRichard Henderson static void G_GNUC_UNUSED set_jmp_insn_offset(TCGContext *s, int which) 389b52a2c03SRichard Henderson { 390b52a2c03SRichard Henderson /* 391b52a2c03SRichard Henderson * We will check for overflow at the end of the opcode loop in 392b52a2c03SRichard Henderson * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX. 393b52a2c03SRichard Henderson */ 3949da6079bSRichard Henderson s->gen_tb->jmp_insn_offset[which] = tcg_current_code_size(s); 395b52a2c03SRichard Henderson } 396b52a2c03SRichard Henderson 397becc452aSRichard Henderson static uintptr_t G_GNUC_UNUSED get_jmp_target_addr(TCGContext *s, int which) 398becc452aSRichard Henderson { 399becc452aSRichard Henderson /* 400becc452aSRichard Henderson * Return the read-execute version of the pointer, for the benefit 401becc452aSRichard Henderson * of any pc-relative addressing mode. 402becc452aSRichard Henderson */ 4039da6079bSRichard Henderson return (uintptr_t)tcg_splitwx_to_rx(&s->gen_tb->jmp_target_addr[which]); 404becc452aSRichard Henderson } 405becc452aSRichard Henderson 406d0a9bb5eSRichard Henderson #if defined(CONFIG_SOFTMMU) && !defined(CONFIG_TCG_INTERPRETER) 407d0a9bb5eSRichard Henderson static int tlb_mask_table_ofs(TCGContext *s, int which) 408d0a9bb5eSRichard Henderson { 4097857ee11SRichard Henderson return (offsetof(CPUNegativeOffsetState, tlb.f[which]) - 4107857ee11SRichard Henderson sizeof(CPUNegativeOffsetState)); 411d0a9bb5eSRichard Henderson } 412d0a9bb5eSRichard Henderson #endif 413d0a9bb5eSRichard Henderson 414db6b7d0cSRichard Henderson /* Signal overflow, starting over with fewer guest insns. */ 4158905770bSMarc-André Lureau static G_NORETURN 4168905770bSMarc-André Lureau void tcg_raise_tb_overflow(TCGContext *s) 417db6b7d0cSRichard Henderson { 418db6b7d0cSRichard Henderson siglongjmp(s->jmp_trans, -2); 419db6b7d0cSRichard Henderson } 420db6b7d0cSRichard Henderson 4218429a1caSRichard Henderson /* 4228429a1caSRichard Henderson * Used by tcg_out_movext{1,2} to hold the arguments for tcg_out_movext. 4238429a1caSRichard Henderson * By the time we arrive at tcg_out_movext1, @dst is always a TCGReg. 4248429a1caSRichard Henderson * 4258429a1caSRichard Henderson * However, tcg_out_helper_load_slots reuses this field to hold an 4268429a1caSRichard Henderson * argument slot number (which may designate a argument register or an 4278429a1caSRichard Henderson * argument stack slot), converting to TCGReg once all arguments that 4288429a1caSRichard Henderson * are destined for the stack are processed. 4298429a1caSRichard Henderson */ 430129f1f9eSRichard Henderson typedef struct TCGMovExtend { 4318429a1caSRichard Henderson unsigned dst; 432129f1f9eSRichard Henderson TCGReg src; 433129f1f9eSRichard Henderson TCGType dst_type; 434129f1f9eSRichard Henderson TCGType src_type; 435129f1f9eSRichard Henderson MemOp src_ext; 436129f1f9eSRichard Henderson } TCGMovExtend; 437129f1f9eSRichard Henderson 438b3dfd5fcSRichard Henderson /** 439b3dfd5fcSRichard Henderson * tcg_out_movext -- move and extend 440b3dfd5fcSRichard Henderson * @s: tcg context 441b3dfd5fcSRichard Henderson * @dst_type: integral type for destination 442b3dfd5fcSRichard Henderson * @dst: destination register 443b3dfd5fcSRichard Henderson * @src_type: integral type for source 444b3dfd5fcSRichard Henderson * @src_ext: extension to apply to source 445b3dfd5fcSRichard Henderson * @src: source register 446b3dfd5fcSRichard Henderson * 447b3dfd5fcSRichard Henderson * Move or extend @src into @dst, depending on @src_ext and the types. 448b3dfd5fcSRichard Henderson */ 449129f1f9eSRichard Henderson static void tcg_out_movext(TCGContext *s, TCGType dst_type, TCGReg dst, 450b3dfd5fcSRichard Henderson TCGType src_type, MemOp src_ext, TCGReg src) 451b3dfd5fcSRichard Henderson { 452b3dfd5fcSRichard Henderson switch (src_ext) { 453b3dfd5fcSRichard Henderson case MO_UB: 454b3dfd5fcSRichard Henderson tcg_out_ext8u(s, dst, src); 455b3dfd5fcSRichard Henderson break; 456b3dfd5fcSRichard Henderson case MO_SB: 457b3dfd5fcSRichard Henderson tcg_out_ext8s(s, dst_type, dst, src); 458b3dfd5fcSRichard Henderson break; 459b3dfd5fcSRichard Henderson case MO_UW: 460b3dfd5fcSRichard Henderson tcg_out_ext16u(s, dst, src); 461b3dfd5fcSRichard Henderson break; 462b3dfd5fcSRichard Henderson case MO_SW: 463b3dfd5fcSRichard Henderson tcg_out_ext16s(s, dst_type, dst, src); 464b3dfd5fcSRichard Henderson break; 465b3dfd5fcSRichard Henderson case MO_UL: 466b3dfd5fcSRichard Henderson case MO_SL: 467b3dfd5fcSRichard Henderson if (dst_type == TCG_TYPE_I32) { 468b3dfd5fcSRichard Henderson if (src_type == TCG_TYPE_I32) { 469b3dfd5fcSRichard Henderson tcg_out_mov(s, TCG_TYPE_I32, dst, src); 470b3dfd5fcSRichard Henderson } else { 471b3dfd5fcSRichard Henderson tcg_out_extrl_i64_i32(s, dst, src); 472b3dfd5fcSRichard Henderson } 473b3dfd5fcSRichard Henderson } else if (src_type == TCG_TYPE_I32) { 474b3dfd5fcSRichard Henderson if (src_ext & MO_SIGN) { 475b3dfd5fcSRichard Henderson tcg_out_exts_i32_i64(s, dst, src); 476b3dfd5fcSRichard Henderson } else { 477b3dfd5fcSRichard Henderson tcg_out_extu_i32_i64(s, dst, src); 478b3dfd5fcSRichard Henderson } 479b3dfd5fcSRichard Henderson } else { 480b3dfd5fcSRichard Henderson if (src_ext & MO_SIGN) { 481b3dfd5fcSRichard Henderson tcg_out_ext32s(s, dst, src); 482b3dfd5fcSRichard Henderson } else { 483b3dfd5fcSRichard Henderson tcg_out_ext32u(s, dst, src); 484b3dfd5fcSRichard Henderson } 485b3dfd5fcSRichard Henderson } 486b3dfd5fcSRichard Henderson break; 487b3dfd5fcSRichard Henderson case MO_UQ: 488b3dfd5fcSRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 64); 489b3dfd5fcSRichard Henderson if (dst_type == TCG_TYPE_I32) { 490b3dfd5fcSRichard Henderson tcg_out_extrl_i64_i32(s, dst, src); 491b3dfd5fcSRichard Henderson } else { 492b3dfd5fcSRichard Henderson tcg_out_mov(s, TCG_TYPE_I64, dst, src); 493b3dfd5fcSRichard Henderson } 494b3dfd5fcSRichard Henderson break; 495b3dfd5fcSRichard Henderson default: 496b3dfd5fcSRichard Henderson g_assert_not_reached(); 497b3dfd5fcSRichard Henderson } 498b3dfd5fcSRichard Henderson } 499b3dfd5fcSRichard Henderson 500129f1f9eSRichard Henderson /* Minor variations on a theme, using a structure. */ 501129f1f9eSRichard Henderson static void tcg_out_movext1_new_src(TCGContext *s, const TCGMovExtend *i, 502129f1f9eSRichard Henderson TCGReg src) 503129f1f9eSRichard Henderson { 504129f1f9eSRichard Henderson tcg_out_movext(s, i->dst_type, i->dst, i->src_type, i->src_ext, src); 505129f1f9eSRichard Henderson } 506129f1f9eSRichard Henderson 507129f1f9eSRichard Henderson static void tcg_out_movext1(TCGContext *s, const TCGMovExtend *i) 508129f1f9eSRichard Henderson { 509129f1f9eSRichard Henderson tcg_out_movext1_new_src(s, i, i->src); 510129f1f9eSRichard Henderson } 511129f1f9eSRichard Henderson 512129f1f9eSRichard Henderson /** 513129f1f9eSRichard Henderson * tcg_out_movext2 -- move and extend two pair 514129f1f9eSRichard Henderson * @s: tcg context 515129f1f9eSRichard Henderson * @i1: first move description 516129f1f9eSRichard Henderson * @i2: second move description 517129f1f9eSRichard Henderson * @scratch: temporary register, or -1 for none 518129f1f9eSRichard Henderson * 519129f1f9eSRichard Henderson * As tcg_out_movext, for both @i1 and @i2, caring for overlap 520129f1f9eSRichard Henderson * between the sources and destinations. 521129f1f9eSRichard Henderson */ 522129f1f9eSRichard Henderson 5238429a1caSRichard Henderson static void tcg_out_movext2(TCGContext *s, const TCGMovExtend *i1, 524129f1f9eSRichard Henderson const TCGMovExtend *i2, int scratch) 525129f1f9eSRichard Henderson { 526129f1f9eSRichard Henderson TCGReg src1 = i1->src; 527129f1f9eSRichard Henderson TCGReg src2 = i2->src; 528129f1f9eSRichard Henderson 529129f1f9eSRichard Henderson if (i1->dst != src2) { 530129f1f9eSRichard Henderson tcg_out_movext1(s, i1); 531129f1f9eSRichard Henderson tcg_out_movext1(s, i2); 532129f1f9eSRichard Henderson return; 533129f1f9eSRichard Henderson } 534129f1f9eSRichard Henderson if (i2->dst == src1) { 535129f1f9eSRichard Henderson TCGType src1_type = i1->src_type; 536129f1f9eSRichard Henderson TCGType src2_type = i2->src_type; 537129f1f9eSRichard Henderson 538129f1f9eSRichard Henderson if (tcg_out_xchg(s, MAX(src1_type, src2_type), src1, src2)) { 539129f1f9eSRichard Henderson /* The data is now in the correct registers, now extend. */ 540129f1f9eSRichard Henderson src1 = i2->src; 541129f1f9eSRichard Henderson src2 = i1->src; 542129f1f9eSRichard Henderson } else { 543129f1f9eSRichard Henderson tcg_debug_assert(scratch >= 0); 544129f1f9eSRichard Henderson tcg_out_mov(s, src1_type, scratch, src1); 545129f1f9eSRichard Henderson src1 = scratch; 546129f1f9eSRichard Henderson } 547129f1f9eSRichard Henderson } 548129f1f9eSRichard Henderson tcg_out_movext1_new_src(s, i2, src2); 549129f1f9eSRichard Henderson tcg_out_movext1_new_src(s, i1, src1); 550129f1f9eSRichard Henderson } 551129f1f9eSRichard Henderson 5522462e30eSRichard Henderson /** 5532462e30eSRichard Henderson * tcg_out_movext3 -- move and extend three pair 5542462e30eSRichard Henderson * @s: tcg context 5552462e30eSRichard Henderson * @i1: first move description 5562462e30eSRichard Henderson * @i2: second move description 5572462e30eSRichard Henderson * @i3: third move description 5582462e30eSRichard Henderson * @scratch: temporary register, or -1 for none 5592462e30eSRichard Henderson * 5602462e30eSRichard Henderson * As tcg_out_movext, for all of @i1, @i2 and @i3, caring for overlap 5612462e30eSRichard Henderson * between the sources and destinations. 5622462e30eSRichard Henderson */ 5632462e30eSRichard Henderson 5642462e30eSRichard Henderson static void tcg_out_movext3(TCGContext *s, const TCGMovExtend *i1, 5652462e30eSRichard Henderson const TCGMovExtend *i2, const TCGMovExtend *i3, 5662462e30eSRichard Henderson int scratch) 5672462e30eSRichard Henderson { 5682462e30eSRichard Henderson TCGReg src1 = i1->src; 5692462e30eSRichard Henderson TCGReg src2 = i2->src; 5702462e30eSRichard Henderson TCGReg src3 = i3->src; 5712462e30eSRichard Henderson 5722462e30eSRichard Henderson if (i1->dst != src2 && i1->dst != src3) { 5732462e30eSRichard Henderson tcg_out_movext1(s, i1); 5742462e30eSRichard Henderson tcg_out_movext2(s, i2, i3, scratch); 5752462e30eSRichard Henderson return; 5762462e30eSRichard Henderson } 5772462e30eSRichard Henderson if (i2->dst != src1 && i2->dst != src3) { 5782462e30eSRichard Henderson tcg_out_movext1(s, i2); 5792462e30eSRichard Henderson tcg_out_movext2(s, i1, i3, scratch); 5802462e30eSRichard Henderson return; 5812462e30eSRichard Henderson } 5822462e30eSRichard Henderson if (i3->dst != src1 && i3->dst != src2) { 5832462e30eSRichard Henderson tcg_out_movext1(s, i3); 5842462e30eSRichard Henderson tcg_out_movext2(s, i1, i2, scratch); 5852462e30eSRichard Henderson return; 5862462e30eSRichard Henderson } 5872462e30eSRichard Henderson 5882462e30eSRichard Henderson /* 5892462e30eSRichard Henderson * There is a cycle. Since there are only 3 nodes, the cycle is 5902462e30eSRichard Henderson * either "clockwise" or "anti-clockwise", and can be solved with 5912462e30eSRichard Henderson * a single scratch or two xchg. 5922462e30eSRichard Henderson */ 5932462e30eSRichard Henderson if (i1->dst == src2 && i2->dst == src3 && i3->dst == src1) { 5942462e30eSRichard Henderson /* "Clockwise" */ 5952462e30eSRichard Henderson if (tcg_out_xchg(s, MAX(i1->src_type, i2->src_type), src1, src2)) { 5962462e30eSRichard Henderson tcg_out_xchg(s, MAX(i2->src_type, i3->src_type), src2, src3); 5972462e30eSRichard Henderson /* The data is now in the correct registers, now extend. */ 5982462e30eSRichard Henderson tcg_out_movext1_new_src(s, i1, i1->dst); 5992462e30eSRichard Henderson tcg_out_movext1_new_src(s, i2, i2->dst); 6002462e30eSRichard Henderson tcg_out_movext1_new_src(s, i3, i3->dst); 6012462e30eSRichard Henderson } else { 6022462e30eSRichard Henderson tcg_debug_assert(scratch >= 0); 6032462e30eSRichard Henderson tcg_out_mov(s, i1->src_type, scratch, src1); 6042462e30eSRichard Henderson tcg_out_movext1(s, i3); 6052462e30eSRichard Henderson tcg_out_movext1(s, i2); 6062462e30eSRichard Henderson tcg_out_movext1_new_src(s, i1, scratch); 6072462e30eSRichard Henderson } 6082462e30eSRichard Henderson } else if (i1->dst == src3 && i2->dst == src1 && i3->dst == src2) { 6092462e30eSRichard Henderson /* "Anti-clockwise" */ 6102462e30eSRichard Henderson if (tcg_out_xchg(s, MAX(i2->src_type, i3->src_type), src2, src3)) { 6112462e30eSRichard Henderson tcg_out_xchg(s, MAX(i1->src_type, i2->src_type), src1, src2); 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, i2); 6202462e30eSRichard Henderson tcg_out_movext1(s, i3); 6212462e30eSRichard Henderson tcg_out_movext1_new_src(s, i1, scratch); 6222462e30eSRichard Henderson } 6232462e30eSRichard Henderson } else { 6242462e30eSRichard Henderson g_assert_not_reached(); 6252462e30eSRichard Henderson } 6262462e30eSRichard Henderson } 6272462e30eSRichard Henderson 6284c22e840SRichard Henderson #define C_PFX1(P, A) P##A 6294c22e840SRichard Henderson #define C_PFX2(P, A, B) P##A##_##B 6304c22e840SRichard Henderson #define C_PFX3(P, A, B, C) P##A##_##B##_##C 6314c22e840SRichard Henderson #define C_PFX4(P, A, B, C, D) P##A##_##B##_##C##_##D 6324c22e840SRichard Henderson #define C_PFX5(P, A, B, C, D, E) P##A##_##B##_##C##_##D##_##E 6334c22e840SRichard Henderson #define C_PFX6(P, A, B, C, D, E, F) P##A##_##B##_##C##_##D##_##E##_##F 6344c22e840SRichard Henderson 6354c22e840SRichard Henderson /* Define an enumeration for the various combinations. */ 6364c22e840SRichard Henderson 6374c22e840SRichard Henderson #define C_O0_I1(I1) C_PFX1(c_o0_i1_, I1), 6384c22e840SRichard Henderson #define C_O0_I2(I1, I2) C_PFX2(c_o0_i2_, I1, I2), 6394c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3) C_PFX3(c_o0_i3_, I1, I2, I3), 6404c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4) C_PFX4(c_o0_i4_, I1, I2, I3, I4), 6414c22e840SRichard Henderson 6424c22e840SRichard Henderson #define C_O1_I1(O1, I1) C_PFX2(c_o1_i1_, O1, I1), 6434c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2) C_PFX3(c_o1_i2_, O1, I1, I2), 6444c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3) C_PFX4(c_o1_i3_, O1, I1, I2, I3), 6454c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4) C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4), 6464c22e840SRichard Henderson 6474c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2) C_PFX3(c_n1_i2_, O1, I1, I2), 6484c22e840SRichard Henderson 6494c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1) C_PFX3(c_o2_i1_, O1, O2, I1), 6504c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2) C_PFX4(c_o2_i2_, O1, O2, I1, I2), 6514c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3) C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3), 6524c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4), 65322d2e535SIlya Leoshkevich #define C_N1_O1_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_n1_o1_i4_, O1, O2, I1, I2, I3, I4), 6544c22e840SRichard Henderson 6554c22e840SRichard Henderson typedef enum { 6564c22e840SRichard Henderson #include "tcg-target-con-set.h" 6574c22e840SRichard Henderson } TCGConstraintSetIndex; 6584c22e840SRichard Henderson 6594c22e840SRichard Henderson static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode); 6604c22e840SRichard Henderson 6614c22e840SRichard Henderson #undef C_O0_I1 6624c22e840SRichard Henderson #undef C_O0_I2 6634c22e840SRichard Henderson #undef C_O0_I3 6644c22e840SRichard Henderson #undef C_O0_I4 6654c22e840SRichard Henderson #undef C_O1_I1 6664c22e840SRichard Henderson #undef C_O1_I2 6674c22e840SRichard Henderson #undef C_O1_I3 6684c22e840SRichard Henderson #undef C_O1_I4 6694c22e840SRichard Henderson #undef C_N1_I2 6704c22e840SRichard Henderson #undef C_O2_I1 6714c22e840SRichard Henderson #undef C_O2_I2 6724c22e840SRichard Henderson #undef C_O2_I3 6734c22e840SRichard Henderson #undef C_O2_I4 67422d2e535SIlya Leoshkevich #undef C_N1_O1_I4 6754c22e840SRichard Henderson 6764c22e840SRichard Henderson /* Put all of the constraint sets into an array, indexed by the enum. */ 6774c22e840SRichard Henderson 6784c22e840SRichard Henderson #define C_O0_I1(I1) { .args_ct_str = { #I1 } }, 6794c22e840SRichard Henderson #define C_O0_I2(I1, I2) { .args_ct_str = { #I1, #I2 } }, 6804c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3) { .args_ct_str = { #I1, #I2, #I3 } }, 6814c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4) { .args_ct_str = { #I1, #I2, #I3, #I4 } }, 6824c22e840SRichard Henderson 6834c22e840SRichard Henderson #define C_O1_I1(O1, I1) { .args_ct_str = { #O1, #I1 } }, 6844c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2) { .args_ct_str = { #O1, #I1, #I2 } }, 6854c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3) { .args_ct_str = { #O1, #I1, #I2, #I3 } }, 6864c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4) { .args_ct_str = { #O1, #I1, #I2, #I3, #I4 } }, 6874c22e840SRichard Henderson 6884c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2) { .args_ct_str = { "&" #O1, #I1, #I2 } }, 6894c22e840SRichard Henderson 6904c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1) { .args_ct_str = { #O1, #O2, #I1 } }, 6914c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2) { .args_ct_str = { #O1, #O2, #I1, #I2 } }, 6924c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3) { .args_ct_str = { #O1, #O2, #I1, #I2, #I3 } }, 6934c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) { .args_ct_str = { #O1, #O2, #I1, #I2, #I3, #I4 } }, 69422d2e535SIlya Leoshkevich #define C_N1_O1_I4(O1, O2, I1, I2, I3, I4) { .args_ct_str = { "&" #O1, #O2, #I1, #I2, #I3, #I4 } }, 6954c22e840SRichard Henderson 6964c22e840SRichard Henderson static const TCGTargetOpDef constraint_sets[] = { 6974c22e840SRichard Henderson #include "tcg-target-con-set.h" 6984c22e840SRichard Henderson }; 6994c22e840SRichard Henderson 7004c22e840SRichard Henderson 7014c22e840SRichard Henderson #undef C_O0_I1 7024c22e840SRichard Henderson #undef C_O0_I2 7034c22e840SRichard Henderson #undef C_O0_I3 7044c22e840SRichard Henderson #undef C_O0_I4 7054c22e840SRichard Henderson #undef C_O1_I1 7064c22e840SRichard Henderson #undef C_O1_I2 7074c22e840SRichard Henderson #undef C_O1_I3 7084c22e840SRichard Henderson #undef C_O1_I4 7094c22e840SRichard Henderson #undef C_N1_I2 7104c22e840SRichard Henderson #undef C_O2_I1 7114c22e840SRichard Henderson #undef C_O2_I2 7124c22e840SRichard Henderson #undef C_O2_I3 7134c22e840SRichard Henderson #undef C_O2_I4 71422d2e535SIlya Leoshkevich #undef C_N1_O1_I4 7154c22e840SRichard Henderson 7164c22e840SRichard Henderson /* Expand the enumerator to be returned from tcg_target_op_def(). */ 7174c22e840SRichard Henderson 7184c22e840SRichard Henderson #define C_O0_I1(I1) C_PFX1(c_o0_i1_, I1) 7194c22e840SRichard Henderson #define C_O0_I2(I1, I2) C_PFX2(c_o0_i2_, I1, I2) 7204c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3) C_PFX3(c_o0_i3_, I1, I2, I3) 7214c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4) C_PFX4(c_o0_i4_, I1, I2, I3, I4) 7224c22e840SRichard Henderson 7234c22e840SRichard Henderson #define C_O1_I1(O1, I1) C_PFX2(c_o1_i1_, O1, I1) 7244c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2) C_PFX3(c_o1_i2_, O1, I1, I2) 7254c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3) C_PFX4(c_o1_i3_, O1, I1, I2, I3) 7264c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4) C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4) 7274c22e840SRichard Henderson 7284c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2) C_PFX3(c_n1_i2_, O1, I1, I2) 7294c22e840SRichard Henderson 7304c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1) C_PFX3(c_o2_i1_, O1, O2, I1) 7314c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2) C_PFX4(c_o2_i2_, O1, O2, I1, I2) 7324c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3) C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3) 7334c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4) 73422d2e535SIlya Leoshkevich #define C_N1_O1_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_n1_o1_i4_, O1, O2, I1, I2, I3, I4) 7354c22e840SRichard Henderson 736139c1837SPaolo Bonzini #include "tcg-target.c.inc" 737c896fe29Sbellard 7387857ee11SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 7397857ee11SRichard Henderson /* Validate CPUTLBDescFast placement. */ 7407857ee11SRichard Henderson QEMU_BUILD_BUG_ON((int)(offsetof(CPUNegativeOffsetState, tlb.f[0]) - 7417857ee11SRichard Henderson sizeof(CPUNegativeOffsetState)) 7427857ee11SRichard Henderson < MIN_TLB_MASK_TABLE_OFS); 7437857ee11SRichard Henderson #endif 7447857ee11SRichard Henderson 74538b47b19SEmilio G. Cota static void alloc_tcg_plugin_context(TCGContext *s) 74638b47b19SEmilio G. Cota { 74738b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN 74838b47b19SEmilio G. Cota s->plugin_tb = g_new0(struct qemu_plugin_tb, 1); 74938b47b19SEmilio G. Cota s->plugin_tb->insns = 75038b47b19SEmilio G. Cota g_ptr_array_new_with_free_func(qemu_plugin_insn_cleanup_fn); 75138b47b19SEmilio G. Cota #endif 75238b47b19SEmilio G. Cota } 75338b47b19SEmilio G. Cota 754e8feb96fSEmilio G. Cota /* 7553468b59eSEmilio G. Cota * All TCG threads except the parent (i.e. the one that called tcg_context_init 7563468b59eSEmilio G. Cota * and registered the target's TCG globals) must register with this function 7573468b59eSEmilio G. Cota * before initiating translation. 7583468b59eSEmilio G. Cota * 7593468b59eSEmilio G. Cota * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation 7603468b59eSEmilio G. Cota * of tcg_region_init() for the reasoning behind this. 7613468b59eSEmilio G. Cota * 7623468b59eSEmilio G. Cota * In softmmu each caller registers its context in tcg_ctxs[]. Note that in 7633468b59eSEmilio G. Cota * softmmu tcg_ctxs[] does not track tcg_ctx_init, since the initial context 7643468b59eSEmilio G. Cota * is not used anymore for translation once this function is called. 7653468b59eSEmilio G. Cota * 7663468b59eSEmilio G. Cota * Not tracking tcg_init_ctx in tcg_ctxs[] in softmmu keeps code that iterates 7673468b59eSEmilio G. Cota * over the array (e.g. tcg_code_size() the same for both softmmu and user-mode. 7683468b59eSEmilio G. Cota */ 7693468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY 7703468b59eSEmilio G. Cota void tcg_register_thread(void) 7713468b59eSEmilio G. Cota { 7723468b59eSEmilio G. Cota tcg_ctx = &tcg_init_ctx; 7733468b59eSEmilio G. Cota } 7743468b59eSEmilio G. Cota #else 7753468b59eSEmilio G. Cota void tcg_register_thread(void) 7763468b59eSEmilio G. Cota { 7773468b59eSEmilio G. Cota TCGContext *s = g_malloc(sizeof(*s)); 7783468b59eSEmilio G. Cota unsigned int i, n; 7793468b59eSEmilio G. Cota 7803468b59eSEmilio G. Cota *s = tcg_init_ctx; 7813468b59eSEmilio G. Cota 7823468b59eSEmilio G. Cota /* Relink mem_base. */ 7833468b59eSEmilio G. Cota for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) { 7843468b59eSEmilio G. Cota if (tcg_init_ctx.temps[i].mem_base) { 7853468b59eSEmilio G. Cota ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps; 7863468b59eSEmilio G. Cota tcg_debug_assert(b >= 0 && b < n); 7873468b59eSEmilio G. Cota s->temps[i].mem_base = &s->temps[b]; 7883468b59eSEmilio G. Cota } 7893468b59eSEmilio G. Cota } 7903468b59eSEmilio G. Cota 7913468b59eSEmilio G. Cota /* Claim an entry in tcg_ctxs */ 7920e2d61cfSRichard Henderson n = qatomic_fetch_inc(&tcg_cur_ctxs); 7930e2d61cfSRichard Henderson g_assert(n < tcg_max_ctxs); 794d73415a3SStefan Hajnoczi qatomic_set(&tcg_ctxs[n], s); 7953468b59eSEmilio G. Cota 79638b47b19SEmilio G. Cota if (n > 0) { 79738b47b19SEmilio G. Cota alloc_tcg_plugin_context(s); 798bf042e8eSRichard Henderson tcg_region_initial_alloc(s); 79938b47b19SEmilio G. Cota } 80038b47b19SEmilio G. Cota 8013468b59eSEmilio G. Cota tcg_ctx = s; 8023468b59eSEmilio G. Cota } 8033468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */ 8043468b59eSEmilio G. Cota 805c896fe29Sbellard /* pool based memory allocation */ 806c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size) 807c896fe29Sbellard { 808c896fe29Sbellard TCGPool *p; 809c896fe29Sbellard int pool_size; 810c896fe29Sbellard 811c896fe29Sbellard if (size > TCG_POOL_CHUNK_SIZE) { 812c896fe29Sbellard /* big malloc: insert a new pool (XXX: could optimize) */ 8137267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + size); 814c896fe29Sbellard p->size = size; 8154055299eSKirill Batuzov p->next = s->pool_first_large; 8164055299eSKirill Batuzov s->pool_first_large = p; 8174055299eSKirill Batuzov return p->data; 818c896fe29Sbellard } else { 819c896fe29Sbellard p = s->pool_current; 820c896fe29Sbellard if (!p) { 821c896fe29Sbellard p = s->pool_first; 822c896fe29Sbellard if (!p) 823c896fe29Sbellard goto new_pool; 824c896fe29Sbellard } else { 825c896fe29Sbellard if (!p->next) { 826c896fe29Sbellard new_pool: 827c896fe29Sbellard pool_size = TCG_POOL_CHUNK_SIZE; 8287267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + pool_size); 829c896fe29Sbellard p->size = pool_size; 830c896fe29Sbellard p->next = NULL; 831a813e36fSRichard Henderson if (s->pool_current) { 832c896fe29Sbellard s->pool_current->next = p; 833a813e36fSRichard Henderson } else { 834c896fe29Sbellard s->pool_first = p; 835a813e36fSRichard Henderson } 836c896fe29Sbellard } else { 837c896fe29Sbellard p = p->next; 838c896fe29Sbellard } 839c896fe29Sbellard } 840c896fe29Sbellard } 841c896fe29Sbellard s->pool_current = p; 842c896fe29Sbellard s->pool_cur = p->data + size; 843c896fe29Sbellard s->pool_end = p->data + p->size; 844c896fe29Sbellard return p->data; 845c896fe29Sbellard } 846c896fe29Sbellard 847c896fe29Sbellard void tcg_pool_reset(TCGContext *s) 848c896fe29Sbellard { 8494055299eSKirill Batuzov TCGPool *p, *t; 8504055299eSKirill Batuzov for (p = s->pool_first_large; p; p = t) { 8514055299eSKirill Batuzov t = p->next; 8524055299eSKirill Batuzov g_free(p); 8534055299eSKirill Batuzov } 8544055299eSKirill Batuzov s->pool_first_large = NULL; 855c896fe29Sbellard s->pool_cur = s->pool_end = NULL; 856c896fe29Sbellard s->pool_current = NULL; 857c896fe29Sbellard } 858c896fe29Sbellard 8598429a1caSRichard Henderson /* 8608429a1caSRichard Henderson * Create TCGHelperInfo structures for "tcg/tcg-ldst.h" functions, 8618429a1caSRichard Henderson * akin to what "exec/helper-tcg.h" does with DEF_HELPER_FLAGS_N. 8628429a1caSRichard Henderson * We only use these for layout in tcg_out_ld_helper_ret and 8638429a1caSRichard Henderson * tcg_out_st_helper_args, and share them between several of 8648429a1caSRichard Henderson * the helpers, with the end result that it's easier to build manually. 8658429a1caSRichard Henderson */ 8668429a1caSRichard Henderson 8678429a1caSRichard Henderson #if TCG_TARGET_REG_BITS == 32 8688429a1caSRichard Henderson # define dh_typecode_ttl dh_typecode_i32 8698429a1caSRichard Henderson #else 8708429a1caSRichard Henderson # define dh_typecode_ttl dh_typecode_i64 8718429a1caSRichard Henderson #endif 8728429a1caSRichard Henderson 8738429a1caSRichard Henderson static TCGHelperInfo info_helper_ld32_mmu = { 8748429a1caSRichard Henderson .flags = TCG_CALL_NO_WG, 8758429a1caSRichard Henderson .typemask = dh_typemask(ttl, 0) /* return tcg_target_ulong */ 8768429a1caSRichard Henderson | dh_typemask(env, 1) 87724e46e6cSRichard Henderson | dh_typemask(i64, 2) /* uint64_t addr */ 8788429a1caSRichard Henderson | dh_typemask(i32, 3) /* unsigned oi */ 8798429a1caSRichard Henderson | dh_typemask(ptr, 4) /* uintptr_t ra */ 8808429a1caSRichard Henderson }; 8818429a1caSRichard Henderson 8828429a1caSRichard Henderson static TCGHelperInfo info_helper_ld64_mmu = { 8838429a1caSRichard Henderson .flags = TCG_CALL_NO_WG, 8848429a1caSRichard Henderson .typemask = dh_typemask(i64, 0) /* return uint64_t */ 8858429a1caSRichard Henderson | dh_typemask(env, 1) 88624e46e6cSRichard Henderson | dh_typemask(i64, 2) /* uint64_t addr */ 8878429a1caSRichard Henderson | dh_typemask(i32, 3) /* unsigned oi */ 8888429a1caSRichard Henderson | dh_typemask(ptr, 4) /* uintptr_t ra */ 8898429a1caSRichard Henderson }; 8908429a1caSRichard Henderson 891ebebea53SRichard Henderson static TCGHelperInfo info_helper_ld128_mmu = { 892ebebea53SRichard Henderson .flags = TCG_CALL_NO_WG, 893ebebea53SRichard Henderson .typemask = dh_typemask(i128, 0) /* return Int128 */ 894ebebea53SRichard Henderson | dh_typemask(env, 1) 89524e46e6cSRichard Henderson | dh_typemask(i64, 2) /* uint64_t addr */ 896ebebea53SRichard Henderson | dh_typemask(i32, 3) /* unsigned oi */ 897ebebea53SRichard Henderson | dh_typemask(ptr, 4) /* uintptr_t ra */ 898ebebea53SRichard Henderson }; 899ebebea53SRichard Henderson 9008429a1caSRichard Henderson static TCGHelperInfo info_helper_st32_mmu = { 9018429a1caSRichard Henderson .flags = TCG_CALL_NO_WG, 9028429a1caSRichard Henderson .typemask = dh_typemask(void, 0) 9038429a1caSRichard Henderson | dh_typemask(env, 1) 90424e46e6cSRichard Henderson | dh_typemask(i64, 2) /* uint64_t addr */ 9058429a1caSRichard Henderson | dh_typemask(i32, 3) /* uint32_t data */ 9068429a1caSRichard Henderson | dh_typemask(i32, 4) /* unsigned oi */ 9078429a1caSRichard Henderson | dh_typemask(ptr, 5) /* uintptr_t ra */ 9088429a1caSRichard Henderson }; 9098429a1caSRichard Henderson 9108429a1caSRichard Henderson static TCGHelperInfo info_helper_st64_mmu = { 9118429a1caSRichard Henderson .flags = TCG_CALL_NO_WG, 9128429a1caSRichard Henderson .typemask = dh_typemask(void, 0) 9138429a1caSRichard Henderson | dh_typemask(env, 1) 91424e46e6cSRichard Henderson | dh_typemask(i64, 2) /* uint64_t addr */ 9158429a1caSRichard Henderson | dh_typemask(i64, 3) /* uint64_t data */ 9168429a1caSRichard Henderson | dh_typemask(i32, 4) /* unsigned oi */ 9178429a1caSRichard Henderson | dh_typemask(ptr, 5) /* uintptr_t ra */ 9188429a1caSRichard Henderson }; 9198429a1caSRichard Henderson 920ebebea53SRichard Henderson static TCGHelperInfo info_helper_st128_mmu = { 921ebebea53SRichard Henderson .flags = TCG_CALL_NO_WG, 922ebebea53SRichard Henderson .typemask = dh_typemask(void, 0) 923ebebea53SRichard Henderson | dh_typemask(env, 1) 92424e46e6cSRichard Henderson | dh_typemask(i64, 2) /* uint64_t addr */ 925ebebea53SRichard Henderson | dh_typemask(i128, 3) /* Int128 data */ 926ebebea53SRichard Henderson | dh_typemask(i32, 4) /* unsigned oi */ 927ebebea53SRichard Henderson | dh_typemask(ptr, 5) /* uintptr_t ra */ 928ebebea53SRichard Henderson }; 929ebebea53SRichard Henderson 93022f15579SRichard Henderson #ifdef CONFIG_TCG_INTERPRETER 931c6ef8c7bSPhilippe Mathieu-Daudé static ffi_type *typecode_to_ffi(int argmask) 932c6ef8c7bSPhilippe Mathieu-Daudé { 933e9709e17SRichard Henderson /* 934e9709e17SRichard Henderson * libffi does not support __int128_t, so we have forced Int128 935e9709e17SRichard Henderson * to use the structure definition instead of the builtin type. 936e9709e17SRichard Henderson */ 937e9709e17SRichard Henderson static ffi_type *ffi_type_i128_elements[3] = { 938e9709e17SRichard Henderson &ffi_type_uint64, 939e9709e17SRichard Henderson &ffi_type_uint64, 940e9709e17SRichard Henderson NULL 941e9709e17SRichard Henderson }; 942e9709e17SRichard Henderson static ffi_type ffi_type_i128 = { 943e9709e17SRichard Henderson .size = 16, 944e9709e17SRichard Henderson .alignment = __alignof__(Int128), 945e9709e17SRichard Henderson .type = FFI_TYPE_STRUCT, 946e9709e17SRichard Henderson .elements = ffi_type_i128_elements, 947e9709e17SRichard Henderson }; 948e9709e17SRichard Henderson 949c6ef8c7bSPhilippe Mathieu-Daudé switch (argmask) { 950c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_void: 951c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_void; 952c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_i32: 953c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_uint32; 954c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_s32: 955c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_sint32; 956c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_i64: 957c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_uint64; 958c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_s64: 959c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_sint64; 960c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_ptr: 961c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_pointer; 962e9709e17SRichard Henderson case dh_typecode_i128: 963e9709e17SRichard Henderson return &ffi_type_i128; 964c6ef8c7bSPhilippe Mathieu-Daudé } 965c6ef8c7bSPhilippe Mathieu-Daudé g_assert_not_reached(); 966c6ef8c7bSPhilippe Mathieu-Daudé } 9670c22e176SPhilippe Mathieu-Daudé 968d53106c9SRichard Henderson static ffi_cif *init_ffi_layout(TCGHelperInfo *info) 9690c22e176SPhilippe Mathieu-Daudé { 970f9c4bb80SRichard Henderson unsigned typemask = info->typemask; 9710c22e176SPhilippe Mathieu-Daudé struct { 9720c22e176SPhilippe Mathieu-Daudé ffi_cif cif; 9730c22e176SPhilippe Mathieu-Daudé ffi_type *args[]; 9740c22e176SPhilippe Mathieu-Daudé } *ca; 9750c22e176SPhilippe Mathieu-Daudé ffi_status status; 9760c22e176SPhilippe Mathieu-Daudé int nargs; 9770c22e176SPhilippe Mathieu-Daudé 9780c22e176SPhilippe Mathieu-Daudé /* Ignoring the return type, find the last non-zero field. */ 9790c22e176SPhilippe Mathieu-Daudé nargs = 32 - clz32(typemask >> 3); 9800c22e176SPhilippe Mathieu-Daudé nargs = DIV_ROUND_UP(nargs, 3); 981e9709e17SRichard Henderson assert(nargs <= MAX_CALL_IARGS); 9820c22e176SPhilippe Mathieu-Daudé 9830c22e176SPhilippe Mathieu-Daudé ca = g_malloc0(sizeof(*ca) + nargs * sizeof(ffi_type *)); 9840c22e176SPhilippe Mathieu-Daudé ca->cif.rtype = typecode_to_ffi(typemask & 7); 9850c22e176SPhilippe Mathieu-Daudé ca->cif.nargs = nargs; 9860c22e176SPhilippe Mathieu-Daudé 9870c22e176SPhilippe Mathieu-Daudé if (nargs != 0) { 9880c22e176SPhilippe Mathieu-Daudé ca->cif.arg_types = ca->args; 9890c22e176SPhilippe Mathieu-Daudé for (int j = 0; j < nargs; ++j) { 9900c22e176SPhilippe Mathieu-Daudé int typecode = extract32(typemask, (j + 1) * 3, 3); 9910c22e176SPhilippe Mathieu-Daudé ca->args[j] = typecode_to_ffi(typecode); 9920c22e176SPhilippe Mathieu-Daudé } 9930c22e176SPhilippe Mathieu-Daudé } 9940c22e176SPhilippe Mathieu-Daudé 9950c22e176SPhilippe Mathieu-Daudé status = ffi_prep_cif(&ca->cif, FFI_DEFAULT_ABI, nargs, 9960c22e176SPhilippe Mathieu-Daudé ca->cif.rtype, ca->cif.arg_types); 9970c22e176SPhilippe Mathieu-Daudé assert(status == FFI_OK); 9980c22e176SPhilippe Mathieu-Daudé 999d53106c9SRichard Henderson return &ca->cif; 10000c22e176SPhilippe Mathieu-Daudé } 1001f9c4bb80SRichard Henderson 1002d53106c9SRichard Henderson #define HELPER_INFO_INIT(I) (&(I)->cif) 1003d53106c9SRichard Henderson #define HELPER_INFO_INIT_VAL(I) init_ffi_layout(I) 1004d53106c9SRichard Henderson #else 1005d53106c9SRichard Henderson #define HELPER_INFO_INIT(I) (&(I)->init) 1006d53106c9SRichard Henderson #define HELPER_INFO_INIT_VAL(I) 1 10070c22e176SPhilippe Mathieu-Daudé #endif /* CONFIG_TCG_INTERPRETER */ 100822f15579SRichard Henderson 1009338b61e9SRichard Henderson static inline bool arg_slot_reg_p(unsigned arg_slot) 1010338b61e9SRichard Henderson { 1011338b61e9SRichard Henderson /* 1012338b61e9SRichard Henderson * Split the sizeof away from the comparison to avoid Werror from 1013338b61e9SRichard Henderson * "unsigned < 0 is always false", when iarg_regs is empty. 1014338b61e9SRichard Henderson */ 1015338b61e9SRichard Henderson unsigned nreg = ARRAY_SIZE(tcg_target_call_iarg_regs); 1016338b61e9SRichard Henderson return arg_slot < nreg; 1017338b61e9SRichard Henderson } 1018338b61e9SRichard Henderson 1019d78e4a4fSRichard Henderson static inline int arg_slot_stk_ofs(unsigned arg_slot) 1020d78e4a4fSRichard Henderson { 1021d78e4a4fSRichard Henderson unsigned max = TCG_STATIC_CALL_ARGS_SIZE / sizeof(tcg_target_long); 1022d78e4a4fSRichard Henderson unsigned stk_slot = arg_slot - ARRAY_SIZE(tcg_target_call_iarg_regs); 1023d78e4a4fSRichard Henderson 1024d78e4a4fSRichard Henderson tcg_debug_assert(stk_slot < max); 1025d78e4a4fSRichard Henderson return TCG_TARGET_CALL_STACK_OFFSET + stk_slot * sizeof(tcg_target_long); 1026d78e4a4fSRichard Henderson } 1027d78e4a4fSRichard Henderson 102839004a71SRichard Henderson typedef struct TCGCumulativeArgs { 102939004a71SRichard Henderson int arg_idx; /* tcg_gen_callN args[] */ 103039004a71SRichard Henderson int info_in_idx; /* TCGHelperInfo in[] */ 103139004a71SRichard Henderson int arg_slot; /* regs+stack slot */ 103239004a71SRichard Henderson int ref_slot; /* stack slots for references */ 103339004a71SRichard Henderson } TCGCumulativeArgs; 103439004a71SRichard Henderson 103539004a71SRichard Henderson static void layout_arg_even(TCGCumulativeArgs *cum) 103639004a71SRichard Henderson { 103739004a71SRichard Henderson cum->arg_slot += cum->arg_slot & 1; 103839004a71SRichard Henderson } 103939004a71SRichard Henderson 104039004a71SRichard Henderson static void layout_arg_1(TCGCumulativeArgs *cum, TCGHelperInfo *info, 104139004a71SRichard Henderson TCGCallArgumentKind kind) 104239004a71SRichard Henderson { 104339004a71SRichard Henderson TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx]; 104439004a71SRichard Henderson 104539004a71SRichard Henderson *loc = (TCGCallArgumentLoc){ 104639004a71SRichard Henderson .kind = kind, 104739004a71SRichard Henderson .arg_idx = cum->arg_idx, 104839004a71SRichard Henderson .arg_slot = cum->arg_slot, 104939004a71SRichard Henderson }; 105039004a71SRichard Henderson cum->info_in_idx++; 105139004a71SRichard Henderson cum->arg_slot++; 105239004a71SRichard Henderson } 105339004a71SRichard Henderson 105439004a71SRichard Henderson static void layout_arg_normal_n(TCGCumulativeArgs *cum, 105539004a71SRichard Henderson TCGHelperInfo *info, int n) 105639004a71SRichard Henderson { 105739004a71SRichard Henderson TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx]; 105839004a71SRichard Henderson 105939004a71SRichard Henderson for (int i = 0; i < n; ++i) { 106039004a71SRichard Henderson /* Layout all using the same arg_idx, adjusting the subindex. */ 106139004a71SRichard Henderson loc[i] = (TCGCallArgumentLoc){ 106239004a71SRichard Henderson .kind = TCG_CALL_ARG_NORMAL, 106339004a71SRichard Henderson .arg_idx = cum->arg_idx, 106439004a71SRichard Henderson .tmp_subindex = i, 106539004a71SRichard Henderson .arg_slot = cum->arg_slot + i, 106639004a71SRichard Henderson }; 106739004a71SRichard Henderson } 106839004a71SRichard Henderson cum->info_in_idx += n; 106939004a71SRichard Henderson cum->arg_slot += n; 107039004a71SRichard Henderson } 107139004a71SRichard Henderson 1072313bdea8SRichard Henderson static void layout_arg_by_ref(TCGCumulativeArgs *cum, TCGHelperInfo *info) 1073313bdea8SRichard Henderson { 1074313bdea8SRichard Henderson TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx]; 1075313bdea8SRichard Henderson int n = 128 / TCG_TARGET_REG_BITS; 1076313bdea8SRichard Henderson 1077313bdea8SRichard Henderson /* The first subindex carries the pointer. */ 1078313bdea8SRichard Henderson layout_arg_1(cum, info, TCG_CALL_ARG_BY_REF); 1079313bdea8SRichard Henderson 1080313bdea8SRichard Henderson /* 1081313bdea8SRichard Henderson * The callee is allowed to clobber memory associated with 1082313bdea8SRichard Henderson * structure pass by-reference. Therefore we must make copies. 1083313bdea8SRichard Henderson * Allocate space from "ref_slot", which will be adjusted to 1084313bdea8SRichard Henderson * follow the parameters on the stack. 1085313bdea8SRichard Henderson */ 1086313bdea8SRichard Henderson loc[0].ref_slot = cum->ref_slot; 1087313bdea8SRichard Henderson 1088313bdea8SRichard Henderson /* 1089313bdea8SRichard Henderson * Subsequent words also go into the reference slot, but 1090313bdea8SRichard Henderson * do not accumulate into the regular arguments. 1091313bdea8SRichard Henderson */ 1092313bdea8SRichard Henderson for (int i = 1; i < n; ++i) { 1093313bdea8SRichard Henderson loc[i] = (TCGCallArgumentLoc){ 1094313bdea8SRichard Henderson .kind = TCG_CALL_ARG_BY_REF_N, 1095313bdea8SRichard Henderson .arg_idx = cum->arg_idx, 1096313bdea8SRichard Henderson .tmp_subindex = i, 1097313bdea8SRichard Henderson .ref_slot = cum->ref_slot + i, 1098313bdea8SRichard Henderson }; 1099313bdea8SRichard Henderson } 1100e18ed26cSRichard Henderson cum->info_in_idx += n - 1; /* i=0 accounted for in layout_arg_1 */ 1101313bdea8SRichard Henderson cum->ref_slot += n; 1102313bdea8SRichard Henderson } 1103313bdea8SRichard Henderson 110439004a71SRichard Henderson static void init_call_layout(TCGHelperInfo *info) 110539004a71SRichard Henderson { 110639004a71SRichard Henderson int max_reg_slots = ARRAY_SIZE(tcg_target_call_iarg_regs); 110739004a71SRichard Henderson int max_stk_slots = TCG_STATIC_CALL_ARGS_SIZE / sizeof(tcg_target_long); 110839004a71SRichard Henderson unsigned typemask = info->typemask; 110939004a71SRichard Henderson unsigned typecode; 111039004a71SRichard Henderson TCGCumulativeArgs cum = { }; 111139004a71SRichard Henderson 111239004a71SRichard Henderson /* 111339004a71SRichard Henderson * Parse and place any function return value. 111439004a71SRichard Henderson */ 111539004a71SRichard Henderson typecode = typemask & 7; 111639004a71SRichard Henderson switch (typecode) { 111739004a71SRichard Henderson case dh_typecode_void: 111839004a71SRichard Henderson info->nr_out = 0; 111939004a71SRichard Henderson break; 112039004a71SRichard Henderson case dh_typecode_i32: 112139004a71SRichard Henderson case dh_typecode_s32: 112239004a71SRichard Henderson case dh_typecode_ptr: 112339004a71SRichard Henderson info->nr_out = 1; 112439004a71SRichard Henderson info->out_kind = TCG_CALL_RET_NORMAL; 112539004a71SRichard Henderson break; 112639004a71SRichard Henderson case dh_typecode_i64: 112739004a71SRichard Henderson case dh_typecode_s64: 112839004a71SRichard Henderson info->nr_out = 64 / TCG_TARGET_REG_BITS; 112939004a71SRichard Henderson info->out_kind = TCG_CALL_RET_NORMAL; 11305e3d0c19SRichard Henderson /* Query the last register now to trigger any assert early. */ 11315e3d0c19SRichard Henderson tcg_target_call_oarg_reg(info->out_kind, info->nr_out - 1); 1132466d3759SRichard Henderson break; 1133466d3759SRichard Henderson case dh_typecode_i128: 1134466d3759SRichard Henderson info->nr_out = 128 / TCG_TARGET_REG_BITS; 11355427a9a7SRichard Henderson info->out_kind = TCG_TARGET_CALL_RET_I128; 11365427a9a7SRichard Henderson switch (TCG_TARGET_CALL_RET_I128) { 1137466d3759SRichard Henderson case TCG_CALL_RET_NORMAL: 11385e3d0c19SRichard Henderson /* Query the last register now to trigger any assert early. */ 11395e3d0c19SRichard Henderson tcg_target_call_oarg_reg(info->out_kind, info->nr_out - 1); 1140466d3759SRichard Henderson break; 1141c6556aa0SRichard Henderson case TCG_CALL_RET_BY_VEC: 1142c6556aa0SRichard Henderson /* Query the single register now to trigger any assert early. */ 1143c6556aa0SRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0); 1144c6556aa0SRichard Henderson break; 1145313bdea8SRichard Henderson case TCG_CALL_RET_BY_REF: 1146313bdea8SRichard Henderson /* 1147313bdea8SRichard Henderson * Allocate the first argument to the output. 1148313bdea8SRichard Henderson * We don't need to store this anywhere, just make it 1149313bdea8SRichard Henderson * unavailable for use in the input loop below. 1150313bdea8SRichard Henderson */ 1151313bdea8SRichard Henderson cum.arg_slot = 1; 1152313bdea8SRichard Henderson break; 1153466d3759SRichard Henderson default: 1154466d3759SRichard Henderson qemu_build_not_reached(); 1155466d3759SRichard Henderson } 115639004a71SRichard Henderson break; 115739004a71SRichard Henderson default: 115839004a71SRichard Henderson g_assert_not_reached(); 115939004a71SRichard Henderson } 116039004a71SRichard Henderson 116139004a71SRichard Henderson /* 116239004a71SRichard Henderson * Parse and place function arguments. 116339004a71SRichard Henderson */ 116439004a71SRichard Henderson for (typemask >>= 3; typemask; typemask >>= 3, cum.arg_idx++) { 116539004a71SRichard Henderson TCGCallArgumentKind kind; 116639004a71SRichard Henderson TCGType type; 116739004a71SRichard Henderson 116839004a71SRichard Henderson typecode = typemask & 7; 116939004a71SRichard Henderson switch (typecode) { 117039004a71SRichard Henderson case dh_typecode_i32: 117139004a71SRichard Henderson case dh_typecode_s32: 117239004a71SRichard Henderson type = TCG_TYPE_I32; 117339004a71SRichard Henderson break; 117439004a71SRichard Henderson case dh_typecode_i64: 117539004a71SRichard Henderson case dh_typecode_s64: 117639004a71SRichard Henderson type = TCG_TYPE_I64; 117739004a71SRichard Henderson break; 117839004a71SRichard Henderson case dh_typecode_ptr: 117939004a71SRichard Henderson type = TCG_TYPE_PTR; 118039004a71SRichard Henderson break; 1181466d3759SRichard Henderson case dh_typecode_i128: 1182466d3759SRichard Henderson type = TCG_TYPE_I128; 1183466d3759SRichard Henderson break; 118439004a71SRichard Henderson default: 118539004a71SRichard Henderson g_assert_not_reached(); 118639004a71SRichard Henderson } 118739004a71SRichard Henderson 118839004a71SRichard Henderson switch (type) { 118939004a71SRichard Henderson case TCG_TYPE_I32: 119039004a71SRichard Henderson switch (TCG_TARGET_CALL_ARG_I32) { 119139004a71SRichard Henderson case TCG_CALL_ARG_EVEN: 119239004a71SRichard Henderson layout_arg_even(&cum); 119339004a71SRichard Henderson /* fall through */ 119439004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 119539004a71SRichard Henderson layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL); 119639004a71SRichard Henderson break; 119739004a71SRichard Henderson case TCG_CALL_ARG_EXTEND: 119839004a71SRichard Henderson kind = TCG_CALL_ARG_EXTEND_U + (typecode & 1); 119939004a71SRichard Henderson layout_arg_1(&cum, info, kind); 120039004a71SRichard Henderson break; 120139004a71SRichard Henderson default: 120239004a71SRichard Henderson qemu_build_not_reached(); 120339004a71SRichard Henderson } 120439004a71SRichard Henderson break; 120539004a71SRichard Henderson 120639004a71SRichard Henderson case TCG_TYPE_I64: 120739004a71SRichard Henderson switch (TCG_TARGET_CALL_ARG_I64) { 120839004a71SRichard Henderson case TCG_CALL_ARG_EVEN: 120939004a71SRichard Henderson layout_arg_even(&cum); 121039004a71SRichard Henderson /* fall through */ 121139004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 121239004a71SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 121339004a71SRichard Henderson layout_arg_normal_n(&cum, info, 2); 121439004a71SRichard Henderson } else { 121539004a71SRichard Henderson layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL); 121639004a71SRichard Henderson } 121739004a71SRichard Henderson break; 121839004a71SRichard Henderson default: 121939004a71SRichard Henderson qemu_build_not_reached(); 122039004a71SRichard Henderson } 122139004a71SRichard Henderson break; 122239004a71SRichard Henderson 1223466d3759SRichard Henderson case TCG_TYPE_I128: 12245427a9a7SRichard Henderson switch (TCG_TARGET_CALL_ARG_I128) { 1225466d3759SRichard Henderson case TCG_CALL_ARG_EVEN: 1226466d3759SRichard Henderson layout_arg_even(&cum); 1227466d3759SRichard Henderson /* fall through */ 1228466d3759SRichard Henderson case TCG_CALL_ARG_NORMAL: 1229466d3759SRichard Henderson layout_arg_normal_n(&cum, info, 128 / TCG_TARGET_REG_BITS); 1230466d3759SRichard Henderson break; 1231313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF: 1232313bdea8SRichard Henderson layout_arg_by_ref(&cum, info); 1233313bdea8SRichard Henderson break; 1234466d3759SRichard Henderson default: 1235466d3759SRichard Henderson qemu_build_not_reached(); 1236466d3759SRichard Henderson } 1237466d3759SRichard Henderson break; 1238466d3759SRichard Henderson 123939004a71SRichard Henderson default: 124039004a71SRichard Henderson g_assert_not_reached(); 124139004a71SRichard Henderson } 124239004a71SRichard Henderson } 124339004a71SRichard Henderson info->nr_in = cum.info_in_idx; 124439004a71SRichard Henderson 124539004a71SRichard Henderson /* Validate that we didn't overrun the input array. */ 124639004a71SRichard Henderson assert(cum.info_in_idx <= ARRAY_SIZE(info->in)); 124739004a71SRichard Henderson /* Validate the backend has enough argument space. */ 124839004a71SRichard Henderson assert(cum.arg_slot <= max_reg_slots + max_stk_slots); 1249313bdea8SRichard Henderson 1250313bdea8SRichard Henderson /* 1251313bdea8SRichard Henderson * Relocate the "ref_slot" area to the end of the parameters. 1252313bdea8SRichard Henderson * Minimizing this stack offset helps code size for x86, 1253313bdea8SRichard Henderson * which has a signed 8-bit offset encoding. 1254313bdea8SRichard Henderson */ 1255313bdea8SRichard Henderson if (cum.ref_slot != 0) { 1256313bdea8SRichard Henderson int ref_base = 0; 1257313bdea8SRichard Henderson 1258313bdea8SRichard Henderson if (cum.arg_slot > max_reg_slots) { 1259313bdea8SRichard Henderson int align = __alignof(Int128) / sizeof(tcg_target_long); 1260313bdea8SRichard Henderson 1261313bdea8SRichard Henderson ref_base = cum.arg_slot - max_reg_slots; 1262313bdea8SRichard Henderson if (align > 1) { 1263313bdea8SRichard Henderson ref_base = ROUND_UP(ref_base, align); 1264313bdea8SRichard Henderson } 1265313bdea8SRichard Henderson } 1266313bdea8SRichard Henderson assert(ref_base + cum.ref_slot <= max_stk_slots); 1267d78e4a4fSRichard Henderson ref_base += max_reg_slots; 1268313bdea8SRichard Henderson 1269313bdea8SRichard Henderson if (ref_base != 0) { 1270313bdea8SRichard Henderson for (int i = cum.info_in_idx - 1; i >= 0; --i) { 1271313bdea8SRichard Henderson TCGCallArgumentLoc *loc = &info->in[i]; 1272313bdea8SRichard Henderson switch (loc->kind) { 1273313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF: 1274313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF_N: 1275313bdea8SRichard Henderson loc->ref_slot += ref_base; 1276313bdea8SRichard Henderson break; 1277313bdea8SRichard Henderson default: 1278313bdea8SRichard Henderson break; 1279313bdea8SRichard Henderson } 1280313bdea8SRichard Henderson } 1281313bdea8SRichard Henderson } 1282313bdea8SRichard Henderson } 128339004a71SRichard Henderson } 128439004a71SRichard Henderson 128591478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)]; 1286f69d277eSRichard Henderson static void process_op_defs(TCGContext *s); 12871c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type, 12881c2adb95SRichard Henderson TCGReg reg, const char *name); 128991478cefSRichard Henderson 129043b972b7SRichard Henderson static void tcg_context_init(unsigned max_cpus) 1291c896fe29Sbellard { 1292a76aabd3SRichard Henderson TCGContext *s = &tcg_init_ctx; 1293100b5e01SRichard Henderson int op, total_args, n, i; 1294c896fe29Sbellard TCGOpDef *def; 1295c896fe29Sbellard TCGArgConstraint *args_ct; 12961c2adb95SRichard Henderson TCGTemp *ts; 1297c896fe29Sbellard 1298c896fe29Sbellard memset(s, 0, sizeof(*s)); 1299c896fe29Sbellard s->nb_globals = 0; 1300c896fe29Sbellard 1301c896fe29Sbellard /* Count total number of arguments and allocate the corresponding 1302c896fe29Sbellard space */ 1303c896fe29Sbellard total_args = 0; 1304c896fe29Sbellard for(op = 0; op < NB_OPS; op++) { 1305c896fe29Sbellard def = &tcg_op_defs[op]; 1306c896fe29Sbellard n = def->nb_iargs + def->nb_oargs; 1307c896fe29Sbellard total_args += n; 1308c896fe29Sbellard } 1309c896fe29Sbellard 1310bc2b17e6SRichard Henderson args_ct = g_new0(TCGArgConstraint, total_args); 1311c896fe29Sbellard 1312c896fe29Sbellard for(op = 0; op < NB_OPS; op++) { 1313c896fe29Sbellard def = &tcg_op_defs[op]; 1314c896fe29Sbellard def->args_ct = args_ct; 1315c896fe29Sbellard n = def->nb_iargs + def->nb_oargs; 1316c896fe29Sbellard args_ct += n; 1317c896fe29Sbellard } 1318c896fe29Sbellard 13198429a1caSRichard Henderson init_call_layout(&info_helper_ld32_mmu); 13208429a1caSRichard Henderson init_call_layout(&info_helper_ld64_mmu); 1321ebebea53SRichard Henderson init_call_layout(&info_helper_ld128_mmu); 13228429a1caSRichard Henderson init_call_layout(&info_helper_st32_mmu); 13238429a1caSRichard Henderson init_call_layout(&info_helper_st64_mmu); 1324ebebea53SRichard Henderson init_call_layout(&info_helper_st128_mmu); 13258429a1caSRichard Henderson 1326c896fe29Sbellard tcg_target_init(s); 1327f69d277eSRichard Henderson process_op_defs(s); 132891478cefSRichard Henderson 132991478cefSRichard Henderson /* Reverse the order of the saved registers, assuming they're all at 133091478cefSRichard Henderson the start of tcg_target_reg_alloc_order. */ 133191478cefSRichard Henderson for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) { 133291478cefSRichard Henderson int r = tcg_target_reg_alloc_order[n]; 133391478cefSRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) { 133491478cefSRichard Henderson break; 133591478cefSRichard Henderson } 133691478cefSRichard Henderson } 133791478cefSRichard Henderson for (i = 0; i < n; ++i) { 133891478cefSRichard Henderson indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i]; 133991478cefSRichard Henderson } 134091478cefSRichard Henderson for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) { 134191478cefSRichard Henderson indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i]; 134291478cefSRichard Henderson } 1343b1311c4aSEmilio G. Cota 134438b47b19SEmilio G. Cota alloc_tcg_plugin_context(s); 134538b47b19SEmilio G. Cota 1346b1311c4aSEmilio G. Cota tcg_ctx = s; 13473468b59eSEmilio G. Cota /* 13483468b59eSEmilio G. Cota * In user-mode we simply share the init context among threads, since we 13493468b59eSEmilio G. Cota * use a single region. See the documentation tcg_region_init() for the 13503468b59eSEmilio G. Cota * reasoning behind this. 13513468b59eSEmilio G. Cota * In softmmu we will have at most max_cpus TCG threads. 13523468b59eSEmilio G. Cota */ 13533468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY 1354df2cce29SEmilio G. Cota tcg_ctxs = &tcg_ctx; 13550e2d61cfSRichard Henderson tcg_cur_ctxs = 1; 13560e2d61cfSRichard Henderson tcg_max_ctxs = 1; 13573468b59eSEmilio G. Cota #else 13580e2d61cfSRichard Henderson tcg_max_ctxs = max_cpus; 13590e2d61cfSRichard Henderson tcg_ctxs = g_new0(TCGContext *, max_cpus); 13603468b59eSEmilio G. Cota #endif 13611c2adb95SRichard Henderson 13621c2adb95SRichard Henderson tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0)); 13631c2adb95SRichard Henderson ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env"); 1364ad75a51eSRichard Henderson tcg_env = temp_tcgv_ptr(ts); 13659002ec79SRichard Henderson } 1366b03cce8eSbellard 136743b972b7SRichard Henderson void tcg_init(size_t tb_size, int splitwx, unsigned max_cpus) 1368a76aabd3SRichard Henderson { 136943b972b7SRichard Henderson tcg_context_init(max_cpus); 137043b972b7SRichard Henderson tcg_region_init(tb_size, splitwx, max_cpus); 1371a76aabd3SRichard Henderson } 1372a76aabd3SRichard Henderson 13736e3b2bfdSEmilio G. Cota /* 13746e3b2bfdSEmilio G. Cota * Allocate TBs right before their corresponding translated code, making 13756e3b2bfdSEmilio G. Cota * sure that TBs and code are on different cache lines. 13766e3b2bfdSEmilio G. Cota */ 13776e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s) 13786e3b2bfdSEmilio G. Cota { 13796e3b2bfdSEmilio G. Cota uintptr_t align = qemu_icache_linesize; 13806e3b2bfdSEmilio G. Cota TranslationBlock *tb; 13816e3b2bfdSEmilio G. Cota void *next; 13826e3b2bfdSEmilio G. Cota 1383e8feb96fSEmilio G. Cota retry: 13846e3b2bfdSEmilio G. Cota tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align); 13856e3b2bfdSEmilio G. Cota next = (void *)ROUND_UP((uintptr_t)(tb + 1), align); 13866e3b2bfdSEmilio G. Cota 13876e3b2bfdSEmilio G. Cota if (unlikely(next > s->code_gen_highwater)) { 1388e8feb96fSEmilio G. Cota if (tcg_region_alloc(s)) { 13896e3b2bfdSEmilio G. Cota return NULL; 13906e3b2bfdSEmilio G. Cota } 1391e8feb96fSEmilio G. Cota goto retry; 1392e8feb96fSEmilio G. Cota } 1393d73415a3SStefan Hajnoczi qatomic_set(&s->code_gen_ptr, next); 139457a26946SRichard Henderson s->data_gen_ptr = NULL; 13956e3b2bfdSEmilio G. Cota return tb; 13966e3b2bfdSEmilio G. Cota } 13976e3b2bfdSEmilio G. Cota 1398*935f75aeSRichard Henderson void tcg_prologue_init(void) 13999002ec79SRichard Henderson { 1400*935f75aeSRichard Henderson TCGContext *s = tcg_ctx; 1401b0a0794aSRichard Henderson size_t prologue_size; 14028163b749SRichard Henderson 1403b0a0794aSRichard Henderson s->code_ptr = s->code_gen_ptr; 1404b0a0794aSRichard Henderson s->code_buf = s->code_gen_ptr; 14055b38ee31SRichard Henderson s->data_gen_ptr = NULL; 1406b91ccb31SRichard Henderson 1407b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 1408b0a0794aSRichard Henderson tcg_qemu_tb_exec = (tcg_prologue_fn *)tcg_splitwx_to_rx(s->code_ptr); 1409b91ccb31SRichard Henderson #endif 14108163b749SRichard Henderson 14115b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 14125b38ee31SRichard Henderson s->pool_labels = NULL; 14135b38ee31SRichard Henderson #endif 14145b38ee31SRichard Henderson 1415653b87ebSRoman Bolshakov qemu_thread_jit_write(); 14168163b749SRichard Henderson /* Generate the prologue. */ 1417b03cce8eSbellard tcg_target_qemu_prologue(s); 14185b38ee31SRichard Henderson 14195b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 14205b38ee31SRichard Henderson /* Allow the prologue to put e.g. guest_base into a pool entry. */ 14215b38ee31SRichard Henderson { 14221768987bSRichard Henderson int result = tcg_out_pool_finalize(s); 14231768987bSRichard Henderson tcg_debug_assert(result == 0); 14245b38ee31SRichard Henderson } 14255b38ee31SRichard Henderson #endif 14265b38ee31SRichard Henderson 1427b0a0794aSRichard Henderson prologue_size = tcg_current_code_size(s); 14285584e2dbSIlya Leoshkevich perf_report_prologue(s->code_gen_ptr, prologue_size); 1429b0a0794aSRichard Henderson 1430df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 1431b0a0794aSRichard Henderson flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf), 1432b0a0794aSRichard Henderson (uintptr_t)s->code_buf, prologue_size); 1433df5d2b16SRichard Henderson #endif 14348163b749SRichard Henderson 1435d6b64b2bSRichard Henderson if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) { 1436c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock(); 143778b54858SRichard Henderson if (logfile) { 143878b54858SRichard Henderson fprintf(logfile, "PROLOGUE: [size=%zu]\n", prologue_size); 14395b38ee31SRichard Henderson if (s->data_gen_ptr) { 1440b0a0794aSRichard Henderson size_t code_size = s->data_gen_ptr - s->code_gen_ptr; 14415b38ee31SRichard Henderson size_t data_size = prologue_size - code_size; 14425b38ee31SRichard Henderson size_t i; 14435b38ee31SRichard Henderson 144478b54858SRichard Henderson disas(logfile, s->code_gen_ptr, code_size); 14455b38ee31SRichard Henderson 14465b38ee31SRichard Henderson for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) { 14475b38ee31SRichard Henderson if (sizeof(tcg_target_ulong) == 8) { 144878b54858SRichard Henderson fprintf(logfile, 144978b54858SRichard Henderson "0x%08" PRIxPTR ": .quad 0x%016" PRIx64 "\n", 14505b38ee31SRichard Henderson (uintptr_t)s->data_gen_ptr + i, 14515b38ee31SRichard Henderson *(uint64_t *)(s->data_gen_ptr + i)); 14525b38ee31SRichard Henderson } else { 145378b54858SRichard Henderson fprintf(logfile, 145478b54858SRichard Henderson "0x%08" PRIxPTR ": .long 0x%08x\n", 14555b38ee31SRichard Henderson (uintptr_t)s->data_gen_ptr + i, 14565b38ee31SRichard Henderson *(uint32_t *)(s->data_gen_ptr + i)); 14575b38ee31SRichard Henderson } 14585b38ee31SRichard Henderson } 14595b38ee31SRichard Henderson } else { 146078b54858SRichard Henderson disas(logfile, s->code_gen_ptr, prologue_size); 14615b38ee31SRichard Henderson } 146278b54858SRichard Henderson fprintf(logfile, "\n"); 1463fc59d2d8SRobert Foley qemu_log_unlock(logfile); 1464d6b64b2bSRichard Henderson } 146578b54858SRichard Henderson } 1466cedbcb01SEmilio G. Cota 14676eea0434SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 14686eea0434SRichard Henderson /* 14696eea0434SRichard Henderson * Assert that goto_ptr is implemented completely, setting an epilogue. 14706eea0434SRichard Henderson * For tci, we use NULL as the signal to return from the interpreter, 14716eea0434SRichard Henderson * so skip this check. 14726eea0434SRichard Henderson */ 14738b5c2b62SRichard Henderson tcg_debug_assert(tcg_code_gen_epilogue != NULL); 14746eea0434SRichard Henderson #endif 1475d1c74ab3SRichard Henderson 1476d1c74ab3SRichard Henderson tcg_region_prologue_set(s); 1477c896fe29Sbellard } 1478c896fe29Sbellard 1479c896fe29Sbellard void tcg_func_start(TCGContext *s) 1480c896fe29Sbellard { 1481c896fe29Sbellard tcg_pool_reset(s); 1482c896fe29Sbellard s->nb_temps = s->nb_globals; 14830ec9eabcSRichard Henderson 14840ec9eabcSRichard Henderson /* No temps have been previously allocated for size or locality. */ 14850ec9eabcSRichard Henderson memset(s->free_temps, 0, sizeof(s->free_temps)); 14860ec9eabcSRichard Henderson 1487c0522136SRichard Henderson /* No constant temps have been previously allocated. */ 1488c0522136SRichard Henderson for (int i = 0; i < TCG_TYPE_COUNT; ++i) { 1489c0522136SRichard Henderson if (s->const_table[i]) { 1490c0522136SRichard Henderson g_hash_table_remove_all(s->const_table[i]); 1491c0522136SRichard Henderson } 1492c0522136SRichard Henderson } 1493c0522136SRichard Henderson 1494abebf925SRichard Henderson s->nb_ops = 0; 1495c896fe29Sbellard s->nb_labels = 0; 1496c896fe29Sbellard s->current_frame_offset = s->frame_start; 1497c896fe29Sbellard 14980a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG 14990a209d4bSRichard Henderson s->goto_tb_issue_mask = 0; 15000a209d4bSRichard Henderson #endif 15010a209d4bSRichard Henderson 150215fa08f8SRichard Henderson QTAILQ_INIT(&s->ops); 150315fa08f8SRichard Henderson QTAILQ_INIT(&s->free_ops); 1504bef16ab4SRichard Henderson QSIMPLEQ_INIT(&s->labels); 15054baf3978SRichard Henderson 15064baf3978SRichard Henderson tcg_debug_assert(s->addr_type == TCG_TYPE_I32 || 15074baf3978SRichard Henderson s->addr_type == TCG_TYPE_I64); 1508d0a9bb5eSRichard Henderson 1509747bd69dSRichard Henderson tcg_debug_assert(s->insn_start_words > 0); 1510c896fe29Sbellard } 1511c896fe29Sbellard 1512ae30e866SRichard Henderson static TCGTemp *tcg_temp_alloc(TCGContext *s) 15137ca4b752SRichard Henderson { 15147ca4b752SRichard Henderson int n = s->nb_temps++; 1515ae30e866SRichard Henderson 1516ae30e866SRichard Henderson if (n >= TCG_MAX_TEMPS) { 1517db6b7d0cSRichard Henderson tcg_raise_tb_overflow(s); 1518ae30e866SRichard Henderson } 15197ca4b752SRichard Henderson return memset(&s->temps[n], 0, sizeof(TCGTemp)); 15207ca4b752SRichard Henderson } 15217ca4b752SRichard Henderson 1522ae30e866SRichard Henderson static TCGTemp *tcg_global_alloc(TCGContext *s) 15237ca4b752SRichard Henderson { 1524fa477d25SRichard Henderson TCGTemp *ts; 1525fa477d25SRichard Henderson 15267ca4b752SRichard Henderson tcg_debug_assert(s->nb_globals == s->nb_temps); 1527ae30e866SRichard Henderson tcg_debug_assert(s->nb_globals < TCG_MAX_TEMPS); 15287ca4b752SRichard Henderson s->nb_globals++; 1529fa477d25SRichard Henderson ts = tcg_temp_alloc(s); 1530ee17db83SRichard Henderson ts->kind = TEMP_GLOBAL; 1531fa477d25SRichard Henderson 1532fa477d25SRichard Henderson return ts; 1533c896fe29Sbellard } 1534c896fe29Sbellard 1535085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type, 1536b6638662SRichard Henderson TCGReg reg, const char *name) 1537c896fe29Sbellard { 1538c896fe29Sbellard TCGTemp *ts; 1539c896fe29Sbellard 15401a057554SRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 64 || type == TCG_TYPE_I32); 15417ca4b752SRichard Henderson 15427ca4b752SRichard Henderson ts = tcg_global_alloc(s); 1543c896fe29Sbellard ts->base_type = type; 1544c896fe29Sbellard ts->type = type; 1545ee17db83SRichard Henderson ts->kind = TEMP_FIXED; 1546c896fe29Sbellard ts->reg = reg; 1547c896fe29Sbellard ts->name = name; 1548c896fe29Sbellard tcg_regset_set_reg(s->reserved_regs, reg); 15497ca4b752SRichard Henderson 1550085272b3SRichard Henderson return ts; 1551a7812ae4Spbrook } 1552a7812ae4Spbrook 1553b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size) 1554a7812ae4Spbrook { 1555b3a62939SRichard Henderson s->frame_start = start; 1556b3a62939SRichard Henderson s->frame_end = start + size; 1557085272b3SRichard Henderson s->frame_temp 1558085272b3SRichard Henderson = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame"); 1559b3a62939SRichard Henderson } 1560a7812ae4Spbrook 1561085272b3SRichard Henderson TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base, 1562e1ccc054SRichard Henderson intptr_t offset, const char *name) 1563c896fe29Sbellard { 1564b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1565dc41aa7dSRichard Henderson TCGTemp *base_ts = tcgv_ptr_temp(base); 15667ca4b752SRichard Henderson TCGTemp *ts = tcg_global_alloc(s); 1567aef85402SRichard Henderson int indirect_reg = 0; 1568c896fe29Sbellard 1569c0522136SRichard Henderson switch (base_ts->kind) { 1570c0522136SRichard Henderson case TEMP_FIXED: 1571c0522136SRichard Henderson break; 1572c0522136SRichard Henderson case TEMP_GLOBAL: 15735a18407fSRichard Henderson /* We do not support double-indirect registers. */ 15745a18407fSRichard Henderson tcg_debug_assert(!base_ts->indirect_reg); 1575b3915dbbSRichard Henderson base_ts->indirect_base = 1; 15765a18407fSRichard Henderson s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64 15775a18407fSRichard Henderson ? 2 : 1); 15785a18407fSRichard Henderson indirect_reg = 1; 1579c0522136SRichard Henderson break; 1580c0522136SRichard Henderson default: 1581c0522136SRichard Henderson g_assert_not_reached(); 1582b3915dbbSRichard Henderson } 1583b3915dbbSRichard Henderson 15847ca4b752SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { 15857ca4b752SRichard Henderson TCGTemp *ts2 = tcg_global_alloc(s); 1586c896fe29Sbellard char buf[64]; 15877ca4b752SRichard Henderson 15887ca4b752SRichard Henderson ts->base_type = TCG_TYPE_I64; 1589c896fe29Sbellard ts->type = TCG_TYPE_I32; 1590b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg; 1591c896fe29Sbellard ts->mem_allocated = 1; 1592b3a62939SRichard Henderson ts->mem_base = base_ts; 1593aef85402SRichard Henderson ts->mem_offset = offset; 1594c896fe29Sbellard pstrcpy(buf, sizeof(buf), name); 1595c896fe29Sbellard pstrcat(buf, sizeof(buf), "_0"); 1596c896fe29Sbellard ts->name = strdup(buf); 1597c896fe29Sbellard 15987ca4b752SRichard Henderson tcg_debug_assert(ts2 == ts + 1); 15997ca4b752SRichard Henderson ts2->base_type = TCG_TYPE_I64; 16007ca4b752SRichard Henderson ts2->type = TCG_TYPE_I32; 1601b3915dbbSRichard Henderson ts2->indirect_reg = indirect_reg; 16027ca4b752SRichard Henderson ts2->mem_allocated = 1; 16037ca4b752SRichard Henderson ts2->mem_base = base_ts; 1604aef85402SRichard Henderson ts2->mem_offset = offset + 4; 1605fac87bd2SRichard Henderson ts2->temp_subindex = 1; 1606c896fe29Sbellard pstrcpy(buf, sizeof(buf), name); 1607c896fe29Sbellard pstrcat(buf, sizeof(buf), "_1"); 1608120c1084SRichard Henderson ts2->name = strdup(buf); 16097ca4b752SRichard Henderson } else { 1610c896fe29Sbellard ts->base_type = type; 1611c896fe29Sbellard ts->type = type; 1612b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg; 1613c896fe29Sbellard ts->mem_allocated = 1; 1614b3a62939SRichard Henderson ts->mem_base = base_ts; 1615c896fe29Sbellard ts->mem_offset = offset; 1616c896fe29Sbellard ts->name = name; 1617c896fe29Sbellard } 1618085272b3SRichard Henderson return ts; 1619c896fe29Sbellard } 1620c896fe29Sbellard 1621bbf989bfSRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, TCGTempKind kind) 1622c896fe29Sbellard { 1623b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1624c896fe29Sbellard TCGTemp *ts; 1625e1c08b00SRichard Henderson int n; 1626c896fe29Sbellard 1627e1c08b00SRichard Henderson if (kind == TEMP_EBB) { 1628e1c08b00SRichard Henderson int idx = find_first_bit(s->free_temps[type].l, TCG_MAX_TEMPS); 1629e1c08b00SRichard Henderson 16300ec9eabcSRichard Henderson if (idx < TCG_MAX_TEMPS) { 16310ec9eabcSRichard Henderson /* There is already an available temp with the right type. */ 1632e1c08b00SRichard Henderson clear_bit(idx, s->free_temps[type].l); 16330ec9eabcSRichard Henderson 1634e8996ee0Sbellard ts = &s->temps[idx]; 1635e8996ee0Sbellard ts->temp_allocated = 1; 16367ca4b752SRichard Henderson tcg_debug_assert(ts->base_type == type); 1637ee17db83SRichard Henderson tcg_debug_assert(ts->kind == kind); 16382f2e911dSRichard Henderson return ts; 1639e1c08b00SRichard Henderson } 1640e8996ee0Sbellard } else { 1641e1c08b00SRichard Henderson tcg_debug_assert(kind == TEMP_TB); 1642e1c08b00SRichard Henderson } 164343eef72fSRichard Henderson 164443eef72fSRichard Henderson switch (type) { 164543eef72fSRichard Henderson case TCG_TYPE_I32: 164643eef72fSRichard Henderson case TCG_TYPE_V64: 164743eef72fSRichard Henderson case TCG_TYPE_V128: 164843eef72fSRichard Henderson case TCG_TYPE_V256: 164943eef72fSRichard Henderson n = 1; 165043eef72fSRichard Henderson break; 165143eef72fSRichard Henderson case TCG_TYPE_I64: 165243eef72fSRichard Henderson n = 64 / TCG_TARGET_REG_BITS; 165343eef72fSRichard Henderson break; 165443eef72fSRichard Henderson case TCG_TYPE_I128: 165543eef72fSRichard Henderson n = 128 / TCG_TARGET_REG_BITS; 165643eef72fSRichard Henderson break; 165743eef72fSRichard Henderson default: 165843eef72fSRichard Henderson g_assert_not_reached(); 165943eef72fSRichard Henderson } 166043eef72fSRichard Henderson 16617ca4b752SRichard Henderson ts = tcg_temp_alloc(s); 166243eef72fSRichard Henderson ts->base_type = type; 166343eef72fSRichard Henderson ts->temp_allocated = 1; 166443eef72fSRichard Henderson ts->kind = kind; 166543eef72fSRichard Henderson 166643eef72fSRichard Henderson if (n == 1) { 166743eef72fSRichard Henderson ts->type = type; 166843eef72fSRichard Henderson } else { 166943eef72fSRichard Henderson ts->type = TCG_TYPE_REG; 167043eef72fSRichard Henderson 1671e1c08b00SRichard Henderson for (int i = 1; i < n; ++i) { 16727ca4b752SRichard Henderson TCGTemp *ts2 = tcg_temp_alloc(s); 16737ca4b752SRichard Henderson 167443eef72fSRichard Henderson tcg_debug_assert(ts2 == ts + i); 167543eef72fSRichard Henderson ts2->base_type = type; 167643eef72fSRichard Henderson ts2->type = TCG_TYPE_REG; 16777ca4b752SRichard Henderson ts2->temp_allocated = 1; 167843eef72fSRichard Henderson ts2->temp_subindex = i; 1679ee17db83SRichard Henderson ts2->kind = kind; 168043eef72fSRichard Henderson } 1681c896fe29Sbellard } 1682085272b3SRichard Henderson return ts; 1683c896fe29Sbellard } 1684c896fe29Sbellard 1685d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type) 1686d2fd745fSRichard Henderson { 1687d2fd745fSRichard Henderson TCGTemp *t; 1688d2fd745fSRichard Henderson 1689d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG 1690d2fd745fSRichard Henderson switch (type) { 1691d2fd745fSRichard Henderson case TCG_TYPE_V64: 1692d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v64); 1693d2fd745fSRichard Henderson break; 1694d2fd745fSRichard Henderson case TCG_TYPE_V128: 1695d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v128); 1696d2fd745fSRichard Henderson break; 1697d2fd745fSRichard Henderson case TCG_TYPE_V256: 1698d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v256); 1699d2fd745fSRichard Henderson break; 1700d2fd745fSRichard Henderson default: 1701d2fd745fSRichard Henderson g_assert_not_reached(); 1702d2fd745fSRichard Henderson } 1703d2fd745fSRichard Henderson #endif 1704d2fd745fSRichard Henderson 1705bbf989bfSRichard Henderson t = tcg_temp_new_internal(type, TEMP_EBB); 1706d2fd745fSRichard Henderson return temp_tcgv_vec(t); 1707d2fd745fSRichard Henderson } 1708d2fd745fSRichard Henderson 1709d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp. */ 1710d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match) 1711d2fd745fSRichard Henderson { 1712d2fd745fSRichard Henderson TCGTemp *t = tcgv_vec_temp(match); 1713d2fd745fSRichard Henderson 1714d2fd745fSRichard Henderson tcg_debug_assert(t->temp_allocated != 0); 1715d2fd745fSRichard Henderson 1716bbf989bfSRichard Henderson t = tcg_temp_new_internal(t->base_type, TEMP_EBB); 1717d2fd745fSRichard Henderson return temp_tcgv_vec(t); 1718d2fd745fSRichard Henderson } 1719d2fd745fSRichard Henderson 17205bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts) 1721c896fe29Sbellard { 1722b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1723c896fe29Sbellard 1724c7482438SRichard Henderson switch (ts->kind) { 1725c7482438SRichard Henderson case TEMP_CONST: 1726f57c6915SRichard Henderson case TEMP_TB: 17272f2e911dSRichard Henderson /* Silently ignore free. */ 1728c7482438SRichard Henderson break; 17292f2e911dSRichard Henderson case TEMP_EBB: 1730eabb7b91SAurelien Jarno tcg_debug_assert(ts->temp_allocated != 0); 1731e8996ee0Sbellard ts->temp_allocated = 0; 17322f2e911dSRichard Henderson set_bit(temp_idx(ts), s->free_temps[ts->base_type].l); 17332f2e911dSRichard Henderson break; 17342f2e911dSRichard Henderson default: 17352f2e911dSRichard Henderson /* It never made sense to free TEMP_FIXED or TEMP_GLOBAL. */ 17362f2e911dSRichard Henderson g_assert_not_reached(); 1737e1c08b00SRichard Henderson } 1738e8996ee0Sbellard } 1739e8996ee0Sbellard 1740c0522136SRichard Henderson TCGTemp *tcg_constant_internal(TCGType type, int64_t val) 1741c0522136SRichard Henderson { 1742c0522136SRichard Henderson TCGContext *s = tcg_ctx; 1743c0522136SRichard Henderson GHashTable *h = s->const_table[type]; 1744c0522136SRichard Henderson TCGTemp *ts; 1745c0522136SRichard Henderson 1746c0522136SRichard Henderson if (h == NULL) { 1747c0522136SRichard Henderson h = g_hash_table_new(g_int64_hash, g_int64_equal); 1748c0522136SRichard Henderson s->const_table[type] = h; 1749c0522136SRichard Henderson } 1750c0522136SRichard Henderson 1751c0522136SRichard Henderson ts = g_hash_table_lookup(h, &val); 1752c0522136SRichard Henderson if (ts == NULL) { 1753aef85402SRichard Henderson int64_t *val_ptr; 1754aef85402SRichard Henderson 1755c0522136SRichard Henderson ts = tcg_temp_alloc(s); 1756c0522136SRichard Henderson 1757c0522136SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { 1758c0522136SRichard Henderson TCGTemp *ts2 = tcg_temp_alloc(s); 1759c0522136SRichard Henderson 1760aef85402SRichard Henderson tcg_debug_assert(ts2 == ts + 1); 1761aef85402SRichard Henderson 1762c0522136SRichard Henderson ts->base_type = TCG_TYPE_I64; 1763c0522136SRichard Henderson ts->type = TCG_TYPE_I32; 1764c0522136SRichard Henderson ts->kind = TEMP_CONST; 1765c0522136SRichard Henderson ts->temp_allocated = 1; 1766c0522136SRichard Henderson 1767c0522136SRichard Henderson ts2->base_type = TCG_TYPE_I64; 1768c0522136SRichard Henderson ts2->type = TCG_TYPE_I32; 1769c0522136SRichard Henderson ts2->kind = TEMP_CONST; 1770c0522136SRichard Henderson ts2->temp_allocated = 1; 1771fac87bd2SRichard Henderson ts2->temp_subindex = 1; 1772aef85402SRichard Henderson 1773aef85402SRichard Henderson /* 1774aef85402SRichard Henderson * Retain the full value of the 64-bit constant in the low 1775aef85402SRichard Henderson * part, so that the hash table works. Actual uses will 1776aef85402SRichard Henderson * truncate the value to the low part. 1777aef85402SRichard Henderson */ 1778aef85402SRichard Henderson ts[HOST_BIG_ENDIAN].val = val; 1779aef85402SRichard Henderson ts[!HOST_BIG_ENDIAN].val = val >> 32; 1780aef85402SRichard Henderson val_ptr = &ts[HOST_BIG_ENDIAN].val; 1781c0522136SRichard Henderson } else { 1782c0522136SRichard Henderson ts->base_type = type; 1783c0522136SRichard Henderson ts->type = type; 1784c0522136SRichard Henderson ts->kind = TEMP_CONST; 1785c0522136SRichard Henderson ts->temp_allocated = 1; 1786c0522136SRichard Henderson ts->val = val; 1787aef85402SRichard Henderson val_ptr = &ts->val; 1788c0522136SRichard Henderson } 1789aef85402SRichard Henderson g_hash_table_insert(h, val_ptr, ts); 1790c0522136SRichard Henderson } 1791c0522136SRichard Henderson 1792c0522136SRichard Henderson return ts; 1793c0522136SRichard Henderson } 1794c0522136SRichard Henderson 1795c0522136SRichard Henderson TCGv_vec tcg_constant_vec(TCGType type, unsigned vece, int64_t val) 1796c0522136SRichard Henderson { 1797c0522136SRichard Henderson val = dup_const(vece, val); 1798c0522136SRichard Henderson return temp_tcgv_vec(tcg_constant_internal(type, val)); 1799c0522136SRichard Henderson } 1800c0522136SRichard Henderson 180188d4005bSRichard Henderson TCGv_vec tcg_constant_vec_matching(TCGv_vec match, unsigned vece, int64_t val) 180288d4005bSRichard Henderson { 180388d4005bSRichard Henderson TCGTemp *t = tcgv_vec_temp(match); 180488d4005bSRichard Henderson 180588d4005bSRichard Henderson tcg_debug_assert(t->temp_allocated != 0); 180688d4005bSRichard Henderson return tcg_constant_vec(t->base_type, vece, val); 180788d4005bSRichard Henderson } 180888d4005bSRichard Henderson 1809177f648fSRichard Henderson #ifdef CONFIG_DEBUG_TCG 1810177f648fSRichard Henderson size_t temp_idx(TCGTemp *ts) 1811177f648fSRichard Henderson { 1812177f648fSRichard Henderson ptrdiff_t n = ts - tcg_ctx->temps; 1813177f648fSRichard Henderson assert(n >= 0 && n < tcg_ctx->nb_temps); 1814177f648fSRichard Henderson return n; 1815177f648fSRichard Henderson } 1816177f648fSRichard Henderson 1817177f648fSRichard Henderson TCGTemp *tcgv_i32_temp(TCGv_i32 v) 1818177f648fSRichard Henderson { 1819177f648fSRichard Henderson uintptr_t o = (uintptr_t)v - offsetof(TCGContext, temps); 1820177f648fSRichard Henderson 1821177f648fSRichard Henderson assert(o < sizeof(TCGTemp) * tcg_ctx->nb_temps); 1822177f648fSRichard Henderson assert(o % sizeof(TCGTemp) == 0); 1823177f648fSRichard Henderson 1824177f648fSRichard Henderson return (void *)tcg_ctx + (uintptr_t)v; 1825177f648fSRichard Henderson } 1826177f648fSRichard Henderson #endif /* CONFIG_DEBUG_TCG */ 1827177f648fSRichard Henderson 1828be0f34b5SRichard Henderson /* Return true if OP may appear in the opcode stream. 1829be0f34b5SRichard Henderson Test the runtime variable that controls each opcode. */ 1830be0f34b5SRichard Henderson bool tcg_op_supported(TCGOpcode op) 1831be0f34b5SRichard Henderson { 1832d2fd745fSRichard Henderson const bool have_vec 1833d2fd745fSRichard Henderson = TCG_TARGET_HAS_v64 | TCG_TARGET_HAS_v128 | TCG_TARGET_HAS_v256; 1834d2fd745fSRichard Henderson 1835be0f34b5SRichard Henderson switch (op) { 1836be0f34b5SRichard Henderson case INDEX_op_discard: 1837be0f34b5SRichard Henderson case INDEX_op_set_label: 1838be0f34b5SRichard Henderson case INDEX_op_call: 1839be0f34b5SRichard Henderson case INDEX_op_br: 1840be0f34b5SRichard Henderson case INDEX_op_mb: 1841be0f34b5SRichard Henderson case INDEX_op_insn_start: 1842be0f34b5SRichard Henderson case INDEX_op_exit_tb: 1843be0f34b5SRichard Henderson case INDEX_op_goto_tb: 1844f4e01e30SRichard Henderson case INDEX_op_goto_ptr: 1845fecccfccSRichard Henderson case INDEX_op_qemu_ld_a32_i32: 1846fecccfccSRichard Henderson case INDEX_op_qemu_ld_a64_i32: 1847fecccfccSRichard Henderson case INDEX_op_qemu_st_a32_i32: 1848fecccfccSRichard Henderson case INDEX_op_qemu_st_a64_i32: 1849fecccfccSRichard Henderson case INDEX_op_qemu_ld_a32_i64: 1850fecccfccSRichard Henderson case INDEX_op_qemu_ld_a64_i64: 1851fecccfccSRichard Henderson case INDEX_op_qemu_st_a32_i64: 1852fecccfccSRichard Henderson case INDEX_op_qemu_st_a64_i64: 1853be0f34b5SRichard Henderson return true; 1854be0f34b5SRichard Henderson 1855fecccfccSRichard Henderson case INDEX_op_qemu_st8_a32_i32: 1856fecccfccSRichard Henderson case INDEX_op_qemu_st8_a64_i32: 185707ce0b05SRichard Henderson return TCG_TARGET_HAS_qemu_st8_i32; 185807ce0b05SRichard Henderson 1859fecccfccSRichard Henderson case INDEX_op_qemu_ld_a32_i128: 1860fecccfccSRichard Henderson case INDEX_op_qemu_ld_a64_i128: 1861fecccfccSRichard Henderson case INDEX_op_qemu_st_a32_i128: 1862fecccfccSRichard Henderson case INDEX_op_qemu_st_a64_i128: 186312fde9bcSRichard Henderson return TCG_TARGET_HAS_qemu_ldst_i128; 186412fde9bcSRichard Henderson 1865be0f34b5SRichard Henderson case INDEX_op_mov_i32: 1866be0f34b5SRichard Henderson case INDEX_op_setcond_i32: 1867be0f34b5SRichard Henderson case INDEX_op_brcond_i32: 1868be0f34b5SRichard Henderson case INDEX_op_ld8u_i32: 1869be0f34b5SRichard Henderson case INDEX_op_ld8s_i32: 1870be0f34b5SRichard Henderson case INDEX_op_ld16u_i32: 1871be0f34b5SRichard Henderson case INDEX_op_ld16s_i32: 1872be0f34b5SRichard Henderson case INDEX_op_ld_i32: 1873be0f34b5SRichard Henderson case INDEX_op_st8_i32: 1874be0f34b5SRichard Henderson case INDEX_op_st16_i32: 1875be0f34b5SRichard Henderson case INDEX_op_st_i32: 1876be0f34b5SRichard Henderson case INDEX_op_add_i32: 1877be0f34b5SRichard Henderson case INDEX_op_sub_i32: 1878be0f34b5SRichard Henderson case INDEX_op_mul_i32: 1879be0f34b5SRichard Henderson case INDEX_op_and_i32: 1880be0f34b5SRichard Henderson case INDEX_op_or_i32: 1881be0f34b5SRichard Henderson case INDEX_op_xor_i32: 1882be0f34b5SRichard Henderson case INDEX_op_shl_i32: 1883be0f34b5SRichard Henderson case INDEX_op_shr_i32: 1884be0f34b5SRichard Henderson case INDEX_op_sar_i32: 1885be0f34b5SRichard Henderson return true; 1886be0f34b5SRichard Henderson 18873635502dSRichard Henderson case INDEX_op_negsetcond_i32: 18883635502dSRichard Henderson return TCG_TARGET_HAS_negsetcond_i32; 1889be0f34b5SRichard Henderson case INDEX_op_movcond_i32: 1890be0f34b5SRichard Henderson return TCG_TARGET_HAS_movcond_i32; 1891be0f34b5SRichard Henderson case INDEX_op_div_i32: 1892be0f34b5SRichard Henderson case INDEX_op_divu_i32: 1893be0f34b5SRichard Henderson return TCG_TARGET_HAS_div_i32; 1894be0f34b5SRichard Henderson case INDEX_op_rem_i32: 1895be0f34b5SRichard Henderson case INDEX_op_remu_i32: 1896be0f34b5SRichard Henderson return TCG_TARGET_HAS_rem_i32; 1897be0f34b5SRichard Henderson case INDEX_op_div2_i32: 1898be0f34b5SRichard Henderson case INDEX_op_divu2_i32: 1899be0f34b5SRichard Henderson return TCG_TARGET_HAS_div2_i32; 1900be0f34b5SRichard Henderson case INDEX_op_rotl_i32: 1901be0f34b5SRichard Henderson case INDEX_op_rotr_i32: 1902be0f34b5SRichard Henderson return TCG_TARGET_HAS_rot_i32; 1903be0f34b5SRichard Henderson case INDEX_op_deposit_i32: 1904be0f34b5SRichard Henderson return TCG_TARGET_HAS_deposit_i32; 1905be0f34b5SRichard Henderson case INDEX_op_extract_i32: 1906be0f34b5SRichard Henderson return TCG_TARGET_HAS_extract_i32; 1907be0f34b5SRichard Henderson case INDEX_op_sextract_i32: 1908be0f34b5SRichard Henderson return TCG_TARGET_HAS_sextract_i32; 1909fce1296fSRichard Henderson case INDEX_op_extract2_i32: 1910fce1296fSRichard Henderson return TCG_TARGET_HAS_extract2_i32; 1911be0f34b5SRichard Henderson case INDEX_op_add2_i32: 1912be0f34b5SRichard Henderson return TCG_TARGET_HAS_add2_i32; 1913be0f34b5SRichard Henderson case INDEX_op_sub2_i32: 1914be0f34b5SRichard Henderson return TCG_TARGET_HAS_sub2_i32; 1915be0f34b5SRichard Henderson case INDEX_op_mulu2_i32: 1916be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulu2_i32; 1917be0f34b5SRichard Henderson case INDEX_op_muls2_i32: 1918be0f34b5SRichard Henderson return TCG_TARGET_HAS_muls2_i32; 1919be0f34b5SRichard Henderson case INDEX_op_muluh_i32: 1920be0f34b5SRichard Henderson return TCG_TARGET_HAS_muluh_i32; 1921be0f34b5SRichard Henderson case INDEX_op_mulsh_i32: 1922be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulsh_i32; 1923be0f34b5SRichard Henderson case INDEX_op_ext8s_i32: 1924be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8s_i32; 1925be0f34b5SRichard Henderson case INDEX_op_ext16s_i32: 1926be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16s_i32; 1927be0f34b5SRichard Henderson case INDEX_op_ext8u_i32: 1928be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8u_i32; 1929be0f34b5SRichard Henderson case INDEX_op_ext16u_i32: 1930be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16u_i32; 1931be0f34b5SRichard Henderson case INDEX_op_bswap16_i32: 1932be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap16_i32; 1933be0f34b5SRichard Henderson case INDEX_op_bswap32_i32: 1934be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap32_i32; 1935be0f34b5SRichard Henderson case INDEX_op_not_i32: 1936be0f34b5SRichard Henderson return TCG_TARGET_HAS_not_i32; 1937be0f34b5SRichard Henderson case INDEX_op_neg_i32: 1938be0f34b5SRichard Henderson return TCG_TARGET_HAS_neg_i32; 1939be0f34b5SRichard Henderson case INDEX_op_andc_i32: 1940be0f34b5SRichard Henderson return TCG_TARGET_HAS_andc_i32; 1941be0f34b5SRichard Henderson case INDEX_op_orc_i32: 1942be0f34b5SRichard Henderson return TCG_TARGET_HAS_orc_i32; 1943be0f34b5SRichard Henderson case INDEX_op_eqv_i32: 1944be0f34b5SRichard Henderson return TCG_TARGET_HAS_eqv_i32; 1945be0f34b5SRichard Henderson case INDEX_op_nand_i32: 1946be0f34b5SRichard Henderson return TCG_TARGET_HAS_nand_i32; 1947be0f34b5SRichard Henderson case INDEX_op_nor_i32: 1948be0f34b5SRichard Henderson return TCG_TARGET_HAS_nor_i32; 1949be0f34b5SRichard Henderson case INDEX_op_clz_i32: 1950be0f34b5SRichard Henderson return TCG_TARGET_HAS_clz_i32; 1951be0f34b5SRichard Henderson case INDEX_op_ctz_i32: 1952be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctz_i32; 1953be0f34b5SRichard Henderson case INDEX_op_ctpop_i32: 1954be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctpop_i32; 1955be0f34b5SRichard Henderson 1956be0f34b5SRichard Henderson case INDEX_op_brcond2_i32: 1957be0f34b5SRichard Henderson case INDEX_op_setcond2_i32: 1958be0f34b5SRichard Henderson return TCG_TARGET_REG_BITS == 32; 1959be0f34b5SRichard Henderson 1960be0f34b5SRichard Henderson case INDEX_op_mov_i64: 1961be0f34b5SRichard Henderson case INDEX_op_setcond_i64: 1962be0f34b5SRichard Henderson case INDEX_op_brcond_i64: 1963be0f34b5SRichard Henderson case INDEX_op_ld8u_i64: 1964be0f34b5SRichard Henderson case INDEX_op_ld8s_i64: 1965be0f34b5SRichard Henderson case INDEX_op_ld16u_i64: 1966be0f34b5SRichard Henderson case INDEX_op_ld16s_i64: 1967be0f34b5SRichard Henderson case INDEX_op_ld32u_i64: 1968be0f34b5SRichard Henderson case INDEX_op_ld32s_i64: 1969be0f34b5SRichard Henderson case INDEX_op_ld_i64: 1970be0f34b5SRichard Henderson case INDEX_op_st8_i64: 1971be0f34b5SRichard Henderson case INDEX_op_st16_i64: 1972be0f34b5SRichard Henderson case INDEX_op_st32_i64: 1973be0f34b5SRichard Henderson case INDEX_op_st_i64: 1974be0f34b5SRichard Henderson case INDEX_op_add_i64: 1975be0f34b5SRichard Henderson case INDEX_op_sub_i64: 1976be0f34b5SRichard Henderson case INDEX_op_mul_i64: 1977be0f34b5SRichard Henderson case INDEX_op_and_i64: 1978be0f34b5SRichard Henderson case INDEX_op_or_i64: 1979be0f34b5SRichard Henderson case INDEX_op_xor_i64: 1980be0f34b5SRichard Henderson case INDEX_op_shl_i64: 1981be0f34b5SRichard Henderson case INDEX_op_shr_i64: 1982be0f34b5SRichard Henderson case INDEX_op_sar_i64: 1983be0f34b5SRichard Henderson case INDEX_op_ext_i32_i64: 1984be0f34b5SRichard Henderson case INDEX_op_extu_i32_i64: 1985be0f34b5SRichard Henderson return TCG_TARGET_REG_BITS == 64; 1986be0f34b5SRichard Henderson 19873635502dSRichard Henderson case INDEX_op_negsetcond_i64: 19883635502dSRichard Henderson return TCG_TARGET_HAS_negsetcond_i64; 1989be0f34b5SRichard Henderson case INDEX_op_movcond_i64: 1990be0f34b5SRichard Henderson return TCG_TARGET_HAS_movcond_i64; 1991be0f34b5SRichard Henderson case INDEX_op_div_i64: 1992be0f34b5SRichard Henderson case INDEX_op_divu_i64: 1993be0f34b5SRichard Henderson return TCG_TARGET_HAS_div_i64; 1994be0f34b5SRichard Henderson case INDEX_op_rem_i64: 1995be0f34b5SRichard Henderson case INDEX_op_remu_i64: 1996be0f34b5SRichard Henderson return TCG_TARGET_HAS_rem_i64; 1997be0f34b5SRichard Henderson case INDEX_op_div2_i64: 1998be0f34b5SRichard Henderson case INDEX_op_divu2_i64: 1999be0f34b5SRichard Henderson return TCG_TARGET_HAS_div2_i64; 2000be0f34b5SRichard Henderson case INDEX_op_rotl_i64: 2001be0f34b5SRichard Henderson case INDEX_op_rotr_i64: 2002be0f34b5SRichard Henderson return TCG_TARGET_HAS_rot_i64; 2003be0f34b5SRichard Henderson case INDEX_op_deposit_i64: 2004be0f34b5SRichard Henderson return TCG_TARGET_HAS_deposit_i64; 2005be0f34b5SRichard Henderson case INDEX_op_extract_i64: 2006be0f34b5SRichard Henderson return TCG_TARGET_HAS_extract_i64; 2007be0f34b5SRichard Henderson case INDEX_op_sextract_i64: 2008be0f34b5SRichard Henderson return TCG_TARGET_HAS_sextract_i64; 2009fce1296fSRichard Henderson case INDEX_op_extract2_i64: 2010fce1296fSRichard Henderson return TCG_TARGET_HAS_extract2_i64; 2011be0f34b5SRichard Henderson case INDEX_op_extrl_i64_i32: 2012be0f34b5SRichard Henderson case INDEX_op_extrh_i64_i32: 201313d885b0SRichard Henderson return TCG_TARGET_HAS_extr_i64_i32; 2014be0f34b5SRichard Henderson case INDEX_op_ext8s_i64: 2015be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8s_i64; 2016be0f34b5SRichard Henderson case INDEX_op_ext16s_i64: 2017be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16s_i64; 2018be0f34b5SRichard Henderson case INDEX_op_ext32s_i64: 2019be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext32s_i64; 2020be0f34b5SRichard Henderson case INDEX_op_ext8u_i64: 2021be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8u_i64; 2022be0f34b5SRichard Henderson case INDEX_op_ext16u_i64: 2023be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16u_i64; 2024be0f34b5SRichard Henderson case INDEX_op_ext32u_i64: 2025be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext32u_i64; 2026be0f34b5SRichard Henderson case INDEX_op_bswap16_i64: 2027be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap16_i64; 2028be0f34b5SRichard Henderson case INDEX_op_bswap32_i64: 2029be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap32_i64; 2030be0f34b5SRichard Henderson case INDEX_op_bswap64_i64: 2031be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap64_i64; 2032be0f34b5SRichard Henderson case INDEX_op_not_i64: 2033be0f34b5SRichard Henderson return TCG_TARGET_HAS_not_i64; 2034be0f34b5SRichard Henderson case INDEX_op_neg_i64: 2035be0f34b5SRichard Henderson return TCG_TARGET_HAS_neg_i64; 2036be0f34b5SRichard Henderson case INDEX_op_andc_i64: 2037be0f34b5SRichard Henderson return TCG_TARGET_HAS_andc_i64; 2038be0f34b5SRichard Henderson case INDEX_op_orc_i64: 2039be0f34b5SRichard Henderson return TCG_TARGET_HAS_orc_i64; 2040be0f34b5SRichard Henderson case INDEX_op_eqv_i64: 2041be0f34b5SRichard Henderson return TCG_TARGET_HAS_eqv_i64; 2042be0f34b5SRichard Henderson case INDEX_op_nand_i64: 2043be0f34b5SRichard Henderson return TCG_TARGET_HAS_nand_i64; 2044be0f34b5SRichard Henderson case INDEX_op_nor_i64: 2045be0f34b5SRichard Henderson return TCG_TARGET_HAS_nor_i64; 2046be0f34b5SRichard Henderson case INDEX_op_clz_i64: 2047be0f34b5SRichard Henderson return TCG_TARGET_HAS_clz_i64; 2048be0f34b5SRichard Henderson case INDEX_op_ctz_i64: 2049be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctz_i64; 2050be0f34b5SRichard Henderson case INDEX_op_ctpop_i64: 2051be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctpop_i64; 2052be0f34b5SRichard Henderson case INDEX_op_add2_i64: 2053be0f34b5SRichard Henderson return TCG_TARGET_HAS_add2_i64; 2054be0f34b5SRichard Henderson case INDEX_op_sub2_i64: 2055be0f34b5SRichard Henderson return TCG_TARGET_HAS_sub2_i64; 2056be0f34b5SRichard Henderson case INDEX_op_mulu2_i64: 2057be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulu2_i64; 2058be0f34b5SRichard Henderson case INDEX_op_muls2_i64: 2059be0f34b5SRichard Henderson return TCG_TARGET_HAS_muls2_i64; 2060be0f34b5SRichard Henderson case INDEX_op_muluh_i64: 2061be0f34b5SRichard Henderson return TCG_TARGET_HAS_muluh_i64; 2062be0f34b5SRichard Henderson case INDEX_op_mulsh_i64: 2063be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulsh_i64; 2064be0f34b5SRichard Henderson 2065d2fd745fSRichard Henderson case INDEX_op_mov_vec: 2066d2fd745fSRichard Henderson case INDEX_op_dup_vec: 206737ee55a0SRichard Henderson case INDEX_op_dupm_vec: 2068d2fd745fSRichard Henderson case INDEX_op_ld_vec: 2069d2fd745fSRichard Henderson case INDEX_op_st_vec: 2070d2fd745fSRichard Henderson case INDEX_op_add_vec: 2071d2fd745fSRichard Henderson case INDEX_op_sub_vec: 2072d2fd745fSRichard Henderson case INDEX_op_and_vec: 2073d2fd745fSRichard Henderson case INDEX_op_or_vec: 2074d2fd745fSRichard Henderson case INDEX_op_xor_vec: 2075212be173SRichard Henderson case INDEX_op_cmp_vec: 2076d2fd745fSRichard Henderson return have_vec; 2077d2fd745fSRichard Henderson case INDEX_op_dup2_vec: 2078d2fd745fSRichard Henderson return have_vec && TCG_TARGET_REG_BITS == 32; 2079d2fd745fSRichard Henderson case INDEX_op_not_vec: 2080d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_not_vec; 2081d2fd745fSRichard Henderson case INDEX_op_neg_vec: 2082d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_neg_vec; 2083bcefc902SRichard Henderson case INDEX_op_abs_vec: 2084bcefc902SRichard Henderson return have_vec && TCG_TARGET_HAS_abs_vec; 2085d2fd745fSRichard Henderson case INDEX_op_andc_vec: 2086d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_andc_vec; 2087d2fd745fSRichard Henderson case INDEX_op_orc_vec: 2088d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_orc_vec; 2089ed523473SRichard Henderson case INDEX_op_nand_vec: 2090ed523473SRichard Henderson return have_vec && TCG_TARGET_HAS_nand_vec; 2091ed523473SRichard Henderson case INDEX_op_nor_vec: 2092ed523473SRichard Henderson return have_vec && TCG_TARGET_HAS_nor_vec; 2093ed523473SRichard Henderson case INDEX_op_eqv_vec: 2094ed523473SRichard Henderson return have_vec && TCG_TARGET_HAS_eqv_vec; 20953774030aSRichard Henderson case INDEX_op_mul_vec: 20963774030aSRichard Henderson return have_vec && TCG_TARGET_HAS_mul_vec; 2097d0ec9796SRichard Henderson case INDEX_op_shli_vec: 2098d0ec9796SRichard Henderson case INDEX_op_shri_vec: 2099d0ec9796SRichard Henderson case INDEX_op_sari_vec: 2100d0ec9796SRichard Henderson return have_vec && TCG_TARGET_HAS_shi_vec; 2101d0ec9796SRichard Henderson case INDEX_op_shls_vec: 2102d0ec9796SRichard Henderson case INDEX_op_shrs_vec: 2103d0ec9796SRichard Henderson case INDEX_op_sars_vec: 2104d0ec9796SRichard Henderson return have_vec && TCG_TARGET_HAS_shs_vec; 2105d0ec9796SRichard Henderson case INDEX_op_shlv_vec: 2106d0ec9796SRichard Henderson case INDEX_op_shrv_vec: 2107d0ec9796SRichard Henderson case INDEX_op_sarv_vec: 2108d0ec9796SRichard Henderson return have_vec && TCG_TARGET_HAS_shv_vec; 2109b0f7e744SRichard Henderson case INDEX_op_rotli_vec: 2110b0f7e744SRichard Henderson return have_vec && TCG_TARGET_HAS_roti_vec; 211123850a74SRichard Henderson case INDEX_op_rotls_vec: 211223850a74SRichard Henderson return have_vec && TCG_TARGET_HAS_rots_vec; 21135d0ceda9SRichard Henderson case INDEX_op_rotlv_vec: 21145d0ceda9SRichard Henderson case INDEX_op_rotrv_vec: 21155d0ceda9SRichard Henderson return have_vec && TCG_TARGET_HAS_rotv_vec; 21168afaf050SRichard Henderson case INDEX_op_ssadd_vec: 21178afaf050SRichard Henderson case INDEX_op_usadd_vec: 21188afaf050SRichard Henderson case INDEX_op_sssub_vec: 21198afaf050SRichard Henderson case INDEX_op_ussub_vec: 21208afaf050SRichard Henderson return have_vec && TCG_TARGET_HAS_sat_vec; 2121dd0a0fcdSRichard Henderson case INDEX_op_smin_vec: 2122dd0a0fcdSRichard Henderson case INDEX_op_umin_vec: 2123dd0a0fcdSRichard Henderson case INDEX_op_smax_vec: 2124dd0a0fcdSRichard Henderson case INDEX_op_umax_vec: 2125dd0a0fcdSRichard Henderson return have_vec && TCG_TARGET_HAS_minmax_vec; 212638dc1294SRichard Henderson case INDEX_op_bitsel_vec: 212738dc1294SRichard Henderson return have_vec && TCG_TARGET_HAS_bitsel_vec; 2128f75da298SRichard Henderson case INDEX_op_cmpsel_vec: 2129f75da298SRichard Henderson return have_vec && TCG_TARGET_HAS_cmpsel_vec; 2130d2fd745fSRichard Henderson 2131db432672SRichard Henderson default: 2132db432672SRichard Henderson tcg_debug_assert(op > INDEX_op_last_generic && op < NB_OPS); 2133db432672SRichard Henderson return true; 2134be0f34b5SRichard Henderson } 2135be0f34b5SRichard Henderson } 2136be0f34b5SRichard Henderson 213739004a71SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs); 213839004a71SRichard Henderson 2139a3a692b8SRichard Henderson static void tcg_gen_callN(TCGHelperInfo *info, TCGTemp *ret, TCGTemp **args) 2140c896fe29Sbellard { 214139004a71SRichard Henderson TCGv_i64 extend_free[MAX_CALL_IARGS]; 214239004a71SRichard Henderson int n_extend = 0; 214375e8b9b7SRichard Henderson TCGOp *op; 214439004a71SRichard Henderson int i, n, pi = 0, total_args; 2145afb49896SRichard Henderson 2146d53106c9SRichard Henderson if (unlikely(g_once_init_enter(HELPER_INFO_INIT(info)))) { 2147d53106c9SRichard Henderson init_call_layout(info); 2148d53106c9SRichard Henderson g_once_init_leave(HELPER_INFO_INIT(info), HELPER_INFO_INIT_VAL(info)); 2149d53106c9SRichard Henderson } 2150d53106c9SRichard Henderson 215139004a71SRichard Henderson total_args = info->nr_out + info->nr_in + 2; 215239004a71SRichard Henderson op = tcg_op_alloc(INDEX_op_call, total_args); 21532bece2c8SRichard Henderson 215438b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN 215517083f6fSEmilio Cota /* Flag helpers that may affect guest state */ 215617083f6fSEmilio Cota if (tcg_ctx->plugin_insn && 215717083f6fSEmilio Cota !(info->flags & TCG_CALL_PLUGIN) && 215817083f6fSEmilio Cota !(info->flags & TCG_CALL_NO_SIDE_EFFECTS)) { 215938b47b19SEmilio G. Cota tcg_ctx->plugin_insn->calls_helpers = true; 216038b47b19SEmilio G. Cota } 216138b47b19SEmilio G. Cota #endif 216238b47b19SEmilio G. Cota 216339004a71SRichard Henderson TCGOP_CALLO(op) = n = info->nr_out; 216439004a71SRichard Henderson switch (n) { 216539004a71SRichard Henderson case 0: 216639004a71SRichard Henderson tcg_debug_assert(ret == NULL); 216739004a71SRichard Henderson break; 216839004a71SRichard Henderson case 1: 216939004a71SRichard Henderson tcg_debug_assert(ret != NULL); 217039004a71SRichard Henderson op->args[pi++] = temp_arg(ret); 217139004a71SRichard Henderson break; 217239004a71SRichard Henderson case 2: 2173466d3759SRichard Henderson case 4: 217439004a71SRichard Henderson tcg_debug_assert(ret != NULL); 2175466d3759SRichard Henderson tcg_debug_assert(ret->base_type == ret->type + ctz32(n)); 217639004a71SRichard Henderson tcg_debug_assert(ret->temp_subindex == 0); 2177466d3759SRichard Henderson for (i = 0; i < n; ++i) { 2178466d3759SRichard Henderson op->args[pi++] = temp_arg(ret + i); 2179466d3759SRichard Henderson } 218039004a71SRichard Henderson break; 218139004a71SRichard Henderson default: 218239004a71SRichard Henderson g_assert_not_reached(); 218339004a71SRichard Henderson } 21847319d83aSRichard Henderson 218539004a71SRichard Henderson TCGOP_CALLI(op) = n = info->nr_in; 218639004a71SRichard Henderson for (i = 0; i < n; i++) { 218739004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i]; 218839004a71SRichard Henderson TCGTemp *ts = args[loc->arg_idx] + loc->tmp_subindex; 218939004a71SRichard Henderson 219039004a71SRichard Henderson switch (loc->kind) { 219139004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 2192313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF: 2193313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF_N: 219439004a71SRichard Henderson op->args[pi++] = temp_arg(ts); 219539004a71SRichard Henderson break; 219639004a71SRichard Henderson 219739004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 219839004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 219939004a71SRichard Henderson { 22005dd48602SRichard Henderson TCGv_i64 temp = tcg_temp_ebb_new_i64(); 220139004a71SRichard Henderson TCGv_i32 orig = temp_tcgv_i32(ts); 220239004a71SRichard Henderson 220339004a71SRichard Henderson if (loc->kind == TCG_CALL_ARG_EXTEND_S) { 220418cf3d07SRichard Henderson tcg_gen_ext_i32_i64(temp, orig); 22052bece2c8SRichard Henderson } else { 220618cf3d07SRichard Henderson tcg_gen_extu_i32_i64(temp, orig); 22072bece2c8SRichard Henderson } 220839004a71SRichard Henderson op->args[pi++] = tcgv_i64_arg(temp); 220939004a71SRichard Henderson extend_free[n_extend++] = temp; 22102bece2c8SRichard Henderson } 221139004a71SRichard Henderson break; 22122bece2c8SRichard Henderson 2213e2a9dd6bSRichard Henderson default: 2214e2a9dd6bSRichard Henderson g_assert_not_reached(); 2215e2a9dd6bSRichard Henderson } 2216c896fe29Sbellard } 2217d53106c9SRichard Henderson op->args[pi++] = (uintptr_t)info->func; 22183e92aa34SRichard Henderson op->args[pi++] = (uintptr_t)info; 221939004a71SRichard Henderson tcg_debug_assert(pi == total_args); 2220a7812ae4Spbrook 222139004a71SRichard Henderson QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link); 22222bece2c8SRichard Henderson 222339004a71SRichard Henderson tcg_debug_assert(n_extend < ARRAY_SIZE(extend_free)); 222439004a71SRichard Henderson for (i = 0; i < n_extend; ++i) { 222539004a71SRichard Henderson tcg_temp_free_i64(extend_free[i]); 2226eb8b0224SRichard Henderson } 2227a7812ae4Spbrook } 2228c896fe29Sbellard 2229a3a692b8SRichard Henderson void tcg_gen_call0(TCGHelperInfo *info, TCGTemp *ret) 2230a3a692b8SRichard Henderson { 2231a3a692b8SRichard Henderson tcg_gen_callN(info, ret, NULL); 2232a3a692b8SRichard Henderson } 2233a3a692b8SRichard Henderson 2234a3a692b8SRichard Henderson void tcg_gen_call1(TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1) 2235a3a692b8SRichard Henderson { 2236a3a692b8SRichard Henderson tcg_gen_callN(info, ret, &t1); 2237a3a692b8SRichard Henderson } 2238a3a692b8SRichard Henderson 2239a3a692b8SRichard Henderson void tcg_gen_call2(TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1, TCGTemp *t2) 2240a3a692b8SRichard Henderson { 2241a3a692b8SRichard Henderson TCGTemp *args[2] = { t1, t2 }; 2242a3a692b8SRichard Henderson tcg_gen_callN(info, ret, args); 2243a3a692b8SRichard Henderson } 2244a3a692b8SRichard Henderson 2245a3a692b8SRichard Henderson void tcg_gen_call3(TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1, 2246a3a692b8SRichard Henderson TCGTemp *t2, TCGTemp *t3) 2247a3a692b8SRichard Henderson { 2248a3a692b8SRichard Henderson TCGTemp *args[3] = { t1, t2, t3 }; 2249a3a692b8SRichard Henderson tcg_gen_callN(info, ret, args); 2250a3a692b8SRichard Henderson } 2251a3a692b8SRichard Henderson 2252a3a692b8SRichard Henderson void tcg_gen_call4(TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1, 2253a3a692b8SRichard Henderson TCGTemp *t2, TCGTemp *t3, TCGTemp *t4) 2254a3a692b8SRichard Henderson { 2255a3a692b8SRichard Henderson TCGTemp *args[4] = { t1, t2, t3, t4 }; 2256a3a692b8SRichard Henderson tcg_gen_callN(info, ret, args); 2257a3a692b8SRichard Henderson } 2258a3a692b8SRichard Henderson 2259a3a692b8SRichard Henderson void tcg_gen_call5(TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1, 2260a3a692b8SRichard Henderson TCGTemp *t2, TCGTemp *t3, TCGTemp *t4, TCGTemp *t5) 2261a3a692b8SRichard Henderson { 2262a3a692b8SRichard Henderson TCGTemp *args[5] = { t1, t2, t3, t4, t5 }; 2263a3a692b8SRichard Henderson tcg_gen_callN(info, ret, args); 2264a3a692b8SRichard Henderson } 2265a3a692b8SRichard Henderson 2266a3a692b8SRichard Henderson void tcg_gen_call6(TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1, TCGTemp *t2, 2267a3a692b8SRichard Henderson TCGTemp *t3, TCGTemp *t4, TCGTemp *t5, TCGTemp *t6) 2268a3a692b8SRichard Henderson { 2269a3a692b8SRichard Henderson TCGTemp *args[6] = { t1, t2, t3, t4, t5, t6 }; 2270a3a692b8SRichard Henderson tcg_gen_callN(info, ret, args); 2271a3a692b8SRichard Henderson } 2272a3a692b8SRichard Henderson 2273a3a692b8SRichard Henderson void tcg_gen_call7(TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1, 2274a3a692b8SRichard Henderson TCGTemp *t2, TCGTemp *t3, TCGTemp *t4, 2275a3a692b8SRichard Henderson TCGTemp *t5, TCGTemp *t6, TCGTemp *t7) 2276a3a692b8SRichard Henderson { 2277a3a692b8SRichard Henderson TCGTemp *args[7] = { t1, t2, t3, t4, t5, t6, t7 }; 2278a3a692b8SRichard Henderson tcg_gen_callN(info, ret, args); 2279a3a692b8SRichard Henderson } 2280a3a692b8SRichard Henderson 22818fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s) 2282c896fe29Sbellard { 2283ac3b8891SRichard Henderson int i, n; 2284ac3b8891SRichard Henderson 2285ee17db83SRichard Henderson for (i = 0, n = s->nb_temps; i < n; i++) { 2286ee17db83SRichard Henderson TCGTemp *ts = &s->temps[i]; 2287ee17db83SRichard Henderson TCGTempVal val = TEMP_VAL_MEM; 2288ee17db83SRichard Henderson 2289ee17db83SRichard Henderson switch (ts->kind) { 2290c0522136SRichard Henderson case TEMP_CONST: 2291c0522136SRichard Henderson val = TEMP_VAL_CONST; 2292c0522136SRichard Henderson break; 2293ee17db83SRichard Henderson case TEMP_FIXED: 2294ee17db83SRichard Henderson val = TEMP_VAL_REG; 2295ee17db83SRichard Henderson break; 2296ee17db83SRichard Henderson case TEMP_GLOBAL: 2297ee17db83SRichard Henderson break; 2298c7482438SRichard Henderson case TEMP_EBB: 2299ee17db83SRichard Henderson val = TEMP_VAL_DEAD; 2300ee17db83SRichard Henderson /* fall through */ 2301f57c6915SRichard Henderson case TEMP_TB: 2302e8996ee0Sbellard ts->mem_allocated = 0; 2303ee17db83SRichard Henderson break; 2304ee17db83SRichard Henderson default: 2305ee17db83SRichard Henderson g_assert_not_reached(); 2306ee17db83SRichard Henderson } 2307ee17db83SRichard Henderson ts->val_type = val; 2308e8996ee0Sbellard } 2309f8b2f202SRichard Henderson 2310f8b2f202SRichard Henderson memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp)); 2311c896fe29Sbellard } 2312c896fe29Sbellard 2313f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size, 2314f8b2f202SRichard Henderson TCGTemp *ts) 2315c896fe29Sbellard { 23161807f4c4SRichard Henderson int idx = temp_idx(ts); 2317ac56dd48Spbrook 2318ee17db83SRichard Henderson switch (ts->kind) { 2319ee17db83SRichard Henderson case TEMP_FIXED: 2320ee17db83SRichard Henderson case TEMP_GLOBAL: 2321ac56dd48Spbrook pstrcpy(buf, buf_size, ts->name); 2322ee17db83SRichard Henderson break; 2323f57c6915SRichard Henderson case TEMP_TB: 2324641d5fbeSbellard snprintf(buf, buf_size, "loc%d", idx - s->nb_globals); 2325ee17db83SRichard Henderson break; 2326c7482438SRichard Henderson case TEMP_EBB: 2327ac56dd48Spbrook snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals); 2328ee17db83SRichard Henderson break; 2329c0522136SRichard Henderson case TEMP_CONST: 2330c0522136SRichard Henderson switch (ts->type) { 2331c0522136SRichard Henderson case TCG_TYPE_I32: 2332c0522136SRichard Henderson snprintf(buf, buf_size, "$0x%x", (int32_t)ts->val); 2333c0522136SRichard Henderson break; 2334c0522136SRichard Henderson #if TCG_TARGET_REG_BITS > 32 2335c0522136SRichard Henderson case TCG_TYPE_I64: 2336c0522136SRichard Henderson snprintf(buf, buf_size, "$0x%" PRIx64, ts->val); 2337c0522136SRichard Henderson break; 2338c0522136SRichard Henderson #endif 2339c0522136SRichard Henderson case TCG_TYPE_V64: 2340c0522136SRichard Henderson case TCG_TYPE_V128: 2341c0522136SRichard Henderson case TCG_TYPE_V256: 2342c0522136SRichard Henderson snprintf(buf, buf_size, "v%d$0x%" PRIx64, 2343c0522136SRichard Henderson 64 << (ts->type - TCG_TYPE_V64), ts->val); 2344c0522136SRichard Henderson break; 2345c0522136SRichard Henderson default: 2346c0522136SRichard Henderson g_assert_not_reached(); 2347c0522136SRichard Henderson } 2348c0522136SRichard Henderson break; 2349c896fe29Sbellard } 2350c896fe29Sbellard return buf; 2351c896fe29Sbellard } 2352c896fe29Sbellard 235343439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf, 235443439139SRichard Henderson int buf_size, TCGArg arg) 2355f8b2f202SRichard Henderson { 235643439139SRichard Henderson return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg)); 2357f8b2f202SRichard Henderson } 2358f8b2f202SRichard Henderson 2359f48f3edeSblueswir1 static const char * const cond_name[] = 2360f48f3edeSblueswir1 { 23610aed257fSRichard Henderson [TCG_COND_NEVER] = "never", 23620aed257fSRichard Henderson [TCG_COND_ALWAYS] = "always", 2363f48f3edeSblueswir1 [TCG_COND_EQ] = "eq", 2364f48f3edeSblueswir1 [TCG_COND_NE] = "ne", 2365f48f3edeSblueswir1 [TCG_COND_LT] = "lt", 2366f48f3edeSblueswir1 [TCG_COND_GE] = "ge", 2367f48f3edeSblueswir1 [TCG_COND_LE] = "le", 2368f48f3edeSblueswir1 [TCG_COND_GT] = "gt", 2369f48f3edeSblueswir1 [TCG_COND_LTU] = "ltu", 2370f48f3edeSblueswir1 [TCG_COND_GEU] = "geu", 2371f48f3edeSblueswir1 [TCG_COND_LEU] = "leu", 2372f48f3edeSblueswir1 [TCG_COND_GTU] = "gtu" 2373f48f3edeSblueswir1 }; 2374f48f3edeSblueswir1 237512fde9bcSRichard Henderson static const char * const ldst_name[(MO_BSWAP | MO_SSIZE) + 1] = 2376f713d6adSRichard Henderson { 2377f713d6adSRichard Henderson [MO_UB] = "ub", 2378f713d6adSRichard Henderson [MO_SB] = "sb", 2379f713d6adSRichard Henderson [MO_LEUW] = "leuw", 2380f713d6adSRichard Henderson [MO_LESW] = "lesw", 2381f713d6adSRichard Henderson [MO_LEUL] = "leul", 2382f713d6adSRichard Henderson [MO_LESL] = "lesl", 2383fc313c64SFrédéric Pétrot [MO_LEUQ] = "leq", 2384f713d6adSRichard Henderson [MO_BEUW] = "beuw", 2385f713d6adSRichard Henderson [MO_BESW] = "besw", 2386f713d6adSRichard Henderson [MO_BEUL] = "beul", 2387f713d6adSRichard Henderson [MO_BESL] = "besl", 2388fc313c64SFrédéric Pétrot [MO_BEUQ] = "beq", 238912fde9bcSRichard Henderson [MO_128 + MO_BE] = "beo", 239012fde9bcSRichard Henderson [MO_128 + MO_LE] = "leo", 2391f713d6adSRichard Henderson }; 2392f713d6adSRichard Henderson 23931f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = { 23941f00b27fSSergey Sorokin [MO_UNALN >> MO_ASHIFT] = "un+", 23951f00b27fSSergey Sorokin [MO_ALIGN >> MO_ASHIFT] = "al+", 23961f00b27fSSergey Sorokin [MO_ALIGN_2 >> MO_ASHIFT] = "al2+", 23971f00b27fSSergey Sorokin [MO_ALIGN_4 >> MO_ASHIFT] = "al4+", 23981f00b27fSSergey Sorokin [MO_ALIGN_8 >> MO_ASHIFT] = "al8+", 23991f00b27fSSergey Sorokin [MO_ALIGN_16 >> MO_ASHIFT] = "al16+", 24001f00b27fSSergey Sorokin [MO_ALIGN_32 >> MO_ASHIFT] = "al32+", 24011f00b27fSSergey Sorokin [MO_ALIGN_64 >> MO_ASHIFT] = "al64+", 24021f00b27fSSergey Sorokin }; 24031f00b27fSSergey Sorokin 240437031fefSRichard Henderson static const char * const atom_name[(MO_ATOM_MASK >> MO_ATOM_SHIFT) + 1] = { 240537031fefSRichard Henderson [MO_ATOM_IFALIGN >> MO_ATOM_SHIFT] = "", 240637031fefSRichard Henderson [MO_ATOM_IFALIGN_PAIR >> MO_ATOM_SHIFT] = "pair+", 240737031fefSRichard Henderson [MO_ATOM_WITHIN16 >> MO_ATOM_SHIFT] = "w16+", 240837031fefSRichard Henderson [MO_ATOM_WITHIN16_PAIR >> MO_ATOM_SHIFT] = "w16p+", 240937031fefSRichard Henderson [MO_ATOM_SUBALIGN >> MO_ATOM_SHIFT] = "sub+", 241037031fefSRichard Henderson [MO_ATOM_NONE >> MO_ATOM_SHIFT] = "noat+", 241137031fefSRichard Henderson }; 241237031fefSRichard Henderson 2413587195bdSRichard Henderson static const char bswap_flag_name[][6] = { 2414587195bdSRichard Henderson [TCG_BSWAP_IZ] = "iz", 2415587195bdSRichard Henderson [TCG_BSWAP_OZ] = "oz", 2416587195bdSRichard Henderson [TCG_BSWAP_OS] = "os", 2417587195bdSRichard Henderson [TCG_BSWAP_IZ | TCG_BSWAP_OZ] = "iz,oz", 2418587195bdSRichard Henderson [TCG_BSWAP_IZ | TCG_BSWAP_OS] = "iz,os", 2419587195bdSRichard Henderson }; 2420587195bdSRichard Henderson 2421b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d) 2422b016486eSRichard Henderson { 2423b016486eSRichard Henderson return (d & (d - 1)) == 0; 2424b016486eSRichard Henderson } 2425b016486eSRichard Henderson 2426b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d) 2427b016486eSRichard Henderson { 2428b016486eSRichard Henderson if (TCG_TARGET_NB_REGS <= 32) { 2429b016486eSRichard Henderson return ctz32(d); 2430b016486eSRichard Henderson } else { 2431b016486eSRichard Henderson return ctz64(d); 2432b016486eSRichard Henderson } 2433b016486eSRichard Henderson } 2434b016486eSRichard Henderson 2435b7a83ff8SRichard Henderson /* Return only the number of characters output -- no error return. */ 2436b7a83ff8SRichard Henderson #define ne_fprintf(...) \ 2437b7a83ff8SRichard Henderson ({ int ret_ = fprintf(__VA_ARGS__); ret_ >= 0 ? ret_ : 0; }) 2438b7a83ff8SRichard Henderson 2439b7a83ff8SRichard Henderson static void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs) 2440c896fe29Sbellard { 2441c896fe29Sbellard char buf[128]; 2442c45cb8bbSRichard Henderson TCGOp *op; 2443c896fe29Sbellard 244415fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 2445c45cb8bbSRichard Henderson int i, k, nb_oargs, nb_iargs, nb_cargs; 2446c45cb8bbSRichard Henderson const TCGOpDef *def; 2447c45cb8bbSRichard Henderson TCGOpcode c; 2448bdfb460eSRichard Henderson int col = 0; 2449c45cb8bbSRichard Henderson 2450c45cb8bbSRichard Henderson c = op->opc; 2451c896fe29Sbellard def = &tcg_op_defs[c]; 2452c45cb8bbSRichard Henderson 2453765b842aSRichard Henderson if (c == INDEX_op_insn_start) { 2454b016486eSRichard Henderson nb_oargs = 0; 2455b7a83ff8SRichard Henderson col += ne_fprintf(f, "\n ----"); 24569aef40edSRichard Henderson 2457747bd69dSRichard Henderson for (i = 0, k = s->insn_start_words; i < k; ++i) { 2458c9ad8d27SRichard Henderson col += ne_fprintf(f, " %016" PRIx64, 2459c9ad8d27SRichard Henderson tcg_get_insn_start_param(op, i)); 2460eeacee4dSBlue Swirl } 24617e4597d7Sbellard } else if (c == INDEX_op_call) { 24623e92aa34SRichard Henderson const TCGHelperInfo *info = tcg_call_info(op); 2463fa52e660SRichard Henderson void *func = tcg_call_func(op); 24643e92aa34SRichard Henderson 2465c896fe29Sbellard /* variable number of arguments */ 2466cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 2467cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 2468c896fe29Sbellard nb_cargs = def->nb_cargs; 2469b03cce8eSbellard 2470b7a83ff8SRichard Henderson col += ne_fprintf(f, " %s ", def->name); 24713e92aa34SRichard Henderson 24723e92aa34SRichard Henderson /* 24733e92aa34SRichard Henderson * Print the function name from TCGHelperInfo, if available. 24743e92aa34SRichard Henderson * Note that plugins have a template function for the info, 24753e92aa34SRichard Henderson * but the actual function pointer comes from the plugin. 24763e92aa34SRichard Henderson */ 24773e92aa34SRichard Henderson if (func == info->func) { 2478b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s", info->name); 24793e92aa34SRichard Henderson } else { 2480b7a83ff8SRichard Henderson col += ne_fprintf(f, "plugin(%p)", func); 24813e92aa34SRichard Henderson } 24823e92aa34SRichard Henderson 2483b7a83ff8SRichard Henderson col += ne_fprintf(f, ",$0x%x,$%d", info->flags, nb_oargs); 2484b03cce8eSbellard for (i = 0; i < nb_oargs; i++) { 2485b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", tcg_get_arg_str(s, buf, sizeof(buf), 2486efee3746SRichard Henderson op->args[i])); 2487b03cce8eSbellard } 2488cf066674SRichard Henderson for (i = 0; i < nb_iargs; i++) { 2489efee3746SRichard Henderson TCGArg arg = op->args[nb_oargs + i]; 249039004a71SRichard Henderson const char *t = tcg_get_arg_str(s, buf, sizeof(buf), arg); 2491b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", t); 2492e8996ee0Sbellard } 2493b03cce8eSbellard } else { 2494b7a83ff8SRichard Henderson col += ne_fprintf(f, " %s ", def->name); 2495c45cb8bbSRichard Henderson 2496c896fe29Sbellard nb_oargs = def->nb_oargs; 2497c896fe29Sbellard nb_iargs = def->nb_iargs; 2498c896fe29Sbellard nb_cargs = def->nb_cargs; 2499c896fe29Sbellard 2500d2fd745fSRichard Henderson if (def->flags & TCG_OPF_VECTOR) { 2501b7a83ff8SRichard Henderson col += ne_fprintf(f, "v%d,e%d,", 64 << TCGOP_VECL(op), 2502d2fd745fSRichard Henderson 8 << TCGOP_VECE(op)); 2503d2fd745fSRichard Henderson } 2504d2fd745fSRichard Henderson 2505c896fe29Sbellard k = 0; 2506c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 2507b7a83ff8SRichard Henderson const char *sep = k ? "," : ""; 2508b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s%s", sep, 2509b7a83ff8SRichard Henderson tcg_get_arg_str(s, buf, sizeof(buf), 2510efee3746SRichard Henderson op->args[k++])); 2511c896fe29Sbellard } 2512c896fe29Sbellard for (i = 0; i < nb_iargs; i++) { 2513b7a83ff8SRichard Henderson const char *sep = k ? "," : ""; 2514b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s%s", sep, 2515b7a83ff8SRichard Henderson tcg_get_arg_str(s, buf, sizeof(buf), 2516efee3746SRichard Henderson op->args[k++])); 2517c896fe29Sbellard } 2518be210acbSRichard Henderson switch (c) { 2519be210acbSRichard Henderson case INDEX_op_brcond_i32: 2520ffc5ea09SRichard Henderson case INDEX_op_setcond_i32: 25213635502dSRichard Henderson case INDEX_op_negsetcond_i32: 2522ffc5ea09SRichard Henderson case INDEX_op_movcond_i32: 2523be210acbSRichard Henderson case INDEX_op_brcond2_i32: 2524be210acbSRichard Henderson case INDEX_op_setcond2_i32: 2525ffc5ea09SRichard Henderson case INDEX_op_brcond_i64: 2526be210acbSRichard Henderson case INDEX_op_setcond_i64: 25273635502dSRichard Henderson case INDEX_op_negsetcond_i64: 2528ffc5ea09SRichard Henderson case INDEX_op_movcond_i64: 2529212be173SRichard Henderson case INDEX_op_cmp_vec: 2530f75da298SRichard Henderson case INDEX_op_cmpsel_vec: 2531efee3746SRichard Henderson if (op->args[k] < ARRAY_SIZE(cond_name) 2532efee3746SRichard Henderson && cond_name[op->args[k]]) { 2533b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", cond_name[op->args[k++]]); 2534eeacee4dSBlue Swirl } else { 2535b7a83ff8SRichard Henderson col += ne_fprintf(f, ",$0x%" TCG_PRIlx, op->args[k++]); 2536eeacee4dSBlue Swirl } 2537f48f3edeSblueswir1 i = 1; 2538be210acbSRichard Henderson break; 2539fecccfccSRichard Henderson case INDEX_op_qemu_ld_a32_i32: 2540fecccfccSRichard Henderson case INDEX_op_qemu_ld_a64_i32: 2541fecccfccSRichard Henderson case INDEX_op_qemu_st_a32_i32: 2542fecccfccSRichard Henderson case INDEX_op_qemu_st_a64_i32: 2543fecccfccSRichard Henderson case INDEX_op_qemu_st8_a32_i32: 2544fecccfccSRichard Henderson case INDEX_op_qemu_st8_a64_i32: 2545fecccfccSRichard Henderson case INDEX_op_qemu_ld_a32_i64: 2546fecccfccSRichard Henderson case INDEX_op_qemu_ld_a64_i64: 2547fecccfccSRichard Henderson case INDEX_op_qemu_st_a32_i64: 2548fecccfccSRichard Henderson case INDEX_op_qemu_st_a64_i64: 2549fecccfccSRichard Henderson case INDEX_op_qemu_ld_a32_i128: 2550fecccfccSRichard Henderson case INDEX_op_qemu_ld_a64_i128: 2551fecccfccSRichard Henderson case INDEX_op_qemu_st_a32_i128: 2552fecccfccSRichard Henderson case INDEX_op_qemu_st_a64_i128: 255359227d5dSRichard Henderson { 255437031fefSRichard Henderson const char *s_al, *s_op, *s_at; 25559002ffcbSRichard Henderson MemOpIdx oi = op->args[k++]; 25569a239c6eSPhilippe Mathieu-Daudé MemOp mop = get_memop(oi); 255759227d5dSRichard Henderson unsigned ix = get_mmuidx(oi); 255859227d5dSRichard Henderson 25599a239c6eSPhilippe Mathieu-Daudé s_al = alignment_name[(mop & MO_AMASK) >> MO_ASHIFT]; 25609a239c6eSPhilippe Mathieu-Daudé s_op = ldst_name[mop & (MO_BSWAP | MO_SSIZE)]; 25619a239c6eSPhilippe Mathieu-Daudé s_at = atom_name[(mop & MO_ATOM_MASK) >> MO_ATOM_SHIFT]; 25629a239c6eSPhilippe Mathieu-Daudé mop &= ~(MO_AMASK | MO_BSWAP | MO_SSIZE | MO_ATOM_MASK); 256337031fefSRichard Henderson 256437031fefSRichard Henderson /* If all fields are accounted for, print symbolically. */ 25659a239c6eSPhilippe Mathieu-Daudé if (!mop && s_al && s_op && s_at) { 256637031fefSRichard Henderson col += ne_fprintf(f, ",%s%s%s,%u", 256737031fefSRichard Henderson s_at, s_al, s_op, ix); 256837031fefSRichard Henderson } else { 25699a239c6eSPhilippe Mathieu-Daudé mop = get_memop(oi); 25709a239c6eSPhilippe Mathieu-Daudé col += ne_fprintf(f, ",$0x%x,%u", mop, ix); 2571f713d6adSRichard Henderson } 2572f713d6adSRichard Henderson i = 1; 257359227d5dSRichard Henderson } 2574f713d6adSRichard Henderson break; 2575587195bdSRichard Henderson case INDEX_op_bswap16_i32: 2576587195bdSRichard Henderson case INDEX_op_bswap16_i64: 2577587195bdSRichard Henderson case INDEX_op_bswap32_i32: 2578587195bdSRichard Henderson case INDEX_op_bswap32_i64: 2579587195bdSRichard Henderson case INDEX_op_bswap64_i64: 2580587195bdSRichard Henderson { 2581587195bdSRichard Henderson TCGArg flags = op->args[k]; 2582587195bdSRichard Henderson const char *name = NULL; 2583587195bdSRichard Henderson 2584587195bdSRichard Henderson if (flags < ARRAY_SIZE(bswap_flag_name)) { 2585587195bdSRichard Henderson name = bswap_flag_name[flags]; 2586587195bdSRichard Henderson } 2587587195bdSRichard Henderson if (name) { 2588b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", name); 2589587195bdSRichard Henderson } else { 2590b7a83ff8SRichard Henderson col += ne_fprintf(f, ",$0x%" TCG_PRIlx, flags); 2591587195bdSRichard Henderson } 2592587195bdSRichard Henderson i = k = 1; 2593587195bdSRichard Henderson } 2594587195bdSRichard Henderson break; 2595be210acbSRichard Henderson default: 2596f48f3edeSblueswir1 i = 0; 2597be210acbSRichard Henderson break; 2598be210acbSRichard Henderson } 259951e3972cSRichard Henderson switch (c) { 260051e3972cSRichard Henderson case INDEX_op_set_label: 260151e3972cSRichard Henderson case INDEX_op_br: 260251e3972cSRichard Henderson case INDEX_op_brcond_i32: 260351e3972cSRichard Henderson case INDEX_op_brcond_i64: 260451e3972cSRichard Henderson case INDEX_op_brcond2_i32: 2605b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s$L%d", k ? "," : "", 2606efee3746SRichard Henderson arg_label(op->args[k])->id); 260751e3972cSRichard Henderson i++, k++; 260851e3972cSRichard Henderson break; 26093470867bSRichard Henderson case INDEX_op_mb: 26103470867bSRichard Henderson { 26113470867bSRichard Henderson TCGBar membar = op->args[k]; 26123470867bSRichard Henderson const char *b_op, *m_op; 26133470867bSRichard Henderson 26143470867bSRichard Henderson switch (membar & TCG_BAR_SC) { 26153470867bSRichard Henderson case 0: 26163470867bSRichard Henderson b_op = "none"; 26173470867bSRichard Henderson break; 26183470867bSRichard Henderson case TCG_BAR_LDAQ: 26193470867bSRichard Henderson b_op = "acq"; 26203470867bSRichard Henderson break; 26213470867bSRichard Henderson case TCG_BAR_STRL: 26223470867bSRichard Henderson b_op = "rel"; 26233470867bSRichard Henderson break; 26243470867bSRichard Henderson case TCG_BAR_SC: 26253470867bSRichard Henderson b_op = "seq"; 26263470867bSRichard Henderson break; 26273470867bSRichard Henderson default: 26283470867bSRichard Henderson g_assert_not_reached(); 26293470867bSRichard Henderson } 26303470867bSRichard Henderson 26313470867bSRichard Henderson switch (membar & TCG_MO_ALL) { 26323470867bSRichard Henderson case 0: 26333470867bSRichard Henderson m_op = "none"; 26343470867bSRichard Henderson break; 26353470867bSRichard Henderson case TCG_MO_LD_LD: 26363470867bSRichard Henderson m_op = "rr"; 26373470867bSRichard Henderson break; 26383470867bSRichard Henderson case TCG_MO_LD_ST: 26393470867bSRichard Henderson m_op = "rw"; 26403470867bSRichard Henderson break; 26413470867bSRichard Henderson case TCG_MO_ST_LD: 26423470867bSRichard Henderson m_op = "wr"; 26433470867bSRichard Henderson break; 26443470867bSRichard Henderson case TCG_MO_ST_ST: 26453470867bSRichard Henderson m_op = "ww"; 26463470867bSRichard Henderson break; 26473470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_LD_ST: 26483470867bSRichard Henderson m_op = "rr+rw"; 26493470867bSRichard Henderson break; 26503470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_ST_LD: 26513470867bSRichard Henderson m_op = "rr+wr"; 26523470867bSRichard Henderson break; 26533470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_ST_ST: 26543470867bSRichard Henderson m_op = "rr+ww"; 26553470867bSRichard Henderson break; 26563470867bSRichard Henderson case TCG_MO_LD_ST | TCG_MO_ST_LD: 26573470867bSRichard Henderson m_op = "rw+wr"; 26583470867bSRichard Henderson break; 26593470867bSRichard Henderson case TCG_MO_LD_ST | TCG_MO_ST_ST: 26603470867bSRichard Henderson m_op = "rw+ww"; 26613470867bSRichard Henderson break; 26623470867bSRichard Henderson case TCG_MO_ST_LD | TCG_MO_ST_ST: 26633470867bSRichard Henderson m_op = "wr+ww"; 26643470867bSRichard Henderson break; 26653470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_MO_ST_LD: 26663470867bSRichard Henderson m_op = "rr+rw+wr"; 26673470867bSRichard Henderson break; 26683470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_MO_ST_ST: 26693470867bSRichard Henderson m_op = "rr+rw+ww"; 26703470867bSRichard Henderson break; 26713470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_ST_LD | TCG_MO_ST_ST: 26723470867bSRichard Henderson m_op = "rr+wr+ww"; 26733470867bSRichard Henderson break; 26743470867bSRichard Henderson case TCG_MO_LD_ST | TCG_MO_ST_LD | TCG_MO_ST_ST: 26753470867bSRichard Henderson m_op = "rw+wr+ww"; 26763470867bSRichard Henderson break; 26773470867bSRichard Henderson case TCG_MO_ALL: 26783470867bSRichard Henderson m_op = "all"; 26793470867bSRichard Henderson break; 26803470867bSRichard Henderson default: 26813470867bSRichard Henderson g_assert_not_reached(); 26823470867bSRichard Henderson } 26833470867bSRichard Henderson 26843470867bSRichard Henderson col += ne_fprintf(f, "%s%s:%s", (k ? "," : ""), b_op, m_op); 26853470867bSRichard Henderson i++, k++; 26863470867bSRichard Henderson } 26873470867bSRichard Henderson break; 268851e3972cSRichard Henderson default: 268951e3972cSRichard Henderson break; 2690eeacee4dSBlue Swirl } 269151e3972cSRichard Henderson for (; i < nb_cargs; i++, k++) { 2692b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s$0x%" TCG_PRIlx, k ? "," : "", 2693b7a83ff8SRichard Henderson op->args[k]); 2694bdfb460eSRichard Henderson } 2695bdfb460eSRichard Henderson } 2696bdfb460eSRichard Henderson 26971894f69aSRichard Henderson if (have_prefs || op->life) { 26981894f69aSRichard Henderson for (; col < 40; ++col) { 2699b7a83ff8SRichard Henderson putc(' ', f); 2700bdfb460eSRichard Henderson } 27011894f69aSRichard Henderson } 27021894f69aSRichard Henderson 27031894f69aSRichard Henderson if (op->life) { 27041894f69aSRichard Henderson unsigned life = op->life; 2705bdfb460eSRichard Henderson 2706bdfb460eSRichard Henderson if (life & (SYNC_ARG * 3)) { 2707b7a83ff8SRichard Henderson ne_fprintf(f, " sync:"); 2708bdfb460eSRichard Henderson for (i = 0; i < 2; ++i) { 2709bdfb460eSRichard Henderson if (life & (SYNC_ARG << i)) { 2710b7a83ff8SRichard Henderson ne_fprintf(f, " %d", i); 2711bdfb460eSRichard Henderson } 2712bdfb460eSRichard Henderson } 2713bdfb460eSRichard Henderson } 2714bdfb460eSRichard Henderson life /= DEAD_ARG; 2715bdfb460eSRichard Henderson if (life) { 2716b7a83ff8SRichard Henderson ne_fprintf(f, " dead:"); 2717bdfb460eSRichard Henderson for (i = 0; life; ++i, life >>= 1) { 2718bdfb460eSRichard Henderson if (life & 1) { 2719b7a83ff8SRichard Henderson ne_fprintf(f, " %d", i); 2720bdfb460eSRichard Henderson } 2721bdfb460eSRichard Henderson } 2722c896fe29Sbellard } 2723b03cce8eSbellard } 27241894f69aSRichard Henderson 27251894f69aSRichard Henderson if (have_prefs) { 27261894f69aSRichard Henderson for (i = 0; i < nb_oargs; ++i) { 272731fd884bSRichard Henderson TCGRegSet set = output_pref(op, i); 27281894f69aSRichard Henderson 27291894f69aSRichard Henderson if (i == 0) { 2730b7a83ff8SRichard Henderson ne_fprintf(f, " pref="); 27311894f69aSRichard Henderson } else { 2732b7a83ff8SRichard Henderson ne_fprintf(f, ","); 27331894f69aSRichard Henderson } 27341894f69aSRichard Henderson if (set == 0) { 2735b7a83ff8SRichard Henderson ne_fprintf(f, "none"); 27361894f69aSRichard Henderson } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) { 2737b7a83ff8SRichard Henderson ne_fprintf(f, "all"); 27381894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG 27391894f69aSRichard Henderson } else if (tcg_regset_single(set)) { 27401894f69aSRichard Henderson TCGReg reg = tcg_regset_first(set); 2741b7a83ff8SRichard Henderson ne_fprintf(f, "%s", tcg_target_reg_names[reg]); 27421894f69aSRichard Henderson #endif 27431894f69aSRichard Henderson } else if (TCG_TARGET_NB_REGS <= 32) { 2744b7a83ff8SRichard Henderson ne_fprintf(f, "0x%x", (uint32_t)set); 27451894f69aSRichard Henderson } else { 2746b7a83ff8SRichard Henderson ne_fprintf(f, "0x%" PRIx64, (uint64_t)set); 27471894f69aSRichard Henderson } 27481894f69aSRichard Henderson } 27491894f69aSRichard Henderson } 27501894f69aSRichard Henderson 2751b7a83ff8SRichard Henderson putc('\n', f); 2752c896fe29Sbellard } 2753c896fe29Sbellard } 2754c896fe29Sbellard 2755c896fe29Sbellard /* we give more priority to constraints with less registers */ 2756c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k) 2757c896fe29Sbellard { 275874a11790SRichard Henderson const TCGArgConstraint *arg_ct = &def->args_ct[k]; 275929f5e925SRichard Henderson int n = ctpop64(arg_ct->regs); 2760c896fe29Sbellard 276129f5e925SRichard Henderson /* 276229f5e925SRichard Henderson * Sort constraints of a single register first, which includes output 276329f5e925SRichard Henderson * aliases (which must exactly match the input already allocated). 276429f5e925SRichard Henderson */ 276529f5e925SRichard Henderson if (n == 1 || arg_ct->oalias) { 276629f5e925SRichard Henderson return INT_MAX; 2767c896fe29Sbellard } 276829f5e925SRichard Henderson 276929f5e925SRichard Henderson /* 277029f5e925SRichard Henderson * Sort register pairs next, first then second immediately after. 277129f5e925SRichard Henderson * Arbitrarily sort multiple pairs by the index of the first reg; 277229f5e925SRichard Henderson * there shouldn't be many pairs. 277329f5e925SRichard Henderson */ 277429f5e925SRichard Henderson switch (arg_ct->pair) { 277529f5e925SRichard Henderson case 1: 277629f5e925SRichard Henderson case 3: 277729f5e925SRichard Henderson return (k + 1) * 2; 277829f5e925SRichard Henderson case 2: 277929f5e925SRichard Henderson return (arg_ct->pair_index + 1) * 2 - 1; 278029f5e925SRichard Henderson } 278129f5e925SRichard Henderson 278229f5e925SRichard Henderson /* Finally, sort by decreasing register count. */ 278329f5e925SRichard Henderson assert(n > 1); 278429f5e925SRichard Henderson return -n; 2785c896fe29Sbellard } 2786c896fe29Sbellard 2787c896fe29Sbellard /* sort from highest priority to lowest */ 2788c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n) 2789c896fe29Sbellard { 279066792f90SRichard Henderson int i, j; 279166792f90SRichard Henderson TCGArgConstraint *a = def->args_ct; 2792c896fe29Sbellard 279366792f90SRichard Henderson for (i = 0; i < n; i++) { 279466792f90SRichard Henderson a[start + i].sort_index = start + i; 279566792f90SRichard Henderson } 279666792f90SRichard Henderson if (n <= 1) { 2797c896fe29Sbellard return; 279866792f90SRichard Henderson } 2799c896fe29Sbellard for (i = 0; i < n - 1; i++) { 2800c896fe29Sbellard for (j = i + 1; j < n; j++) { 280166792f90SRichard Henderson int p1 = get_constraint_priority(def, a[start + i].sort_index); 280266792f90SRichard Henderson int p2 = get_constraint_priority(def, a[start + j].sort_index); 2803c896fe29Sbellard if (p1 < p2) { 280466792f90SRichard Henderson int tmp = a[start + i].sort_index; 280566792f90SRichard Henderson a[start + i].sort_index = a[start + j].sort_index; 280666792f90SRichard Henderson a[start + j].sort_index = tmp; 2807c896fe29Sbellard } 2808c896fe29Sbellard } 2809c896fe29Sbellard } 2810c896fe29Sbellard } 2811c896fe29Sbellard 2812f69d277eSRichard Henderson static void process_op_defs(TCGContext *s) 2813c896fe29Sbellard { 2814a9751609SRichard Henderson TCGOpcode op; 2815c896fe29Sbellard 2816f69d277eSRichard Henderson for (op = 0; op < NB_OPS; op++) { 2817f69d277eSRichard Henderson TCGOpDef *def = &tcg_op_defs[op]; 2818f69d277eSRichard Henderson const TCGTargetOpDef *tdefs; 281929f5e925SRichard Henderson bool saw_alias_pair = false; 282029f5e925SRichard Henderson int i, o, i2, o2, nb_args; 2821f69d277eSRichard Henderson 2822f69d277eSRichard Henderson if (def->flags & TCG_OPF_NOT_PRESENT) { 2823f69d277eSRichard Henderson continue; 2824f69d277eSRichard Henderson } 2825f69d277eSRichard Henderson 2826c896fe29Sbellard nb_args = def->nb_iargs + def->nb_oargs; 2827f69d277eSRichard Henderson if (nb_args == 0) { 2828f69d277eSRichard Henderson continue; 2829f69d277eSRichard Henderson } 2830f69d277eSRichard Henderson 28314c22e840SRichard Henderson /* 28324c22e840SRichard Henderson * Macro magic should make it impossible, but double-check that 28334c22e840SRichard Henderson * the array index is in range. Since the signness of an enum 28344c22e840SRichard Henderson * is implementation defined, force the result to unsigned. 28354c22e840SRichard Henderson */ 28364c22e840SRichard Henderson unsigned con_set = tcg_target_op_def(op); 28374c22e840SRichard Henderson tcg_debug_assert(con_set < ARRAY_SIZE(constraint_sets)); 28384c22e840SRichard Henderson tdefs = &constraint_sets[con_set]; 2839f69d277eSRichard Henderson 2840c896fe29Sbellard for (i = 0; i < nb_args; i++) { 2841f69d277eSRichard Henderson const char *ct_str = tdefs->args_ct_str[i]; 28428940ea0dSPhilippe Mathieu-Daudé bool input_p = i >= def->nb_oargs; 28438940ea0dSPhilippe Mathieu-Daudé 2844f69d277eSRichard Henderson /* Incomplete TCGTargetOpDef entry. */ 2845eabb7b91SAurelien Jarno tcg_debug_assert(ct_str != NULL); 2846f69d277eSRichard Henderson 284717280ff4SRichard Henderson switch (*ct_str) { 284817280ff4SRichard Henderson case '0' ... '9': 28498940ea0dSPhilippe Mathieu-Daudé o = *ct_str - '0'; 28508940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(input_p); 28518940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(o < def->nb_oargs); 28528940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(def->args_ct[o].regs != 0); 28538940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(!def->args_ct[o].oalias); 28548940ea0dSPhilippe Mathieu-Daudé def->args_ct[i] = def->args_ct[o]; 2855bc2b17e6SRichard Henderson /* The output sets oalias. */ 28568940ea0dSPhilippe Mathieu-Daudé def->args_ct[o].oalias = 1; 28578940ea0dSPhilippe Mathieu-Daudé def->args_ct[o].alias_index = i; 2858bc2b17e6SRichard Henderson /* The input sets ialias. */ 28598940ea0dSPhilippe Mathieu-Daudé def->args_ct[i].ialias = 1; 28608940ea0dSPhilippe Mathieu-Daudé def->args_ct[i].alias_index = o; 286129f5e925SRichard Henderson if (def->args_ct[i].pair) { 286229f5e925SRichard Henderson saw_alias_pair = true; 286329f5e925SRichard Henderson } 28648940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(ct_str[1] == '\0'); 28658940ea0dSPhilippe Mathieu-Daudé continue; 28668940ea0dSPhilippe Mathieu-Daudé 286782790a87SRichard Henderson case '&': 28688940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(!input_p); 2869bc2b17e6SRichard Henderson def->args_ct[i].newreg = true; 287082790a87SRichard Henderson ct_str++; 287182790a87SRichard Henderson break; 287229f5e925SRichard Henderson 287329f5e925SRichard Henderson case 'p': /* plus */ 287429f5e925SRichard Henderson /* Allocate to the register after the previous. */ 287529f5e925SRichard Henderson tcg_debug_assert(i > (input_p ? def->nb_oargs : 0)); 287629f5e925SRichard Henderson o = i - 1; 287729f5e925SRichard Henderson tcg_debug_assert(!def->args_ct[o].pair); 287829f5e925SRichard Henderson tcg_debug_assert(!def->args_ct[o].ct); 287929f5e925SRichard Henderson def->args_ct[i] = (TCGArgConstraint){ 288029f5e925SRichard Henderson .pair = 2, 288129f5e925SRichard Henderson .pair_index = o, 288229f5e925SRichard Henderson .regs = def->args_ct[o].regs << 1, 288329f5e925SRichard Henderson }; 288429f5e925SRichard Henderson def->args_ct[o].pair = 1; 288529f5e925SRichard Henderson def->args_ct[o].pair_index = i; 288629f5e925SRichard Henderson tcg_debug_assert(ct_str[1] == '\0'); 288729f5e925SRichard Henderson continue; 288829f5e925SRichard Henderson 288929f5e925SRichard Henderson case 'm': /* minus */ 289029f5e925SRichard Henderson /* Allocate to the register before the previous. */ 289129f5e925SRichard Henderson tcg_debug_assert(i > (input_p ? def->nb_oargs : 0)); 289229f5e925SRichard Henderson o = i - 1; 289329f5e925SRichard Henderson tcg_debug_assert(!def->args_ct[o].pair); 289429f5e925SRichard Henderson tcg_debug_assert(!def->args_ct[o].ct); 289529f5e925SRichard Henderson def->args_ct[i] = (TCGArgConstraint){ 289629f5e925SRichard Henderson .pair = 1, 289729f5e925SRichard Henderson .pair_index = o, 289829f5e925SRichard Henderson .regs = def->args_ct[o].regs >> 1, 289929f5e925SRichard Henderson }; 290029f5e925SRichard Henderson def->args_ct[o].pair = 2; 290129f5e925SRichard Henderson def->args_ct[o].pair_index = i; 290229f5e925SRichard Henderson tcg_debug_assert(ct_str[1] == '\0'); 290329f5e925SRichard Henderson continue; 29048940ea0dSPhilippe Mathieu-Daudé } 29058940ea0dSPhilippe Mathieu-Daudé 29068940ea0dSPhilippe Mathieu-Daudé do { 29078940ea0dSPhilippe Mathieu-Daudé switch (*ct_str) { 2908c896fe29Sbellard case 'i': 2909c896fe29Sbellard def->args_ct[i].ct |= TCG_CT_CONST; 2910c896fe29Sbellard break; 2911358b4923SRichard Henderson 2912358b4923SRichard Henderson /* Include all of the target-specific constraints. */ 2913358b4923SRichard Henderson 2914358b4923SRichard Henderson #undef CONST 2915358b4923SRichard Henderson #define CONST(CASE, MASK) \ 29168940ea0dSPhilippe Mathieu-Daudé case CASE: def->args_ct[i].ct |= MASK; break; 2917358b4923SRichard Henderson #define REGS(CASE, MASK) \ 29188940ea0dSPhilippe Mathieu-Daudé case CASE: def->args_ct[i].regs |= MASK; break; 2919358b4923SRichard Henderson 2920358b4923SRichard Henderson #include "tcg-target-con-str.h" 2921358b4923SRichard Henderson 2922358b4923SRichard Henderson #undef REGS 2923358b4923SRichard Henderson #undef CONST 2924c896fe29Sbellard default: 29258940ea0dSPhilippe Mathieu-Daudé case '0' ... '9': 29268940ea0dSPhilippe Mathieu-Daudé case '&': 292729f5e925SRichard Henderson case 'p': 292829f5e925SRichard Henderson case 'm': 2929358b4923SRichard Henderson /* Typo in TCGTargetOpDef constraint. */ 2930358b4923SRichard Henderson g_assert_not_reached(); 2931358b4923SRichard Henderson } 29328940ea0dSPhilippe Mathieu-Daudé } while (*++ct_str != '\0'); 2933c896fe29Sbellard } 2934c896fe29Sbellard 2935c68aaa18SStefan Weil /* TCGTargetOpDef entry with too much information? */ 2936eabb7b91SAurelien Jarno tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL); 2937c68aaa18SStefan Weil 293829f5e925SRichard Henderson /* 293929f5e925SRichard Henderson * Fix up output pairs that are aliased with inputs. 294029f5e925SRichard Henderson * When we created the alias, we copied pair from the output. 294129f5e925SRichard Henderson * There are three cases: 294229f5e925SRichard Henderson * (1a) Pairs of inputs alias pairs of outputs. 294329f5e925SRichard Henderson * (1b) One input aliases the first of a pair of outputs. 294429f5e925SRichard Henderson * (2) One input aliases the second of a pair of outputs. 294529f5e925SRichard Henderson * 294629f5e925SRichard Henderson * Case 1a is handled by making sure that the pair_index'es are 294729f5e925SRichard Henderson * properly updated so that they appear the same as a pair of inputs. 294829f5e925SRichard Henderson * 294929f5e925SRichard Henderson * Case 1b is handled by setting the pair_index of the input to 295029f5e925SRichard Henderson * itself, simply so it doesn't point to an unrelated argument. 295129f5e925SRichard Henderson * Since we don't encounter the "second" during the input allocation 295229f5e925SRichard Henderson * phase, nothing happens with the second half of the input pair. 295329f5e925SRichard Henderson * 295429f5e925SRichard Henderson * Case 2 is handled by setting the second input to pair=3, the 295529f5e925SRichard Henderson * first output to pair=3, and the pair_index'es to match. 295629f5e925SRichard Henderson */ 295729f5e925SRichard Henderson if (saw_alias_pair) { 295829f5e925SRichard Henderson for (i = def->nb_oargs; i < nb_args; i++) { 295929f5e925SRichard Henderson /* 296029f5e925SRichard Henderson * Since [0-9pm] must be alone in the constraint string, 296129f5e925SRichard Henderson * the only way they can both be set is if the pair comes 296229f5e925SRichard Henderson * from the output alias. 296329f5e925SRichard Henderson */ 296429f5e925SRichard Henderson if (!def->args_ct[i].ialias) { 296529f5e925SRichard Henderson continue; 296629f5e925SRichard Henderson } 296729f5e925SRichard Henderson switch (def->args_ct[i].pair) { 296829f5e925SRichard Henderson case 0: 296929f5e925SRichard Henderson break; 297029f5e925SRichard Henderson case 1: 297129f5e925SRichard Henderson o = def->args_ct[i].alias_index; 297229f5e925SRichard Henderson o2 = def->args_ct[o].pair_index; 297329f5e925SRichard Henderson tcg_debug_assert(def->args_ct[o].pair == 1); 297429f5e925SRichard Henderson tcg_debug_assert(def->args_ct[o2].pair == 2); 297529f5e925SRichard Henderson if (def->args_ct[o2].oalias) { 297629f5e925SRichard Henderson /* Case 1a */ 297729f5e925SRichard Henderson i2 = def->args_ct[o2].alias_index; 297829f5e925SRichard Henderson tcg_debug_assert(def->args_ct[i2].pair == 2); 297929f5e925SRichard Henderson def->args_ct[i2].pair_index = i; 298029f5e925SRichard Henderson def->args_ct[i].pair_index = i2; 298129f5e925SRichard Henderson } else { 298229f5e925SRichard Henderson /* Case 1b */ 298329f5e925SRichard Henderson def->args_ct[i].pair_index = i; 298429f5e925SRichard Henderson } 298529f5e925SRichard Henderson break; 298629f5e925SRichard Henderson case 2: 298729f5e925SRichard Henderson o = def->args_ct[i].alias_index; 298829f5e925SRichard Henderson o2 = def->args_ct[o].pair_index; 298929f5e925SRichard Henderson tcg_debug_assert(def->args_ct[o].pair == 2); 299029f5e925SRichard Henderson tcg_debug_assert(def->args_ct[o2].pair == 1); 299129f5e925SRichard Henderson if (def->args_ct[o2].oalias) { 299229f5e925SRichard Henderson /* Case 1a */ 299329f5e925SRichard Henderson i2 = def->args_ct[o2].alias_index; 299429f5e925SRichard Henderson tcg_debug_assert(def->args_ct[i2].pair == 1); 299529f5e925SRichard Henderson def->args_ct[i2].pair_index = i; 299629f5e925SRichard Henderson def->args_ct[i].pair_index = i2; 299729f5e925SRichard Henderson } else { 299829f5e925SRichard Henderson /* Case 2 */ 299929f5e925SRichard Henderson def->args_ct[i].pair = 3; 300029f5e925SRichard Henderson def->args_ct[o2].pair = 3; 300129f5e925SRichard Henderson def->args_ct[i].pair_index = o2; 300229f5e925SRichard Henderson def->args_ct[o2].pair_index = i; 300329f5e925SRichard Henderson } 300429f5e925SRichard Henderson break; 300529f5e925SRichard Henderson default: 300629f5e925SRichard Henderson g_assert_not_reached(); 300729f5e925SRichard Henderson } 300829f5e925SRichard Henderson } 300929f5e925SRichard Henderson } 301029f5e925SRichard Henderson 3011c896fe29Sbellard /* sort the constraints (XXX: this is just an heuristic) */ 3012c896fe29Sbellard sort_constraints(def, 0, def->nb_oargs); 3013c896fe29Sbellard sort_constraints(def, def->nb_oargs, def->nb_iargs); 3014c896fe29Sbellard } 3015c896fe29Sbellard } 3016c896fe29Sbellard 3017f85b1fc4SRichard Henderson static void remove_label_use(TCGOp *op, int idx) 3018f85b1fc4SRichard Henderson { 3019f85b1fc4SRichard Henderson TCGLabel *label = arg_label(op->args[idx]); 3020f85b1fc4SRichard Henderson TCGLabelUse *use; 3021f85b1fc4SRichard Henderson 3022f85b1fc4SRichard Henderson QSIMPLEQ_FOREACH(use, &label->branches, next) { 3023f85b1fc4SRichard Henderson if (use->op == op) { 3024f85b1fc4SRichard Henderson QSIMPLEQ_REMOVE(&label->branches, use, TCGLabelUse, next); 3025f85b1fc4SRichard Henderson return; 3026f85b1fc4SRichard Henderson } 3027f85b1fc4SRichard Henderson } 3028f85b1fc4SRichard Henderson g_assert_not_reached(); 3029f85b1fc4SRichard Henderson } 3030f85b1fc4SRichard Henderson 30310c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op) 30320c627cdcSRichard Henderson { 3033d88a117eSRichard Henderson switch (op->opc) { 3034d88a117eSRichard Henderson case INDEX_op_br: 3035f85b1fc4SRichard Henderson remove_label_use(op, 0); 3036d88a117eSRichard Henderson break; 3037d88a117eSRichard Henderson case INDEX_op_brcond_i32: 3038d88a117eSRichard Henderson case INDEX_op_brcond_i64: 3039f85b1fc4SRichard Henderson remove_label_use(op, 3); 3040d88a117eSRichard Henderson break; 3041d88a117eSRichard Henderson case INDEX_op_brcond2_i32: 3042f85b1fc4SRichard Henderson remove_label_use(op, 5); 3043d88a117eSRichard Henderson break; 3044d88a117eSRichard Henderson default: 3045d88a117eSRichard Henderson break; 3046d88a117eSRichard Henderson } 3047d88a117eSRichard Henderson 304815fa08f8SRichard Henderson QTAILQ_REMOVE(&s->ops, op, link); 304915fa08f8SRichard Henderson QTAILQ_INSERT_TAIL(&s->free_ops, op, link); 3050abebf925SRichard Henderson s->nb_ops--; 30510c627cdcSRichard Henderson } 30520c627cdcSRichard Henderson 3053a80cdd31SRichard Henderson void tcg_remove_ops_after(TCGOp *op) 3054a80cdd31SRichard Henderson { 3055a80cdd31SRichard Henderson TCGContext *s = tcg_ctx; 3056a80cdd31SRichard Henderson 3057a80cdd31SRichard Henderson while (true) { 3058a80cdd31SRichard Henderson TCGOp *last = tcg_last_op(); 3059a80cdd31SRichard Henderson if (last == op) { 3060a80cdd31SRichard Henderson return; 3061a80cdd31SRichard Henderson } 3062a80cdd31SRichard Henderson tcg_op_remove(s, last); 3063a80cdd31SRichard Henderson } 3064a80cdd31SRichard Henderson } 3065a80cdd31SRichard Henderson 3066d4478943SPhilippe Mathieu-Daudé static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs) 306715fa08f8SRichard Henderson { 306815fa08f8SRichard Henderson TCGContext *s = tcg_ctx; 3069cb10bc63SRichard Henderson TCGOp *op = NULL; 307015fa08f8SRichard Henderson 3071cb10bc63SRichard Henderson if (unlikely(!QTAILQ_EMPTY(&s->free_ops))) { 3072cb10bc63SRichard Henderson QTAILQ_FOREACH(op, &s->free_ops, link) { 3073cb10bc63SRichard Henderson if (nargs <= op->nargs) { 307415fa08f8SRichard Henderson QTAILQ_REMOVE(&s->free_ops, op, link); 3075cb10bc63SRichard Henderson nargs = op->nargs; 3076cb10bc63SRichard Henderson goto found; 307715fa08f8SRichard Henderson } 3078cb10bc63SRichard Henderson } 3079cb10bc63SRichard Henderson } 3080cb10bc63SRichard Henderson 3081cb10bc63SRichard Henderson /* Most opcodes have 3 or 4 operands: reduce fragmentation. */ 3082cb10bc63SRichard Henderson nargs = MAX(4, nargs); 3083cb10bc63SRichard Henderson op = tcg_malloc(sizeof(TCGOp) + sizeof(TCGArg) * nargs); 3084cb10bc63SRichard Henderson 3085cb10bc63SRichard Henderson found: 308615fa08f8SRichard Henderson memset(op, 0, offsetof(TCGOp, link)); 308715fa08f8SRichard Henderson op->opc = opc; 3088cb10bc63SRichard Henderson op->nargs = nargs; 308915fa08f8SRichard Henderson 3090cb10bc63SRichard Henderson /* Check for bitfield overflow. */ 3091cb10bc63SRichard Henderson tcg_debug_assert(op->nargs == nargs); 3092cb10bc63SRichard Henderson 3093cb10bc63SRichard Henderson s->nb_ops++; 309415fa08f8SRichard Henderson return op; 309515fa08f8SRichard Henderson } 309615fa08f8SRichard Henderson 3097d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_emit_op(TCGOpcode opc, unsigned nargs) 309815fa08f8SRichard Henderson { 3099d4478943SPhilippe Mathieu-Daudé TCGOp *op = tcg_op_alloc(opc, nargs); 310015fa08f8SRichard Henderson QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link); 310115fa08f8SRichard Henderson return op; 310215fa08f8SRichard Henderson } 310315fa08f8SRichard Henderson 3104d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op, 3105d4478943SPhilippe Mathieu-Daudé TCGOpcode opc, unsigned nargs) 31065a18407fSRichard Henderson { 3107d4478943SPhilippe Mathieu-Daudé TCGOp *new_op = tcg_op_alloc(opc, nargs); 310815fa08f8SRichard Henderson QTAILQ_INSERT_BEFORE(old_op, new_op, link); 31095a18407fSRichard Henderson return new_op; 31105a18407fSRichard Henderson } 31115a18407fSRichard Henderson 3112d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, 3113d4478943SPhilippe Mathieu-Daudé TCGOpcode opc, unsigned nargs) 31145a18407fSRichard Henderson { 3115d4478943SPhilippe Mathieu-Daudé TCGOp *new_op = tcg_op_alloc(opc, nargs); 311615fa08f8SRichard Henderson QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link); 31175a18407fSRichard Henderson return new_op; 31185a18407fSRichard Henderson } 31195a18407fSRichard Henderson 3120968f305eSRichard Henderson static void move_label_uses(TCGLabel *to, TCGLabel *from) 3121968f305eSRichard Henderson { 3122968f305eSRichard Henderson TCGLabelUse *u; 3123968f305eSRichard Henderson 3124968f305eSRichard Henderson QSIMPLEQ_FOREACH(u, &from->branches, next) { 3125968f305eSRichard Henderson TCGOp *op = u->op; 3126968f305eSRichard Henderson switch (op->opc) { 3127968f305eSRichard Henderson case INDEX_op_br: 3128968f305eSRichard Henderson op->args[0] = label_arg(to); 3129968f305eSRichard Henderson break; 3130968f305eSRichard Henderson case INDEX_op_brcond_i32: 3131968f305eSRichard Henderson case INDEX_op_brcond_i64: 3132968f305eSRichard Henderson op->args[3] = label_arg(to); 3133968f305eSRichard Henderson break; 3134968f305eSRichard Henderson case INDEX_op_brcond2_i32: 3135968f305eSRichard Henderson op->args[5] = label_arg(to); 3136968f305eSRichard Henderson break; 3137968f305eSRichard Henderson default: 3138968f305eSRichard Henderson g_assert_not_reached(); 3139968f305eSRichard Henderson } 3140968f305eSRichard Henderson } 3141968f305eSRichard Henderson 3142968f305eSRichard Henderson QSIMPLEQ_CONCAT(&to->branches, &from->branches); 3143968f305eSRichard Henderson } 3144968f305eSRichard Henderson 3145b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code. */ 31469bbee4c0SRichard Henderson static void __attribute__((noinline)) 31479bbee4c0SRichard Henderson reachable_code_pass(TCGContext *s) 3148b4fc67c7SRichard Henderson { 31494d89d0bbSRichard Henderson TCGOp *op, *op_next, *op_prev; 3150b4fc67c7SRichard Henderson bool dead = false; 3151b4fc67c7SRichard Henderson 3152b4fc67c7SRichard Henderson QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) { 3153b4fc67c7SRichard Henderson bool remove = dead; 3154b4fc67c7SRichard Henderson TCGLabel *label; 3155b4fc67c7SRichard Henderson 3156b4fc67c7SRichard Henderson switch (op->opc) { 3157b4fc67c7SRichard Henderson case INDEX_op_set_label: 3158b4fc67c7SRichard Henderson label = arg_label(op->args[0]); 31594d89d0bbSRichard Henderson 31604d89d0bbSRichard Henderson /* 3161968f305eSRichard Henderson * Note that the first op in the TB is always a load, 3162968f305eSRichard Henderson * so there is always something before a label. 3163968f305eSRichard Henderson */ 3164968f305eSRichard Henderson op_prev = QTAILQ_PREV(op, link); 3165968f305eSRichard Henderson 3166968f305eSRichard Henderson /* 3167968f305eSRichard Henderson * If we find two sequential labels, move all branches to 3168968f305eSRichard Henderson * reference the second label and remove the first label. 3169968f305eSRichard Henderson * Do this before branch to next optimization, so that the 3170968f305eSRichard Henderson * middle label is out of the way. 3171968f305eSRichard Henderson */ 3172968f305eSRichard Henderson if (op_prev->opc == INDEX_op_set_label) { 3173968f305eSRichard Henderson move_label_uses(label, arg_label(op_prev->args[0])); 3174968f305eSRichard Henderson tcg_op_remove(s, op_prev); 3175968f305eSRichard Henderson op_prev = QTAILQ_PREV(op, link); 3176968f305eSRichard Henderson } 3177968f305eSRichard Henderson 3178968f305eSRichard Henderson /* 31794d89d0bbSRichard Henderson * Optimization can fold conditional branches to unconditional. 31804d89d0bbSRichard Henderson * If we find a label which is preceded by an unconditional 31814d89d0bbSRichard Henderson * branch to next, remove the branch. We couldn't do this when 31824d89d0bbSRichard Henderson * processing the branch because any dead code between the branch 31834d89d0bbSRichard Henderson * and label had not yet been removed. 31844d89d0bbSRichard Henderson */ 31854d89d0bbSRichard Henderson if (op_prev->opc == INDEX_op_br && 31864d89d0bbSRichard Henderson label == arg_label(op_prev->args[0])) { 31874d89d0bbSRichard Henderson tcg_op_remove(s, op_prev); 31884d89d0bbSRichard Henderson /* Fall through means insns become live again. */ 31894d89d0bbSRichard Henderson dead = false; 31904d89d0bbSRichard Henderson } 31914d89d0bbSRichard Henderson 3192f85b1fc4SRichard Henderson if (QSIMPLEQ_EMPTY(&label->branches)) { 3193b4fc67c7SRichard Henderson /* 3194b4fc67c7SRichard Henderson * While there is an occasional backward branch, virtually 3195b4fc67c7SRichard Henderson * all branches generated by the translators are forward. 3196b4fc67c7SRichard Henderson * Which means that generally we will have already removed 3197b4fc67c7SRichard Henderson * all references to the label that will be, and there is 3198b4fc67c7SRichard Henderson * little to be gained by iterating. 3199b4fc67c7SRichard Henderson */ 3200b4fc67c7SRichard Henderson remove = true; 3201b4fc67c7SRichard Henderson } else { 3202b4fc67c7SRichard Henderson /* Once we see a label, insns become live again. */ 3203b4fc67c7SRichard Henderson dead = false; 3204b4fc67c7SRichard Henderson remove = false; 3205b4fc67c7SRichard Henderson } 3206b4fc67c7SRichard Henderson break; 3207b4fc67c7SRichard Henderson 3208b4fc67c7SRichard Henderson case INDEX_op_br: 3209b4fc67c7SRichard Henderson case INDEX_op_exit_tb: 3210b4fc67c7SRichard Henderson case INDEX_op_goto_ptr: 3211b4fc67c7SRichard Henderson /* Unconditional branches; everything following is dead. */ 3212b4fc67c7SRichard Henderson dead = true; 3213b4fc67c7SRichard Henderson break; 3214b4fc67c7SRichard Henderson 3215b4fc67c7SRichard Henderson case INDEX_op_call: 3216b4fc67c7SRichard Henderson /* Notice noreturn helper calls, raising exceptions. */ 321790163900SRichard Henderson if (tcg_call_flags(op) & TCG_CALL_NO_RETURN) { 3218b4fc67c7SRichard Henderson dead = true; 3219b4fc67c7SRichard Henderson } 3220b4fc67c7SRichard Henderson break; 3221b4fc67c7SRichard Henderson 3222b4fc67c7SRichard Henderson case INDEX_op_insn_start: 3223b4fc67c7SRichard Henderson /* Never remove -- we need to keep these for unwind. */ 3224b4fc67c7SRichard Henderson remove = false; 3225b4fc67c7SRichard Henderson break; 3226b4fc67c7SRichard Henderson 3227b4fc67c7SRichard Henderson default: 3228b4fc67c7SRichard Henderson break; 3229b4fc67c7SRichard Henderson } 3230b4fc67c7SRichard Henderson 3231b4fc67c7SRichard Henderson if (remove) { 3232b4fc67c7SRichard Henderson tcg_op_remove(s, op); 3233b4fc67c7SRichard Henderson } 3234b4fc67c7SRichard Henderson } 3235b4fc67c7SRichard Henderson } 3236b4fc67c7SRichard Henderson 3237c70fbf0aSRichard Henderson #define TS_DEAD 1 3238c70fbf0aSRichard Henderson #define TS_MEM 2 3239c70fbf0aSRichard Henderson 32405a18407fSRichard Henderson #define IS_DEAD_ARG(n) (arg_life & (DEAD_ARG << (n))) 32415a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n))) 32425a18407fSRichard Henderson 324325f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp. */ 324425f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts) 324525f49c5fSRichard Henderson { 324625f49c5fSRichard Henderson return ts->state_ptr; 324725f49c5fSRichard Henderson } 324825f49c5fSRichard Henderson 324925f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the 325025f49c5fSRichard Henderson * maximal regset for its type. 325125f49c5fSRichard Henderson */ 325225f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts) 325325f49c5fSRichard Henderson { 325425f49c5fSRichard Henderson *la_temp_pref(ts) 325525f49c5fSRichard Henderson = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]); 325625f49c5fSRichard Henderson } 325725f49c5fSRichard Henderson 32589c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals 32599c43b68dSAurelien Jarno should be in memory. */ 32602616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt) 3261c896fe29Sbellard { 3262b83eabeaSRichard Henderson int i; 3263b83eabeaSRichard Henderson 3264b83eabeaSRichard Henderson for (i = 0; i < ng; ++i) { 3265b83eabeaSRichard Henderson s->temps[i].state = TS_DEAD | TS_MEM; 326625f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 3267b83eabeaSRichard Henderson } 3268b83eabeaSRichard Henderson for (i = ng; i < nt; ++i) { 3269b83eabeaSRichard Henderson s->temps[i].state = TS_DEAD; 327025f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 3271b83eabeaSRichard Henderson } 3272c896fe29Sbellard } 3273c896fe29Sbellard 32749c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals 32759c43b68dSAurelien Jarno and local temps should be in memory. */ 32762616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt) 3277641d5fbeSbellard { 3278b83eabeaSRichard Henderson int i; 3279641d5fbeSbellard 3280ee17db83SRichard Henderson for (i = 0; i < nt; ++i) { 3281ee17db83SRichard Henderson TCGTemp *ts = &s->temps[i]; 3282ee17db83SRichard Henderson int state; 3283ee17db83SRichard Henderson 3284ee17db83SRichard Henderson switch (ts->kind) { 3285ee17db83SRichard Henderson case TEMP_FIXED: 3286ee17db83SRichard Henderson case TEMP_GLOBAL: 3287f57c6915SRichard Henderson case TEMP_TB: 3288ee17db83SRichard Henderson state = TS_DEAD | TS_MEM; 3289ee17db83SRichard Henderson break; 3290c7482438SRichard Henderson case TEMP_EBB: 3291c0522136SRichard Henderson case TEMP_CONST: 3292ee17db83SRichard Henderson state = TS_DEAD; 3293ee17db83SRichard Henderson break; 3294ee17db83SRichard Henderson default: 3295ee17db83SRichard Henderson g_assert_not_reached(); 3296c70fbf0aSRichard Henderson } 3297ee17db83SRichard Henderson ts->state = state; 3298ee17db83SRichard Henderson la_reset_pref(ts); 3299641d5fbeSbellard } 3300641d5fbeSbellard } 3301641d5fbeSbellard 3302f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory. */ 3303f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng) 3304f65a061cSRichard Henderson { 3305f65a061cSRichard Henderson int i; 3306f65a061cSRichard Henderson 3307f65a061cSRichard Henderson for (i = 0; i < ng; ++i) { 330825f49c5fSRichard Henderson int state = s->temps[i].state; 330925f49c5fSRichard Henderson s->temps[i].state = state | TS_MEM; 331025f49c5fSRichard Henderson if (state == TS_DEAD) { 331125f49c5fSRichard Henderson /* If the global was previously dead, reset prefs. */ 331225f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 331325f49c5fSRichard Henderson } 3314f65a061cSRichard Henderson } 3315f65a061cSRichard Henderson } 3316f65a061cSRichard Henderson 3317b4cb76e6SRichard Henderson /* 3318c7482438SRichard Henderson * liveness analysis: conditional branch: all temps are dead unless 3319c7482438SRichard Henderson * explicitly live-across-conditional-branch, globals and local temps 3320c7482438SRichard Henderson * should be synced. 3321b4cb76e6SRichard Henderson */ 3322b4cb76e6SRichard Henderson static void la_bb_sync(TCGContext *s, int ng, int nt) 3323b4cb76e6SRichard Henderson { 3324b4cb76e6SRichard Henderson la_global_sync(s, ng); 3325b4cb76e6SRichard Henderson 3326b4cb76e6SRichard Henderson for (int i = ng; i < nt; ++i) { 3327c0522136SRichard Henderson TCGTemp *ts = &s->temps[i]; 3328c0522136SRichard Henderson int state; 3329c0522136SRichard Henderson 3330c0522136SRichard Henderson switch (ts->kind) { 3331f57c6915SRichard Henderson case TEMP_TB: 3332c0522136SRichard Henderson state = ts->state; 3333c0522136SRichard Henderson ts->state = state | TS_MEM; 3334b4cb76e6SRichard Henderson if (state != TS_DEAD) { 3335b4cb76e6SRichard Henderson continue; 3336b4cb76e6SRichard Henderson } 3337c0522136SRichard Henderson break; 3338c7482438SRichard Henderson case TEMP_EBB: 3339c0522136SRichard Henderson case TEMP_CONST: 3340c0522136SRichard Henderson continue; 3341c0522136SRichard Henderson default: 3342c0522136SRichard Henderson g_assert_not_reached(); 3343b4cb76e6SRichard Henderson } 3344b4cb76e6SRichard Henderson la_reset_pref(&s->temps[i]); 3345b4cb76e6SRichard Henderson } 3346b4cb76e6SRichard Henderson } 3347b4cb76e6SRichard Henderson 3348f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill. */ 3349f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng) 3350f65a061cSRichard Henderson { 3351f65a061cSRichard Henderson int i; 3352f65a061cSRichard Henderson 3353f65a061cSRichard Henderson for (i = 0; i < ng; i++) { 3354f65a061cSRichard Henderson s->temps[i].state = TS_DEAD | TS_MEM; 335525f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 335625f49c5fSRichard Henderson } 335725f49c5fSRichard Henderson } 335825f49c5fSRichard Henderson 335925f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls. */ 336025f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt) 336125f49c5fSRichard Henderson { 336225f49c5fSRichard Henderson TCGRegSet mask = ~tcg_target_call_clobber_regs; 336325f49c5fSRichard Henderson int i; 336425f49c5fSRichard Henderson 336525f49c5fSRichard Henderson for (i = 0; i < nt; i++) { 336625f49c5fSRichard Henderson TCGTemp *ts = &s->temps[i]; 336725f49c5fSRichard Henderson if (!(ts->state & TS_DEAD)) { 336825f49c5fSRichard Henderson TCGRegSet *pset = la_temp_pref(ts); 336925f49c5fSRichard Henderson TCGRegSet set = *pset; 337025f49c5fSRichard Henderson 337125f49c5fSRichard Henderson set &= mask; 337225f49c5fSRichard Henderson /* If the combination is not possible, restart. */ 337325f49c5fSRichard Henderson if (set == 0) { 337425f49c5fSRichard Henderson set = tcg_target_available_regs[ts->type] & mask; 337525f49c5fSRichard Henderson } 337625f49c5fSRichard Henderson *pset = set; 337725f49c5fSRichard Henderson } 3378f65a061cSRichard Henderson } 3379f65a061cSRichard Henderson } 3380f65a061cSRichard Henderson 3381874b8574SRichard Henderson /* 3382874b8574SRichard Henderson * Liveness analysis: Verify the lifetime of TEMP_TB, and reduce 3383874b8574SRichard Henderson * to TEMP_EBB, if possible. 3384874b8574SRichard Henderson */ 3385874b8574SRichard Henderson static void __attribute__((noinline)) 3386874b8574SRichard Henderson liveness_pass_0(TCGContext *s) 3387874b8574SRichard Henderson { 3388874b8574SRichard Henderson void * const multiple_ebb = (void *)(uintptr_t)-1; 3389874b8574SRichard Henderson int nb_temps = s->nb_temps; 3390874b8574SRichard Henderson TCGOp *op, *ebb; 3391874b8574SRichard Henderson 3392874b8574SRichard Henderson for (int i = s->nb_globals; i < nb_temps; ++i) { 3393874b8574SRichard Henderson s->temps[i].state_ptr = NULL; 3394874b8574SRichard Henderson } 3395874b8574SRichard Henderson 3396874b8574SRichard Henderson /* 3397874b8574SRichard Henderson * Represent each EBB by the op at which it begins. In the case of 3398874b8574SRichard Henderson * the first EBB, this is the first op, otherwise it is a label. 3399874b8574SRichard Henderson * Collect the uses of each TEMP_TB: NULL for unused, EBB for use 3400874b8574SRichard Henderson * within a single EBB, else MULTIPLE_EBB. 3401874b8574SRichard Henderson */ 3402874b8574SRichard Henderson ebb = QTAILQ_FIRST(&s->ops); 3403874b8574SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 3404874b8574SRichard Henderson const TCGOpDef *def; 3405874b8574SRichard Henderson int nb_oargs, nb_iargs; 3406874b8574SRichard Henderson 3407874b8574SRichard Henderson switch (op->opc) { 3408874b8574SRichard Henderson case INDEX_op_set_label: 3409874b8574SRichard Henderson ebb = op; 3410874b8574SRichard Henderson continue; 3411874b8574SRichard Henderson case INDEX_op_discard: 3412874b8574SRichard Henderson continue; 3413874b8574SRichard Henderson case INDEX_op_call: 3414874b8574SRichard Henderson nb_oargs = TCGOP_CALLO(op); 3415874b8574SRichard Henderson nb_iargs = TCGOP_CALLI(op); 3416874b8574SRichard Henderson break; 3417874b8574SRichard Henderson default: 3418874b8574SRichard Henderson def = &tcg_op_defs[op->opc]; 3419874b8574SRichard Henderson nb_oargs = def->nb_oargs; 3420874b8574SRichard Henderson nb_iargs = def->nb_iargs; 3421874b8574SRichard Henderson break; 3422874b8574SRichard Henderson } 3423874b8574SRichard Henderson 3424874b8574SRichard Henderson for (int i = 0; i < nb_oargs + nb_iargs; ++i) { 3425874b8574SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]); 3426874b8574SRichard Henderson 3427874b8574SRichard Henderson if (ts->kind != TEMP_TB) { 3428874b8574SRichard Henderson continue; 3429874b8574SRichard Henderson } 3430874b8574SRichard Henderson if (ts->state_ptr == NULL) { 3431874b8574SRichard Henderson ts->state_ptr = ebb; 3432874b8574SRichard Henderson } else if (ts->state_ptr != ebb) { 3433874b8574SRichard Henderson ts->state_ptr = multiple_ebb; 3434874b8574SRichard Henderson } 3435874b8574SRichard Henderson } 3436874b8574SRichard Henderson } 3437874b8574SRichard Henderson 3438874b8574SRichard Henderson /* 3439874b8574SRichard Henderson * For TEMP_TB that turned out not to be used beyond one EBB, 3440874b8574SRichard Henderson * reduce the liveness to TEMP_EBB. 3441874b8574SRichard Henderson */ 3442874b8574SRichard Henderson for (int i = s->nb_globals; i < nb_temps; ++i) { 3443874b8574SRichard Henderson TCGTemp *ts = &s->temps[i]; 3444874b8574SRichard Henderson if (ts->kind == TEMP_TB && ts->state_ptr != multiple_ebb) { 3445874b8574SRichard Henderson ts->kind = TEMP_EBB; 3446874b8574SRichard Henderson } 3447874b8574SRichard Henderson } 3448874b8574SRichard Henderson } 3449874b8574SRichard Henderson 3450a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a 3451c896fe29Sbellard given input arguments is dead. Instructions updating dead 3452c896fe29Sbellard temporaries are removed. */ 34539bbee4c0SRichard Henderson static void __attribute__((noinline)) 34549bbee4c0SRichard Henderson liveness_pass_1(TCGContext *s) 3455c896fe29Sbellard { 3456c70fbf0aSRichard Henderson int nb_globals = s->nb_globals; 34572616c808SRichard Henderson int nb_temps = s->nb_temps; 345815fa08f8SRichard Henderson TCGOp *op, *op_prev; 345925f49c5fSRichard Henderson TCGRegSet *prefs; 346025f49c5fSRichard Henderson int i; 346125f49c5fSRichard Henderson 346225f49c5fSRichard Henderson prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps); 346325f49c5fSRichard Henderson for (i = 0; i < nb_temps; ++i) { 346425f49c5fSRichard Henderson s->temps[i].state_ptr = prefs + i; 346525f49c5fSRichard Henderson } 3466c896fe29Sbellard 3467ae36a246SRichard Henderson /* ??? Should be redundant with the exit_tb that ends the TB. */ 34682616c808SRichard Henderson la_func_end(s, nb_globals, nb_temps); 3469c896fe29Sbellard 3470eae3eb3eSPaolo Bonzini QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) { 347125f49c5fSRichard Henderson int nb_iargs, nb_oargs; 3472c45cb8bbSRichard Henderson TCGOpcode opc_new, opc_new2; 3473c45cb8bbSRichard Henderson bool have_opc_new2; 3474a1b3c48dSRichard Henderson TCGLifeData arg_life = 0; 347525f49c5fSRichard Henderson TCGTemp *ts; 3476c45cb8bbSRichard Henderson TCGOpcode opc = op->opc; 3477c45cb8bbSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 3478c45cb8bbSRichard Henderson 3479c45cb8bbSRichard Henderson switch (opc) { 3480c896fe29Sbellard case INDEX_op_call: 3481c6e113f5Sbellard { 348239004a71SRichard Henderson const TCGHelperInfo *info = tcg_call_info(op); 348339004a71SRichard Henderson int call_flags = tcg_call_flags(op); 3484c6e113f5Sbellard 3485cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 3486cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 3487c6e113f5Sbellard 3488c45cb8bbSRichard Henderson /* pure functions can be removed if their result is unused */ 348978505279SAurelien Jarno if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) { 3490c6e113f5Sbellard for (i = 0; i < nb_oargs; i++) { 349125f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 349225f49c5fSRichard Henderson if (ts->state != TS_DEAD) { 3493c6e113f5Sbellard goto do_not_remove_call; 3494c6e113f5Sbellard } 34959c43b68dSAurelien Jarno } 3496c45cb8bbSRichard Henderson goto do_remove; 3497152c35aaSRichard Henderson } 3498c6e113f5Sbellard do_not_remove_call: 3499c896fe29Sbellard 350025f49c5fSRichard Henderson /* Output args are dead. */ 3501c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 350225f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 350325f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 3504a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 35056b64b624SAurelien Jarno } 350625f49c5fSRichard Henderson if (ts->state & TS_MEM) { 3507a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i; 35089c43b68dSAurelien Jarno } 350925f49c5fSRichard Henderson ts->state = TS_DEAD; 351025f49c5fSRichard Henderson la_reset_pref(ts); 3511c896fe29Sbellard } 3512c896fe29Sbellard 351331fd884bSRichard Henderson /* Not used -- it will be tcg_target_call_oarg_reg(). */ 351431fd884bSRichard Henderson memset(op->output_pref, 0, sizeof(op->output_pref)); 351531fd884bSRichard Henderson 351678505279SAurelien Jarno if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS | 351778505279SAurelien Jarno TCG_CALL_NO_READ_GLOBALS))) { 3518f65a061cSRichard Henderson la_global_kill(s, nb_globals); 3519c70fbf0aSRichard Henderson } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) { 3520f65a061cSRichard Henderson la_global_sync(s, nb_globals); 3521b9c18f56Saurel32 } 3522c896fe29Sbellard 352325f49c5fSRichard Henderson /* Record arguments that die in this helper. */ 3524866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 352525f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 352639004a71SRichard Henderson if (ts->state & TS_DEAD) { 3527a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 3528c896fe29Sbellard } 3529c896fe29Sbellard } 353025f49c5fSRichard Henderson 353125f49c5fSRichard Henderson /* For all live registers, remove call-clobbered prefs. */ 353225f49c5fSRichard Henderson la_cross_call(s, nb_temps); 353325f49c5fSRichard Henderson 353439004a71SRichard Henderson /* 353539004a71SRichard Henderson * Input arguments are live for preceding opcodes. 353639004a71SRichard Henderson * 353739004a71SRichard Henderson * For those arguments that die, and will be allocated in 353839004a71SRichard Henderson * registers, clear the register set for that arg, to be 353939004a71SRichard Henderson * filled in below. For args that will be on the stack, 354039004a71SRichard Henderson * reset to any available reg. Process arguments in reverse 354139004a71SRichard Henderson * order so that if a temp is used more than once, the stack 354239004a71SRichard Henderson * reset to max happens before the register reset to 0. 354325f49c5fSRichard Henderson */ 354439004a71SRichard Henderson for (i = nb_iargs - 1; i >= 0; i--) { 354539004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i]; 354639004a71SRichard Henderson ts = arg_temp(op->args[nb_oargs + i]); 354739004a71SRichard Henderson 354839004a71SRichard Henderson if (ts->state & TS_DEAD) { 354939004a71SRichard Henderson switch (loc->kind) { 355039004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 355139004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 355239004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 3553338b61e9SRichard Henderson if (arg_slot_reg_p(loc->arg_slot)) { 355439004a71SRichard Henderson *la_temp_pref(ts) = 0; 355539004a71SRichard Henderson break; 355639004a71SRichard Henderson } 355739004a71SRichard Henderson /* fall through */ 355839004a71SRichard Henderson default: 355939004a71SRichard Henderson *la_temp_pref(ts) = 356039004a71SRichard Henderson tcg_target_available_regs[ts->type]; 356139004a71SRichard Henderson break; 356239004a71SRichard Henderson } 356325f49c5fSRichard Henderson ts->state &= ~TS_DEAD; 356425f49c5fSRichard Henderson } 356525f49c5fSRichard Henderson } 356625f49c5fSRichard Henderson 356739004a71SRichard Henderson /* 356839004a71SRichard Henderson * For each input argument, add its input register to prefs. 356939004a71SRichard Henderson * If a temp is used once, this produces a single set bit; 357039004a71SRichard Henderson * if a temp is used multiple times, this produces a set. 357139004a71SRichard Henderson */ 357239004a71SRichard Henderson for (i = 0; i < nb_iargs; i++) { 357339004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i]; 357439004a71SRichard Henderson ts = arg_temp(op->args[nb_oargs + i]); 357539004a71SRichard Henderson 357639004a71SRichard Henderson switch (loc->kind) { 357739004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 357839004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 357939004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 3580338b61e9SRichard Henderson if (arg_slot_reg_p(loc->arg_slot)) { 358125f49c5fSRichard Henderson tcg_regset_set_reg(*la_temp_pref(ts), 358239004a71SRichard Henderson tcg_target_call_iarg_regs[loc->arg_slot]); 358339004a71SRichard Henderson } 358439004a71SRichard Henderson break; 358539004a71SRichard Henderson default: 358639004a71SRichard Henderson break; 3587c70fbf0aSRichard Henderson } 3588c19f47bfSAurelien Jarno } 3589c6e113f5Sbellard } 3590c896fe29Sbellard break; 3591765b842aSRichard Henderson case INDEX_op_insn_start: 3592c896fe29Sbellard break; 35935ff9d6a4Sbellard case INDEX_op_discard: 35945ff9d6a4Sbellard /* mark the temporary as dead */ 359525f49c5fSRichard Henderson ts = arg_temp(op->args[0]); 359625f49c5fSRichard Henderson ts->state = TS_DEAD; 359725f49c5fSRichard Henderson la_reset_pref(ts); 35985ff9d6a4Sbellard break; 35991305c451SRichard Henderson 36001305c451SRichard Henderson case INDEX_op_add2_i32: 3601c45cb8bbSRichard Henderson opc_new = INDEX_op_add_i32; 3602f1fae40cSRichard Henderson goto do_addsub2; 36031305c451SRichard Henderson case INDEX_op_sub2_i32: 3604c45cb8bbSRichard Henderson opc_new = INDEX_op_sub_i32; 3605f1fae40cSRichard Henderson goto do_addsub2; 3606f1fae40cSRichard Henderson case INDEX_op_add2_i64: 3607c45cb8bbSRichard Henderson opc_new = INDEX_op_add_i64; 3608f1fae40cSRichard Henderson goto do_addsub2; 3609f1fae40cSRichard Henderson case INDEX_op_sub2_i64: 3610c45cb8bbSRichard Henderson opc_new = INDEX_op_sub_i64; 3611f1fae40cSRichard Henderson do_addsub2: 36121305c451SRichard Henderson nb_iargs = 4; 36131305c451SRichard Henderson nb_oargs = 2; 36141305c451SRichard Henderson /* Test if the high part of the operation is dead, but not 36151305c451SRichard Henderson the low part. The result can be optimized to a simple 36161305c451SRichard Henderson add or sub. This happens often for x86_64 guest when the 36171305c451SRichard Henderson cpu mode is set to 32 bit. */ 3618b83eabeaSRichard Henderson if (arg_temp(op->args[1])->state == TS_DEAD) { 3619b83eabeaSRichard Henderson if (arg_temp(op->args[0])->state == TS_DEAD) { 36201305c451SRichard Henderson goto do_remove; 36211305c451SRichard Henderson } 3622c45cb8bbSRichard Henderson /* Replace the opcode and adjust the args in place, 3623c45cb8bbSRichard Henderson leaving 3 unused args at the end. */ 3624c45cb8bbSRichard Henderson op->opc = opc = opc_new; 3625efee3746SRichard Henderson op->args[1] = op->args[2]; 3626efee3746SRichard Henderson op->args[2] = op->args[4]; 36271305c451SRichard Henderson /* Fall through and mark the single-word operation live. */ 36281305c451SRichard Henderson nb_iargs = 2; 36291305c451SRichard Henderson nb_oargs = 1; 36301305c451SRichard Henderson } 36311305c451SRichard Henderson goto do_not_remove; 36321305c451SRichard Henderson 36331414968aSRichard Henderson case INDEX_op_mulu2_i32: 3634c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i32; 3635c45cb8bbSRichard Henderson opc_new2 = INDEX_op_muluh_i32; 3636c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_muluh_i32; 363703271524SRichard Henderson goto do_mul2; 3638f1fae40cSRichard Henderson case INDEX_op_muls2_i32: 3639c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i32; 3640c45cb8bbSRichard Henderson opc_new2 = INDEX_op_mulsh_i32; 3641c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_mulsh_i32; 3642f1fae40cSRichard Henderson goto do_mul2; 3643f1fae40cSRichard Henderson case INDEX_op_mulu2_i64: 3644c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i64; 3645c45cb8bbSRichard Henderson opc_new2 = INDEX_op_muluh_i64; 3646c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_muluh_i64; 364703271524SRichard Henderson goto do_mul2; 3648f1fae40cSRichard Henderson case INDEX_op_muls2_i64: 3649c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i64; 3650c45cb8bbSRichard Henderson opc_new2 = INDEX_op_mulsh_i64; 3651c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_mulsh_i64; 365203271524SRichard Henderson goto do_mul2; 3653f1fae40cSRichard Henderson do_mul2: 36541414968aSRichard Henderson nb_iargs = 2; 36551414968aSRichard Henderson nb_oargs = 2; 3656b83eabeaSRichard Henderson if (arg_temp(op->args[1])->state == TS_DEAD) { 3657b83eabeaSRichard Henderson if (arg_temp(op->args[0])->state == TS_DEAD) { 365803271524SRichard Henderson /* Both parts of the operation are dead. */ 36591414968aSRichard Henderson goto do_remove; 36601414968aSRichard Henderson } 366103271524SRichard Henderson /* The high part of the operation is dead; generate the low. */ 3662c45cb8bbSRichard Henderson op->opc = opc = opc_new; 3663efee3746SRichard Henderson op->args[1] = op->args[2]; 3664efee3746SRichard Henderson op->args[2] = op->args[3]; 3665b83eabeaSRichard Henderson } else if (arg_temp(op->args[0])->state == TS_DEAD && have_opc_new2) { 366603271524SRichard Henderson /* The low part of the operation is dead; generate the high. */ 3667c45cb8bbSRichard Henderson op->opc = opc = opc_new2; 3668efee3746SRichard Henderson op->args[0] = op->args[1]; 3669efee3746SRichard Henderson op->args[1] = op->args[2]; 3670efee3746SRichard Henderson op->args[2] = op->args[3]; 367103271524SRichard Henderson } else { 367203271524SRichard Henderson goto do_not_remove; 367303271524SRichard Henderson } 367403271524SRichard Henderson /* Mark the single-word operation live. */ 36751414968aSRichard Henderson nb_oargs = 1; 36761414968aSRichard Henderson goto do_not_remove; 36771414968aSRichard Henderson 3678c896fe29Sbellard default: 36791305c451SRichard Henderson /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */ 3680c896fe29Sbellard nb_iargs = def->nb_iargs; 3681c896fe29Sbellard nb_oargs = def->nb_oargs; 3682c896fe29Sbellard 3683c896fe29Sbellard /* Test if the operation can be removed because all 36845ff9d6a4Sbellard its outputs are dead. We assume that nb_oargs == 0 36855ff9d6a4Sbellard implies side effects */ 36865ff9d6a4Sbellard if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) { 3687c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 3688b83eabeaSRichard Henderson if (arg_temp(op->args[i])->state != TS_DEAD) { 3689c896fe29Sbellard goto do_not_remove; 3690c896fe29Sbellard } 36919c43b68dSAurelien Jarno } 3692152c35aaSRichard Henderson goto do_remove; 3693152c35aaSRichard Henderson } 3694152c35aaSRichard Henderson goto do_not_remove; 3695152c35aaSRichard Henderson 36961305c451SRichard Henderson do_remove: 36970c627cdcSRichard Henderson tcg_op_remove(s, op); 3698152c35aaSRichard Henderson break; 3699152c35aaSRichard Henderson 3700c896fe29Sbellard do_not_remove: 3701c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 370225f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 370325f49c5fSRichard Henderson 370425f49c5fSRichard Henderson /* Remember the preference of the uses that followed. */ 370531fd884bSRichard Henderson if (i < ARRAY_SIZE(op->output_pref)) { 370625f49c5fSRichard Henderson op->output_pref[i] = *la_temp_pref(ts); 370731fd884bSRichard Henderson } 370825f49c5fSRichard Henderson 370925f49c5fSRichard Henderson /* Output args are dead. */ 371025f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 3711a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 37126b64b624SAurelien Jarno } 371325f49c5fSRichard Henderson if (ts->state & TS_MEM) { 3714a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i; 37159c43b68dSAurelien Jarno } 371625f49c5fSRichard Henderson ts->state = TS_DEAD; 371725f49c5fSRichard Henderson la_reset_pref(ts); 3718c896fe29Sbellard } 3719c896fe29Sbellard 372025f49c5fSRichard Henderson /* If end of basic block, update. */ 3721ae36a246SRichard Henderson if (def->flags & TCG_OPF_BB_EXIT) { 3722ae36a246SRichard Henderson la_func_end(s, nb_globals, nb_temps); 3723b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_COND_BRANCH) { 3724b4cb76e6SRichard Henderson la_bb_sync(s, nb_globals, nb_temps); 3725ae36a246SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 37262616c808SRichard Henderson la_bb_end(s, nb_globals, nb_temps); 37273d5c5f87SAurelien Jarno } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { 3728f65a061cSRichard Henderson la_global_sync(s, nb_globals); 372925f49c5fSRichard Henderson if (def->flags & TCG_OPF_CALL_CLOBBER) { 373025f49c5fSRichard Henderson la_cross_call(s, nb_temps); 373125f49c5fSRichard Henderson } 3732c896fe29Sbellard } 3733c896fe29Sbellard 373425f49c5fSRichard Henderson /* Record arguments that die in this opcode. */ 3735866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 373625f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 373725f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 3738a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 3739c896fe29Sbellard } 3740c19f47bfSAurelien Jarno } 374125f49c5fSRichard Henderson 374225f49c5fSRichard Henderson /* Input arguments are live for preceding opcodes. */ 3743c19f47bfSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 374425f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 374525f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 374625f49c5fSRichard Henderson /* For operands that were dead, initially allow 374725f49c5fSRichard Henderson all regs for the type. */ 374825f49c5fSRichard Henderson *la_temp_pref(ts) = tcg_target_available_regs[ts->type]; 374925f49c5fSRichard Henderson ts->state &= ~TS_DEAD; 375025f49c5fSRichard Henderson } 375125f49c5fSRichard Henderson } 375225f49c5fSRichard Henderson 375325f49c5fSRichard Henderson /* Incorporate constraints for this operand. */ 375425f49c5fSRichard Henderson switch (opc) { 375525f49c5fSRichard Henderson case INDEX_op_mov_i32: 375625f49c5fSRichard Henderson case INDEX_op_mov_i64: 375725f49c5fSRichard Henderson /* Note that these are TCG_OPF_NOT_PRESENT and do not 375825f49c5fSRichard Henderson have proper constraints. That said, special case 375925f49c5fSRichard Henderson moves to propagate preferences backward. */ 376025f49c5fSRichard Henderson if (IS_DEAD_ARG(1)) { 376125f49c5fSRichard Henderson *la_temp_pref(arg_temp(op->args[0])) 376225f49c5fSRichard Henderson = *la_temp_pref(arg_temp(op->args[1])); 376325f49c5fSRichard Henderson } 376425f49c5fSRichard Henderson break; 376525f49c5fSRichard Henderson 376625f49c5fSRichard Henderson default: 376725f49c5fSRichard Henderson for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 376825f49c5fSRichard Henderson const TCGArgConstraint *ct = &def->args_ct[i]; 376925f49c5fSRichard Henderson TCGRegSet set, *pset; 377025f49c5fSRichard Henderson 377125f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 377225f49c5fSRichard Henderson pset = la_temp_pref(ts); 377325f49c5fSRichard Henderson set = *pset; 377425f49c5fSRichard Henderson 37759be0d080SRichard Henderson set &= ct->regs; 3776bc2b17e6SRichard Henderson if (ct->ialias) { 377731fd884bSRichard Henderson set &= output_pref(op, ct->alias_index); 377825f49c5fSRichard Henderson } 377925f49c5fSRichard Henderson /* If the combination is not possible, restart. */ 378025f49c5fSRichard Henderson if (set == 0) { 37819be0d080SRichard Henderson set = ct->regs; 378225f49c5fSRichard Henderson } 378325f49c5fSRichard Henderson *pset = set; 378425f49c5fSRichard Henderson } 378525f49c5fSRichard Henderson break; 3786c896fe29Sbellard } 3787c896fe29Sbellard break; 3788c896fe29Sbellard } 3789bee158cbSRichard Henderson op->life = arg_life; 3790c896fe29Sbellard } 37911ff0a2c5SEvgeny Voevodin } 3792c896fe29Sbellard 37935a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries. */ 37949bbee4c0SRichard Henderson static bool __attribute__((noinline)) 37959bbee4c0SRichard Henderson liveness_pass_2(TCGContext *s) 37965a18407fSRichard Henderson { 37975a18407fSRichard Henderson int nb_globals = s->nb_globals; 379815fa08f8SRichard Henderson int nb_temps, i; 37995a18407fSRichard Henderson bool changes = false; 380015fa08f8SRichard Henderson TCGOp *op, *op_next; 38015a18407fSRichard Henderson 38025a18407fSRichard Henderson /* Create a temporary for each indirect global. */ 38035a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 38045a18407fSRichard Henderson TCGTemp *its = &s->temps[i]; 38055a18407fSRichard Henderson if (its->indirect_reg) { 38065a18407fSRichard Henderson TCGTemp *dts = tcg_temp_alloc(s); 38075a18407fSRichard Henderson dts->type = its->type; 38085a18407fSRichard Henderson dts->base_type = its->base_type; 3809e1e64652SRichard Henderson dts->temp_subindex = its->temp_subindex; 3810c7482438SRichard Henderson dts->kind = TEMP_EBB; 3811b83eabeaSRichard Henderson its->state_ptr = dts; 3812b83eabeaSRichard Henderson } else { 3813b83eabeaSRichard Henderson its->state_ptr = NULL; 38145a18407fSRichard Henderson } 3815b83eabeaSRichard Henderson /* All globals begin dead. */ 3816b83eabeaSRichard Henderson its->state = TS_DEAD; 38175a18407fSRichard Henderson } 3818b83eabeaSRichard Henderson for (nb_temps = s->nb_temps; i < nb_temps; ++i) { 3819b83eabeaSRichard Henderson TCGTemp *its = &s->temps[i]; 3820b83eabeaSRichard Henderson its->state_ptr = NULL; 3821b83eabeaSRichard Henderson its->state = TS_DEAD; 3822b83eabeaSRichard Henderson } 38235a18407fSRichard Henderson 382415fa08f8SRichard Henderson QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) { 38255a18407fSRichard Henderson TCGOpcode opc = op->opc; 38265a18407fSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 38275a18407fSRichard Henderson TCGLifeData arg_life = op->life; 38285a18407fSRichard Henderson int nb_iargs, nb_oargs, call_flags; 3829b83eabeaSRichard Henderson TCGTemp *arg_ts, *dir_ts; 38305a18407fSRichard Henderson 38315a18407fSRichard Henderson if (opc == INDEX_op_call) { 3832cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 3833cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 383490163900SRichard Henderson call_flags = tcg_call_flags(op); 38355a18407fSRichard Henderson } else { 38365a18407fSRichard Henderson nb_iargs = def->nb_iargs; 38375a18407fSRichard Henderson nb_oargs = def->nb_oargs; 38385a18407fSRichard Henderson 38395a18407fSRichard Henderson /* Set flags similar to how calls require. */ 3840b4cb76e6SRichard Henderson if (def->flags & TCG_OPF_COND_BRANCH) { 3841b4cb76e6SRichard Henderson /* Like reading globals: sync_globals */ 3842b4cb76e6SRichard Henderson call_flags = TCG_CALL_NO_WRITE_GLOBALS; 3843b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 38445a18407fSRichard Henderson /* Like writing globals: save_globals */ 38455a18407fSRichard Henderson call_flags = 0; 38465a18407fSRichard Henderson } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { 38475a18407fSRichard Henderson /* Like reading globals: sync_globals */ 38485a18407fSRichard Henderson call_flags = TCG_CALL_NO_WRITE_GLOBALS; 38495a18407fSRichard Henderson } else { 38505a18407fSRichard Henderson /* No effect on globals. */ 38515a18407fSRichard Henderson call_flags = (TCG_CALL_NO_READ_GLOBALS | 38525a18407fSRichard Henderson TCG_CALL_NO_WRITE_GLOBALS); 38535a18407fSRichard Henderson } 38545a18407fSRichard Henderson } 38555a18407fSRichard Henderson 38565a18407fSRichard Henderson /* Make sure that input arguments are available. */ 38575a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 3858b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 3859b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 3860b83eabeaSRichard Henderson if (dir_ts && arg_ts->state == TS_DEAD) { 3861b83eabeaSRichard Henderson TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32 38625a18407fSRichard Henderson ? INDEX_op_ld_i32 38635a18407fSRichard Henderson : INDEX_op_ld_i64); 3864d4478943SPhilippe Mathieu-Daudé TCGOp *lop = tcg_op_insert_before(s, op, lopc, 3); 38655a18407fSRichard Henderson 3866b83eabeaSRichard Henderson lop->args[0] = temp_arg(dir_ts); 3867b83eabeaSRichard Henderson lop->args[1] = temp_arg(arg_ts->mem_base); 3868b83eabeaSRichard Henderson lop->args[2] = arg_ts->mem_offset; 38695a18407fSRichard Henderson 38705a18407fSRichard Henderson /* Loaded, but synced with memory. */ 3871b83eabeaSRichard Henderson arg_ts->state = TS_MEM; 38725a18407fSRichard Henderson } 38735a18407fSRichard Henderson } 38745a18407fSRichard Henderson 38755a18407fSRichard Henderson /* Perform input replacement, and mark inputs that became dead. 38765a18407fSRichard Henderson No action is required except keeping temp_state up to date 38775a18407fSRichard Henderson so that we reload when needed. */ 38785a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 3879b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 3880b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 3881b83eabeaSRichard Henderson if (dir_ts) { 3882b83eabeaSRichard Henderson op->args[i] = temp_arg(dir_ts); 38835a18407fSRichard Henderson changes = true; 38845a18407fSRichard Henderson if (IS_DEAD_ARG(i)) { 3885b83eabeaSRichard Henderson arg_ts->state = TS_DEAD; 38865a18407fSRichard Henderson } 38875a18407fSRichard Henderson } 38885a18407fSRichard Henderson } 38895a18407fSRichard Henderson 38905a18407fSRichard Henderson /* Liveness analysis should ensure that the following are 38915a18407fSRichard Henderson all correct, for call sites and basic block end points. */ 38925a18407fSRichard Henderson if (call_flags & TCG_CALL_NO_READ_GLOBALS) { 38935a18407fSRichard Henderson /* Nothing to do */ 38945a18407fSRichard Henderson } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) { 38955a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 38965a18407fSRichard Henderson /* Liveness should see that globals are synced back, 38975a18407fSRichard Henderson that is, either TS_DEAD or TS_MEM. */ 3898b83eabeaSRichard Henderson arg_ts = &s->temps[i]; 3899b83eabeaSRichard Henderson tcg_debug_assert(arg_ts->state_ptr == 0 3900b83eabeaSRichard Henderson || arg_ts->state != 0); 39015a18407fSRichard Henderson } 39025a18407fSRichard Henderson } else { 39035a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 39045a18407fSRichard Henderson /* Liveness should see that globals are saved back, 39055a18407fSRichard Henderson that is, TS_DEAD, waiting to be reloaded. */ 3906b83eabeaSRichard Henderson arg_ts = &s->temps[i]; 3907b83eabeaSRichard Henderson tcg_debug_assert(arg_ts->state_ptr == 0 3908b83eabeaSRichard Henderson || arg_ts->state == TS_DEAD); 39095a18407fSRichard Henderson } 39105a18407fSRichard Henderson } 39115a18407fSRichard Henderson 39125a18407fSRichard Henderson /* Outputs become available. */ 391361f15c48SRichard Henderson if (opc == INDEX_op_mov_i32 || opc == INDEX_op_mov_i64) { 391461f15c48SRichard Henderson arg_ts = arg_temp(op->args[0]); 391561f15c48SRichard Henderson dir_ts = arg_ts->state_ptr; 391661f15c48SRichard Henderson if (dir_ts) { 391761f15c48SRichard Henderson op->args[0] = temp_arg(dir_ts); 391861f15c48SRichard Henderson changes = true; 391961f15c48SRichard Henderson 392061f15c48SRichard Henderson /* The output is now live and modified. */ 392161f15c48SRichard Henderson arg_ts->state = 0; 392261f15c48SRichard Henderson 392361f15c48SRichard Henderson if (NEED_SYNC_ARG(0)) { 392461f15c48SRichard Henderson TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 392561f15c48SRichard Henderson ? INDEX_op_st_i32 392661f15c48SRichard Henderson : INDEX_op_st_i64); 3927d4478943SPhilippe Mathieu-Daudé TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3); 392861f15c48SRichard Henderson TCGTemp *out_ts = dir_ts; 392961f15c48SRichard Henderson 393061f15c48SRichard Henderson if (IS_DEAD_ARG(0)) { 393161f15c48SRichard Henderson out_ts = arg_temp(op->args[1]); 393261f15c48SRichard Henderson arg_ts->state = TS_DEAD; 393361f15c48SRichard Henderson tcg_op_remove(s, op); 393461f15c48SRichard Henderson } else { 393561f15c48SRichard Henderson arg_ts->state = TS_MEM; 393661f15c48SRichard Henderson } 393761f15c48SRichard Henderson 393861f15c48SRichard Henderson sop->args[0] = temp_arg(out_ts); 393961f15c48SRichard Henderson sop->args[1] = temp_arg(arg_ts->mem_base); 394061f15c48SRichard Henderson sop->args[2] = arg_ts->mem_offset; 394161f15c48SRichard Henderson } else { 394261f15c48SRichard Henderson tcg_debug_assert(!IS_DEAD_ARG(0)); 394361f15c48SRichard Henderson } 394461f15c48SRichard Henderson } 394561f15c48SRichard Henderson } else { 39465a18407fSRichard Henderson for (i = 0; i < nb_oargs; i++) { 3947b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 3948b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 3949b83eabeaSRichard Henderson if (!dir_ts) { 39505a18407fSRichard Henderson continue; 39515a18407fSRichard Henderson } 3952b83eabeaSRichard Henderson op->args[i] = temp_arg(dir_ts); 39535a18407fSRichard Henderson changes = true; 39545a18407fSRichard Henderson 39555a18407fSRichard Henderson /* The output is now live and modified. */ 3956b83eabeaSRichard Henderson arg_ts->state = 0; 39575a18407fSRichard Henderson 39585a18407fSRichard Henderson /* Sync outputs upon their last write. */ 39595a18407fSRichard Henderson if (NEED_SYNC_ARG(i)) { 3960b83eabeaSRichard Henderson TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 39615a18407fSRichard Henderson ? INDEX_op_st_i32 39625a18407fSRichard Henderson : INDEX_op_st_i64); 3963d4478943SPhilippe Mathieu-Daudé TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3); 39645a18407fSRichard Henderson 3965b83eabeaSRichard Henderson sop->args[0] = temp_arg(dir_ts); 3966b83eabeaSRichard Henderson sop->args[1] = temp_arg(arg_ts->mem_base); 3967b83eabeaSRichard Henderson sop->args[2] = arg_ts->mem_offset; 39685a18407fSRichard Henderson 3969b83eabeaSRichard Henderson arg_ts->state = TS_MEM; 39705a18407fSRichard Henderson } 39715a18407fSRichard Henderson /* Drop outputs that are dead. */ 39725a18407fSRichard Henderson if (IS_DEAD_ARG(i)) { 3973b83eabeaSRichard Henderson arg_ts->state = TS_DEAD; 39745a18407fSRichard Henderson } 39755a18407fSRichard Henderson } 39765a18407fSRichard Henderson } 397761f15c48SRichard Henderson } 39785a18407fSRichard Henderson 39795a18407fSRichard Henderson return changes; 39805a18407fSRichard Henderson } 39815a18407fSRichard Henderson 39822272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts) 3983c896fe29Sbellard { 398431c96417SRichard Henderson intptr_t off; 3985273eb50cSRichard Henderson int size, align; 3986c1c09194SRichard Henderson 3987273eb50cSRichard Henderson /* When allocating an object, look at the full type. */ 3988273eb50cSRichard Henderson size = tcg_type_size(ts->base_type); 3989273eb50cSRichard Henderson switch (ts->base_type) { 3990c1c09194SRichard Henderson case TCG_TYPE_I32: 399131c96417SRichard Henderson align = 4; 3992c1c09194SRichard Henderson break; 3993c1c09194SRichard Henderson case TCG_TYPE_I64: 3994c1c09194SRichard Henderson case TCG_TYPE_V64: 399531c96417SRichard Henderson align = 8; 3996c1c09194SRichard Henderson break; 399743eef72fSRichard Henderson case TCG_TYPE_I128: 3998c1c09194SRichard Henderson case TCG_TYPE_V128: 3999c1c09194SRichard Henderson case TCG_TYPE_V256: 400043eef72fSRichard Henderson /* 400143eef72fSRichard Henderson * Note that we do not require aligned storage for V256, 400243eef72fSRichard Henderson * and that we provide alignment for I128 to match V128, 400343eef72fSRichard Henderson * even if that's above what the host ABI requires. 400443eef72fSRichard Henderson */ 400531c96417SRichard Henderson align = 16; 4006c1c09194SRichard Henderson break; 4007c1c09194SRichard Henderson default: 4008c1c09194SRichard Henderson g_assert_not_reached(); 4009b591dc59SBlue Swirl } 4010c1c09194SRichard Henderson 4011b9537d59SRichard Henderson /* 4012b9537d59SRichard Henderson * Assume the stack is sufficiently aligned. 4013b9537d59SRichard Henderson * This affects e.g. ARM NEON, where we have 8 byte stack alignment 4014b9537d59SRichard Henderson * and do not require 16 byte vector alignment. This seems slightly 4015b9537d59SRichard Henderson * easier than fully parameterizing the above switch statement. 4016b9537d59SRichard Henderson */ 4017b9537d59SRichard Henderson align = MIN(TCG_TARGET_STACK_ALIGN, align); 4018c1c09194SRichard Henderson off = ROUND_UP(s->current_frame_offset, align); 4019732d5897SRichard Henderson 4020732d5897SRichard Henderson /* If we've exhausted the stack frame, restart with a smaller TB. */ 4021732d5897SRichard Henderson if (off + size > s->frame_end) { 4022732d5897SRichard Henderson tcg_raise_tb_overflow(s); 4023732d5897SRichard Henderson } 4024c1c09194SRichard Henderson s->current_frame_offset = off + size; 40259defd1bdSRichard Henderson #if defined(__sparc__) 4026273eb50cSRichard Henderson off += TCG_TARGET_STACK_BIAS; 40279defd1bdSRichard Henderson #endif 4028273eb50cSRichard Henderson 4029273eb50cSRichard Henderson /* If the object was subdivided, assign memory to all the parts. */ 4030273eb50cSRichard Henderson if (ts->base_type != ts->type) { 4031273eb50cSRichard Henderson int part_size = tcg_type_size(ts->type); 4032273eb50cSRichard Henderson int part_count = size / part_size; 4033273eb50cSRichard Henderson 4034273eb50cSRichard Henderson /* 4035273eb50cSRichard Henderson * Each part is allocated sequentially in tcg_temp_new_internal. 4036273eb50cSRichard Henderson * Jump back to the first part by subtracting the current index. 4037273eb50cSRichard Henderson */ 4038273eb50cSRichard Henderson ts -= ts->temp_subindex; 4039273eb50cSRichard Henderson for (int i = 0; i < part_count; ++i) { 4040273eb50cSRichard Henderson ts[i].mem_offset = off + i * part_size; 4041273eb50cSRichard Henderson ts[i].mem_base = s->frame_temp; 4042273eb50cSRichard Henderson ts[i].mem_allocated = 1; 4043273eb50cSRichard Henderson } 4044273eb50cSRichard Henderson } else { 4045273eb50cSRichard Henderson ts->mem_offset = off; 4046b3a62939SRichard Henderson ts->mem_base = s->frame_temp; 4047c896fe29Sbellard ts->mem_allocated = 1; 4048c896fe29Sbellard } 4049273eb50cSRichard Henderson } 4050c896fe29Sbellard 4051098859f1SRichard Henderson /* Assign @reg to @ts, and update reg_to_temp[]. */ 4052098859f1SRichard Henderson static void set_temp_val_reg(TCGContext *s, TCGTemp *ts, TCGReg reg) 4053098859f1SRichard Henderson { 4054098859f1SRichard Henderson if (ts->val_type == TEMP_VAL_REG) { 4055098859f1SRichard Henderson TCGReg old = ts->reg; 4056098859f1SRichard Henderson tcg_debug_assert(s->reg_to_temp[old] == ts); 4057098859f1SRichard Henderson if (old == reg) { 4058098859f1SRichard Henderson return; 4059098859f1SRichard Henderson } 4060098859f1SRichard Henderson s->reg_to_temp[old] = NULL; 4061098859f1SRichard Henderson } 4062098859f1SRichard Henderson tcg_debug_assert(s->reg_to_temp[reg] == NULL); 4063098859f1SRichard Henderson s->reg_to_temp[reg] = ts; 4064098859f1SRichard Henderson ts->val_type = TEMP_VAL_REG; 4065098859f1SRichard Henderson ts->reg = reg; 4066098859f1SRichard Henderson } 4067098859f1SRichard Henderson 4068098859f1SRichard Henderson /* Assign a non-register value type to @ts, and update reg_to_temp[]. */ 4069098859f1SRichard Henderson static void set_temp_val_nonreg(TCGContext *s, TCGTemp *ts, TCGTempVal type) 4070098859f1SRichard Henderson { 4071098859f1SRichard Henderson tcg_debug_assert(type != TEMP_VAL_REG); 4072098859f1SRichard Henderson if (ts->val_type == TEMP_VAL_REG) { 4073098859f1SRichard Henderson TCGReg reg = ts->reg; 4074098859f1SRichard Henderson tcg_debug_assert(s->reg_to_temp[reg] == ts); 4075098859f1SRichard Henderson s->reg_to_temp[reg] = NULL; 4076098859f1SRichard Henderson } 4077098859f1SRichard Henderson ts->val_type = type; 4078098859f1SRichard Henderson } 4079098859f1SRichard Henderson 4080b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet); 4081b3915dbbSRichard Henderson 408259d7c14eSRichard Henderson /* Mark a temporary as free or dead. If 'free_or_dead' is negative, 408359d7c14eSRichard Henderson mark it free; otherwise mark it dead. */ 408459d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead) 4085c896fe29Sbellard { 4086c0522136SRichard Henderson TCGTempVal new_type; 4087c0522136SRichard Henderson 4088c0522136SRichard Henderson switch (ts->kind) { 4089c0522136SRichard Henderson case TEMP_FIXED: 409059d7c14eSRichard Henderson return; 4091c0522136SRichard Henderson case TEMP_GLOBAL: 4092f57c6915SRichard Henderson case TEMP_TB: 4093c0522136SRichard Henderson new_type = TEMP_VAL_MEM; 4094c0522136SRichard Henderson break; 4095c7482438SRichard Henderson case TEMP_EBB: 4096c0522136SRichard Henderson new_type = free_or_dead < 0 ? TEMP_VAL_MEM : TEMP_VAL_DEAD; 4097c0522136SRichard Henderson break; 4098c0522136SRichard Henderson case TEMP_CONST: 4099c0522136SRichard Henderson new_type = TEMP_VAL_CONST; 4100c0522136SRichard Henderson break; 4101c0522136SRichard Henderson default: 4102c0522136SRichard Henderson g_assert_not_reached(); 410359d7c14eSRichard Henderson } 4104098859f1SRichard Henderson set_temp_val_nonreg(s, ts, new_type); 410559d7c14eSRichard Henderson } 4106c896fe29Sbellard 410759d7c14eSRichard Henderson /* Mark a temporary as dead. */ 410859d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts) 410959d7c14eSRichard Henderson { 411059d7c14eSRichard Henderson temp_free_or_dead(s, ts, 1); 411159d7c14eSRichard Henderson } 411259d7c14eSRichard Henderson 411359d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary 411459d7c14eSRichard Henderson registers needs to be allocated to store a constant. If 'free_or_dead' 411559d7c14eSRichard Henderson is non-zero, subsequently release the temporary; if it is positive, the 411659d7c14eSRichard Henderson temp is dead; if it is negative, the temp is free. */ 411798b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs, 411898b4e186SRichard Henderson TCGRegSet preferred_regs, int free_or_dead) 411959d7c14eSRichard Henderson { 4120c0522136SRichard Henderson if (!temp_readonly(ts) && !ts->mem_coherent) { 41217f6ceedfSAurelien Jarno if (!ts->mem_allocated) { 41222272e4a7SRichard Henderson temp_allocate_frame(s, ts); 412359d7c14eSRichard Henderson } 412459d7c14eSRichard Henderson switch (ts->val_type) { 412559d7c14eSRichard Henderson case TEMP_VAL_CONST: 412659d7c14eSRichard Henderson /* If we're going to free the temp immediately, then we won't 412759d7c14eSRichard Henderson require it later in a register, so attempt to store the 412859d7c14eSRichard Henderson constant to memory directly. */ 412959d7c14eSRichard Henderson if (free_or_dead 413059d7c14eSRichard Henderson && tcg_out_sti(s, ts->type, ts->val, 413159d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset)) { 413259d7c14eSRichard Henderson break; 413359d7c14eSRichard Henderson } 413459d7c14eSRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 413598b4e186SRichard Henderson allocated_regs, preferred_regs); 413659d7c14eSRichard Henderson /* fallthrough */ 413759d7c14eSRichard Henderson 413859d7c14eSRichard Henderson case TEMP_VAL_REG: 413959d7c14eSRichard Henderson tcg_out_st(s, ts->type, ts->reg, 414059d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset); 414159d7c14eSRichard Henderson break; 414259d7c14eSRichard Henderson 414359d7c14eSRichard Henderson case TEMP_VAL_MEM: 414459d7c14eSRichard Henderson break; 414559d7c14eSRichard Henderson 414659d7c14eSRichard Henderson case TEMP_VAL_DEAD: 414759d7c14eSRichard Henderson default: 4148732e89f4SRichard Henderson g_assert_not_reached(); 4149c896fe29Sbellard } 41507f6ceedfSAurelien Jarno ts->mem_coherent = 1; 41517f6ceedfSAurelien Jarno } 415259d7c14eSRichard Henderson if (free_or_dead) { 415359d7c14eSRichard Henderson temp_free_or_dead(s, ts, free_or_dead); 415459d7c14eSRichard Henderson } 415559d7c14eSRichard Henderson } 41567f6ceedfSAurelien Jarno 41577f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */ 4158b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs) 41597f6ceedfSAurelien Jarno { 4160f8b2f202SRichard Henderson TCGTemp *ts = s->reg_to_temp[reg]; 4161f8b2f202SRichard Henderson if (ts != NULL) { 416298b4e186SRichard Henderson temp_sync(s, ts, allocated_regs, 0, -1); 4163c896fe29Sbellard } 4164c896fe29Sbellard } 4165c896fe29Sbellard 4166b016486eSRichard Henderson /** 4167b016486eSRichard Henderson * tcg_reg_alloc: 4168b016486eSRichard Henderson * @required_regs: Set of registers in which we must allocate. 4169b016486eSRichard Henderson * @allocated_regs: Set of registers which must be avoided. 4170b016486eSRichard Henderson * @preferred_regs: Set of registers we should prefer. 4171b016486eSRichard Henderson * @rev: True if we search the registers in "indirect" order. 4172b016486eSRichard Henderson * 4173b016486eSRichard Henderson * The allocated register must be in @required_regs & ~@allocated_regs, 4174b016486eSRichard Henderson * but if we can put it in @preferred_regs we may save a move later. 4175b016486eSRichard Henderson */ 4176b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs, 4177b016486eSRichard Henderson TCGRegSet allocated_regs, 4178b016486eSRichard Henderson TCGRegSet preferred_regs, bool rev) 4179c896fe29Sbellard { 4180b016486eSRichard Henderson int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order); 4181b016486eSRichard Henderson TCGRegSet reg_ct[2]; 418291478cefSRichard Henderson const int *order; 4183c896fe29Sbellard 4184b016486eSRichard Henderson reg_ct[1] = required_regs & ~allocated_regs; 4185b016486eSRichard Henderson tcg_debug_assert(reg_ct[1] != 0); 4186b016486eSRichard Henderson reg_ct[0] = reg_ct[1] & preferred_regs; 4187b016486eSRichard Henderson 4188b016486eSRichard Henderson /* Skip the preferred_regs option if it cannot be satisfied, 4189b016486eSRichard Henderson or if the preference made no difference. */ 4190b016486eSRichard Henderson f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1]; 4191b016486eSRichard Henderson 419291478cefSRichard Henderson order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order; 4193c896fe29Sbellard 4194b016486eSRichard Henderson /* Try free registers, preferences first. */ 4195b016486eSRichard Henderson for (j = f; j < 2; j++) { 4196b016486eSRichard Henderson TCGRegSet set = reg_ct[j]; 4197b016486eSRichard Henderson 4198b016486eSRichard Henderson if (tcg_regset_single(set)) { 4199b016486eSRichard Henderson /* One register in the set. */ 4200b016486eSRichard Henderson TCGReg reg = tcg_regset_first(set); 4201b016486eSRichard Henderson if (s->reg_to_temp[reg] == NULL) { 4202c896fe29Sbellard return reg; 4203c896fe29Sbellard } 4204b016486eSRichard Henderson } else { 420591478cefSRichard Henderson for (i = 0; i < n; i++) { 4206b016486eSRichard Henderson TCGReg reg = order[i]; 4207b016486eSRichard Henderson if (s->reg_to_temp[reg] == NULL && 4208b016486eSRichard Henderson tcg_regset_test_reg(set, reg)) { 4209b016486eSRichard Henderson return reg; 4210b016486eSRichard Henderson } 4211b016486eSRichard Henderson } 4212b016486eSRichard Henderson } 4213b016486eSRichard Henderson } 4214b016486eSRichard Henderson 4215b016486eSRichard Henderson /* We must spill something. */ 4216b016486eSRichard Henderson for (j = f; j < 2; j++) { 4217b016486eSRichard Henderson TCGRegSet set = reg_ct[j]; 4218b016486eSRichard Henderson 4219b016486eSRichard Henderson if (tcg_regset_single(set)) { 4220b016486eSRichard Henderson /* One register in the set. */ 4221b016486eSRichard Henderson TCGReg reg = tcg_regset_first(set); 4222b3915dbbSRichard Henderson tcg_reg_free(s, reg, allocated_regs); 4223c896fe29Sbellard return reg; 4224b016486eSRichard Henderson } else { 4225b016486eSRichard Henderson for (i = 0; i < n; i++) { 4226b016486eSRichard Henderson TCGReg reg = order[i]; 4227b016486eSRichard Henderson if (tcg_regset_test_reg(set, reg)) { 4228b016486eSRichard Henderson tcg_reg_free(s, reg, allocated_regs); 4229b016486eSRichard Henderson return reg; 4230b016486eSRichard Henderson } 4231b016486eSRichard Henderson } 4232c896fe29Sbellard } 4233c896fe29Sbellard } 4234c896fe29Sbellard 4235732e89f4SRichard Henderson g_assert_not_reached(); 4236c896fe29Sbellard } 4237c896fe29Sbellard 423829f5e925SRichard Henderson static TCGReg tcg_reg_alloc_pair(TCGContext *s, TCGRegSet required_regs, 423929f5e925SRichard Henderson TCGRegSet allocated_regs, 424029f5e925SRichard Henderson TCGRegSet preferred_regs, bool rev) 424129f5e925SRichard Henderson { 424229f5e925SRichard Henderson int i, j, k, fmin, n = ARRAY_SIZE(tcg_target_reg_alloc_order); 424329f5e925SRichard Henderson TCGRegSet reg_ct[2]; 424429f5e925SRichard Henderson const int *order; 424529f5e925SRichard Henderson 424629f5e925SRichard Henderson /* Ensure that if I is not in allocated_regs, I+1 is not either. */ 424729f5e925SRichard Henderson reg_ct[1] = required_regs & ~(allocated_regs | (allocated_regs >> 1)); 424829f5e925SRichard Henderson tcg_debug_assert(reg_ct[1] != 0); 424929f5e925SRichard Henderson reg_ct[0] = reg_ct[1] & preferred_regs; 425029f5e925SRichard Henderson 425129f5e925SRichard Henderson order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order; 425229f5e925SRichard Henderson 425329f5e925SRichard Henderson /* 425429f5e925SRichard Henderson * Skip the preferred_regs option if it cannot be satisfied, 425529f5e925SRichard Henderson * or if the preference made no difference. 425629f5e925SRichard Henderson */ 425729f5e925SRichard Henderson k = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1]; 425829f5e925SRichard Henderson 425929f5e925SRichard Henderson /* 426029f5e925SRichard Henderson * Minimize the number of flushes by looking for 2 free registers first, 426129f5e925SRichard Henderson * then a single flush, then two flushes. 426229f5e925SRichard Henderson */ 426329f5e925SRichard Henderson for (fmin = 2; fmin >= 0; fmin--) { 426429f5e925SRichard Henderson for (j = k; j < 2; j++) { 426529f5e925SRichard Henderson TCGRegSet set = reg_ct[j]; 426629f5e925SRichard Henderson 426729f5e925SRichard Henderson for (i = 0; i < n; i++) { 426829f5e925SRichard Henderson TCGReg reg = order[i]; 426929f5e925SRichard Henderson 427029f5e925SRichard Henderson if (tcg_regset_test_reg(set, reg)) { 427129f5e925SRichard Henderson int f = !s->reg_to_temp[reg] + !s->reg_to_temp[reg + 1]; 427229f5e925SRichard Henderson if (f >= fmin) { 427329f5e925SRichard Henderson tcg_reg_free(s, reg, allocated_regs); 427429f5e925SRichard Henderson tcg_reg_free(s, reg + 1, allocated_regs); 427529f5e925SRichard Henderson return reg; 427629f5e925SRichard Henderson } 427729f5e925SRichard Henderson } 427829f5e925SRichard Henderson } 427929f5e925SRichard Henderson } 428029f5e925SRichard Henderson } 4281732e89f4SRichard Henderson g_assert_not_reached(); 428229f5e925SRichard Henderson } 428329f5e925SRichard Henderson 428440ae5c62SRichard Henderson /* Make sure the temporary is in a register. If needed, allocate the register 428540ae5c62SRichard Henderson from DESIRED while avoiding ALLOCATED. */ 428640ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs, 4287b722452aSRichard Henderson TCGRegSet allocated_regs, TCGRegSet preferred_regs) 428840ae5c62SRichard Henderson { 428940ae5c62SRichard Henderson TCGReg reg; 429040ae5c62SRichard Henderson 429140ae5c62SRichard Henderson switch (ts->val_type) { 429240ae5c62SRichard Henderson case TEMP_VAL_REG: 429340ae5c62SRichard Henderson return; 429440ae5c62SRichard Henderson case TEMP_VAL_CONST: 4295b016486eSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs, 4296b722452aSRichard Henderson preferred_regs, ts->indirect_base); 42970a6a8bc8SRichard Henderson if (ts->type <= TCG_TYPE_I64) { 429840ae5c62SRichard Henderson tcg_out_movi(s, ts->type, reg, ts->val); 42990a6a8bc8SRichard Henderson } else { 43004e186175SRichard Henderson uint64_t val = ts->val; 43014e186175SRichard Henderson MemOp vece = MO_64; 43024e186175SRichard Henderson 43034e186175SRichard Henderson /* 43044e186175SRichard Henderson * Find the minimal vector element that matches the constant. 43054e186175SRichard Henderson * The targets will, in general, have to do this search anyway, 43064e186175SRichard Henderson * do this generically. 43074e186175SRichard Henderson */ 43084e186175SRichard Henderson if (val == dup_const(MO_8, val)) { 43094e186175SRichard Henderson vece = MO_8; 43104e186175SRichard Henderson } else if (val == dup_const(MO_16, val)) { 43114e186175SRichard Henderson vece = MO_16; 43120b4286ddSRichard Henderson } else if (val == dup_const(MO_32, val)) { 43134e186175SRichard Henderson vece = MO_32; 43144e186175SRichard Henderson } 43154e186175SRichard Henderson 43164e186175SRichard Henderson tcg_out_dupi_vec(s, ts->type, vece, reg, ts->val); 43170a6a8bc8SRichard Henderson } 431840ae5c62SRichard Henderson ts->mem_coherent = 0; 431940ae5c62SRichard Henderson break; 432040ae5c62SRichard Henderson case TEMP_VAL_MEM: 4321b016486eSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs, 4322b722452aSRichard Henderson preferred_regs, ts->indirect_base); 432340ae5c62SRichard Henderson tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset); 432440ae5c62SRichard Henderson ts->mem_coherent = 1; 432540ae5c62SRichard Henderson break; 432640ae5c62SRichard Henderson case TEMP_VAL_DEAD: 432740ae5c62SRichard Henderson default: 4328732e89f4SRichard Henderson g_assert_not_reached(); 432940ae5c62SRichard Henderson } 4330098859f1SRichard Henderson set_temp_val_reg(s, ts, reg); 433140ae5c62SRichard Henderson } 433240ae5c62SRichard Henderson 433359d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a 4334e8996ee0Sbellard temporary registers needs to be allocated to store a constant. */ 433559d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs) 43361ad80729SAurelien Jarno { 43372c0366f0SAurelien Jarno /* The liveness analysis already ensures that globals are back 4338eabb7b91SAurelien Jarno in memory. Keep an tcg_debug_assert for safety. */ 4339e01fa97dSRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || temp_readonly(ts)); 43401ad80729SAurelien Jarno } 43411ad80729SAurelien Jarno 43429814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be 4343641d5fbeSbellard modified be the following code. 'allocated_regs' is used in case a 4344641d5fbeSbellard temporary registers needs to be allocated to store a constant. */ 4345641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs) 4346641d5fbeSbellard { 4347ac3b8891SRichard Henderson int i, n; 4348641d5fbeSbellard 4349ac3b8891SRichard Henderson for (i = 0, n = s->nb_globals; i < n; i++) { 4350b13eb728SRichard Henderson temp_save(s, &s->temps[i], allocated_regs); 4351641d5fbeSbellard } 4352e5097dc8Sbellard } 4353e5097dc8Sbellard 43543d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be 43553d5c5f87SAurelien Jarno read by the following code. 'allocated_regs' is used in case a 43563d5c5f87SAurelien Jarno temporary registers needs to be allocated to store a constant. */ 43573d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs) 43583d5c5f87SAurelien Jarno { 4359ac3b8891SRichard Henderson int i, n; 43603d5c5f87SAurelien Jarno 4361ac3b8891SRichard Henderson for (i = 0, n = s->nb_globals; i < n; i++) { 436212b9b11aSRichard Henderson TCGTemp *ts = &s->temps[i]; 436312b9b11aSRichard Henderson tcg_debug_assert(ts->val_type != TEMP_VAL_REG 4364ee17db83SRichard Henderson || ts->kind == TEMP_FIXED 436512b9b11aSRichard Henderson || ts->mem_coherent); 43663d5c5f87SAurelien Jarno } 43673d5c5f87SAurelien Jarno } 43683d5c5f87SAurelien Jarno 4369e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and 4370e8996ee0Sbellard all globals are stored at their canonical location. */ 4371e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs) 4372e5097dc8Sbellard { 4373e5097dc8Sbellard int i; 4374e5097dc8Sbellard 4375c896fe29Sbellard for (i = s->nb_globals; i < s->nb_temps; i++) { 4376b13eb728SRichard Henderson TCGTemp *ts = &s->temps[i]; 4377c0522136SRichard Henderson 4378c0522136SRichard Henderson switch (ts->kind) { 4379f57c6915SRichard Henderson case TEMP_TB: 4380b13eb728SRichard Henderson temp_save(s, ts, allocated_regs); 4381c0522136SRichard Henderson break; 4382c7482438SRichard Henderson case TEMP_EBB: 43832c0366f0SAurelien Jarno /* The liveness analysis already ensures that temps are dead. 4384eabb7b91SAurelien Jarno Keep an tcg_debug_assert for safety. */ 4385eabb7b91SAurelien Jarno tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD); 4386c0522136SRichard Henderson break; 4387c0522136SRichard Henderson case TEMP_CONST: 4388c0522136SRichard Henderson /* Similarly, we should have freed any allocated register. */ 4389c0522136SRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_CONST); 4390c0522136SRichard Henderson break; 4391c0522136SRichard Henderson default: 4392c0522136SRichard Henderson g_assert_not_reached(); 4393c896fe29Sbellard } 4394641d5fbeSbellard } 4395e8996ee0Sbellard 4396e8996ee0Sbellard save_globals(s, allocated_regs); 4397c896fe29Sbellard } 4398c896fe29Sbellard 4399bab1671fSRichard Henderson /* 4400c7482438SRichard Henderson * At a conditional branch, we assume all temporaries are dead unless 4401c7482438SRichard Henderson * explicitly live-across-conditional-branch; all globals and local 4402c7482438SRichard Henderson * temps are synced to their location. 4403b4cb76e6SRichard Henderson */ 4404b4cb76e6SRichard Henderson static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs) 4405b4cb76e6SRichard Henderson { 4406b4cb76e6SRichard Henderson sync_globals(s, allocated_regs); 4407b4cb76e6SRichard Henderson 4408b4cb76e6SRichard Henderson for (int i = s->nb_globals; i < s->nb_temps; i++) { 4409b4cb76e6SRichard Henderson TCGTemp *ts = &s->temps[i]; 4410b4cb76e6SRichard Henderson /* 4411b4cb76e6SRichard Henderson * The liveness analysis already ensures that temps are dead. 4412b4cb76e6SRichard Henderson * Keep tcg_debug_asserts for safety. 4413b4cb76e6SRichard Henderson */ 4414c0522136SRichard Henderson switch (ts->kind) { 4415f57c6915SRichard Henderson case TEMP_TB: 4416b4cb76e6SRichard Henderson tcg_debug_assert(ts->val_type != TEMP_VAL_REG || ts->mem_coherent); 4417c0522136SRichard Henderson break; 4418c7482438SRichard Henderson case TEMP_EBB: 4419c0522136SRichard Henderson case TEMP_CONST: 4420c0522136SRichard Henderson break; 4421c0522136SRichard Henderson default: 4422c0522136SRichard Henderson g_assert_not_reached(); 4423b4cb76e6SRichard Henderson } 4424b4cb76e6SRichard Henderson } 4425b4cb76e6SRichard Henderson } 4426b4cb76e6SRichard Henderson 4427b4cb76e6SRichard Henderson /* 4428c58f4c97SRichard Henderson * Specialized code generation for INDEX_op_mov_* with a constant. 4429bab1671fSRichard Henderson */ 44300fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots, 4431ba87719cSRichard Henderson tcg_target_ulong val, TCGLifeData arg_life, 4432ba87719cSRichard Henderson TCGRegSet preferred_regs) 4433e8996ee0Sbellard { 4434d63e3b6eSRichard Henderson /* ENV should not be modified. */ 4435e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 443659d7c14eSRichard Henderson 443759d7c14eSRichard Henderson /* The movi is not explicitly generated here. */ 4438098859f1SRichard Henderson set_temp_val_nonreg(s, ots, TEMP_VAL_CONST); 4439e8996ee0Sbellard ots->val = val; 444059d7c14eSRichard Henderson ots->mem_coherent = 0; 4441ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) { 4442ba87719cSRichard Henderson temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0)); 444359d7c14eSRichard Henderson } else if (IS_DEAD_ARG(0)) { 4444f8bf00f1SRichard Henderson temp_dead(s, ots); 44454c4e1ab2SAurelien Jarno } 4446e8996ee0Sbellard } 4447e8996ee0Sbellard 4448bab1671fSRichard Henderson /* 4449bab1671fSRichard Henderson * Specialized code generation for INDEX_op_mov_*. 4450bab1671fSRichard Henderson */ 4451dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op) 4452c896fe29Sbellard { 4453dd186292SRichard Henderson const TCGLifeData arg_life = op->life; 445469e3706dSRichard Henderson TCGRegSet allocated_regs, preferred_regs; 4455c896fe29Sbellard TCGTemp *ts, *ots; 4456450445d5SRichard Henderson TCGType otype, itype; 4457098859f1SRichard Henderson TCGReg oreg, ireg; 4458c896fe29Sbellard 4459d21369f5SRichard Henderson allocated_regs = s->reserved_regs; 446031fd884bSRichard Henderson preferred_regs = output_pref(op, 0); 446143439139SRichard Henderson ots = arg_temp(op->args[0]); 446243439139SRichard Henderson ts = arg_temp(op->args[1]); 4463450445d5SRichard Henderson 4464d63e3b6eSRichard Henderson /* ENV should not be modified. */ 4465e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 4466d63e3b6eSRichard Henderson 4467450445d5SRichard Henderson /* Note that otype != itype for no-op truncation. */ 4468450445d5SRichard Henderson otype = ots->type; 4469450445d5SRichard Henderson itype = ts->type; 4470c896fe29Sbellard 44710fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_CONST) { 44720fe4fca4SPaolo Bonzini /* propagate constant or generate sti */ 44730fe4fca4SPaolo Bonzini tcg_target_ulong val = ts->val; 44740fe4fca4SPaolo Bonzini if (IS_DEAD_ARG(1)) { 44750fe4fca4SPaolo Bonzini temp_dead(s, ts); 44760fe4fca4SPaolo Bonzini } 447769e3706dSRichard Henderson tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs); 44780fe4fca4SPaolo Bonzini return; 44790fe4fca4SPaolo Bonzini } 44800fe4fca4SPaolo Bonzini 44810fe4fca4SPaolo Bonzini /* If the source value is in memory we're going to be forced 44820fe4fca4SPaolo Bonzini to have it in a register in order to perform the copy. Copy 44830fe4fca4SPaolo Bonzini the SOURCE value into its own register first, that way we 44840fe4fca4SPaolo Bonzini don't have to reload SOURCE the next time it is used. */ 44850fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_MEM) { 448669e3706dSRichard Henderson temp_load(s, ts, tcg_target_available_regs[itype], 448769e3706dSRichard Henderson allocated_regs, preferred_regs); 4488c29c1d7eSAurelien Jarno } 44890fe4fca4SPaolo Bonzini tcg_debug_assert(ts->val_type == TEMP_VAL_REG); 4490098859f1SRichard Henderson ireg = ts->reg; 4491098859f1SRichard Henderson 4492d63e3b6eSRichard Henderson if (IS_DEAD_ARG(0)) { 4493c29c1d7eSAurelien Jarno /* mov to a non-saved dead register makes no sense (even with 4494c29c1d7eSAurelien Jarno liveness analysis disabled). */ 4495eabb7b91SAurelien Jarno tcg_debug_assert(NEED_SYNC_ARG(0)); 4496c29c1d7eSAurelien Jarno if (!ots->mem_allocated) { 44972272e4a7SRichard Henderson temp_allocate_frame(s, ots); 4498c29c1d7eSAurelien Jarno } 4499098859f1SRichard Henderson tcg_out_st(s, otype, ireg, ots->mem_base->reg, ots->mem_offset); 4500c29c1d7eSAurelien Jarno if (IS_DEAD_ARG(1)) { 4501f8bf00f1SRichard Henderson temp_dead(s, ts); 4502c29c1d7eSAurelien Jarno } 4503f8bf00f1SRichard Henderson temp_dead(s, ots); 4504098859f1SRichard Henderson return; 4505098859f1SRichard Henderson } 4506098859f1SRichard Henderson 4507ee17db83SRichard Henderson if (IS_DEAD_ARG(1) && ts->kind != TEMP_FIXED) { 4508098859f1SRichard Henderson /* 4509098859f1SRichard Henderson * The mov can be suppressed. Kill input first, so that it 4510098859f1SRichard Henderson * is unlinked from reg_to_temp, then set the output to the 4511098859f1SRichard Henderson * reg that we saved from the input. 4512098859f1SRichard Henderson */ 4513f8bf00f1SRichard Henderson temp_dead(s, ts); 4514098859f1SRichard Henderson oreg = ireg; 4515c29c1d7eSAurelien Jarno } else { 4516098859f1SRichard Henderson if (ots->val_type == TEMP_VAL_REG) { 4517098859f1SRichard Henderson oreg = ots->reg; 4518098859f1SRichard Henderson } else { 4519098859f1SRichard Henderson /* Make sure to not spill the input register during allocation. */ 4520098859f1SRichard Henderson oreg = tcg_reg_alloc(s, tcg_target_available_regs[otype], 4521098859f1SRichard Henderson allocated_regs | ((TCGRegSet)1 << ireg), 4522098859f1SRichard Henderson preferred_regs, ots->indirect_base); 4523c29c1d7eSAurelien Jarno } 4524098859f1SRichard Henderson if (!tcg_out_mov(s, otype, oreg, ireg)) { 4525240c08d0SRichard Henderson /* 4526240c08d0SRichard Henderson * Cross register class move not supported. 4527240c08d0SRichard Henderson * Store the source register into the destination slot 4528240c08d0SRichard Henderson * and leave the destination temp as TEMP_VAL_MEM. 4529240c08d0SRichard Henderson */ 4530e01fa97dSRichard Henderson assert(!temp_readonly(ots)); 4531240c08d0SRichard Henderson if (!ts->mem_allocated) { 4532240c08d0SRichard Henderson temp_allocate_frame(s, ots); 4533240c08d0SRichard Henderson } 4534098859f1SRichard Henderson tcg_out_st(s, ts->type, ireg, ots->mem_base->reg, ots->mem_offset); 4535098859f1SRichard Henderson set_temp_val_nonreg(s, ts, TEMP_VAL_MEM); 4536240c08d0SRichard Henderson ots->mem_coherent = 1; 4537240c08d0SRichard Henderson return; 453878113e83SRichard Henderson } 4539c29c1d7eSAurelien Jarno } 4540098859f1SRichard Henderson set_temp_val_reg(s, ots, oreg); 4541c896fe29Sbellard ots->mem_coherent = 0; 4542098859f1SRichard Henderson 4543ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) { 454498b4e186SRichard Henderson temp_sync(s, ots, allocated_regs, 0, 0); 4545c29c1d7eSAurelien Jarno } 4546ec7a869dSAurelien Jarno } 4547c896fe29Sbellard 4548bab1671fSRichard Henderson /* 4549bab1671fSRichard Henderson * Specialized code generation for INDEX_op_dup_vec. 4550bab1671fSRichard Henderson */ 4551bab1671fSRichard Henderson static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op) 4552bab1671fSRichard Henderson { 4553bab1671fSRichard Henderson const TCGLifeData arg_life = op->life; 4554bab1671fSRichard Henderson TCGRegSet dup_out_regs, dup_in_regs; 4555bab1671fSRichard Henderson TCGTemp *its, *ots; 4556bab1671fSRichard Henderson TCGType itype, vtype; 4557bab1671fSRichard Henderson unsigned vece; 455831c96417SRichard Henderson int lowpart_ofs; 4559bab1671fSRichard Henderson bool ok; 4560bab1671fSRichard Henderson 4561bab1671fSRichard Henderson ots = arg_temp(op->args[0]); 4562bab1671fSRichard Henderson its = arg_temp(op->args[1]); 4563bab1671fSRichard Henderson 4564bab1671fSRichard Henderson /* ENV should not be modified. */ 4565e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 4566bab1671fSRichard Henderson 4567bab1671fSRichard Henderson itype = its->type; 4568bab1671fSRichard Henderson vece = TCGOP_VECE(op); 4569bab1671fSRichard Henderson vtype = TCGOP_VECL(op) + TCG_TYPE_V64; 4570bab1671fSRichard Henderson 4571bab1671fSRichard Henderson if (its->val_type == TEMP_VAL_CONST) { 4572bab1671fSRichard Henderson /* Propagate constant via movi -> dupi. */ 4573bab1671fSRichard Henderson tcg_target_ulong val = its->val; 4574bab1671fSRichard Henderson if (IS_DEAD_ARG(1)) { 4575bab1671fSRichard Henderson temp_dead(s, its); 4576bab1671fSRichard Henderson } 457731fd884bSRichard Henderson tcg_reg_alloc_do_movi(s, ots, val, arg_life, output_pref(op, 0)); 4578bab1671fSRichard Henderson return; 4579bab1671fSRichard Henderson } 4580bab1671fSRichard Henderson 45819be0d080SRichard Henderson dup_out_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs; 45829be0d080SRichard Henderson dup_in_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[1].regs; 4583bab1671fSRichard Henderson 4584bab1671fSRichard Henderson /* Allocate the output register now. */ 4585bab1671fSRichard Henderson if (ots->val_type != TEMP_VAL_REG) { 4586bab1671fSRichard Henderson TCGRegSet allocated_regs = s->reserved_regs; 4587098859f1SRichard Henderson TCGReg oreg; 4588bab1671fSRichard Henderson 4589bab1671fSRichard Henderson if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) { 4590bab1671fSRichard Henderson /* Make sure to not spill the input register. */ 4591bab1671fSRichard Henderson tcg_regset_set_reg(allocated_regs, its->reg); 4592bab1671fSRichard Henderson } 4593098859f1SRichard Henderson oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs, 459431fd884bSRichard Henderson output_pref(op, 0), ots->indirect_base); 4595098859f1SRichard Henderson set_temp_val_reg(s, ots, oreg); 4596bab1671fSRichard Henderson } 4597bab1671fSRichard Henderson 4598bab1671fSRichard Henderson switch (its->val_type) { 4599bab1671fSRichard Henderson case TEMP_VAL_REG: 4600bab1671fSRichard Henderson /* 4601bab1671fSRichard Henderson * The dup constriaints must be broad, covering all possible VECE. 4602bab1671fSRichard Henderson * However, tcg_op_dup_vec() gets to see the VECE and we allow it 4603bab1671fSRichard Henderson * to fail, indicating that extra moves are required for that case. 4604bab1671fSRichard Henderson */ 4605bab1671fSRichard Henderson if (tcg_regset_test_reg(dup_in_regs, its->reg)) { 4606bab1671fSRichard Henderson if (tcg_out_dup_vec(s, vtype, vece, ots->reg, its->reg)) { 4607bab1671fSRichard Henderson goto done; 4608bab1671fSRichard Henderson } 4609bab1671fSRichard Henderson /* Try again from memory or a vector input register. */ 4610bab1671fSRichard Henderson } 4611bab1671fSRichard Henderson if (!its->mem_coherent) { 4612bab1671fSRichard Henderson /* 4613bab1671fSRichard Henderson * The input register is not synced, and so an extra store 4614bab1671fSRichard Henderson * would be required to use memory. Attempt an integer-vector 4615bab1671fSRichard Henderson * register move first. We do not have a TCGRegSet for this. 4616bab1671fSRichard Henderson */ 4617bab1671fSRichard Henderson if (tcg_out_mov(s, itype, ots->reg, its->reg)) { 4618bab1671fSRichard Henderson break; 4619bab1671fSRichard Henderson } 4620bab1671fSRichard Henderson /* Sync the temp back to its slot and load from there. */ 4621bab1671fSRichard Henderson temp_sync(s, its, s->reserved_regs, 0, 0); 4622bab1671fSRichard Henderson } 4623bab1671fSRichard Henderson /* fall through */ 4624bab1671fSRichard Henderson 4625bab1671fSRichard Henderson case TEMP_VAL_MEM: 462631c96417SRichard Henderson lowpart_ofs = 0; 462731c96417SRichard Henderson if (HOST_BIG_ENDIAN) { 462831c96417SRichard Henderson lowpart_ofs = tcg_type_size(itype) - (1 << vece); 462931c96417SRichard Henderson } 4630d6ecb4a9SRichard Henderson if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg, 463131c96417SRichard Henderson its->mem_offset + lowpart_ofs)) { 4632d6ecb4a9SRichard Henderson goto done; 4633d6ecb4a9SRichard Henderson } 4634098859f1SRichard Henderson /* Load the input into the destination vector register. */ 4635bab1671fSRichard Henderson tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset); 4636bab1671fSRichard Henderson break; 4637bab1671fSRichard Henderson 4638bab1671fSRichard Henderson default: 4639bab1671fSRichard Henderson g_assert_not_reached(); 4640bab1671fSRichard Henderson } 4641bab1671fSRichard Henderson 4642bab1671fSRichard Henderson /* We now have a vector input register, so dup must succeed. */ 4643bab1671fSRichard Henderson ok = tcg_out_dup_vec(s, vtype, vece, ots->reg, ots->reg); 4644bab1671fSRichard Henderson tcg_debug_assert(ok); 4645bab1671fSRichard Henderson 4646bab1671fSRichard Henderson done: 464736f5539cSRichard Henderson ots->mem_coherent = 0; 4648bab1671fSRichard Henderson if (IS_DEAD_ARG(1)) { 4649bab1671fSRichard Henderson temp_dead(s, its); 4650bab1671fSRichard Henderson } 4651bab1671fSRichard Henderson if (NEED_SYNC_ARG(0)) { 4652bab1671fSRichard Henderson temp_sync(s, ots, s->reserved_regs, 0, 0); 4653bab1671fSRichard Henderson } 4654bab1671fSRichard Henderson if (IS_DEAD_ARG(0)) { 4655bab1671fSRichard Henderson temp_dead(s, ots); 4656bab1671fSRichard Henderson } 4657bab1671fSRichard Henderson } 4658bab1671fSRichard Henderson 4659dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) 4660c896fe29Sbellard { 4661dd186292SRichard Henderson const TCGLifeData arg_life = op->life; 4662dd186292SRichard Henderson const TCGOpDef * const def = &tcg_op_defs[op->opc]; 466382790a87SRichard Henderson TCGRegSet i_allocated_regs; 466482790a87SRichard Henderson TCGRegSet o_allocated_regs; 4665b6638662SRichard Henderson int i, k, nb_iargs, nb_oargs; 4666b6638662SRichard Henderson TCGReg reg; 4667c896fe29Sbellard TCGArg arg; 4668c896fe29Sbellard const TCGArgConstraint *arg_ct; 4669c896fe29Sbellard TCGTemp *ts; 4670c896fe29Sbellard TCGArg new_args[TCG_MAX_OP_ARGS]; 4671c896fe29Sbellard int const_args[TCG_MAX_OP_ARGS]; 4672c896fe29Sbellard 4673c896fe29Sbellard nb_oargs = def->nb_oargs; 4674c896fe29Sbellard nb_iargs = def->nb_iargs; 4675c896fe29Sbellard 4676c896fe29Sbellard /* copy constants */ 4677c896fe29Sbellard memcpy(new_args + nb_oargs + nb_iargs, 4678dd186292SRichard Henderson op->args + nb_oargs + nb_iargs, 4679c896fe29Sbellard sizeof(TCGArg) * def->nb_cargs); 4680c896fe29Sbellard 4681d21369f5SRichard Henderson i_allocated_regs = s->reserved_regs; 4682d21369f5SRichard Henderson o_allocated_regs = s->reserved_regs; 468382790a87SRichard Henderson 4684c896fe29Sbellard /* satisfy input constraints */ 4685c896fe29Sbellard for (k = 0; k < nb_iargs; k++) { 468629f5e925SRichard Henderson TCGRegSet i_preferred_regs, i_required_regs; 468729f5e925SRichard Henderson bool allocate_new_reg, copyto_new_reg; 468829f5e925SRichard Henderson TCGTemp *ts2; 468929f5e925SRichard Henderson int i1, i2; 4690d62816f2SRichard Henderson 469166792f90SRichard Henderson i = def->args_ct[nb_oargs + k].sort_index; 4692dd186292SRichard Henderson arg = op->args[i]; 4693c896fe29Sbellard arg_ct = &def->args_ct[i]; 469443439139SRichard Henderson ts = arg_temp(arg); 469540ae5c62SRichard Henderson 469640ae5c62SRichard Henderson if (ts->val_type == TEMP_VAL_CONST 4697ebe92db2SJiajie Chen && tcg_target_const_match(ts->val, ts->type, arg_ct->ct, TCGOP_VECE(op))) { 4698c896fe29Sbellard /* constant is OK for instruction */ 4699c896fe29Sbellard const_args[i] = 1; 4700c896fe29Sbellard new_args[i] = ts->val; 4701d62816f2SRichard Henderson continue; 4702c896fe29Sbellard } 470340ae5c62SRichard Henderson 47041c1824dcSRichard Henderson reg = ts->reg; 47051c1824dcSRichard Henderson i_preferred_regs = 0; 470629f5e925SRichard Henderson i_required_regs = arg_ct->regs; 47071c1824dcSRichard Henderson allocate_new_reg = false; 470829f5e925SRichard Henderson copyto_new_reg = false; 47091c1824dcSRichard Henderson 471029f5e925SRichard Henderson switch (arg_ct->pair) { 471129f5e925SRichard Henderson case 0: /* not paired */ 4712bc2b17e6SRichard Henderson if (arg_ct->ialias) { 471331fd884bSRichard Henderson i_preferred_regs = output_pref(op, arg_ct->alias_index); 4714c0522136SRichard Henderson 4715c0522136SRichard Henderson /* 4716c0522136SRichard Henderson * If the input is readonly, then it cannot also be an 4717c0522136SRichard Henderson * output and aliased to itself. If the input is not 4718c0522136SRichard Henderson * dead after the instruction, we must allocate a new 4719c0522136SRichard Henderson * register and move it. 4720c0522136SRichard Henderson */ 472122d2e535SIlya Leoshkevich if (temp_readonly(ts) || !IS_DEAD_ARG(i) 472222d2e535SIlya Leoshkevich || def->args_ct[arg_ct->alias_index].newreg) { 47231c1824dcSRichard Henderson allocate_new_reg = true; 47241c1824dcSRichard Henderson } else if (ts->val_type == TEMP_VAL_REG) { 4725c0522136SRichard Henderson /* 47261c1824dcSRichard Henderson * Check if the current register has already been 47271c1824dcSRichard Henderson * allocated for another input. 4728c0522136SRichard Henderson */ 472929f5e925SRichard Henderson allocate_new_reg = 473029f5e925SRichard Henderson tcg_regset_test_reg(i_allocated_regs, reg); 47317e1df267SAurelien Jarno } 47327e1df267SAurelien Jarno } 47331c1824dcSRichard Henderson if (!allocate_new_reg) { 473429f5e925SRichard Henderson temp_load(s, ts, i_required_regs, i_allocated_regs, 473529f5e925SRichard Henderson i_preferred_regs); 4736c896fe29Sbellard reg = ts->reg; 473729f5e925SRichard Henderson allocate_new_reg = !tcg_regset_test_reg(i_required_regs, reg); 47381c1824dcSRichard Henderson } 47391c1824dcSRichard Henderson if (allocate_new_reg) { 4740c0522136SRichard Henderson /* 4741c0522136SRichard Henderson * Allocate a new register matching the constraint 4742c0522136SRichard Henderson * and move the temporary register into it. 4743c0522136SRichard Henderson */ 4744d62816f2SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 4745d62816f2SRichard Henderson i_allocated_regs, 0); 474629f5e925SRichard Henderson reg = tcg_reg_alloc(s, i_required_regs, i_allocated_regs, 47471c1824dcSRichard Henderson i_preferred_regs, ts->indirect_base); 474829f5e925SRichard Henderson copyto_new_reg = true; 474929f5e925SRichard Henderson } 475029f5e925SRichard Henderson break; 475129f5e925SRichard Henderson 475229f5e925SRichard Henderson case 1: 475329f5e925SRichard Henderson /* First of an input pair; if i1 == i2, the second is an output. */ 475429f5e925SRichard Henderson i1 = i; 475529f5e925SRichard Henderson i2 = arg_ct->pair_index; 475629f5e925SRichard Henderson ts2 = i1 != i2 ? arg_temp(op->args[i2]) : NULL; 475729f5e925SRichard Henderson 475829f5e925SRichard Henderson /* 475929f5e925SRichard Henderson * It is easier to default to allocating a new pair 476029f5e925SRichard Henderson * and to identify a few cases where it's not required. 476129f5e925SRichard Henderson */ 476229f5e925SRichard Henderson if (arg_ct->ialias) { 476331fd884bSRichard Henderson i_preferred_regs = output_pref(op, arg_ct->alias_index); 476429f5e925SRichard Henderson if (IS_DEAD_ARG(i1) && 476529f5e925SRichard Henderson IS_DEAD_ARG(i2) && 476629f5e925SRichard Henderson !temp_readonly(ts) && 476729f5e925SRichard Henderson ts->val_type == TEMP_VAL_REG && 476829f5e925SRichard Henderson ts->reg < TCG_TARGET_NB_REGS - 1 && 476929f5e925SRichard Henderson tcg_regset_test_reg(i_required_regs, reg) && 477029f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg) && 477129f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg + 1) && 477229f5e925SRichard Henderson (ts2 477329f5e925SRichard Henderson ? ts2->val_type == TEMP_VAL_REG && 477429f5e925SRichard Henderson ts2->reg == reg + 1 && 477529f5e925SRichard Henderson !temp_readonly(ts2) 477629f5e925SRichard Henderson : s->reg_to_temp[reg + 1] == NULL)) { 477729f5e925SRichard Henderson break; 477829f5e925SRichard Henderson } 477929f5e925SRichard Henderson } else { 478029f5e925SRichard Henderson /* Without aliasing, the pair must also be an input. */ 478129f5e925SRichard Henderson tcg_debug_assert(ts2); 478229f5e925SRichard Henderson if (ts->val_type == TEMP_VAL_REG && 478329f5e925SRichard Henderson ts2->val_type == TEMP_VAL_REG && 478429f5e925SRichard Henderson ts2->reg == reg + 1 && 478529f5e925SRichard Henderson tcg_regset_test_reg(i_required_regs, reg)) { 478629f5e925SRichard Henderson break; 478729f5e925SRichard Henderson } 478829f5e925SRichard Henderson } 478929f5e925SRichard Henderson reg = tcg_reg_alloc_pair(s, i_required_regs, i_allocated_regs, 479029f5e925SRichard Henderson 0, ts->indirect_base); 479129f5e925SRichard Henderson goto do_pair; 479229f5e925SRichard Henderson 479329f5e925SRichard Henderson case 2: /* pair second */ 479429f5e925SRichard Henderson reg = new_args[arg_ct->pair_index] + 1; 479529f5e925SRichard Henderson goto do_pair; 479629f5e925SRichard Henderson 479729f5e925SRichard Henderson case 3: /* ialias with second output, no first input */ 479829f5e925SRichard Henderson tcg_debug_assert(arg_ct->ialias); 479931fd884bSRichard Henderson i_preferred_regs = output_pref(op, arg_ct->alias_index); 480029f5e925SRichard Henderson 480129f5e925SRichard Henderson if (IS_DEAD_ARG(i) && 480229f5e925SRichard Henderson !temp_readonly(ts) && 480329f5e925SRichard Henderson ts->val_type == TEMP_VAL_REG && 480429f5e925SRichard Henderson reg > 0 && 480529f5e925SRichard Henderson s->reg_to_temp[reg - 1] == NULL && 480629f5e925SRichard Henderson tcg_regset_test_reg(i_required_regs, reg) && 480729f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg) && 480829f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg - 1)) { 480929f5e925SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg - 1); 481029f5e925SRichard Henderson break; 481129f5e925SRichard Henderson } 481229f5e925SRichard Henderson reg = tcg_reg_alloc_pair(s, i_required_regs >> 1, 481329f5e925SRichard Henderson i_allocated_regs, 0, 481429f5e925SRichard Henderson ts->indirect_base); 481529f5e925SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg); 481629f5e925SRichard Henderson reg += 1; 481729f5e925SRichard Henderson goto do_pair; 481829f5e925SRichard Henderson 481929f5e925SRichard Henderson do_pair: 482029f5e925SRichard Henderson /* 482129f5e925SRichard Henderson * If an aliased input is not dead after the instruction, 482229f5e925SRichard Henderson * we must allocate a new register and move it. 482329f5e925SRichard Henderson */ 482429f5e925SRichard Henderson if (arg_ct->ialias && (!IS_DEAD_ARG(i) || temp_readonly(ts))) { 482529f5e925SRichard Henderson TCGRegSet t_allocated_regs = i_allocated_regs; 482629f5e925SRichard Henderson 482729f5e925SRichard Henderson /* 482829f5e925SRichard Henderson * Because of the alias, and the continued life, make sure 482929f5e925SRichard Henderson * that the temp is somewhere *other* than the reg pair, 483029f5e925SRichard Henderson * and we get a copy in reg. 483129f5e925SRichard Henderson */ 483229f5e925SRichard Henderson tcg_regset_set_reg(t_allocated_regs, reg); 483329f5e925SRichard Henderson tcg_regset_set_reg(t_allocated_regs, reg + 1); 483429f5e925SRichard Henderson if (ts->val_type == TEMP_VAL_REG && ts->reg == reg) { 483529f5e925SRichard Henderson /* If ts was already in reg, copy it somewhere else. */ 483629f5e925SRichard Henderson TCGReg nr; 483729f5e925SRichard Henderson bool ok; 483829f5e925SRichard Henderson 483929f5e925SRichard Henderson tcg_debug_assert(ts->kind != TEMP_FIXED); 484029f5e925SRichard Henderson nr = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], 484129f5e925SRichard Henderson t_allocated_regs, 0, ts->indirect_base); 484229f5e925SRichard Henderson ok = tcg_out_mov(s, ts->type, nr, reg); 484329f5e925SRichard Henderson tcg_debug_assert(ok); 484429f5e925SRichard Henderson 484529f5e925SRichard Henderson set_temp_val_reg(s, ts, nr); 484629f5e925SRichard Henderson } else { 484729f5e925SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 484829f5e925SRichard Henderson t_allocated_regs, 0); 484929f5e925SRichard Henderson copyto_new_reg = true; 485029f5e925SRichard Henderson } 485129f5e925SRichard Henderson } else { 485229f5e925SRichard Henderson /* Preferably allocate to reg, otherwise copy. */ 485329f5e925SRichard Henderson i_required_regs = (TCGRegSet)1 << reg; 485429f5e925SRichard Henderson temp_load(s, ts, i_required_regs, i_allocated_regs, 485529f5e925SRichard Henderson i_preferred_regs); 485629f5e925SRichard Henderson copyto_new_reg = ts->reg != reg; 485729f5e925SRichard Henderson } 485829f5e925SRichard Henderson break; 485929f5e925SRichard Henderson 486029f5e925SRichard Henderson default: 486129f5e925SRichard Henderson g_assert_not_reached(); 486229f5e925SRichard Henderson } 486329f5e925SRichard Henderson 486429f5e925SRichard Henderson if (copyto_new_reg) { 486578113e83SRichard Henderson if (!tcg_out_mov(s, ts->type, reg, ts->reg)) { 4866240c08d0SRichard Henderson /* 4867240c08d0SRichard Henderson * Cross register class move not supported. Sync the 4868240c08d0SRichard Henderson * temp back to its slot and load from there. 4869240c08d0SRichard Henderson */ 4870240c08d0SRichard Henderson temp_sync(s, ts, i_allocated_regs, 0, 0); 4871240c08d0SRichard Henderson tcg_out_ld(s, ts->type, reg, 4872240c08d0SRichard Henderson ts->mem_base->reg, ts->mem_offset); 487378113e83SRichard Henderson } 4874c896fe29Sbellard } 4875c896fe29Sbellard new_args[i] = reg; 4876c896fe29Sbellard const_args[i] = 0; 487782790a87SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg); 4878c896fe29Sbellard } 4879c896fe29Sbellard 4880c896fe29Sbellard /* mark dead temporaries and free the associated registers */ 4881866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 4882866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) { 488343439139SRichard Henderson temp_dead(s, arg_temp(op->args[i])); 4884c896fe29Sbellard } 4885c896fe29Sbellard } 4886c896fe29Sbellard 4887b4cb76e6SRichard Henderson if (def->flags & TCG_OPF_COND_BRANCH) { 4888b4cb76e6SRichard Henderson tcg_reg_alloc_cbranch(s, i_allocated_regs); 4889b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 489082790a87SRichard Henderson tcg_reg_alloc_bb_end(s, i_allocated_regs); 4891a52ad07eSAurelien Jarno } else { 4892c896fe29Sbellard if (def->flags & TCG_OPF_CALL_CLOBBER) { 4893b03cce8eSbellard /* XXX: permit generic clobber register list ? */ 4894c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) { 4895c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { 489682790a87SRichard Henderson tcg_reg_free(s, i, i_allocated_regs); 4897c896fe29Sbellard } 4898c896fe29Sbellard } 48993d5c5f87SAurelien Jarno } 49003d5c5f87SAurelien Jarno if (def->flags & TCG_OPF_SIDE_EFFECTS) { 49013d5c5f87SAurelien Jarno /* sync globals if the op has side effects and might trigger 49023d5c5f87SAurelien Jarno an exception. */ 490382790a87SRichard Henderson sync_globals(s, i_allocated_regs); 4904c896fe29Sbellard } 4905c896fe29Sbellard 4906c896fe29Sbellard /* satisfy the output constraints */ 4907c896fe29Sbellard for(k = 0; k < nb_oargs; k++) { 490866792f90SRichard Henderson i = def->args_ct[k].sort_index; 4909dd186292SRichard Henderson arg = op->args[i]; 4910c896fe29Sbellard arg_ct = &def->args_ct[i]; 491143439139SRichard Henderson ts = arg_temp(arg); 4912d63e3b6eSRichard Henderson 4913d63e3b6eSRichard Henderson /* ENV should not be modified. */ 4914e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ts)); 4915d63e3b6eSRichard Henderson 491629f5e925SRichard Henderson switch (arg_ct->pair) { 491729f5e925SRichard Henderson case 0: /* not paired */ 4918bc2b17e6SRichard Henderson if (arg_ct->oalias && !const_args[arg_ct->alias_index]) { 49195ff9d6a4Sbellard reg = new_args[arg_ct->alias_index]; 4920bc2b17e6SRichard Henderson } else if (arg_ct->newreg) { 49219be0d080SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->regs, 492282790a87SRichard Henderson i_allocated_regs | o_allocated_regs, 492331fd884bSRichard Henderson output_pref(op, k), ts->indirect_base); 4924c896fe29Sbellard } else { 49259be0d080SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs, 492631fd884bSRichard Henderson output_pref(op, k), ts->indirect_base); 4927c896fe29Sbellard } 492829f5e925SRichard Henderson break; 492929f5e925SRichard Henderson 493029f5e925SRichard Henderson case 1: /* first of pair */ 493129f5e925SRichard Henderson tcg_debug_assert(!arg_ct->newreg); 493229f5e925SRichard Henderson if (arg_ct->oalias) { 493329f5e925SRichard Henderson reg = new_args[arg_ct->alias_index]; 493429f5e925SRichard Henderson break; 493529f5e925SRichard Henderson } 493629f5e925SRichard Henderson reg = tcg_reg_alloc_pair(s, arg_ct->regs, o_allocated_regs, 493731fd884bSRichard Henderson output_pref(op, k), ts->indirect_base); 493829f5e925SRichard Henderson break; 493929f5e925SRichard Henderson 494029f5e925SRichard Henderson case 2: /* second of pair */ 494129f5e925SRichard Henderson tcg_debug_assert(!arg_ct->newreg); 494229f5e925SRichard Henderson if (arg_ct->oalias) { 494329f5e925SRichard Henderson reg = new_args[arg_ct->alias_index]; 494429f5e925SRichard Henderson } else { 494529f5e925SRichard Henderson reg = new_args[arg_ct->pair_index] + 1; 494629f5e925SRichard Henderson } 494729f5e925SRichard Henderson break; 494829f5e925SRichard Henderson 494929f5e925SRichard Henderson case 3: /* first of pair, aliasing with a second input */ 495029f5e925SRichard Henderson tcg_debug_assert(!arg_ct->newreg); 495129f5e925SRichard Henderson reg = new_args[arg_ct->pair_index] - 1; 495229f5e925SRichard Henderson break; 495329f5e925SRichard Henderson 495429f5e925SRichard Henderson default: 495529f5e925SRichard Henderson g_assert_not_reached(); 495629f5e925SRichard Henderson } 495782790a87SRichard Henderson tcg_regset_set_reg(o_allocated_regs, reg); 4958098859f1SRichard Henderson set_temp_val_reg(s, ts, reg); 4959c896fe29Sbellard ts->mem_coherent = 0; 4960c896fe29Sbellard new_args[i] = reg; 4961c896fe29Sbellard } 4962e8996ee0Sbellard } 4963c896fe29Sbellard 4964c896fe29Sbellard /* emit instruction */ 4965678155b2SRichard Henderson switch (op->opc) { 4966678155b2SRichard Henderson case INDEX_op_ext8s_i32: 4967678155b2SRichard Henderson tcg_out_ext8s(s, TCG_TYPE_I32, new_args[0], new_args[1]); 4968678155b2SRichard Henderson break; 4969678155b2SRichard Henderson case INDEX_op_ext8s_i64: 4970678155b2SRichard Henderson tcg_out_ext8s(s, TCG_TYPE_I64, new_args[0], new_args[1]); 4971678155b2SRichard Henderson break; 4972d0e66c89SRichard Henderson case INDEX_op_ext8u_i32: 4973d0e66c89SRichard Henderson case INDEX_op_ext8u_i64: 4974d0e66c89SRichard Henderson tcg_out_ext8u(s, new_args[0], new_args[1]); 4975d0e66c89SRichard Henderson break; 4976753e42eaSRichard Henderson case INDEX_op_ext16s_i32: 4977753e42eaSRichard Henderson tcg_out_ext16s(s, TCG_TYPE_I32, new_args[0], new_args[1]); 4978753e42eaSRichard Henderson break; 4979753e42eaSRichard Henderson case INDEX_op_ext16s_i64: 4980753e42eaSRichard Henderson tcg_out_ext16s(s, TCG_TYPE_I64, new_args[0], new_args[1]); 4981753e42eaSRichard Henderson break; 4982379afdffSRichard Henderson case INDEX_op_ext16u_i32: 4983379afdffSRichard Henderson case INDEX_op_ext16u_i64: 4984379afdffSRichard Henderson tcg_out_ext16u(s, new_args[0], new_args[1]); 4985379afdffSRichard Henderson break; 498652bf3398SRichard Henderson case INDEX_op_ext32s_i64: 498752bf3398SRichard Henderson tcg_out_ext32s(s, new_args[0], new_args[1]); 498852bf3398SRichard Henderson break; 49899ecf5f61SRichard Henderson case INDEX_op_ext32u_i64: 49909ecf5f61SRichard Henderson tcg_out_ext32u(s, new_args[0], new_args[1]); 49919ecf5f61SRichard Henderson break; 49929c6aa274SRichard Henderson case INDEX_op_ext_i32_i64: 49939c6aa274SRichard Henderson tcg_out_exts_i32_i64(s, new_args[0], new_args[1]); 49949c6aa274SRichard Henderson break; 4995b9bfe000SRichard Henderson case INDEX_op_extu_i32_i64: 4996b9bfe000SRichard Henderson tcg_out_extu_i32_i64(s, new_args[0], new_args[1]); 4997b9bfe000SRichard Henderson break; 4998b8b94ac6SRichard Henderson case INDEX_op_extrl_i64_i32: 4999b8b94ac6SRichard Henderson tcg_out_extrl_i64_i32(s, new_args[0], new_args[1]); 5000b8b94ac6SRichard Henderson break; 5001678155b2SRichard Henderson default: 5002d2fd745fSRichard Henderson if (def->flags & TCG_OPF_VECTOR) { 5003d2fd745fSRichard Henderson tcg_out_vec_op(s, op->opc, TCGOP_VECL(op), TCGOP_VECE(op), 5004d2fd745fSRichard Henderson new_args, const_args); 5005d2fd745fSRichard Henderson } else { 5006dd186292SRichard Henderson tcg_out_op(s, op->opc, new_args, const_args); 5007d2fd745fSRichard Henderson } 5008678155b2SRichard Henderson break; 5009678155b2SRichard Henderson } 5010c896fe29Sbellard 5011c896fe29Sbellard /* move the outputs in the correct register if needed */ 5012c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 501343439139SRichard Henderson ts = arg_temp(op->args[i]); 5014d63e3b6eSRichard Henderson 5015d63e3b6eSRichard Henderson /* ENV should not be modified. */ 5016e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ts)); 5017d63e3b6eSRichard Henderson 5018ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) { 501998b4e186SRichard Henderson temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i)); 502059d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) { 5021f8bf00f1SRichard Henderson temp_dead(s, ts); 5022ec7a869dSAurelien Jarno } 5023c896fe29Sbellard } 5024c896fe29Sbellard } 5025c896fe29Sbellard 5026efe86b21SRichard Henderson static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op) 5027efe86b21SRichard Henderson { 5028efe86b21SRichard Henderson const TCGLifeData arg_life = op->life; 5029efe86b21SRichard Henderson TCGTemp *ots, *itsl, *itsh; 5030efe86b21SRichard Henderson TCGType vtype = TCGOP_VECL(op) + TCG_TYPE_V64; 5031efe86b21SRichard Henderson 5032efe86b21SRichard Henderson /* This opcode is only valid for 32-bit hosts, for 64-bit elements. */ 5033efe86b21SRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 32); 5034efe86b21SRichard Henderson tcg_debug_assert(TCGOP_VECE(op) == MO_64); 5035efe86b21SRichard Henderson 5036efe86b21SRichard Henderson ots = arg_temp(op->args[0]); 5037efe86b21SRichard Henderson itsl = arg_temp(op->args[1]); 5038efe86b21SRichard Henderson itsh = arg_temp(op->args[2]); 5039efe86b21SRichard Henderson 5040efe86b21SRichard Henderson /* ENV should not be modified. */ 5041efe86b21SRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 5042efe86b21SRichard Henderson 5043efe86b21SRichard Henderson /* Allocate the output register now. */ 5044efe86b21SRichard Henderson if (ots->val_type != TEMP_VAL_REG) { 5045efe86b21SRichard Henderson TCGRegSet allocated_regs = s->reserved_regs; 5046efe86b21SRichard Henderson TCGRegSet dup_out_regs = 5047efe86b21SRichard Henderson tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs; 5048098859f1SRichard Henderson TCGReg oreg; 5049efe86b21SRichard Henderson 5050efe86b21SRichard Henderson /* Make sure to not spill the input registers. */ 5051efe86b21SRichard Henderson if (!IS_DEAD_ARG(1) && itsl->val_type == TEMP_VAL_REG) { 5052efe86b21SRichard Henderson tcg_regset_set_reg(allocated_regs, itsl->reg); 5053efe86b21SRichard Henderson } 5054efe86b21SRichard Henderson if (!IS_DEAD_ARG(2) && itsh->val_type == TEMP_VAL_REG) { 5055efe86b21SRichard Henderson tcg_regset_set_reg(allocated_regs, itsh->reg); 5056efe86b21SRichard Henderson } 5057efe86b21SRichard Henderson 5058098859f1SRichard Henderson oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs, 505931fd884bSRichard Henderson output_pref(op, 0), ots->indirect_base); 5060098859f1SRichard Henderson set_temp_val_reg(s, ots, oreg); 5061efe86b21SRichard Henderson } 5062efe86b21SRichard Henderson 5063efe86b21SRichard Henderson /* Promote dup2 of immediates to dupi_vec. */ 5064efe86b21SRichard Henderson if (itsl->val_type == TEMP_VAL_CONST && itsh->val_type == TEMP_VAL_CONST) { 5065efe86b21SRichard Henderson uint64_t val = deposit64(itsl->val, 32, 32, itsh->val); 5066efe86b21SRichard Henderson MemOp vece = MO_64; 5067efe86b21SRichard Henderson 5068efe86b21SRichard Henderson if (val == dup_const(MO_8, val)) { 5069efe86b21SRichard Henderson vece = MO_8; 5070efe86b21SRichard Henderson } else if (val == dup_const(MO_16, val)) { 5071efe86b21SRichard Henderson vece = MO_16; 5072efe86b21SRichard Henderson } else if (val == dup_const(MO_32, val)) { 5073efe86b21SRichard Henderson vece = MO_32; 5074efe86b21SRichard Henderson } 5075efe86b21SRichard Henderson 5076efe86b21SRichard Henderson tcg_out_dupi_vec(s, vtype, vece, ots->reg, val); 5077efe86b21SRichard Henderson goto done; 5078efe86b21SRichard Henderson } 5079efe86b21SRichard Henderson 5080efe86b21SRichard Henderson /* If the two inputs form one 64-bit value, try dupm_vec. */ 5081aef85402SRichard Henderson if (itsl->temp_subindex == HOST_BIG_ENDIAN && 5082aef85402SRichard Henderson itsh->temp_subindex == !HOST_BIG_ENDIAN && 5083aef85402SRichard Henderson itsl == itsh + (HOST_BIG_ENDIAN ? 1 : -1)) { 5084aef85402SRichard Henderson TCGTemp *its = itsl - HOST_BIG_ENDIAN; 5085aef85402SRichard Henderson 5086aef85402SRichard Henderson temp_sync(s, its + 0, s->reserved_regs, 0, 0); 5087aef85402SRichard Henderson temp_sync(s, its + 1, s->reserved_regs, 0, 0); 5088aef85402SRichard Henderson 5089efe86b21SRichard Henderson if (tcg_out_dupm_vec(s, vtype, MO_64, ots->reg, 5090efe86b21SRichard Henderson its->mem_base->reg, its->mem_offset)) { 5091efe86b21SRichard Henderson goto done; 5092efe86b21SRichard Henderson } 5093efe86b21SRichard Henderson } 5094efe86b21SRichard Henderson 5095efe86b21SRichard Henderson /* Fall back to generic expansion. */ 5096efe86b21SRichard Henderson return false; 5097efe86b21SRichard Henderson 5098efe86b21SRichard Henderson done: 509936f5539cSRichard Henderson ots->mem_coherent = 0; 5100efe86b21SRichard Henderson if (IS_DEAD_ARG(1)) { 5101efe86b21SRichard Henderson temp_dead(s, itsl); 5102efe86b21SRichard Henderson } 5103efe86b21SRichard Henderson if (IS_DEAD_ARG(2)) { 5104efe86b21SRichard Henderson temp_dead(s, itsh); 5105efe86b21SRichard Henderson } 5106efe86b21SRichard Henderson if (NEED_SYNC_ARG(0)) { 5107efe86b21SRichard Henderson temp_sync(s, ots, s->reserved_regs, 0, IS_DEAD_ARG(0)); 5108efe86b21SRichard Henderson } else if (IS_DEAD_ARG(0)) { 5109efe86b21SRichard Henderson temp_dead(s, ots); 5110efe86b21SRichard Henderson } 5111efe86b21SRichard Henderson return true; 5112efe86b21SRichard Henderson } 5113efe86b21SRichard Henderson 511439004a71SRichard Henderson static void load_arg_reg(TCGContext *s, TCGReg reg, TCGTemp *ts, 511539004a71SRichard Henderson TCGRegSet allocated_regs) 5116c896fe29Sbellard { 5117c896fe29Sbellard if (ts->val_type == TEMP_VAL_REG) { 5118c896fe29Sbellard if (ts->reg != reg) { 51194250da10SRichard Henderson tcg_reg_free(s, reg, allocated_regs); 512078113e83SRichard Henderson if (!tcg_out_mov(s, ts->type, reg, ts->reg)) { 5121240c08d0SRichard Henderson /* 5122240c08d0SRichard Henderson * Cross register class move not supported. Sync the 5123240c08d0SRichard Henderson * temp back to its slot and load from there. 5124240c08d0SRichard Henderson */ 5125240c08d0SRichard Henderson temp_sync(s, ts, allocated_regs, 0, 0); 5126240c08d0SRichard Henderson tcg_out_ld(s, ts->type, reg, 5127240c08d0SRichard Henderson ts->mem_base->reg, ts->mem_offset); 512878113e83SRichard Henderson } 5129c896fe29Sbellard } 5130c896fe29Sbellard } else { 5131ccb1bb66SRichard Henderson TCGRegSet arg_set = 0; 513240ae5c62SRichard Henderson 51334250da10SRichard Henderson tcg_reg_free(s, reg, allocated_regs); 513440ae5c62SRichard Henderson tcg_regset_set_reg(arg_set, reg); 5135b722452aSRichard Henderson temp_load(s, ts, arg_set, allocated_regs, 0); 5136c896fe29Sbellard } 513739004a71SRichard Henderson } 513840ae5c62SRichard Henderson 5139d78e4a4fSRichard Henderson static void load_arg_stk(TCGContext *s, unsigned arg_slot, TCGTemp *ts, 514039004a71SRichard Henderson TCGRegSet allocated_regs) 514139004a71SRichard Henderson { 514239004a71SRichard Henderson /* 514339004a71SRichard Henderson * When the destination is on the stack, load up the temp and store. 514439004a71SRichard Henderson * If there are many call-saved registers, the temp might live to 514539004a71SRichard Henderson * see another use; otherwise it'll be discarded. 514639004a71SRichard Henderson */ 514739004a71SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], allocated_regs, 0); 514839004a71SRichard Henderson tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, 5149d78e4a4fSRichard Henderson arg_slot_stk_ofs(arg_slot)); 515039004a71SRichard Henderson } 515139004a71SRichard Henderson 515239004a71SRichard Henderson static void load_arg_normal(TCGContext *s, const TCGCallArgumentLoc *l, 515339004a71SRichard Henderson TCGTemp *ts, TCGRegSet *allocated_regs) 515439004a71SRichard Henderson { 5155338b61e9SRichard Henderson if (arg_slot_reg_p(l->arg_slot)) { 515639004a71SRichard Henderson TCGReg reg = tcg_target_call_iarg_regs[l->arg_slot]; 515739004a71SRichard Henderson load_arg_reg(s, reg, ts, *allocated_regs); 515839004a71SRichard Henderson tcg_regset_set_reg(*allocated_regs, reg); 515939004a71SRichard Henderson } else { 5160d78e4a4fSRichard Henderson load_arg_stk(s, l->arg_slot, ts, *allocated_regs); 5161c896fe29Sbellard } 516239cf05d3Sbellard } 5163c896fe29Sbellard 5164d78e4a4fSRichard Henderson static void load_arg_ref(TCGContext *s, unsigned arg_slot, TCGReg ref_base, 5165313bdea8SRichard Henderson intptr_t ref_off, TCGRegSet *allocated_regs) 5166313bdea8SRichard Henderson { 5167313bdea8SRichard Henderson TCGReg reg; 5168313bdea8SRichard Henderson 5169d78e4a4fSRichard Henderson if (arg_slot_reg_p(arg_slot)) { 5170313bdea8SRichard Henderson reg = tcg_target_call_iarg_regs[arg_slot]; 5171313bdea8SRichard Henderson tcg_reg_free(s, reg, *allocated_regs); 5172313bdea8SRichard Henderson tcg_out_addi_ptr(s, reg, ref_base, ref_off); 5173313bdea8SRichard Henderson tcg_regset_set_reg(*allocated_regs, reg); 5174313bdea8SRichard Henderson } else { 5175313bdea8SRichard Henderson reg = tcg_reg_alloc(s, tcg_target_available_regs[TCG_TYPE_PTR], 5176313bdea8SRichard Henderson *allocated_regs, 0, false); 5177313bdea8SRichard Henderson tcg_out_addi_ptr(s, reg, ref_base, ref_off); 5178313bdea8SRichard Henderson tcg_out_st(s, TCG_TYPE_PTR, reg, TCG_REG_CALL_STACK, 5179d78e4a4fSRichard Henderson arg_slot_stk_ofs(arg_slot)); 5180313bdea8SRichard Henderson } 5181313bdea8SRichard Henderson } 5182313bdea8SRichard Henderson 518339004a71SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op) 518439004a71SRichard Henderson { 518539004a71SRichard Henderson const int nb_oargs = TCGOP_CALLO(op); 518639004a71SRichard Henderson const int nb_iargs = TCGOP_CALLI(op); 518739004a71SRichard Henderson const TCGLifeData arg_life = op->life; 518839004a71SRichard Henderson const TCGHelperInfo *info = tcg_call_info(op); 518939004a71SRichard Henderson TCGRegSet allocated_regs = s->reserved_regs; 519039004a71SRichard Henderson int i; 519139004a71SRichard Henderson 519239004a71SRichard Henderson /* 519339004a71SRichard Henderson * Move inputs into place in reverse order, 519439004a71SRichard Henderson * so that we place stacked arguments first. 519539004a71SRichard Henderson */ 519639004a71SRichard Henderson for (i = nb_iargs - 1; i >= 0; --i) { 519739004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i]; 519839004a71SRichard Henderson TCGTemp *ts = arg_temp(op->args[nb_oargs + i]); 519939004a71SRichard Henderson 520039004a71SRichard Henderson switch (loc->kind) { 520139004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 520239004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 520339004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 520439004a71SRichard Henderson load_arg_normal(s, loc, ts, &allocated_regs); 520539004a71SRichard Henderson break; 5206313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF: 5207313bdea8SRichard Henderson load_arg_stk(s, loc->ref_slot, ts, allocated_regs); 5208313bdea8SRichard Henderson load_arg_ref(s, loc->arg_slot, TCG_REG_CALL_STACK, 5209d78e4a4fSRichard Henderson arg_slot_stk_ofs(loc->ref_slot), 5210313bdea8SRichard Henderson &allocated_regs); 5211313bdea8SRichard Henderson break; 5212313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF_N: 5213313bdea8SRichard Henderson load_arg_stk(s, loc->ref_slot, ts, allocated_regs); 5214313bdea8SRichard Henderson break; 521539004a71SRichard Henderson default: 521639004a71SRichard Henderson g_assert_not_reached(); 521739004a71SRichard Henderson } 521839004a71SRichard Henderson } 521939004a71SRichard Henderson 522039004a71SRichard Henderson /* Mark dead temporaries and free the associated registers. */ 5221866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 5222866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) { 522343439139SRichard Henderson temp_dead(s, arg_temp(op->args[i])); 5224c896fe29Sbellard } 5225c896fe29Sbellard } 5226c896fe29Sbellard 522739004a71SRichard Henderson /* Clobber call registers. */ 5228c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) { 5229c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { 5230b3915dbbSRichard Henderson tcg_reg_free(s, i, allocated_regs); 5231c896fe29Sbellard } 5232c896fe29Sbellard } 5233c896fe29Sbellard 523439004a71SRichard Henderson /* 523539004a71SRichard Henderson * Save globals if they might be written by the helper, 523639004a71SRichard Henderson * sync them if they might be read. 523739004a71SRichard Henderson */ 523839004a71SRichard Henderson if (info->flags & TCG_CALL_NO_READ_GLOBALS) { 523978505279SAurelien Jarno /* Nothing to do */ 524039004a71SRichard Henderson } else if (info->flags & TCG_CALL_NO_WRITE_GLOBALS) { 524178505279SAurelien Jarno sync_globals(s, allocated_regs); 524278505279SAurelien Jarno } else { 5243e8996ee0Sbellard save_globals(s, allocated_regs); 5244b9c18f56Saurel32 } 5245c896fe29Sbellard 5246313bdea8SRichard Henderson /* 5247313bdea8SRichard Henderson * If the ABI passes a pointer to the returned struct as the first 5248313bdea8SRichard Henderson * argument, load that now. Pass a pointer to the output home slot. 5249313bdea8SRichard Henderson */ 5250313bdea8SRichard Henderson if (info->out_kind == TCG_CALL_RET_BY_REF) { 5251313bdea8SRichard Henderson TCGTemp *ts = arg_temp(op->args[0]); 5252313bdea8SRichard Henderson 5253313bdea8SRichard Henderson if (!ts->mem_allocated) { 5254313bdea8SRichard Henderson temp_allocate_frame(s, ts); 5255313bdea8SRichard Henderson } 5256313bdea8SRichard Henderson load_arg_ref(s, 0, ts->mem_base->reg, ts->mem_offset, &allocated_regs); 5257313bdea8SRichard Henderson } 5258313bdea8SRichard Henderson 5259cee44b03SRichard Henderson tcg_out_call(s, tcg_call_func(op), info); 5260c896fe29Sbellard 526139004a71SRichard Henderson /* Assign output registers and emit moves if needed. */ 526239004a71SRichard Henderson switch (info->out_kind) { 526339004a71SRichard Henderson case TCG_CALL_RET_NORMAL: 5264c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 526539004a71SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]); 52665e3d0c19SRichard Henderson TCGReg reg = tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, i); 5267d63e3b6eSRichard Henderson 5268d63e3b6eSRichard Henderson /* ENV should not be modified. */ 5269e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ts)); 5270d63e3b6eSRichard Henderson 5271098859f1SRichard Henderson set_temp_val_reg(s, ts, reg); 5272c896fe29Sbellard ts->mem_coherent = 0; 527339004a71SRichard Henderson } 527439004a71SRichard Henderson break; 5275313bdea8SRichard Henderson 5276c6556aa0SRichard Henderson case TCG_CALL_RET_BY_VEC: 5277c6556aa0SRichard Henderson { 5278c6556aa0SRichard Henderson TCGTemp *ts = arg_temp(op->args[0]); 5279c6556aa0SRichard Henderson 5280c6556aa0SRichard Henderson tcg_debug_assert(ts->base_type == TCG_TYPE_I128); 5281c6556aa0SRichard Henderson tcg_debug_assert(ts->temp_subindex == 0); 5282c6556aa0SRichard Henderson if (!ts->mem_allocated) { 5283c6556aa0SRichard Henderson temp_allocate_frame(s, ts); 5284c6556aa0SRichard Henderson } 5285c6556aa0SRichard Henderson tcg_out_st(s, TCG_TYPE_V128, 5286c6556aa0SRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0), 5287c6556aa0SRichard Henderson ts->mem_base->reg, ts->mem_offset); 5288c6556aa0SRichard Henderson } 5289c6556aa0SRichard Henderson /* fall through to mark all parts in memory */ 5290c6556aa0SRichard Henderson 5291313bdea8SRichard Henderson case TCG_CALL_RET_BY_REF: 5292313bdea8SRichard Henderson /* The callee has performed a write through the reference. */ 5293313bdea8SRichard Henderson for (i = 0; i < nb_oargs; i++) { 5294313bdea8SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]); 5295313bdea8SRichard Henderson ts->val_type = TEMP_VAL_MEM; 5296313bdea8SRichard Henderson } 5297313bdea8SRichard Henderson break; 5298313bdea8SRichard Henderson 529939004a71SRichard Henderson default: 530039004a71SRichard Henderson g_assert_not_reached(); 530139004a71SRichard Henderson } 530239004a71SRichard Henderson 530339004a71SRichard Henderson /* Flush or discard output registers as needed. */ 530439004a71SRichard Henderson for (i = 0; i < nb_oargs; i++) { 530539004a71SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]); 5306ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) { 530739004a71SRichard Henderson temp_sync(s, ts, s->reserved_regs, 0, IS_DEAD_ARG(i)); 530859d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) { 5309f8bf00f1SRichard Henderson temp_dead(s, ts); 5310c896fe29Sbellard } 5311c896fe29Sbellard } 53128c11ad25SAurelien Jarno } 5313c896fe29Sbellard 5314e63b8a29SRichard Henderson /** 5315e63b8a29SRichard Henderson * atom_and_align_for_opc: 5316e63b8a29SRichard Henderson * @s: tcg context 5317e63b8a29SRichard Henderson * @opc: memory operation code 5318e63b8a29SRichard Henderson * @host_atom: MO_ATOM_{IFALIGN,WITHIN16,SUBALIGN} for host operations 5319e63b8a29SRichard Henderson * @allow_two_ops: true if we are prepared to issue two operations 5320e63b8a29SRichard Henderson * 5321e63b8a29SRichard Henderson * Return the alignment and atomicity to use for the inline fast path 5322e63b8a29SRichard Henderson * for the given memory operation. The alignment may be larger than 5323e63b8a29SRichard Henderson * that specified in @opc, and the correct alignment will be diagnosed 5324e63b8a29SRichard Henderson * by the slow path helper. 5325e63b8a29SRichard Henderson * 5326e63b8a29SRichard Henderson * If @allow_two_ops, the host is prepared to test for 2x alignment, 5327e63b8a29SRichard Henderson * and issue two loads or stores for subalignment. 5328e63b8a29SRichard Henderson */ 5329e63b8a29SRichard Henderson static TCGAtomAlign atom_and_align_for_opc(TCGContext *s, MemOp opc, 5330e63b8a29SRichard Henderson MemOp host_atom, bool allow_two_ops) 5331e63b8a29SRichard Henderson { 5332e63b8a29SRichard Henderson MemOp align = get_alignment_bits(opc); 5333e63b8a29SRichard Henderson MemOp size = opc & MO_SIZE; 5334e63b8a29SRichard Henderson MemOp half = size ? size - 1 : 0; 5335e63b8a29SRichard Henderson MemOp atmax; 5336e63b8a29SRichard Henderson MemOp atom; 5337e63b8a29SRichard Henderson 5338e63b8a29SRichard Henderson /* When serialized, no further atomicity required. */ 5339e63b8a29SRichard Henderson if (s->gen_tb->cflags & CF_PARALLEL) { 5340e63b8a29SRichard Henderson atom = opc & MO_ATOM_MASK; 5341e63b8a29SRichard Henderson } else { 5342e63b8a29SRichard Henderson atom = MO_ATOM_NONE; 5343e63b8a29SRichard Henderson } 5344e63b8a29SRichard Henderson 5345e63b8a29SRichard Henderson switch (atom) { 5346e63b8a29SRichard Henderson case MO_ATOM_NONE: 5347e63b8a29SRichard Henderson /* The operation requires no specific atomicity. */ 5348e63b8a29SRichard Henderson atmax = MO_8; 5349e63b8a29SRichard Henderson break; 5350e63b8a29SRichard Henderson 5351e63b8a29SRichard Henderson case MO_ATOM_IFALIGN: 5352e63b8a29SRichard Henderson atmax = size; 5353e63b8a29SRichard Henderson break; 5354e63b8a29SRichard Henderson 5355e63b8a29SRichard Henderson case MO_ATOM_IFALIGN_PAIR: 5356e63b8a29SRichard Henderson atmax = half; 5357e63b8a29SRichard Henderson break; 5358e63b8a29SRichard Henderson 5359e63b8a29SRichard Henderson case MO_ATOM_WITHIN16: 5360e63b8a29SRichard Henderson atmax = size; 5361e63b8a29SRichard Henderson if (size == MO_128) { 5362e63b8a29SRichard Henderson /* Misalignment implies !within16, and therefore no atomicity. */ 5363e63b8a29SRichard Henderson } else if (host_atom != MO_ATOM_WITHIN16) { 5364e63b8a29SRichard Henderson /* The host does not implement within16, so require alignment. */ 5365e63b8a29SRichard Henderson align = MAX(align, size); 5366e63b8a29SRichard Henderson } 5367e63b8a29SRichard Henderson break; 5368e63b8a29SRichard Henderson 5369e63b8a29SRichard Henderson case MO_ATOM_WITHIN16_PAIR: 5370e63b8a29SRichard Henderson atmax = size; 5371e63b8a29SRichard Henderson /* 5372e63b8a29SRichard Henderson * Misalignment implies !within16, and therefore half atomicity. 5373e63b8a29SRichard Henderson * Any host prepared for two operations can implement this with 5374e63b8a29SRichard Henderson * half alignment. 5375e63b8a29SRichard Henderson */ 5376e63b8a29SRichard Henderson if (host_atom != MO_ATOM_WITHIN16 && allow_two_ops) { 5377e63b8a29SRichard Henderson align = MAX(align, half); 5378e63b8a29SRichard Henderson } 5379e63b8a29SRichard Henderson break; 5380e63b8a29SRichard Henderson 5381e63b8a29SRichard Henderson case MO_ATOM_SUBALIGN: 5382e63b8a29SRichard Henderson atmax = size; 5383e63b8a29SRichard Henderson if (host_atom != MO_ATOM_SUBALIGN) { 5384e63b8a29SRichard Henderson /* If unaligned but not odd, there are subobjects up to half. */ 5385e63b8a29SRichard Henderson if (allow_two_ops) { 5386e63b8a29SRichard Henderson align = MAX(align, half); 5387e63b8a29SRichard Henderson } else { 5388e63b8a29SRichard Henderson align = MAX(align, size); 5389e63b8a29SRichard Henderson } 5390e63b8a29SRichard Henderson } 5391e63b8a29SRichard Henderson break; 5392e63b8a29SRichard Henderson 5393e63b8a29SRichard Henderson default: 5394e63b8a29SRichard Henderson g_assert_not_reached(); 5395e63b8a29SRichard Henderson } 5396e63b8a29SRichard Henderson 5397e63b8a29SRichard Henderson return (TCGAtomAlign){ .atom = atmax, .align = align }; 5398e63b8a29SRichard Henderson } 5399e63b8a29SRichard Henderson 54008429a1caSRichard Henderson /* 54018429a1caSRichard Henderson * Similarly for qemu_ld/st slow path helpers. 54028429a1caSRichard Henderson * We must re-implement tcg_gen_callN and tcg_reg_alloc_call simultaneously, 54038429a1caSRichard Henderson * using only the provided backend tcg_out_* functions. 54048429a1caSRichard Henderson */ 54058429a1caSRichard Henderson 54068429a1caSRichard Henderson static int tcg_out_helper_stk_ofs(TCGType type, unsigned slot) 54078429a1caSRichard Henderson { 54088429a1caSRichard Henderson int ofs = arg_slot_stk_ofs(slot); 54098429a1caSRichard Henderson 54108429a1caSRichard Henderson /* 54118429a1caSRichard Henderson * Each stack slot is TCG_TARGET_LONG_BITS. If the host does not 54128429a1caSRichard Henderson * require extension to uint64_t, adjust the address for uint32_t. 54138429a1caSRichard Henderson */ 54148429a1caSRichard Henderson if (HOST_BIG_ENDIAN && 54158429a1caSRichard Henderson TCG_TARGET_REG_BITS == 64 && 54168429a1caSRichard Henderson type == TCG_TYPE_I32) { 54178429a1caSRichard Henderson ofs += 4; 54188429a1caSRichard Henderson } 54198429a1caSRichard Henderson return ofs; 54208429a1caSRichard Henderson } 54218429a1caSRichard Henderson 54228d314041SRichard Henderson static void tcg_out_helper_load_slots(TCGContext *s, 54238429a1caSRichard Henderson unsigned nmov, TCGMovExtend *mov, 54242462e30eSRichard Henderson const TCGLdstHelperParam *parm) 54258429a1caSRichard Henderson { 54268d314041SRichard Henderson unsigned i; 54272462e30eSRichard Henderson TCGReg dst3; 54282462e30eSRichard Henderson 54298d314041SRichard Henderson /* 54308d314041SRichard Henderson * Start from the end, storing to the stack first. 54318d314041SRichard Henderson * This frees those registers, so we need not consider overlap. 54328d314041SRichard Henderson */ 54338d314041SRichard Henderson for (i = nmov; i-- > 0; ) { 54348d314041SRichard Henderson unsigned slot = mov[i].dst; 54358d314041SRichard Henderson 54368d314041SRichard Henderson if (arg_slot_reg_p(slot)) { 54378d314041SRichard Henderson goto found_reg; 54388d314041SRichard Henderson } 54398d314041SRichard Henderson 54408d314041SRichard Henderson TCGReg src = mov[i].src; 54418d314041SRichard Henderson TCGType dst_type = mov[i].dst_type; 54428d314041SRichard Henderson MemOp dst_mo = dst_type == TCG_TYPE_I32 ? MO_32 : MO_64; 54438d314041SRichard Henderson 54448d314041SRichard Henderson /* The argument is going onto the stack; extend into scratch. */ 54458d314041SRichard Henderson if ((mov[i].src_ext & MO_SIZE) != dst_mo) { 54468d314041SRichard Henderson tcg_debug_assert(parm->ntmp != 0); 54478d314041SRichard Henderson mov[i].dst = src = parm->tmp[0]; 54488d314041SRichard Henderson tcg_out_movext1(s, &mov[i]); 54498d314041SRichard Henderson } 54508d314041SRichard Henderson 54518d314041SRichard Henderson tcg_out_st(s, dst_type, src, TCG_REG_CALL_STACK, 54528d314041SRichard Henderson tcg_out_helper_stk_ofs(dst_type, slot)); 54538d314041SRichard Henderson } 54548d314041SRichard Henderson return; 54558d314041SRichard Henderson 54568d314041SRichard Henderson found_reg: 54578d314041SRichard Henderson /* 54588d314041SRichard Henderson * The remaining arguments are in registers. 54598d314041SRichard Henderson * Convert slot numbers to argument registers. 54608d314041SRichard Henderson */ 54618d314041SRichard Henderson nmov = i + 1; 54628d314041SRichard Henderson for (i = 0; i < nmov; ++i) { 54638d314041SRichard Henderson mov[i].dst = tcg_target_call_iarg_regs[mov[i].dst]; 54648d314041SRichard Henderson } 54658d314041SRichard Henderson 54668429a1caSRichard Henderson switch (nmov) { 54672462e30eSRichard Henderson case 4: 54688429a1caSRichard Henderson /* The backend must have provided enough temps for the worst case. */ 54692462e30eSRichard Henderson tcg_debug_assert(parm->ntmp >= 2); 54708429a1caSRichard Henderson 54712462e30eSRichard Henderson dst3 = mov[3].dst; 54722462e30eSRichard Henderson for (unsigned j = 0; j < 3; ++j) { 54732462e30eSRichard Henderson if (dst3 == mov[j].src) { 54748429a1caSRichard Henderson /* 54752462e30eSRichard Henderson * Conflict. Copy the source to a temporary, perform the 54762462e30eSRichard Henderson * remaining moves, then the extension from our scratch 54772462e30eSRichard Henderson * on the way out. 54788429a1caSRichard Henderson */ 54792462e30eSRichard Henderson TCGReg scratch = parm->tmp[1]; 54808429a1caSRichard Henderson 54812462e30eSRichard Henderson tcg_out_mov(s, mov[3].src_type, scratch, mov[3].src); 54822462e30eSRichard Henderson tcg_out_movext3(s, mov, mov + 1, mov + 2, parm->tmp[0]); 54832462e30eSRichard Henderson tcg_out_movext1_new_src(s, &mov[3], scratch); 54842462e30eSRichard Henderson break; 54858429a1caSRichard Henderson } 54868429a1caSRichard Henderson } 54878429a1caSRichard Henderson 54888429a1caSRichard Henderson /* No conflicts: perform this move and continue. */ 54892462e30eSRichard Henderson tcg_out_movext1(s, &mov[3]); 54902462e30eSRichard Henderson /* fall through */ 54918429a1caSRichard Henderson 54922462e30eSRichard Henderson case 3: 54932462e30eSRichard Henderson tcg_out_movext3(s, mov, mov + 1, mov + 2, 54942462e30eSRichard Henderson parm->ntmp ? parm->tmp[0] : -1); 54952462e30eSRichard Henderson break; 54968429a1caSRichard Henderson case 2: 54972462e30eSRichard Henderson tcg_out_movext2(s, mov, mov + 1, 54982462e30eSRichard Henderson parm->ntmp ? parm->tmp[0] : -1); 54992462e30eSRichard Henderson break; 55008429a1caSRichard Henderson case 1: 55018429a1caSRichard Henderson tcg_out_movext1(s, mov); 55022462e30eSRichard Henderson break; 55032462e30eSRichard Henderson default: 55048429a1caSRichard Henderson g_assert_not_reached(); 55058429a1caSRichard Henderson } 55068429a1caSRichard Henderson } 55078429a1caSRichard Henderson 55088429a1caSRichard Henderson static void tcg_out_helper_load_imm(TCGContext *s, unsigned slot, 55098429a1caSRichard Henderson TCGType type, tcg_target_long imm, 55108429a1caSRichard Henderson const TCGLdstHelperParam *parm) 55118429a1caSRichard Henderson { 55128429a1caSRichard Henderson if (arg_slot_reg_p(slot)) { 55138429a1caSRichard Henderson tcg_out_movi(s, type, tcg_target_call_iarg_regs[slot], imm); 55148429a1caSRichard Henderson } else { 55158429a1caSRichard Henderson int ofs = tcg_out_helper_stk_ofs(type, slot); 55168429a1caSRichard Henderson if (!tcg_out_sti(s, type, imm, TCG_REG_CALL_STACK, ofs)) { 55178429a1caSRichard Henderson tcg_debug_assert(parm->ntmp != 0); 55188429a1caSRichard Henderson tcg_out_movi(s, type, parm->tmp[0], imm); 55198429a1caSRichard Henderson tcg_out_st(s, type, parm->tmp[0], TCG_REG_CALL_STACK, ofs); 55208429a1caSRichard Henderson } 55218429a1caSRichard Henderson } 55228429a1caSRichard Henderson } 55238429a1caSRichard Henderson 55248429a1caSRichard Henderson static void tcg_out_helper_load_common_args(TCGContext *s, 55258429a1caSRichard Henderson const TCGLabelQemuLdst *ldst, 55268429a1caSRichard Henderson const TCGLdstHelperParam *parm, 55278429a1caSRichard Henderson const TCGHelperInfo *info, 55288429a1caSRichard Henderson unsigned next_arg) 55298429a1caSRichard Henderson { 55308429a1caSRichard Henderson TCGMovExtend ptr_mov = { 55318429a1caSRichard Henderson .dst_type = TCG_TYPE_PTR, 55328429a1caSRichard Henderson .src_type = TCG_TYPE_PTR, 55338429a1caSRichard Henderson .src_ext = sizeof(void *) == 4 ? MO_32 : MO_64 55348429a1caSRichard Henderson }; 55358429a1caSRichard Henderson const TCGCallArgumentLoc *loc = &info->in[0]; 55368429a1caSRichard Henderson TCGType type; 55378429a1caSRichard Henderson unsigned slot; 55388429a1caSRichard Henderson tcg_target_ulong imm; 55398429a1caSRichard Henderson 55408429a1caSRichard Henderson /* 55418429a1caSRichard Henderson * Handle env, which is always first. 55428429a1caSRichard Henderson */ 55438429a1caSRichard Henderson ptr_mov.dst = loc->arg_slot; 55448429a1caSRichard Henderson ptr_mov.src = TCG_AREG0; 55458429a1caSRichard Henderson tcg_out_helper_load_slots(s, 1, &ptr_mov, parm); 55468429a1caSRichard Henderson 55478429a1caSRichard Henderson /* 55488429a1caSRichard Henderson * Handle oi. 55498429a1caSRichard Henderson */ 55508429a1caSRichard Henderson imm = ldst->oi; 55518429a1caSRichard Henderson loc = &info->in[next_arg]; 55528429a1caSRichard Henderson type = TCG_TYPE_I32; 55538429a1caSRichard Henderson switch (loc->kind) { 55548429a1caSRichard Henderson case TCG_CALL_ARG_NORMAL: 55558429a1caSRichard Henderson break; 55568429a1caSRichard Henderson case TCG_CALL_ARG_EXTEND_U: 55578429a1caSRichard Henderson case TCG_CALL_ARG_EXTEND_S: 55588429a1caSRichard Henderson /* No extension required for MemOpIdx. */ 55598429a1caSRichard Henderson tcg_debug_assert(imm <= INT32_MAX); 55608429a1caSRichard Henderson type = TCG_TYPE_REG; 55618429a1caSRichard Henderson break; 55628429a1caSRichard Henderson default: 55638429a1caSRichard Henderson g_assert_not_reached(); 55648429a1caSRichard Henderson } 55658429a1caSRichard Henderson tcg_out_helper_load_imm(s, loc->arg_slot, type, imm, parm); 55668429a1caSRichard Henderson next_arg++; 55678429a1caSRichard Henderson 55688429a1caSRichard Henderson /* 55698429a1caSRichard Henderson * Handle ra. 55708429a1caSRichard Henderson */ 55718429a1caSRichard Henderson loc = &info->in[next_arg]; 55728429a1caSRichard Henderson slot = loc->arg_slot; 55738429a1caSRichard Henderson if (parm->ra_gen) { 55748429a1caSRichard Henderson int arg_reg = -1; 55758429a1caSRichard Henderson TCGReg ra_reg; 55768429a1caSRichard Henderson 55778429a1caSRichard Henderson if (arg_slot_reg_p(slot)) { 55788429a1caSRichard Henderson arg_reg = tcg_target_call_iarg_regs[slot]; 55798429a1caSRichard Henderson } 55808429a1caSRichard Henderson ra_reg = parm->ra_gen(s, ldst, arg_reg); 55818429a1caSRichard Henderson 55828429a1caSRichard Henderson ptr_mov.dst = slot; 55838429a1caSRichard Henderson ptr_mov.src = ra_reg; 55848429a1caSRichard Henderson tcg_out_helper_load_slots(s, 1, &ptr_mov, parm); 55858429a1caSRichard Henderson } else { 55868429a1caSRichard Henderson imm = (uintptr_t)ldst->raddr; 55878429a1caSRichard Henderson tcg_out_helper_load_imm(s, slot, TCG_TYPE_PTR, imm, parm); 55888429a1caSRichard Henderson } 55898429a1caSRichard Henderson } 55908429a1caSRichard Henderson 55918429a1caSRichard Henderson static unsigned tcg_out_helper_add_mov(TCGMovExtend *mov, 55928429a1caSRichard Henderson const TCGCallArgumentLoc *loc, 55938429a1caSRichard Henderson TCGType dst_type, TCGType src_type, 55948429a1caSRichard Henderson TCGReg lo, TCGReg hi) 55958429a1caSRichard Henderson { 5596ebebea53SRichard Henderson MemOp reg_mo; 5597ebebea53SRichard Henderson 55988429a1caSRichard Henderson if (dst_type <= TCG_TYPE_REG) { 55998429a1caSRichard Henderson MemOp src_ext; 56008429a1caSRichard Henderson 56018429a1caSRichard Henderson switch (loc->kind) { 56028429a1caSRichard Henderson case TCG_CALL_ARG_NORMAL: 56038429a1caSRichard Henderson src_ext = src_type == TCG_TYPE_I32 ? MO_32 : MO_64; 56048429a1caSRichard Henderson break; 56058429a1caSRichard Henderson case TCG_CALL_ARG_EXTEND_U: 56068429a1caSRichard Henderson dst_type = TCG_TYPE_REG; 56078429a1caSRichard Henderson src_ext = MO_UL; 56088429a1caSRichard Henderson break; 56098429a1caSRichard Henderson case TCG_CALL_ARG_EXTEND_S: 56108429a1caSRichard Henderson dst_type = TCG_TYPE_REG; 56118429a1caSRichard Henderson src_ext = MO_SL; 56128429a1caSRichard Henderson break; 56138429a1caSRichard Henderson default: 56148429a1caSRichard Henderson g_assert_not_reached(); 56158429a1caSRichard Henderson } 56168429a1caSRichard Henderson 56178429a1caSRichard Henderson mov[0].dst = loc->arg_slot; 56188429a1caSRichard Henderson mov[0].dst_type = dst_type; 56198429a1caSRichard Henderson mov[0].src = lo; 56208429a1caSRichard Henderson mov[0].src_type = src_type; 56218429a1caSRichard Henderson mov[0].src_ext = src_ext; 56228429a1caSRichard Henderson return 1; 56238429a1caSRichard Henderson } 56248429a1caSRichard Henderson 5625ebebea53SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 5626ebebea53SRichard Henderson assert(dst_type == TCG_TYPE_I64); 5627ebebea53SRichard Henderson reg_mo = MO_32; 5628ebebea53SRichard Henderson } else { 5629ebebea53SRichard Henderson assert(dst_type == TCG_TYPE_I128); 5630ebebea53SRichard Henderson reg_mo = MO_64; 5631ebebea53SRichard Henderson } 56328429a1caSRichard Henderson 56338429a1caSRichard Henderson mov[0].dst = loc[HOST_BIG_ENDIAN].arg_slot; 56348429a1caSRichard Henderson mov[0].src = lo; 5635ebebea53SRichard Henderson mov[0].dst_type = TCG_TYPE_REG; 5636ebebea53SRichard Henderson mov[0].src_type = TCG_TYPE_REG; 5637ebebea53SRichard Henderson mov[0].src_ext = reg_mo; 56388429a1caSRichard Henderson 56398429a1caSRichard Henderson mov[1].dst = loc[!HOST_BIG_ENDIAN].arg_slot; 56408429a1caSRichard Henderson mov[1].src = hi; 5641ebebea53SRichard Henderson mov[1].dst_type = TCG_TYPE_REG; 5642ebebea53SRichard Henderson mov[1].src_type = TCG_TYPE_REG; 5643ebebea53SRichard Henderson mov[1].src_ext = reg_mo; 56448429a1caSRichard Henderson 56458429a1caSRichard Henderson return 2; 56468429a1caSRichard Henderson } 56478429a1caSRichard Henderson 56488429a1caSRichard Henderson static void tcg_out_ld_helper_args(TCGContext *s, const TCGLabelQemuLdst *ldst, 56498429a1caSRichard Henderson const TCGLdstHelperParam *parm) 56508429a1caSRichard Henderson { 56518429a1caSRichard Henderson const TCGHelperInfo *info; 56528429a1caSRichard Henderson const TCGCallArgumentLoc *loc; 56538429a1caSRichard Henderson TCGMovExtend mov[2]; 56548429a1caSRichard Henderson unsigned next_arg, nmov; 56558429a1caSRichard Henderson MemOp mop = get_memop(ldst->oi); 56568429a1caSRichard Henderson 56578429a1caSRichard Henderson switch (mop & MO_SIZE) { 56588429a1caSRichard Henderson case MO_8: 56598429a1caSRichard Henderson case MO_16: 56608429a1caSRichard Henderson case MO_32: 56618429a1caSRichard Henderson info = &info_helper_ld32_mmu; 56628429a1caSRichard Henderson break; 56638429a1caSRichard Henderson case MO_64: 56648429a1caSRichard Henderson info = &info_helper_ld64_mmu; 56658429a1caSRichard Henderson break; 5666ebebea53SRichard Henderson case MO_128: 5667ebebea53SRichard Henderson info = &info_helper_ld128_mmu; 5668ebebea53SRichard Henderson break; 56698429a1caSRichard Henderson default: 56708429a1caSRichard Henderson g_assert_not_reached(); 56718429a1caSRichard Henderson } 56728429a1caSRichard Henderson 56738429a1caSRichard Henderson /* Defer env argument. */ 56748429a1caSRichard Henderson next_arg = 1; 56758429a1caSRichard Henderson 56768429a1caSRichard Henderson loc = &info->in[next_arg]; 5677c31e5fa4SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && s->addr_type == TCG_TYPE_I32) { 567824e46e6cSRichard Henderson /* 567924e46e6cSRichard Henderson * 32-bit host with 32-bit guest: zero-extend the guest address 568024e46e6cSRichard Henderson * to 64-bits for the helper by storing the low part, then 568124e46e6cSRichard Henderson * load a zero for the high part. 568224e46e6cSRichard Henderson */ 568324e46e6cSRichard Henderson tcg_out_helper_add_mov(mov, loc + HOST_BIG_ENDIAN, 568424e46e6cSRichard Henderson TCG_TYPE_I32, TCG_TYPE_I32, 568524e46e6cSRichard Henderson ldst->addrlo_reg, -1); 568624e46e6cSRichard Henderson tcg_out_helper_load_slots(s, 1, mov, parm); 568724e46e6cSRichard Henderson 568824e46e6cSRichard Henderson tcg_out_helper_load_imm(s, loc[!HOST_BIG_ENDIAN].arg_slot, 568924e46e6cSRichard Henderson TCG_TYPE_I32, 0, parm); 569024e46e6cSRichard Henderson next_arg += 2; 5691c31e5fa4SRichard Henderson } else { 5692c31e5fa4SRichard Henderson nmov = tcg_out_helper_add_mov(mov, loc, TCG_TYPE_I64, s->addr_type, 5693c31e5fa4SRichard Henderson ldst->addrlo_reg, ldst->addrhi_reg); 5694c31e5fa4SRichard Henderson tcg_out_helper_load_slots(s, nmov, mov, parm); 5695c31e5fa4SRichard Henderson next_arg += nmov; 569624e46e6cSRichard Henderson } 56978429a1caSRichard Henderson 5698ebebea53SRichard Henderson switch (info->out_kind) { 5699ebebea53SRichard Henderson case TCG_CALL_RET_NORMAL: 5700ebebea53SRichard Henderson case TCG_CALL_RET_BY_VEC: 5701ebebea53SRichard Henderson break; 5702ebebea53SRichard Henderson case TCG_CALL_RET_BY_REF: 5703ebebea53SRichard Henderson /* 5704ebebea53SRichard Henderson * The return reference is in the first argument slot. 5705ebebea53SRichard Henderson * We need memory in which to return: re-use the top of stack. 5706ebebea53SRichard Henderson */ 5707ebebea53SRichard Henderson { 5708ebebea53SRichard Henderson int ofs_slot0 = TCG_TARGET_CALL_STACK_OFFSET; 5709ebebea53SRichard Henderson 5710ebebea53SRichard Henderson if (arg_slot_reg_p(0)) { 5711ebebea53SRichard Henderson tcg_out_addi_ptr(s, tcg_target_call_iarg_regs[0], 5712ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0); 5713ebebea53SRichard Henderson } else { 5714ebebea53SRichard Henderson tcg_debug_assert(parm->ntmp != 0); 5715ebebea53SRichard Henderson tcg_out_addi_ptr(s, parm->tmp[0], 5716ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0); 5717ebebea53SRichard Henderson tcg_out_st(s, TCG_TYPE_PTR, parm->tmp[0], 5718ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0); 5719ebebea53SRichard Henderson } 5720ebebea53SRichard Henderson } 5721ebebea53SRichard Henderson break; 5722ebebea53SRichard Henderson default: 5723ebebea53SRichard Henderson g_assert_not_reached(); 5724ebebea53SRichard Henderson } 57258429a1caSRichard Henderson 57268429a1caSRichard Henderson tcg_out_helper_load_common_args(s, ldst, parm, info, next_arg); 57278429a1caSRichard Henderson } 57288429a1caSRichard Henderson 57298429a1caSRichard Henderson static void tcg_out_ld_helper_ret(TCGContext *s, const TCGLabelQemuLdst *ldst, 57308429a1caSRichard Henderson bool load_sign, 57318429a1caSRichard Henderson const TCGLdstHelperParam *parm) 57328429a1caSRichard Henderson { 57338429a1caSRichard Henderson MemOp mop = get_memop(ldst->oi); 5734ebebea53SRichard Henderson TCGMovExtend mov[2]; 5735ebebea53SRichard Henderson int ofs_slot0; 57368429a1caSRichard Henderson 5737ebebea53SRichard Henderson switch (ldst->type) { 5738ebebea53SRichard Henderson case TCG_TYPE_I64: 5739ebebea53SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 5740ebebea53SRichard Henderson break; 5741ebebea53SRichard Henderson } 5742ebebea53SRichard Henderson /* fall through */ 5743ebebea53SRichard Henderson 5744ebebea53SRichard Henderson case TCG_TYPE_I32: 57458429a1caSRichard Henderson mov[0].dst = ldst->datalo_reg; 57468429a1caSRichard Henderson mov[0].src = tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, 0); 57478429a1caSRichard Henderson mov[0].dst_type = ldst->type; 57488429a1caSRichard Henderson mov[0].src_type = TCG_TYPE_REG; 57498429a1caSRichard Henderson 57508429a1caSRichard Henderson /* 57518429a1caSRichard Henderson * If load_sign, then we allowed the helper to perform the 57528429a1caSRichard Henderson * appropriate sign extension to tcg_target_ulong, and all 57538429a1caSRichard Henderson * we need now is a plain move. 57548429a1caSRichard Henderson * 57558429a1caSRichard Henderson * If they do not, then we expect the relevant extension 57568429a1caSRichard Henderson * instruction to be no more expensive than a move, and 57578429a1caSRichard Henderson * we thus save the icache etc by only using one of two 57588429a1caSRichard Henderson * helper functions. 57598429a1caSRichard Henderson */ 57608429a1caSRichard Henderson if (load_sign || !(mop & MO_SIGN)) { 57618429a1caSRichard Henderson if (TCG_TARGET_REG_BITS == 32 || ldst->type == TCG_TYPE_I32) { 57628429a1caSRichard Henderson mov[0].src_ext = MO_32; 57638429a1caSRichard Henderson } else { 57648429a1caSRichard Henderson mov[0].src_ext = MO_64; 57658429a1caSRichard Henderson } 57668429a1caSRichard Henderson } else { 57678429a1caSRichard Henderson mov[0].src_ext = mop & MO_SSIZE; 57688429a1caSRichard Henderson } 57698429a1caSRichard Henderson tcg_out_movext1(s, mov); 5770ebebea53SRichard Henderson return; 5771ebebea53SRichard Henderson 5772ebebea53SRichard Henderson case TCG_TYPE_I128: 5773ebebea53SRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 64); 5774ebebea53SRichard Henderson ofs_slot0 = TCG_TARGET_CALL_STACK_OFFSET; 5775ebebea53SRichard Henderson switch (TCG_TARGET_CALL_RET_I128) { 5776ebebea53SRichard Henderson case TCG_CALL_RET_NORMAL: 5777ebebea53SRichard Henderson break; 5778ebebea53SRichard Henderson case TCG_CALL_RET_BY_VEC: 5779ebebea53SRichard Henderson tcg_out_st(s, TCG_TYPE_V128, 5780ebebea53SRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0), 5781ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0); 5782ebebea53SRichard Henderson /* fall through */ 5783ebebea53SRichard Henderson case TCG_CALL_RET_BY_REF: 5784ebebea53SRichard Henderson tcg_out_ld(s, TCG_TYPE_I64, ldst->datalo_reg, 5785ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0 + 8 * HOST_BIG_ENDIAN); 5786ebebea53SRichard Henderson tcg_out_ld(s, TCG_TYPE_I64, ldst->datahi_reg, 5787ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0 + 8 * !HOST_BIG_ENDIAN); 5788ebebea53SRichard Henderson return; 5789ebebea53SRichard Henderson default: 5790ebebea53SRichard Henderson g_assert_not_reached(); 5791ebebea53SRichard Henderson } 5792ebebea53SRichard Henderson break; 5793ebebea53SRichard Henderson 5794ebebea53SRichard Henderson default: 5795ebebea53SRichard Henderson g_assert_not_reached(); 5796ebebea53SRichard Henderson } 57978429a1caSRichard Henderson 57988429a1caSRichard Henderson mov[0].dst = ldst->datalo_reg; 57998429a1caSRichard Henderson mov[0].src = 58008429a1caSRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, HOST_BIG_ENDIAN); 5801723d3a27SRichard Henderson mov[0].dst_type = TCG_TYPE_REG; 5802723d3a27SRichard Henderson mov[0].src_type = TCG_TYPE_REG; 5803ebebea53SRichard Henderson mov[0].src_ext = TCG_TARGET_REG_BITS == 32 ? MO_32 : MO_64; 58048429a1caSRichard Henderson 58058429a1caSRichard Henderson mov[1].dst = ldst->datahi_reg; 58068429a1caSRichard Henderson mov[1].src = 58078429a1caSRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, !HOST_BIG_ENDIAN); 58088429a1caSRichard Henderson mov[1].dst_type = TCG_TYPE_REG; 58098429a1caSRichard Henderson mov[1].src_type = TCG_TYPE_REG; 5810ebebea53SRichard Henderson mov[1].src_ext = TCG_TARGET_REG_BITS == 32 ? MO_32 : MO_64; 58118429a1caSRichard Henderson 58128429a1caSRichard Henderson tcg_out_movext2(s, mov, mov + 1, parm->ntmp ? parm->tmp[0] : -1); 58138429a1caSRichard Henderson } 58148429a1caSRichard Henderson 58158429a1caSRichard Henderson static void tcg_out_st_helper_args(TCGContext *s, const TCGLabelQemuLdst *ldst, 58168429a1caSRichard Henderson const TCGLdstHelperParam *parm) 58178429a1caSRichard Henderson { 58188429a1caSRichard Henderson const TCGHelperInfo *info; 58198429a1caSRichard Henderson const TCGCallArgumentLoc *loc; 58208429a1caSRichard Henderson TCGMovExtend mov[4]; 58218429a1caSRichard Henderson TCGType data_type; 58228429a1caSRichard Henderson unsigned next_arg, nmov, n; 58238429a1caSRichard Henderson MemOp mop = get_memop(ldst->oi); 58248429a1caSRichard Henderson 58258429a1caSRichard Henderson switch (mop & MO_SIZE) { 58268429a1caSRichard Henderson case MO_8: 58278429a1caSRichard Henderson case MO_16: 58288429a1caSRichard Henderson case MO_32: 58298429a1caSRichard Henderson info = &info_helper_st32_mmu; 58308429a1caSRichard Henderson data_type = TCG_TYPE_I32; 58318429a1caSRichard Henderson break; 58328429a1caSRichard Henderson case MO_64: 58338429a1caSRichard Henderson info = &info_helper_st64_mmu; 58348429a1caSRichard Henderson data_type = TCG_TYPE_I64; 58358429a1caSRichard Henderson break; 5836ebebea53SRichard Henderson case MO_128: 5837ebebea53SRichard Henderson info = &info_helper_st128_mmu; 5838ebebea53SRichard Henderson data_type = TCG_TYPE_I128; 5839ebebea53SRichard Henderson break; 58408429a1caSRichard Henderson default: 58418429a1caSRichard Henderson g_assert_not_reached(); 58428429a1caSRichard Henderson } 58438429a1caSRichard Henderson 58448429a1caSRichard Henderson /* Defer env argument. */ 58458429a1caSRichard Henderson next_arg = 1; 58468429a1caSRichard Henderson nmov = 0; 58478429a1caSRichard Henderson 58488429a1caSRichard Henderson /* Handle addr argument. */ 58498429a1caSRichard Henderson loc = &info->in[next_arg]; 5850c31e5fa4SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && s->addr_type == TCG_TYPE_I32) { 585124e46e6cSRichard Henderson /* 585224e46e6cSRichard Henderson * 32-bit host with 32-bit guest: zero-extend the guest address 585324e46e6cSRichard Henderson * to 64-bits for the helper by storing the low part. Later, 585424e46e6cSRichard Henderson * after we have processed the register inputs, we will load a 585524e46e6cSRichard Henderson * zero for the high part. 585624e46e6cSRichard Henderson */ 585724e46e6cSRichard Henderson tcg_out_helper_add_mov(mov, loc + HOST_BIG_ENDIAN, 585824e46e6cSRichard Henderson TCG_TYPE_I32, TCG_TYPE_I32, 585924e46e6cSRichard Henderson ldst->addrlo_reg, -1); 586024e46e6cSRichard Henderson next_arg += 2; 586124e46e6cSRichard Henderson nmov += 1; 5862c31e5fa4SRichard Henderson } else { 5863c31e5fa4SRichard Henderson n = tcg_out_helper_add_mov(mov, loc, TCG_TYPE_I64, s->addr_type, 5864c31e5fa4SRichard Henderson ldst->addrlo_reg, ldst->addrhi_reg); 5865c31e5fa4SRichard Henderson next_arg += n; 5866c31e5fa4SRichard Henderson nmov += n; 586724e46e6cSRichard Henderson } 58688429a1caSRichard Henderson 58698429a1caSRichard Henderson /* Handle data argument. */ 58708429a1caSRichard Henderson loc = &info->in[next_arg]; 5871ebebea53SRichard Henderson switch (loc->kind) { 5872ebebea53SRichard Henderson case TCG_CALL_ARG_NORMAL: 5873ebebea53SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 5874ebebea53SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 58758429a1caSRichard Henderson n = tcg_out_helper_add_mov(mov + nmov, loc, data_type, ldst->type, 58768429a1caSRichard Henderson ldst->datalo_reg, ldst->datahi_reg); 58778429a1caSRichard Henderson next_arg += n; 58788429a1caSRichard Henderson nmov += n; 5879ebebea53SRichard Henderson tcg_out_helper_load_slots(s, nmov, mov, parm); 5880ebebea53SRichard Henderson break; 5881ebebea53SRichard Henderson 5882ebebea53SRichard Henderson case TCG_CALL_ARG_BY_REF: 5883ebebea53SRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 64); 5884ebebea53SRichard Henderson tcg_debug_assert(data_type == TCG_TYPE_I128); 5885ebebea53SRichard Henderson tcg_out_st(s, TCG_TYPE_I64, 5886ebebea53SRichard Henderson HOST_BIG_ENDIAN ? ldst->datahi_reg : ldst->datalo_reg, 5887ebebea53SRichard Henderson TCG_REG_CALL_STACK, arg_slot_stk_ofs(loc[0].ref_slot)); 5888ebebea53SRichard Henderson tcg_out_st(s, TCG_TYPE_I64, 5889ebebea53SRichard Henderson HOST_BIG_ENDIAN ? ldst->datalo_reg : ldst->datahi_reg, 5890ebebea53SRichard Henderson TCG_REG_CALL_STACK, arg_slot_stk_ofs(loc[1].ref_slot)); 58918429a1caSRichard Henderson 58928429a1caSRichard Henderson tcg_out_helper_load_slots(s, nmov, mov, parm); 5893ebebea53SRichard Henderson 5894ebebea53SRichard Henderson if (arg_slot_reg_p(loc->arg_slot)) { 5895ebebea53SRichard Henderson tcg_out_addi_ptr(s, tcg_target_call_iarg_regs[loc->arg_slot], 5896ebebea53SRichard Henderson TCG_REG_CALL_STACK, 5897ebebea53SRichard Henderson arg_slot_stk_ofs(loc->ref_slot)); 5898ebebea53SRichard Henderson } else { 5899ebebea53SRichard Henderson tcg_debug_assert(parm->ntmp != 0); 5900ebebea53SRichard Henderson tcg_out_addi_ptr(s, parm->tmp[0], TCG_REG_CALL_STACK, 5901ebebea53SRichard Henderson arg_slot_stk_ofs(loc->ref_slot)); 5902ebebea53SRichard Henderson tcg_out_st(s, TCG_TYPE_PTR, parm->tmp[0], 5903ebebea53SRichard Henderson TCG_REG_CALL_STACK, arg_slot_stk_ofs(loc->arg_slot)); 5904ebebea53SRichard Henderson } 5905ebebea53SRichard Henderson next_arg += 2; 5906ebebea53SRichard Henderson break; 5907ebebea53SRichard Henderson 5908ebebea53SRichard Henderson default: 5909ebebea53SRichard Henderson g_assert_not_reached(); 5910ebebea53SRichard Henderson } 5911ebebea53SRichard Henderson 5912c31e5fa4SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && s->addr_type == TCG_TYPE_I32) { 5913c31e5fa4SRichard Henderson /* Zero extend the address by loading a zero for the high part. */ 591424e46e6cSRichard Henderson loc = &info->in[1 + !HOST_BIG_ENDIAN]; 591524e46e6cSRichard Henderson tcg_out_helper_load_imm(s, loc->arg_slot, TCG_TYPE_I32, 0, parm); 591624e46e6cSRichard Henderson } 591724e46e6cSRichard Henderson 59188429a1caSRichard Henderson tcg_out_helper_load_common_args(s, ldst, parm, info, next_arg); 59198429a1caSRichard Henderson } 59208429a1caSRichard Henderson 5921b6a7f3e0SDaniel P. Berrangé void tcg_dump_op_count(GString *buf) 5922246ae24dSMax Filippov { 5923b6a7f3e0SDaniel P. Berrangé g_string_append_printf(buf, "[TCG profiler not compiled]\n"); 5924246ae24dSMax Filippov } 592572fd2efbSEmilio G. Cota 592676cef4b2SRichard Henderson int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start) 5927c896fe29Sbellard { 5928747bd69dSRichard Henderson int i, start_words, num_insns; 592915fa08f8SRichard Henderson TCGOp *op; 5930c896fe29Sbellard 5931d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP) 5932fbf59aadSRichard Henderson && qemu_log_in_addr_range(pc_start))) { 5933c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock(); 593478b54858SRichard Henderson if (logfile) { 593578b54858SRichard Henderson fprintf(logfile, "OP:\n"); 5936b7a83ff8SRichard Henderson tcg_dump_ops(s, logfile, false); 593778b54858SRichard Henderson fprintf(logfile, "\n"); 5938fc59d2d8SRobert Foley qemu_log_unlock(logfile); 5939c896fe29Sbellard } 594078b54858SRichard Henderson } 5941c896fe29Sbellard 5942bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG 5943bef16ab4SRichard Henderson /* Ensure all labels referenced have been emitted. */ 5944bef16ab4SRichard Henderson { 5945bef16ab4SRichard Henderson TCGLabel *l; 5946bef16ab4SRichard Henderson bool error = false; 5947bef16ab4SRichard Henderson 5948bef16ab4SRichard Henderson QSIMPLEQ_FOREACH(l, &s->labels, next) { 5949f85b1fc4SRichard Henderson if (unlikely(!l->present) && !QSIMPLEQ_EMPTY(&l->branches)) { 5950bef16ab4SRichard Henderson qemu_log_mask(CPU_LOG_TB_OP, 5951bef16ab4SRichard Henderson "$L%d referenced but not present.\n", l->id); 5952bef16ab4SRichard Henderson error = true; 5953bef16ab4SRichard Henderson } 5954bef16ab4SRichard Henderson } 5955bef16ab4SRichard Henderson assert(!error); 5956bef16ab4SRichard Henderson } 5957bef16ab4SRichard Henderson #endif 5958bef16ab4SRichard Henderson 5959c45cb8bbSRichard Henderson tcg_optimize(s); 59608f2e8c07SKirill Batuzov 5961b4fc67c7SRichard Henderson reachable_code_pass(s); 5962874b8574SRichard Henderson liveness_pass_0(s); 5963b83eabeaSRichard Henderson liveness_pass_1(s); 59645a18407fSRichard Henderson 59655a18407fSRichard Henderson if (s->nb_indirects > 0) { 59665a18407fSRichard Henderson if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND) 5967fbf59aadSRichard Henderson && qemu_log_in_addr_range(pc_start))) { 5968c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock(); 596978b54858SRichard Henderson if (logfile) { 597078b54858SRichard Henderson fprintf(logfile, "OP before indirect lowering:\n"); 5971b7a83ff8SRichard Henderson tcg_dump_ops(s, logfile, false); 597278b54858SRichard Henderson fprintf(logfile, "\n"); 5973fc59d2d8SRobert Foley qemu_log_unlock(logfile); 59745a18407fSRichard Henderson } 597578b54858SRichard Henderson } 5976645e3a81SRichard Henderson 59775a18407fSRichard Henderson /* Replace indirect temps with direct temps. */ 5978b83eabeaSRichard Henderson if (liveness_pass_2(s)) { 59795a18407fSRichard Henderson /* If changes were made, re-run liveness. */ 5980b83eabeaSRichard Henderson liveness_pass_1(s); 59815a18407fSRichard Henderson } 59825a18407fSRichard Henderson } 5983c5cc28ffSAurelien Jarno 5984d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT) 5985fbf59aadSRichard Henderson && qemu_log_in_addr_range(pc_start))) { 5986c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock(); 598778b54858SRichard Henderson if (logfile) { 598878b54858SRichard Henderson fprintf(logfile, "OP after optimization and liveness analysis:\n"); 5989b7a83ff8SRichard Henderson tcg_dump_ops(s, logfile, true); 599078b54858SRichard Henderson fprintf(logfile, "\n"); 5991fc59d2d8SRobert Foley qemu_log_unlock(logfile); 5992c896fe29Sbellard } 599378b54858SRichard Henderson } 5994c896fe29Sbellard 599535abb009SRichard Henderson /* Initialize goto_tb jump offsets. */ 59963a50f424SRichard Henderson tb->jmp_reset_offset[0] = TB_JMP_OFFSET_INVALID; 59973a50f424SRichard Henderson tb->jmp_reset_offset[1] = TB_JMP_OFFSET_INVALID; 59989da6079bSRichard Henderson tb->jmp_insn_offset[0] = TB_JMP_OFFSET_INVALID; 59999da6079bSRichard Henderson tb->jmp_insn_offset[1] = TB_JMP_OFFSET_INVALID; 600035abb009SRichard Henderson 6001c896fe29Sbellard tcg_reg_alloc_start(s); 6002c896fe29Sbellard 6003db0c51a3SRichard Henderson /* 6004db0c51a3SRichard Henderson * Reset the buffer pointers when restarting after overflow. 6005db0c51a3SRichard Henderson * TODO: Move this into translate-all.c with the rest of the 6006db0c51a3SRichard Henderson * buffer management. Having only this done here is confusing. 6007db0c51a3SRichard Henderson */ 6008db0c51a3SRichard Henderson s->code_buf = tcg_splitwx_to_rw(tb->tc.ptr); 6009db0c51a3SRichard Henderson s->code_ptr = s->code_buf; 6010c896fe29Sbellard 6011659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS 60126001f772SLaurent Vivier QSIMPLEQ_INIT(&s->ldst_labels); 6013659ef5cbSRichard Henderson #endif 601457a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 601557a26946SRichard Henderson s->pool_labels = NULL; 601657a26946SRichard Henderson #endif 60179ecefc84SRichard Henderson 6018747bd69dSRichard Henderson start_words = s->insn_start_words; 6019747bd69dSRichard Henderson s->gen_insn_data = 6020747bd69dSRichard Henderson tcg_malloc(sizeof(uint64_t) * s->gen_tb->icount * start_words); 6021747bd69dSRichard Henderson 60229358fbbfSRichard Henderson tcg_out_tb_start(s); 60239358fbbfSRichard Henderson 6024fca8a500SRichard Henderson num_insns = -1; 602515fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 6026c45cb8bbSRichard Henderson TCGOpcode opc = op->opc; 6027b3db8758Sblueswir1 6028c896fe29Sbellard switch (opc) { 6029c896fe29Sbellard case INDEX_op_mov_i32: 6030c896fe29Sbellard case INDEX_op_mov_i64: 6031d2fd745fSRichard Henderson case INDEX_op_mov_vec: 6032dd186292SRichard Henderson tcg_reg_alloc_mov(s, op); 6033c896fe29Sbellard break; 6034bab1671fSRichard Henderson case INDEX_op_dup_vec: 6035bab1671fSRichard Henderson tcg_reg_alloc_dup(s, op); 6036bab1671fSRichard Henderson break; 6037765b842aSRichard Henderson case INDEX_op_insn_start: 6038fca8a500SRichard Henderson if (num_insns >= 0) { 60399f754620SRichard Henderson size_t off = tcg_current_code_size(s); 60409f754620SRichard Henderson s->gen_insn_end_off[num_insns] = off; 60419f754620SRichard Henderson /* Assert that we do not overflow our stored offset. */ 60429f754620SRichard Henderson assert(s->gen_insn_end_off[num_insns] == off); 6043fca8a500SRichard Henderson } 6044fca8a500SRichard Henderson num_insns++; 6045747bd69dSRichard Henderson for (i = 0; i < start_words; ++i) { 6046747bd69dSRichard Henderson s->gen_insn_data[num_insns * start_words + i] = 6047c9ad8d27SRichard Henderson tcg_get_insn_start_param(op, i); 6048bad729e2SRichard Henderson } 6049c896fe29Sbellard break; 60505ff9d6a4Sbellard case INDEX_op_discard: 605143439139SRichard Henderson temp_dead(s, arg_temp(op->args[0])); 60525ff9d6a4Sbellard break; 6053c896fe29Sbellard case INDEX_op_set_label: 6054e8996ee0Sbellard tcg_reg_alloc_bb_end(s, s->reserved_regs); 605592ab8e7dSRichard Henderson tcg_out_label(s, arg_label(op->args[0])); 6056c896fe29Sbellard break; 6057c896fe29Sbellard case INDEX_op_call: 6058dd186292SRichard Henderson tcg_reg_alloc_call(s, op); 6059c45cb8bbSRichard Henderson break; 6060b55a8d9dSRichard Henderson case INDEX_op_exit_tb: 6061b55a8d9dSRichard Henderson tcg_out_exit_tb(s, op->args[0]); 6062b55a8d9dSRichard Henderson break; 6063cf7d6b8eSRichard Henderson case INDEX_op_goto_tb: 6064cf7d6b8eSRichard Henderson tcg_out_goto_tb(s, op->args[0]); 6065cf7d6b8eSRichard Henderson break; 6066efe86b21SRichard Henderson case INDEX_op_dup2_vec: 6067efe86b21SRichard Henderson if (tcg_reg_alloc_dup2(s, op)) { 6068efe86b21SRichard Henderson break; 6069efe86b21SRichard Henderson } 6070efe86b21SRichard Henderson /* fall through */ 6071c896fe29Sbellard default: 607225c4d9ccSRichard Henderson /* Sanity check that we've not introduced any unhandled opcodes. */ 6073be0f34b5SRichard Henderson tcg_debug_assert(tcg_op_supported(opc)); 6074c896fe29Sbellard /* Note: in order to speed up the code, it would be much 6075c896fe29Sbellard faster to have specialized register allocator functions for 6076c896fe29Sbellard some common argument patterns */ 6077dd186292SRichard Henderson tcg_reg_alloc_op(s, op); 6078c896fe29Sbellard break; 6079c896fe29Sbellard } 6080b125f9dcSRichard Henderson /* Test for (pending) buffer overflow. The assumption is that any 6081b125f9dcSRichard Henderson one operation beginning below the high water mark cannot overrun 6082b125f9dcSRichard Henderson the buffer completely. Thus we can test for overflow after 6083b125f9dcSRichard Henderson generating code without having to check during generation. */ 6084644da9b3SJohn Clarke if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) { 6085b125f9dcSRichard Henderson return -1; 6086b125f9dcSRichard Henderson } 60876e6c4efeSRichard Henderson /* Test for TB overflow, as seen by gen_insn_end_off. */ 60886e6c4efeSRichard Henderson if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) { 60896e6c4efeSRichard Henderson return -2; 60906e6c4efeSRichard Henderson } 6091c896fe29Sbellard } 6092747bd69dSRichard Henderson tcg_debug_assert(num_insns + 1 == s->gen_tb->icount); 6093fca8a500SRichard Henderson s->gen_insn_end_off[num_insns] = tcg_current_code_size(s); 6094c45cb8bbSRichard Henderson 6095b76f0d8cSYeongkyoon Lee /* Generate TB finalization at the end of block */ 6096659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS 6097aeee05f5SRichard Henderson i = tcg_out_ldst_finalize(s); 6098aeee05f5SRichard Henderson if (i < 0) { 6099aeee05f5SRichard Henderson return i; 610023dceda6SRichard Henderson } 6101659ef5cbSRichard Henderson #endif 610257a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 61031768987bSRichard Henderson i = tcg_out_pool_finalize(s); 61041768987bSRichard Henderson if (i < 0) { 61051768987bSRichard Henderson return i; 610657a26946SRichard Henderson } 610757a26946SRichard Henderson #endif 61087ecd02a0SRichard Henderson if (!tcg_resolve_relocs(s)) { 61097ecd02a0SRichard Henderson return -2; 61107ecd02a0SRichard Henderson } 6111c896fe29Sbellard 6112df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 6113c896fe29Sbellard /* flush instruction cache */ 6114db0c51a3SRichard Henderson flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf), 6115db0c51a3SRichard Henderson (uintptr_t)s->code_buf, 61161da8de39SRichard Henderson tcg_ptr_byte_diff(s->code_ptr, s->code_buf)); 6117df5d2b16SRichard Henderson #endif 61182aeabc08SStefan Weil 61191813e175SRichard Henderson return tcg_current_code_size(s); 6120c896fe29Sbellard } 6121c896fe29Sbellard 61223a841ab5SDaniel P. Berrangé void tcg_dump_info(GString *buf) 6123a23a9ec6Sbellard { 61243a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "[TCG profiler not compiled]\n"); 6125a23a9ec6Sbellard } 6126813da627SRichard Henderson 6127813da627SRichard Henderson #ifdef ELF_HOST_MACHINE 61285872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things: 61295872bbf2SRichard Henderson 61305872bbf2SRichard Henderson (1) Define ELF_HOST_MACHINE to indicate both what value to 61315872bbf2SRichard Henderson put into the ELF image and to indicate support for the feature. 61325872bbf2SRichard Henderson 61335872bbf2SRichard Henderson (2) Define tcg_register_jit. This should create a buffer containing 61345872bbf2SRichard Henderson the contents of a .debug_frame section that describes the post- 61355872bbf2SRichard Henderson prologue unwind info for the tcg machine. 61365872bbf2SRichard Henderson 61375872bbf2SRichard Henderson (3) Call tcg_register_jit_int, with the constructed .debug_frame. 61385872bbf2SRichard Henderson */ 6139813da627SRichard Henderson 6140813da627SRichard Henderson /* Begin GDB interface. THE FOLLOWING MUST MATCH GDB DOCS. */ 6141813da627SRichard Henderson typedef enum { 6142813da627SRichard Henderson JIT_NOACTION = 0, 6143813da627SRichard Henderson JIT_REGISTER_FN, 6144813da627SRichard Henderson JIT_UNREGISTER_FN 6145813da627SRichard Henderson } jit_actions_t; 6146813da627SRichard Henderson 6147813da627SRichard Henderson struct jit_code_entry { 6148813da627SRichard Henderson struct jit_code_entry *next_entry; 6149813da627SRichard Henderson struct jit_code_entry *prev_entry; 6150813da627SRichard Henderson const void *symfile_addr; 6151813da627SRichard Henderson uint64_t symfile_size; 6152813da627SRichard Henderson }; 6153813da627SRichard Henderson 6154813da627SRichard Henderson struct jit_descriptor { 6155813da627SRichard Henderson uint32_t version; 6156813da627SRichard Henderson uint32_t action_flag; 6157813da627SRichard Henderson struct jit_code_entry *relevant_entry; 6158813da627SRichard Henderson struct jit_code_entry *first_entry; 6159813da627SRichard Henderson }; 6160813da627SRichard Henderson 6161813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline)); 6162813da627SRichard Henderson void __jit_debug_register_code(void) 6163813da627SRichard Henderson { 6164813da627SRichard Henderson asm(""); 6165813da627SRichard Henderson } 6166813da627SRichard Henderson 6167813da627SRichard Henderson /* Must statically initialize the version, because GDB may check 6168813da627SRichard Henderson the version before we can set it. */ 6169813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 }; 6170813da627SRichard Henderson 6171813da627SRichard Henderson /* End GDB interface. */ 6172813da627SRichard Henderson 6173813da627SRichard Henderson static int find_string(const char *strtab, const char *str) 6174813da627SRichard Henderson { 6175813da627SRichard Henderson const char *p = strtab + 1; 6176813da627SRichard Henderson 6177813da627SRichard Henderson while (1) { 6178813da627SRichard Henderson if (strcmp(p, str) == 0) { 6179813da627SRichard Henderson return p - strtab; 6180813da627SRichard Henderson } 6181813da627SRichard Henderson p += strlen(p) + 1; 6182813da627SRichard Henderson } 6183813da627SRichard Henderson } 6184813da627SRichard Henderson 6185755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf_ptr, size_t buf_size, 61862c90784aSRichard Henderson const void *debug_frame, 61872c90784aSRichard Henderson size_t debug_frame_size) 6188813da627SRichard Henderson { 61895872bbf2SRichard Henderson struct __attribute__((packed)) DebugInfo { 61905872bbf2SRichard Henderson uint32_t len; 61915872bbf2SRichard Henderson uint16_t version; 61925872bbf2SRichard Henderson uint32_t abbrev; 61935872bbf2SRichard Henderson uint8_t ptr_size; 61945872bbf2SRichard Henderson uint8_t cu_die; 61955872bbf2SRichard Henderson uint16_t cu_lang; 61965872bbf2SRichard Henderson uintptr_t cu_low_pc; 61975872bbf2SRichard Henderson uintptr_t cu_high_pc; 61985872bbf2SRichard Henderson uint8_t fn_die; 61995872bbf2SRichard Henderson char fn_name[16]; 62005872bbf2SRichard Henderson uintptr_t fn_low_pc; 62015872bbf2SRichard Henderson uintptr_t fn_high_pc; 62025872bbf2SRichard Henderson uint8_t cu_eoc; 62035872bbf2SRichard Henderson }; 6204813da627SRichard Henderson 6205813da627SRichard Henderson struct ElfImage { 6206813da627SRichard Henderson ElfW(Ehdr) ehdr; 6207813da627SRichard Henderson ElfW(Phdr) phdr; 62085872bbf2SRichard Henderson ElfW(Shdr) shdr[7]; 62095872bbf2SRichard Henderson ElfW(Sym) sym[2]; 62105872bbf2SRichard Henderson struct DebugInfo di; 62115872bbf2SRichard Henderson uint8_t da[24]; 62125872bbf2SRichard Henderson char str[80]; 62135872bbf2SRichard Henderson }; 62145872bbf2SRichard Henderson 62155872bbf2SRichard Henderson struct ElfImage *img; 62165872bbf2SRichard Henderson 62175872bbf2SRichard Henderson static const struct ElfImage img_template = { 62185872bbf2SRichard Henderson .ehdr = { 62195872bbf2SRichard Henderson .e_ident[EI_MAG0] = ELFMAG0, 62205872bbf2SRichard Henderson .e_ident[EI_MAG1] = ELFMAG1, 62215872bbf2SRichard Henderson .e_ident[EI_MAG2] = ELFMAG2, 62225872bbf2SRichard Henderson .e_ident[EI_MAG3] = ELFMAG3, 62235872bbf2SRichard Henderson .e_ident[EI_CLASS] = ELF_CLASS, 62245872bbf2SRichard Henderson .e_ident[EI_DATA] = ELF_DATA, 62255872bbf2SRichard Henderson .e_ident[EI_VERSION] = EV_CURRENT, 62265872bbf2SRichard Henderson .e_type = ET_EXEC, 62275872bbf2SRichard Henderson .e_machine = ELF_HOST_MACHINE, 62285872bbf2SRichard Henderson .e_version = EV_CURRENT, 62295872bbf2SRichard Henderson .e_phoff = offsetof(struct ElfImage, phdr), 62305872bbf2SRichard Henderson .e_shoff = offsetof(struct ElfImage, shdr), 62315872bbf2SRichard Henderson .e_ehsize = sizeof(ElfW(Shdr)), 62325872bbf2SRichard Henderson .e_phentsize = sizeof(ElfW(Phdr)), 62335872bbf2SRichard Henderson .e_phnum = 1, 62345872bbf2SRichard Henderson .e_shentsize = sizeof(ElfW(Shdr)), 62355872bbf2SRichard Henderson .e_shnum = ARRAY_SIZE(img->shdr), 62365872bbf2SRichard Henderson .e_shstrndx = ARRAY_SIZE(img->shdr) - 1, 6237abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS 6238abbb3eaeSRichard Henderson .e_flags = ELF_HOST_FLAGS, 6239abbb3eaeSRichard Henderson #endif 6240abbb3eaeSRichard Henderson #ifdef ELF_OSABI 6241abbb3eaeSRichard Henderson .e_ident[EI_OSABI] = ELF_OSABI, 6242abbb3eaeSRichard Henderson #endif 62435872bbf2SRichard Henderson }, 62445872bbf2SRichard Henderson .phdr = { 62455872bbf2SRichard Henderson .p_type = PT_LOAD, 62465872bbf2SRichard Henderson .p_flags = PF_X, 62475872bbf2SRichard Henderson }, 62485872bbf2SRichard Henderson .shdr = { 62495872bbf2SRichard Henderson [0] = { .sh_type = SHT_NULL }, 62505872bbf2SRichard Henderson /* Trick: The contents of code_gen_buffer are not present in 62515872bbf2SRichard Henderson this fake ELF file; that got allocated elsewhere. Therefore 62525872bbf2SRichard Henderson we mark .text as SHT_NOBITS (similar to .bss) so that readers 62535872bbf2SRichard Henderson will not look for contents. We can record any address. */ 62545872bbf2SRichard Henderson [1] = { /* .text */ 62555872bbf2SRichard Henderson .sh_type = SHT_NOBITS, 62565872bbf2SRichard Henderson .sh_flags = SHF_EXECINSTR | SHF_ALLOC, 62575872bbf2SRichard Henderson }, 62585872bbf2SRichard Henderson [2] = { /* .debug_info */ 62595872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 62605872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, di), 62615872bbf2SRichard Henderson .sh_size = sizeof(struct DebugInfo), 62625872bbf2SRichard Henderson }, 62635872bbf2SRichard Henderson [3] = { /* .debug_abbrev */ 62645872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 62655872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, da), 62665872bbf2SRichard Henderson .sh_size = sizeof(img->da), 62675872bbf2SRichard Henderson }, 62685872bbf2SRichard Henderson [4] = { /* .debug_frame */ 62695872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 62705872bbf2SRichard Henderson .sh_offset = sizeof(struct ElfImage), 62715872bbf2SRichard Henderson }, 62725872bbf2SRichard Henderson [5] = { /* .symtab */ 62735872bbf2SRichard Henderson .sh_type = SHT_SYMTAB, 62745872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, sym), 62755872bbf2SRichard Henderson .sh_size = sizeof(img->sym), 62765872bbf2SRichard Henderson .sh_info = 1, 62775872bbf2SRichard Henderson .sh_link = ARRAY_SIZE(img->shdr) - 1, 62785872bbf2SRichard Henderson .sh_entsize = sizeof(ElfW(Sym)), 62795872bbf2SRichard Henderson }, 62805872bbf2SRichard Henderson [6] = { /* .strtab */ 62815872bbf2SRichard Henderson .sh_type = SHT_STRTAB, 62825872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, str), 62835872bbf2SRichard Henderson .sh_size = sizeof(img->str), 62845872bbf2SRichard Henderson } 62855872bbf2SRichard Henderson }, 62865872bbf2SRichard Henderson .sym = { 62875872bbf2SRichard Henderson [1] = { /* code_gen_buffer */ 62885872bbf2SRichard Henderson .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC), 62895872bbf2SRichard Henderson .st_shndx = 1, 62905872bbf2SRichard Henderson } 62915872bbf2SRichard Henderson }, 62925872bbf2SRichard Henderson .di = { 62935872bbf2SRichard Henderson .len = sizeof(struct DebugInfo) - 4, 62945872bbf2SRichard Henderson .version = 2, 62955872bbf2SRichard Henderson .ptr_size = sizeof(void *), 62965872bbf2SRichard Henderson .cu_die = 1, 62975872bbf2SRichard Henderson .cu_lang = 0x8001, /* DW_LANG_Mips_Assembler */ 62985872bbf2SRichard Henderson .fn_die = 2, 62995872bbf2SRichard Henderson .fn_name = "code_gen_buffer" 63005872bbf2SRichard Henderson }, 63015872bbf2SRichard Henderson .da = { 63025872bbf2SRichard Henderson 1, /* abbrev number (the cu) */ 63035872bbf2SRichard Henderson 0x11, 1, /* DW_TAG_compile_unit, has children */ 63045872bbf2SRichard Henderson 0x13, 0x5, /* DW_AT_language, DW_FORM_data2 */ 63055872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */ 63065872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */ 63075872bbf2SRichard Henderson 0, 0, /* end of abbrev */ 63085872bbf2SRichard Henderson 2, /* abbrev number (the fn) */ 63095872bbf2SRichard Henderson 0x2e, 0, /* DW_TAG_subprogram, no children */ 63105872bbf2SRichard Henderson 0x3, 0x8, /* DW_AT_name, DW_FORM_string */ 63115872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */ 63125872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */ 63135872bbf2SRichard Henderson 0, 0, /* end of abbrev */ 63145872bbf2SRichard Henderson 0 /* no more abbrev */ 63155872bbf2SRichard Henderson }, 63165872bbf2SRichard Henderson .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0" 63175872bbf2SRichard Henderson ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer", 6318813da627SRichard Henderson }; 6319813da627SRichard Henderson 6320813da627SRichard Henderson /* We only need a single jit entry; statically allocate it. */ 6321813da627SRichard Henderson static struct jit_code_entry one_entry; 6322813da627SRichard Henderson 63235872bbf2SRichard Henderson uintptr_t buf = (uintptr_t)buf_ptr; 6324813da627SRichard Henderson size_t img_size = sizeof(struct ElfImage) + debug_frame_size; 63252c90784aSRichard Henderson DebugFrameHeader *dfh; 6326813da627SRichard Henderson 63275872bbf2SRichard Henderson img = g_malloc(img_size); 63285872bbf2SRichard Henderson *img = img_template; 6329813da627SRichard Henderson 63305872bbf2SRichard Henderson img->phdr.p_vaddr = buf; 63315872bbf2SRichard Henderson img->phdr.p_paddr = buf; 63325872bbf2SRichard Henderson img->phdr.p_memsz = buf_size; 6333813da627SRichard Henderson 63345872bbf2SRichard Henderson img->shdr[1].sh_name = find_string(img->str, ".text"); 63355872bbf2SRichard Henderson img->shdr[1].sh_addr = buf; 63365872bbf2SRichard Henderson img->shdr[1].sh_size = buf_size; 6337813da627SRichard Henderson 63385872bbf2SRichard Henderson img->shdr[2].sh_name = find_string(img->str, ".debug_info"); 63395872bbf2SRichard Henderson img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev"); 63405872bbf2SRichard Henderson 63415872bbf2SRichard Henderson img->shdr[4].sh_name = find_string(img->str, ".debug_frame"); 63425872bbf2SRichard Henderson img->shdr[4].sh_size = debug_frame_size; 63435872bbf2SRichard Henderson 63445872bbf2SRichard Henderson img->shdr[5].sh_name = find_string(img->str, ".symtab"); 63455872bbf2SRichard Henderson img->shdr[6].sh_name = find_string(img->str, ".strtab"); 63465872bbf2SRichard Henderson 63475872bbf2SRichard Henderson img->sym[1].st_name = find_string(img->str, "code_gen_buffer"); 63485872bbf2SRichard Henderson img->sym[1].st_value = buf; 63495872bbf2SRichard Henderson img->sym[1].st_size = buf_size; 63505872bbf2SRichard Henderson 63515872bbf2SRichard Henderson img->di.cu_low_pc = buf; 635245aba097SRichard Henderson img->di.cu_high_pc = buf + buf_size; 63535872bbf2SRichard Henderson img->di.fn_low_pc = buf; 635445aba097SRichard Henderson img->di.fn_high_pc = buf + buf_size; 6355813da627SRichard Henderson 63562c90784aSRichard Henderson dfh = (DebugFrameHeader *)(img + 1); 63572c90784aSRichard Henderson memcpy(dfh, debug_frame, debug_frame_size); 63582c90784aSRichard Henderson dfh->fde.func_start = buf; 63592c90784aSRichard Henderson dfh->fde.func_len = buf_size; 63602c90784aSRichard Henderson 6361813da627SRichard Henderson #ifdef DEBUG_JIT 6362813da627SRichard Henderson /* Enable this block to be able to debug the ELF image file creation. 6363813da627SRichard Henderson One can use readelf, objdump, or other inspection utilities. */ 6364813da627SRichard Henderson { 6365eb6b2edfSBin Meng g_autofree char *jit = g_strdup_printf("%s/qemu.jit", g_get_tmp_dir()); 6366eb6b2edfSBin Meng FILE *f = fopen(jit, "w+b"); 6367813da627SRichard Henderson if (f) { 63685872bbf2SRichard Henderson if (fwrite(img, img_size, 1, f) != img_size) { 6369813da627SRichard Henderson /* Avoid stupid unused return value warning for fwrite. */ 6370813da627SRichard Henderson } 6371813da627SRichard Henderson fclose(f); 6372813da627SRichard Henderson } 6373813da627SRichard Henderson } 6374813da627SRichard Henderson #endif 6375813da627SRichard Henderson 6376813da627SRichard Henderson one_entry.symfile_addr = img; 6377813da627SRichard Henderson one_entry.symfile_size = img_size; 6378813da627SRichard Henderson 6379813da627SRichard Henderson __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; 6380813da627SRichard Henderson __jit_debug_descriptor.relevant_entry = &one_entry; 6381813da627SRichard Henderson __jit_debug_descriptor.first_entry = &one_entry; 6382813da627SRichard Henderson __jit_debug_register_code(); 6383813da627SRichard Henderson } 6384813da627SRichard Henderson #else 63855872bbf2SRichard Henderson /* No support for the feature. Provide the entry point expected by exec.c, 63865872bbf2SRichard Henderson and implement the internal function we declared earlier. */ 6387813da627SRichard Henderson 6388755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size, 63892c90784aSRichard Henderson const void *debug_frame, 63902c90784aSRichard Henderson size_t debug_frame_size) 6391813da627SRichard Henderson { 6392813da627SRichard Henderson } 6393813da627SRichard Henderson 6394755bf9e5SRichard Henderson void tcg_register_jit(const void *buf, size_t buf_size) 6395813da627SRichard Henderson { 6396813da627SRichard Henderson } 6397813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */ 6398db432672SRichard Henderson 6399db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec 6400db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...) 6401db432672SRichard Henderson { 6402db432672SRichard Henderson g_assert_not_reached(); 6403db432672SRichard Henderson } 6404db432672SRichard Henderson #endif 6405