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 25c896fe29Sbellard /* define it to use liveness analysis (better code) */ 268f2e8c07SKirill Batuzov #define USE_TCG_OPTIMIZATIONS 27c896fe29Sbellard 28757e725bSPeter Maydell #include "qemu/osdep.h" 29cca82982Saurel32 30813da627SRichard Henderson /* Define to jump the ELF file used to communicate with GDB. */ 31813da627SRichard Henderson #undef DEBUG_JIT 32813da627SRichard Henderson 3372fd2efbSEmilio G. Cota #include "qemu/error-report.h" 34f348b6d1SVeronia Bahaa #include "qemu/cutils.h" 351de7afc9SPaolo Bonzini #include "qemu/host-utils.h" 36d4c51a0aSMarkus Armbruster #include "qemu/qemu-print.h" 37084cfca1SRichard Henderson #include "qemu/cacheflush.h" 38ad768e6fSPeter Maydell #include "qemu/cacheinfo.h" 39533206f0SRichard W.M. Jones #include "qemu/timer.h" 40c896fe29Sbellard 41c5d3c498SStefan Weil /* Note: the long term plan is to reduce the dependencies on the QEMU 42c896fe29Sbellard CPU definitions. Currently they are used for qemu_ld/st 43c896fe29Sbellard instructions */ 44c896fe29Sbellard #define NO_CPU_IO_DEFS 45c896fe29Sbellard 4663c91552SPaolo Bonzini #include "exec/exec-all.h" 47dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h" 48813da627SRichard Henderson 49edee2579SRichard Henderson #if UINTPTR_MAX == UINT32_MAX 50813da627SRichard Henderson # define ELF_CLASS ELFCLASS32 51edee2579SRichard Henderson #else 52edee2579SRichard Henderson # define ELF_CLASS ELFCLASS64 53813da627SRichard Henderson #endif 54e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN 55813da627SRichard Henderson # define ELF_DATA ELFDATA2MSB 56813da627SRichard Henderson #else 57813da627SRichard Henderson # define ELF_DATA ELFDATA2LSB 58813da627SRichard Henderson #endif 59813da627SRichard Henderson 60c896fe29Sbellard #include "elf.h" 61508127e2SPaolo Bonzini #include "exec/log.h" 62d2ba8026SRichard Henderson #include "tcg/tcg-ldst.h" 6347f7313dSRichard Henderson #include "tcg/tcg-temp-internal.h" 645ff7258cSRichard Henderson #include "tcg-internal.h" 655584e2dbSIlya Leoshkevich #include "accel/tcg/perf.h" 66c896fe29Sbellard 67139c1837SPaolo Bonzini /* Forward declarations for functions declared in tcg-target.c.inc and 68ce151109SPeter Maydell used here. */ 69e4d58b41SRichard Henderson static void tcg_target_init(TCGContext *s); 70e4d58b41SRichard Henderson static void tcg_target_qemu_prologue(TCGContext *s); 716ac17786SRichard Henderson static bool patch_reloc(tcg_insn_unit *code_ptr, int type, 722ba7fae2SRichard Henderson intptr_t value, intptr_t addend); 73c896fe29Sbellard 74497a22ebSRichard Henderson /* The CIE and FDE header definitions will be common to all hosts. */ 75497a22ebSRichard Henderson typedef struct { 76497a22ebSRichard Henderson uint32_t len __attribute__((aligned((sizeof(void *))))); 77497a22ebSRichard Henderson uint32_t id; 78497a22ebSRichard Henderson uint8_t version; 79497a22ebSRichard Henderson char augmentation[1]; 80497a22ebSRichard Henderson uint8_t code_align; 81497a22ebSRichard Henderson uint8_t data_align; 82497a22ebSRichard Henderson uint8_t return_column; 83497a22ebSRichard Henderson } DebugFrameCIE; 84497a22ebSRichard Henderson 85497a22ebSRichard Henderson typedef struct QEMU_PACKED { 86497a22ebSRichard Henderson uint32_t len __attribute__((aligned((sizeof(void *))))); 87497a22ebSRichard Henderson uint32_t cie_offset; 88edee2579SRichard Henderson uintptr_t func_start; 89edee2579SRichard Henderson uintptr_t func_len; 90497a22ebSRichard Henderson } DebugFrameFDEHeader; 91497a22ebSRichard Henderson 922c90784aSRichard Henderson typedef struct QEMU_PACKED { 932c90784aSRichard Henderson DebugFrameCIE cie; 942c90784aSRichard Henderson DebugFrameFDEHeader fde; 952c90784aSRichard Henderson } DebugFrameHeader; 962c90784aSRichard Henderson 97755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size, 982c90784aSRichard Henderson const void *debug_frame, 992c90784aSRichard Henderson size_t debug_frame_size) 100813da627SRichard Henderson __attribute__((unused)); 101813da627SRichard Henderson 102139c1837SPaolo Bonzini /* Forward declarations for functions declared and used in tcg-target.c.inc. */ 1032a534affSRichard Henderson static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1, 104a05b5b9bSRichard Henderson intptr_t arg2); 10578113e83SRichard Henderson static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg); 106c0ad3001SStefan Weil static void tcg_out_movi(TCGContext *s, TCGType type, 1072a534affSRichard Henderson TCGReg ret, tcg_target_long arg); 108678155b2SRichard Henderson static void tcg_out_ext8s(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg); 109*753e42eaSRichard Henderson static void tcg_out_ext16s(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg); 110d0e66c89SRichard Henderson static void tcg_out_ext8u(TCGContext *s, TCGReg ret, TCGReg arg); 111313bdea8SRichard Henderson static void tcg_out_addi_ptr(TCGContext *s, TCGReg, TCGReg, tcg_target_long); 112b55a8d9dSRichard Henderson static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg); 113cf7d6b8eSRichard Henderson static void tcg_out_goto_tb(TCGContext *s, int which); 1145e8892dbSMiroslav Rezanina static void tcg_out_op(TCGContext *s, TCGOpcode opc, 1155e8892dbSMiroslav Rezanina const TCGArg args[TCG_MAX_OP_ARGS], 1165e8892dbSMiroslav Rezanina const int const_args[TCG_MAX_OP_ARGS]); 117d2fd745fSRichard Henderson #if TCG_TARGET_MAYBE_vec 118e7632cfaSRichard Henderson static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece, 119e7632cfaSRichard Henderson TCGReg dst, TCGReg src); 120d6ecb4a9SRichard Henderson static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece, 121d6ecb4a9SRichard Henderson TCGReg dst, TCGReg base, intptr_t offset); 1224e186175SRichard Henderson static void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece, 1234e186175SRichard Henderson TCGReg dst, int64_t arg); 1245e8892dbSMiroslav Rezanina static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, 1255e8892dbSMiroslav Rezanina unsigned vecl, unsigned vece, 1265e8892dbSMiroslav Rezanina const TCGArg args[TCG_MAX_OP_ARGS], 1275e8892dbSMiroslav Rezanina const int const_args[TCG_MAX_OP_ARGS]); 128d2fd745fSRichard Henderson #else 129e7632cfaSRichard Henderson static inline bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece, 130e7632cfaSRichard Henderson TCGReg dst, TCGReg src) 131e7632cfaSRichard Henderson { 132e7632cfaSRichard Henderson g_assert_not_reached(); 133e7632cfaSRichard Henderson } 134d6ecb4a9SRichard Henderson static inline bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece, 135d6ecb4a9SRichard Henderson TCGReg dst, TCGReg base, intptr_t offset) 136d6ecb4a9SRichard Henderson { 137d6ecb4a9SRichard Henderson g_assert_not_reached(); 138d6ecb4a9SRichard Henderson } 1394e186175SRichard Henderson static inline void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece, 1404e186175SRichard Henderson TCGReg dst, int64_t arg) 141e7632cfaSRichard Henderson { 142e7632cfaSRichard Henderson g_assert_not_reached(); 143e7632cfaSRichard Henderson } 1445e8892dbSMiroslav Rezanina static inline void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, 1455e8892dbSMiroslav Rezanina unsigned vecl, unsigned vece, 1465e8892dbSMiroslav Rezanina const TCGArg args[TCG_MAX_OP_ARGS], 1475e8892dbSMiroslav Rezanina const int const_args[TCG_MAX_OP_ARGS]) 148d2fd745fSRichard Henderson { 149d2fd745fSRichard Henderson g_assert_not_reached(); 150d2fd745fSRichard Henderson } 151d2fd745fSRichard Henderson #endif 1522a534affSRichard Henderson static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1, 153a05b5b9bSRichard Henderson intptr_t arg2); 15459d7c14eSRichard Henderson static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val, 15559d7c14eSRichard Henderson TCGReg base, intptr_t ofs); 1567b7d8b2dSRichard Henderson static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target, 157cee44b03SRichard Henderson const TCGHelperInfo *info); 1585e3d0c19SRichard Henderson static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot); 159a4fbbd77SRichard Henderson static bool tcg_target_const_match(int64_t val, TCGType type, int ct); 160659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS 161aeee05f5SRichard Henderson static int tcg_out_ldst_finalize(TCGContext *s); 162659ef5cbSRichard Henderson #endif 163c896fe29Sbellard 16442eb6dfcSRichard Henderson TCGContext tcg_init_ctx; 16542eb6dfcSRichard Henderson __thread TCGContext *tcg_ctx; 16642eb6dfcSRichard Henderson 1675ff7258cSRichard Henderson TCGContext **tcg_ctxs; 1680e2d61cfSRichard Henderson unsigned int tcg_cur_ctxs; 1690e2d61cfSRichard Henderson unsigned int tcg_max_ctxs; 1701c2adb95SRichard Henderson TCGv_env cpu_env = 0; 171c8bc1168SRichard Henderson const void *tcg_code_gen_epilogue; 172db0c51a3SRichard Henderson uintptr_t tcg_splitwx_diff; 173df2cce29SEmilio G. Cota 174b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 175b91ccb31SRichard Henderson tcg_prologue_fn *tcg_qemu_tb_exec; 176b91ccb31SRichard Henderson #endif 177b91ccb31SRichard Henderson 178d2fd745fSRichard Henderson static TCGRegSet tcg_target_available_regs[TCG_TYPE_COUNT]; 179b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs; 180c896fe29Sbellard 1811813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1 1824196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v) 183c896fe29Sbellard { 184c896fe29Sbellard *s->code_ptr++ = v; 185c896fe29Sbellard } 186c896fe29Sbellard 1874196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p, 1884196dca6SPeter Maydell uint8_t v) 1895c53bb81SPeter Maydell { 1901813e175SRichard Henderson *p = v; 1915c53bb81SPeter Maydell } 1921813e175SRichard Henderson #endif 1935c53bb81SPeter Maydell 1941813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2 1954196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v) 196c896fe29Sbellard { 1971813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 2) { 1981813e175SRichard Henderson *s->code_ptr++ = v; 1991813e175SRichard Henderson } else { 2001813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 2014387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 2021813e175SRichard Henderson s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE); 2031813e175SRichard Henderson } 204c896fe29Sbellard } 205c896fe29Sbellard 2064196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p, 2074196dca6SPeter Maydell uint16_t v) 2085c53bb81SPeter Maydell { 2091813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 2) { 2101813e175SRichard Henderson *p = v; 2111813e175SRichard Henderson } else { 2125c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 2135c53bb81SPeter Maydell } 2141813e175SRichard Henderson } 2151813e175SRichard Henderson #endif 2165c53bb81SPeter Maydell 2171813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4 2184196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v) 219c896fe29Sbellard { 2201813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 4) { 2211813e175SRichard Henderson *s->code_ptr++ = v; 2221813e175SRichard Henderson } else { 2231813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 2244387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 2251813e175SRichard Henderson s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE); 2261813e175SRichard Henderson } 227c896fe29Sbellard } 228c896fe29Sbellard 2294196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p, 2304196dca6SPeter Maydell uint32_t v) 2315c53bb81SPeter Maydell { 2321813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 4) { 2331813e175SRichard Henderson *p = v; 2341813e175SRichard Henderson } else { 2355c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 2365c53bb81SPeter Maydell } 2371813e175SRichard Henderson } 2381813e175SRichard Henderson #endif 2395c53bb81SPeter Maydell 2401813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 8 2414196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v) 242ac26eb69SRichard Henderson { 2431813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 8) { 2441813e175SRichard Henderson *s->code_ptr++ = v; 2451813e175SRichard Henderson } else { 2461813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 2474387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 2481813e175SRichard Henderson s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE); 2491813e175SRichard Henderson } 250ac26eb69SRichard Henderson } 251ac26eb69SRichard Henderson 2524196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p, 2534196dca6SPeter Maydell uint64_t v) 2545c53bb81SPeter Maydell { 2551813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 8) { 2561813e175SRichard Henderson *p = v; 2571813e175SRichard Henderson } else { 2585c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 2595c53bb81SPeter Maydell } 2601813e175SRichard Henderson } 2611813e175SRichard Henderson #endif 2625c53bb81SPeter Maydell 263c896fe29Sbellard /* label relocation processing */ 264c896fe29Sbellard 2651813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type, 266bec16311SRichard Henderson TCGLabel *l, intptr_t addend) 267c896fe29Sbellard { 2687ecd02a0SRichard Henderson TCGRelocation *r = tcg_malloc(sizeof(TCGRelocation)); 269c896fe29Sbellard 270c896fe29Sbellard r->type = type; 271c896fe29Sbellard r->ptr = code_ptr; 272c896fe29Sbellard r->addend = addend; 2737ecd02a0SRichard Henderson QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next); 274c896fe29Sbellard } 275c896fe29Sbellard 27692ab8e7dSRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l) 277c896fe29Sbellard { 278eabb7b91SAurelien Jarno tcg_debug_assert(!l->has_value); 279c896fe29Sbellard l->has_value = 1; 28092ab8e7dSRichard Henderson l->u.value_ptr = tcg_splitwx_to_rx(s->code_ptr); 281c896fe29Sbellard } 282c896fe29Sbellard 28342a268c2SRichard Henderson TCGLabel *gen_new_label(void) 284c896fe29Sbellard { 285b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 28651e3972cSRichard Henderson TCGLabel *l = tcg_malloc(sizeof(TCGLabel)); 287c896fe29Sbellard 2887ecd02a0SRichard Henderson memset(l, 0, sizeof(TCGLabel)); 2897ecd02a0SRichard Henderson l->id = s->nb_labels++; 290f85b1fc4SRichard Henderson QSIMPLEQ_INIT(&l->branches); 2917ecd02a0SRichard Henderson QSIMPLEQ_INIT(&l->relocs); 2927ecd02a0SRichard Henderson 293bef16ab4SRichard Henderson QSIMPLEQ_INSERT_TAIL(&s->labels, l, next); 29442a268c2SRichard Henderson 29542a268c2SRichard Henderson return l; 296c896fe29Sbellard } 297c896fe29Sbellard 2987ecd02a0SRichard Henderson static bool tcg_resolve_relocs(TCGContext *s) 2997ecd02a0SRichard Henderson { 3007ecd02a0SRichard Henderson TCGLabel *l; 3017ecd02a0SRichard Henderson 3027ecd02a0SRichard Henderson QSIMPLEQ_FOREACH(l, &s->labels, next) { 3037ecd02a0SRichard Henderson TCGRelocation *r; 3047ecd02a0SRichard Henderson uintptr_t value = l->u.value; 3057ecd02a0SRichard Henderson 3067ecd02a0SRichard Henderson QSIMPLEQ_FOREACH(r, &l->relocs, next) { 3077ecd02a0SRichard Henderson if (!patch_reloc(r->ptr, r->type, value, r->addend)) { 3087ecd02a0SRichard Henderson return false; 3097ecd02a0SRichard Henderson } 3107ecd02a0SRichard Henderson } 3117ecd02a0SRichard Henderson } 3127ecd02a0SRichard Henderson return true; 3137ecd02a0SRichard Henderson } 3147ecd02a0SRichard Henderson 3159f754620SRichard Henderson static void set_jmp_reset_offset(TCGContext *s, int which) 3169f754620SRichard Henderson { 317f14bed3fSRichard Henderson /* 318f14bed3fSRichard Henderson * We will check for overflow at the end of the opcode loop in 319f14bed3fSRichard Henderson * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX. 320f14bed3fSRichard Henderson */ 321b7e4afbdSRichard Henderson s->gen_tb->jmp_reset_offset[which] = tcg_current_code_size(s); 3229f754620SRichard Henderson } 3239f754620SRichard Henderson 324b52a2c03SRichard Henderson static void G_GNUC_UNUSED set_jmp_insn_offset(TCGContext *s, int which) 325b52a2c03SRichard Henderson { 326b52a2c03SRichard Henderson /* 327b52a2c03SRichard Henderson * We will check for overflow at the end of the opcode loop in 328b52a2c03SRichard Henderson * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX. 329b52a2c03SRichard Henderson */ 3309da6079bSRichard Henderson s->gen_tb->jmp_insn_offset[which] = tcg_current_code_size(s); 331b52a2c03SRichard Henderson } 332b52a2c03SRichard Henderson 333becc452aSRichard Henderson static uintptr_t G_GNUC_UNUSED get_jmp_target_addr(TCGContext *s, int which) 334becc452aSRichard Henderson { 335becc452aSRichard Henderson /* 336becc452aSRichard Henderson * Return the read-execute version of the pointer, for the benefit 337becc452aSRichard Henderson * of any pc-relative addressing mode. 338becc452aSRichard Henderson */ 3399da6079bSRichard Henderson return (uintptr_t)tcg_splitwx_to_rx(&s->gen_tb->jmp_target_addr[which]); 340becc452aSRichard Henderson } 341becc452aSRichard Henderson 342db6b7d0cSRichard Henderson /* Signal overflow, starting over with fewer guest insns. */ 3438905770bSMarc-André Lureau static G_NORETURN 3448905770bSMarc-André Lureau void tcg_raise_tb_overflow(TCGContext *s) 345db6b7d0cSRichard Henderson { 346db6b7d0cSRichard Henderson siglongjmp(s->jmp_trans, -2); 347db6b7d0cSRichard Henderson } 348db6b7d0cSRichard Henderson 3494c22e840SRichard Henderson #define C_PFX1(P, A) P##A 3504c22e840SRichard Henderson #define C_PFX2(P, A, B) P##A##_##B 3514c22e840SRichard Henderson #define C_PFX3(P, A, B, C) P##A##_##B##_##C 3524c22e840SRichard Henderson #define C_PFX4(P, A, B, C, D) P##A##_##B##_##C##_##D 3534c22e840SRichard Henderson #define C_PFX5(P, A, B, C, D, E) P##A##_##B##_##C##_##D##_##E 3544c22e840SRichard Henderson #define C_PFX6(P, A, B, C, D, E, F) P##A##_##B##_##C##_##D##_##E##_##F 3554c22e840SRichard Henderson 3564c22e840SRichard Henderson /* Define an enumeration for the various combinations. */ 3574c22e840SRichard Henderson 3584c22e840SRichard Henderson #define C_O0_I1(I1) C_PFX1(c_o0_i1_, I1), 3594c22e840SRichard Henderson #define C_O0_I2(I1, I2) C_PFX2(c_o0_i2_, I1, I2), 3604c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3) C_PFX3(c_o0_i3_, I1, I2, I3), 3614c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4) C_PFX4(c_o0_i4_, I1, I2, I3, I4), 3624c22e840SRichard Henderson 3634c22e840SRichard Henderson #define C_O1_I1(O1, I1) C_PFX2(c_o1_i1_, O1, I1), 3644c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2) C_PFX3(c_o1_i2_, O1, I1, I2), 3654c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3) C_PFX4(c_o1_i3_, O1, I1, I2, I3), 3664c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4) C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4), 3674c22e840SRichard Henderson 3684c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2) C_PFX3(c_n1_i2_, O1, I1, I2), 3694c22e840SRichard Henderson 3704c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1) C_PFX3(c_o2_i1_, O1, O2, I1), 3714c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2) C_PFX4(c_o2_i2_, O1, O2, I1, I2), 3724c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3) C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3), 3734c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4), 3744c22e840SRichard Henderson 3754c22e840SRichard Henderson typedef enum { 3764c22e840SRichard Henderson #include "tcg-target-con-set.h" 3774c22e840SRichard Henderson } TCGConstraintSetIndex; 3784c22e840SRichard Henderson 3794c22e840SRichard Henderson static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode); 3804c22e840SRichard Henderson 3814c22e840SRichard Henderson #undef C_O0_I1 3824c22e840SRichard Henderson #undef C_O0_I2 3834c22e840SRichard Henderson #undef C_O0_I3 3844c22e840SRichard Henderson #undef C_O0_I4 3854c22e840SRichard Henderson #undef C_O1_I1 3864c22e840SRichard Henderson #undef C_O1_I2 3874c22e840SRichard Henderson #undef C_O1_I3 3884c22e840SRichard Henderson #undef C_O1_I4 3894c22e840SRichard Henderson #undef C_N1_I2 3904c22e840SRichard Henderson #undef C_O2_I1 3914c22e840SRichard Henderson #undef C_O2_I2 3924c22e840SRichard Henderson #undef C_O2_I3 3934c22e840SRichard Henderson #undef C_O2_I4 3944c22e840SRichard Henderson 3954c22e840SRichard Henderson /* Put all of the constraint sets into an array, indexed by the enum. */ 3964c22e840SRichard Henderson 3974c22e840SRichard Henderson #define C_O0_I1(I1) { .args_ct_str = { #I1 } }, 3984c22e840SRichard Henderson #define C_O0_I2(I1, I2) { .args_ct_str = { #I1, #I2 } }, 3994c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3) { .args_ct_str = { #I1, #I2, #I3 } }, 4004c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4) { .args_ct_str = { #I1, #I2, #I3, #I4 } }, 4014c22e840SRichard Henderson 4024c22e840SRichard Henderson #define C_O1_I1(O1, I1) { .args_ct_str = { #O1, #I1 } }, 4034c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2) { .args_ct_str = { #O1, #I1, #I2 } }, 4044c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3) { .args_ct_str = { #O1, #I1, #I2, #I3 } }, 4054c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4) { .args_ct_str = { #O1, #I1, #I2, #I3, #I4 } }, 4064c22e840SRichard Henderson 4074c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2) { .args_ct_str = { "&" #O1, #I1, #I2 } }, 4084c22e840SRichard Henderson 4094c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1) { .args_ct_str = { #O1, #O2, #I1 } }, 4104c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2) { .args_ct_str = { #O1, #O2, #I1, #I2 } }, 4114c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3) { .args_ct_str = { #O1, #O2, #I1, #I2, #I3 } }, 4124c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) { .args_ct_str = { #O1, #O2, #I1, #I2, #I3, #I4 } }, 4134c22e840SRichard Henderson 4144c22e840SRichard Henderson static const TCGTargetOpDef constraint_sets[] = { 4154c22e840SRichard Henderson #include "tcg-target-con-set.h" 4164c22e840SRichard Henderson }; 4174c22e840SRichard Henderson 4184c22e840SRichard Henderson 4194c22e840SRichard Henderson #undef C_O0_I1 4204c22e840SRichard Henderson #undef C_O0_I2 4214c22e840SRichard Henderson #undef C_O0_I3 4224c22e840SRichard Henderson #undef C_O0_I4 4234c22e840SRichard Henderson #undef C_O1_I1 4244c22e840SRichard Henderson #undef C_O1_I2 4254c22e840SRichard Henderson #undef C_O1_I3 4264c22e840SRichard Henderson #undef C_O1_I4 4274c22e840SRichard Henderson #undef C_N1_I2 4284c22e840SRichard Henderson #undef C_O2_I1 4294c22e840SRichard Henderson #undef C_O2_I2 4304c22e840SRichard Henderson #undef C_O2_I3 4314c22e840SRichard Henderson #undef C_O2_I4 4324c22e840SRichard Henderson 4334c22e840SRichard Henderson /* Expand the enumerator to be returned from tcg_target_op_def(). */ 4344c22e840SRichard Henderson 4354c22e840SRichard Henderson #define C_O0_I1(I1) C_PFX1(c_o0_i1_, I1) 4364c22e840SRichard Henderson #define C_O0_I2(I1, I2) C_PFX2(c_o0_i2_, I1, I2) 4374c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3) C_PFX3(c_o0_i3_, I1, I2, I3) 4384c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4) C_PFX4(c_o0_i4_, I1, I2, I3, I4) 4394c22e840SRichard Henderson 4404c22e840SRichard Henderson #define C_O1_I1(O1, I1) C_PFX2(c_o1_i1_, O1, I1) 4414c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2) C_PFX3(c_o1_i2_, O1, I1, I2) 4424c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3) C_PFX4(c_o1_i3_, O1, I1, I2, I3) 4434c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4) C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4) 4444c22e840SRichard Henderson 4454c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2) C_PFX3(c_n1_i2_, O1, I1, I2) 4464c22e840SRichard Henderson 4474c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1) C_PFX3(c_o2_i1_, O1, O2, I1) 4484c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2) C_PFX4(c_o2_i2_, O1, O2, I1, I2) 4494c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3) C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3) 4504c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4) 4514c22e840SRichard Henderson 452139c1837SPaolo Bonzini #include "tcg-target.c.inc" 453c896fe29Sbellard 45438b47b19SEmilio G. Cota static void alloc_tcg_plugin_context(TCGContext *s) 45538b47b19SEmilio G. Cota { 45638b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN 45738b47b19SEmilio G. Cota s->plugin_tb = g_new0(struct qemu_plugin_tb, 1); 45838b47b19SEmilio G. Cota s->plugin_tb->insns = 45938b47b19SEmilio G. Cota g_ptr_array_new_with_free_func(qemu_plugin_insn_cleanup_fn); 46038b47b19SEmilio G. Cota #endif 46138b47b19SEmilio G. Cota } 46238b47b19SEmilio G. Cota 463e8feb96fSEmilio G. Cota /* 4643468b59eSEmilio G. Cota * All TCG threads except the parent (i.e. the one that called tcg_context_init 4653468b59eSEmilio G. Cota * and registered the target's TCG globals) must register with this function 4663468b59eSEmilio G. Cota * before initiating translation. 4673468b59eSEmilio G. Cota * 4683468b59eSEmilio G. Cota * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation 4693468b59eSEmilio G. Cota * of tcg_region_init() for the reasoning behind this. 4703468b59eSEmilio G. Cota * 4713468b59eSEmilio G. Cota * In softmmu each caller registers its context in tcg_ctxs[]. Note that in 4723468b59eSEmilio G. Cota * softmmu tcg_ctxs[] does not track tcg_ctx_init, since the initial context 4733468b59eSEmilio G. Cota * is not used anymore for translation once this function is called. 4743468b59eSEmilio G. Cota * 4753468b59eSEmilio G. Cota * Not tracking tcg_init_ctx in tcg_ctxs[] in softmmu keeps code that iterates 4763468b59eSEmilio G. Cota * over the array (e.g. tcg_code_size() the same for both softmmu and user-mode. 4773468b59eSEmilio G. Cota */ 4783468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY 4793468b59eSEmilio G. Cota void tcg_register_thread(void) 4803468b59eSEmilio G. Cota { 4813468b59eSEmilio G. Cota tcg_ctx = &tcg_init_ctx; 4823468b59eSEmilio G. Cota } 4833468b59eSEmilio G. Cota #else 4843468b59eSEmilio G. Cota void tcg_register_thread(void) 4853468b59eSEmilio G. Cota { 4863468b59eSEmilio G. Cota TCGContext *s = g_malloc(sizeof(*s)); 4873468b59eSEmilio G. Cota unsigned int i, n; 4883468b59eSEmilio G. Cota 4893468b59eSEmilio G. Cota *s = tcg_init_ctx; 4903468b59eSEmilio G. Cota 4913468b59eSEmilio G. Cota /* Relink mem_base. */ 4923468b59eSEmilio G. Cota for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) { 4933468b59eSEmilio G. Cota if (tcg_init_ctx.temps[i].mem_base) { 4943468b59eSEmilio G. Cota ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps; 4953468b59eSEmilio G. Cota tcg_debug_assert(b >= 0 && b < n); 4963468b59eSEmilio G. Cota s->temps[i].mem_base = &s->temps[b]; 4973468b59eSEmilio G. Cota } 4983468b59eSEmilio G. Cota } 4993468b59eSEmilio G. Cota 5003468b59eSEmilio G. Cota /* Claim an entry in tcg_ctxs */ 5010e2d61cfSRichard Henderson n = qatomic_fetch_inc(&tcg_cur_ctxs); 5020e2d61cfSRichard Henderson g_assert(n < tcg_max_ctxs); 503d73415a3SStefan Hajnoczi qatomic_set(&tcg_ctxs[n], s); 5043468b59eSEmilio G. Cota 50538b47b19SEmilio G. Cota if (n > 0) { 50638b47b19SEmilio G. Cota alloc_tcg_plugin_context(s); 507bf042e8eSRichard Henderson tcg_region_initial_alloc(s); 50838b47b19SEmilio G. Cota } 50938b47b19SEmilio G. Cota 5103468b59eSEmilio G. Cota tcg_ctx = s; 5113468b59eSEmilio G. Cota } 5123468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */ 5133468b59eSEmilio G. Cota 514c896fe29Sbellard /* pool based memory allocation */ 515c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size) 516c896fe29Sbellard { 517c896fe29Sbellard TCGPool *p; 518c896fe29Sbellard int pool_size; 519c896fe29Sbellard 520c896fe29Sbellard if (size > TCG_POOL_CHUNK_SIZE) { 521c896fe29Sbellard /* big malloc: insert a new pool (XXX: could optimize) */ 5227267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + size); 523c896fe29Sbellard p->size = size; 5244055299eSKirill Batuzov p->next = s->pool_first_large; 5254055299eSKirill Batuzov s->pool_first_large = p; 5264055299eSKirill Batuzov return p->data; 527c896fe29Sbellard } else { 528c896fe29Sbellard p = s->pool_current; 529c896fe29Sbellard if (!p) { 530c896fe29Sbellard p = s->pool_first; 531c896fe29Sbellard if (!p) 532c896fe29Sbellard goto new_pool; 533c896fe29Sbellard } else { 534c896fe29Sbellard if (!p->next) { 535c896fe29Sbellard new_pool: 536c896fe29Sbellard pool_size = TCG_POOL_CHUNK_SIZE; 5377267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + pool_size); 538c896fe29Sbellard p->size = pool_size; 539c896fe29Sbellard p->next = NULL; 540a813e36fSRichard Henderson if (s->pool_current) { 541c896fe29Sbellard s->pool_current->next = p; 542a813e36fSRichard Henderson } else { 543c896fe29Sbellard s->pool_first = p; 544a813e36fSRichard Henderson } 545c896fe29Sbellard } else { 546c896fe29Sbellard p = p->next; 547c896fe29Sbellard } 548c896fe29Sbellard } 549c896fe29Sbellard } 550c896fe29Sbellard s->pool_current = p; 551c896fe29Sbellard s->pool_cur = p->data + size; 552c896fe29Sbellard s->pool_end = p->data + p->size; 553c896fe29Sbellard return p->data; 554c896fe29Sbellard } 555c896fe29Sbellard 556c896fe29Sbellard void tcg_pool_reset(TCGContext *s) 557c896fe29Sbellard { 5584055299eSKirill Batuzov TCGPool *p, *t; 5594055299eSKirill Batuzov for (p = s->pool_first_large; p; p = t) { 5604055299eSKirill Batuzov t = p->next; 5614055299eSKirill Batuzov g_free(p); 5624055299eSKirill Batuzov } 5634055299eSKirill Batuzov s->pool_first_large = NULL; 564c896fe29Sbellard s->pool_cur = s->pool_end = NULL; 565c896fe29Sbellard s->pool_current = NULL; 566c896fe29Sbellard } 567c896fe29Sbellard 5682ef6175aSRichard Henderson #include "exec/helper-proto.h" 5692ef6175aSRichard Henderson 57039004a71SRichard Henderson static TCGHelperInfo all_helpers[] = { 5712ef6175aSRichard Henderson #include "exec/helper-tcg.h" 572100b5e01SRichard Henderson }; 573619205fdSEmilio G. Cota static GHashTable *helper_table; 574100b5e01SRichard Henderson 57522f15579SRichard Henderson #ifdef CONFIG_TCG_INTERPRETER 576c6ef8c7bSPhilippe Mathieu-Daudé static ffi_type *typecode_to_ffi(int argmask) 577c6ef8c7bSPhilippe Mathieu-Daudé { 578e9709e17SRichard Henderson /* 579e9709e17SRichard Henderson * libffi does not support __int128_t, so we have forced Int128 580e9709e17SRichard Henderson * to use the structure definition instead of the builtin type. 581e9709e17SRichard Henderson */ 582e9709e17SRichard Henderson static ffi_type *ffi_type_i128_elements[3] = { 583e9709e17SRichard Henderson &ffi_type_uint64, 584e9709e17SRichard Henderson &ffi_type_uint64, 585e9709e17SRichard Henderson NULL 586e9709e17SRichard Henderson }; 587e9709e17SRichard Henderson static ffi_type ffi_type_i128 = { 588e9709e17SRichard Henderson .size = 16, 589e9709e17SRichard Henderson .alignment = __alignof__(Int128), 590e9709e17SRichard Henderson .type = FFI_TYPE_STRUCT, 591e9709e17SRichard Henderson .elements = ffi_type_i128_elements, 592e9709e17SRichard Henderson }; 593e9709e17SRichard Henderson 594c6ef8c7bSPhilippe Mathieu-Daudé switch (argmask) { 595c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_void: 596c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_void; 597c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_i32: 598c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_uint32; 599c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_s32: 600c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_sint32; 601c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_i64: 602c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_uint64; 603c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_s64: 604c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_sint64; 605c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_ptr: 606c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_pointer; 607e9709e17SRichard Henderson case dh_typecode_i128: 608e9709e17SRichard Henderson return &ffi_type_i128; 609c6ef8c7bSPhilippe Mathieu-Daudé } 610c6ef8c7bSPhilippe Mathieu-Daudé g_assert_not_reached(); 611c6ef8c7bSPhilippe Mathieu-Daudé } 6120c22e176SPhilippe Mathieu-Daudé 6130c22e176SPhilippe Mathieu-Daudé static void init_ffi_layouts(void) 6140c22e176SPhilippe Mathieu-Daudé { 6150c22e176SPhilippe Mathieu-Daudé /* g_direct_hash/equal for direct comparisons on uint32_t. */ 616f9c4bb80SRichard Henderson GHashTable *ffi_table = g_hash_table_new(NULL, NULL); 617f9c4bb80SRichard Henderson 6180c22e176SPhilippe Mathieu-Daudé for (int i = 0; i < ARRAY_SIZE(all_helpers); ++i) { 619f9c4bb80SRichard Henderson TCGHelperInfo *info = &all_helpers[i]; 620f9c4bb80SRichard Henderson unsigned typemask = info->typemask; 6210c22e176SPhilippe Mathieu-Daudé gpointer hash = (gpointer)(uintptr_t)typemask; 6220c22e176SPhilippe Mathieu-Daudé struct { 6230c22e176SPhilippe Mathieu-Daudé ffi_cif cif; 6240c22e176SPhilippe Mathieu-Daudé ffi_type *args[]; 6250c22e176SPhilippe Mathieu-Daudé } *ca; 6260c22e176SPhilippe Mathieu-Daudé ffi_status status; 6270c22e176SPhilippe Mathieu-Daudé int nargs; 628f9c4bb80SRichard Henderson ffi_cif *cif; 6290c22e176SPhilippe Mathieu-Daudé 630f9c4bb80SRichard Henderson cif = g_hash_table_lookup(ffi_table, hash); 631f9c4bb80SRichard Henderson if (cif) { 632f9c4bb80SRichard Henderson info->cif = cif; 6330c22e176SPhilippe Mathieu-Daudé continue; 6340c22e176SPhilippe Mathieu-Daudé } 6350c22e176SPhilippe Mathieu-Daudé 6360c22e176SPhilippe Mathieu-Daudé /* Ignoring the return type, find the last non-zero field. */ 6370c22e176SPhilippe Mathieu-Daudé nargs = 32 - clz32(typemask >> 3); 6380c22e176SPhilippe Mathieu-Daudé nargs = DIV_ROUND_UP(nargs, 3); 639e9709e17SRichard Henderson assert(nargs <= MAX_CALL_IARGS); 6400c22e176SPhilippe Mathieu-Daudé 6410c22e176SPhilippe Mathieu-Daudé ca = g_malloc0(sizeof(*ca) + nargs * sizeof(ffi_type *)); 6420c22e176SPhilippe Mathieu-Daudé ca->cif.rtype = typecode_to_ffi(typemask & 7); 6430c22e176SPhilippe Mathieu-Daudé ca->cif.nargs = nargs; 6440c22e176SPhilippe Mathieu-Daudé 6450c22e176SPhilippe Mathieu-Daudé if (nargs != 0) { 6460c22e176SPhilippe Mathieu-Daudé ca->cif.arg_types = ca->args; 6470c22e176SPhilippe Mathieu-Daudé for (int j = 0; j < nargs; ++j) { 6480c22e176SPhilippe Mathieu-Daudé int typecode = extract32(typemask, (j + 1) * 3, 3); 6490c22e176SPhilippe Mathieu-Daudé ca->args[j] = typecode_to_ffi(typecode); 6500c22e176SPhilippe Mathieu-Daudé } 6510c22e176SPhilippe Mathieu-Daudé } 6520c22e176SPhilippe Mathieu-Daudé 6530c22e176SPhilippe Mathieu-Daudé status = ffi_prep_cif(&ca->cif, FFI_DEFAULT_ABI, nargs, 6540c22e176SPhilippe Mathieu-Daudé ca->cif.rtype, ca->cif.arg_types); 6550c22e176SPhilippe Mathieu-Daudé assert(status == FFI_OK); 6560c22e176SPhilippe Mathieu-Daudé 657f9c4bb80SRichard Henderson cif = &ca->cif; 658f9c4bb80SRichard Henderson info->cif = cif; 659f9c4bb80SRichard Henderson g_hash_table_insert(ffi_table, hash, (gpointer)cif); 6600c22e176SPhilippe Mathieu-Daudé } 661f9c4bb80SRichard Henderson 662f9c4bb80SRichard Henderson g_hash_table_destroy(ffi_table); 6630c22e176SPhilippe Mathieu-Daudé } 6640c22e176SPhilippe Mathieu-Daudé #endif /* CONFIG_TCG_INTERPRETER */ 66522f15579SRichard Henderson 66639004a71SRichard Henderson typedef struct TCGCumulativeArgs { 66739004a71SRichard Henderson int arg_idx; /* tcg_gen_callN args[] */ 66839004a71SRichard Henderson int info_in_idx; /* TCGHelperInfo in[] */ 66939004a71SRichard Henderson int arg_slot; /* regs+stack slot */ 67039004a71SRichard Henderson int ref_slot; /* stack slots for references */ 67139004a71SRichard Henderson } TCGCumulativeArgs; 67239004a71SRichard Henderson 67339004a71SRichard Henderson static void layout_arg_even(TCGCumulativeArgs *cum) 67439004a71SRichard Henderson { 67539004a71SRichard Henderson cum->arg_slot += cum->arg_slot & 1; 67639004a71SRichard Henderson } 67739004a71SRichard Henderson 67839004a71SRichard Henderson static void layout_arg_1(TCGCumulativeArgs *cum, TCGHelperInfo *info, 67939004a71SRichard Henderson TCGCallArgumentKind kind) 68039004a71SRichard Henderson { 68139004a71SRichard Henderson TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx]; 68239004a71SRichard Henderson 68339004a71SRichard Henderson *loc = (TCGCallArgumentLoc){ 68439004a71SRichard Henderson .kind = kind, 68539004a71SRichard Henderson .arg_idx = cum->arg_idx, 68639004a71SRichard Henderson .arg_slot = cum->arg_slot, 68739004a71SRichard Henderson }; 68839004a71SRichard Henderson cum->info_in_idx++; 68939004a71SRichard Henderson cum->arg_slot++; 69039004a71SRichard Henderson } 69139004a71SRichard Henderson 69239004a71SRichard Henderson static void layout_arg_normal_n(TCGCumulativeArgs *cum, 69339004a71SRichard Henderson TCGHelperInfo *info, int n) 69439004a71SRichard Henderson { 69539004a71SRichard Henderson TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx]; 69639004a71SRichard Henderson 69739004a71SRichard Henderson for (int i = 0; i < n; ++i) { 69839004a71SRichard Henderson /* Layout all using the same arg_idx, adjusting the subindex. */ 69939004a71SRichard Henderson loc[i] = (TCGCallArgumentLoc){ 70039004a71SRichard Henderson .kind = TCG_CALL_ARG_NORMAL, 70139004a71SRichard Henderson .arg_idx = cum->arg_idx, 70239004a71SRichard Henderson .tmp_subindex = i, 70339004a71SRichard Henderson .arg_slot = cum->arg_slot + i, 70439004a71SRichard Henderson }; 70539004a71SRichard Henderson } 70639004a71SRichard Henderson cum->info_in_idx += n; 70739004a71SRichard Henderson cum->arg_slot += n; 70839004a71SRichard Henderson } 70939004a71SRichard Henderson 710313bdea8SRichard Henderson static void layout_arg_by_ref(TCGCumulativeArgs *cum, TCGHelperInfo *info) 711313bdea8SRichard Henderson { 712313bdea8SRichard Henderson TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx]; 713313bdea8SRichard Henderson int n = 128 / TCG_TARGET_REG_BITS; 714313bdea8SRichard Henderson 715313bdea8SRichard Henderson /* The first subindex carries the pointer. */ 716313bdea8SRichard Henderson layout_arg_1(cum, info, TCG_CALL_ARG_BY_REF); 717313bdea8SRichard Henderson 718313bdea8SRichard Henderson /* 719313bdea8SRichard Henderson * The callee is allowed to clobber memory associated with 720313bdea8SRichard Henderson * structure pass by-reference. Therefore we must make copies. 721313bdea8SRichard Henderson * Allocate space from "ref_slot", which will be adjusted to 722313bdea8SRichard Henderson * follow the parameters on the stack. 723313bdea8SRichard Henderson */ 724313bdea8SRichard Henderson loc[0].ref_slot = cum->ref_slot; 725313bdea8SRichard Henderson 726313bdea8SRichard Henderson /* 727313bdea8SRichard Henderson * Subsequent words also go into the reference slot, but 728313bdea8SRichard Henderson * do not accumulate into the regular arguments. 729313bdea8SRichard Henderson */ 730313bdea8SRichard Henderson for (int i = 1; i < n; ++i) { 731313bdea8SRichard Henderson loc[i] = (TCGCallArgumentLoc){ 732313bdea8SRichard Henderson .kind = TCG_CALL_ARG_BY_REF_N, 733313bdea8SRichard Henderson .arg_idx = cum->arg_idx, 734313bdea8SRichard Henderson .tmp_subindex = i, 735313bdea8SRichard Henderson .ref_slot = cum->ref_slot + i, 736313bdea8SRichard Henderson }; 737313bdea8SRichard Henderson } 738313bdea8SRichard Henderson cum->info_in_idx += n; 739313bdea8SRichard Henderson cum->ref_slot += n; 740313bdea8SRichard Henderson } 741313bdea8SRichard Henderson 74239004a71SRichard Henderson static void init_call_layout(TCGHelperInfo *info) 74339004a71SRichard Henderson { 74439004a71SRichard Henderson int max_reg_slots = ARRAY_SIZE(tcg_target_call_iarg_regs); 74539004a71SRichard Henderson int max_stk_slots = TCG_STATIC_CALL_ARGS_SIZE / sizeof(tcg_target_long); 74639004a71SRichard Henderson unsigned typemask = info->typemask; 74739004a71SRichard Henderson unsigned typecode; 74839004a71SRichard Henderson TCGCumulativeArgs cum = { }; 74939004a71SRichard Henderson 75039004a71SRichard Henderson /* 75139004a71SRichard Henderson * Parse and place any function return value. 75239004a71SRichard Henderson */ 75339004a71SRichard Henderson typecode = typemask & 7; 75439004a71SRichard Henderson switch (typecode) { 75539004a71SRichard Henderson case dh_typecode_void: 75639004a71SRichard Henderson info->nr_out = 0; 75739004a71SRichard Henderson break; 75839004a71SRichard Henderson case dh_typecode_i32: 75939004a71SRichard Henderson case dh_typecode_s32: 76039004a71SRichard Henderson case dh_typecode_ptr: 76139004a71SRichard Henderson info->nr_out = 1; 76239004a71SRichard Henderson info->out_kind = TCG_CALL_RET_NORMAL; 76339004a71SRichard Henderson break; 76439004a71SRichard Henderson case dh_typecode_i64: 76539004a71SRichard Henderson case dh_typecode_s64: 76639004a71SRichard Henderson info->nr_out = 64 / TCG_TARGET_REG_BITS; 76739004a71SRichard Henderson info->out_kind = TCG_CALL_RET_NORMAL; 7685e3d0c19SRichard Henderson /* Query the last register now to trigger any assert early. */ 7695e3d0c19SRichard Henderson tcg_target_call_oarg_reg(info->out_kind, info->nr_out - 1); 770466d3759SRichard Henderson break; 771466d3759SRichard Henderson case dh_typecode_i128: 772466d3759SRichard Henderson info->nr_out = 128 / TCG_TARGET_REG_BITS; 7735427a9a7SRichard Henderson info->out_kind = TCG_TARGET_CALL_RET_I128; 7745427a9a7SRichard Henderson switch (TCG_TARGET_CALL_RET_I128) { 775466d3759SRichard Henderson case TCG_CALL_RET_NORMAL: 7765e3d0c19SRichard Henderson /* Query the last register now to trigger any assert early. */ 7775e3d0c19SRichard Henderson tcg_target_call_oarg_reg(info->out_kind, info->nr_out - 1); 778466d3759SRichard Henderson break; 779c6556aa0SRichard Henderson case TCG_CALL_RET_BY_VEC: 780c6556aa0SRichard Henderson /* Query the single register now to trigger any assert early. */ 781c6556aa0SRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0); 782c6556aa0SRichard Henderson break; 783313bdea8SRichard Henderson case TCG_CALL_RET_BY_REF: 784313bdea8SRichard Henderson /* 785313bdea8SRichard Henderson * Allocate the first argument to the output. 786313bdea8SRichard Henderson * We don't need to store this anywhere, just make it 787313bdea8SRichard Henderson * unavailable for use in the input loop below. 788313bdea8SRichard Henderson */ 789313bdea8SRichard Henderson cum.arg_slot = 1; 790313bdea8SRichard Henderson break; 791466d3759SRichard Henderson default: 792466d3759SRichard Henderson qemu_build_not_reached(); 793466d3759SRichard Henderson } 79439004a71SRichard Henderson break; 79539004a71SRichard Henderson default: 79639004a71SRichard Henderson g_assert_not_reached(); 79739004a71SRichard Henderson } 79839004a71SRichard Henderson 79939004a71SRichard Henderson /* 80039004a71SRichard Henderson * Parse and place function arguments. 80139004a71SRichard Henderson */ 80239004a71SRichard Henderson for (typemask >>= 3; typemask; typemask >>= 3, cum.arg_idx++) { 80339004a71SRichard Henderson TCGCallArgumentKind kind; 80439004a71SRichard Henderson TCGType type; 80539004a71SRichard Henderson 80639004a71SRichard Henderson typecode = typemask & 7; 80739004a71SRichard Henderson switch (typecode) { 80839004a71SRichard Henderson case dh_typecode_i32: 80939004a71SRichard Henderson case dh_typecode_s32: 81039004a71SRichard Henderson type = TCG_TYPE_I32; 81139004a71SRichard Henderson break; 81239004a71SRichard Henderson case dh_typecode_i64: 81339004a71SRichard Henderson case dh_typecode_s64: 81439004a71SRichard Henderson type = TCG_TYPE_I64; 81539004a71SRichard Henderson break; 81639004a71SRichard Henderson case dh_typecode_ptr: 81739004a71SRichard Henderson type = TCG_TYPE_PTR; 81839004a71SRichard Henderson break; 819466d3759SRichard Henderson case dh_typecode_i128: 820466d3759SRichard Henderson type = TCG_TYPE_I128; 821466d3759SRichard Henderson break; 82239004a71SRichard Henderson default: 82339004a71SRichard Henderson g_assert_not_reached(); 82439004a71SRichard Henderson } 82539004a71SRichard Henderson 82639004a71SRichard Henderson switch (type) { 82739004a71SRichard Henderson case TCG_TYPE_I32: 82839004a71SRichard Henderson switch (TCG_TARGET_CALL_ARG_I32) { 82939004a71SRichard Henderson case TCG_CALL_ARG_EVEN: 83039004a71SRichard Henderson layout_arg_even(&cum); 83139004a71SRichard Henderson /* fall through */ 83239004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 83339004a71SRichard Henderson layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL); 83439004a71SRichard Henderson break; 83539004a71SRichard Henderson case TCG_CALL_ARG_EXTEND: 83639004a71SRichard Henderson kind = TCG_CALL_ARG_EXTEND_U + (typecode & 1); 83739004a71SRichard Henderson layout_arg_1(&cum, info, kind); 83839004a71SRichard Henderson break; 83939004a71SRichard Henderson default: 84039004a71SRichard Henderson qemu_build_not_reached(); 84139004a71SRichard Henderson } 84239004a71SRichard Henderson break; 84339004a71SRichard Henderson 84439004a71SRichard Henderson case TCG_TYPE_I64: 84539004a71SRichard Henderson switch (TCG_TARGET_CALL_ARG_I64) { 84639004a71SRichard Henderson case TCG_CALL_ARG_EVEN: 84739004a71SRichard Henderson layout_arg_even(&cum); 84839004a71SRichard Henderson /* fall through */ 84939004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 85039004a71SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 85139004a71SRichard Henderson layout_arg_normal_n(&cum, info, 2); 85239004a71SRichard Henderson } else { 85339004a71SRichard Henderson layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL); 85439004a71SRichard Henderson } 85539004a71SRichard Henderson break; 85639004a71SRichard Henderson default: 85739004a71SRichard Henderson qemu_build_not_reached(); 85839004a71SRichard Henderson } 85939004a71SRichard Henderson break; 86039004a71SRichard Henderson 861466d3759SRichard Henderson case TCG_TYPE_I128: 8625427a9a7SRichard Henderson switch (TCG_TARGET_CALL_ARG_I128) { 863466d3759SRichard Henderson case TCG_CALL_ARG_EVEN: 864466d3759SRichard Henderson layout_arg_even(&cum); 865466d3759SRichard Henderson /* fall through */ 866466d3759SRichard Henderson case TCG_CALL_ARG_NORMAL: 867466d3759SRichard Henderson layout_arg_normal_n(&cum, info, 128 / TCG_TARGET_REG_BITS); 868466d3759SRichard Henderson break; 869313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF: 870313bdea8SRichard Henderson layout_arg_by_ref(&cum, info); 871313bdea8SRichard Henderson break; 872466d3759SRichard Henderson default: 873466d3759SRichard Henderson qemu_build_not_reached(); 874466d3759SRichard Henderson } 875466d3759SRichard Henderson break; 876466d3759SRichard Henderson 87739004a71SRichard Henderson default: 87839004a71SRichard Henderson g_assert_not_reached(); 87939004a71SRichard Henderson } 88039004a71SRichard Henderson } 88139004a71SRichard Henderson info->nr_in = cum.info_in_idx; 88239004a71SRichard Henderson 88339004a71SRichard Henderson /* Validate that we didn't overrun the input array. */ 88439004a71SRichard Henderson assert(cum.info_in_idx <= ARRAY_SIZE(info->in)); 88539004a71SRichard Henderson /* Validate the backend has enough argument space. */ 88639004a71SRichard Henderson assert(cum.arg_slot <= max_reg_slots + max_stk_slots); 887313bdea8SRichard Henderson 888313bdea8SRichard Henderson /* 889313bdea8SRichard Henderson * Relocate the "ref_slot" area to the end of the parameters. 890313bdea8SRichard Henderson * Minimizing this stack offset helps code size for x86, 891313bdea8SRichard Henderson * which has a signed 8-bit offset encoding. 892313bdea8SRichard Henderson */ 893313bdea8SRichard Henderson if (cum.ref_slot != 0) { 894313bdea8SRichard Henderson int ref_base = 0; 895313bdea8SRichard Henderson 896313bdea8SRichard Henderson if (cum.arg_slot > max_reg_slots) { 897313bdea8SRichard Henderson int align = __alignof(Int128) / sizeof(tcg_target_long); 898313bdea8SRichard Henderson 899313bdea8SRichard Henderson ref_base = cum.arg_slot - max_reg_slots; 900313bdea8SRichard Henderson if (align > 1) { 901313bdea8SRichard Henderson ref_base = ROUND_UP(ref_base, align); 902313bdea8SRichard Henderson } 903313bdea8SRichard Henderson } 904313bdea8SRichard Henderson assert(ref_base + cum.ref_slot <= max_stk_slots); 905313bdea8SRichard Henderson 906313bdea8SRichard Henderson if (ref_base != 0) { 907313bdea8SRichard Henderson for (int i = cum.info_in_idx - 1; i >= 0; --i) { 908313bdea8SRichard Henderson TCGCallArgumentLoc *loc = &info->in[i]; 909313bdea8SRichard Henderson switch (loc->kind) { 910313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF: 911313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF_N: 912313bdea8SRichard Henderson loc->ref_slot += ref_base; 913313bdea8SRichard Henderson break; 914313bdea8SRichard Henderson default: 915313bdea8SRichard Henderson break; 916313bdea8SRichard Henderson } 917313bdea8SRichard Henderson } 918313bdea8SRichard Henderson } 919313bdea8SRichard Henderson } 92039004a71SRichard Henderson } 92139004a71SRichard Henderson 92291478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)]; 923f69d277eSRichard Henderson static void process_op_defs(TCGContext *s); 9241c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type, 9251c2adb95SRichard Henderson TCGReg reg, const char *name); 92691478cefSRichard Henderson 92743b972b7SRichard Henderson static void tcg_context_init(unsigned max_cpus) 928c896fe29Sbellard { 929a76aabd3SRichard Henderson TCGContext *s = &tcg_init_ctx; 930100b5e01SRichard Henderson int op, total_args, n, i; 931c896fe29Sbellard TCGOpDef *def; 932c896fe29Sbellard TCGArgConstraint *args_ct; 9331c2adb95SRichard Henderson TCGTemp *ts; 934c896fe29Sbellard 935c896fe29Sbellard memset(s, 0, sizeof(*s)); 936c896fe29Sbellard s->nb_globals = 0; 937c896fe29Sbellard 938c896fe29Sbellard /* Count total number of arguments and allocate the corresponding 939c896fe29Sbellard space */ 940c896fe29Sbellard total_args = 0; 941c896fe29Sbellard for(op = 0; op < NB_OPS; op++) { 942c896fe29Sbellard def = &tcg_op_defs[op]; 943c896fe29Sbellard n = def->nb_iargs + def->nb_oargs; 944c896fe29Sbellard total_args += n; 945c896fe29Sbellard } 946c896fe29Sbellard 947bc2b17e6SRichard Henderson args_ct = g_new0(TCGArgConstraint, total_args); 948c896fe29Sbellard 949c896fe29Sbellard for(op = 0; op < NB_OPS; op++) { 950c896fe29Sbellard def = &tcg_op_defs[op]; 951c896fe29Sbellard def->args_ct = args_ct; 952c896fe29Sbellard n = def->nb_iargs + def->nb_oargs; 953c896fe29Sbellard args_ct += n; 954c896fe29Sbellard } 955c896fe29Sbellard 9565cd8f621SRichard Henderson /* Register helpers. */ 95784fd9dd3SRichard Henderson /* Use g_direct_hash/equal for direct pointer comparisons on func. */ 958619205fdSEmilio G. Cota helper_table = g_hash_table_new(NULL, NULL); 95984fd9dd3SRichard Henderson 960100b5e01SRichard Henderson for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) { 96139004a71SRichard Henderson init_call_layout(&all_helpers[i]); 96284fd9dd3SRichard Henderson g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func, 96372866e82SRichard Henderson (gpointer)&all_helpers[i]); 964100b5e01SRichard Henderson } 9655cd8f621SRichard Henderson 96622f15579SRichard Henderson #ifdef CONFIG_TCG_INTERPRETER 9670c22e176SPhilippe Mathieu-Daudé init_ffi_layouts(); 96822f15579SRichard Henderson #endif 96922f15579SRichard Henderson 970c896fe29Sbellard tcg_target_init(s); 971f69d277eSRichard Henderson process_op_defs(s); 97291478cefSRichard Henderson 97391478cefSRichard Henderson /* Reverse the order of the saved registers, assuming they're all at 97491478cefSRichard Henderson the start of tcg_target_reg_alloc_order. */ 97591478cefSRichard Henderson for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) { 97691478cefSRichard Henderson int r = tcg_target_reg_alloc_order[n]; 97791478cefSRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) { 97891478cefSRichard Henderson break; 97991478cefSRichard Henderson } 98091478cefSRichard Henderson } 98191478cefSRichard Henderson for (i = 0; i < n; ++i) { 98291478cefSRichard Henderson indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i]; 98391478cefSRichard Henderson } 98491478cefSRichard Henderson for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) { 98591478cefSRichard Henderson indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i]; 98691478cefSRichard Henderson } 987b1311c4aSEmilio G. Cota 98838b47b19SEmilio G. Cota alloc_tcg_plugin_context(s); 98938b47b19SEmilio G. Cota 990b1311c4aSEmilio G. Cota tcg_ctx = s; 9913468b59eSEmilio G. Cota /* 9923468b59eSEmilio G. Cota * In user-mode we simply share the init context among threads, since we 9933468b59eSEmilio G. Cota * use a single region. See the documentation tcg_region_init() for the 9943468b59eSEmilio G. Cota * reasoning behind this. 9953468b59eSEmilio G. Cota * In softmmu we will have at most max_cpus TCG threads. 9963468b59eSEmilio G. Cota */ 9973468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY 998df2cce29SEmilio G. Cota tcg_ctxs = &tcg_ctx; 9990e2d61cfSRichard Henderson tcg_cur_ctxs = 1; 10000e2d61cfSRichard Henderson tcg_max_ctxs = 1; 10013468b59eSEmilio G. Cota #else 10020e2d61cfSRichard Henderson tcg_max_ctxs = max_cpus; 10030e2d61cfSRichard Henderson tcg_ctxs = g_new0(TCGContext *, max_cpus); 10043468b59eSEmilio G. Cota #endif 10051c2adb95SRichard Henderson 10061c2adb95SRichard Henderson tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0)); 10071c2adb95SRichard Henderson ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env"); 10081c2adb95SRichard Henderson cpu_env = temp_tcgv_ptr(ts); 10099002ec79SRichard Henderson } 1010b03cce8eSbellard 101143b972b7SRichard Henderson void tcg_init(size_t tb_size, int splitwx, unsigned max_cpus) 1012a76aabd3SRichard Henderson { 101343b972b7SRichard Henderson tcg_context_init(max_cpus); 101443b972b7SRichard Henderson tcg_region_init(tb_size, splitwx, max_cpus); 1015a76aabd3SRichard Henderson } 1016a76aabd3SRichard Henderson 10176e3b2bfdSEmilio G. Cota /* 10186e3b2bfdSEmilio G. Cota * Allocate TBs right before their corresponding translated code, making 10196e3b2bfdSEmilio G. Cota * sure that TBs and code are on different cache lines. 10206e3b2bfdSEmilio G. Cota */ 10216e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s) 10226e3b2bfdSEmilio G. Cota { 10236e3b2bfdSEmilio G. Cota uintptr_t align = qemu_icache_linesize; 10246e3b2bfdSEmilio G. Cota TranslationBlock *tb; 10256e3b2bfdSEmilio G. Cota void *next; 10266e3b2bfdSEmilio G. Cota 1027e8feb96fSEmilio G. Cota retry: 10286e3b2bfdSEmilio G. Cota tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align); 10296e3b2bfdSEmilio G. Cota next = (void *)ROUND_UP((uintptr_t)(tb + 1), align); 10306e3b2bfdSEmilio G. Cota 10316e3b2bfdSEmilio G. Cota if (unlikely(next > s->code_gen_highwater)) { 1032e8feb96fSEmilio G. Cota if (tcg_region_alloc(s)) { 10336e3b2bfdSEmilio G. Cota return NULL; 10346e3b2bfdSEmilio G. Cota } 1035e8feb96fSEmilio G. Cota goto retry; 1036e8feb96fSEmilio G. Cota } 1037d73415a3SStefan Hajnoczi qatomic_set(&s->code_gen_ptr, next); 103857a26946SRichard Henderson s->data_gen_ptr = NULL; 10396e3b2bfdSEmilio G. Cota return tb; 10406e3b2bfdSEmilio G. Cota } 10416e3b2bfdSEmilio G. Cota 10429002ec79SRichard Henderson void tcg_prologue_init(TCGContext *s) 10439002ec79SRichard Henderson { 1044b0a0794aSRichard Henderson size_t prologue_size; 10458163b749SRichard Henderson 1046b0a0794aSRichard Henderson s->code_ptr = s->code_gen_ptr; 1047b0a0794aSRichard Henderson s->code_buf = s->code_gen_ptr; 10485b38ee31SRichard Henderson s->data_gen_ptr = NULL; 1049b91ccb31SRichard Henderson 1050b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 1051b0a0794aSRichard Henderson tcg_qemu_tb_exec = (tcg_prologue_fn *)tcg_splitwx_to_rx(s->code_ptr); 1052b91ccb31SRichard Henderson #endif 10538163b749SRichard Henderson 10545b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 10555b38ee31SRichard Henderson s->pool_labels = NULL; 10565b38ee31SRichard Henderson #endif 10575b38ee31SRichard Henderson 1058653b87ebSRoman Bolshakov qemu_thread_jit_write(); 10598163b749SRichard Henderson /* Generate the prologue. */ 1060b03cce8eSbellard tcg_target_qemu_prologue(s); 10615b38ee31SRichard Henderson 10625b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 10635b38ee31SRichard Henderson /* Allow the prologue to put e.g. guest_base into a pool entry. */ 10645b38ee31SRichard Henderson { 10651768987bSRichard Henderson int result = tcg_out_pool_finalize(s); 10661768987bSRichard Henderson tcg_debug_assert(result == 0); 10675b38ee31SRichard Henderson } 10685b38ee31SRichard Henderson #endif 10695b38ee31SRichard Henderson 1070b0a0794aSRichard Henderson prologue_size = tcg_current_code_size(s); 10715584e2dbSIlya Leoshkevich perf_report_prologue(s->code_gen_ptr, prologue_size); 1072b0a0794aSRichard Henderson 1073df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 1074b0a0794aSRichard Henderson flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf), 1075b0a0794aSRichard Henderson (uintptr_t)s->code_buf, prologue_size); 1076df5d2b16SRichard Henderson #endif 10778163b749SRichard Henderson 1078d6b64b2bSRichard Henderson #ifdef DEBUG_DISAS 1079d6b64b2bSRichard Henderson if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) { 1080c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock(); 108178b54858SRichard Henderson if (logfile) { 108278b54858SRichard Henderson fprintf(logfile, "PROLOGUE: [size=%zu]\n", prologue_size); 10835b38ee31SRichard Henderson if (s->data_gen_ptr) { 1084b0a0794aSRichard Henderson size_t code_size = s->data_gen_ptr - s->code_gen_ptr; 10855b38ee31SRichard Henderson size_t data_size = prologue_size - code_size; 10865b38ee31SRichard Henderson size_t i; 10875b38ee31SRichard Henderson 108878b54858SRichard Henderson disas(logfile, s->code_gen_ptr, code_size); 10895b38ee31SRichard Henderson 10905b38ee31SRichard Henderson for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) { 10915b38ee31SRichard Henderson if (sizeof(tcg_target_ulong) == 8) { 109278b54858SRichard Henderson fprintf(logfile, 109378b54858SRichard Henderson "0x%08" PRIxPTR ": .quad 0x%016" PRIx64 "\n", 10945b38ee31SRichard Henderson (uintptr_t)s->data_gen_ptr + i, 10955b38ee31SRichard Henderson *(uint64_t *)(s->data_gen_ptr + i)); 10965b38ee31SRichard Henderson } else { 109778b54858SRichard Henderson fprintf(logfile, 109878b54858SRichard Henderson "0x%08" PRIxPTR ": .long 0x%08x\n", 10995b38ee31SRichard Henderson (uintptr_t)s->data_gen_ptr + i, 11005b38ee31SRichard Henderson *(uint32_t *)(s->data_gen_ptr + i)); 11015b38ee31SRichard Henderson } 11025b38ee31SRichard Henderson } 11035b38ee31SRichard Henderson } else { 110478b54858SRichard Henderson disas(logfile, s->code_gen_ptr, prologue_size); 11055b38ee31SRichard Henderson } 110678b54858SRichard Henderson fprintf(logfile, "\n"); 1107fc59d2d8SRobert Foley qemu_log_unlock(logfile); 1108d6b64b2bSRichard Henderson } 110978b54858SRichard Henderson } 1110d6b64b2bSRichard Henderson #endif 1111cedbcb01SEmilio G. Cota 11126eea0434SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 11136eea0434SRichard Henderson /* 11146eea0434SRichard Henderson * Assert that goto_ptr is implemented completely, setting an epilogue. 11156eea0434SRichard Henderson * For tci, we use NULL as the signal to return from the interpreter, 11166eea0434SRichard Henderson * so skip this check. 11176eea0434SRichard Henderson */ 11188b5c2b62SRichard Henderson tcg_debug_assert(tcg_code_gen_epilogue != NULL); 11196eea0434SRichard Henderson #endif 1120d1c74ab3SRichard Henderson 1121d1c74ab3SRichard Henderson tcg_region_prologue_set(s); 1122c896fe29Sbellard } 1123c896fe29Sbellard 1124c896fe29Sbellard void tcg_func_start(TCGContext *s) 1125c896fe29Sbellard { 1126c896fe29Sbellard tcg_pool_reset(s); 1127c896fe29Sbellard s->nb_temps = s->nb_globals; 11280ec9eabcSRichard Henderson 11290ec9eabcSRichard Henderson /* No temps have been previously allocated for size or locality. */ 11300ec9eabcSRichard Henderson memset(s->free_temps, 0, sizeof(s->free_temps)); 11310ec9eabcSRichard Henderson 1132c0522136SRichard Henderson /* No constant temps have been previously allocated. */ 1133c0522136SRichard Henderson for (int i = 0; i < TCG_TYPE_COUNT; ++i) { 1134c0522136SRichard Henderson if (s->const_table[i]) { 1135c0522136SRichard Henderson g_hash_table_remove_all(s->const_table[i]); 1136c0522136SRichard Henderson } 1137c0522136SRichard Henderson } 1138c0522136SRichard Henderson 1139abebf925SRichard Henderson s->nb_ops = 0; 1140c896fe29Sbellard s->nb_labels = 0; 1141c896fe29Sbellard s->current_frame_offset = s->frame_start; 1142c896fe29Sbellard 11430a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG 11440a209d4bSRichard Henderson s->goto_tb_issue_mask = 0; 11450a209d4bSRichard Henderson #endif 11460a209d4bSRichard Henderson 114715fa08f8SRichard Henderson QTAILQ_INIT(&s->ops); 114815fa08f8SRichard Henderson QTAILQ_INIT(&s->free_ops); 1149bef16ab4SRichard Henderson QSIMPLEQ_INIT(&s->labels); 1150c896fe29Sbellard } 1151c896fe29Sbellard 1152ae30e866SRichard Henderson static TCGTemp *tcg_temp_alloc(TCGContext *s) 11537ca4b752SRichard Henderson { 11547ca4b752SRichard Henderson int n = s->nb_temps++; 1155ae30e866SRichard Henderson 1156ae30e866SRichard Henderson if (n >= TCG_MAX_TEMPS) { 1157db6b7d0cSRichard Henderson tcg_raise_tb_overflow(s); 1158ae30e866SRichard Henderson } 11597ca4b752SRichard Henderson return memset(&s->temps[n], 0, sizeof(TCGTemp)); 11607ca4b752SRichard Henderson } 11617ca4b752SRichard Henderson 1162ae30e866SRichard Henderson static TCGTemp *tcg_global_alloc(TCGContext *s) 11637ca4b752SRichard Henderson { 1164fa477d25SRichard Henderson TCGTemp *ts; 1165fa477d25SRichard Henderson 11667ca4b752SRichard Henderson tcg_debug_assert(s->nb_globals == s->nb_temps); 1167ae30e866SRichard Henderson tcg_debug_assert(s->nb_globals < TCG_MAX_TEMPS); 11687ca4b752SRichard Henderson s->nb_globals++; 1169fa477d25SRichard Henderson ts = tcg_temp_alloc(s); 1170ee17db83SRichard Henderson ts->kind = TEMP_GLOBAL; 1171fa477d25SRichard Henderson 1172fa477d25SRichard Henderson return ts; 1173c896fe29Sbellard } 1174c896fe29Sbellard 1175085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type, 1176b6638662SRichard Henderson TCGReg reg, const char *name) 1177c896fe29Sbellard { 1178c896fe29Sbellard TCGTemp *ts; 1179c896fe29Sbellard 11801a057554SRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 64 || type == TCG_TYPE_I32); 11817ca4b752SRichard Henderson 11827ca4b752SRichard Henderson ts = tcg_global_alloc(s); 1183c896fe29Sbellard ts->base_type = type; 1184c896fe29Sbellard ts->type = type; 1185ee17db83SRichard Henderson ts->kind = TEMP_FIXED; 1186c896fe29Sbellard ts->reg = reg; 1187c896fe29Sbellard ts->name = name; 1188c896fe29Sbellard tcg_regset_set_reg(s->reserved_regs, reg); 11897ca4b752SRichard Henderson 1190085272b3SRichard Henderson return ts; 1191a7812ae4Spbrook } 1192a7812ae4Spbrook 1193b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size) 1194a7812ae4Spbrook { 1195b3a62939SRichard Henderson s->frame_start = start; 1196b3a62939SRichard Henderson s->frame_end = start + size; 1197085272b3SRichard Henderson s->frame_temp 1198085272b3SRichard Henderson = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame"); 1199b3a62939SRichard Henderson } 1200a7812ae4Spbrook 1201085272b3SRichard Henderson TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base, 1202e1ccc054SRichard Henderson intptr_t offset, const char *name) 1203c896fe29Sbellard { 1204b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1205dc41aa7dSRichard Henderson TCGTemp *base_ts = tcgv_ptr_temp(base); 12067ca4b752SRichard Henderson TCGTemp *ts = tcg_global_alloc(s); 1207aef85402SRichard Henderson int indirect_reg = 0; 1208c896fe29Sbellard 1209c0522136SRichard Henderson switch (base_ts->kind) { 1210c0522136SRichard Henderson case TEMP_FIXED: 1211c0522136SRichard Henderson break; 1212c0522136SRichard Henderson case TEMP_GLOBAL: 12135a18407fSRichard Henderson /* We do not support double-indirect registers. */ 12145a18407fSRichard Henderson tcg_debug_assert(!base_ts->indirect_reg); 1215b3915dbbSRichard Henderson base_ts->indirect_base = 1; 12165a18407fSRichard Henderson s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64 12175a18407fSRichard Henderson ? 2 : 1); 12185a18407fSRichard Henderson indirect_reg = 1; 1219c0522136SRichard Henderson break; 1220c0522136SRichard Henderson default: 1221c0522136SRichard Henderson g_assert_not_reached(); 1222b3915dbbSRichard Henderson } 1223b3915dbbSRichard Henderson 12247ca4b752SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { 12257ca4b752SRichard Henderson TCGTemp *ts2 = tcg_global_alloc(s); 1226c896fe29Sbellard char buf[64]; 12277ca4b752SRichard Henderson 12287ca4b752SRichard Henderson ts->base_type = TCG_TYPE_I64; 1229c896fe29Sbellard ts->type = TCG_TYPE_I32; 1230b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg; 1231c896fe29Sbellard ts->mem_allocated = 1; 1232b3a62939SRichard Henderson ts->mem_base = base_ts; 1233aef85402SRichard Henderson ts->mem_offset = offset; 1234c896fe29Sbellard pstrcpy(buf, sizeof(buf), name); 1235c896fe29Sbellard pstrcat(buf, sizeof(buf), "_0"); 1236c896fe29Sbellard ts->name = strdup(buf); 1237c896fe29Sbellard 12387ca4b752SRichard Henderson tcg_debug_assert(ts2 == ts + 1); 12397ca4b752SRichard Henderson ts2->base_type = TCG_TYPE_I64; 12407ca4b752SRichard Henderson ts2->type = TCG_TYPE_I32; 1241b3915dbbSRichard Henderson ts2->indirect_reg = indirect_reg; 12427ca4b752SRichard Henderson ts2->mem_allocated = 1; 12437ca4b752SRichard Henderson ts2->mem_base = base_ts; 1244aef85402SRichard Henderson ts2->mem_offset = offset + 4; 1245fac87bd2SRichard Henderson ts2->temp_subindex = 1; 1246c896fe29Sbellard pstrcpy(buf, sizeof(buf), name); 1247c896fe29Sbellard pstrcat(buf, sizeof(buf), "_1"); 1248120c1084SRichard Henderson ts2->name = strdup(buf); 12497ca4b752SRichard Henderson } else { 1250c896fe29Sbellard ts->base_type = type; 1251c896fe29Sbellard ts->type = type; 1252b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg; 1253c896fe29Sbellard ts->mem_allocated = 1; 1254b3a62939SRichard Henderson ts->mem_base = base_ts; 1255c896fe29Sbellard ts->mem_offset = offset; 1256c896fe29Sbellard ts->name = name; 1257c896fe29Sbellard } 1258085272b3SRichard Henderson return ts; 1259c896fe29Sbellard } 1260c896fe29Sbellard 1261bbf989bfSRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, TCGTempKind kind) 1262c896fe29Sbellard { 1263b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1264c896fe29Sbellard TCGTemp *ts; 1265e1c08b00SRichard Henderson int n; 1266c896fe29Sbellard 1267e1c08b00SRichard Henderson if (kind == TEMP_EBB) { 1268e1c08b00SRichard Henderson int idx = find_first_bit(s->free_temps[type].l, TCG_MAX_TEMPS); 1269e1c08b00SRichard Henderson 12700ec9eabcSRichard Henderson if (idx < TCG_MAX_TEMPS) { 12710ec9eabcSRichard Henderson /* There is already an available temp with the right type. */ 1272e1c08b00SRichard Henderson clear_bit(idx, s->free_temps[type].l); 12730ec9eabcSRichard Henderson 1274e8996ee0Sbellard ts = &s->temps[idx]; 1275e8996ee0Sbellard ts->temp_allocated = 1; 12767ca4b752SRichard Henderson tcg_debug_assert(ts->base_type == type); 1277ee17db83SRichard Henderson tcg_debug_assert(ts->kind == kind); 12782f2e911dSRichard Henderson return ts; 1279e1c08b00SRichard Henderson } 1280e8996ee0Sbellard } else { 1281e1c08b00SRichard Henderson tcg_debug_assert(kind == TEMP_TB); 1282e1c08b00SRichard Henderson } 128343eef72fSRichard Henderson 128443eef72fSRichard Henderson switch (type) { 128543eef72fSRichard Henderson case TCG_TYPE_I32: 128643eef72fSRichard Henderson case TCG_TYPE_V64: 128743eef72fSRichard Henderson case TCG_TYPE_V128: 128843eef72fSRichard Henderson case TCG_TYPE_V256: 128943eef72fSRichard Henderson n = 1; 129043eef72fSRichard Henderson break; 129143eef72fSRichard Henderson case TCG_TYPE_I64: 129243eef72fSRichard Henderson n = 64 / TCG_TARGET_REG_BITS; 129343eef72fSRichard Henderson break; 129443eef72fSRichard Henderson case TCG_TYPE_I128: 129543eef72fSRichard Henderson n = 128 / TCG_TARGET_REG_BITS; 129643eef72fSRichard Henderson break; 129743eef72fSRichard Henderson default: 129843eef72fSRichard Henderson g_assert_not_reached(); 129943eef72fSRichard Henderson } 130043eef72fSRichard Henderson 13017ca4b752SRichard Henderson ts = tcg_temp_alloc(s); 130243eef72fSRichard Henderson ts->base_type = type; 130343eef72fSRichard Henderson ts->temp_allocated = 1; 130443eef72fSRichard Henderson ts->kind = kind; 130543eef72fSRichard Henderson 130643eef72fSRichard Henderson if (n == 1) { 130743eef72fSRichard Henderson ts->type = type; 130843eef72fSRichard Henderson } else { 130943eef72fSRichard Henderson ts->type = TCG_TYPE_REG; 131043eef72fSRichard Henderson 1311e1c08b00SRichard Henderson for (int i = 1; i < n; ++i) { 13127ca4b752SRichard Henderson TCGTemp *ts2 = tcg_temp_alloc(s); 13137ca4b752SRichard Henderson 131443eef72fSRichard Henderson tcg_debug_assert(ts2 == ts + i); 131543eef72fSRichard Henderson ts2->base_type = type; 131643eef72fSRichard Henderson ts2->type = TCG_TYPE_REG; 13177ca4b752SRichard Henderson ts2->temp_allocated = 1; 131843eef72fSRichard Henderson ts2->temp_subindex = i; 1319ee17db83SRichard Henderson ts2->kind = kind; 132043eef72fSRichard Henderson } 1321c896fe29Sbellard } 1322085272b3SRichard Henderson return ts; 1323c896fe29Sbellard } 1324c896fe29Sbellard 1325d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type) 1326d2fd745fSRichard Henderson { 1327d2fd745fSRichard Henderson TCGTemp *t; 1328d2fd745fSRichard Henderson 1329d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG 1330d2fd745fSRichard Henderson switch (type) { 1331d2fd745fSRichard Henderson case TCG_TYPE_V64: 1332d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v64); 1333d2fd745fSRichard Henderson break; 1334d2fd745fSRichard Henderson case TCG_TYPE_V128: 1335d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v128); 1336d2fd745fSRichard Henderson break; 1337d2fd745fSRichard Henderson case TCG_TYPE_V256: 1338d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v256); 1339d2fd745fSRichard Henderson break; 1340d2fd745fSRichard Henderson default: 1341d2fd745fSRichard Henderson g_assert_not_reached(); 1342d2fd745fSRichard Henderson } 1343d2fd745fSRichard Henderson #endif 1344d2fd745fSRichard Henderson 1345bbf989bfSRichard Henderson t = tcg_temp_new_internal(type, TEMP_EBB); 1346d2fd745fSRichard Henderson return temp_tcgv_vec(t); 1347d2fd745fSRichard Henderson } 1348d2fd745fSRichard Henderson 1349d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp. */ 1350d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match) 1351d2fd745fSRichard Henderson { 1352d2fd745fSRichard Henderson TCGTemp *t = tcgv_vec_temp(match); 1353d2fd745fSRichard Henderson 1354d2fd745fSRichard Henderson tcg_debug_assert(t->temp_allocated != 0); 1355d2fd745fSRichard Henderson 1356bbf989bfSRichard Henderson t = tcg_temp_new_internal(t->base_type, TEMP_EBB); 1357d2fd745fSRichard Henderson return temp_tcgv_vec(t); 1358d2fd745fSRichard Henderson } 1359d2fd745fSRichard Henderson 13605bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts) 1361c896fe29Sbellard { 1362b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1363c896fe29Sbellard 1364c7482438SRichard Henderson switch (ts->kind) { 1365c7482438SRichard Henderson case TEMP_CONST: 1366f57c6915SRichard Henderson case TEMP_TB: 13672f2e911dSRichard Henderson /* Silently ignore free. */ 1368c7482438SRichard Henderson break; 13692f2e911dSRichard Henderson case TEMP_EBB: 1370eabb7b91SAurelien Jarno tcg_debug_assert(ts->temp_allocated != 0); 1371e8996ee0Sbellard ts->temp_allocated = 0; 13722f2e911dSRichard Henderson set_bit(temp_idx(ts), s->free_temps[ts->base_type].l); 13732f2e911dSRichard Henderson break; 13742f2e911dSRichard Henderson default: 13752f2e911dSRichard Henderson /* It never made sense to free TEMP_FIXED or TEMP_GLOBAL. */ 13762f2e911dSRichard Henderson g_assert_not_reached(); 1377e1c08b00SRichard Henderson } 1378e8996ee0Sbellard } 1379e8996ee0Sbellard 1380c0522136SRichard Henderson TCGTemp *tcg_constant_internal(TCGType type, int64_t val) 1381c0522136SRichard Henderson { 1382c0522136SRichard Henderson TCGContext *s = tcg_ctx; 1383c0522136SRichard Henderson GHashTable *h = s->const_table[type]; 1384c0522136SRichard Henderson TCGTemp *ts; 1385c0522136SRichard Henderson 1386c0522136SRichard Henderson if (h == NULL) { 1387c0522136SRichard Henderson h = g_hash_table_new(g_int64_hash, g_int64_equal); 1388c0522136SRichard Henderson s->const_table[type] = h; 1389c0522136SRichard Henderson } 1390c0522136SRichard Henderson 1391c0522136SRichard Henderson ts = g_hash_table_lookup(h, &val); 1392c0522136SRichard Henderson if (ts == NULL) { 1393aef85402SRichard Henderson int64_t *val_ptr; 1394aef85402SRichard Henderson 1395c0522136SRichard Henderson ts = tcg_temp_alloc(s); 1396c0522136SRichard Henderson 1397c0522136SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { 1398c0522136SRichard Henderson TCGTemp *ts2 = tcg_temp_alloc(s); 1399c0522136SRichard Henderson 1400aef85402SRichard Henderson tcg_debug_assert(ts2 == ts + 1); 1401aef85402SRichard Henderson 1402c0522136SRichard Henderson ts->base_type = TCG_TYPE_I64; 1403c0522136SRichard Henderson ts->type = TCG_TYPE_I32; 1404c0522136SRichard Henderson ts->kind = TEMP_CONST; 1405c0522136SRichard Henderson ts->temp_allocated = 1; 1406c0522136SRichard Henderson 1407c0522136SRichard Henderson ts2->base_type = TCG_TYPE_I64; 1408c0522136SRichard Henderson ts2->type = TCG_TYPE_I32; 1409c0522136SRichard Henderson ts2->kind = TEMP_CONST; 1410c0522136SRichard Henderson ts2->temp_allocated = 1; 1411fac87bd2SRichard Henderson ts2->temp_subindex = 1; 1412aef85402SRichard Henderson 1413aef85402SRichard Henderson /* 1414aef85402SRichard Henderson * Retain the full value of the 64-bit constant in the low 1415aef85402SRichard Henderson * part, so that the hash table works. Actual uses will 1416aef85402SRichard Henderson * truncate the value to the low part. 1417aef85402SRichard Henderson */ 1418aef85402SRichard Henderson ts[HOST_BIG_ENDIAN].val = val; 1419aef85402SRichard Henderson ts[!HOST_BIG_ENDIAN].val = val >> 32; 1420aef85402SRichard Henderson val_ptr = &ts[HOST_BIG_ENDIAN].val; 1421c0522136SRichard Henderson } else { 1422c0522136SRichard Henderson ts->base_type = type; 1423c0522136SRichard Henderson ts->type = type; 1424c0522136SRichard Henderson ts->kind = TEMP_CONST; 1425c0522136SRichard Henderson ts->temp_allocated = 1; 1426c0522136SRichard Henderson ts->val = val; 1427aef85402SRichard Henderson val_ptr = &ts->val; 1428c0522136SRichard Henderson } 1429aef85402SRichard Henderson g_hash_table_insert(h, val_ptr, ts); 1430c0522136SRichard Henderson } 1431c0522136SRichard Henderson 1432c0522136SRichard Henderson return ts; 1433c0522136SRichard Henderson } 1434c0522136SRichard Henderson 1435c0522136SRichard Henderson TCGv_vec tcg_constant_vec(TCGType type, unsigned vece, int64_t val) 1436c0522136SRichard Henderson { 1437c0522136SRichard Henderson val = dup_const(vece, val); 1438c0522136SRichard Henderson return temp_tcgv_vec(tcg_constant_internal(type, val)); 1439c0522136SRichard Henderson } 1440c0522136SRichard Henderson 144188d4005bSRichard Henderson TCGv_vec tcg_constant_vec_matching(TCGv_vec match, unsigned vece, int64_t val) 144288d4005bSRichard Henderson { 144388d4005bSRichard Henderson TCGTemp *t = tcgv_vec_temp(match); 144488d4005bSRichard Henderson 144588d4005bSRichard Henderson tcg_debug_assert(t->temp_allocated != 0); 144688d4005bSRichard Henderson return tcg_constant_vec(t->base_type, vece, val); 144788d4005bSRichard Henderson } 144888d4005bSRichard Henderson 1449be0f34b5SRichard Henderson /* Return true if OP may appear in the opcode stream. 1450be0f34b5SRichard Henderson Test the runtime variable that controls each opcode. */ 1451be0f34b5SRichard Henderson bool tcg_op_supported(TCGOpcode op) 1452be0f34b5SRichard Henderson { 1453d2fd745fSRichard Henderson const bool have_vec 1454d2fd745fSRichard Henderson = TCG_TARGET_HAS_v64 | TCG_TARGET_HAS_v128 | TCG_TARGET_HAS_v256; 1455d2fd745fSRichard Henderson 1456be0f34b5SRichard Henderson switch (op) { 1457be0f34b5SRichard Henderson case INDEX_op_discard: 1458be0f34b5SRichard Henderson case INDEX_op_set_label: 1459be0f34b5SRichard Henderson case INDEX_op_call: 1460be0f34b5SRichard Henderson case INDEX_op_br: 1461be0f34b5SRichard Henderson case INDEX_op_mb: 1462be0f34b5SRichard Henderson case INDEX_op_insn_start: 1463be0f34b5SRichard Henderson case INDEX_op_exit_tb: 1464be0f34b5SRichard Henderson case INDEX_op_goto_tb: 1465f4e01e30SRichard Henderson case INDEX_op_goto_ptr: 1466be0f34b5SRichard Henderson case INDEX_op_qemu_ld_i32: 1467be0f34b5SRichard Henderson case INDEX_op_qemu_st_i32: 1468be0f34b5SRichard Henderson case INDEX_op_qemu_ld_i64: 1469be0f34b5SRichard Henderson case INDEX_op_qemu_st_i64: 1470be0f34b5SRichard Henderson return true; 1471be0f34b5SRichard Henderson 147207ce0b05SRichard Henderson case INDEX_op_qemu_st8_i32: 147307ce0b05SRichard Henderson return TCG_TARGET_HAS_qemu_st8_i32; 147407ce0b05SRichard Henderson 1475be0f34b5SRichard Henderson case INDEX_op_mov_i32: 1476be0f34b5SRichard Henderson case INDEX_op_setcond_i32: 1477be0f34b5SRichard Henderson case INDEX_op_brcond_i32: 1478be0f34b5SRichard Henderson case INDEX_op_ld8u_i32: 1479be0f34b5SRichard Henderson case INDEX_op_ld8s_i32: 1480be0f34b5SRichard Henderson case INDEX_op_ld16u_i32: 1481be0f34b5SRichard Henderson case INDEX_op_ld16s_i32: 1482be0f34b5SRichard Henderson case INDEX_op_ld_i32: 1483be0f34b5SRichard Henderson case INDEX_op_st8_i32: 1484be0f34b5SRichard Henderson case INDEX_op_st16_i32: 1485be0f34b5SRichard Henderson case INDEX_op_st_i32: 1486be0f34b5SRichard Henderson case INDEX_op_add_i32: 1487be0f34b5SRichard Henderson case INDEX_op_sub_i32: 1488be0f34b5SRichard Henderson case INDEX_op_mul_i32: 1489be0f34b5SRichard Henderson case INDEX_op_and_i32: 1490be0f34b5SRichard Henderson case INDEX_op_or_i32: 1491be0f34b5SRichard Henderson case INDEX_op_xor_i32: 1492be0f34b5SRichard Henderson case INDEX_op_shl_i32: 1493be0f34b5SRichard Henderson case INDEX_op_shr_i32: 1494be0f34b5SRichard Henderson case INDEX_op_sar_i32: 1495be0f34b5SRichard Henderson return true; 1496be0f34b5SRichard Henderson 1497be0f34b5SRichard Henderson case INDEX_op_movcond_i32: 1498be0f34b5SRichard Henderson return TCG_TARGET_HAS_movcond_i32; 1499be0f34b5SRichard Henderson case INDEX_op_div_i32: 1500be0f34b5SRichard Henderson case INDEX_op_divu_i32: 1501be0f34b5SRichard Henderson return TCG_TARGET_HAS_div_i32; 1502be0f34b5SRichard Henderson case INDEX_op_rem_i32: 1503be0f34b5SRichard Henderson case INDEX_op_remu_i32: 1504be0f34b5SRichard Henderson return TCG_TARGET_HAS_rem_i32; 1505be0f34b5SRichard Henderson case INDEX_op_div2_i32: 1506be0f34b5SRichard Henderson case INDEX_op_divu2_i32: 1507be0f34b5SRichard Henderson return TCG_TARGET_HAS_div2_i32; 1508be0f34b5SRichard Henderson case INDEX_op_rotl_i32: 1509be0f34b5SRichard Henderson case INDEX_op_rotr_i32: 1510be0f34b5SRichard Henderson return TCG_TARGET_HAS_rot_i32; 1511be0f34b5SRichard Henderson case INDEX_op_deposit_i32: 1512be0f34b5SRichard Henderson return TCG_TARGET_HAS_deposit_i32; 1513be0f34b5SRichard Henderson case INDEX_op_extract_i32: 1514be0f34b5SRichard Henderson return TCG_TARGET_HAS_extract_i32; 1515be0f34b5SRichard Henderson case INDEX_op_sextract_i32: 1516be0f34b5SRichard Henderson return TCG_TARGET_HAS_sextract_i32; 1517fce1296fSRichard Henderson case INDEX_op_extract2_i32: 1518fce1296fSRichard Henderson return TCG_TARGET_HAS_extract2_i32; 1519be0f34b5SRichard Henderson case INDEX_op_add2_i32: 1520be0f34b5SRichard Henderson return TCG_TARGET_HAS_add2_i32; 1521be0f34b5SRichard Henderson case INDEX_op_sub2_i32: 1522be0f34b5SRichard Henderson return TCG_TARGET_HAS_sub2_i32; 1523be0f34b5SRichard Henderson case INDEX_op_mulu2_i32: 1524be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulu2_i32; 1525be0f34b5SRichard Henderson case INDEX_op_muls2_i32: 1526be0f34b5SRichard Henderson return TCG_TARGET_HAS_muls2_i32; 1527be0f34b5SRichard Henderson case INDEX_op_muluh_i32: 1528be0f34b5SRichard Henderson return TCG_TARGET_HAS_muluh_i32; 1529be0f34b5SRichard Henderson case INDEX_op_mulsh_i32: 1530be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulsh_i32; 1531be0f34b5SRichard Henderson case INDEX_op_ext8s_i32: 1532be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8s_i32; 1533be0f34b5SRichard Henderson case INDEX_op_ext16s_i32: 1534be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16s_i32; 1535be0f34b5SRichard Henderson case INDEX_op_ext8u_i32: 1536be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8u_i32; 1537be0f34b5SRichard Henderson case INDEX_op_ext16u_i32: 1538be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16u_i32; 1539be0f34b5SRichard Henderson case INDEX_op_bswap16_i32: 1540be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap16_i32; 1541be0f34b5SRichard Henderson case INDEX_op_bswap32_i32: 1542be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap32_i32; 1543be0f34b5SRichard Henderson case INDEX_op_not_i32: 1544be0f34b5SRichard Henderson return TCG_TARGET_HAS_not_i32; 1545be0f34b5SRichard Henderson case INDEX_op_neg_i32: 1546be0f34b5SRichard Henderson return TCG_TARGET_HAS_neg_i32; 1547be0f34b5SRichard Henderson case INDEX_op_andc_i32: 1548be0f34b5SRichard Henderson return TCG_TARGET_HAS_andc_i32; 1549be0f34b5SRichard Henderson case INDEX_op_orc_i32: 1550be0f34b5SRichard Henderson return TCG_TARGET_HAS_orc_i32; 1551be0f34b5SRichard Henderson case INDEX_op_eqv_i32: 1552be0f34b5SRichard Henderson return TCG_TARGET_HAS_eqv_i32; 1553be0f34b5SRichard Henderson case INDEX_op_nand_i32: 1554be0f34b5SRichard Henderson return TCG_TARGET_HAS_nand_i32; 1555be0f34b5SRichard Henderson case INDEX_op_nor_i32: 1556be0f34b5SRichard Henderson return TCG_TARGET_HAS_nor_i32; 1557be0f34b5SRichard Henderson case INDEX_op_clz_i32: 1558be0f34b5SRichard Henderson return TCG_TARGET_HAS_clz_i32; 1559be0f34b5SRichard Henderson case INDEX_op_ctz_i32: 1560be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctz_i32; 1561be0f34b5SRichard Henderson case INDEX_op_ctpop_i32: 1562be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctpop_i32; 1563be0f34b5SRichard Henderson 1564be0f34b5SRichard Henderson case INDEX_op_brcond2_i32: 1565be0f34b5SRichard Henderson case INDEX_op_setcond2_i32: 1566be0f34b5SRichard Henderson return TCG_TARGET_REG_BITS == 32; 1567be0f34b5SRichard Henderson 1568be0f34b5SRichard Henderson case INDEX_op_mov_i64: 1569be0f34b5SRichard Henderson case INDEX_op_setcond_i64: 1570be0f34b5SRichard Henderson case INDEX_op_brcond_i64: 1571be0f34b5SRichard Henderson case INDEX_op_ld8u_i64: 1572be0f34b5SRichard Henderson case INDEX_op_ld8s_i64: 1573be0f34b5SRichard Henderson case INDEX_op_ld16u_i64: 1574be0f34b5SRichard Henderson case INDEX_op_ld16s_i64: 1575be0f34b5SRichard Henderson case INDEX_op_ld32u_i64: 1576be0f34b5SRichard Henderson case INDEX_op_ld32s_i64: 1577be0f34b5SRichard Henderson case INDEX_op_ld_i64: 1578be0f34b5SRichard Henderson case INDEX_op_st8_i64: 1579be0f34b5SRichard Henderson case INDEX_op_st16_i64: 1580be0f34b5SRichard Henderson case INDEX_op_st32_i64: 1581be0f34b5SRichard Henderson case INDEX_op_st_i64: 1582be0f34b5SRichard Henderson case INDEX_op_add_i64: 1583be0f34b5SRichard Henderson case INDEX_op_sub_i64: 1584be0f34b5SRichard Henderson case INDEX_op_mul_i64: 1585be0f34b5SRichard Henderson case INDEX_op_and_i64: 1586be0f34b5SRichard Henderson case INDEX_op_or_i64: 1587be0f34b5SRichard Henderson case INDEX_op_xor_i64: 1588be0f34b5SRichard Henderson case INDEX_op_shl_i64: 1589be0f34b5SRichard Henderson case INDEX_op_shr_i64: 1590be0f34b5SRichard Henderson case INDEX_op_sar_i64: 1591be0f34b5SRichard Henderson case INDEX_op_ext_i32_i64: 1592be0f34b5SRichard Henderson case INDEX_op_extu_i32_i64: 1593be0f34b5SRichard Henderson return TCG_TARGET_REG_BITS == 64; 1594be0f34b5SRichard Henderson 1595be0f34b5SRichard Henderson case INDEX_op_movcond_i64: 1596be0f34b5SRichard Henderson return TCG_TARGET_HAS_movcond_i64; 1597be0f34b5SRichard Henderson case INDEX_op_div_i64: 1598be0f34b5SRichard Henderson case INDEX_op_divu_i64: 1599be0f34b5SRichard Henderson return TCG_TARGET_HAS_div_i64; 1600be0f34b5SRichard Henderson case INDEX_op_rem_i64: 1601be0f34b5SRichard Henderson case INDEX_op_remu_i64: 1602be0f34b5SRichard Henderson return TCG_TARGET_HAS_rem_i64; 1603be0f34b5SRichard Henderson case INDEX_op_div2_i64: 1604be0f34b5SRichard Henderson case INDEX_op_divu2_i64: 1605be0f34b5SRichard Henderson return TCG_TARGET_HAS_div2_i64; 1606be0f34b5SRichard Henderson case INDEX_op_rotl_i64: 1607be0f34b5SRichard Henderson case INDEX_op_rotr_i64: 1608be0f34b5SRichard Henderson return TCG_TARGET_HAS_rot_i64; 1609be0f34b5SRichard Henderson case INDEX_op_deposit_i64: 1610be0f34b5SRichard Henderson return TCG_TARGET_HAS_deposit_i64; 1611be0f34b5SRichard Henderson case INDEX_op_extract_i64: 1612be0f34b5SRichard Henderson return TCG_TARGET_HAS_extract_i64; 1613be0f34b5SRichard Henderson case INDEX_op_sextract_i64: 1614be0f34b5SRichard Henderson return TCG_TARGET_HAS_sextract_i64; 1615fce1296fSRichard Henderson case INDEX_op_extract2_i64: 1616fce1296fSRichard Henderson return TCG_TARGET_HAS_extract2_i64; 1617be0f34b5SRichard Henderson case INDEX_op_extrl_i64_i32: 1618be0f34b5SRichard Henderson return TCG_TARGET_HAS_extrl_i64_i32; 1619be0f34b5SRichard Henderson case INDEX_op_extrh_i64_i32: 1620be0f34b5SRichard Henderson return TCG_TARGET_HAS_extrh_i64_i32; 1621be0f34b5SRichard Henderson case INDEX_op_ext8s_i64: 1622be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8s_i64; 1623be0f34b5SRichard Henderson case INDEX_op_ext16s_i64: 1624be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16s_i64; 1625be0f34b5SRichard Henderson case INDEX_op_ext32s_i64: 1626be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext32s_i64; 1627be0f34b5SRichard Henderson case INDEX_op_ext8u_i64: 1628be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8u_i64; 1629be0f34b5SRichard Henderson case INDEX_op_ext16u_i64: 1630be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16u_i64; 1631be0f34b5SRichard Henderson case INDEX_op_ext32u_i64: 1632be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext32u_i64; 1633be0f34b5SRichard Henderson case INDEX_op_bswap16_i64: 1634be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap16_i64; 1635be0f34b5SRichard Henderson case INDEX_op_bswap32_i64: 1636be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap32_i64; 1637be0f34b5SRichard Henderson case INDEX_op_bswap64_i64: 1638be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap64_i64; 1639be0f34b5SRichard Henderson case INDEX_op_not_i64: 1640be0f34b5SRichard Henderson return TCG_TARGET_HAS_not_i64; 1641be0f34b5SRichard Henderson case INDEX_op_neg_i64: 1642be0f34b5SRichard Henderson return TCG_TARGET_HAS_neg_i64; 1643be0f34b5SRichard Henderson case INDEX_op_andc_i64: 1644be0f34b5SRichard Henderson return TCG_TARGET_HAS_andc_i64; 1645be0f34b5SRichard Henderson case INDEX_op_orc_i64: 1646be0f34b5SRichard Henderson return TCG_TARGET_HAS_orc_i64; 1647be0f34b5SRichard Henderson case INDEX_op_eqv_i64: 1648be0f34b5SRichard Henderson return TCG_TARGET_HAS_eqv_i64; 1649be0f34b5SRichard Henderson case INDEX_op_nand_i64: 1650be0f34b5SRichard Henderson return TCG_TARGET_HAS_nand_i64; 1651be0f34b5SRichard Henderson case INDEX_op_nor_i64: 1652be0f34b5SRichard Henderson return TCG_TARGET_HAS_nor_i64; 1653be0f34b5SRichard Henderson case INDEX_op_clz_i64: 1654be0f34b5SRichard Henderson return TCG_TARGET_HAS_clz_i64; 1655be0f34b5SRichard Henderson case INDEX_op_ctz_i64: 1656be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctz_i64; 1657be0f34b5SRichard Henderson case INDEX_op_ctpop_i64: 1658be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctpop_i64; 1659be0f34b5SRichard Henderson case INDEX_op_add2_i64: 1660be0f34b5SRichard Henderson return TCG_TARGET_HAS_add2_i64; 1661be0f34b5SRichard Henderson case INDEX_op_sub2_i64: 1662be0f34b5SRichard Henderson return TCG_TARGET_HAS_sub2_i64; 1663be0f34b5SRichard Henderson case INDEX_op_mulu2_i64: 1664be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulu2_i64; 1665be0f34b5SRichard Henderson case INDEX_op_muls2_i64: 1666be0f34b5SRichard Henderson return TCG_TARGET_HAS_muls2_i64; 1667be0f34b5SRichard Henderson case INDEX_op_muluh_i64: 1668be0f34b5SRichard Henderson return TCG_TARGET_HAS_muluh_i64; 1669be0f34b5SRichard Henderson case INDEX_op_mulsh_i64: 1670be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulsh_i64; 1671be0f34b5SRichard Henderson 1672d2fd745fSRichard Henderson case INDEX_op_mov_vec: 1673d2fd745fSRichard Henderson case INDEX_op_dup_vec: 167437ee55a0SRichard Henderson case INDEX_op_dupm_vec: 1675d2fd745fSRichard Henderson case INDEX_op_ld_vec: 1676d2fd745fSRichard Henderson case INDEX_op_st_vec: 1677d2fd745fSRichard Henderson case INDEX_op_add_vec: 1678d2fd745fSRichard Henderson case INDEX_op_sub_vec: 1679d2fd745fSRichard Henderson case INDEX_op_and_vec: 1680d2fd745fSRichard Henderson case INDEX_op_or_vec: 1681d2fd745fSRichard Henderson case INDEX_op_xor_vec: 1682212be173SRichard Henderson case INDEX_op_cmp_vec: 1683d2fd745fSRichard Henderson return have_vec; 1684d2fd745fSRichard Henderson case INDEX_op_dup2_vec: 1685d2fd745fSRichard Henderson return have_vec && TCG_TARGET_REG_BITS == 32; 1686d2fd745fSRichard Henderson case INDEX_op_not_vec: 1687d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_not_vec; 1688d2fd745fSRichard Henderson case INDEX_op_neg_vec: 1689d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_neg_vec; 1690bcefc902SRichard Henderson case INDEX_op_abs_vec: 1691bcefc902SRichard Henderson return have_vec && TCG_TARGET_HAS_abs_vec; 1692d2fd745fSRichard Henderson case INDEX_op_andc_vec: 1693d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_andc_vec; 1694d2fd745fSRichard Henderson case INDEX_op_orc_vec: 1695d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_orc_vec; 1696ed523473SRichard Henderson case INDEX_op_nand_vec: 1697ed523473SRichard Henderson return have_vec && TCG_TARGET_HAS_nand_vec; 1698ed523473SRichard Henderson case INDEX_op_nor_vec: 1699ed523473SRichard Henderson return have_vec && TCG_TARGET_HAS_nor_vec; 1700ed523473SRichard Henderson case INDEX_op_eqv_vec: 1701ed523473SRichard Henderson return have_vec && TCG_TARGET_HAS_eqv_vec; 17023774030aSRichard Henderson case INDEX_op_mul_vec: 17033774030aSRichard Henderson return have_vec && TCG_TARGET_HAS_mul_vec; 1704d0ec9796SRichard Henderson case INDEX_op_shli_vec: 1705d0ec9796SRichard Henderson case INDEX_op_shri_vec: 1706d0ec9796SRichard Henderson case INDEX_op_sari_vec: 1707d0ec9796SRichard Henderson return have_vec && TCG_TARGET_HAS_shi_vec; 1708d0ec9796SRichard Henderson case INDEX_op_shls_vec: 1709d0ec9796SRichard Henderson case INDEX_op_shrs_vec: 1710d0ec9796SRichard Henderson case INDEX_op_sars_vec: 1711d0ec9796SRichard Henderson return have_vec && TCG_TARGET_HAS_shs_vec; 1712d0ec9796SRichard Henderson case INDEX_op_shlv_vec: 1713d0ec9796SRichard Henderson case INDEX_op_shrv_vec: 1714d0ec9796SRichard Henderson case INDEX_op_sarv_vec: 1715d0ec9796SRichard Henderson return have_vec && TCG_TARGET_HAS_shv_vec; 1716b0f7e744SRichard Henderson case INDEX_op_rotli_vec: 1717b0f7e744SRichard Henderson return have_vec && TCG_TARGET_HAS_roti_vec; 171823850a74SRichard Henderson case INDEX_op_rotls_vec: 171923850a74SRichard Henderson return have_vec && TCG_TARGET_HAS_rots_vec; 17205d0ceda9SRichard Henderson case INDEX_op_rotlv_vec: 17215d0ceda9SRichard Henderson case INDEX_op_rotrv_vec: 17225d0ceda9SRichard Henderson return have_vec && TCG_TARGET_HAS_rotv_vec; 17238afaf050SRichard Henderson case INDEX_op_ssadd_vec: 17248afaf050SRichard Henderson case INDEX_op_usadd_vec: 17258afaf050SRichard Henderson case INDEX_op_sssub_vec: 17268afaf050SRichard Henderson case INDEX_op_ussub_vec: 17278afaf050SRichard Henderson return have_vec && TCG_TARGET_HAS_sat_vec; 1728dd0a0fcdSRichard Henderson case INDEX_op_smin_vec: 1729dd0a0fcdSRichard Henderson case INDEX_op_umin_vec: 1730dd0a0fcdSRichard Henderson case INDEX_op_smax_vec: 1731dd0a0fcdSRichard Henderson case INDEX_op_umax_vec: 1732dd0a0fcdSRichard Henderson return have_vec && TCG_TARGET_HAS_minmax_vec; 173338dc1294SRichard Henderson case INDEX_op_bitsel_vec: 173438dc1294SRichard Henderson return have_vec && TCG_TARGET_HAS_bitsel_vec; 1735f75da298SRichard Henderson case INDEX_op_cmpsel_vec: 1736f75da298SRichard Henderson return have_vec && TCG_TARGET_HAS_cmpsel_vec; 1737d2fd745fSRichard Henderson 1738db432672SRichard Henderson default: 1739db432672SRichard Henderson tcg_debug_assert(op > INDEX_op_last_generic && op < NB_OPS); 1740db432672SRichard Henderson return true; 1741be0f34b5SRichard Henderson } 1742be0f34b5SRichard Henderson } 1743be0f34b5SRichard Henderson 174439004a71SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs); 174539004a71SRichard Henderson 1746ae8b75dcSRichard Henderson void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args) 1747c896fe29Sbellard { 17483e92aa34SRichard Henderson const TCGHelperInfo *info; 174939004a71SRichard Henderson TCGv_i64 extend_free[MAX_CALL_IARGS]; 175039004a71SRichard Henderson int n_extend = 0; 175175e8b9b7SRichard Henderson TCGOp *op; 175239004a71SRichard Henderson int i, n, pi = 0, total_args; 1753afb49896SRichard Henderson 1754619205fdSEmilio G. Cota info = g_hash_table_lookup(helper_table, (gpointer)func); 175539004a71SRichard Henderson total_args = info->nr_out + info->nr_in + 2; 175639004a71SRichard Henderson op = tcg_op_alloc(INDEX_op_call, total_args); 17572bece2c8SRichard Henderson 175838b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN 175917083f6fSEmilio Cota /* Flag helpers that may affect guest state */ 176017083f6fSEmilio Cota if (tcg_ctx->plugin_insn && 176117083f6fSEmilio Cota !(info->flags & TCG_CALL_PLUGIN) && 176217083f6fSEmilio Cota !(info->flags & TCG_CALL_NO_SIDE_EFFECTS)) { 176338b47b19SEmilio G. Cota tcg_ctx->plugin_insn->calls_helpers = true; 176438b47b19SEmilio G. Cota } 176538b47b19SEmilio G. Cota #endif 176638b47b19SEmilio G. Cota 176739004a71SRichard Henderson TCGOP_CALLO(op) = n = info->nr_out; 176839004a71SRichard Henderson switch (n) { 176939004a71SRichard Henderson case 0: 177039004a71SRichard Henderson tcg_debug_assert(ret == NULL); 177139004a71SRichard Henderson break; 177239004a71SRichard Henderson case 1: 177339004a71SRichard Henderson tcg_debug_assert(ret != NULL); 177439004a71SRichard Henderson op->args[pi++] = temp_arg(ret); 177539004a71SRichard Henderson break; 177639004a71SRichard Henderson case 2: 1777466d3759SRichard Henderson case 4: 177839004a71SRichard Henderson tcg_debug_assert(ret != NULL); 1779466d3759SRichard Henderson tcg_debug_assert(ret->base_type == ret->type + ctz32(n)); 178039004a71SRichard Henderson tcg_debug_assert(ret->temp_subindex == 0); 1781466d3759SRichard Henderson for (i = 0; i < n; ++i) { 1782466d3759SRichard Henderson op->args[pi++] = temp_arg(ret + i); 1783466d3759SRichard Henderson } 178439004a71SRichard Henderson break; 178539004a71SRichard Henderson default: 178639004a71SRichard Henderson g_assert_not_reached(); 178739004a71SRichard Henderson } 17887319d83aSRichard Henderson 178939004a71SRichard Henderson TCGOP_CALLI(op) = n = info->nr_in; 179039004a71SRichard Henderson for (i = 0; i < n; i++) { 179139004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i]; 179239004a71SRichard Henderson TCGTemp *ts = args[loc->arg_idx] + loc->tmp_subindex; 179339004a71SRichard Henderson 179439004a71SRichard Henderson switch (loc->kind) { 179539004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 1796313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF: 1797313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF_N: 179839004a71SRichard Henderson op->args[pi++] = temp_arg(ts); 179939004a71SRichard Henderson break; 180039004a71SRichard Henderson 180139004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 180239004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 180339004a71SRichard Henderson { 18045dd48602SRichard Henderson TCGv_i64 temp = tcg_temp_ebb_new_i64(); 180539004a71SRichard Henderson TCGv_i32 orig = temp_tcgv_i32(ts); 180639004a71SRichard Henderson 180739004a71SRichard Henderson if (loc->kind == TCG_CALL_ARG_EXTEND_S) { 180818cf3d07SRichard Henderson tcg_gen_ext_i32_i64(temp, orig); 18092bece2c8SRichard Henderson } else { 181018cf3d07SRichard Henderson tcg_gen_extu_i32_i64(temp, orig); 18112bece2c8SRichard Henderson } 181239004a71SRichard Henderson op->args[pi++] = tcgv_i64_arg(temp); 181339004a71SRichard Henderson extend_free[n_extend++] = temp; 18142bece2c8SRichard Henderson } 181539004a71SRichard Henderson break; 18162bece2c8SRichard Henderson 1817e2a9dd6bSRichard Henderson default: 1818e2a9dd6bSRichard Henderson g_assert_not_reached(); 1819e2a9dd6bSRichard Henderson } 1820c896fe29Sbellard } 182175e8b9b7SRichard Henderson op->args[pi++] = (uintptr_t)func; 18223e92aa34SRichard Henderson op->args[pi++] = (uintptr_t)info; 182339004a71SRichard Henderson tcg_debug_assert(pi == total_args); 1824a7812ae4Spbrook 182539004a71SRichard Henderson QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link); 18262bece2c8SRichard Henderson 182739004a71SRichard Henderson tcg_debug_assert(n_extend < ARRAY_SIZE(extend_free)); 182839004a71SRichard Henderson for (i = 0; i < n_extend; ++i) { 182939004a71SRichard Henderson tcg_temp_free_i64(extend_free[i]); 1830eb8b0224SRichard Henderson } 1831a7812ae4Spbrook } 1832c896fe29Sbellard 18338fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s) 1834c896fe29Sbellard { 1835ac3b8891SRichard Henderson int i, n; 1836ac3b8891SRichard Henderson 1837ee17db83SRichard Henderson for (i = 0, n = s->nb_temps; i < n; i++) { 1838ee17db83SRichard Henderson TCGTemp *ts = &s->temps[i]; 1839ee17db83SRichard Henderson TCGTempVal val = TEMP_VAL_MEM; 1840ee17db83SRichard Henderson 1841ee17db83SRichard Henderson switch (ts->kind) { 1842c0522136SRichard Henderson case TEMP_CONST: 1843c0522136SRichard Henderson val = TEMP_VAL_CONST; 1844c0522136SRichard Henderson break; 1845ee17db83SRichard Henderson case TEMP_FIXED: 1846ee17db83SRichard Henderson val = TEMP_VAL_REG; 1847ee17db83SRichard Henderson break; 1848ee17db83SRichard Henderson case TEMP_GLOBAL: 1849ee17db83SRichard Henderson break; 1850c7482438SRichard Henderson case TEMP_EBB: 1851ee17db83SRichard Henderson val = TEMP_VAL_DEAD; 1852ee17db83SRichard Henderson /* fall through */ 1853f57c6915SRichard Henderson case TEMP_TB: 1854e8996ee0Sbellard ts->mem_allocated = 0; 1855ee17db83SRichard Henderson break; 1856ee17db83SRichard Henderson default: 1857ee17db83SRichard Henderson g_assert_not_reached(); 1858ee17db83SRichard Henderson } 1859ee17db83SRichard Henderson ts->val_type = val; 1860e8996ee0Sbellard } 1861f8b2f202SRichard Henderson 1862f8b2f202SRichard Henderson memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp)); 1863c896fe29Sbellard } 1864c896fe29Sbellard 1865f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size, 1866f8b2f202SRichard Henderson TCGTemp *ts) 1867c896fe29Sbellard { 18681807f4c4SRichard Henderson int idx = temp_idx(ts); 1869ac56dd48Spbrook 1870ee17db83SRichard Henderson switch (ts->kind) { 1871ee17db83SRichard Henderson case TEMP_FIXED: 1872ee17db83SRichard Henderson case TEMP_GLOBAL: 1873ac56dd48Spbrook pstrcpy(buf, buf_size, ts->name); 1874ee17db83SRichard Henderson break; 1875f57c6915SRichard Henderson case TEMP_TB: 1876641d5fbeSbellard snprintf(buf, buf_size, "loc%d", idx - s->nb_globals); 1877ee17db83SRichard Henderson break; 1878c7482438SRichard Henderson case TEMP_EBB: 1879ac56dd48Spbrook snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals); 1880ee17db83SRichard Henderson break; 1881c0522136SRichard Henderson case TEMP_CONST: 1882c0522136SRichard Henderson switch (ts->type) { 1883c0522136SRichard Henderson case TCG_TYPE_I32: 1884c0522136SRichard Henderson snprintf(buf, buf_size, "$0x%x", (int32_t)ts->val); 1885c0522136SRichard Henderson break; 1886c0522136SRichard Henderson #if TCG_TARGET_REG_BITS > 32 1887c0522136SRichard Henderson case TCG_TYPE_I64: 1888c0522136SRichard Henderson snprintf(buf, buf_size, "$0x%" PRIx64, ts->val); 1889c0522136SRichard Henderson break; 1890c0522136SRichard Henderson #endif 1891c0522136SRichard Henderson case TCG_TYPE_V64: 1892c0522136SRichard Henderson case TCG_TYPE_V128: 1893c0522136SRichard Henderson case TCG_TYPE_V256: 1894c0522136SRichard Henderson snprintf(buf, buf_size, "v%d$0x%" PRIx64, 1895c0522136SRichard Henderson 64 << (ts->type - TCG_TYPE_V64), ts->val); 1896c0522136SRichard Henderson break; 1897c0522136SRichard Henderson default: 1898c0522136SRichard Henderson g_assert_not_reached(); 1899c0522136SRichard Henderson } 1900c0522136SRichard Henderson break; 1901c896fe29Sbellard } 1902c896fe29Sbellard return buf; 1903c896fe29Sbellard } 1904c896fe29Sbellard 190543439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf, 190643439139SRichard Henderson int buf_size, TCGArg arg) 1907f8b2f202SRichard Henderson { 190843439139SRichard Henderson return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg)); 1909f8b2f202SRichard Henderson } 1910f8b2f202SRichard Henderson 1911f48f3edeSblueswir1 static const char * const cond_name[] = 1912f48f3edeSblueswir1 { 19130aed257fSRichard Henderson [TCG_COND_NEVER] = "never", 19140aed257fSRichard Henderson [TCG_COND_ALWAYS] = "always", 1915f48f3edeSblueswir1 [TCG_COND_EQ] = "eq", 1916f48f3edeSblueswir1 [TCG_COND_NE] = "ne", 1917f48f3edeSblueswir1 [TCG_COND_LT] = "lt", 1918f48f3edeSblueswir1 [TCG_COND_GE] = "ge", 1919f48f3edeSblueswir1 [TCG_COND_LE] = "le", 1920f48f3edeSblueswir1 [TCG_COND_GT] = "gt", 1921f48f3edeSblueswir1 [TCG_COND_LTU] = "ltu", 1922f48f3edeSblueswir1 [TCG_COND_GEU] = "geu", 1923f48f3edeSblueswir1 [TCG_COND_LEU] = "leu", 1924f48f3edeSblueswir1 [TCG_COND_GTU] = "gtu" 1925f48f3edeSblueswir1 }; 1926f48f3edeSblueswir1 1927f713d6adSRichard Henderson static const char * const ldst_name[] = 1928f713d6adSRichard Henderson { 1929f713d6adSRichard Henderson [MO_UB] = "ub", 1930f713d6adSRichard Henderson [MO_SB] = "sb", 1931f713d6adSRichard Henderson [MO_LEUW] = "leuw", 1932f713d6adSRichard Henderson [MO_LESW] = "lesw", 1933f713d6adSRichard Henderson [MO_LEUL] = "leul", 1934f713d6adSRichard Henderson [MO_LESL] = "lesl", 1935fc313c64SFrédéric Pétrot [MO_LEUQ] = "leq", 1936f713d6adSRichard Henderson [MO_BEUW] = "beuw", 1937f713d6adSRichard Henderson [MO_BESW] = "besw", 1938f713d6adSRichard Henderson [MO_BEUL] = "beul", 1939f713d6adSRichard Henderson [MO_BESL] = "besl", 1940fc313c64SFrédéric Pétrot [MO_BEUQ] = "beq", 1941f713d6adSRichard Henderson }; 1942f713d6adSRichard Henderson 19431f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = { 194452bf9771Stony.nguyen@bt.com #ifdef TARGET_ALIGNED_ONLY 19451f00b27fSSergey Sorokin [MO_UNALN >> MO_ASHIFT] = "un+", 19461f00b27fSSergey Sorokin [MO_ALIGN >> MO_ASHIFT] = "", 19471f00b27fSSergey Sorokin #else 19481f00b27fSSergey Sorokin [MO_UNALN >> MO_ASHIFT] = "", 19491f00b27fSSergey Sorokin [MO_ALIGN >> MO_ASHIFT] = "al+", 19501f00b27fSSergey Sorokin #endif 19511f00b27fSSergey Sorokin [MO_ALIGN_2 >> MO_ASHIFT] = "al2+", 19521f00b27fSSergey Sorokin [MO_ALIGN_4 >> MO_ASHIFT] = "al4+", 19531f00b27fSSergey Sorokin [MO_ALIGN_8 >> MO_ASHIFT] = "al8+", 19541f00b27fSSergey Sorokin [MO_ALIGN_16 >> MO_ASHIFT] = "al16+", 19551f00b27fSSergey Sorokin [MO_ALIGN_32 >> MO_ASHIFT] = "al32+", 19561f00b27fSSergey Sorokin [MO_ALIGN_64 >> MO_ASHIFT] = "al64+", 19571f00b27fSSergey Sorokin }; 19581f00b27fSSergey Sorokin 1959587195bdSRichard Henderson static const char bswap_flag_name[][6] = { 1960587195bdSRichard Henderson [TCG_BSWAP_IZ] = "iz", 1961587195bdSRichard Henderson [TCG_BSWAP_OZ] = "oz", 1962587195bdSRichard Henderson [TCG_BSWAP_OS] = "os", 1963587195bdSRichard Henderson [TCG_BSWAP_IZ | TCG_BSWAP_OZ] = "iz,oz", 1964587195bdSRichard Henderson [TCG_BSWAP_IZ | TCG_BSWAP_OS] = "iz,os", 1965587195bdSRichard Henderson }; 1966587195bdSRichard Henderson 1967b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d) 1968b016486eSRichard Henderson { 1969b016486eSRichard Henderson return (d & (d - 1)) == 0; 1970b016486eSRichard Henderson } 1971b016486eSRichard Henderson 1972b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d) 1973b016486eSRichard Henderson { 1974b016486eSRichard Henderson if (TCG_TARGET_NB_REGS <= 32) { 1975b016486eSRichard Henderson return ctz32(d); 1976b016486eSRichard Henderson } else { 1977b016486eSRichard Henderson return ctz64(d); 1978b016486eSRichard Henderson } 1979b016486eSRichard Henderson } 1980b016486eSRichard Henderson 1981b7a83ff8SRichard Henderson /* Return only the number of characters output -- no error return. */ 1982b7a83ff8SRichard Henderson #define ne_fprintf(...) \ 1983b7a83ff8SRichard Henderson ({ int ret_ = fprintf(__VA_ARGS__); ret_ >= 0 ? ret_ : 0; }) 1984b7a83ff8SRichard Henderson 1985b7a83ff8SRichard Henderson static void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs) 1986c896fe29Sbellard { 1987c896fe29Sbellard char buf[128]; 1988c45cb8bbSRichard Henderson TCGOp *op; 1989c896fe29Sbellard 199015fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 1991c45cb8bbSRichard Henderson int i, k, nb_oargs, nb_iargs, nb_cargs; 1992c45cb8bbSRichard Henderson const TCGOpDef *def; 1993c45cb8bbSRichard Henderson TCGOpcode c; 1994bdfb460eSRichard Henderson int col = 0; 1995c45cb8bbSRichard Henderson 1996c45cb8bbSRichard Henderson c = op->opc; 1997c896fe29Sbellard def = &tcg_op_defs[c]; 1998c45cb8bbSRichard Henderson 1999765b842aSRichard Henderson if (c == INDEX_op_insn_start) { 2000b016486eSRichard Henderson nb_oargs = 0; 2001b7a83ff8SRichard Henderson col += ne_fprintf(f, "\n ----"); 20029aef40edSRichard Henderson 20039aef40edSRichard Henderson for (i = 0; i < TARGET_INSN_START_WORDS; ++i) { 20049aef40edSRichard Henderson target_ulong a; 20057e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS 2006efee3746SRichard Henderson a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]); 20077e4597d7Sbellard #else 2008efee3746SRichard Henderson a = op->args[i]; 20097e4597d7Sbellard #endif 2010b7a83ff8SRichard Henderson col += ne_fprintf(f, " " TARGET_FMT_lx, a); 2011eeacee4dSBlue Swirl } 20127e4597d7Sbellard } else if (c == INDEX_op_call) { 20133e92aa34SRichard Henderson const TCGHelperInfo *info = tcg_call_info(op); 2014fa52e660SRichard Henderson void *func = tcg_call_func(op); 20153e92aa34SRichard Henderson 2016c896fe29Sbellard /* variable number of arguments */ 2017cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 2018cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 2019c896fe29Sbellard nb_cargs = def->nb_cargs; 2020b03cce8eSbellard 2021b7a83ff8SRichard Henderson col += ne_fprintf(f, " %s ", def->name); 20223e92aa34SRichard Henderson 20233e92aa34SRichard Henderson /* 20243e92aa34SRichard Henderson * Print the function name from TCGHelperInfo, if available. 20253e92aa34SRichard Henderson * Note that plugins have a template function for the info, 20263e92aa34SRichard Henderson * but the actual function pointer comes from the plugin. 20273e92aa34SRichard Henderson */ 20283e92aa34SRichard Henderson if (func == info->func) { 2029b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s", info->name); 20303e92aa34SRichard Henderson } else { 2031b7a83ff8SRichard Henderson col += ne_fprintf(f, "plugin(%p)", func); 20323e92aa34SRichard Henderson } 20333e92aa34SRichard Henderson 2034b7a83ff8SRichard Henderson col += ne_fprintf(f, ",$0x%x,$%d", info->flags, nb_oargs); 2035b03cce8eSbellard for (i = 0; i < nb_oargs; i++) { 2036b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", tcg_get_arg_str(s, buf, sizeof(buf), 2037efee3746SRichard Henderson op->args[i])); 2038b03cce8eSbellard } 2039cf066674SRichard Henderson for (i = 0; i < nb_iargs; i++) { 2040efee3746SRichard Henderson TCGArg arg = op->args[nb_oargs + i]; 204139004a71SRichard Henderson const char *t = tcg_get_arg_str(s, buf, sizeof(buf), arg); 2042b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", t); 2043e8996ee0Sbellard } 2044b03cce8eSbellard } else { 2045b7a83ff8SRichard Henderson col += ne_fprintf(f, " %s ", def->name); 2046c45cb8bbSRichard Henderson 2047c896fe29Sbellard nb_oargs = def->nb_oargs; 2048c896fe29Sbellard nb_iargs = def->nb_iargs; 2049c896fe29Sbellard nb_cargs = def->nb_cargs; 2050c896fe29Sbellard 2051d2fd745fSRichard Henderson if (def->flags & TCG_OPF_VECTOR) { 2052b7a83ff8SRichard Henderson col += ne_fprintf(f, "v%d,e%d,", 64 << TCGOP_VECL(op), 2053d2fd745fSRichard Henderson 8 << TCGOP_VECE(op)); 2054d2fd745fSRichard Henderson } 2055d2fd745fSRichard Henderson 2056c896fe29Sbellard k = 0; 2057c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 2058b7a83ff8SRichard Henderson const char *sep = k ? "," : ""; 2059b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s%s", sep, 2060b7a83ff8SRichard Henderson tcg_get_arg_str(s, buf, sizeof(buf), 2061efee3746SRichard Henderson op->args[k++])); 2062c896fe29Sbellard } 2063c896fe29Sbellard for (i = 0; i < nb_iargs; i++) { 2064b7a83ff8SRichard Henderson const char *sep = k ? "," : ""; 2065b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s%s", sep, 2066b7a83ff8SRichard Henderson tcg_get_arg_str(s, buf, sizeof(buf), 2067efee3746SRichard Henderson op->args[k++])); 2068c896fe29Sbellard } 2069be210acbSRichard Henderson switch (c) { 2070be210acbSRichard Henderson case INDEX_op_brcond_i32: 2071ffc5ea09SRichard Henderson case INDEX_op_setcond_i32: 2072ffc5ea09SRichard Henderson case INDEX_op_movcond_i32: 2073be210acbSRichard Henderson case INDEX_op_brcond2_i32: 2074be210acbSRichard Henderson case INDEX_op_setcond2_i32: 2075ffc5ea09SRichard Henderson case INDEX_op_brcond_i64: 2076be210acbSRichard Henderson case INDEX_op_setcond_i64: 2077ffc5ea09SRichard Henderson case INDEX_op_movcond_i64: 2078212be173SRichard Henderson case INDEX_op_cmp_vec: 2079f75da298SRichard Henderson case INDEX_op_cmpsel_vec: 2080efee3746SRichard Henderson if (op->args[k] < ARRAY_SIZE(cond_name) 2081efee3746SRichard Henderson && cond_name[op->args[k]]) { 2082b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", cond_name[op->args[k++]]); 2083eeacee4dSBlue Swirl } else { 2084b7a83ff8SRichard Henderson col += ne_fprintf(f, ",$0x%" TCG_PRIlx, op->args[k++]); 2085eeacee4dSBlue Swirl } 2086f48f3edeSblueswir1 i = 1; 2087be210acbSRichard Henderson break; 2088f713d6adSRichard Henderson case INDEX_op_qemu_ld_i32: 2089f713d6adSRichard Henderson case INDEX_op_qemu_st_i32: 209007ce0b05SRichard Henderson case INDEX_op_qemu_st8_i32: 2091f713d6adSRichard Henderson case INDEX_op_qemu_ld_i64: 2092f713d6adSRichard Henderson case INDEX_op_qemu_st_i64: 209359227d5dSRichard Henderson { 20949002ffcbSRichard Henderson MemOpIdx oi = op->args[k++]; 209514776ab5STony Nguyen MemOp op = get_memop(oi); 209659227d5dSRichard Henderson unsigned ix = get_mmuidx(oi); 209759227d5dSRichard Henderson 209859c4b7e8SRichard Henderson if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) { 2099b7a83ff8SRichard Henderson col += ne_fprintf(f, ",$0x%x,%u", op, ix); 210059c4b7e8SRichard Henderson } else { 21011f00b27fSSergey Sorokin const char *s_al, *s_op; 21021f00b27fSSergey Sorokin s_al = alignment_name[(op & MO_AMASK) >> MO_ASHIFT]; 210359c4b7e8SRichard Henderson s_op = ldst_name[op & (MO_BSWAP | MO_SSIZE)]; 2104b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s%s,%u", s_al, s_op, ix); 2105f713d6adSRichard Henderson } 2106f713d6adSRichard Henderson i = 1; 210759227d5dSRichard Henderson } 2108f713d6adSRichard Henderson break; 2109587195bdSRichard Henderson case INDEX_op_bswap16_i32: 2110587195bdSRichard Henderson case INDEX_op_bswap16_i64: 2111587195bdSRichard Henderson case INDEX_op_bswap32_i32: 2112587195bdSRichard Henderson case INDEX_op_bswap32_i64: 2113587195bdSRichard Henderson case INDEX_op_bswap64_i64: 2114587195bdSRichard Henderson { 2115587195bdSRichard Henderson TCGArg flags = op->args[k]; 2116587195bdSRichard Henderson const char *name = NULL; 2117587195bdSRichard Henderson 2118587195bdSRichard Henderson if (flags < ARRAY_SIZE(bswap_flag_name)) { 2119587195bdSRichard Henderson name = bswap_flag_name[flags]; 2120587195bdSRichard Henderson } 2121587195bdSRichard Henderson if (name) { 2122b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", name); 2123587195bdSRichard Henderson } else { 2124b7a83ff8SRichard Henderson col += ne_fprintf(f, ",$0x%" TCG_PRIlx, flags); 2125587195bdSRichard Henderson } 2126587195bdSRichard Henderson i = k = 1; 2127587195bdSRichard Henderson } 2128587195bdSRichard Henderson break; 2129be210acbSRichard Henderson default: 2130f48f3edeSblueswir1 i = 0; 2131be210acbSRichard Henderson break; 2132be210acbSRichard Henderson } 213351e3972cSRichard Henderson switch (c) { 213451e3972cSRichard Henderson case INDEX_op_set_label: 213551e3972cSRichard Henderson case INDEX_op_br: 213651e3972cSRichard Henderson case INDEX_op_brcond_i32: 213751e3972cSRichard Henderson case INDEX_op_brcond_i64: 213851e3972cSRichard Henderson case INDEX_op_brcond2_i32: 2139b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s$L%d", k ? "," : "", 2140efee3746SRichard Henderson arg_label(op->args[k])->id); 214151e3972cSRichard Henderson i++, k++; 214251e3972cSRichard Henderson break; 21433470867bSRichard Henderson case INDEX_op_mb: 21443470867bSRichard Henderson { 21453470867bSRichard Henderson TCGBar membar = op->args[k]; 21463470867bSRichard Henderson const char *b_op, *m_op; 21473470867bSRichard Henderson 21483470867bSRichard Henderson switch (membar & TCG_BAR_SC) { 21493470867bSRichard Henderson case 0: 21503470867bSRichard Henderson b_op = "none"; 21513470867bSRichard Henderson break; 21523470867bSRichard Henderson case TCG_BAR_LDAQ: 21533470867bSRichard Henderson b_op = "acq"; 21543470867bSRichard Henderson break; 21553470867bSRichard Henderson case TCG_BAR_STRL: 21563470867bSRichard Henderson b_op = "rel"; 21573470867bSRichard Henderson break; 21583470867bSRichard Henderson case TCG_BAR_SC: 21593470867bSRichard Henderson b_op = "seq"; 21603470867bSRichard Henderson break; 21613470867bSRichard Henderson default: 21623470867bSRichard Henderson g_assert_not_reached(); 21633470867bSRichard Henderson } 21643470867bSRichard Henderson 21653470867bSRichard Henderson switch (membar & TCG_MO_ALL) { 21663470867bSRichard Henderson case 0: 21673470867bSRichard Henderson m_op = "none"; 21683470867bSRichard Henderson break; 21693470867bSRichard Henderson case TCG_MO_LD_LD: 21703470867bSRichard Henderson m_op = "rr"; 21713470867bSRichard Henderson break; 21723470867bSRichard Henderson case TCG_MO_LD_ST: 21733470867bSRichard Henderson m_op = "rw"; 21743470867bSRichard Henderson break; 21753470867bSRichard Henderson case TCG_MO_ST_LD: 21763470867bSRichard Henderson m_op = "wr"; 21773470867bSRichard Henderson break; 21783470867bSRichard Henderson case TCG_MO_ST_ST: 21793470867bSRichard Henderson m_op = "ww"; 21803470867bSRichard Henderson break; 21813470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_LD_ST: 21823470867bSRichard Henderson m_op = "rr+rw"; 21833470867bSRichard Henderson break; 21843470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_ST_LD: 21853470867bSRichard Henderson m_op = "rr+wr"; 21863470867bSRichard Henderson break; 21873470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_ST_ST: 21883470867bSRichard Henderson m_op = "rr+ww"; 21893470867bSRichard Henderson break; 21903470867bSRichard Henderson case TCG_MO_LD_ST | TCG_MO_ST_LD: 21913470867bSRichard Henderson m_op = "rw+wr"; 21923470867bSRichard Henderson break; 21933470867bSRichard Henderson case TCG_MO_LD_ST | TCG_MO_ST_ST: 21943470867bSRichard Henderson m_op = "rw+ww"; 21953470867bSRichard Henderson break; 21963470867bSRichard Henderson case TCG_MO_ST_LD | TCG_MO_ST_ST: 21973470867bSRichard Henderson m_op = "wr+ww"; 21983470867bSRichard Henderson break; 21993470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_MO_ST_LD: 22003470867bSRichard Henderson m_op = "rr+rw+wr"; 22013470867bSRichard Henderson break; 22023470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_MO_ST_ST: 22033470867bSRichard Henderson m_op = "rr+rw+ww"; 22043470867bSRichard Henderson break; 22053470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_ST_LD | TCG_MO_ST_ST: 22063470867bSRichard Henderson m_op = "rr+wr+ww"; 22073470867bSRichard Henderson break; 22083470867bSRichard Henderson case TCG_MO_LD_ST | TCG_MO_ST_LD | TCG_MO_ST_ST: 22093470867bSRichard Henderson m_op = "rw+wr+ww"; 22103470867bSRichard Henderson break; 22113470867bSRichard Henderson case TCG_MO_ALL: 22123470867bSRichard Henderson m_op = "all"; 22133470867bSRichard Henderson break; 22143470867bSRichard Henderson default: 22153470867bSRichard Henderson g_assert_not_reached(); 22163470867bSRichard Henderson } 22173470867bSRichard Henderson 22183470867bSRichard Henderson col += ne_fprintf(f, "%s%s:%s", (k ? "," : ""), b_op, m_op); 22193470867bSRichard Henderson i++, k++; 22203470867bSRichard Henderson } 22213470867bSRichard Henderson break; 222251e3972cSRichard Henderson default: 222351e3972cSRichard Henderson break; 2224eeacee4dSBlue Swirl } 222551e3972cSRichard Henderson for (; i < nb_cargs; i++, k++) { 2226b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s$0x%" TCG_PRIlx, k ? "," : "", 2227b7a83ff8SRichard Henderson op->args[k]); 2228bdfb460eSRichard Henderson } 2229bdfb460eSRichard Henderson } 2230bdfb460eSRichard Henderson 22311894f69aSRichard Henderson if (have_prefs || op->life) { 22321894f69aSRichard Henderson for (; col < 40; ++col) { 2233b7a83ff8SRichard Henderson putc(' ', f); 2234bdfb460eSRichard Henderson } 22351894f69aSRichard Henderson } 22361894f69aSRichard Henderson 22371894f69aSRichard Henderson if (op->life) { 22381894f69aSRichard Henderson unsigned life = op->life; 2239bdfb460eSRichard Henderson 2240bdfb460eSRichard Henderson if (life & (SYNC_ARG * 3)) { 2241b7a83ff8SRichard Henderson ne_fprintf(f, " sync:"); 2242bdfb460eSRichard Henderson for (i = 0; i < 2; ++i) { 2243bdfb460eSRichard Henderson if (life & (SYNC_ARG << i)) { 2244b7a83ff8SRichard Henderson ne_fprintf(f, " %d", i); 2245bdfb460eSRichard Henderson } 2246bdfb460eSRichard Henderson } 2247bdfb460eSRichard Henderson } 2248bdfb460eSRichard Henderson life /= DEAD_ARG; 2249bdfb460eSRichard Henderson if (life) { 2250b7a83ff8SRichard Henderson ne_fprintf(f, " dead:"); 2251bdfb460eSRichard Henderson for (i = 0; life; ++i, life >>= 1) { 2252bdfb460eSRichard Henderson if (life & 1) { 2253b7a83ff8SRichard Henderson ne_fprintf(f, " %d", i); 2254bdfb460eSRichard Henderson } 2255bdfb460eSRichard Henderson } 2256c896fe29Sbellard } 2257b03cce8eSbellard } 22581894f69aSRichard Henderson 22591894f69aSRichard Henderson if (have_prefs) { 22601894f69aSRichard Henderson for (i = 0; i < nb_oargs; ++i) { 226131fd884bSRichard Henderson TCGRegSet set = output_pref(op, i); 22621894f69aSRichard Henderson 22631894f69aSRichard Henderson if (i == 0) { 2264b7a83ff8SRichard Henderson ne_fprintf(f, " pref="); 22651894f69aSRichard Henderson } else { 2266b7a83ff8SRichard Henderson ne_fprintf(f, ","); 22671894f69aSRichard Henderson } 22681894f69aSRichard Henderson if (set == 0) { 2269b7a83ff8SRichard Henderson ne_fprintf(f, "none"); 22701894f69aSRichard Henderson } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) { 2271b7a83ff8SRichard Henderson ne_fprintf(f, "all"); 22721894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG 22731894f69aSRichard Henderson } else if (tcg_regset_single(set)) { 22741894f69aSRichard Henderson TCGReg reg = tcg_regset_first(set); 2275b7a83ff8SRichard Henderson ne_fprintf(f, "%s", tcg_target_reg_names[reg]); 22761894f69aSRichard Henderson #endif 22771894f69aSRichard Henderson } else if (TCG_TARGET_NB_REGS <= 32) { 2278b7a83ff8SRichard Henderson ne_fprintf(f, "0x%x", (uint32_t)set); 22791894f69aSRichard Henderson } else { 2280b7a83ff8SRichard Henderson ne_fprintf(f, "0x%" PRIx64, (uint64_t)set); 22811894f69aSRichard Henderson } 22821894f69aSRichard Henderson } 22831894f69aSRichard Henderson } 22841894f69aSRichard Henderson 2285b7a83ff8SRichard Henderson putc('\n', f); 2286c896fe29Sbellard } 2287c896fe29Sbellard } 2288c896fe29Sbellard 2289c896fe29Sbellard /* we give more priority to constraints with less registers */ 2290c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k) 2291c896fe29Sbellard { 229274a11790SRichard Henderson const TCGArgConstraint *arg_ct = &def->args_ct[k]; 229329f5e925SRichard Henderson int n = ctpop64(arg_ct->regs); 2294c896fe29Sbellard 229529f5e925SRichard Henderson /* 229629f5e925SRichard Henderson * Sort constraints of a single register first, which includes output 229729f5e925SRichard Henderson * aliases (which must exactly match the input already allocated). 229829f5e925SRichard Henderson */ 229929f5e925SRichard Henderson if (n == 1 || arg_ct->oalias) { 230029f5e925SRichard Henderson return INT_MAX; 2301c896fe29Sbellard } 230229f5e925SRichard Henderson 230329f5e925SRichard Henderson /* 230429f5e925SRichard Henderson * Sort register pairs next, first then second immediately after. 230529f5e925SRichard Henderson * Arbitrarily sort multiple pairs by the index of the first reg; 230629f5e925SRichard Henderson * there shouldn't be many pairs. 230729f5e925SRichard Henderson */ 230829f5e925SRichard Henderson switch (arg_ct->pair) { 230929f5e925SRichard Henderson case 1: 231029f5e925SRichard Henderson case 3: 231129f5e925SRichard Henderson return (k + 1) * 2; 231229f5e925SRichard Henderson case 2: 231329f5e925SRichard Henderson return (arg_ct->pair_index + 1) * 2 - 1; 231429f5e925SRichard Henderson } 231529f5e925SRichard Henderson 231629f5e925SRichard Henderson /* Finally, sort by decreasing register count. */ 231729f5e925SRichard Henderson assert(n > 1); 231829f5e925SRichard Henderson return -n; 2319c896fe29Sbellard } 2320c896fe29Sbellard 2321c896fe29Sbellard /* sort from highest priority to lowest */ 2322c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n) 2323c896fe29Sbellard { 232466792f90SRichard Henderson int i, j; 232566792f90SRichard Henderson TCGArgConstraint *a = def->args_ct; 2326c896fe29Sbellard 232766792f90SRichard Henderson for (i = 0; i < n; i++) { 232866792f90SRichard Henderson a[start + i].sort_index = start + i; 232966792f90SRichard Henderson } 233066792f90SRichard Henderson if (n <= 1) { 2331c896fe29Sbellard return; 233266792f90SRichard Henderson } 2333c896fe29Sbellard for (i = 0; i < n - 1; i++) { 2334c896fe29Sbellard for (j = i + 1; j < n; j++) { 233566792f90SRichard Henderson int p1 = get_constraint_priority(def, a[start + i].sort_index); 233666792f90SRichard Henderson int p2 = get_constraint_priority(def, a[start + j].sort_index); 2337c896fe29Sbellard if (p1 < p2) { 233866792f90SRichard Henderson int tmp = a[start + i].sort_index; 233966792f90SRichard Henderson a[start + i].sort_index = a[start + j].sort_index; 234066792f90SRichard Henderson a[start + j].sort_index = tmp; 2341c896fe29Sbellard } 2342c896fe29Sbellard } 2343c896fe29Sbellard } 2344c896fe29Sbellard } 2345c896fe29Sbellard 2346f69d277eSRichard Henderson static void process_op_defs(TCGContext *s) 2347c896fe29Sbellard { 2348a9751609SRichard Henderson TCGOpcode op; 2349c896fe29Sbellard 2350f69d277eSRichard Henderson for (op = 0; op < NB_OPS; op++) { 2351f69d277eSRichard Henderson TCGOpDef *def = &tcg_op_defs[op]; 2352f69d277eSRichard Henderson const TCGTargetOpDef *tdefs; 235329f5e925SRichard Henderson bool saw_alias_pair = false; 235429f5e925SRichard Henderson int i, o, i2, o2, nb_args; 2355f69d277eSRichard Henderson 2356f69d277eSRichard Henderson if (def->flags & TCG_OPF_NOT_PRESENT) { 2357f69d277eSRichard Henderson continue; 2358f69d277eSRichard Henderson } 2359f69d277eSRichard Henderson 2360c896fe29Sbellard nb_args = def->nb_iargs + def->nb_oargs; 2361f69d277eSRichard Henderson if (nb_args == 0) { 2362f69d277eSRichard Henderson continue; 2363f69d277eSRichard Henderson } 2364f69d277eSRichard Henderson 23654c22e840SRichard Henderson /* 23664c22e840SRichard Henderson * Macro magic should make it impossible, but double-check that 23674c22e840SRichard Henderson * the array index is in range. Since the signness of an enum 23684c22e840SRichard Henderson * is implementation defined, force the result to unsigned. 23694c22e840SRichard Henderson */ 23704c22e840SRichard Henderson unsigned con_set = tcg_target_op_def(op); 23714c22e840SRichard Henderson tcg_debug_assert(con_set < ARRAY_SIZE(constraint_sets)); 23724c22e840SRichard Henderson tdefs = &constraint_sets[con_set]; 2373f69d277eSRichard Henderson 2374c896fe29Sbellard for (i = 0; i < nb_args; i++) { 2375f69d277eSRichard Henderson const char *ct_str = tdefs->args_ct_str[i]; 23768940ea0dSPhilippe Mathieu-Daudé bool input_p = i >= def->nb_oargs; 23778940ea0dSPhilippe Mathieu-Daudé 2378f69d277eSRichard Henderson /* Incomplete TCGTargetOpDef entry. */ 2379eabb7b91SAurelien Jarno tcg_debug_assert(ct_str != NULL); 2380f69d277eSRichard Henderson 238117280ff4SRichard Henderson switch (*ct_str) { 238217280ff4SRichard Henderson case '0' ... '9': 23838940ea0dSPhilippe Mathieu-Daudé o = *ct_str - '0'; 23848940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(input_p); 23858940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(o < def->nb_oargs); 23868940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(def->args_ct[o].regs != 0); 23878940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(!def->args_ct[o].oalias); 23888940ea0dSPhilippe Mathieu-Daudé def->args_ct[i] = def->args_ct[o]; 2389bc2b17e6SRichard Henderson /* The output sets oalias. */ 23908940ea0dSPhilippe Mathieu-Daudé def->args_ct[o].oalias = 1; 23918940ea0dSPhilippe Mathieu-Daudé def->args_ct[o].alias_index = i; 2392bc2b17e6SRichard Henderson /* The input sets ialias. */ 23938940ea0dSPhilippe Mathieu-Daudé def->args_ct[i].ialias = 1; 23948940ea0dSPhilippe Mathieu-Daudé def->args_ct[i].alias_index = o; 239529f5e925SRichard Henderson if (def->args_ct[i].pair) { 239629f5e925SRichard Henderson saw_alias_pair = true; 239729f5e925SRichard Henderson } 23988940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(ct_str[1] == '\0'); 23998940ea0dSPhilippe Mathieu-Daudé continue; 24008940ea0dSPhilippe Mathieu-Daudé 240182790a87SRichard Henderson case '&': 24028940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(!input_p); 2403bc2b17e6SRichard Henderson def->args_ct[i].newreg = true; 240482790a87SRichard Henderson ct_str++; 240582790a87SRichard Henderson break; 240629f5e925SRichard Henderson 240729f5e925SRichard Henderson case 'p': /* plus */ 240829f5e925SRichard Henderson /* Allocate to the register after the previous. */ 240929f5e925SRichard Henderson tcg_debug_assert(i > (input_p ? def->nb_oargs : 0)); 241029f5e925SRichard Henderson o = i - 1; 241129f5e925SRichard Henderson tcg_debug_assert(!def->args_ct[o].pair); 241229f5e925SRichard Henderson tcg_debug_assert(!def->args_ct[o].ct); 241329f5e925SRichard Henderson def->args_ct[i] = (TCGArgConstraint){ 241429f5e925SRichard Henderson .pair = 2, 241529f5e925SRichard Henderson .pair_index = o, 241629f5e925SRichard Henderson .regs = def->args_ct[o].regs << 1, 241729f5e925SRichard Henderson }; 241829f5e925SRichard Henderson def->args_ct[o].pair = 1; 241929f5e925SRichard Henderson def->args_ct[o].pair_index = i; 242029f5e925SRichard Henderson tcg_debug_assert(ct_str[1] == '\0'); 242129f5e925SRichard Henderson continue; 242229f5e925SRichard Henderson 242329f5e925SRichard Henderson case 'm': /* minus */ 242429f5e925SRichard Henderson /* Allocate to the register before the previous. */ 242529f5e925SRichard Henderson tcg_debug_assert(i > (input_p ? def->nb_oargs : 0)); 242629f5e925SRichard Henderson o = i - 1; 242729f5e925SRichard Henderson tcg_debug_assert(!def->args_ct[o].pair); 242829f5e925SRichard Henderson tcg_debug_assert(!def->args_ct[o].ct); 242929f5e925SRichard Henderson def->args_ct[i] = (TCGArgConstraint){ 243029f5e925SRichard Henderson .pair = 1, 243129f5e925SRichard Henderson .pair_index = o, 243229f5e925SRichard Henderson .regs = def->args_ct[o].regs >> 1, 243329f5e925SRichard Henderson }; 243429f5e925SRichard Henderson def->args_ct[o].pair = 2; 243529f5e925SRichard Henderson def->args_ct[o].pair_index = i; 243629f5e925SRichard Henderson tcg_debug_assert(ct_str[1] == '\0'); 243729f5e925SRichard Henderson continue; 24388940ea0dSPhilippe Mathieu-Daudé } 24398940ea0dSPhilippe Mathieu-Daudé 24408940ea0dSPhilippe Mathieu-Daudé do { 24418940ea0dSPhilippe Mathieu-Daudé switch (*ct_str) { 2442c896fe29Sbellard case 'i': 2443c896fe29Sbellard def->args_ct[i].ct |= TCG_CT_CONST; 2444c896fe29Sbellard break; 2445358b4923SRichard Henderson 2446358b4923SRichard Henderson /* Include all of the target-specific constraints. */ 2447358b4923SRichard Henderson 2448358b4923SRichard Henderson #undef CONST 2449358b4923SRichard Henderson #define CONST(CASE, MASK) \ 24508940ea0dSPhilippe Mathieu-Daudé case CASE: def->args_ct[i].ct |= MASK; break; 2451358b4923SRichard Henderson #define REGS(CASE, MASK) \ 24528940ea0dSPhilippe Mathieu-Daudé case CASE: def->args_ct[i].regs |= MASK; break; 2453358b4923SRichard Henderson 2454358b4923SRichard Henderson #include "tcg-target-con-str.h" 2455358b4923SRichard Henderson 2456358b4923SRichard Henderson #undef REGS 2457358b4923SRichard Henderson #undef CONST 2458c896fe29Sbellard default: 24598940ea0dSPhilippe Mathieu-Daudé case '0' ... '9': 24608940ea0dSPhilippe Mathieu-Daudé case '&': 246129f5e925SRichard Henderson case 'p': 246229f5e925SRichard Henderson case 'm': 2463358b4923SRichard Henderson /* Typo in TCGTargetOpDef constraint. */ 2464358b4923SRichard Henderson g_assert_not_reached(); 2465358b4923SRichard Henderson } 24668940ea0dSPhilippe Mathieu-Daudé } while (*++ct_str != '\0'); 2467c896fe29Sbellard } 2468c896fe29Sbellard 2469c68aaa18SStefan Weil /* TCGTargetOpDef entry with too much information? */ 2470eabb7b91SAurelien Jarno tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL); 2471c68aaa18SStefan Weil 247229f5e925SRichard Henderson /* 247329f5e925SRichard Henderson * Fix up output pairs that are aliased with inputs. 247429f5e925SRichard Henderson * When we created the alias, we copied pair from the output. 247529f5e925SRichard Henderson * There are three cases: 247629f5e925SRichard Henderson * (1a) Pairs of inputs alias pairs of outputs. 247729f5e925SRichard Henderson * (1b) One input aliases the first of a pair of outputs. 247829f5e925SRichard Henderson * (2) One input aliases the second of a pair of outputs. 247929f5e925SRichard Henderson * 248029f5e925SRichard Henderson * Case 1a is handled by making sure that the pair_index'es are 248129f5e925SRichard Henderson * properly updated so that they appear the same as a pair of inputs. 248229f5e925SRichard Henderson * 248329f5e925SRichard Henderson * Case 1b is handled by setting the pair_index of the input to 248429f5e925SRichard Henderson * itself, simply so it doesn't point to an unrelated argument. 248529f5e925SRichard Henderson * Since we don't encounter the "second" during the input allocation 248629f5e925SRichard Henderson * phase, nothing happens with the second half of the input pair. 248729f5e925SRichard Henderson * 248829f5e925SRichard Henderson * Case 2 is handled by setting the second input to pair=3, the 248929f5e925SRichard Henderson * first output to pair=3, and the pair_index'es to match. 249029f5e925SRichard Henderson */ 249129f5e925SRichard Henderson if (saw_alias_pair) { 249229f5e925SRichard Henderson for (i = def->nb_oargs; i < nb_args; i++) { 249329f5e925SRichard Henderson /* 249429f5e925SRichard Henderson * Since [0-9pm] must be alone in the constraint string, 249529f5e925SRichard Henderson * the only way they can both be set is if the pair comes 249629f5e925SRichard Henderson * from the output alias. 249729f5e925SRichard Henderson */ 249829f5e925SRichard Henderson if (!def->args_ct[i].ialias) { 249929f5e925SRichard Henderson continue; 250029f5e925SRichard Henderson } 250129f5e925SRichard Henderson switch (def->args_ct[i].pair) { 250229f5e925SRichard Henderson case 0: 250329f5e925SRichard Henderson break; 250429f5e925SRichard Henderson case 1: 250529f5e925SRichard Henderson o = def->args_ct[i].alias_index; 250629f5e925SRichard Henderson o2 = def->args_ct[o].pair_index; 250729f5e925SRichard Henderson tcg_debug_assert(def->args_ct[o].pair == 1); 250829f5e925SRichard Henderson tcg_debug_assert(def->args_ct[o2].pair == 2); 250929f5e925SRichard Henderson if (def->args_ct[o2].oalias) { 251029f5e925SRichard Henderson /* Case 1a */ 251129f5e925SRichard Henderson i2 = def->args_ct[o2].alias_index; 251229f5e925SRichard Henderson tcg_debug_assert(def->args_ct[i2].pair == 2); 251329f5e925SRichard Henderson def->args_ct[i2].pair_index = i; 251429f5e925SRichard Henderson def->args_ct[i].pair_index = i2; 251529f5e925SRichard Henderson } else { 251629f5e925SRichard Henderson /* Case 1b */ 251729f5e925SRichard Henderson def->args_ct[i].pair_index = i; 251829f5e925SRichard Henderson } 251929f5e925SRichard Henderson break; 252029f5e925SRichard Henderson case 2: 252129f5e925SRichard Henderson o = def->args_ct[i].alias_index; 252229f5e925SRichard Henderson o2 = def->args_ct[o].pair_index; 252329f5e925SRichard Henderson tcg_debug_assert(def->args_ct[o].pair == 2); 252429f5e925SRichard Henderson tcg_debug_assert(def->args_ct[o2].pair == 1); 252529f5e925SRichard Henderson if (def->args_ct[o2].oalias) { 252629f5e925SRichard Henderson /* Case 1a */ 252729f5e925SRichard Henderson i2 = def->args_ct[o2].alias_index; 252829f5e925SRichard Henderson tcg_debug_assert(def->args_ct[i2].pair == 1); 252929f5e925SRichard Henderson def->args_ct[i2].pair_index = i; 253029f5e925SRichard Henderson def->args_ct[i].pair_index = i2; 253129f5e925SRichard Henderson } else { 253229f5e925SRichard Henderson /* Case 2 */ 253329f5e925SRichard Henderson def->args_ct[i].pair = 3; 253429f5e925SRichard Henderson def->args_ct[o2].pair = 3; 253529f5e925SRichard Henderson def->args_ct[i].pair_index = o2; 253629f5e925SRichard Henderson def->args_ct[o2].pair_index = i; 253729f5e925SRichard Henderson } 253829f5e925SRichard Henderson break; 253929f5e925SRichard Henderson default: 254029f5e925SRichard Henderson g_assert_not_reached(); 254129f5e925SRichard Henderson } 254229f5e925SRichard Henderson } 254329f5e925SRichard Henderson } 254429f5e925SRichard Henderson 2545c896fe29Sbellard /* sort the constraints (XXX: this is just an heuristic) */ 2546c896fe29Sbellard sort_constraints(def, 0, def->nb_oargs); 2547c896fe29Sbellard sort_constraints(def, def->nb_oargs, def->nb_iargs); 2548c896fe29Sbellard } 2549c896fe29Sbellard } 2550c896fe29Sbellard 2551f85b1fc4SRichard Henderson static void remove_label_use(TCGOp *op, int idx) 2552f85b1fc4SRichard Henderson { 2553f85b1fc4SRichard Henderson TCGLabel *label = arg_label(op->args[idx]); 2554f85b1fc4SRichard Henderson TCGLabelUse *use; 2555f85b1fc4SRichard Henderson 2556f85b1fc4SRichard Henderson QSIMPLEQ_FOREACH(use, &label->branches, next) { 2557f85b1fc4SRichard Henderson if (use->op == op) { 2558f85b1fc4SRichard Henderson QSIMPLEQ_REMOVE(&label->branches, use, TCGLabelUse, next); 2559f85b1fc4SRichard Henderson return; 2560f85b1fc4SRichard Henderson } 2561f85b1fc4SRichard Henderson } 2562f85b1fc4SRichard Henderson g_assert_not_reached(); 2563f85b1fc4SRichard Henderson } 2564f85b1fc4SRichard Henderson 25650c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op) 25660c627cdcSRichard Henderson { 2567d88a117eSRichard Henderson switch (op->opc) { 2568d88a117eSRichard Henderson case INDEX_op_br: 2569f85b1fc4SRichard Henderson remove_label_use(op, 0); 2570d88a117eSRichard Henderson break; 2571d88a117eSRichard Henderson case INDEX_op_brcond_i32: 2572d88a117eSRichard Henderson case INDEX_op_brcond_i64: 2573f85b1fc4SRichard Henderson remove_label_use(op, 3); 2574d88a117eSRichard Henderson break; 2575d88a117eSRichard Henderson case INDEX_op_brcond2_i32: 2576f85b1fc4SRichard Henderson remove_label_use(op, 5); 2577d88a117eSRichard Henderson break; 2578d88a117eSRichard Henderson default: 2579d88a117eSRichard Henderson break; 2580d88a117eSRichard Henderson } 2581d88a117eSRichard Henderson 258215fa08f8SRichard Henderson QTAILQ_REMOVE(&s->ops, op, link); 258315fa08f8SRichard Henderson QTAILQ_INSERT_TAIL(&s->free_ops, op, link); 2584abebf925SRichard Henderson s->nb_ops--; 25850c627cdcSRichard Henderson 25860c627cdcSRichard Henderson #ifdef CONFIG_PROFILER 2587d73415a3SStefan Hajnoczi qatomic_set(&s->prof.del_op_count, s->prof.del_op_count + 1); 25880c627cdcSRichard Henderson #endif 25890c627cdcSRichard Henderson } 25900c627cdcSRichard Henderson 2591a80cdd31SRichard Henderson void tcg_remove_ops_after(TCGOp *op) 2592a80cdd31SRichard Henderson { 2593a80cdd31SRichard Henderson TCGContext *s = tcg_ctx; 2594a80cdd31SRichard Henderson 2595a80cdd31SRichard Henderson while (true) { 2596a80cdd31SRichard Henderson TCGOp *last = tcg_last_op(); 2597a80cdd31SRichard Henderson if (last == op) { 2598a80cdd31SRichard Henderson return; 2599a80cdd31SRichard Henderson } 2600a80cdd31SRichard Henderson tcg_op_remove(s, last); 2601a80cdd31SRichard Henderson } 2602a80cdd31SRichard Henderson } 2603a80cdd31SRichard Henderson 2604d4478943SPhilippe Mathieu-Daudé static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs) 260515fa08f8SRichard Henderson { 260615fa08f8SRichard Henderson TCGContext *s = tcg_ctx; 2607cb10bc63SRichard Henderson TCGOp *op = NULL; 260815fa08f8SRichard Henderson 2609cb10bc63SRichard Henderson if (unlikely(!QTAILQ_EMPTY(&s->free_ops))) { 2610cb10bc63SRichard Henderson QTAILQ_FOREACH(op, &s->free_ops, link) { 2611cb10bc63SRichard Henderson if (nargs <= op->nargs) { 261215fa08f8SRichard Henderson QTAILQ_REMOVE(&s->free_ops, op, link); 2613cb10bc63SRichard Henderson nargs = op->nargs; 2614cb10bc63SRichard Henderson goto found; 261515fa08f8SRichard Henderson } 2616cb10bc63SRichard Henderson } 2617cb10bc63SRichard Henderson } 2618cb10bc63SRichard Henderson 2619cb10bc63SRichard Henderson /* Most opcodes have 3 or 4 operands: reduce fragmentation. */ 2620cb10bc63SRichard Henderson nargs = MAX(4, nargs); 2621cb10bc63SRichard Henderson op = tcg_malloc(sizeof(TCGOp) + sizeof(TCGArg) * nargs); 2622cb10bc63SRichard Henderson 2623cb10bc63SRichard Henderson found: 262415fa08f8SRichard Henderson memset(op, 0, offsetof(TCGOp, link)); 262515fa08f8SRichard Henderson op->opc = opc; 2626cb10bc63SRichard Henderson op->nargs = nargs; 262715fa08f8SRichard Henderson 2628cb10bc63SRichard Henderson /* Check for bitfield overflow. */ 2629cb10bc63SRichard Henderson tcg_debug_assert(op->nargs == nargs); 2630cb10bc63SRichard Henderson 2631cb10bc63SRichard Henderson s->nb_ops++; 263215fa08f8SRichard Henderson return op; 263315fa08f8SRichard Henderson } 263415fa08f8SRichard Henderson 2635d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_emit_op(TCGOpcode opc, unsigned nargs) 263615fa08f8SRichard Henderson { 2637d4478943SPhilippe Mathieu-Daudé TCGOp *op = tcg_op_alloc(opc, nargs); 263815fa08f8SRichard Henderson QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link); 263915fa08f8SRichard Henderson return op; 264015fa08f8SRichard Henderson } 264115fa08f8SRichard Henderson 2642d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op, 2643d4478943SPhilippe Mathieu-Daudé TCGOpcode opc, unsigned nargs) 26445a18407fSRichard Henderson { 2645d4478943SPhilippe Mathieu-Daudé TCGOp *new_op = tcg_op_alloc(opc, nargs); 264615fa08f8SRichard Henderson QTAILQ_INSERT_BEFORE(old_op, new_op, link); 26475a18407fSRichard Henderson return new_op; 26485a18407fSRichard Henderson } 26495a18407fSRichard Henderson 2650d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, 2651d4478943SPhilippe Mathieu-Daudé TCGOpcode opc, unsigned nargs) 26525a18407fSRichard Henderson { 2653d4478943SPhilippe Mathieu-Daudé TCGOp *new_op = tcg_op_alloc(opc, nargs); 265415fa08f8SRichard Henderson QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link); 26555a18407fSRichard Henderson return new_op; 26565a18407fSRichard Henderson } 26575a18407fSRichard Henderson 2658968f305eSRichard Henderson static void move_label_uses(TCGLabel *to, TCGLabel *from) 2659968f305eSRichard Henderson { 2660968f305eSRichard Henderson TCGLabelUse *u; 2661968f305eSRichard Henderson 2662968f305eSRichard Henderson QSIMPLEQ_FOREACH(u, &from->branches, next) { 2663968f305eSRichard Henderson TCGOp *op = u->op; 2664968f305eSRichard Henderson switch (op->opc) { 2665968f305eSRichard Henderson case INDEX_op_br: 2666968f305eSRichard Henderson op->args[0] = label_arg(to); 2667968f305eSRichard Henderson break; 2668968f305eSRichard Henderson case INDEX_op_brcond_i32: 2669968f305eSRichard Henderson case INDEX_op_brcond_i64: 2670968f305eSRichard Henderson op->args[3] = label_arg(to); 2671968f305eSRichard Henderson break; 2672968f305eSRichard Henderson case INDEX_op_brcond2_i32: 2673968f305eSRichard Henderson op->args[5] = label_arg(to); 2674968f305eSRichard Henderson break; 2675968f305eSRichard Henderson default: 2676968f305eSRichard Henderson g_assert_not_reached(); 2677968f305eSRichard Henderson } 2678968f305eSRichard Henderson } 2679968f305eSRichard Henderson 2680968f305eSRichard Henderson QSIMPLEQ_CONCAT(&to->branches, &from->branches); 2681968f305eSRichard Henderson } 2682968f305eSRichard Henderson 2683b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code. */ 26849bbee4c0SRichard Henderson static void __attribute__((noinline)) 26859bbee4c0SRichard Henderson reachable_code_pass(TCGContext *s) 2686b4fc67c7SRichard Henderson { 26874d89d0bbSRichard Henderson TCGOp *op, *op_next, *op_prev; 2688b4fc67c7SRichard Henderson bool dead = false; 2689b4fc67c7SRichard Henderson 2690b4fc67c7SRichard Henderson QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) { 2691b4fc67c7SRichard Henderson bool remove = dead; 2692b4fc67c7SRichard Henderson TCGLabel *label; 2693b4fc67c7SRichard Henderson 2694b4fc67c7SRichard Henderson switch (op->opc) { 2695b4fc67c7SRichard Henderson case INDEX_op_set_label: 2696b4fc67c7SRichard Henderson label = arg_label(op->args[0]); 26974d89d0bbSRichard Henderson 26984d89d0bbSRichard Henderson /* 2699968f305eSRichard Henderson * Note that the first op in the TB is always a load, 2700968f305eSRichard Henderson * so there is always something before a label. 2701968f305eSRichard Henderson */ 2702968f305eSRichard Henderson op_prev = QTAILQ_PREV(op, link); 2703968f305eSRichard Henderson 2704968f305eSRichard Henderson /* 2705968f305eSRichard Henderson * If we find two sequential labels, move all branches to 2706968f305eSRichard Henderson * reference the second label and remove the first label. 2707968f305eSRichard Henderson * Do this before branch to next optimization, so that the 2708968f305eSRichard Henderson * middle label is out of the way. 2709968f305eSRichard Henderson */ 2710968f305eSRichard Henderson if (op_prev->opc == INDEX_op_set_label) { 2711968f305eSRichard Henderson move_label_uses(label, arg_label(op_prev->args[0])); 2712968f305eSRichard Henderson tcg_op_remove(s, op_prev); 2713968f305eSRichard Henderson op_prev = QTAILQ_PREV(op, link); 2714968f305eSRichard Henderson } 2715968f305eSRichard Henderson 2716968f305eSRichard Henderson /* 27174d89d0bbSRichard Henderson * Optimization can fold conditional branches to unconditional. 27184d89d0bbSRichard Henderson * If we find a label which is preceded by an unconditional 27194d89d0bbSRichard Henderson * branch to next, remove the branch. We couldn't do this when 27204d89d0bbSRichard Henderson * processing the branch because any dead code between the branch 27214d89d0bbSRichard Henderson * and label had not yet been removed. 27224d89d0bbSRichard Henderson */ 27234d89d0bbSRichard Henderson if (op_prev->opc == INDEX_op_br && 27244d89d0bbSRichard Henderson label == arg_label(op_prev->args[0])) { 27254d89d0bbSRichard Henderson tcg_op_remove(s, op_prev); 27264d89d0bbSRichard Henderson /* Fall through means insns become live again. */ 27274d89d0bbSRichard Henderson dead = false; 27284d89d0bbSRichard Henderson } 27294d89d0bbSRichard Henderson 2730f85b1fc4SRichard Henderson if (QSIMPLEQ_EMPTY(&label->branches)) { 2731b4fc67c7SRichard Henderson /* 2732b4fc67c7SRichard Henderson * While there is an occasional backward branch, virtually 2733b4fc67c7SRichard Henderson * all branches generated by the translators are forward. 2734b4fc67c7SRichard Henderson * Which means that generally we will have already removed 2735b4fc67c7SRichard Henderson * all references to the label that will be, and there is 2736b4fc67c7SRichard Henderson * little to be gained by iterating. 2737b4fc67c7SRichard Henderson */ 2738b4fc67c7SRichard Henderson remove = true; 2739b4fc67c7SRichard Henderson } else { 2740b4fc67c7SRichard Henderson /* Once we see a label, insns become live again. */ 2741b4fc67c7SRichard Henderson dead = false; 2742b4fc67c7SRichard Henderson remove = false; 2743b4fc67c7SRichard Henderson } 2744b4fc67c7SRichard Henderson break; 2745b4fc67c7SRichard Henderson 2746b4fc67c7SRichard Henderson case INDEX_op_br: 2747b4fc67c7SRichard Henderson case INDEX_op_exit_tb: 2748b4fc67c7SRichard Henderson case INDEX_op_goto_ptr: 2749b4fc67c7SRichard Henderson /* Unconditional branches; everything following is dead. */ 2750b4fc67c7SRichard Henderson dead = true; 2751b4fc67c7SRichard Henderson break; 2752b4fc67c7SRichard Henderson 2753b4fc67c7SRichard Henderson case INDEX_op_call: 2754b4fc67c7SRichard Henderson /* Notice noreturn helper calls, raising exceptions. */ 275590163900SRichard Henderson if (tcg_call_flags(op) & TCG_CALL_NO_RETURN) { 2756b4fc67c7SRichard Henderson dead = true; 2757b4fc67c7SRichard Henderson } 2758b4fc67c7SRichard Henderson break; 2759b4fc67c7SRichard Henderson 2760b4fc67c7SRichard Henderson case INDEX_op_insn_start: 2761b4fc67c7SRichard Henderson /* Never remove -- we need to keep these for unwind. */ 2762b4fc67c7SRichard Henderson remove = false; 2763b4fc67c7SRichard Henderson break; 2764b4fc67c7SRichard Henderson 2765b4fc67c7SRichard Henderson default: 2766b4fc67c7SRichard Henderson break; 2767b4fc67c7SRichard Henderson } 2768b4fc67c7SRichard Henderson 2769b4fc67c7SRichard Henderson if (remove) { 2770b4fc67c7SRichard Henderson tcg_op_remove(s, op); 2771b4fc67c7SRichard Henderson } 2772b4fc67c7SRichard Henderson } 2773b4fc67c7SRichard Henderson } 2774b4fc67c7SRichard Henderson 2775c70fbf0aSRichard Henderson #define TS_DEAD 1 2776c70fbf0aSRichard Henderson #define TS_MEM 2 2777c70fbf0aSRichard Henderson 27785a18407fSRichard Henderson #define IS_DEAD_ARG(n) (arg_life & (DEAD_ARG << (n))) 27795a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n))) 27805a18407fSRichard Henderson 278125f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp. */ 278225f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts) 278325f49c5fSRichard Henderson { 278425f49c5fSRichard Henderson return ts->state_ptr; 278525f49c5fSRichard Henderson } 278625f49c5fSRichard Henderson 278725f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the 278825f49c5fSRichard Henderson * maximal regset for its type. 278925f49c5fSRichard Henderson */ 279025f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts) 279125f49c5fSRichard Henderson { 279225f49c5fSRichard Henderson *la_temp_pref(ts) 279325f49c5fSRichard Henderson = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]); 279425f49c5fSRichard Henderson } 279525f49c5fSRichard Henderson 27969c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals 27979c43b68dSAurelien Jarno should be in memory. */ 27982616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt) 2799c896fe29Sbellard { 2800b83eabeaSRichard Henderson int i; 2801b83eabeaSRichard Henderson 2802b83eabeaSRichard Henderson for (i = 0; i < ng; ++i) { 2803b83eabeaSRichard Henderson s->temps[i].state = TS_DEAD | TS_MEM; 280425f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 2805b83eabeaSRichard Henderson } 2806b83eabeaSRichard Henderson for (i = ng; i < nt; ++i) { 2807b83eabeaSRichard Henderson s->temps[i].state = TS_DEAD; 280825f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 2809b83eabeaSRichard Henderson } 2810c896fe29Sbellard } 2811c896fe29Sbellard 28129c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals 28139c43b68dSAurelien Jarno and local temps should be in memory. */ 28142616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt) 2815641d5fbeSbellard { 2816b83eabeaSRichard Henderson int i; 2817641d5fbeSbellard 2818ee17db83SRichard Henderson for (i = 0; i < nt; ++i) { 2819ee17db83SRichard Henderson TCGTemp *ts = &s->temps[i]; 2820ee17db83SRichard Henderson int state; 2821ee17db83SRichard Henderson 2822ee17db83SRichard Henderson switch (ts->kind) { 2823ee17db83SRichard Henderson case TEMP_FIXED: 2824ee17db83SRichard Henderson case TEMP_GLOBAL: 2825f57c6915SRichard Henderson case TEMP_TB: 2826ee17db83SRichard Henderson state = TS_DEAD | TS_MEM; 2827ee17db83SRichard Henderson break; 2828c7482438SRichard Henderson case TEMP_EBB: 2829c0522136SRichard Henderson case TEMP_CONST: 2830ee17db83SRichard Henderson state = TS_DEAD; 2831ee17db83SRichard Henderson break; 2832ee17db83SRichard Henderson default: 2833ee17db83SRichard Henderson g_assert_not_reached(); 2834c70fbf0aSRichard Henderson } 2835ee17db83SRichard Henderson ts->state = state; 2836ee17db83SRichard Henderson la_reset_pref(ts); 2837641d5fbeSbellard } 2838641d5fbeSbellard } 2839641d5fbeSbellard 2840f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory. */ 2841f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng) 2842f65a061cSRichard Henderson { 2843f65a061cSRichard Henderson int i; 2844f65a061cSRichard Henderson 2845f65a061cSRichard Henderson for (i = 0; i < ng; ++i) { 284625f49c5fSRichard Henderson int state = s->temps[i].state; 284725f49c5fSRichard Henderson s->temps[i].state = state | TS_MEM; 284825f49c5fSRichard Henderson if (state == TS_DEAD) { 284925f49c5fSRichard Henderson /* If the global was previously dead, reset prefs. */ 285025f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 285125f49c5fSRichard Henderson } 2852f65a061cSRichard Henderson } 2853f65a061cSRichard Henderson } 2854f65a061cSRichard Henderson 2855b4cb76e6SRichard Henderson /* 2856c7482438SRichard Henderson * liveness analysis: conditional branch: all temps are dead unless 2857c7482438SRichard Henderson * explicitly live-across-conditional-branch, globals and local temps 2858c7482438SRichard Henderson * should be synced. 2859b4cb76e6SRichard Henderson */ 2860b4cb76e6SRichard Henderson static void la_bb_sync(TCGContext *s, int ng, int nt) 2861b4cb76e6SRichard Henderson { 2862b4cb76e6SRichard Henderson la_global_sync(s, ng); 2863b4cb76e6SRichard Henderson 2864b4cb76e6SRichard Henderson for (int i = ng; i < nt; ++i) { 2865c0522136SRichard Henderson TCGTemp *ts = &s->temps[i]; 2866c0522136SRichard Henderson int state; 2867c0522136SRichard Henderson 2868c0522136SRichard Henderson switch (ts->kind) { 2869f57c6915SRichard Henderson case TEMP_TB: 2870c0522136SRichard Henderson state = ts->state; 2871c0522136SRichard Henderson ts->state = state | TS_MEM; 2872b4cb76e6SRichard Henderson if (state != TS_DEAD) { 2873b4cb76e6SRichard Henderson continue; 2874b4cb76e6SRichard Henderson } 2875c0522136SRichard Henderson break; 2876c7482438SRichard Henderson case TEMP_EBB: 2877c0522136SRichard Henderson case TEMP_CONST: 2878c0522136SRichard Henderson continue; 2879c0522136SRichard Henderson default: 2880c0522136SRichard Henderson g_assert_not_reached(); 2881b4cb76e6SRichard Henderson } 2882b4cb76e6SRichard Henderson la_reset_pref(&s->temps[i]); 2883b4cb76e6SRichard Henderson } 2884b4cb76e6SRichard Henderson } 2885b4cb76e6SRichard Henderson 2886f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill. */ 2887f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng) 2888f65a061cSRichard Henderson { 2889f65a061cSRichard Henderson int i; 2890f65a061cSRichard Henderson 2891f65a061cSRichard Henderson for (i = 0; i < ng; i++) { 2892f65a061cSRichard Henderson s->temps[i].state = TS_DEAD | TS_MEM; 289325f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 289425f49c5fSRichard Henderson } 289525f49c5fSRichard Henderson } 289625f49c5fSRichard Henderson 289725f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls. */ 289825f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt) 289925f49c5fSRichard Henderson { 290025f49c5fSRichard Henderson TCGRegSet mask = ~tcg_target_call_clobber_regs; 290125f49c5fSRichard Henderson int i; 290225f49c5fSRichard Henderson 290325f49c5fSRichard Henderson for (i = 0; i < nt; i++) { 290425f49c5fSRichard Henderson TCGTemp *ts = &s->temps[i]; 290525f49c5fSRichard Henderson if (!(ts->state & TS_DEAD)) { 290625f49c5fSRichard Henderson TCGRegSet *pset = la_temp_pref(ts); 290725f49c5fSRichard Henderson TCGRegSet set = *pset; 290825f49c5fSRichard Henderson 290925f49c5fSRichard Henderson set &= mask; 291025f49c5fSRichard Henderson /* If the combination is not possible, restart. */ 291125f49c5fSRichard Henderson if (set == 0) { 291225f49c5fSRichard Henderson set = tcg_target_available_regs[ts->type] & mask; 291325f49c5fSRichard Henderson } 291425f49c5fSRichard Henderson *pset = set; 291525f49c5fSRichard Henderson } 2916f65a061cSRichard Henderson } 2917f65a061cSRichard Henderson } 2918f65a061cSRichard Henderson 2919874b8574SRichard Henderson /* 2920874b8574SRichard Henderson * Liveness analysis: Verify the lifetime of TEMP_TB, and reduce 2921874b8574SRichard Henderson * to TEMP_EBB, if possible. 2922874b8574SRichard Henderson */ 2923874b8574SRichard Henderson static void __attribute__((noinline)) 2924874b8574SRichard Henderson liveness_pass_0(TCGContext *s) 2925874b8574SRichard Henderson { 2926874b8574SRichard Henderson void * const multiple_ebb = (void *)(uintptr_t)-1; 2927874b8574SRichard Henderson int nb_temps = s->nb_temps; 2928874b8574SRichard Henderson TCGOp *op, *ebb; 2929874b8574SRichard Henderson 2930874b8574SRichard Henderson for (int i = s->nb_globals; i < nb_temps; ++i) { 2931874b8574SRichard Henderson s->temps[i].state_ptr = NULL; 2932874b8574SRichard Henderson } 2933874b8574SRichard Henderson 2934874b8574SRichard Henderson /* 2935874b8574SRichard Henderson * Represent each EBB by the op at which it begins. In the case of 2936874b8574SRichard Henderson * the first EBB, this is the first op, otherwise it is a label. 2937874b8574SRichard Henderson * Collect the uses of each TEMP_TB: NULL for unused, EBB for use 2938874b8574SRichard Henderson * within a single EBB, else MULTIPLE_EBB. 2939874b8574SRichard Henderson */ 2940874b8574SRichard Henderson ebb = QTAILQ_FIRST(&s->ops); 2941874b8574SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 2942874b8574SRichard Henderson const TCGOpDef *def; 2943874b8574SRichard Henderson int nb_oargs, nb_iargs; 2944874b8574SRichard Henderson 2945874b8574SRichard Henderson switch (op->opc) { 2946874b8574SRichard Henderson case INDEX_op_set_label: 2947874b8574SRichard Henderson ebb = op; 2948874b8574SRichard Henderson continue; 2949874b8574SRichard Henderson case INDEX_op_discard: 2950874b8574SRichard Henderson continue; 2951874b8574SRichard Henderson case INDEX_op_call: 2952874b8574SRichard Henderson nb_oargs = TCGOP_CALLO(op); 2953874b8574SRichard Henderson nb_iargs = TCGOP_CALLI(op); 2954874b8574SRichard Henderson break; 2955874b8574SRichard Henderson default: 2956874b8574SRichard Henderson def = &tcg_op_defs[op->opc]; 2957874b8574SRichard Henderson nb_oargs = def->nb_oargs; 2958874b8574SRichard Henderson nb_iargs = def->nb_iargs; 2959874b8574SRichard Henderson break; 2960874b8574SRichard Henderson } 2961874b8574SRichard Henderson 2962874b8574SRichard Henderson for (int i = 0; i < nb_oargs + nb_iargs; ++i) { 2963874b8574SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]); 2964874b8574SRichard Henderson 2965874b8574SRichard Henderson if (ts->kind != TEMP_TB) { 2966874b8574SRichard Henderson continue; 2967874b8574SRichard Henderson } 2968874b8574SRichard Henderson if (ts->state_ptr == NULL) { 2969874b8574SRichard Henderson ts->state_ptr = ebb; 2970874b8574SRichard Henderson } else if (ts->state_ptr != ebb) { 2971874b8574SRichard Henderson ts->state_ptr = multiple_ebb; 2972874b8574SRichard Henderson } 2973874b8574SRichard Henderson } 2974874b8574SRichard Henderson } 2975874b8574SRichard Henderson 2976874b8574SRichard Henderson /* 2977874b8574SRichard Henderson * For TEMP_TB that turned out not to be used beyond one EBB, 2978874b8574SRichard Henderson * reduce the liveness to TEMP_EBB. 2979874b8574SRichard Henderson */ 2980874b8574SRichard Henderson for (int i = s->nb_globals; i < nb_temps; ++i) { 2981874b8574SRichard Henderson TCGTemp *ts = &s->temps[i]; 2982874b8574SRichard Henderson if (ts->kind == TEMP_TB && ts->state_ptr != multiple_ebb) { 2983874b8574SRichard Henderson ts->kind = TEMP_EBB; 2984874b8574SRichard Henderson } 2985874b8574SRichard Henderson } 2986874b8574SRichard Henderson } 2987874b8574SRichard Henderson 2988a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a 2989c896fe29Sbellard given input arguments is dead. Instructions updating dead 2990c896fe29Sbellard temporaries are removed. */ 29919bbee4c0SRichard Henderson static void __attribute__((noinline)) 29929bbee4c0SRichard Henderson liveness_pass_1(TCGContext *s) 2993c896fe29Sbellard { 2994c70fbf0aSRichard Henderson int nb_globals = s->nb_globals; 29952616c808SRichard Henderson int nb_temps = s->nb_temps; 299615fa08f8SRichard Henderson TCGOp *op, *op_prev; 299725f49c5fSRichard Henderson TCGRegSet *prefs; 299825f49c5fSRichard Henderson int i; 299925f49c5fSRichard Henderson 300025f49c5fSRichard Henderson prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps); 300125f49c5fSRichard Henderson for (i = 0; i < nb_temps; ++i) { 300225f49c5fSRichard Henderson s->temps[i].state_ptr = prefs + i; 300325f49c5fSRichard Henderson } 3004c896fe29Sbellard 3005ae36a246SRichard Henderson /* ??? Should be redundant with the exit_tb that ends the TB. */ 30062616c808SRichard Henderson la_func_end(s, nb_globals, nb_temps); 3007c896fe29Sbellard 3008eae3eb3eSPaolo Bonzini QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) { 300925f49c5fSRichard Henderson int nb_iargs, nb_oargs; 3010c45cb8bbSRichard Henderson TCGOpcode opc_new, opc_new2; 3011c45cb8bbSRichard Henderson bool have_opc_new2; 3012a1b3c48dSRichard Henderson TCGLifeData arg_life = 0; 301325f49c5fSRichard Henderson TCGTemp *ts; 3014c45cb8bbSRichard Henderson TCGOpcode opc = op->opc; 3015c45cb8bbSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 3016c45cb8bbSRichard Henderson 3017c45cb8bbSRichard Henderson switch (opc) { 3018c896fe29Sbellard case INDEX_op_call: 3019c6e113f5Sbellard { 302039004a71SRichard Henderson const TCGHelperInfo *info = tcg_call_info(op); 302139004a71SRichard Henderson int call_flags = tcg_call_flags(op); 3022c6e113f5Sbellard 3023cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 3024cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 3025c6e113f5Sbellard 3026c45cb8bbSRichard Henderson /* pure functions can be removed if their result is unused */ 302778505279SAurelien Jarno if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) { 3028c6e113f5Sbellard for (i = 0; i < nb_oargs; i++) { 302925f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 303025f49c5fSRichard Henderson if (ts->state != TS_DEAD) { 3031c6e113f5Sbellard goto do_not_remove_call; 3032c6e113f5Sbellard } 30339c43b68dSAurelien Jarno } 3034c45cb8bbSRichard Henderson goto do_remove; 3035152c35aaSRichard Henderson } 3036c6e113f5Sbellard do_not_remove_call: 3037c896fe29Sbellard 303825f49c5fSRichard Henderson /* Output args are dead. */ 3039c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 304025f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 304125f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 3042a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 30436b64b624SAurelien Jarno } 304425f49c5fSRichard Henderson if (ts->state & TS_MEM) { 3045a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i; 30469c43b68dSAurelien Jarno } 304725f49c5fSRichard Henderson ts->state = TS_DEAD; 304825f49c5fSRichard Henderson la_reset_pref(ts); 3049c896fe29Sbellard } 3050c896fe29Sbellard 305131fd884bSRichard Henderson /* Not used -- it will be tcg_target_call_oarg_reg(). */ 305231fd884bSRichard Henderson memset(op->output_pref, 0, sizeof(op->output_pref)); 305331fd884bSRichard Henderson 305478505279SAurelien Jarno if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS | 305578505279SAurelien Jarno TCG_CALL_NO_READ_GLOBALS))) { 3056f65a061cSRichard Henderson la_global_kill(s, nb_globals); 3057c70fbf0aSRichard Henderson } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) { 3058f65a061cSRichard Henderson la_global_sync(s, nb_globals); 3059b9c18f56Saurel32 } 3060c896fe29Sbellard 306125f49c5fSRichard Henderson /* Record arguments that die in this helper. */ 3062866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 306325f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 306439004a71SRichard Henderson if (ts->state & TS_DEAD) { 3065a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 3066c896fe29Sbellard } 3067c896fe29Sbellard } 306825f49c5fSRichard Henderson 306925f49c5fSRichard Henderson /* For all live registers, remove call-clobbered prefs. */ 307025f49c5fSRichard Henderson la_cross_call(s, nb_temps); 307125f49c5fSRichard Henderson 307239004a71SRichard Henderson /* 307339004a71SRichard Henderson * Input arguments are live for preceding opcodes. 307439004a71SRichard Henderson * 307539004a71SRichard Henderson * For those arguments that die, and will be allocated in 307639004a71SRichard Henderson * registers, clear the register set for that arg, to be 307739004a71SRichard Henderson * filled in below. For args that will be on the stack, 307839004a71SRichard Henderson * reset to any available reg. Process arguments in reverse 307939004a71SRichard Henderson * order so that if a temp is used more than once, the stack 308039004a71SRichard Henderson * reset to max happens before the register reset to 0. 308125f49c5fSRichard Henderson */ 308239004a71SRichard Henderson for (i = nb_iargs - 1; i >= 0; i--) { 308339004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i]; 308439004a71SRichard Henderson ts = arg_temp(op->args[nb_oargs + i]); 308539004a71SRichard Henderson 308639004a71SRichard Henderson if (ts->state & TS_DEAD) { 308739004a71SRichard Henderson switch (loc->kind) { 308839004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 308939004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 309039004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 309139004a71SRichard Henderson if (REG_P(loc)) { 309239004a71SRichard Henderson *la_temp_pref(ts) = 0; 309339004a71SRichard Henderson break; 309439004a71SRichard Henderson } 309539004a71SRichard Henderson /* fall through */ 309639004a71SRichard Henderson default: 309739004a71SRichard Henderson *la_temp_pref(ts) = 309839004a71SRichard Henderson tcg_target_available_regs[ts->type]; 309939004a71SRichard Henderson break; 310039004a71SRichard Henderson } 310125f49c5fSRichard Henderson ts->state &= ~TS_DEAD; 310225f49c5fSRichard Henderson } 310325f49c5fSRichard Henderson } 310425f49c5fSRichard Henderson 310539004a71SRichard Henderson /* 310639004a71SRichard Henderson * For each input argument, add its input register to prefs. 310739004a71SRichard Henderson * If a temp is used once, this produces a single set bit; 310839004a71SRichard Henderson * if a temp is used multiple times, this produces a set. 310939004a71SRichard Henderson */ 311039004a71SRichard Henderson for (i = 0; i < nb_iargs; i++) { 311139004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i]; 311239004a71SRichard Henderson ts = arg_temp(op->args[nb_oargs + i]); 311339004a71SRichard Henderson 311439004a71SRichard Henderson switch (loc->kind) { 311539004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 311639004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 311739004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 311839004a71SRichard Henderson if (REG_P(loc)) { 311925f49c5fSRichard Henderson tcg_regset_set_reg(*la_temp_pref(ts), 312039004a71SRichard Henderson tcg_target_call_iarg_regs[loc->arg_slot]); 312139004a71SRichard Henderson } 312239004a71SRichard Henderson break; 312339004a71SRichard Henderson default: 312439004a71SRichard Henderson break; 3125c70fbf0aSRichard Henderson } 3126c19f47bfSAurelien Jarno } 3127c6e113f5Sbellard } 3128c896fe29Sbellard break; 3129765b842aSRichard Henderson case INDEX_op_insn_start: 3130c896fe29Sbellard break; 31315ff9d6a4Sbellard case INDEX_op_discard: 31325ff9d6a4Sbellard /* mark the temporary as dead */ 313325f49c5fSRichard Henderson ts = arg_temp(op->args[0]); 313425f49c5fSRichard Henderson ts->state = TS_DEAD; 313525f49c5fSRichard Henderson la_reset_pref(ts); 31365ff9d6a4Sbellard break; 31371305c451SRichard Henderson 31381305c451SRichard Henderson case INDEX_op_add2_i32: 3139c45cb8bbSRichard Henderson opc_new = INDEX_op_add_i32; 3140f1fae40cSRichard Henderson goto do_addsub2; 31411305c451SRichard Henderson case INDEX_op_sub2_i32: 3142c45cb8bbSRichard Henderson opc_new = INDEX_op_sub_i32; 3143f1fae40cSRichard Henderson goto do_addsub2; 3144f1fae40cSRichard Henderson case INDEX_op_add2_i64: 3145c45cb8bbSRichard Henderson opc_new = INDEX_op_add_i64; 3146f1fae40cSRichard Henderson goto do_addsub2; 3147f1fae40cSRichard Henderson case INDEX_op_sub2_i64: 3148c45cb8bbSRichard Henderson opc_new = INDEX_op_sub_i64; 3149f1fae40cSRichard Henderson do_addsub2: 31501305c451SRichard Henderson nb_iargs = 4; 31511305c451SRichard Henderson nb_oargs = 2; 31521305c451SRichard Henderson /* Test if the high part of the operation is dead, but not 31531305c451SRichard Henderson the low part. The result can be optimized to a simple 31541305c451SRichard Henderson add or sub. This happens often for x86_64 guest when the 31551305c451SRichard Henderson cpu mode is set to 32 bit. */ 3156b83eabeaSRichard Henderson if (arg_temp(op->args[1])->state == TS_DEAD) { 3157b83eabeaSRichard Henderson if (arg_temp(op->args[0])->state == TS_DEAD) { 31581305c451SRichard Henderson goto do_remove; 31591305c451SRichard Henderson } 3160c45cb8bbSRichard Henderson /* Replace the opcode and adjust the args in place, 3161c45cb8bbSRichard Henderson leaving 3 unused args at the end. */ 3162c45cb8bbSRichard Henderson op->opc = opc = opc_new; 3163efee3746SRichard Henderson op->args[1] = op->args[2]; 3164efee3746SRichard Henderson op->args[2] = op->args[4]; 31651305c451SRichard Henderson /* Fall through and mark the single-word operation live. */ 31661305c451SRichard Henderson nb_iargs = 2; 31671305c451SRichard Henderson nb_oargs = 1; 31681305c451SRichard Henderson } 31691305c451SRichard Henderson goto do_not_remove; 31701305c451SRichard Henderson 31711414968aSRichard Henderson case INDEX_op_mulu2_i32: 3172c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i32; 3173c45cb8bbSRichard Henderson opc_new2 = INDEX_op_muluh_i32; 3174c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_muluh_i32; 317503271524SRichard Henderson goto do_mul2; 3176f1fae40cSRichard Henderson case INDEX_op_muls2_i32: 3177c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i32; 3178c45cb8bbSRichard Henderson opc_new2 = INDEX_op_mulsh_i32; 3179c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_mulsh_i32; 3180f1fae40cSRichard Henderson goto do_mul2; 3181f1fae40cSRichard Henderson case INDEX_op_mulu2_i64: 3182c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i64; 3183c45cb8bbSRichard Henderson opc_new2 = INDEX_op_muluh_i64; 3184c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_muluh_i64; 318503271524SRichard Henderson goto do_mul2; 3186f1fae40cSRichard Henderson case INDEX_op_muls2_i64: 3187c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i64; 3188c45cb8bbSRichard Henderson opc_new2 = INDEX_op_mulsh_i64; 3189c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_mulsh_i64; 319003271524SRichard Henderson goto do_mul2; 3191f1fae40cSRichard Henderson do_mul2: 31921414968aSRichard Henderson nb_iargs = 2; 31931414968aSRichard Henderson nb_oargs = 2; 3194b83eabeaSRichard Henderson if (arg_temp(op->args[1])->state == TS_DEAD) { 3195b83eabeaSRichard Henderson if (arg_temp(op->args[0])->state == TS_DEAD) { 319603271524SRichard Henderson /* Both parts of the operation are dead. */ 31971414968aSRichard Henderson goto do_remove; 31981414968aSRichard Henderson } 319903271524SRichard Henderson /* The high part of the operation is dead; generate the low. */ 3200c45cb8bbSRichard Henderson op->opc = opc = opc_new; 3201efee3746SRichard Henderson op->args[1] = op->args[2]; 3202efee3746SRichard Henderson op->args[2] = op->args[3]; 3203b83eabeaSRichard Henderson } else if (arg_temp(op->args[0])->state == TS_DEAD && have_opc_new2) { 320403271524SRichard Henderson /* The low part of the operation is dead; generate the high. */ 3205c45cb8bbSRichard Henderson op->opc = opc = opc_new2; 3206efee3746SRichard Henderson op->args[0] = op->args[1]; 3207efee3746SRichard Henderson op->args[1] = op->args[2]; 3208efee3746SRichard Henderson op->args[2] = op->args[3]; 320903271524SRichard Henderson } else { 321003271524SRichard Henderson goto do_not_remove; 321103271524SRichard Henderson } 321203271524SRichard Henderson /* Mark the single-word operation live. */ 32131414968aSRichard Henderson nb_oargs = 1; 32141414968aSRichard Henderson goto do_not_remove; 32151414968aSRichard Henderson 3216c896fe29Sbellard default: 32171305c451SRichard Henderson /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */ 3218c896fe29Sbellard nb_iargs = def->nb_iargs; 3219c896fe29Sbellard nb_oargs = def->nb_oargs; 3220c896fe29Sbellard 3221c896fe29Sbellard /* Test if the operation can be removed because all 32225ff9d6a4Sbellard its outputs are dead. We assume that nb_oargs == 0 32235ff9d6a4Sbellard implies side effects */ 32245ff9d6a4Sbellard if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) { 3225c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 3226b83eabeaSRichard Henderson if (arg_temp(op->args[i])->state != TS_DEAD) { 3227c896fe29Sbellard goto do_not_remove; 3228c896fe29Sbellard } 32299c43b68dSAurelien Jarno } 3230152c35aaSRichard Henderson goto do_remove; 3231152c35aaSRichard Henderson } 3232152c35aaSRichard Henderson goto do_not_remove; 3233152c35aaSRichard Henderson 32341305c451SRichard Henderson do_remove: 32350c627cdcSRichard Henderson tcg_op_remove(s, op); 3236152c35aaSRichard Henderson break; 3237152c35aaSRichard Henderson 3238c896fe29Sbellard do_not_remove: 3239c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 324025f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 324125f49c5fSRichard Henderson 324225f49c5fSRichard Henderson /* Remember the preference of the uses that followed. */ 324331fd884bSRichard Henderson if (i < ARRAY_SIZE(op->output_pref)) { 324425f49c5fSRichard Henderson op->output_pref[i] = *la_temp_pref(ts); 324531fd884bSRichard Henderson } 324625f49c5fSRichard Henderson 324725f49c5fSRichard Henderson /* Output args are dead. */ 324825f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 3249a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 32506b64b624SAurelien Jarno } 325125f49c5fSRichard Henderson if (ts->state & TS_MEM) { 3252a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i; 32539c43b68dSAurelien Jarno } 325425f49c5fSRichard Henderson ts->state = TS_DEAD; 325525f49c5fSRichard Henderson la_reset_pref(ts); 3256c896fe29Sbellard } 3257c896fe29Sbellard 325825f49c5fSRichard Henderson /* If end of basic block, update. */ 3259ae36a246SRichard Henderson if (def->flags & TCG_OPF_BB_EXIT) { 3260ae36a246SRichard Henderson la_func_end(s, nb_globals, nb_temps); 3261b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_COND_BRANCH) { 3262b4cb76e6SRichard Henderson la_bb_sync(s, nb_globals, nb_temps); 3263ae36a246SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 32642616c808SRichard Henderson la_bb_end(s, nb_globals, nb_temps); 32653d5c5f87SAurelien Jarno } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { 3266f65a061cSRichard Henderson la_global_sync(s, nb_globals); 326725f49c5fSRichard Henderson if (def->flags & TCG_OPF_CALL_CLOBBER) { 326825f49c5fSRichard Henderson la_cross_call(s, nb_temps); 326925f49c5fSRichard Henderson } 3270c896fe29Sbellard } 3271c896fe29Sbellard 327225f49c5fSRichard Henderson /* Record arguments that die in this opcode. */ 3273866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 327425f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 327525f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 3276a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 3277c896fe29Sbellard } 3278c19f47bfSAurelien Jarno } 327925f49c5fSRichard Henderson 328025f49c5fSRichard Henderson /* Input arguments are live for preceding opcodes. */ 3281c19f47bfSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 328225f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 328325f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 328425f49c5fSRichard Henderson /* For operands that were dead, initially allow 328525f49c5fSRichard Henderson all regs for the type. */ 328625f49c5fSRichard Henderson *la_temp_pref(ts) = tcg_target_available_regs[ts->type]; 328725f49c5fSRichard Henderson ts->state &= ~TS_DEAD; 328825f49c5fSRichard Henderson } 328925f49c5fSRichard Henderson } 329025f49c5fSRichard Henderson 329125f49c5fSRichard Henderson /* Incorporate constraints for this operand. */ 329225f49c5fSRichard Henderson switch (opc) { 329325f49c5fSRichard Henderson case INDEX_op_mov_i32: 329425f49c5fSRichard Henderson case INDEX_op_mov_i64: 329525f49c5fSRichard Henderson /* Note that these are TCG_OPF_NOT_PRESENT and do not 329625f49c5fSRichard Henderson have proper constraints. That said, special case 329725f49c5fSRichard Henderson moves to propagate preferences backward. */ 329825f49c5fSRichard Henderson if (IS_DEAD_ARG(1)) { 329925f49c5fSRichard Henderson *la_temp_pref(arg_temp(op->args[0])) 330025f49c5fSRichard Henderson = *la_temp_pref(arg_temp(op->args[1])); 330125f49c5fSRichard Henderson } 330225f49c5fSRichard Henderson break; 330325f49c5fSRichard Henderson 330425f49c5fSRichard Henderson default: 330525f49c5fSRichard Henderson for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 330625f49c5fSRichard Henderson const TCGArgConstraint *ct = &def->args_ct[i]; 330725f49c5fSRichard Henderson TCGRegSet set, *pset; 330825f49c5fSRichard Henderson 330925f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 331025f49c5fSRichard Henderson pset = la_temp_pref(ts); 331125f49c5fSRichard Henderson set = *pset; 331225f49c5fSRichard Henderson 33139be0d080SRichard Henderson set &= ct->regs; 3314bc2b17e6SRichard Henderson if (ct->ialias) { 331531fd884bSRichard Henderson set &= output_pref(op, ct->alias_index); 331625f49c5fSRichard Henderson } 331725f49c5fSRichard Henderson /* If the combination is not possible, restart. */ 331825f49c5fSRichard Henderson if (set == 0) { 33199be0d080SRichard Henderson set = ct->regs; 332025f49c5fSRichard Henderson } 332125f49c5fSRichard Henderson *pset = set; 332225f49c5fSRichard Henderson } 332325f49c5fSRichard Henderson break; 3324c896fe29Sbellard } 3325c896fe29Sbellard break; 3326c896fe29Sbellard } 3327bee158cbSRichard Henderson op->life = arg_life; 3328c896fe29Sbellard } 33291ff0a2c5SEvgeny Voevodin } 3330c896fe29Sbellard 33315a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries. */ 33329bbee4c0SRichard Henderson static bool __attribute__((noinline)) 33339bbee4c0SRichard Henderson liveness_pass_2(TCGContext *s) 33345a18407fSRichard Henderson { 33355a18407fSRichard Henderson int nb_globals = s->nb_globals; 333615fa08f8SRichard Henderson int nb_temps, i; 33375a18407fSRichard Henderson bool changes = false; 333815fa08f8SRichard Henderson TCGOp *op, *op_next; 33395a18407fSRichard Henderson 33405a18407fSRichard Henderson /* Create a temporary for each indirect global. */ 33415a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 33425a18407fSRichard Henderson TCGTemp *its = &s->temps[i]; 33435a18407fSRichard Henderson if (its->indirect_reg) { 33445a18407fSRichard Henderson TCGTemp *dts = tcg_temp_alloc(s); 33455a18407fSRichard Henderson dts->type = its->type; 33465a18407fSRichard Henderson dts->base_type = its->base_type; 3347e1e64652SRichard Henderson dts->temp_subindex = its->temp_subindex; 3348c7482438SRichard Henderson dts->kind = TEMP_EBB; 3349b83eabeaSRichard Henderson its->state_ptr = dts; 3350b83eabeaSRichard Henderson } else { 3351b83eabeaSRichard Henderson its->state_ptr = NULL; 33525a18407fSRichard Henderson } 3353b83eabeaSRichard Henderson /* All globals begin dead. */ 3354b83eabeaSRichard Henderson its->state = TS_DEAD; 33555a18407fSRichard Henderson } 3356b83eabeaSRichard Henderson for (nb_temps = s->nb_temps; i < nb_temps; ++i) { 3357b83eabeaSRichard Henderson TCGTemp *its = &s->temps[i]; 3358b83eabeaSRichard Henderson its->state_ptr = NULL; 3359b83eabeaSRichard Henderson its->state = TS_DEAD; 3360b83eabeaSRichard Henderson } 33615a18407fSRichard Henderson 336215fa08f8SRichard Henderson QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) { 33635a18407fSRichard Henderson TCGOpcode opc = op->opc; 33645a18407fSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 33655a18407fSRichard Henderson TCGLifeData arg_life = op->life; 33665a18407fSRichard Henderson int nb_iargs, nb_oargs, call_flags; 3367b83eabeaSRichard Henderson TCGTemp *arg_ts, *dir_ts; 33685a18407fSRichard Henderson 33695a18407fSRichard Henderson if (opc == INDEX_op_call) { 3370cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 3371cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 337290163900SRichard Henderson call_flags = tcg_call_flags(op); 33735a18407fSRichard Henderson } else { 33745a18407fSRichard Henderson nb_iargs = def->nb_iargs; 33755a18407fSRichard Henderson nb_oargs = def->nb_oargs; 33765a18407fSRichard Henderson 33775a18407fSRichard Henderson /* Set flags similar to how calls require. */ 3378b4cb76e6SRichard Henderson if (def->flags & TCG_OPF_COND_BRANCH) { 3379b4cb76e6SRichard Henderson /* Like reading globals: sync_globals */ 3380b4cb76e6SRichard Henderson call_flags = TCG_CALL_NO_WRITE_GLOBALS; 3381b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 33825a18407fSRichard Henderson /* Like writing globals: save_globals */ 33835a18407fSRichard Henderson call_flags = 0; 33845a18407fSRichard Henderson } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { 33855a18407fSRichard Henderson /* Like reading globals: sync_globals */ 33865a18407fSRichard Henderson call_flags = TCG_CALL_NO_WRITE_GLOBALS; 33875a18407fSRichard Henderson } else { 33885a18407fSRichard Henderson /* No effect on globals. */ 33895a18407fSRichard Henderson call_flags = (TCG_CALL_NO_READ_GLOBALS | 33905a18407fSRichard Henderson TCG_CALL_NO_WRITE_GLOBALS); 33915a18407fSRichard Henderson } 33925a18407fSRichard Henderson } 33935a18407fSRichard Henderson 33945a18407fSRichard Henderson /* Make sure that input arguments are available. */ 33955a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 3396b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 3397b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 3398b83eabeaSRichard Henderson if (dir_ts && arg_ts->state == TS_DEAD) { 3399b83eabeaSRichard Henderson TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32 34005a18407fSRichard Henderson ? INDEX_op_ld_i32 34015a18407fSRichard Henderson : INDEX_op_ld_i64); 3402d4478943SPhilippe Mathieu-Daudé TCGOp *lop = tcg_op_insert_before(s, op, lopc, 3); 34035a18407fSRichard Henderson 3404b83eabeaSRichard Henderson lop->args[0] = temp_arg(dir_ts); 3405b83eabeaSRichard Henderson lop->args[1] = temp_arg(arg_ts->mem_base); 3406b83eabeaSRichard Henderson lop->args[2] = arg_ts->mem_offset; 34075a18407fSRichard Henderson 34085a18407fSRichard Henderson /* Loaded, but synced with memory. */ 3409b83eabeaSRichard Henderson arg_ts->state = TS_MEM; 34105a18407fSRichard Henderson } 34115a18407fSRichard Henderson } 34125a18407fSRichard Henderson 34135a18407fSRichard Henderson /* Perform input replacement, and mark inputs that became dead. 34145a18407fSRichard Henderson No action is required except keeping temp_state up to date 34155a18407fSRichard Henderson so that we reload when needed. */ 34165a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 3417b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 3418b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 3419b83eabeaSRichard Henderson if (dir_ts) { 3420b83eabeaSRichard Henderson op->args[i] = temp_arg(dir_ts); 34215a18407fSRichard Henderson changes = true; 34225a18407fSRichard Henderson if (IS_DEAD_ARG(i)) { 3423b83eabeaSRichard Henderson arg_ts->state = TS_DEAD; 34245a18407fSRichard Henderson } 34255a18407fSRichard Henderson } 34265a18407fSRichard Henderson } 34275a18407fSRichard Henderson 34285a18407fSRichard Henderson /* Liveness analysis should ensure that the following are 34295a18407fSRichard Henderson all correct, for call sites and basic block end points. */ 34305a18407fSRichard Henderson if (call_flags & TCG_CALL_NO_READ_GLOBALS) { 34315a18407fSRichard Henderson /* Nothing to do */ 34325a18407fSRichard Henderson } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) { 34335a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 34345a18407fSRichard Henderson /* Liveness should see that globals are synced back, 34355a18407fSRichard Henderson that is, either TS_DEAD or TS_MEM. */ 3436b83eabeaSRichard Henderson arg_ts = &s->temps[i]; 3437b83eabeaSRichard Henderson tcg_debug_assert(arg_ts->state_ptr == 0 3438b83eabeaSRichard Henderson || arg_ts->state != 0); 34395a18407fSRichard Henderson } 34405a18407fSRichard Henderson } else { 34415a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 34425a18407fSRichard Henderson /* Liveness should see that globals are saved back, 34435a18407fSRichard Henderson that is, TS_DEAD, waiting to be reloaded. */ 3444b83eabeaSRichard Henderson arg_ts = &s->temps[i]; 3445b83eabeaSRichard Henderson tcg_debug_assert(arg_ts->state_ptr == 0 3446b83eabeaSRichard Henderson || arg_ts->state == TS_DEAD); 34475a18407fSRichard Henderson } 34485a18407fSRichard Henderson } 34495a18407fSRichard Henderson 34505a18407fSRichard Henderson /* Outputs become available. */ 345161f15c48SRichard Henderson if (opc == INDEX_op_mov_i32 || opc == INDEX_op_mov_i64) { 345261f15c48SRichard Henderson arg_ts = arg_temp(op->args[0]); 345361f15c48SRichard Henderson dir_ts = arg_ts->state_ptr; 345461f15c48SRichard Henderson if (dir_ts) { 345561f15c48SRichard Henderson op->args[0] = temp_arg(dir_ts); 345661f15c48SRichard Henderson changes = true; 345761f15c48SRichard Henderson 345861f15c48SRichard Henderson /* The output is now live and modified. */ 345961f15c48SRichard Henderson arg_ts->state = 0; 346061f15c48SRichard Henderson 346161f15c48SRichard Henderson if (NEED_SYNC_ARG(0)) { 346261f15c48SRichard Henderson TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 346361f15c48SRichard Henderson ? INDEX_op_st_i32 346461f15c48SRichard Henderson : INDEX_op_st_i64); 3465d4478943SPhilippe Mathieu-Daudé TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3); 346661f15c48SRichard Henderson TCGTemp *out_ts = dir_ts; 346761f15c48SRichard Henderson 346861f15c48SRichard Henderson if (IS_DEAD_ARG(0)) { 346961f15c48SRichard Henderson out_ts = arg_temp(op->args[1]); 347061f15c48SRichard Henderson arg_ts->state = TS_DEAD; 347161f15c48SRichard Henderson tcg_op_remove(s, op); 347261f15c48SRichard Henderson } else { 347361f15c48SRichard Henderson arg_ts->state = TS_MEM; 347461f15c48SRichard Henderson } 347561f15c48SRichard Henderson 347661f15c48SRichard Henderson sop->args[0] = temp_arg(out_ts); 347761f15c48SRichard Henderson sop->args[1] = temp_arg(arg_ts->mem_base); 347861f15c48SRichard Henderson sop->args[2] = arg_ts->mem_offset; 347961f15c48SRichard Henderson } else { 348061f15c48SRichard Henderson tcg_debug_assert(!IS_DEAD_ARG(0)); 348161f15c48SRichard Henderson } 348261f15c48SRichard Henderson } 348361f15c48SRichard Henderson } else { 34845a18407fSRichard Henderson for (i = 0; i < nb_oargs; i++) { 3485b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 3486b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 3487b83eabeaSRichard Henderson if (!dir_ts) { 34885a18407fSRichard Henderson continue; 34895a18407fSRichard Henderson } 3490b83eabeaSRichard Henderson op->args[i] = temp_arg(dir_ts); 34915a18407fSRichard Henderson changes = true; 34925a18407fSRichard Henderson 34935a18407fSRichard Henderson /* The output is now live and modified. */ 3494b83eabeaSRichard Henderson arg_ts->state = 0; 34955a18407fSRichard Henderson 34965a18407fSRichard Henderson /* Sync outputs upon their last write. */ 34975a18407fSRichard Henderson if (NEED_SYNC_ARG(i)) { 3498b83eabeaSRichard Henderson TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 34995a18407fSRichard Henderson ? INDEX_op_st_i32 35005a18407fSRichard Henderson : INDEX_op_st_i64); 3501d4478943SPhilippe Mathieu-Daudé TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3); 35025a18407fSRichard Henderson 3503b83eabeaSRichard Henderson sop->args[0] = temp_arg(dir_ts); 3504b83eabeaSRichard Henderson sop->args[1] = temp_arg(arg_ts->mem_base); 3505b83eabeaSRichard Henderson sop->args[2] = arg_ts->mem_offset; 35065a18407fSRichard Henderson 3507b83eabeaSRichard Henderson arg_ts->state = TS_MEM; 35085a18407fSRichard Henderson } 35095a18407fSRichard Henderson /* Drop outputs that are dead. */ 35105a18407fSRichard Henderson if (IS_DEAD_ARG(i)) { 3511b83eabeaSRichard Henderson arg_ts->state = TS_DEAD; 35125a18407fSRichard Henderson } 35135a18407fSRichard Henderson } 35145a18407fSRichard Henderson } 351561f15c48SRichard Henderson } 35165a18407fSRichard Henderson 35175a18407fSRichard Henderson return changes; 35185a18407fSRichard Henderson } 35195a18407fSRichard Henderson 35202272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts) 3521c896fe29Sbellard { 352231c96417SRichard Henderson intptr_t off; 3523273eb50cSRichard Henderson int size, align; 3524c1c09194SRichard Henderson 3525273eb50cSRichard Henderson /* When allocating an object, look at the full type. */ 3526273eb50cSRichard Henderson size = tcg_type_size(ts->base_type); 3527273eb50cSRichard Henderson switch (ts->base_type) { 3528c1c09194SRichard Henderson case TCG_TYPE_I32: 352931c96417SRichard Henderson align = 4; 3530c1c09194SRichard Henderson break; 3531c1c09194SRichard Henderson case TCG_TYPE_I64: 3532c1c09194SRichard Henderson case TCG_TYPE_V64: 353331c96417SRichard Henderson align = 8; 3534c1c09194SRichard Henderson break; 353543eef72fSRichard Henderson case TCG_TYPE_I128: 3536c1c09194SRichard Henderson case TCG_TYPE_V128: 3537c1c09194SRichard Henderson case TCG_TYPE_V256: 353843eef72fSRichard Henderson /* 353943eef72fSRichard Henderson * Note that we do not require aligned storage for V256, 354043eef72fSRichard Henderson * and that we provide alignment for I128 to match V128, 354143eef72fSRichard Henderson * even if that's above what the host ABI requires. 354243eef72fSRichard Henderson */ 354331c96417SRichard Henderson align = 16; 3544c1c09194SRichard Henderson break; 3545c1c09194SRichard Henderson default: 3546c1c09194SRichard Henderson g_assert_not_reached(); 3547b591dc59SBlue Swirl } 3548c1c09194SRichard Henderson 3549b9537d59SRichard Henderson /* 3550b9537d59SRichard Henderson * Assume the stack is sufficiently aligned. 3551b9537d59SRichard Henderson * This affects e.g. ARM NEON, where we have 8 byte stack alignment 3552b9537d59SRichard Henderson * and do not require 16 byte vector alignment. This seems slightly 3553b9537d59SRichard Henderson * easier than fully parameterizing the above switch statement. 3554b9537d59SRichard Henderson */ 3555b9537d59SRichard Henderson align = MIN(TCG_TARGET_STACK_ALIGN, align); 3556c1c09194SRichard Henderson off = ROUND_UP(s->current_frame_offset, align); 3557732d5897SRichard Henderson 3558732d5897SRichard Henderson /* If we've exhausted the stack frame, restart with a smaller TB. */ 3559732d5897SRichard Henderson if (off + size > s->frame_end) { 3560732d5897SRichard Henderson tcg_raise_tb_overflow(s); 3561732d5897SRichard Henderson } 3562c1c09194SRichard Henderson s->current_frame_offset = off + size; 35639defd1bdSRichard Henderson #if defined(__sparc__) 3564273eb50cSRichard Henderson off += TCG_TARGET_STACK_BIAS; 35659defd1bdSRichard Henderson #endif 3566273eb50cSRichard Henderson 3567273eb50cSRichard Henderson /* If the object was subdivided, assign memory to all the parts. */ 3568273eb50cSRichard Henderson if (ts->base_type != ts->type) { 3569273eb50cSRichard Henderson int part_size = tcg_type_size(ts->type); 3570273eb50cSRichard Henderson int part_count = size / part_size; 3571273eb50cSRichard Henderson 3572273eb50cSRichard Henderson /* 3573273eb50cSRichard Henderson * Each part is allocated sequentially in tcg_temp_new_internal. 3574273eb50cSRichard Henderson * Jump back to the first part by subtracting the current index. 3575273eb50cSRichard Henderson */ 3576273eb50cSRichard Henderson ts -= ts->temp_subindex; 3577273eb50cSRichard Henderson for (int i = 0; i < part_count; ++i) { 3578273eb50cSRichard Henderson ts[i].mem_offset = off + i * part_size; 3579273eb50cSRichard Henderson ts[i].mem_base = s->frame_temp; 3580273eb50cSRichard Henderson ts[i].mem_allocated = 1; 3581273eb50cSRichard Henderson } 3582273eb50cSRichard Henderson } else { 3583273eb50cSRichard Henderson ts->mem_offset = off; 3584b3a62939SRichard Henderson ts->mem_base = s->frame_temp; 3585c896fe29Sbellard ts->mem_allocated = 1; 3586c896fe29Sbellard } 3587273eb50cSRichard Henderson } 3588c896fe29Sbellard 3589098859f1SRichard Henderson /* Assign @reg to @ts, and update reg_to_temp[]. */ 3590098859f1SRichard Henderson static void set_temp_val_reg(TCGContext *s, TCGTemp *ts, TCGReg reg) 3591098859f1SRichard Henderson { 3592098859f1SRichard Henderson if (ts->val_type == TEMP_VAL_REG) { 3593098859f1SRichard Henderson TCGReg old = ts->reg; 3594098859f1SRichard Henderson tcg_debug_assert(s->reg_to_temp[old] == ts); 3595098859f1SRichard Henderson if (old == reg) { 3596098859f1SRichard Henderson return; 3597098859f1SRichard Henderson } 3598098859f1SRichard Henderson s->reg_to_temp[old] = NULL; 3599098859f1SRichard Henderson } 3600098859f1SRichard Henderson tcg_debug_assert(s->reg_to_temp[reg] == NULL); 3601098859f1SRichard Henderson s->reg_to_temp[reg] = ts; 3602098859f1SRichard Henderson ts->val_type = TEMP_VAL_REG; 3603098859f1SRichard Henderson ts->reg = reg; 3604098859f1SRichard Henderson } 3605098859f1SRichard Henderson 3606098859f1SRichard Henderson /* Assign a non-register value type to @ts, and update reg_to_temp[]. */ 3607098859f1SRichard Henderson static void set_temp_val_nonreg(TCGContext *s, TCGTemp *ts, TCGTempVal type) 3608098859f1SRichard Henderson { 3609098859f1SRichard Henderson tcg_debug_assert(type != TEMP_VAL_REG); 3610098859f1SRichard Henderson if (ts->val_type == TEMP_VAL_REG) { 3611098859f1SRichard Henderson TCGReg reg = ts->reg; 3612098859f1SRichard Henderson tcg_debug_assert(s->reg_to_temp[reg] == ts); 3613098859f1SRichard Henderson s->reg_to_temp[reg] = NULL; 3614098859f1SRichard Henderson } 3615098859f1SRichard Henderson ts->val_type = type; 3616098859f1SRichard Henderson } 3617098859f1SRichard Henderson 3618b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet); 3619b3915dbbSRichard Henderson 362059d7c14eSRichard Henderson /* Mark a temporary as free or dead. If 'free_or_dead' is negative, 362159d7c14eSRichard Henderson mark it free; otherwise mark it dead. */ 362259d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead) 3623c896fe29Sbellard { 3624c0522136SRichard Henderson TCGTempVal new_type; 3625c0522136SRichard Henderson 3626c0522136SRichard Henderson switch (ts->kind) { 3627c0522136SRichard Henderson case TEMP_FIXED: 362859d7c14eSRichard Henderson return; 3629c0522136SRichard Henderson case TEMP_GLOBAL: 3630f57c6915SRichard Henderson case TEMP_TB: 3631c0522136SRichard Henderson new_type = TEMP_VAL_MEM; 3632c0522136SRichard Henderson break; 3633c7482438SRichard Henderson case TEMP_EBB: 3634c0522136SRichard Henderson new_type = free_or_dead < 0 ? TEMP_VAL_MEM : TEMP_VAL_DEAD; 3635c0522136SRichard Henderson break; 3636c0522136SRichard Henderson case TEMP_CONST: 3637c0522136SRichard Henderson new_type = TEMP_VAL_CONST; 3638c0522136SRichard Henderson break; 3639c0522136SRichard Henderson default: 3640c0522136SRichard Henderson g_assert_not_reached(); 364159d7c14eSRichard Henderson } 3642098859f1SRichard Henderson set_temp_val_nonreg(s, ts, new_type); 364359d7c14eSRichard Henderson } 3644c896fe29Sbellard 364559d7c14eSRichard Henderson /* Mark a temporary as dead. */ 364659d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts) 364759d7c14eSRichard Henderson { 364859d7c14eSRichard Henderson temp_free_or_dead(s, ts, 1); 364959d7c14eSRichard Henderson } 365059d7c14eSRichard Henderson 365159d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary 365259d7c14eSRichard Henderson registers needs to be allocated to store a constant. If 'free_or_dead' 365359d7c14eSRichard Henderson is non-zero, subsequently release the temporary; if it is positive, the 365459d7c14eSRichard Henderson temp is dead; if it is negative, the temp is free. */ 365598b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs, 365698b4e186SRichard Henderson TCGRegSet preferred_regs, int free_or_dead) 365759d7c14eSRichard Henderson { 3658c0522136SRichard Henderson if (!temp_readonly(ts) && !ts->mem_coherent) { 36597f6ceedfSAurelien Jarno if (!ts->mem_allocated) { 36602272e4a7SRichard Henderson temp_allocate_frame(s, ts); 366159d7c14eSRichard Henderson } 366259d7c14eSRichard Henderson switch (ts->val_type) { 366359d7c14eSRichard Henderson case TEMP_VAL_CONST: 366459d7c14eSRichard Henderson /* If we're going to free the temp immediately, then we won't 366559d7c14eSRichard Henderson require it later in a register, so attempt to store the 366659d7c14eSRichard Henderson constant to memory directly. */ 366759d7c14eSRichard Henderson if (free_or_dead 366859d7c14eSRichard Henderson && tcg_out_sti(s, ts->type, ts->val, 366959d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset)) { 367059d7c14eSRichard Henderson break; 367159d7c14eSRichard Henderson } 367259d7c14eSRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 367398b4e186SRichard Henderson allocated_regs, preferred_regs); 367459d7c14eSRichard Henderson /* fallthrough */ 367559d7c14eSRichard Henderson 367659d7c14eSRichard Henderson case TEMP_VAL_REG: 367759d7c14eSRichard Henderson tcg_out_st(s, ts->type, ts->reg, 367859d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset); 367959d7c14eSRichard Henderson break; 368059d7c14eSRichard Henderson 368159d7c14eSRichard Henderson case TEMP_VAL_MEM: 368259d7c14eSRichard Henderson break; 368359d7c14eSRichard Henderson 368459d7c14eSRichard Henderson case TEMP_VAL_DEAD: 368559d7c14eSRichard Henderson default: 3686732e89f4SRichard Henderson g_assert_not_reached(); 3687c896fe29Sbellard } 36887f6ceedfSAurelien Jarno ts->mem_coherent = 1; 36897f6ceedfSAurelien Jarno } 369059d7c14eSRichard Henderson if (free_or_dead) { 369159d7c14eSRichard Henderson temp_free_or_dead(s, ts, free_or_dead); 369259d7c14eSRichard Henderson } 369359d7c14eSRichard Henderson } 36947f6ceedfSAurelien Jarno 36957f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */ 3696b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs) 36977f6ceedfSAurelien Jarno { 3698f8b2f202SRichard Henderson TCGTemp *ts = s->reg_to_temp[reg]; 3699f8b2f202SRichard Henderson if (ts != NULL) { 370098b4e186SRichard Henderson temp_sync(s, ts, allocated_regs, 0, -1); 3701c896fe29Sbellard } 3702c896fe29Sbellard } 3703c896fe29Sbellard 3704b016486eSRichard Henderson /** 3705b016486eSRichard Henderson * tcg_reg_alloc: 3706b016486eSRichard Henderson * @required_regs: Set of registers in which we must allocate. 3707b016486eSRichard Henderson * @allocated_regs: Set of registers which must be avoided. 3708b016486eSRichard Henderson * @preferred_regs: Set of registers we should prefer. 3709b016486eSRichard Henderson * @rev: True if we search the registers in "indirect" order. 3710b016486eSRichard Henderson * 3711b016486eSRichard Henderson * The allocated register must be in @required_regs & ~@allocated_regs, 3712b016486eSRichard Henderson * but if we can put it in @preferred_regs we may save a move later. 3713b016486eSRichard Henderson */ 3714b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs, 3715b016486eSRichard Henderson TCGRegSet allocated_regs, 3716b016486eSRichard Henderson TCGRegSet preferred_regs, bool rev) 3717c896fe29Sbellard { 3718b016486eSRichard Henderson int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order); 3719b016486eSRichard Henderson TCGRegSet reg_ct[2]; 372091478cefSRichard Henderson const int *order; 3721c896fe29Sbellard 3722b016486eSRichard Henderson reg_ct[1] = required_regs & ~allocated_regs; 3723b016486eSRichard Henderson tcg_debug_assert(reg_ct[1] != 0); 3724b016486eSRichard Henderson reg_ct[0] = reg_ct[1] & preferred_regs; 3725b016486eSRichard Henderson 3726b016486eSRichard Henderson /* Skip the preferred_regs option if it cannot be satisfied, 3727b016486eSRichard Henderson or if the preference made no difference. */ 3728b016486eSRichard Henderson f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1]; 3729b016486eSRichard Henderson 373091478cefSRichard Henderson order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order; 3731c896fe29Sbellard 3732b016486eSRichard Henderson /* Try free registers, preferences first. */ 3733b016486eSRichard Henderson for (j = f; j < 2; j++) { 3734b016486eSRichard Henderson TCGRegSet set = reg_ct[j]; 3735b016486eSRichard Henderson 3736b016486eSRichard Henderson if (tcg_regset_single(set)) { 3737b016486eSRichard Henderson /* One register in the set. */ 3738b016486eSRichard Henderson TCGReg reg = tcg_regset_first(set); 3739b016486eSRichard Henderson if (s->reg_to_temp[reg] == NULL) { 3740c896fe29Sbellard return reg; 3741c896fe29Sbellard } 3742b016486eSRichard Henderson } else { 374391478cefSRichard Henderson for (i = 0; i < n; i++) { 3744b016486eSRichard Henderson TCGReg reg = order[i]; 3745b016486eSRichard Henderson if (s->reg_to_temp[reg] == NULL && 3746b016486eSRichard Henderson tcg_regset_test_reg(set, reg)) { 3747b016486eSRichard Henderson return reg; 3748b016486eSRichard Henderson } 3749b016486eSRichard Henderson } 3750b016486eSRichard Henderson } 3751b016486eSRichard Henderson } 3752b016486eSRichard Henderson 3753b016486eSRichard Henderson /* We must spill something. */ 3754b016486eSRichard Henderson for (j = f; j < 2; j++) { 3755b016486eSRichard Henderson TCGRegSet set = reg_ct[j]; 3756b016486eSRichard Henderson 3757b016486eSRichard Henderson if (tcg_regset_single(set)) { 3758b016486eSRichard Henderson /* One register in the set. */ 3759b016486eSRichard Henderson TCGReg reg = tcg_regset_first(set); 3760b3915dbbSRichard Henderson tcg_reg_free(s, reg, allocated_regs); 3761c896fe29Sbellard return reg; 3762b016486eSRichard Henderson } else { 3763b016486eSRichard Henderson for (i = 0; i < n; i++) { 3764b016486eSRichard Henderson TCGReg reg = order[i]; 3765b016486eSRichard Henderson if (tcg_regset_test_reg(set, reg)) { 3766b016486eSRichard Henderson tcg_reg_free(s, reg, allocated_regs); 3767b016486eSRichard Henderson return reg; 3768b016486eSRichard Henderson } 3769b016486eSRichard Henderson } 3770c896fe29Sbellard } 3771c896fe29Sbellard } 3772c896fe29Sbellard 3773732e89f4SRichard Henderson g_assert_not_reached(); 3774c896fe29Sbellard } 3775c896fe29Sbellard 377629f5e925SRichard Henderson static TCGReg tcg_reg_alloc_pair(TCGContext *s, TCGRegSet required_regs, 377729f5e925SRichard Henderson TCGRegSet allocated_regs, 377829f5e925SRichard Henderson TCGRegSet preferred_regs, bool rev) 377929f5e925SRichard Henderson { 378029f5e925SRichard Henderson int i, j, k, fmin, n = ARRAY_SIZE(tcg_target_reg_alloc_order); 378129f5e925SRichard Henderson TCGRegSet reg_ct[2]; 378229f5e925SRichard Henderson const int *order; 378329f5e925SRichard Henderson 378429f5e925SRichard Henderson /* Ensure that if I is not in allocated_regs, I+1 is not either. */ 378529f5e925SRichard Henderson reg_ct[1] = required_regs & ~(allocated_regs | (allocated_regs >> 1)); 378629f5e925SRichard Henderson tcg_debug_assert(reg_ct[1] != 0); 378729f5e925SRichard Henderson reg_ct[0] = reg_ct[1] & preferred_regs; 378829f5e925SRichard Henderson 378929f5e925SRichard Henderson order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order; 379029f5e925SRichard Henderson 379129f5e925SRichard Henderson /* 379229f5e925SRichard Henderson * Skip the preferred_regs option if it cannot be satisfied, 379329f5e925SRichard Henderson * or if the preference made no difference. 379429f5e925SRichard Henderson */ 379529f5e925SRichard Henderson k = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1]; 379629f5e925SRichard Henderson 379729f5e925SRichard Henderson /* 379829f5e925SRichard Henderson * Minimize the number of flushes by looking for 2 free registers first, 379929f5e925SRichard Henderson * then a single flush, then two flushes. 380029f5e925SRichard Henderson */ 380129f5e925SRichard Henderson for (fmin = 2; fmin >= 0; fmin--) { 380229f5e925SRichard Henderson for (j = k; j < 2; j++) { 380329f5e925SRichard Henderson TCGRegSet set = reg_ct[j]; 380429f5e925SRichard Henderson 380529f5e925SRichard Henderson for (i = 0; i < n; i++) { 380629f5e925SRichard Henderson TCGReg reg = order[i]; 380729f5e925SRichard Henderson 380829f5e925SRichard Henderson if (tcg_regset_test_reg(set, reg)) { 380929f5e925SRichard Henderson int f = !s->reg_to_temp[reg] + !s->reg_to_temp[reg + 1]; 381029f5e925SRichard Henderson if (f >= fmin) { 381129f5e925SRichard Henderson tcg_reg_free(s, reg, allocated_regs); 381229f5e925SRichard Henderson tcg_reg_free(s, reg + 1, allocated_regs); 381329f5e925SRichard Henderson return reg; 381429f5e925SRichard Henderson } 381529f5e925SRichard Henderson } 381629f5e925SRichard Henderson } 381729f5e925SRichard Henderson } 381829f5e925SRichard Henderson } 3819732e89f4SRichard Henderson g_assert_not_reached(); 382029f5e925SRichard Henderson } 382129f5e925SRichard Henderson 382240ae5c62SRichard Henderson /* Make sure the temporary is in a register. If needed, allocate the register 382340ae5c62SRichard Henderson from DESIRED while avoiding ALLOCATED. */ 382440ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs, 3825b722452aSRichard Henderson TCGRegSet allocated_regs, TCGRegSet preferred_regs) 382640ae5c62SRichard Henderson { 382740ae5c62SRichard Henderson TCGReg reg; 382840ae5c62SRichard Henderson 382940ae5c62SRichard Henderson switch (ts->val_type) { 383040ae5c62SRichard Henderson case TEMP_VAL_REG: 383140ae5c62SRichard Henderson return; 383240ae5c62SRichard Henderson case TEMP_VAL_CONST: 3833b016486eSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs, 3834b722452aSRichard Henderson preferred_regs, ts->indirect_base); 38350a6a8bc8SRichard Henderson if (ts->type <= TCG_TYPE_I64) { 383640ae5c62SRichard Henderson tcg_out_movi(s, ts->type, reg, ts->val); 38370a6a8bc8SRichard Henderson } else { 38384e186175SRichard Henderson uint64_t val = ts->val; 38394e186175SRichard Henderson MemOp vece = MO_64; 38404e186175SRichard Henderson 38414e186175SRichard Henderson /* 38424e186175SRichard Henderson * Find the minimal vector element that matches the constant. 38434e186175SRichard Henderson * The targets will, in general, have to do this search anyway, 38444e186175SRichard Henderson * do this generically. 38454e186175SRichard Henderson */ 38464e186175SRichard Henderson if (val == dup_const(MO_8, val)) { 38474e186175SRichard Henderson vece = MO_8; 38484e186175SRichard Henderson } else if (val == dup_const(MO_16, val)) { 38494e186175SRichard Henderson vece = MO_16; 38500b4286ddSRichard Henderson } else if (val == dup_const(MO_32, val)) { 38514e186175SRichard Henderson vece = MO_32; 38524e186175SRichard Henderson } 38534e186175SRichard Henderson 38544e186175SRichard Henderson tcg_out_dupi_vec(s, ts->type, vece, reg, ts->val); 38550a6a8bc8SRichard Henderson } 385640ae5c62SRichard Henderson ts->mem_coherent = 0; 385740ae5c62SRichard Henderson break; 385840ae5c62SRichard Henderson case TEMP_VAL_MEM: 3859b016486eSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs, 3860b722452aSRichard Henderson preferred_regs, ts->indirect_base); 386140ae5c62SRichard Henderson tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset); 386240ae5c62SRichard Henderson ts->mem_coherent = 1; 386340ae5c62SRichard Henderson break; 386440ae5c62SRichard Henderson case TEMP_VAL_DEAD: 386540ae5c62SRichard Henderson default: 3866732e89f4SRichard Henderson g_assert_not_reached(); 386740ae5c62SRichard Henderson } 3868098859f1SRichard Henderson set_temp_val_reg(s, ts, reg); 386940ae5c62SRichard Henderson } 387040ae5c62SRichard Henderson 387159d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a 3872e8996ee0Sbellard temporary registers needs to be allocated to store a constant. */ 387359d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs) 38741ad80729SAurelien Jarno { 38752c0366f0SAurelien Jarno /* The liveness analysis already ensures that globals are back 3876eabb7b91SAurelien Jarno in memory. Keep an tcg_debug_assert for safety. */ 3877e01fa97dSRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || temp_readonly(ts)); 38781ad80729SAurelien Jarno } 38791ad80729SAurelien Jarno 38809814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be 3881641d5fbeSbellard modified be the following code. 'allocated_regs' is used in case a 3882641d5fbeSbellard temporary registers needs to be allocated to store a constant. */ 3883641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs) 3884641d5fbeSbellard { 3885ac3b8891SRichard Henderson int i, n; 3886641d5fbeSbellard 3887ac3b8891SRichard Henderson for (i = 0, n = s->nb_globals; i < n; i++) { 3888b13eb728SRichard Henderson temp_save(s, &s->temps[i], allocated_regs); 3889641d5fbeSbellard } 3890e5097dc8Sbellard } 3891e5097dc8Sbellard 38923d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be 38933d5c5f87SAurelien Jarno read by the following code. 'allocated_regs' is used in case a 38943d5c5f87SAurelien Jarno temporary registers needs to be allocated to store a constant. */ 38953d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs) 38963d5c5f87SAurelien Jarno { 3897ac3b8891SRichard Henderson int i, n; 38983d5c5f87SAurelien Jarno 3899ac3b8891SRichard Henderson for (i = 0, n = s->nb_globals; i < n; i++) { 390012b9b11aSRichard Henderson TCGTemp *ts = &s->temps[i]; 390112b9b11aSRichard Henderson tcg_debug_assert(ts->val_type != TEMP_VAL_REG 3902ee17db83SRichard Henderson || ts->kind == TEMP_FIXED 390312b9b11aSRichard Henderson || ts->mem_coherent); 39043d5c5f87SAurelien Jarno } 39053d5c5f87SAurelien Jarno } 39063d5c5f87SAurelien Jarno 3907e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and 3908e8996ee0Sbellard all globals are stored at their canonical location. */ 3909e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs) 3910e5097dc8Sbellard { 3911e5097dc8Sbellard int i; 3912e5097dc8Sbellard 3913c896fe29Sbellard for (i = s->nb_globals; i < s->nb_temps; i++) { 3914b13eb728SRichard Henderson TCGTemp *ts = &s->temps[i]; 3915c0522136SRichard Henderson 3916c0522136SRichard Henderson switch (ts->kind) { 3917f57c6915SRichard Henderson case TEMP_TB: 3918b13eb728SRichard Henderson temp_save(s, ts, allocated_regs); 3919c0522136SRichard Henderson break; 3920c7482438SRichard Henderson case TEMP_EBB: 39212c0366f0SAurelien Jarno /* The liveness analysis already ensures that temps are dead. 3922eabb7b91SAurelien Jarno Keep an tcg_debug_assert for safety. */ 3923eabb7b91SAurelien Jarno tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD); 3924c0522136SRichard Henderson break; 3925c0522136SRichard Henderson case TEMP_CONST: 3926c0522136SRichard Henderson /* Similarly, we should have freed any allocated register. */ 3927c0522136SRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_CONST); 3928c0522136SRichard Henderson break; 3929c0522136SRichard Henderson default: 3930c0522136SRichard Henderson g_assert_not_reached(); 3931c896fe29Sbellard } 3932641d5fbeSbellard } 3933e8996ee0Sbellard 3934e8996ee0Sbellard save_globals(s, allocated_regs); 3935c896fe29Sbellard } 3936c896fe29Sbellard 3937bab1671fSRichard Henderson /* 3938c7482438SRichard Henderson * At a conditional branch, we assume all temporaries are dead unless 3939c7482438SRichard Henderson * explicitly live-across-conditional-branch; all globals and local 3940c7482438SRichard Henderson * temps are synced to their location. 3941b4cb76e6SRichard Henderson */ 3942b4cb76e6SRichard Henderson static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs) 3943b4cb76e6SRichard Henderson { 3944b4cb76e6SRichard Henderson sync_globals(s, allocated_regs); 3945b4cb76e6SRichard Henderson 3946b4cb76e6SRichard Henderson for (int i = s->nb_globals; i < s->nb_temps; i++) { 3947b4cb76e6SRichard Henderson TCGTemp *ts = &s->temps[i]; 3948b4cb76e6SRichard Henderson /* 3949b4cb76e6SRichard Henderson * The liveness analysis already ensures that temps are dead. 3950b4cb76e6SRichard Henderson * Keep tcg_debug_asserts for safety. 3951b4cb76e6SRichard Henderson */ 3952c0522136SRichard Henderson switch (ts->kind) { 3953f57c6915SRichard Henderson case TEMP_TB: 3954b4cb76e6SRichard Henderson tcg_debug_assert(ts->val_type != TEMP_VAL_REG || ts->mem_coherent); 3955c0522136SRichard Henderson break; 3956c7482438SRichard Henderson case TEMP_EBB: 3957c0522136SRichard Henderson case TEMP_CONST: 3958c0522136SRichard Henderson break; 3959c0522136SRichard Henderson default: 3960c0522136SRichard Henderson g_assert_not_reached(); 3961b4cb76e6SRichard Henderson } 3962b4cb76e6SRichard Henderson } 3963b4cb76e6SRichard Henderson } 3964b4cb76e6SRichard Henderson 3965b4cb76e6SRichard Henderson /* 3966c58f4c97SRichard Henderson * Specialized code generation for INDEX_op_mov_* with a constant. 3967bab1671fSRichard Henderson */ 39680fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots, 3969ba87719cSRichard Henderson tcg_target_ulong val, TCGLifeData arg_life, 3970ba87719cSRichard Henderson TCGRegSet preferred_regs) 3971e8996ee0Sbellard { 3972d63e3b6eSRichard Henderson /* ENV should not be modified. */ 3973e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 397459d7c14eSRichard Henderson 397559d7c14eSRichard Henderson /* The movi is not explicitly generated here. */ 3976098859f1SRichard Henderson set_temp_val_nonreg(s, ots, TEMP_VAL_CONST); 3977e8996ee0Sbellard ots->val = val; 397859d7c14eSRichard Henderson ots->mem_coherent = 0; 3979ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) { 3980ba87719cSRichard Henderson temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0)); 398159d7c14eSRichard Henderson } else if (IS_DEAD_ARG(0)) { 3982f8bf00f1SRichard Henderson temp_dead(s, ots); 39834c4e1ab2SAurelien Jarno } 3984e8996ee0Sbellard } 3985e8996ee0Sbellard 3986bab1671fSRichard Henderson /* 3987bab1671fSRichard Henderson * Specialized code generation for INDEX_op_mov_*. 3988bab1671fSRichard Henderson */ 3989dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op) 3990c896fe29Sbellard { 3991dd186292SRichard Henderson const TCGLifeData arg_life = op->life; 399269e3706dSRichard Henderson TCGRegSet allocated_regs, preferred_regs; 3993c896fe29Sbellard TCGTemp *ts, *ots; 3994450445d5SRichard Henderson TCGType otype, itype; 3995098859f1SRichard Henderson TCGReg oreg, ireg; 3996c896fe29Sbellard 3997d21369f5SRichard Henderson allocated_regs = s->reserved_regs; 399831fd884bSRichard Henderson preferred_regs = output_pref(op, 0); 399943439139SRichard Henderson ots = arg_temp(op->args[0]); 400043439139SRichard Henderson ts = arg_temp(op->args[1]); 4001450445d5SRichard Henderson 4002d63e3b6eSRichard Henderson /* ENV should not be modified. */ 4003e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 4004d63e3b6eSRichard Henderson 4005450445d5SRichard Henderson /* Note that otype != itype for no-op truncation. */ 4006450445d5SRichard Henderson otype = ots->type; 4007450445d5SRichard Henderson itype = ts->type; 4008c896fe29Sbellard 40090fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_CONST) { 40100fe4fca4SPaolo Bonzini /* propagate constant or generate sti */ 40110fe4fca4SPaolo Bonzini tcg_target_ulong val = ts->val; 40120fe4fca4SPaolo Bonzini if (IS_DEAD_ARG(1)) { 40130fe4fca4SPaolo Bonzini temp_dead(s, ts); 40140fe4fca4SPaolo Bonzini } 401569e3706dSRichard Henderson tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs); 40160fe4fca4SPaolo Bonzini return; 40170fe4fca4SPaolo Bonzini } 40180fe4fca4SPaolo Bonzini 40190fe4fca4SPaolo Bonzini /* If the source value is in memory we're going to be forced 40200fe4fca4SPaolo Bonzini to have it in a register in order to perform the copy. Copy 40210fe4fca4SPaolo Bonzini the SOURCE value into its own register first, that way we 40220fe4fca4SPaolo Bonzini don't have to reload SOURCE the next time it is used. */ 40230fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_MEM) { 402469e3706dSRichard Henderson temp_load(s, ts, tcg_target_available_regs[itype], 402569e3706dSRichard Henderson allocated_regs, preferred_regs); 4026c29c1d7eSAurelien Jarno } 40270fe4fca4SPaolo Bonzini tcg_debug_assert(ts->val_type == TEMP_VAL_REG); 4028098859f1SRichard Henderson ireg = ts->reg; 4029098859f1SRichard Henderson 4030d63e3b6eSRichard Henderson if (IS_DEAD_ARG(0)) { 4031c29c1d7eSAurelien Jarno /* mov to a non-saved dead register makes no sense (even with 4032c29c1d7eSAurelien Jarno liveness analysis disabled). */ 4033eabb7b91SAurelien Jarno tcg_debug_assert(NEED_SYNC_ARG(0)); 4034c29c1d7eSAurelien Jarno if (!ots->mem_allocated) { 40352272e4a7SRichard Henderson temp_allocate_frame(s, ots); 4036c29c1d7eSAurelien Jarno } 4037098859f1SRichard Henderson tcg_out_st(s, otype, ireg, ots->mem_base->reg, ots->mem_offset); 4038c29c1d7eSAurelien Jarno if (IS_DEAD_ARG(1)) { 4039f8bf00f1SRichard Henderson temp_dead(s, ts); 4040c29c1d7eSAurelien Jarno } 4041f8bf00f1SRichard Henderson temp_dead(s, ots); 4042098859f1SRichard Henderson return; 4043098859f1SRichard Henderson } 4044098859f1SRichard Henderson 4045ee17db83SRichard Henderson if (IS_DEAD_ARG(1) && ts->kind != TEMP_FIXED) { 4046098859f1SRichard Henderson /* 4047098859f1SRichard Henderson * The mov can be suppressed. Kill input first, so that it 4048098859f1SRichard Henderson * is unlinked from reg_to_temp, then set the output to the 4049098859f1SRichard Henderson * reg that we saved from the input. 4050098859f1SRichard Henderson */ 4051f8bf00f1SRichard Henderson temp_dead(s, ts); 4052098859f1SRichard Henderson oreg = ireg; 4053c29c1d7eSAurelien Jarno } else { 4054098859f1SRichard Henderson if (ots->val_type == TEMP_VAL_REG) { 4055098859f1SRichard Henderson oreg = ots->reg; 4056098859f1SRichard Henderson } else { 4057098859f1SRichard Henderson /* Make sure to not spill the input register during allocation. */ 4058098859f1SRichard Henderson oreg = tcg_reg_alloc(s, tcg_target_available_regs[otype], 4059098859f1SRichard Henderson allocated_regs | ((TCGRegSet)1 << ireg), 4060098859f1SRichard Henderson preferred_regs, ots->indirect_base); 4061c29c1d7eSAurelien Jarno } 4062098859f1SRichard Henderson if (!tcg_out_mov(s, otype, oreg, ireg)) { 4063240c08d0SRichard Henderson /* 4064240c08d0SRichard Henderson * Cross register class move not supported. 4065240c08d0SRichard Henderson * Store the source register into the destination slot 4066240c08d0SRichard Henderson * and leave the destination temp as TEMP_VAL_MEM. 4067240c08d0SRichard Henderson */ 4068e01fa97dSRichard Henderson assert(!temp_readonly(ots)); 4069240c08d0SRichard Henderson if (!ts->mem_allocated) { 4070240c08d0SRichard Henderson temp_allocate_frame(s, ots); 4071240c08d0SRichard Henderson } 4072098859f1SRichard Henderson tcg_out_st(s, ts->type, ireg, ots->mem_base->reg, ots->mem_offset); 4073098859f1SRichard Henderson set_temp_val_nonreg(s, ts, TEMP_VAL_MEM); 4074240c08d0SRichard Henderson ots->mem_coherent = 1; 4075240c08d0SRichard Henderson return; 407678113e83SRichard Henderson } 4077c29c1d7eSAurelien Jarno } 4078098859f1SRichard Henderson set_temp_val_reg(s, ots, oreg); 4079c896fe29Sbellard ots->mem_coherent = 0; 4080098859f1SRichard Henderson 4081ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) { 408298b4e186SRichard Henderson temp_sync(s, ots, allocated_regs, 0, 0); 4083c29c1d7eSAurelien Jarno } 4084ec7a869dSAurelien Jarno } 4085c896fe29Sbellard 4086bab1671fSRichard Henderson /* 4087bab1671fSRichard Henderson * Specialized code generation for INDEX_op_dup_vec. 4088bab1671fSRichard Henderson */ 4089bab1671fSRichard Henderson static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op) 4090bab1671fSRichard Henderson { 4091bab1671fSRichard Henderson const TCGLifeData arg_life = op->life; 4092bab1671fSRichard Henderson TCGRegSet dup_out_regs, dup_in_regs; 4093bab1671fSRichard Henderson TCGTemp *its, *ots; 4094bab1671fSRichard Henderson TCGType itype, vtype; 4095bab1671fSRichard Henderson unsigned vece; 409631c96417SRichard Henderson int lowpart_ofs; 4097bab1671fSRichard Henderson bool ok; 4098bab1671fSRichard Henderson 4099bab1671fSRichard Henderson ots = arg_temp(op->args[0]); 4100bab1671fSRichard Henderson its = arg_temp(op->args[1]); 4101bab1671fSRichard Henderson 4102bab1671fSRichard Henderson /* ENV should not be modified. */ 4103e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 4104bab1671fSRichard Henderson 4105bab1671fSRichard Henderson itype = its->type; 4106bab1671fSRichard Henderson vece = TCGOP_VECE(op); 4107bab1671fSRichard Henderson vtype = TCGOP_VECL(op) + TCG_TYPE_V64; 4108bab1671fSRichard Henderson 4109bab1671fSRichard Henderson if (its->val_type == TEMP_VAL_CONST) { 4110bab1671fSRichard Henderson /* Propagate constant via movi -> dupi. */ 4111bab1671fSRichard Henderson tcg_target_ulong val = its->val; 4112bab1671fSRichard Henderson if (IS_DEAD_ARG(1)) { 4113bab1671fSRichard Henderson temp_dead(s, its); 4114bab1671fSRichard Henderson } 411531fd884bSRichard Henderson tcg_reg_alloc_do_movi(s, ots, val, arg_life, output_pref(op, 0)); 4116bab1671fSRichard Henderson return; 4117bab1671fSRichard Henderson } 4118bab1671fSRichard Henderson 41199be0d080SRichard Henderson dup_out_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs; 41209be0d080SRichard Henderson dup_in_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[1].regs; 4121bab1671fSRichard Henderson 4122bab1671fSRichard Henderson /* Allocate the output register now. */ 4123bab1671fSRichard Henderson if (ots->val_type != TEMP_VAL_REG) { 4124bab1671fSRichard Henderson TCGRegSet allocated_regs = s->reserved_regs; 4125098859f1SRichard Henderson TCGReg oreg; 4126bab1671fSRichard Henderson 4127bab1671fSRichard Henderson if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) { 4128bab1671fSRichard Henderson /* Make sure to not spill the input register. */ 4129bab1671fSRichard Henderson tcg_regset_set_reg(allocated_regs, its->reg); 4130bab1671fSRichard Henderson } 4131098859f1SRichard Henderson oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs, 413231fd884bSRichard Henderson output_pref(op, 0), ots->indirect_base); 4133098859f1SRichard Henderson set_temp_val_reg(s, ots, oreg); 4134bab1671fSRichard Henderson } 4135bab1671fSRichard Henderson 4136bab1671fSRichard Henderson switch (its->val_type) { 4137bab1671fSRichard Henderson case TEMP_VAL_REG: 4138bab1671fSRichard Henderson /* 4139bab1671fSRichard Henderson * The dup constriaints must be broad, covering all possible VECE. 4140bab1671fSRichard Henderson * However, tcg_op_dup_vec() gets to see the VECE and we allow it 4141bab1671fSRichard Henderson * to fail, indicating that extra moves are required for that case. 4142bab1671fSRichard Henderson */ 4143bab1671fSRichard Henderson if (tcg_regset_test_reg(dup_in_regs, its->reg)) { 4144bab1671fSRichard Henderson if (tcg_out_dup_vec(s, vtype, vece, ots->reg, its->reg)) { 4145bab1671fSRichard Henderson goto done; 4146bab1671fSRichard Henderson } 4147bab1671fSRichard Henderson /* Try again from memory or a vector input register. */ 4148bab1671fSRichard Henderson } 4149bab1671fSRichard Henderson if (!its->mem_coherent) { 4150bab1671fSRichard Henderson /* 4151bab1671fSRichard Henderson * The input register is not synced, and so an extra store 4152bab1671fSRichard Henderson * would be required to use memory. Attempt an integer-vector 4153bab1671fSRichard Henderson * register move first. We do not have a TCGRegSet for this. 4154bab1671fSRichard Henderson */ 4155bab1671fSRichard Henderson if (tcg_out_mov(s, itype, ots->reg, its->reg)) { 4156bab1671fSRichard Henderson break; 4157bab1671fSRichard Henderson } 4158bab1671fSRichard Henderson /* Sync the temp back to its slot and load from there. */ 4159bab1671fSRichard Henderson temp_sync(s, its, s->reserved_regs, 0, 0); 4160bab1671fSRichard Henderson } 4161bab1671fSRichard Henderson /* fall through */ 4162bab1671fSRichard Henderson 4163bab1671fSRichard Henderson case TEMP_VAL_MEM: 416431c96417SRichard Henderson lowpart_ofs = 0; 416531c96417SRichard Henderson if (HOST_BIG_ENDIAN) { 416631c96417SRichard Henderson lowpart_ofs = tcg_type_size(itype) - (1 << vece); 416731c96417SRichard Henderson } 4168d6ecb4a9SRichard Henderson if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg, 416931c96417SRichard Henderson its->mem_offset + lowpart_ofs)) { 4170d6ecb4a9SRichard Henderson goto done; 4171d6ecb4a9SRichard Henderson } 4172098859f1SRichard Henderson /* Load the input into the destination vector register. */ 4173bab1671fSRichard Henderson tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset); 4174bab1671fSRichard Henderson break; 4175bab1671fSRichard Henderson 4176bab1671fSRichard Henderson default: 4177bab1671fSRichard Henderson g_assert_not_reached(); 4178bab1671fSRichard Henderson } 4179bab1671fSRichard Henderson 4180bab1671fSRichard Henderson /* We now have a vector input register, so dup must succeed. */ 4181bab1671fSRichard Henderson ok = tcg_out_dup_vec(s, vtype, vece, ots->reg, ots->reg); 4182bab1671fSRichard Henderson tcg_debug_assert(ok); 4183bab1671fSRichard Henderson 4184bab1671fSRichard Henderson done: 418536f5539cSRichard Henderson ots->mem_coherent = 0; 4186bab1671fSRichard Henderson if (IS_DEAD_ARG(1)) { 4187bab1671fSRichard Henderson temp_dead(s, its); 4188bab1671fSRichard Henderson } 4189bab1671fSRichard Henderson if (NEED_SYNC_ARG(0)) { 4190bab1671fSRichard Henderson temp_sync(s, ots, s->reserved_regs, 0, 0); 4191bab1671fSRichard Henderson } 4192bab1671fSRichard Henderson if (IS_DEAD_ARG(0)) { 4193bab1671fSRichard Henderson temp_dead(s, ots); 4194bab1671fSRichard Henderson } 4195bab1671fSRichard Henderson } 4196bab1671fSRichard Henderson 4197dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) 4198c896fe29Sbellard { 4199dd186292SRichard Henderson const TCGLifeData arg_life = op->life; 4200dd186292SRichard Henderson const TCGOpDef * const def = &tcg_op_defs[op->opc]; 420182790a87SRichard Henderson TCGRegSet i_allocated_regs; 420282790a87SRichard Henderson TCGRegSet o_allocated_regs; 4203b6638662SRichard Henderson int i, k, nb_iargs, nb_oargs; 4204b6638662SRichard Henderson TCGReg reg; 4205c896fe29Sbellard TCGArg arg; 4206c896fe29Sbellard const TCGArgConstraint *arg_ct; 4207c896fe29Sbellard TCGTemp *ts; 4208c896fe29Sbellard TCGArg new_args[TCG_MAX_OP_ARGS]; 4209c896fe29Sbellard int const_args[TCG_MAX_OP_ARGS]; 4210c896fe29Sbellard 4211c896fe29Sbellard nb_oargs = def->nb_oargs; 4212c896fe29Sbellard nb_iargs = def->nb_iargs; 4213c896fe29Sbellard 4214c896fe29Sbellard /* copy constants */ 4215c896fe29Sbellard memcpy(new_args + nb_oargs + nb_iargs, 4216dd186292SRichard Henderson op->args + nb_oargs + nb_iargs, 4217c896fe29Sbellard sizeof(TCGArg) * def->nb_cargs); 4218c896fe29Sbellard 4219d21369f5SRichard Henderson i_allocated_regs = s->reserved_regs; 4220d21369f5SRichard Henderson o_allocated_regs = s->reserved_regs; 422182790a87SRichard Henderson 4222c896fe29Sbellard /* satisfy input constraints */ 4223c896fe29Sbellard for (k = 0; k < nb_iargs; k++) { 422429f5e925SRichard Henderson TCGRegSet i_preferred_regs, i_required_regs; 422529f5e925SRichard Henderson bool allocate_new_reg, copyto_new_reg; 422629f5e925SRichard Henderson TCGTemp *ts2; 422729f5e925SRichard Henderson int i1, i2; 4228d62816f2SRichard Henderson 422966792f90SRichard Henderson i = def->args_ct[nb_oargs + k].sort_index; 4230dd186292SRichard Henderson arg = op->args[i]; 4231c896fe29Sbellard arg_ct = &def->args_ct[i]; 423243439139SRichard Henderson ts = arg_temp(arg); 423340ae5c62SRichard Henderson 423440ae5c62SRichard Henderson if (ts->val_type == TEMP_VAL_CONST 4235a4fbbd77SRichard Henderson && tcg_target_const_match(ts->val, ts->type, arg_ct->ct)) { 4236c896fe29Sbellard /* constant is OK for instruction */ 4237c896fe29Sbellard const_args[i] = 1; 4238c896fe29Sbellard new_args[i] = ts->val; 4239d62816f2SRichard Henderson continue; 4240c896fe29Sbellard } 424140ae5c62SRichard Henderson 42421c1824dcSRichard Henderson reg = ts->reg; 42431c1824dcSRichard Henderson i_preferred_regs = 0; 424429f5e925SRichard Henderson i_required_regs = arg_ct->regs; 42451c1824dcSRichard Henderson allocate_new_reg = false; 424629f5e925SRichard Henderson copyto_new_reg = false; 42471c1824dcSRichard Henderson 424829f5e925SRichard Henderson switch (arg_ct->pair) { 424929f5e925SRichard Henderson case 0: /* not paired */ 4250bc2b17e6SRichard Henderson if (arg_ct->ialias) { 425131fd884bSRichard Henderson i_preferred_regs = output_pref(op, arg_ct->alias_index); 4252c0522136SRichard Henderson 4253c0522136SRichard Henderson /* 4254c0522136SRichard Henderson * If the input is readonly, then it cannot also be an 4255c0522136SRichard Henderson * output and aliased to itself. If the input is not 4256c0522136SRichard Henderson * dead after the instruction, we must allocate a new 4257c0522136SRichard Henderson * register and move it. 4258c0522136SRichard Henderson */ 4259c0522136SRichard Henderson if (temp_readonly(ts) || !IS_DEAD_ARG(i)) { 42601c1824dcSRichard Henderson allocate_new_reg = true; 42611c1824dcSRichard Henderson } else if (ts->val_type == TEMP_VAL_REG) { 4262c0522136SRichard Henderson /* 42631c1824dcSRichard Henderson * Check if the current register has already been 42641c1824dcSRichard Henderson * allocated for another input. 4265c0522136SRichard Henderson */ 426629f5e925SRichard Henderson allocate_new_reg = 426729f5e925SRichard Henderson tcg_regset_test_reg(i_allocated_regs, reg); 42687e1df267SAurelien Jarno } 42697e1df267SAurelien Jarno } 42701c1824dcSRichard Henderson if (!allocate_new_reg) { 427129f5e925SRichard Henderson temp_load(s, ts, i_required_regs, i_allocated_regs, 427229f5e925SRichard Henderson i_preferred_regs); 4273c896fe29Sbellard reg = ts->reg; 427429f5e925SRichard Henderson allocate_new_reg = !tcg_regset_test_reg(i_required_regs, reg); 42751c1824dcSRichard Henderson } 42761c1824dcSRichard Henderson if (allocate_new_reg) { 4277c0522136SRichard Henderson /* 4278c0522136SRichard Henderson * Allocate a new register matching the constraint 4279c0522136SRichard Henderson * and move the temporary register into it. 4280c0522136SRichard Henderson */ 4281d62816f2SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 4282d62816f2SRichard Henderson i_allocated_regs, 0); 428329f5e925SRichard Henderson reg = tcg_reg_alloc(s, i_required_regs, i_allocated_regs, 42841c1824dcSRichard Henderson i_preferred_regs, ts->indirect_base); 428529f5e925SRichard Henderson copyto_new_reg = true; 428629f5e925SRichard Henderson } 428729f5e925SRichard Henderson break; 428829f5e925SRichard Henderson 428929f5e925SRichard Henderson case 1: 429029f5e925SRichard Henderson /* First of an input pair; if i1 == i2, the second is an output. */ 429129f5e925SRichard Henderson i1 = i; 429229f5e925SRichard Henderson i2 = arg_ct->pair_index; 429329f5e925SRichard Henderson ts2 = i1 != i2 ? arg_temp(op->args[i2]) : NULL; 429429f5e925SRichard Henderson 429529f5e925SRichard Henderson /* 429629f5e925SRichard Henderson * It is easier to default to allocating a new pair 429729f5e925SRichard Henderson * and to identify a few cases where it's not required. 429829f5e925SRichard Henderson */ 429929f5e925SRichard Henderson if (arg_ct->ialias) { 430031fd884bSRichard Henderson i_preferred_regs = output_pref(op, arg_ct->alias_index); 430129f5e925SRichard Henderson if (IS_DEAD_ARG(i1) && 430229f5e925SRichard Henderson IS_DEAD_ARG(i2) && 430329f5e925SRichard Henderson !temp_readonly(ts) && 430429f5e925SRichard Henderson ts->val_type == TEMP_VAL_REG && 430529f5e925SRichard Henderson ts->reg < TCG_TARGET_NB_REGS - 1 && 430629f5e925SRichard Henderson tcg_regset_test_reg(i_required_regs, reg) && 430729f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg) && 430829f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg + 1) && 430929f5e925SRichard Henderson (ts2 431029f5e925SRichard Henderson ? ts2->val_type == TEMP_VAL_REG && 431129f5e925SRichard Henderson ts2->reg == reg + 1 && 431229f5e925SRichard Henderson !temp_readonly(ts2) 431329f5e925SRichard Henderson : s->reg_to_temp[reg + 1] == NULL)) { 431429f5e925SRichard Henderson break; 431529f5e925SRichard Henderson } 431629f5e925SRichard Henderson } else { 431729f5e925SRichard Henderson /* Without aliasing, the pair must also be an input. */ 431829f5e925SRichard Henderson tcg_debug_assert(ts2); 431929f5e925SRichard Henderson if (ts->val_type == TEMP_VAL_REG && 432029f5e925SRichard Henderson ts2->val_type == TEMP_VAL_REG && 432129f5e925SRichard Henderson ts2->reg == reg + 1 && 432229f5e925SRichard Henderson tcg_regset_test_reg(i_required_regs, reg)) { 432329f5e925SRichard Henderson break; 432429f5e925SRichard Henderson } 432529f5e925SRichard Henderson } 432629f5e925SRichard Henderson reg = tcg_reg_alloc_pair(s, i_required_regs, i_allocated_regs, 432729f5e925SRichard Henderson 0, ts->indirect_base); 432829f5e925SRichard Henderson goto do_pair; 432929f5e925SRichard Henderson 433029f5e925SRichard Henderson case 2: /* pair second */ 433129f5e925SRichard Henderson reg = new_args[arg_ct->pair_index] + 1; 433229f5e925SRichard Henderson goto do_pair; 433329f5e925SRichard Henderson 433429f5e925SRichard Henderson case 3: /* ialias with second output, no first input */ 433529f5e925SRichard Henderson tcg_debug_assert(arg_ct->ialias); 433631fd884bSRichard Henderson i_preferred_regs = output_pref(op, arg_ct->alias_index); 433729f5e925SRichard Henderson 433829f5e925SRichard Henderson if (IS_DEAD_ARG(i) && 433929f5e925SRichard Henderson !temp_readonly(ts) && 434029f5e925SRichard Henderson ts->val_type == TEMP_VAL_REG && 434129f5e925SRichard Henderson reg > 0 && 434229f5e925SRichard Henderson s->reg_to_temp[reg - 1] == NULL && 434329f5e925SRichard Henderson tcg_regset_test_reg(i_required_regs, reg) && 434429f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg) && 434529f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg - 1)) { 434629f5e925SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg - 1); 434729f5e925SRichard Henderson break; 434829f5e925SRichard Henderson } 434929f5e925SRichard Henderson reg = tcg_reg_alloc_pair(s, i_required_regs >> 1, 435029f5e925SRichard Henderson i_allocated_regs, 0, 435129f5e925SRichard Henderson ts->indirect_base); 435229f5e925SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg); 435329f5e925SRichard Henderson reg += 1; 435429f5e925SRichard Henderson goto do_pair; 435529f5e925SRichard Henderson 435629f5e925SRichard Henderson do_pair: 435729f5e925SRichard Henderson /* 435829f5e925SRichard Henderson * If an aliased input is not dead after the instruction, 435929f5e925SRichard Henderson * we must allocate a new register and move it. 436029f5e925SRichard Henderson */ 436129f5e925SRichard Henderson if (arg_ct->ialias && (!IS_DEAD_ARG(i) || temp_readonly(ts))) { 436229f5e925SRichard Henderson TCGRegSet t_allocated_regs = i_allocated_regs; 436329f5e925SRichard Henderson 436429f5e925SRichard Henderson /* 436529f5e925SRichard Henderson * Because of the alias, and the continued life, make sure 436629f5e925SRichard Henderson * that the temp is somewhere *other* than the reg pair, 436729f5e925SRichard Henderson * and we get a copy in reg. 436829f5e925SRichard Henderson */ 436929f5e925SRichard Henderson tcg_regset_set_reg(t_allocated_regs, reg); 437029f5e925SRichard Henderson tcg_regset_set_reg(t_allocated_regs, reg + 1); 437129f5e925SRichard Henderson if (ts->val_type == TEMP_VAL_REG && ts->reg == reg) { 437229f5e925SRichard Henderson /* If ts was already in reg, copy it somewhere else. */ 437329f5e925SRichard Henderson TCGReg nr; 437429f5e925SRichard Henderson bool ok; 437529f5e925SRichard Henderson 437629f5e925SRichard Henderson tcg_debug_assert(ts->kind != TEMP_FIXED); 437729f5e925SRichard Henderson nr = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], 437829f5e925SRichard Henderson t_allocated_regs, 0, ts->indirect_base); 437929f5e925SRichard Henderson ok = tcg_out_mov(s, ts->type, nr, reg); 438029f5e925SRichard Henderson tcg_debug_assert(ok); 438129f5e925SRichard Henderson 438229f5e925SRichard Henderson set_temp_val_reg(s, ts, nr); 438329f5e925SRichard Henderson } else { 438429f5e925SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 438529f5e925SRichard Henderson t_allocated_regs, 0); 438629f5e925SRichard Henderson copyto_new_reg = true; 438729f5e925SRichard Henderson } 438829f5e925SRichard Henderson } else { 438929f5e925SRichard Henderson /* Preferably allocate to reg, otherwise copy. */ 439029f5e925SRichard Henderson i_required_regs = (TCGRegSet)1 << reg; 439129f5e925SRichard Henderson temp_load(s, ts, i_required_regs, i_allocated_regs, 439229f5e925SRichard Henderson i_preferred_regs); 439329f5e925SRichard Henderson copyto_new_reg = ts->reg != reg; 439429f5e925SRichard Henderson } 439529f5e925SRichard Henderson break; 439629f5e925SRichard Henderson 439729f5e925SRichard Henderson default: 439829f5e925SRichard Henderson g_assert_not_reached(); 439929f5e925SRichard Henderson } 440029f5e925SRichard Henderson 440129f5e925SRichard Henderson if (copyto_new_reg) { 440278113e83SRichard Henderson if (!tcg_out_mov(s, ts->type, reg, ts->reg)) { 4403240c08d0SRichard Henderson /* 4404240c08d0SRichard Henderson * Cross register class move not supported. Sync the 4405240c08d0SRichard Henderson * temp back to its slot and load from there. 4406240c08d0SRichard Henderson */ 4407240c08d0SRichard Henderson temp_sync(s, ts, i_allocated_regs, 0, 0); 4408240c08d0SRichard Henderson tcg_out_ld(s, ts->type, reg, 4409240c08d0SRichard Henderson ts->mem_base->reg, ts->mem_offset); 441078113e83SRichard Henderson } 4411c896fe29Sbellard } 4412c896fe29Sbellard new_args[i] = reg; 4413c896fe29Sbellard const_args[i] = 0; 441482790a87SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg); 4415c896fe29Sbellard } 4416c896fe29Sbellard 4417c896fe29Sbellard /* mark dead temporaries and free the associated registers */ 4418866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 4419866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) { 442043439139SRichard Henderson temp_dead(s, arg_temp(op->args[i])); 4421c896fe29Sbellard } 4422c896fe29Sbellard } 4423c896fe29Sbellard 4424b4cb76e6SRichard Henderson if (def->flags & TCG_OPF_COND_BRANCH) { 4425b4cb76e6SRichard Henderson tcg_reg_alloc_cbranch(s, i_allocated_regs); 4426b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 442782790a87SRichard Henderson tcg_reg_alloc_bb_end(s, i_allocated_regs); 4428a52ad07eSAurelien Jarno } else { 4429c896fe29Sbellard if (def->flags & TCG_OPF_CALL_CLOBBER) { 4430b03cce8eSbellard /* XXX: permit generic clobber register list ? */ 4431c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) { 4432c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { 443382790a87SRichard Henderson tcg_reg_free(s, i, i_allocated_regs); 4434c896fe29Sbellard } 4435c896fe29Sbellard } 44363d5c5f87SAurelien Jarno } 44373d5c5f87SAurelien Jarno if (def->flags & TCG_OPF_SIDE_EFFECTS) { 44383d5c5f87SAurelien Jarno /* sync globals if the op has side effects and might trigger 44393d5c5f87SAurelien Jarno an exception. */ 444082790a87SRichard Henderson sync_globals(s, i_allocated_regs); 4441c896fe29Sbellard } 4442c896fe29Sbellard 4443c896fe29Sbellard /* satisfy the output constraints */ 4444c896fe29Sbellard for(k = 0; k < nb_oargs; k++) { 444566792f90SRichard Henderson i = def->args_ct[k].sort_index; 4446dd186292SRichard Henderson arg = op->args[i]; 4447c896fe29Sbellard arg_ct = &def->args_ct[i]; 444843439139SRichard Henderson ts = arg_temp(arg); 4449d63e3b6eSRichard Henderson 4450d63e3b6eSRichard Henderson /* ENV should not be modified. */ 4451e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ts)); 4452d63e3b6eSRichard Henderson 445329f5e925SRichard Henderson switch (arg_ct->pair) { 445429f5e925SRichard Henderson case 0: /* not paired */ 4455bc2b17e6SRichard Henderson if (arg_ct->oalias && !const_args[arg_ct->alias_index]) { 44565ff9d6a4Sbellard reg = new_args[arg_ct->alias_index]; 4457bc2b17e6SRichard Henderson } else if (arg_ct->newreg) { 44589be0d080SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->regs, 445982790a87SRichard Henderson i_allocated_regs | o_allocated_regs, 446031fd884bSRichard Henderson output_pref(op, k), ts->indirect_base); 4461c896fe29Sbellard } else { 44629be0d080SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs, 446331fd884bSRichard Henderson output_pref(op, k), ts->indirect_base); 4464c896fe29Sbellard } 446529f5e925SRichard Henderson break; 446629f5e925SRichard Henderson 446729f5e925SRichard Henderson case 1: /* first of pair */ 446829f5e925SRichard Henderson tcg_debug_assert(!arg_ct->newreg); 446929f5e925SRichard Henderson if (arg_ct->oalias) { 447029f5e925SRichard Henderson reg = new_args[arg_ct->alias_index]; 447129f5e925SRichard Henderson break; 447229f5e925SRichard Henderson } 447329f5e925SRichard Henderson reg = tcg_reg_alloc_pair(s, arg_ct->regs, o_allocated_regs, 447431fd884bSRichard Henderson output_pref(op, k), ts->indirect_base); 447529f5e925SRichard Henderson break; 447629f5e925SRichard Henderson 447729f5e925SRichard Henderson case 2: /* second of pair */ 447829f5e925SRichard Henderson tcg_debug_assert(!arg_ct->newreg); 447929f5e925SRichard Henderson if (arg_ct->oalias) { 448029f5e925SRichard Henderson reg = new_args[arg_ct->alias_index]; 448129f5e925SRichard Henderson } else { 448229f5e925SRichard Henderson reg = new_args[arg_ct->pair_index] + 1; 448329f5e925SRichard Henderson } 448429f5e925SRichard Henderson break; 448529f5e925SRichard Henderson 448629f5e925SRichard Henderson case 3: /* first of pair, aliasing with a second input */ 448729f5e925SRichard Henderson tcg_debug_assert(!arg_ct->newreg); 448829f5e925SRichard Henderson reg = new_args[arg_ct->pair_index] - 1; 448929f5e925SRichard Henderson break; 449029f5e925SRichard Henderson 449129f5e925SRichard Henderson default: 449229f5e925SRichard Henderson g_assert_not_reached(); 449329f5e925SRichard Henderson } 449482790a87SRichard Henderson tcg_regset_set_reg(o_allocated_regs, reg); 4495098859f1SRichard Henderson set_temp_val_reg(s, ts, reg); 4496c896fe29Sbellard ts->mem_coherent = 0; 4497c896fe29Sbellard new_args[i] = reg; 4498c896fe29Sbellard } 4499e8996ee0Sbellard } 4500c896fe29Sbellard 4501c896fe29Sbellard /* emit instruction */ 4502678155b2SRichard Henderson switch (op->opc) { 4503678155b2SRichard Henderson case INDEX_op_ext8s_i32: 4504678155b2SRichard Henderson tcg_out_ext8s(s, TCG_TYPE_I32, new_args[0], new_args[1]); 4505678155b2SRichard Henderson break; 4506678155b2SRichard Henderson case INDEX_op_ext8s_i64: 4507678155b2SRichard Henderson tcg_out_ext8s(s, TCG_TYPE_I64, new_args[0], new_args[1]); 4508678155b2SRichard Henderson break; 4509d0e66c89SRichard Henderson case INDEX_op_ext8u_i32: 4510d0e66c89SRichard Henderson case INDEX_op_ext8u_i64: 4511d0e66c89SRichard Henderson tcg_out_ext8u(s, new_args[0], new_args[1]); 4512d0e66c89SRichard Henderson break; 4513*753e42eaSRichard Henderson case INDEX_op_ext16s_i32: 4514*753e42eaSRichard Henderson tcg_out_ext16s(s, TCG_TYPE_I32, new_args[0], new_args[1]); 4515*753e42eaSRichard Henderson break; 4516*753e42eaSRichard Henderson case INDEX_op_ext16s_i64: 4517*753e42eaSRichard Henderson tcg_out_ext16s(s, TCG_TYPE_I64, new_args[0], new_args[1]); 4518*753e42eaSRichard Henderson break; 4519678155b2SRichard Henderson default: 4520d2fd745fSRichard Henderson if (def->flags & TCG_OPF_VECTOR) { 4521d2fd745fSRichard Henderson tcg_out_vec_op(s, op->opc, TCGOP_VECL(op), TCGOP_VECE(op), 4522d2fd745fSRichard Henderson new_args, const_args); 4523d2fd745fSRichard Henderson } else { 4524dd186292SRichard Henderson tcg_out_op(s, op->opc, new_args, const_args); 4525d2fd745fSRichard Henderson } 4526678155b2SRichard Henderson break; 4527678155b2SRichard Henderson } 4528c896fe29Sbellard 4529c896fe29Sbellard /* move the outputs in the correct register if needed */ 4530c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 453143439139SRichard Henderson ts = arg_temp(op->args[i]); 4532d63e3b6eSRichard Henderson 4533d63e3b6eSRichard Henderson /* ENV should not be modified. */ 4534e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ts)); 4535d63e3b6eSRichard Henderson 4536ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) { 453798b4e186SRichard Henderson temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i)); 453859d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) { 4539f8bf00f1SRichard Henderson temp_dead(s, ts); 4540ec7a869dSAurelien Jarno } 4541c896fe29Sbellard } 4542c896fe29Sbellard } 4543c896fe29Sbellard 4544efe86b21SRichard Henderson static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op) 4545efe86b21SRichard Henderson { 4546efe86b21SRichard Henderson const TCGLifeData arg_life = op->life; 4547efe86b21SRichard Henderson TCGTemp *ots, *itsl, *itsh; 4548efe86b21SRichard Henderson TCGType vtype = TCGOP_VECL(op) + TCG_TYPE_V64; 4549efe86b21SRichard Henderson 4550efe86b21SRichard Henderson /* This opcode is only valid for 32-bit hosts, for 64-bit elements. */ 4551efe86b21SRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 32); 4552efe86b21SRichard Henderson tcg_debug_assert(TCGOP_VECE(op) == MO_64); 4553efe86b21SRichard Henderson 4554efe86b21SRichard Henderson ots = arg_temp(op->args[0]); 4555efe86b21SRichard Henderson itsl = arg_temp(op->args[1]); 4556efe86b21SRichard Henderson itsh = arg_temp(op->args[2]); 4557efe86b21SRichard Henderson 4558efe86b21SRichard Henderson /* ENV should not be modified. */ 4559efe86b21SRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 4560efe86b21SRichard Henderson 4561efe86b21SRichard Henderson /* Allocate the output register now. */ 4562efe86b21SRichard Henderson if (ots->val_type != TEMP_VAL_REG) { 4563efe86b21SRichard Henderson TCGRegSet allocated_regs = s->reserved_regs; 4564efe86b21SRichard Henderson TCGRegSet dup_out_regs = 4565efe86b21SRichard Henderson tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs; 4566098859f1SRichard Henderson TCGReg oreg; 4567efe86b21SRichard Henderson 4568efe86b21SRichard Henderson /* Make sure to not spill the input registers. */ 4569efe86b21SRichard Henderson if (!IS_DEAD_ARG(1) && itsl->val_type == TEMP_VAL_REG) { 4570efe86b21SRichard Henderson tcg_regset_set_reg(allocated_regs, itsl->reg); 4571efe86b21SRichard Henderson } 4572efe86b21SRichard Henderson if (!IS_DEAD_ARG(2) && itsh->val_type == TEMP_VAL_REG) { 4573efe86b21SRichard Henderson tcg_regset_set_reg(allocated_regs, itsh->reg); 4574efe86b21SRichard Henderson } 4575efe86b21SRichard Henderson 4576098859f1SRichard Henderson oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs, 457731fd884bSRichard Henderson output_pref(op, 0), ots->indirect_base); 4578098859f1SRichard Henderson set_temp_val_reg(s, ots, oreg); 4579efe86b21SRichard Henderson } 4580efe86b21SRichard Henderson 4581efe86b21SRichard Henderson /* Promote dup2 of immediates to dupi_vec. */ 4582efe86b21SRichard Henderson if (itsl->val_type == TEMP_VAL_CONST && itsh->val_type == TEMP_VAL_CONST) { 4583efe86b21SRichard Henderson uint64_t val = deposit64(itsl->val, 32, 32, itsh->val); 4584efe86b21SRichard Henderson MemOp vece = MO_64; 4585efe86b21SRichard Henderson 4586efe86b21SRichard Henderson if (val == dup_const(MO_8, val)) { 4587efe86b21SRichard Henderson vece = MO_8; 4588efe86b21SRichard Henderson } else if (val == dup_const(MO_16, val)) { 4589efe86b21SRichard Henderson vece = MO_16; 4590efe86b21SRichard Henderson } else if (val == dup_const(MO_32, val)) { 4591efe86b21SRichard Henderson vece = MO_32; 4592efe86b21SRichard Henderson } 4593efe86b21SRichard Henderson 4594efe86b21SRichard Henderson tcg_out_dupi_vec(s, vtype, vece, ots->reg, val); 4595efe86b21SRichard Henderson goto done; 4596efe86b21SRichard Henderson } 4597efe86b21SRichard Henderson 4598efe86b21SRichard Henderson /* If the two inputs form one 64-bit value, try dupm_vec. */ 4599aef85402SRichard Henderson if (itsl->temp_subindex == HOST_BIG_ENDIAN && 4600aef85402SRichard Henderson itsh->temp_subindex == !HOST_BIG_ENDIAN && 4601aef85402SRichard Henderson itsl == itsh + (HOST_BIG_ENDIAN ? 1 : -1)) { 4602aef85402SRichard Henderson TCGTemp *its = itsl - HOST_BIG_ENDIAN; 4603aef85402SRichard Henderson 4604aef85402SRichard Henderson temp_sync(s, its + 0, s->reserved_regs, 0, 0); 4605aef85402SRichard Henderson temp_sync(s, its + 1, s->reserved_regs, 0, 0); 4606aef85402SRichard Henderson 4607efe86b21SRichard Henderson if (tcg_out_dupm_vec(s, vtype, MO_64, ots->reg, 4608efe86b21SRichard Henderson its->mem_base->reg, its->mem_offset)) { 4609efe86b21SRichard Henderson goto done; 4610efe86b21SRichard Henderson } 4611efe86b21SRichard Henderson } 4612efe86b21SRichard Henderson 4613efe86b21SRichard Henderson /* Fall back to generic expansion. */ 4614efe86b21SRichard Henderson return false; 4615efe86b21SRichard Henderson 4616efe86b21SRichard Henderson done: 461736f5539cSRichard Henderson ots->mem_coherent = 0; 4618efe86b21SRichard Henderson if (IS_DEAD_ARG(1)) { 4619efe86b21SRichard Henderson temp_dead(s, itsl); 4620efe86b21SRichard Henderson } 4621efe86b21SRichard Henderson if (IS_DEAD_ARG(2)) { 4622efe86b21SRichard Henderson temp_dead(s, itsh); 4623efe86b21SRichard Henderson } 4624efe86b21SRichard Henderson if (NEED_SYNC_ARG(0)) { 4625efe86b21SRichard Henderson temp_sync(s, ots, s->reserved_regs, 0, IS_DEAD_ARG(0)); 4626efe86b21SRichard Henderson } else if (IS_DEAD_ARG(0)) { 4627efe86b21SRichard Henderson temp_dead(s, ots); 4628efe86b21SRichard Henderson } 4629efe86b21SRichard Henderson return true; 4630efe86b21SRichard Henderson } 4631efe86b21SRichard Henderson 463239004a71SRichard Henderson static void load_arg_reg(TCGContext *s, TCGReg reg, TCGTemp *ts, 463339004a71SRichard Henderson TCGRegSet allocated_regs) 4634c896fe29Sbellard { 4635c896fe29Sbellard if (ts->val_type == TEMP_VAL_REG) { 4636c896fe29Sbellard if (ts->reg != reg) { 46374250da10SRichard Henderson tcg_reg_free(s, reg, allocated_regs); 463878113e83SRichard Henderson if (!tcg_out_mov(s, ts->type, reg, ts->reg)) { 4639240c08d0SRichard Henderson /* 4640240c08d0SRichard Henderson * Cross register class move not supported. Sync the 4641240c08d0SRichard Henderson * temp back to its slot and load from there. 4642240c08d0SRichard Henderson */ 4643240c08d0SRichard Henderson temp_sync(s, ts, allocated_regs, 0, 0); 4644240c08d0SRichard Henderson tcg_out_ld(s, ts->type, reg, 4645240c08d0SRichard Henderson ts->mem_base->reg, ts->mem_offset); 464678113e83SRichard Henderson } 4647c896fe29Sbellard } 4648c896fe29Sbellard } else { 4649ccb1bb66SRichard Henderson TCGRegSet arg_set = 0; 465040ae5c62SRichard Henderson 46514250da10SRichard Henderson tcg_reg_free(s, reg, allocated_regs); 465240ae5c62SRichard Henderson tcg_regset_set_reg(arg_set, reg); 4653b722452aSRichard Henderson temp_load(s, ts, arg_set, allocated_regs, 0); 4654c896fe29Sbellard } 465539004a71SRichard Henderson } 465640ae5c62SRichard Henderson 465739004a71SRichard Henderson static void load_arg_stk(TCGContext *s, int stk_slot, TCGTemp *ts, 465839004a71SRichard Henderson TCGRegSet allocated_regs) 465939004a71SRichard Henderson { 466039004a71SRichard Henderson /* 466139004a71SRichard Henderson * When the destination is on the stack, load up the temp and store. 466239004a71SRichard Henderson * If there are many call-saved registers, the temp might live to 466339004a71SRichard Henderson * see another use; otherwise it'll be discarded. 466439004a71SRichard Henderson */ 466539004a71SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], allocated_regs, 0); 466639004a71SRichard Henderson tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, 466739004a71SRichard Henderson TCG_TARGET_CALL_STACK_OFFSET + 466839004a71SRichard Henderson stk_slot * sizeof(tcg_target_long)); 466939004a71SRichard Henderson } 467039004a71SRichard Henderson 467139004a71SRichard Henderson static void load_arg_normal(TCGContext *s, const TCGCallArgumentLoc *l, 467239004a71SRichard Henderson TCGTemp *ts, TCGRegSet *allocated_regs) 467339004a71SRichard Henderson { 467439004a71SRichard Henderson if (REG_P(l)) { 467539004a71SRichard Henderson TCGReg reg = tcg_target_call_iarg_regs[l->arg_slot]; 467639004a71SRichard Henderson load_arg_reg(s, reg, ts, *allocated_regs); 467739004a71SRichard Henderson tcg_regset_set_reg(*allocated_regs, reg); 467839004a71SRichard Henderson } else { 467939004a71SRichard Henderson load_arg_stk(s, l->arg_slot - ARRAY_SIZE(tcg_target_call_iarg_regs), 468039004a71SRichard Henderson ts, *allocated_regs); 4681c896fe29Sbellard } 468239cf05d3Sbellard } 4683c896fe29Sbellard 4684313bdea8SRichard Henderson static void load_arg_ref(TCGContext *s, int arg_slot, TCGReg ref_base, 4685313bdea8SRichard Henderson intptr_t ref_off, TCGRegSet *allocated_regs) 4686313bdea8SRichard Henderson { 4687313bdea8SRichard Henderson TCGReg reg; 4688313bdea8SRichard Henderson int stk_slot = arg_slot - ARRAY_SIZE(tcg_target_call_iarg_regs); 4689313bdea8SRichard Henderson 4690313bdea8SRichard Henderson if (stk_slot < 0) { 4691313bdea8SRichard Henderson reg = tcg_target_call_iarg_regs[arg_slot]; 4692313bdea8SRichard Henderson tcg_reg_free(s, reg, *allocated_regs); 4693313bdea8SRichard Henderson tcg_out_addi_ptr(s, reg, ref_base, ref_off); 4694313bdea8SRichard Henderson tcg_regset_set_reg(*allocated_regs, reg); 4695313bdea8SRichard Henderson } else { 4696313bdea8SRichard Henderson reg = tcg_reg_alloc(s, tcg_target_available_regs[TCG_TYPE_PTR], 4697313bdea8SRichard Henderson *allocated_regs, 0, false); 4698313bdea8SRichard Henderson tcg_out_addi_ptr(s, reg, ref_base, ref_off); 4699313bdea8SRichard Henderson tcg_out_st(s, TCG_TYPE_PTR, reg, TCG_REG_CALL_STACK, 4700313bdea8SRichard Henderson TCG_TARGET_CALL_STACK_OFFSET 4701313bdea8SRichard Henderson + stk_slot * sizeof(tcg_target_long)); 4702313bdea8SRichard Henderson } 4703313bdea8SRichard Henderson } 4704313bdea8SRichard Henderson 470539004a71SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op) 470639004a71SRichard Henderson { 470739004a71SRichard Henderson const int nb_oargs = TCGOP_CALLO(op); 470839004a71SRichard Henderson const int nb_iargs = TCGOP_CALLI(op); 470939004a71SRichard Henderson const TCGLifeData arg_life = op->life; 471039004a71SRichard Henderson const TCGHelperInfo *info = tcg_call_info(op); 471139004a71SRichard Henderson TCGRegSet allocated_regs = s->reserved_regs; 471239004a71SRichard Henderson int i; 471339004a71SRichard Henderson 471439004a71SRichard Henderson /* 471539004a71SRichard Henderson * Move inputs into place in reverse order, 471639004a71SRichard Henderson * so that we place stacked arguments first. 471739004a71SRichard Henderson */ 471839004a71SRichard Henderson for (i = nb_iargs - 1; i >= 0; --i) { 471939004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i]; 472039004a71SRichard Henderson TCGTemp *ts = arg_temp(op->args[nb_oargs + i]); 472139004a71SRichard Henderson 472239004a71SRichard Henderson switch (loc->kind) { 472339004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 472439004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 472539004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 472639004a71SRichard Henderson load_arg_normal(s, loc, ts, &allocated_regs); 472739004a71SRichard Henderson break; 4728313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF: 4729313bdea8SRichard Henderson load_arg_stk(s, loc->ref_slot, ts, allocated_regs); 4730313bdea8SRichard Henderson load_arg_ref(s, loc->arg_slot, TCG_REG_CALL_STACK, 4731313bdea8SRichard Henderson TCG_TARGET_CALL_STACK_OFFSET 4732313bdea8SRichard Henderson + loc->ref_slot * sizeof(tcg_target_long), 4733313bdea8SRichard Henderson &allocated_regs); 4734313bdea8SRichard Henderson break; 4735313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF_N: 4736313bdea8SRichard Henderson load_arg_stk(s, loc->ref_slot, ts, allocated_regs); 4737313bdea8SRichard Henderson break; 473839004a71SRichard Henderson default: 473939004a71SRichard Henderson g_assert_not_reached(); 474039004a71SRichard Henderson } 474139004a71SRichard Henderson } 474239004a71SRichard Henderson 474339004a71SRichard Henderson /* Mark dead temporaries and free the associated registers. */ 4744866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 4745866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) { 474643439139SRichard Henderson temp_dead(s, arg_temp(op->args[i])); 4747c896fe29Sbellard } 4748c896fe29Sbellard } 4749c896fe29Sbellard 475039004a71SRichard Henderson /* Clobber call registers. */ 4751c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) { 4752c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { 4753b3915dbbSRichard Henderson tcg_reg_free(s, i, allocated_regs); 4754c896fe29Sbellard } 4755c896fe29Sbellard } 4756c896fe29Sbellard 475739004a71SRichard Henderson /* 475839004a71SRichard Henderson * Save globals if they might be written by the helper, 475939004a71SRichard Henderson * sync them if they might be read. 476039004a71SRichard Henderson */ 476139004a71SRichard Henderson if (info->flags & TCG_CALL_NO_READ_GLOBALS) { 476278505279SAurelien Jarno /* Nothing to do */ 476339004a71SRichard Henderson } else if (info->flags & TCG_CALL_NO_WRITE_GLOBALS) { 476478505279SAurelien Jarno sync_globals(s, allocated_regs); 476578505279SAurelien Jarno } else { 4766e8996ee0Sbellard save_globals(s, allocated_regs); 4767b9c18f56Saurel32 } 4768c896fe29Sbellard 4769313bdea8SRichard Henderson /* 4770313bdea8SRichard Henderson * If the ABI passes a pointer to the returned struct as the first 4771313bdea8SRichard Henderson * argument, load that now. Pass a pointer to the output home slot. 4772313bdea8SRichard Henderson */ 4773313bdea8SRichard Henderson if (info->out_kind == TCG_CALL_RET_BY_REF) { 4774313bdea8SRichard Henderson TCGTemp *ts = arg_temp(op->args[0]); 4775313bdea8SRichard Henderson 4776313bdea8SRichard Henderson if (!ts->mem_allocated) { 4777313bdea8SRichard Henderson temp_allocate_frame(s, ts); 4778313bdea8SRichard Henderson } 4779313bdea8SRichard Henderson load_arg_ref(s, 0, ts->mem_base->reg, ts->mem_offset, &allocated_regs); 4780313bdea8SRichard Henderson } 4781313bdea8SRichard Henderson 4782cee44b03SRichard Henderson tcg_out_call(s, tcg_call_func(op), info); 4783c896fe29Sbellard 478439004a71SRichard Henderson /* Assign output registers and emit moves if needed. */ 478539004a71SRichard Henderson switch (info->out_kind) { 478639004a71SRichard Henderson case TCG_CALL_RET_NORMAL: 4787c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 478839004a71SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]); 47895e3d0c19SRichard Henderson TCGReg reg = tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, i); 4790d63e3b6eSRichard Henderson 4791d63e3b6eSRichard Henderson /* ENV should not be modified. */ 4792e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ts)); 4793d63e3b6eSRichard Henderson 4794098859f1SRichard Henderson set_temp_val_reg(s, ts, reg); 4795c896fe29Sbellard ts->mem_coherent = 0; 479639004a71SRichard Henderson } 479739004a71SRichard Henderson break; 4798313bdea8SRichard Henderson 4799c6556aa0SRichard Henderson case TCG_CALL_RET_BY_VEC: 4800c6556aa0SRichard Henderson { 4801c6556aa0SRichard Henderson TCGTemp *ts = arg_temp(op->args[0]); 4802c6556aa0SRichard Henderson 4803c6556aa0SRichard Henderson tcg_debug_assert(ts->base_type == TCG_TYPE_I128); 4804c6556aa0SRichard Henderson tcg_debug_assert(ts->temp_subindex == 0); 4805c6556aa0SRichard Henderson if (!ts->mem_allocated) { 4806c6556aa0SRichard Henderson temp_allocate_frame(s, ts); 4807c6556aa0SRichard Henderson } 4808c6556aa0SRichard Henderson tcg_out_st(s, TCG_TYPE_V128, 4809c6556aa0SRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0), 4810c6556aa0SRichard Henderson ts->mem_base->reg, ts->mem_offset); 4811c6556aa0SRichard Henderson } 4812c6556aa0SRichard Henderson /* fall through to mark all parts in memory */ 4813c6556aa0SRichard Henderson 4814313bdea8SRichard Henderson case TCG_CALL_RET_BY_REF: 4815313bdea8SRichard Henderson /* The callee has performed a write through the reference. */ 4816313bdea8SRichard Henderson for (i = 0; i < nb_oargs; i++) { 4817313bdea8SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]); 4818313bdea8SRichard Henderson ts->val_type = TEMP_VAL_MEM; 4819313bdea8SRichard Henderson } 4820313bdea8SRichard Henderson break; 4821313bdea8SRichard Henderson 482239004a71SRichard Henderson default: 482339004a71SRichard Henderson g_assert_not_reached(); 482439004a71SRichard Henderson } 482539004a71SRichard Henderson 482639004a71SRichard Henderson /* Flush or discard output registers as needed. */ 482739004a71SRichard Henderson for (i = 0; i < nb_oargs; i++) { 482839004a71SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]); 4829ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) { 483039004a71SRichard Henderson temp_sync(s, ts, s->reserved_regs, 0, IS_DEAD_ARG(i)); 483159d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) { 4832f8bf00f1SRichard Henderson temp_dead(s, ts); 4833c896fe29Sbellard } 4834c896fe29Sbellard } 48358c11ad25SAurelien Jarno } 4836c896fe29Sbellard 4837c896fe29Sbellard #ifdef CONFIG_PROFILER 4838c896fe29Sbellard 4839c3fac113SEmilio G. Cota /* avoid copy/paste errors */ 4840c3fac113SEmilio G. Cota #define PROF_ADD(to, from, field) \ 4841c3fac113SEmilio G. Cota do { \ 4842d73415a3SStefan Hajnoczi (to)->field += qatomic_read(&((from)->field)); \ 4843c3fac113SEmilio G. Cota } while (0) 4844c896fe29Sbellard 4845c3fac113SEmilio G. Cota #define PROF_MAX(to, from, field) \ 4846c3fac113SEmilio G. Cota do { \ 4847d73415a3SStefan Hajnoczi typeof((from)->field) val__ = qatomic_read(&((from)->field)); \ 4848c3fac113SEmilio G. Cota if (val__ > (to)->field) { \ 4849c3fac113SEmilio G. Cota (to)->field = val__; \ 4850c3fac113SEmilio G. Cota } \ 4851c3fac113SEmilio G. Cota } while (0) 4852c3fac113SEmilio G. Cota 4853c3fac113SEmilio G. Cota /* Pass in a zero'ed @prof */ 4854c3fac113SEmilio G. Cota static inline 4855c3fac113SEmilio G. Cota void tcg_profile_snapshot(TCGProfile *prof, bool counters, bool table) 4856c896fe29Sbellard { 48570e2d61cfSRichard Henderson unsigned int n_ctxs = qatomic_read(&tcg_cur_ctxs); 4858c3fac113SEmilio G. Cota unsigned int i; 4859c3fac113SEmilio G. Cota 48603468b59eSEmilio G. Cota for (i = 0; i < n_ctxs; i++) { 4861d73415a3SStefan Hajnoczi TCGContext *s = qatomic_read(&tcg_ctxs[i]); 48623468b59eSEmilio G. Cota const TCGProfile *orig = &s->prof; 4863c3fac113SEmilio G. Cota 4864c3fac113SEmilio G. Cota if (counters) { 486572fd2efbSEmilio G. Cota PROF_ADD(prof, orig, cpu_exec_time); 4866c3fac113SEmilio G. Cota PROF_ADD(prof, orig, tb_count1); 4867c3fac113SEmilio G. Cota PROF_ADD(prof, orig, tb_count); 4868c3fac113SEmilio G. Cota PROF_ADD(prof, orig, op_count); 4869c3fac113SEmilio G. Cota PROF_MAX(prof, orig, op_count_max); 4870c3fac113SEmilio G. Cota PROF_ADD(prof, orig, temp_count); 4871c3fac113SEmilio G. Cota PROF_MAX(prof, orig, temp_count_max); 4872c3fac113SEmilio G. Cota PROF_ADD(prof, orig, del_op_count); 4873c3fac113SEmilio G. Cota PROF_ADD(prof, orig, code_in_len); 4874c3fac113SEmilio G. Cota PROF_ADD(prof, orig, code_out_len); 4875c3fac113SEmilio G. Cota PROF_ADD(prof, orig, search_out_len); 4876c3fac113SEmilio G. Cota PROF_ADD(prof, orig, interm_time); 4877c3fac113SEmilio G. Cota PROF_ADD(prof, orig, code_time); 4878c3fac113SEmilio G. Cota PROF_ADD(prof, orig, la_time); 4879c3fac113SEmilio G. Cota PROF_ADD(prof, orig, opt_time); 4880c3fac113SEmilio G. Cota PROF_ADD(prof, orig, restore_count); 4881c3fac113SEmilio G. Cota PROF_ADD(prof, orig, restore_time); 4882c3fac113SEmilio G. Cota } 4883c3fac113SEmilio G. Cota if (table) { 4884c896fe29Sbellard int i; 4885d70724ceSzhanghailiang 488615fc7daaSRichard Henderson for (i = 0; i < NB_OPS; i++) { 4887c3fac113SEmilio G. Cota PROF_ADD(prof, orig, table_op_count[i]); 4888c3fac113SEmilio G. Cota } 4889c3fac113SEmilio G. Cota } 4890c3fac113SEmilio G. Cota } 4891c3fac113SEmilio G. Cota } 4892c3fac113SEmilio G. Cota 4893c3fac113SEmilio G. Cota #undef PROF_ADD 4894c3fac113SEmilio G. Cota #undef PROF_MAX 4895c3fac113SEmilio G. Cota 4896c3fac113SEmilio G. Cota static void tcg_profile_snapshot_counters(TCGProfile *prof) 4897c3fac113SEmilio G. Cota { 4898c3fac113SEmilio G. Cota tcg_profile_snapshot(prof, true, false); 4899c3fac113SEmilio G. Cota } 4900c3fac113SEmilio G. Cota 4901c3fac113SEmilio G. Cota static void tcg_profile_snapshot_table(TCGProfile *prof) 4902c3fac113SEmilio G. Cota { 4903c3fac113SEmilio G. Cota tcg_profile_snapshot(prof, false, true); 4904c3fac113SEmilio G. Cota } 4905c3fac113SEmilio G. Cota 4906b6a7f3e0SDaniel P. Berrangé void tcg_dump_op_count(GString *buf) 4907c3fac113SEmilio G. Cota { 4908c3fac113SEmilio G. Cota TCGProfile prof = {}; 4909c3fac113SEmilio G. Cota int i; 4910c3fac113SEmilio G. Cota 4911c3fac113SEmilio G. Cota tcg_profile_snapshot_table(&prof); 4912c3fac113SEmilio G. Cota for (i = 0; i < NB_OPS; i++) { 4913b6a7f3e0SDaniel P. Berrangé g_string_append_printf(buf, "%s %" PRId64 "\n", tcg_op_defs[i].name, 4914c3fac113SEmilio G. Cota prof.table_op_count[i]); 4915c896fe29Sbellard } 4916c896fe29Sbellard } 491772fd2efbSEmilio G. Cota 491872fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void) 491972fd2efbSEmilio G. Cota { 49200e2d61cfSRichard Henderson unsigned int n_ctxs = qatomic_read(&tcg_cur_ctxs); 492172fd2efbSEmilio G. Cota unsigned int i; 492272fd2efbSEmilio G. Cota int64_t ret = 0; 492372fd2efbSEmilio G. Cota 492472fd2efbSEmilio G. Cota for (i = 0; i < n_ctxs; i++) { 4925d73415a3SStefan Hajnoczi const TCGContext *s = qatomic_read(&tcg_ctxs[i]); 492672fd2efbSEmilio G. Cota const TCGProfile *prof = &s->prof; 492772fd2efbSEmilio G. Cota 4928d73415a3SStefan Hajnoczi ret += qatomic_read(&prof->cpu_exec_time); 492972fd2efbSEmilio G. Cota } 493072fd2efbSEmilio G. Cota return ret; 493172fd2efbSEmilio G. Cota } 4932246ae24dSMax Filippov #else 4933b6a7f3e0SDaniel P. Berrangé void tcg_dump_op_count(GString *buf) 4934246ae24dSMax Filippov { 4935b6a7f3e0SDaniel P. Berrangé g_string_append_printf(buf, "[TCG profiler not compiled]\n"); 4936246ae24dSMax Filippov } 493772fd2efbSEmilio G. Cota 493872fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void) 493972fd2efbSEmilio G. Cota { 494072fd2efbSEmilio G. Cota error_report("%s: TCG profiler not compiled", __func__); 494172fd2efbSEmilio G. Cota exit(EXIT_FAILURE); 494272fd2efbSEmilio G. Cota } 4943c896fe29Sbellard #endif 4944c896fe29Sbellard 4945c896fe29Sbellard 4946fbf59aadSRichard Henderson int tcg_gen_code(TCGContext *s, TranslationBlock *tb, target_ulong pc_start) 4947c896fe29Sbellard { 4948c3fac113SEmilio G. Cota #ifdef CONFIG_PROFILER 4949c3fac113SEmilio G. Cota TCGProfile *prof = &s->prof; 4950c3fac113SEmilio G. Cota #endif 495115fa08f8SRichard Henderson int i, num_insns; 495215fa08f8SRichard Henderson TCGOp *op; 4953c896fe29Sbellard 495404fe6400SRichard Henderson #ifdef CONFIG_PROFILER 495504fe6400SRichard Henderson { 4956c1f543b7SEmilio G. Cota int n = 0; 495704fe6400SRichard Henderson 495815fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 495915fa08f8SRichard Henderson n++; 496015fa08f8SRichard Henderson } 4961d73415a3SStefan Hajnoczi qatomic_set(&prof->op_count, prof->op_count + n); 4962c3fac113SEmilio G. Cota if (n > prof->op_count_max) { 4963d73415a3SStefan Hajnoczi qatomic_set(&prof->op_count_max, n); 496404fe6400SRichard Henderson } 496504fe6400SRichard Henderson 496604fe6400SRichard Henderson n = s->nb_temps; 4967d73415a3SStefan Hajnoczi qatomic_set(&prof->temp_count, prof->temp_count + n); 4968c3fac113SEmilio G. Cota if (n > prof->temp_count_max) { 4969d73415a3SStefan Hajnoczi qatomic_set(&prof->temp_count_max, n); 497004fe6400SRichard Henderson } 497104fe6400SRichard Henderson } 497204fe6400SRichard Henderson #endif 497304fe6400SRichard Henderson 4974c896fe29Sbellard #ifdef DEBUG_DISAS 4975d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP) 4976fbf59aadSRichard Henderson && qemu_log_in_addr_range(pc_start))) { 4977c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock(); 497878b54858SRichard Henderson if (logfile) { 497978b54858SRichard Henderson fprintf(logfile, "OP:\n"); 4980b7a83ff8SRichard Henderson tcg_dump_ops(s, logfile, false); 498178b54858SRichard Henderson fprintf(logfile, "\n"); 4982fc59d2d8SRobert Foley qemu_log_unlock(logfile); 4983c896fe29Sbellard } 498478b54858SRichard Henderson } 4985c896fe29Sbellard #endif 4986c896fe29Sbellard 4987bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG 4988bef16ab4SRichard Henderson /* Ensure all labels referenced have been emitted. */ 4989bef16ab4SRichard Henderson { 4990bef16ab4SRichard Henderson TCGLabel *l; 4991bef16ab4SRichard Henderson bool error = false; 4992bef16ab4SRichard Henderson 4993bef16ab4SRichard Henderson QSIMPLEQ_FOREACH(l, &s->labels, next) { 4994f85b1fc4SRichard Henderson if (unlikely(!l->present) && !QSIMPLEQ_EMPTY(&l->branches)) { 4995bef16ab4SRichard Henderson qemu_log_mask(CPU_LOG_TB_OP, 4996bef16ab4SRichard Henderson "$L%d referenced but not present.\n", l->id); 4997bef16ab4SRichard Henderson error = true; 4998bef16ab4SRichard Henderson } 4999bef16ab4SRichard Henderson } 5000bef16ab4SRichard Henderson assert(!error); 5001bef16ab4SRichard Henderson } 5002bef16ab4SRichard Henderson #endif 5003bef16ab4SRichard Henderson 5004c5cc28ffSAurelien Jarno #ifdef CONFIG_PROFILER 5005d73415a3SStefan Hajnoczi qatomic_set(&prof->opt_time, prof->opt_time - profile_getclock()); 5006c5cc28ffSAurelien Jarno #endif 5007c5cc28ffSAurelien Jarno 50088f2e8c07SKirill Batuzov #ifdef USE_TCG_OPTIMIZATIONS 5009c45cb8bbSRichard Henderson tcg_optimize(s); 50108f2e8c07SKirill Batuzov #endif 50118f2e8c07SKirill Batuzov 5012a23a9ec6Sbellard #ifdef CONFIG_PROFILER 5013d73415a3SStefan Hajnoczi qatomic_set(&prof->opt_time, prof->opt_time + profile_getclock()); 5014d73415a3SStefan Hajnoczi qatomic_set(&prof->la_time, prof->la_time - profile_getclock()); 5015a23a9ec6Sbellard #endif 5016c5cc28ffSAurelien Jarno 5017b4fc67c7SRichard Henderson reachable_code_pass(s); 5018874b8574SRichard Henderson liveness_pass_0(s); 5019b83eabeaSRichard Henderson liveness_pass_1(s); 50205a18407fSRichard Henderson 50215a18407fSRichard Henderson if (s->nb_indirects > 0) { 50225a18407fSRichard Henderson #ifdef DEBUG_DISAS 50235a18407fSRichard Henderson if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND) 5024fbf59aadSRichard Henderson && qemu_log_in_addr_range(pc_start))) { 5025c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock(); 502678b54858SRichard Henderson if (logfile) { 502778b54858SRichard Henderson fprintf(logfile, "OP before indirect lowering:\n"); 5028b7a83ff8SRichard Henderson tcg_dump_ops(s, logfile, false); 502978b54858SRichard Henderson fprintf(logfile, "\n"); 5030fc59d2d8SRobert Foley qemu_log_unlock(logfile); 50315a18407fSRichard Henderson } 503278b54858SRichard Henderson } 50335a18407fSRichard Henderson #endif 50345a18407fSRichard Henderson /* Replace indirect temps with direct temps. */ 5035b83eabeaSRichard Henderson if (liveness_pass_2(s)) { 50365a18407fSRichard Henderson /* If changes were made, re-run liveness. */ 5037b83eabeaSRichard Henderson liveness_pass_1(s); 50385a18407fSRichard Henderson } 50395a18407fSRichard Henderson } 5040c5cc28ffSAurelien Jarno 5041a23a9ec6Sbellard #ifdef CONFIG_PROFILER 5042d73415a3SStefan Hajnoczi qatomic_set(&prof->la_time, prof->la_time + profile_getclock()); 5043a23a9ec6Sbellard #endif 5044c896fe29Sbellard 5045c896fe29Sbellard #ifdef DEBUG_DISAS 5046d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT) 5047fbf59aadSRichard Henderson && qemu_log_in_addr_range(pc_start))) { 5048c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock(); 504978b54858SRichard Henderson if (logfile) { 505078b54858SRichard Henderson fprintf(logfile, "OP after optimization and liveness analysis:\n"); 5051b7a83ff8SRichard Henderson tcg_dump_ops(s, logfile, true); 505278b54858SRichard Henderson fprintf(logfile, "\n"); 5053fc59d2d8SRobert Foley qemu_log_unlock(logfile); 5054c896fe29Sbellard } 505578b54858SRichard Henderson } 5056c896fe29Sbellard #endif 5057c896fe29Sbellard 505835abb009SRichard Henderson /* Initialize goto_tb jump offsets. */ 50593a50f424SRichard Henderson tb->jmp_reset_offset[0] = TB_JMP_OFFSET_INVALID; 50603a50f424SRichard Henderson tb->jmp_reset_offset[1] = TB_JMP_OFFSET_INVALID; 50619da6079bSRichard Henderson tb->jmp_insn_offset[0] = TB_JMP_OFFSET_INVALID; 50629da6079bSRichard Henderson tb->jmp_insn_offset[1] = TB_JMP_OFFSET_INVALID; 506335abb009SRichard Henderson 5064c896fe29Sbellard tcg_reg_alloc_start(s); 5065c896fe29Sbellard 5066db0c51a3SRichard Henderson /* 5067db0c51a3SRichard Henderson * Reset the buffer pointers when restarting after overflow. 5068db0c51a3SRichard Henderson * TODO: Move this into translate-all.c with the rest of the 5069db0c51a3SRichard Henderson * buffer management. Having only this done here is confusing. 5070db0c51a3SRichard Henderson */ 5071db0c51a3SRichard Henderson s->code_buf = tcg_splitwx_to_rw(tb->tc.ptr); 5072db0c51a3SRichard Henderson s->code_ptr = s->code_buf; 5073c896fe29Sbellard 5074659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS 50756001f772SLaurent Vivier QSIMPLEQ_INIT(&s->ldst_labels); 5076659ef5cbSRichard Henderson #endif 507757a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 507857a26946SRichard Henderson s->pool_labels = NULL; 507957a26946SRichard Henderson #endif 50809ecefc84SRichard Henderson 5081fca8a500SRichard Henderson num_insns = -1; 508215fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 5083c45cb8bbSRichard Henderson TCGOpcode opc = op->opc; 5084b3db8758Sblueswir1 5085c896fe29Sbellard #ifdef CONFIG_PROFILER 5086d73415a3SStefan Hajnoczi qatomic_set(&prof->table_op_count[opc], prof->table_op_count[opc] + 1); 5087c896fe29Sbellard #endif 5088c45cb8bbSRichard Henderson 5089c896fe29Sbellard switch (opc) { 5090c896fe29Sbellard case INDEX_op_mov_i32: 5091c896fe29Sbellard case INDEX_op_mov_i64: 5092d2fd745fSRichard Henderson case INDEX_op_mov_vec: 5093dd186292SRichard Henderson tcg_reg_alloc_mov(s, op); 5094c896fe29Sbellard break; 5095bab1671fSRichard Henderson case INDEX_op_dup_vec: 5096bab1671fSRichard Henderson tcg_reg_alloc_dup(s, op); 5097bab1671fSRichard Henderson break; 5098765b842aSRichard Henderson case INDEX_op_insn_start: 5099fca8a500SRichard Henderson if (num_insns >= 0) { 51009f754620SRichard Henderson size_t off = tcg_current_code_size(s); 51019f754620SRichard Henderson s->gen_insn_end_off[num_insns] = off; 51029f754620SRichard Henderson /* Assert that we do not overflow our stored offset. */ 51039f754620SRichard Henderson assert(s->gen_insn_end_off[num_insns] == off); 5104fca8a500SRichard Henderson } 5105fca8a500SRichard Henderson num_insns++; 5106bad729e2SRichard Henderson for (i = 0; i < TARGET_INSN_START_WORDS; ++i) { 5107bad729e2SRichard Henderson target_ulong a; 5108bad729e2SRichard Henderson #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS 5109efee3746SRichard Henderson a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]); 5110bad729e2SRichard Henderson #else 5111efee3746SRichard Henderson a = op->args[i]; 5112bad729e2SRichard Henderson #endif 5113fca8a500SRichard Henderson s->gen_insn_data[num_insns][i] = a; 5114bad729e2SRichard Henderson } 5115c896fe29Sbellard break; 51165ff9d6a4Sbellard case INDEX_op_discard: 511743439139SRichard Henderson temp_dead(s, arg_temp(op->args[0])); 51185ff9d6a4Sbellard break; 5119c896fe29Sbellard case INDEX_op_set_label: 5120e8996ee0Sbellard tcg_reg_alloc_bb_end(s, s->reserved_regs); 512192ab8e7dSRichard Henderson tcg_out_label(s, arg_label(op->args[0])); 5122c896fe29Sbellard break; 5123c896fe29Sbellard case INDEX_op_call: 5124dd186292SRichard Henderson tcg_reg_alloc_call(s, op); 5125c45cb8bbSRichard Henderson break; 5126b55a8d9dSRichard Henderson case INDEX_op_exit_tb: 5127b55a8d9dSRichard Henderson tcg_out_exit_tb(s, op->args[0]); 5128b55a8d9dSRichard Henderson break; 5129cf7d6b8eSRichard Henderson case INDEX_op_goto_tb: 5130cf7d6b8eSRichard Henderson tcg_out_goto_tb(s, op->args[0]); 5131cf7d6b8eSRichard Henderson break; 5132efe86b21SRichard Henderson case INDEX_op_dup2_vec: 5133efe86b21SRichard Henderson if (tcg_reg_alloc_dup2(s, op)) { 5134efe86b21SRichard Henderson break; 5135efe86b21SRichard Henderson } 5136efe86b21SRichard Henderson /* fall through */ 5137c896fe29Sbellard default: 513825c4d9ccSRichard Henderson /* Sanity check that we've not introduced any unhandled opcodes. */ 5139be0f34b5SRichard Henderson tcg_debug_assert(tcg_op_supported(opc)); 5140c896fe29Sbellard /* Note: in order to speed up the code, it would be much 5141c896fe29Sbellard faster to have specialized register allocator functions for 5142c896fe29Sbellard some common argument patterns */ 5143dd186292SRichard Henderson tcg_reg_alloc_op(s, op); 5144c896fe29Sbellard break; 5145c896fe29Sbellard } 5146b125f9dcSRichard Henderson /* Test for (pending) buffer overflow. The assumption is that any 5147b125f9dcSRichard Henderson one operation beginning below the high water mark cannot overrun 5148b125f9dcSRichard Henderson the buffer completely. Thus we can test for overflow after 5149b125f9dcSRichard Henderson generating code without having to check during generation. */ 5150644da9b3SJohn Clarke if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) { 5151b125f9dcSRichard Henderson return -1; 5152b125f9dcSRichard Henderson } 51536e6c4efeSRichard Henderson /* Test for TB overflow, as seen by gen_insn_end_off. */ 51546e6c4efeSRichard Henderson if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) { 51556e6c4efeSRichard Henderson return -2; 51566e6c4efeSRichard Henderson } 5157c896fe29Sbellard } 5158fca8a500SRichard Henderson tcg_debug_assert(num_insns >= 0); 5159fca8a500SRichard Henderson s->gen_insn_end_off[num_insns] = tcg_current_code_size(s); 5160c45cb8bbSRichard Henderson 5161b76f0d8cSYeongkyoon Lee /* Generate TB finalization at the end of block */ 5162659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS 5163aeee05f5SRichard Henderson i = tcg_out_ldst_finalize(s); 5164aeee05f5SRichard Henderson if (i < 0) { 5165aeee05f5SRichard Henderson return i; 516623dceda6SRichard Henderson } 5167659ef5cbSRichard Henderson #endif 516857a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 51691768987bSRichard Henderson i = tcg_out_pool_finalize(s); 51701768987bSRichard Henderson if (i < 0) { 51711768987bSRichard Henderson return i; 517257a26946SRichard Henderson } 517357a26946SRichard Henderson #endif 51747ecd02a0SRichard Henderson if (!tcg_resolve_relocs(s)) { 51757ecd02a0SRichard Henderson return -2; 51767ecd02a0SRichard Henderson } 5177c896fe29Sbellard 5178df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 5179c896fe29Sbellard /* flush instruction cache */ 5180db0c51a3SRichard Henderson flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf), 5181db0c51a3SRichard Henderson (uintptr_t)s->code_buf, 51821da8de39SRichard Henderson tcg_ptr_byte_diff(s->code_ptr, s->code_buf)); 5183df5d2b16SRichard Henderson #endif 51842aeabc08SStefan Weil 51851813e175SRichard Henderson return tcg_current_code_size(s); 5186c896fe29Sbellard } 5187c896fe29Sbellard 5188a23a9ec6Sbellard #ifdef CONFIG_PROFILER 51893a841ab5SDaniel P. Berrangé void tcg_dump_info(GString *buf) 5190a23a9ec6Sbellard { 5191c3fac113SEmilio G. Cota TCGProfile prof = {}; 5192c3fac113SEmilio G. Cota const TCGProfile *s; 5193c3fac113SEmilio G. Cota int64_t tb_count; 5194c3fac113SEmilio G. Cota int64_t tb_div_count; 5195c3fac113SEmilio G. Cota int64_t tot; 5196c3fac113SEmilio G. Cota 5197c3fac113SEmilio G. Cota tcg_profile_snapshot_counters(&prof); 5198c3fac113SEmilio G. Cota s = &prof; 5199c3fac113SEmilio G. Cota tb_count = s->tb_count; 5200c3fac113SEmilio G. Cota tb_div_count = tb_count ? tb_count : 1; 5201c3fac113SEmilio G. Cota tot = s->interm_time + s->code_time; 5202a23a9ec6Sbellard 52033a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "JIT cycles %" PRId64 52043a841ab5SDaniel P. Berrangé " (%0.3f s at 2.4 GHz)\n", 5205a23a9ec6Sbellard tot, tot / 2.4e9); 52063a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "translated TBs %" PRId64 52073a841ab5SDaniel P. Berrangé " (aborted=%" PRId64 " %0.1f%%)\n", 5208fca8a500SRichard Henderson tb_count, s->tb_count1 - tb_count, 5209fca8a500SRichard Henderson (double)(s->tb_count1 - s->tb_count) 5210fca8a500SRichard Henderson / (s->tb_count1 ? s->tb_count1 : 1) * 100.0); 52113a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "avg ops/TB %0.1f max=%d\n", 5212fca8a500SRichard Henderson (double)s->op_count / tb_div_count, s->op_count_max); 52133a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "deleted ops/TB %0.2f\n", 5214fca8a500SRichard Henderson (double)s->del_op_count / tb_div_count); 52153a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "avg temps/TB %0.2f max=%d\n", 52163a841ab5SDaniel P. Berrangé (double)s->temp_count / tb_div_count, 52173a841ab5SDaniel P. Berrangé s->temp_count_max); 52183a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "avg host code/TB %0.1f\n", 5219fca8a500SRichard Henderson (double)s->code_out_len / tb_div_count); 52203a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "avg search data/TB %0.1f\n", 5221fca8a500SRichard Henderson (double)s->search_out_len / tb_div_count); 5222a23a9ec6Sbellard 52233a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "cycles/op %0.1f\n", 5224a23a9ec6Sbellard s->op_count ? (double)tot / s->op_count : 0); 52253a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "cycles/in byte %0.1f\n", 5226a23a9ec6Sbellard s->code_in_len ? (double)tot / s->code_in_len : 0); 52273a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "cycles/out byte %0.1f\n", 5228a23a9ec6Sbellard s->code_out_len ? (double)tot / s->code_out_len : 0); 52293a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "cycles/search byte %0.1f\n", 52303a841ab5SDaniel P. Berrangé s->search_out_len ? 52313a841ab5SDaniel P. Berrangé (double)tot / s->search_out_len : 0); 5232fca8a500SRichard Henderson if (tot == 0) { 5233a23a9ec6Sbellard tot = 1; 5234fca8a500SRichard Henderson } 52353a841ab5SDaniel P. Berrangé g_string_append_printf(buf, " gen_interm time %0.1f%%\n", 5236a23a9ec6Sbellard (double)s->interm_time / tot * 100.0); 52373a841ab5SDaniel P. Berrangé g_string_append_printf(buf, " gen_code time %0.1f%%\n", 5238a23a9ec6Sbellard (double)s->code_time / tot * 100.0); 52393a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "optim./code time %0.1f%%\n", 52403a841ab5SDaniel P. Berrangé (double)s->opt_time / (s->code_time ? 52413a841ab5SDaniel P. Berrangé s->code_time : 1) 5242c5cc28ffSAurelien Jarno * 100.0); 52433a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "liveness/code time %0.1f%%\n", 52443a841ab5SDaniel P. Berrangé (double)s->la_time / (s->code_time ? 52453a841ab5SDaniel P. Berrangé s->code_time : 1) * 100.0); 52463a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "cpu_restore count %" PRId64 "\n", 5247a23a9ec6Sbellard s->restore_count); 52483a841ab5SDaniel P. Berrangé g_string_append_printf(buf, " avg cycles %0.1f\n", 52493a841ab5SDaniel P. Berrangé s->restore_count ? 52503a841ab5SDaniel P. Berrangé (double)s->restore_time / s->restore_count : 0); 5251a23a9ec6Sbellard } 5252a23a9ec6Sbellard #else 52533a841ab5SDaniel P. Berrangé void tcg_dump_info(GString *buf) 5254a23a9ec6Sbellard { 52553a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "[TCG profiler not compiled]\n"); 5256a23a9ec6Sbellard } 5257a23a9ec6Sbellard #endif 5258813da627SRichard Henderson 5259813da627SRichard Henderson #ifdef ELF_HOST_MACHINE 52605872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things: 52615872bbf2SRichard Henderson 52625872bbf2SRichard Henderson (1) Define ELF_HOST_MACHINE to indicate both what value to 52635872bbf2SRichard Henderson put into the ELF image and to indicate support for the feature. 52645872bbf2SRichard Henderson 52655872bbf2SRichard Henderson (2) Define tcg_register_jit. This should create a buffer containing 52665872bbf2SRichard Henderson the contents of a .debug_frame section that describes the post- 52675872bbf2SRichard Henderson prologue unwind info for the tcg machine. 52685872bbf2SRichard Henderson 52695872bbf2SRichard Henderson (3) Call tcg_register_jit_int, with the constructed .debug_frame. 52705872bbf2SRichard Henderson */ 5271813da627SRichard Henderson 5272813da627SRichard Henderson /* Begin GDB interface. THE FOLLOWING MUST MATCH GDB DOCS. */ 5273813da627SRichard Henderson typedef enum { 5274813da627SRichard Henderson JIT_NOACTION = 0, 5275813da627SRichard Henderson JIT_REGISTER_FN, 5276813da627SRichard Henderson JIT_UNREGISTER_FN 5277813da627SRichard Henderson } jit_actions_t; 5278813da627SRichard Henderson 5279813da627SRichard Henderson struct jit_code_entry { 5280813da627SRichard Henderson struct jit_code_entry *next_entry; 5281813da627SRichard Henderson struct jit_code_entry *prev_entry; 5282813da627SRichard Henderson const void *symfile_addr; 5283813da627SRichard Henderson uint64_t symfile_size; 5284813da627SRichard Henderson }; 5285813da627SRichard Henderson 5286813da627SRichard Henderson struct jit_descriptor { 5287813da627SRichard Henderson uint32_t version; 5288813da627SRichard Henderson uint32_t action_flag; 5289813da627SRichard Henderson struct jit_code_entry *relevant_entry; 5290813da627SRichard Henderson struct jit_code_entry *first_entry; 5291813da627SRichard Henderson }; 5292813da627SRichard Henderson 5293813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline)); 5294813da627SRichard Henderson void __jit_debug_register_code(void) 5295813da627SRichard Henderson { 5296813da627SRichard Henderson asm(""); 5297813da627SRichard Henderson } 5298813da627SRichard Henderson 5299813da627SRichard Henderson /* Must statically initialize the version, because GDB may check 5300813da627SRichard Henderson the version before we can set it. */ 5301813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 }; 5302813da627SRichard Henderson 5303813da627SRichard Henderson /* End GDB interface. */ 5304813da627SRichard Henderson 5305813da627SRichard Henderson static int find_string(const char *strtab, const char *str) 5306813da627SRichard Henderson { 5307813da627SRichard Henderson const char *p = strtab + 1; 5308813da627SRichard Henderson 5309813da627SRichard Henderson while (1) { 5310813da627SRichard Henderson if (strcmp(p, str) == 0) { 5311813da627SRichard Henderson return p - strtab; 5312813da627SRichard Henderson } 5313813da627SRichard Henderson p += strlen(p) + 1; 5314813da627SRichard Henderson } 5315813da627SRichard Henderson } 5316813da627SRichard Henderson 5317755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf_ptr, size_t buf_size, 53182c90784aSRichard Henderson const void *debug_frame, 53192c90784aSRichard Henderson size_t debug_frame_size) 5320813da627SRichard Henderson { 53215872bbf2SRichard Henderson struct __attribute__((packed)) DebugInfo { 53225872bbf2SRichard Henderson uint32_t len; 53235872bbf2SRichard Henderson uint16_t version; 53245872bbf2SRichard Henderson uint32_t abbrev; 53255872bbf2SRichard Henderson uint8_t ptr_size; 53265872bbf2SRichard Henderson uint8_t cu_die; 53275872bbf2SRichard Henderson uint16_t cu_lang; 53285872bbf2SRichard Henderson uintptr_t cu_low_pc; 53295872bbf2SRichard Henderson uintptr_t cu_high_pc; 53305872bbf2SRichard Henderson uint8_t fn_die; 53315872bbf2SRichard Henderson char fn_name[16]; 53325872bbf2SRichard Henderson uintptr_t fn_low_pc; 53335872bbf2SRichard Henderson uintptr_t fn_high_pc; 53345872bbf2SRichard Henderson uint8_t cu_eoc; 53355872bbf2SRichard Henderson }; 5336813da627SRichard Henderson 5337813da627SRichard Henderson struct ElfImage { 5338813da627SRichard Henderson ElfW(Ehdr) ehdr; 5339813da627SRichard Henderson ElfW(Phdr) phdr; 53405872bbf2SRichard Henderson ElfW(Shdr) shdr[7]; 53415872bbf2SRichard Henderson ElfW(Sym) sym[2]; 53425872bbf2SRichard Henderson struct DebugInfo di; 53435872bbf2SRichard Henderson uint8_t da[24]; 53445872bbf2SRichard Henderson char str[80]; 53455872bbf2SRichard Henderson }; 53465872bbf2SRichard Henderson 53475872bbf2SRichard Henderson struct ElfImage *img; 53485872bbf2SRichard Henderson 53495872bbf2SRichard Henderson static const struct ElfImage img_template = { 53505872bbf2SRichard Henderson .ehdr = { 53515872bbf2SRichard Henderson .e_ident[EI_MAG0] = ELFMAG0, 53525872bbf2SRichard Henderson .e_ident[EI_MAG1] = ELFMAG1, 53535872bbf2SRichard Henderson .e_ident[EI_MAG2] = ELFMAG2, 53545872bbf2SRichard Henderson .e_ident[EI_MAG3] = ELFMAG3, 53555872bbf2SRichard Henderson .e_ident[EI_CLASS] = ELF_CLASS, 53565872bbf2SRichard Henderson .e_ident[EI_DATA] = ELF_DATA, 53575872bbf2SRichard Henderson .e_ident[EI_VERSION] = EV_CURRENT, 53585872bbf2SRichard Henderson .e_type = ET_EXEC, 53595872bbf2SRichard Henderson .e_machine = ELF_HOST_MACHINE, 53605872bbf2SRichard Henderson .e_version = EV_CURRENT, 53615872bbf2SRichard Henderson .e_phoff = offsetof(struct ElfImage, phdr), 53625872bbf2SRichard Henderson .e_shoff = offsetof(struct ElfImage, shdr), 53635872bbf2SRichard Henderson .e_ehsize = sizeof(ElfW(Shdr)), 53645872bbf2SRichard Henderson .e_phentsize = sizeof(ElfW(Phdr)), 53655872bbf2SRichard Henderson .e_phnum = 1, 53665872bbf2SRichard Henderson .e_shentsize = sizeof(ElfW(Shdr)), 53675872bbf2SRichard Henderson .e_shnum = ARRAY_SIZE(img->shdr), 53685872bbf2SRichard Henderson .e_shstrndx = ARRAY_SIZE(img->shdr) - 1, 5369abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS 5370abbb3eaeSRichard Henderson .e_flags = ELF_HOST_FLAGS, 5371abbb3eaeSRichard Henderson #endif 5372abbb3eaeSRichard Henderson #ifdef ELF_OSABI 5373abbb3eaeSRichard Henderson .e_ident[EI_OSABI] = ELF_OSABI, 5374abbb3eaeSRichard Henderson #endif 53755872bbf2SRichard Henderson }, 53765872bbf2SRichard Henderson .phdr = { 53775872bbf2SRichard Henderson .p_type = PT_LOAD, 53785872bbf2SRichard Henderson .p_flags = PF_X, 53795872bbf2SRichard Henderson }, 53805872bbf2SRichard Henderson .shdr = { 53815872bbf2SRichard Henderson [0] = { .sh_type = SHT_NULL }, 53825872bbf2SRichard Henderson /* Trick: The contents of code_gen_buffer are not present in 53835872bbf2SRichard Henderson this fake ELF file; that got allocated elsewhere. Therefore 53845872bbf2SRichard Henderson we mark .text as SHT_NOBITS (similar to .bss) so that readers 53855872bbf2SRichard Henderson will not look for contents. We can record any address. */ 53865872bbf2SRichard Henderson [1] = { /* .text */ 53875872bbf2SRichard Henderson .sh_type = SHT_NOBITS, 53885872bbf2SRichard Henderson .sh_flags = SHF_EXECINSTR | SHF_ALLOC, 53895872bbf2SRichard Henderson }, 53905872bbf2SRichard Henderson [2] = { /* .debug_info */ 53915872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 53925872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, di), 53935872bbf2SRichard Henderson .sh_size = sizeof(struct DebugInfo), 53945872bbf2SRichard Henderson }, 53955872bbf2SRichard Henderson [3] = { /* .debug_abbrev */ 53965872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 53975872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, da), 53985872bbf2SRichard Henderson .sh_size = sizeof(img->da), 53995872bbf2SRichard Henderson }, 54005872bbf2SRichard Henderson [4] = { /* .debug_frame */ 54015872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 54025872bbf2SRichard Henderson .sh_offset = sizeof(struct ElfImage), 54035872bbf2SRichard Henderson }, 54045872bbf2SRichard Henderson [5] = { /* .symtab */ 54055872bbf2SRichard Henderson .sh_type = SHT_SYMTAB, 54065872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, sym), 54075872bbf2SRichard Henderson .sh_size = sizeof(img->sym), 54085872bbf2SRichard Henderson .sh_info = 1, 54095872bbf2SRichard Henderson .sh_link = ARRAY_SIZE(img->shdr) - 1, 54105872bbf2SRichard Henderson .sh_entsize = sizeof(ElfW(Sym)), 54115872bbf2SRichard Henderson }, 54125872bbf2SRichard Henderson [6] = { /* .strtab */ 54135872bbf2SRichard Henderson .sh_type = SHT_STRTAB, 54145872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, str), 54155872bbf2SRichard Henderson .sh_size = sizeof(img->str), 54165872bbf2SRichard Henderson } 54175872bbf2SRichard Henderson }, 54185872bbf2SRichard Henderson .sym = { 54195872bbf2SRichard Henderson [1] = { /* code_gen_buffer */ 54205872bbf2SRichard Henderson .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC), 54215872bbf2SRichard Henderson .st_shndx = 1, 54225872bbf2SRichard Henderson } 54235872bbf2SRichard Henderson }, 54245872bbf2SRichard Henderson .di = { 54255872bbf2SRichard Henderson .len = sizeof(struct DebugInfo) - 4, 54265872bbf2SRichard Henderson .version = 2, 54275872bbf2SRichard Henderson .ptr_size = sizeof(void *), 54285872bbf2SRichard Henderson .cu_die = 1, 54295872bbf2SRichard Henderson .cu_lang = 0x8001, /* DW_LANG_Mips_Assembler */ 54305872bbf2SRichard Henderson .fn_die = 2, 54315872bbf2SRichard Henderson .fn_name = "code_gen_buffer" 54325872bbf2SRichard Henderson }, 54335872bbf2SRichard Henderson .da = { 54345872bbf2SRichard Henderson 1, /* abbrev number (the cu) */ 54355872bbf2SRichard Henderson 0x11, 1, /* DW_TAG_compile_unit, has children */ 54365872bbf2SRichard Henderson 0x13, 0x5, /* DW_AT_language, DW_FORM_data2 */ 54375872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */ 54385872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */ 54395872bbf2SRichard Henderson 0, 0, /* end of abbrev */ 54405872bbf2SRichard Henderson 2, /* abbrev number (the fn) */ 54415872bbf2SRichard Henderson 0x2e, 0, /* DW_TAG_subprogram, no children */ 54425872bbf2SRichard Henderson 0x3, 0x8, /* DW_AT_name, DW_FORM_string */ 54435872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */ 54445872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */ 54455872bbf2SRichard Henderson 0, 0, /* end of abbrev */ 54465872bbf2SRichard Henderson 0 /* no more abbrev */ 54475872bbf2SRichard Henderson }, 54485872bbf2SRichard Henderson .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0" 54495872bbf2SRichard Henderson ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer", 5450813da627SRichard Henderson }; 5451813da627SRichard Henderson 5452813da627SRichard Henderson /* We only need a single jit entry; statically allocate it. */ 5453813da627SRichard Henderson static struct jit_code_entry one_entry; 5454813da627SRichard Henderson 54555872bbf2SRichard Henderson uintptr_t buf = (uintptr_t)buf_ptr; 5456813da627SRichard Henderson size_t img_size = sizeof(struct ElfImage) + debug_frame_size; 54572c90784aSRichard Henderson DebugFrameHeader *dfh; 5458813da627SRichard Henderson 54595872bbf2SRichard Henderson img = g_malloc(img_size); 54605872bbf2SRichard Henderson *img = img_template; 5461813da627SRichard Henderson 54625872bbf2SRichard Henderson img->phdr.p_vaddr = buf; 54635872bbf2SRichard Henderson img->phdr.p_paddr = buf; 54645872bbf2SRichard Henderson img->phdr.p_memsz = buf_size; 5465813da627SRichard Henderson 54665872bbf2SRichard Henderson img->shdr[1].sh_name = find_string(img->str, ".text"); 54675872bbf2SRichard Henderson img->shdr[1].sh_addr = buf; 54685872bbf2SRichard Henderson img->shdr[1].sh_size = buf_size; 5469813da627SRichard Henderson 54705872bbf2SRichard Henderson img->shdr[2].sh_name = find_string(img->str, ".debug_info"); 54715872bbf2SRichard Henderson img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev"); 54725872bbf2SRichard Henderson 54735872bbf2SRichard Henderson img->shdr[4].sh_name = find_string(img->str, ".debug_frame"); 54745872bbf2SRichard Henderson img->shdr[4].sh_size = debug_frame_size; 54755872bbf2SRichard Henderson 54765872bbf2SRichard Henderson img->shdr[5].sh_name = find_string(img->str, ".symtab"); 54775872bbf2SRichard Henderson img->shdr[6].sh_name = find_string(img->str, ".strtab"); 54785872bbf2SRichard Henderson 54795872bbf2SRichard Henderson img->sym[1].st_name = find_string(img->str, "code_gen_buffer"); 54805872bbf2SRichard Henderson img->sym[1].st_value = buf; 54815872bbf2SRichard Henderson img->sym[1].st_size = buf_size; 54825872bbf2SRichard Henderson 54835872bbf2SRichard Henderson img->di.cu_low_pc = buf; 548445aba097SRichard Henderson img->di.cu_high_pc = buf + buf_size; 54855872bbf2SRichard Henderson img->di.fn_low_pc = buf; 548645aba097SRichard Henderson img->di.fn_high_pc = buf + buf_size; 5487813da627SRichard Henderson 54882c90784aSRichard Henderson dfh = (DebugFrameHeader *)(img + 1); 54892c90784aSRichard Henderson memcpy(dfh, debug_frame, debug_frame_size); 54902c90784aSRichard Henderson dfh->fde.func_start = buf; 54912c90784aSRichard Henderson dfh->fde.func_len = buf_size; 54922c90784aSRichard Henderson 5493813da627SRichard Henderson #ifdef DEBUG_JIT 5494813da627SRichard Henderson /* Enable this block to be able to debug the ELF image file creation. 5495813da627SRichard Henderson One can use readelf, objdump, or other inspection utilities. */ 5496813da627SRichard Henderson { 5497eb6b2edfSBin Meng g_autofree char *jit = g_strdup_printf("%s/qemu.jit", g_get_tmp_dir()); 5498eb6b2edfSBin Meng FILE *f = fopen(jit, "w+b"); 5499813da627SRichard Henderson if (f) { 55005872bbf2SRichard Henderson if (fwrite(img, img_size, 1, f) != img_size) { 5501813da627SRichard Henderson /* Avoid stupid unused return value warning for fwrite. */ 5502813da627SRichard Henderson } 5503813da627SRichard Henderson fclose(f); 5504813da627SRichard Henderson } 5505813da627SRichard Henderson } 5506813da627SRichard Henderson #endif 5507813da627SRichard Henderson 5508813da627SRichard Henderson one_entry.symfile_addr = img; 5509813da627SRichard Henderson one_entry.symfile_size = img_size; 5510813da627SRichard Henderson 5511813da627SRichard Henderson __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; 5512813da627SRichard Henderson __jit_debug_descriptor.relevant_entry = &one_entry; 5513813da627SRichard Henderson __jit_debug_descriptor.first_entry = &one_entry; 5514813da627SRichard Henderson __jit_debug_register_code(); 5515813da627SRichard Henderson } 5516813da627SRichard Henderson #else 55175872bbf2SRichard Henderson /* No support for the feature. Provide the entry point expected by exec.c, 55185872bbf2SRichard Henderson and implement the internal function we declared earlier. */ 5519813da627SRichard Henderson 5520755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size, 55212c90784aSRichard Henderson const void *debug_frame, 55222c90784aSRichard Henderson size_t debug_frame_size) 5523813da627SRichard Henderson { 5524813da627SRichard Henderson } 5525813da627SRichard Henderson 5526755bf9e5SRichard Henderson void tcg_register_jit(const void *buf, size_t buf_size) 5527813da627SRichard Henderson { 5528813da627SRichard Henderson } 5529813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */ 5530db432672SRichard Henderson 5531db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec 5532db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...) 5533db432672SRichard Henderson { 5534db432672SRichard Henderson g_assert_not_reached(); 5535db432672SRichard Henderson } 5536db432672SRichard Henderson #endif 5537