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 972528f771SRichard Henderson typedef struct TCGLabelQemuLdst { 982528f771SRichard Henderson bool is_ld; /* qemu_ld: true, qemu_st: false */ 992528f771SRichard Henderson MemOpIdx oi; 1002528f771SRichard Henderson TCGType type; /* result type of a load */ 1012528f771SRichard Henderson TCGReg addrlo_reg; /* reg index for low word of guest virtual addr */ 1022528f771SRichard Henderson TCGReg addrhi_reg; /* reg index for high word of guest virtual addr */ 1032528f771SRichard Henderson TCGReg datalo_reg; /* reg index for low word to be loaded or stored */ 1042528f771SRichard Henderson TCGReg datahi_reg; /* reg index for high word to be loaded or stored */ 1052528f771SRichard Henderson const tcg_insn_unit *raddr; /* addr of the next IR of qemu_ld/st IR */ 1062528f771SRichard Henderson tcg_insn_unit *label_ptr[2]; /* label pointers to be updated */ 1072528f771SRichard Henderson QSIMPLEQ_ENTRY(TCGLabelQemuLdst) next; 1082528f771SRichard Henderson } TCGLabelQemuLdst; 1092528f771SRichard Henderson 110755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size, 1112c90784aSRichard Henderson const void *debug_frame, 1122c90784aSRichard Henderson size_t debug_frame_size) 113813da627SRichard Henderson __attribute__((unused)); 114813da627SRichard Henderson 115139c1837SPaolo Bonzini /* Forward declarations for functions declared and used in tcg-target.c.inc. */ 1162a534affSRichard Henderson static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1, 117a05b5b9bSRichard Henderson intptr_t arg2); 11878113e83SRichard Henderson static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg); 119c0ad3001SStefan Weil static void tcg_out_movi(TCGContext *s, TCGType type, 1202a534affSRichard Henderson TCGReg ret, tcg_target_long arg); 121678155b2SRichard Henderson static void tcg_out_ext8s(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg); 122753e42eaSRichard Henderson static void tcg_out_ext16s(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg); 123d0e66c89SRichard Henderson static void tcg_out_ext8u(TCGContext *s, TCGReg ret, TCGReg arg); 124379afdffSRichard Henderson static void tcg_out_ext16u(TCGContext *s, TCGReg ret, TCGReg arg); 12552bf3398SRichard Henderson static void tcg_out_ext32s(TCGContext *s, TCGReg ret, TCGReg arg); 1269ecf5f61SRichard Henderson static void tcg_out_ext32u(TCGContext *s, TCGReg ret, TCGReg arg); 1279c6aa274SRichard Henderson static void tcg_out_exts_i32_i64(TCGContext *s, TCGReg ret, TCGReg arg); 128b9bfe000SRichard Henderson static void tcg_out_extu_i32_i64(TCGContext *s, TCGReg ret, TCGReg arg); 129b8b94ac6SRichard Henderson static void tcg_out_extrl_i64_i32(TCGContext *s, TCGReg ret, TCGReg arg); 130313bdea8SRichard Henderson static void tcg_out_addi_ptr(TCGContext *s, TCGReg, TCGReg, tcg_target_long); 131129f1f9eSRichard Henderson static bool tcg_out_xchg(TCGContext *s, TCGType type, TCGReg r1, TCGReg r2); 132b55a8d9dSRichard Henderson static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg); 133cf7d6b8eSRichard Henderson static void tcg_out_goto_tb(TCGContext *s, int which); 1345e8892dbSMiroslav Rezanina static void tcg_out_op(TCGContext *s, TCGOpcode opc, 1355e8892dbSMiroslav Rezanina const TCGArg args[TCG_MAX_OP_ARGS], 1365e8892dbSMiroslav Rezanina const int const_args[TCG_MAX_OP_ARGS]); 137d2fd745fSRichard Henderson #if TCG_TARGET_MAYBE_vec 138e7632cfaSRichard Henderson static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece, 139e7632cfaSRichard Henderson TCGReg dst, TCGReg src); 140d6ecb4a9SRichard Henderson static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece, 141d6ecb4a9SRichard Henderson TCGReg dst, TCGReg base, intptr_t offset); 1424e186175SRichard Henderson static void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece, 1434e186175SRichard Henderson TCGReg dst, int64_t arg); 1445e8892dbSMiroslav Rezanina static 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 #else 149e7632cfaSRichard Henderson static inline bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece, 150e7632cfaSRichard Henderson TCGReg dst, TCGReg src) 151e7632cfaSRichard Henderson { 152e7632cfaSRichard Henderson g_assert_not_reached(); 153e7632cfaSRichard Henderson } 154d6ecb4a9SRichard Henderson static inline bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece, 155d6ecb4a9SRichard Henderson TCGReg dst, TCGReg base, intptr_t offset) 156d6ecb4a9SRichard Henderson { 157d6ecb4a9SRichard Henderson g_assert_not_reached(); 158d6ecb4a9SRichard Henderson } 1594e186175SRichard Henderson static inline void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece, 1604e186175SRichard Henderson TCGReg dst, int64_t arg) 161e7632cfaSRichard Henderson { 162e7632cfaSRichard Henderson g_assert_not_reached(); 163e7632cfaSRichard Henderson } 1645e8892dbSMiroslav Rezanina static inline void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, 1655e8892dbSMiroslav Rezanina unsigned vecl, unsigned vece, 1665e8892dbSMiroslav Rezanina const TCGArg args[TCG_MAX_OP_ARGS], 1675e8892dbSMiroslav Rezanina const int const_args[TCG_MAX_OP_ARGS]) 168d2fd745fSRichard Henderson { 169d2fd745fSRichard Henderson g_assert_not_reached(); 170d2fd745fSRichard Henderson } 171d2fd745fSRichard Henderson #endif 1722a534affSRichard Henderson static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1, 173a05b5b9bSRichard Henderson intptr_t arg2); 17459d7c14eSRichard Henderson static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val, 17559d7c14eSRichard Henderson TCGReg base, intptr_t ofs); 1767b7d8b2dSRichard Henderson static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target, 177cee44b03SRichard Henderson const TCGHelperInfo *info); 1785e3d0c19SRichard Henderson static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot); 179a4fbbd77SRichard Henderson static bool tcg_target_const_match(int64_t val, TCGType type, int ct); 180659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS 181aeee05f5SRichard Henderson static int tcg_out_ldst_finalize(TCGContext *s); 182659ef5cbSRichard Henderson #endif 183c896fe29Sbellard 18442eb6dfcSRichard Henderson TCGContext tcg_init_ctx; 18542eb6dfcSRichard Henderson __thread TCGContext *tcg_ctx; 18642eb6dfcSRichard Henderson 1875ff7258cSRichard Henderson TCGContext **tcg_ctxs; 1880e2d61cfSRichard Henderson unsigned int tcg_cur_ctxs; 1890e2d61cfSRichard Henderson unsigned int tcg_max_ctxs; 1901c2adb95SRichard Henderson TCGv_env cpu_env = 0; 191c8bc1168SRichard Henderson const void *tcg_code_gen_epilogue; 192db0c51a3SRichard Henderson uintptr_t tcg_splitwx_diff; 193df2cce29SEmilio G. Cota 194b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 195b91ccb31SRichard Henderson tcg_prologue_fn *tcg_qemu_tb_exec; 196b91ccb31SRichard Henderson #endif 197b91ccb31SRichard Henderson 198d2fd745fSRichard Henderson static TCGRegSet tcg_target_available_regs[TCG_TYPE_COUNT]; 199b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs; 200c896fe29Sbellard 2011813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1 2024196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v) 203c896fe29Sbellard { 204c896fe29Sbellard *s->code_ptr++ = v; 205c896fe29Sbellard } 206c896fe29Sbellard 2074196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p, 2084196dca6SPeter Maydell uint8_t v) 2095c53bb81SPeter Maydell { 2101813e175SRichard Henderson *p = v; 2115c53bb81SPeter Maydell } 2121813e175SRichard Henderson #endif 2135c53bb81SPeter Maydell 2141813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2 2154196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v) 216c896fe29Sbellard { 2171813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 2) { 2181813e175SRichard Henderson *s->code_ptr++ = v; 2191813e175SRichard Henderson } else { 2201813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 2214387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 2221813e175SRichard Henderson s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE); 2231813e175SRichard Henderson } 224c896fe29Sbellard } 225c896fe29Sbellard 2264196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p, 2274196dca6SPeter Maydell uint16_t v) 2285c53bb81SPeter Maydell { 2291813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 2) { 2301813e175SRichard Henderson *p = v; 2311813e175SRichard Henderson } else { 2325c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 2335c53bb81SPeter Maydell } 2341813e175SRichard Henderson } 2351813e175SRichard Henderson #endif 2365c53bb81SPeter Maydell 2371813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4 2384196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v) 239c896fe29Sbellard { 2401813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 4) { 2411813e175SRichard Henderson *s->code_ptr++ = v; 2421813e175SRichard Henderson } else { 2431813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 2444387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 2451813e175SRichard Henderson s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE); 2461813e175SRichard Henderson } 247c896fe29Sbellard } 248c896fe29Sbellard 2494196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p, 2504196dca6SPeter Maydell uint32_t v) 2515c53bb81SPeter Maydell { 2521813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 4) { 2531813e175SRichard Henderson *p = v; 2541813e175SRichard Henderson } else { 2555c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 2565c53bb81SPeter Maydell } 2571813e175SRichard Henderson } 2581813e175SRichard Henderson #endif 2595c53bb81SPeter Maydell 2601813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 8 2614196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v) 262ac26eb69SRichard Henderson { 2631813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 8) { 2641813e175SRichard Henderson *s->code_ptr++ = v; 2651813e175SRichard Henderson } else { 2661813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 2674387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 2681813e175SRichard Henderson s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE); 2691813e175SRichard Henderson } 270ac26eb69SRichard Henderson } 271ac26eb69SRichard Henderson 2724196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p, 2734196dca6SPeter Maydell uint64_t v) 2745c53bb81SPeter Maydell { 2751813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 8) { 2761813e175SRichard Henderson *p = v; 2771813e175SRichard Henderson } else { 2785c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 2795c53bb81SPeter Maydell } 2801813e175SRichard Henderson } 2811813e175SRichard Henderson #endif 2825c53bb81SPeter Maydell 283c896fe29Sbellard /* label relocation processing */ 284c896fe29Sbellard 2851813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type, 286bec16311SRichard Henderson TCGLabel *l, intptr_t addend) 287c896fe29Sbellard { 2887ecd02a0SRichard Henderson TCGRelocation *r = tcg_malloc(sizeof(TCGRelocation)); 289c896fe29Sbellard 290c896fe29Sbellard r->type = type; 291c896fe29Sbellard r->ptr = code_ptr; 292c896fe29Sbellard r->addend = addend; 2937ecd02a0SRichard Henderson QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next); 294c896fe29Sbellard } 295c896fe29Sbellard 29692ab8e7dSRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l) 297c896fe29Sbellard { 298eabb7b91SAurelien Jarno tcg_debug_assert(!l->has_value); 299c896fe29Sbellard l->has_value = 1; 30092ab8e7dSRichard Henderson l->u.value_ptr = tcg_splitwx_to_rx(s->code_ptr); 301c896fe29Sbellard } 302c896fe29Sbellard 30342a268c2SRichard Henderson TCGLabel *gen_new_label(void) 304c896fe29Sbellard { 305b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 30651e3972cSRichard Henderson TCGLabel *l = tcg_malloc(sizeof(TCGLabel)); 307c896fe29Sbellard 3087ecd02a0SRichard Henderson memset(l, 0, sizeof(TCGLabel)); 3097ecd02a0SRichard Henderson l->id = s->nb_labels++; 310f85b1fc4SRichard Henderson QSIMPLEQ_INIT(&l->branches); 3117ecd02a0SRichard Henderson QSIMPLEQ_INIT(&l->relocs); 3127ecd02a0SRichard Henderson 313bef16ab4SRichard Henderson QSIMPLEQ_INSERT_TAIL(&s->labels, l, next); 31442a268c2SRichard Henderson 31542a268c2SRichard Henderson return l; 316c896fe29Sbellard } 317c896fe29Sbellard 3187ecd02a0SRichard Henderson static bool tcg_resolve_relocs(TCGContext *s) 3197ecd02a0SRichard Henderson { 3207ecd02a0SRichard Henderson TCGLabel *l; 3217ecd02a0SRichard Henderson 3227ecd02a0SRichard Henderson QSIMPLEQ_FOREACH(l, &s->labels, next) { 3237ecd02a0SRichard Henderson TCGRelocation *r; 3247ecd02a0SRichard Henderson uintptr_t value = l->u.value; 3257ecd02a0SRichard Henderson 3267ecd02a0SRichard Henderson QSIMPLEQ_FOREACH(r, &l->relocs, next) { 3277ecd02a0SRichard Henderson if (!patch_reloc(r->ptr, r->type, value, r->addend)) { 3287ecd02a0SRichard Henderson return false; 3297ecd02a0SRichard Henderson } 3307ecd02a0SRichard Henderson } 3317ecd02a0SRichard Henderson } 3327ecd02a0SRichard Henderson return true; 3337ecd02a0SRichard Henderson } 3347ecd02a0SRichard Henderson 3359f754620SRichard Henderson static void set_jmp_reset_offset(TCGContext *s, int which) 3369f754620SRichard Henderson { 337f14bed3fSRichard Henderson /* 338f14bed3fSRichard Henderson * We will check for overflow at the end of the opcode loop in 339f14bed3fSRichard Henderson * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX. 340f14bed3fSRichard Henderson */ 341b7e4afbdSRichard Henderson s->gen_tb->jmp_reset_offset[which] = tcg_current_code_size(s); 3429f754620SRichard Henderson } 3439f754620SRichard Henderson 344b52a2c03SRichard Henderson static void G_GNUC_UNUSED set_jmp_insn_offset(TCGContext *s, int which) 345b52a2c03SRichard Henderson { 346b52a2c03SRichard Henderson /* 347b52a2c03SRichard Henderson * We will check for overflow at the end of the opcode loop in 348b52a2c03SRichard Henderson * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX. 349b52a2c03SRichard Henderson */ 3509da6079bSRichard Henderson s->gen_tb->jmp_insn_offset[which] = tcg_current_code_size(s); 351b52a2c03SRichard Henderson } 352b52a2c03SRichard Henderson 353becc452aSRichard Henderson static uintptr_t G_GNUC_UNUSED get_jmp_target_addr(TCGContext *s, int which) 354becc452aSRichard Henderson { 355becc452aSRichard Henderson /* 356becc452aSRichard Henderson * Return the read-execute version of the pointer, for the benefit 357becc452aSRichard Henderson * of any pc-relative addressing mode. 358becc452aSRichard Henderson */ 3599da6079bSRichard Henderson return (uintptr_t)tcg_splitwx_to_rx(&s->gen_tb->jmp_target_addr[which]); 360becc452aSRichard Henderson } 361becc452aSRichard Henderson 362db6b7d0cSRichard Henderson /* Signal overflow, starting over with fewer guest insns. */ 3638905770bSMarc-André Lureau static G_NORETURN 3648905770bSMarc-André Lureau void tcg_raise_tb_overflow(TCGContext *s) 365db6b7d0cSRichard Henderson { 366db6b7d0cSRichard Henderson siglongjmp(s->jmp_trans, -2); 367db6b7d0cSRichard Henderson } 368db6b7d0cSRichard Henderson 369129f1f9eSRichard Henderson typedef struct TCGMovExtend { 370129f1f9eSRichard Henderson TCGReg dst; 371129f1f9eSRichard Henderson TCGReg src; 372129f1f9eSRichard Henderson TCGType dst_type; 373129f1f9eSRichard Henderson TCGType src_type; 374129f1f9eSRichard Henderson MemOp src_ext; 375129f1f9eSRichard Henderson } TCGMovExtend; 376129f1f9eSRichard Henderson 377b3dfd5fcSRichard Henderson /** 378b3dfd5fcSRichard Henderson * tcg_out_movext -- move and extend 379b3dfd5fcSRichard Henderson * @s: tcg context 380b3dfd5fcSRichard Henderson * @dst_type: integral type for destination 381b3dfd5fcSRichard Henderson * @dst: destination register 382b3dfd5fcSRichard Henderson * @src_type: integral type for source 383b3dfd5fcSRichard Henderson * @src_ext: extension to apply to source 384b3dfd5fcSRichard Henderson * @src: source register 385b3dfd5fcSRichard Henderson * 386b3dfd5fcSRichard Henderson * Move or extend @src into @dst, depending on @src_ext and the types. 387b3dfd5fcSRichard Henderson */ 388129f1f9eSRichard Henderson static void tcg_out_movext(TCGContext *s, TCGType dst_type, TCGReg dst, 389b3dfd5fcSRichard Henderson TCGType src_type, MemOp src_ext, TCGReg src) 390b3dfd5fcSRichard Henderson { 391b3dfd5fcSRichard Henderson switch (src_ext) { 392b3dfd5fcSRichard Henderson case MO_UB: 393b3dfd5fcSRichard Henderson tcg_out_ext8u(s, dst, src); 394b3dfd5fcSRichard Henderson break; 395b3dfd5fcSRichard Henderson case MO_SB: 396b3dfd5fcSRichard Henderson tcg_out_ext8s(s, dst_type, dst, src); 397b3dfd5fcSRichard Henderson break; 398b3dfd5fcSRichard Henderson case MO_UW: 399b3dfd5fcSRichard Henderson tcg_out_ext16u(s, dst, src); 400b3dfd5fcSRichard Henderson break; 401b3dfd5fcSRichard Henderson case MO_SW: 402b3dfd5fcSRichard Henderson tcg_out_ext16s(s, dst_type, dst, src); 403b3dfd5fcSRichard Henderson break; 404b3dfd5fcSRichard Henderson case MO_UL: 405b3dfd5fcSRichard Henderson case MO_SL: 406b3dfd5fcSRichard Henderson if (dst_type == TCG_TYPE_I32) { 407b3dfd5fcSRichard Henderson if (src_type == TCG_TYPE_I32) { 408b3dfd5fcSRichard Henderson tcg_out_mov(s, TCG_TYPE_I32, dst, src); 409b3dfd5fcSRichard Henderson } else { 410b3dfd5fcSRichard Henderson tcg_out_extrl_i64_i32(s, dst, src); 411b3dfd5fcSRichard Henderson } 412b3dfd5fcSRichard Henderson } else if (src_type == TCG_TYPE_I32) { 413b3dfd5fcSRichard Henderson if (src_ext & MO_SIGN) { 414b3dfd5fcSRichard Henderson tcg_out_exts_i32_i64(s, dst, src); 415b3dfd5fcSRichard Henderson } else { 416b3dfd5fcSRichard Henderson tcg_out_extu_i32_i64(s, dst, src); 417b3dfd5fcSRichard Henderson } 418b3dfd5fcSRichard Henderson } else { 419b3dfd5fcSRichard Henderson if (src_ext & MO_SIGN) { 420b3dfd5fcSRichard Henderson tcg_out_ext32s(s, dst, src); 421b3dfd5fcSRichard Henderson } else { 422b3dfd5fcSRichard Henderson tcg_out_ext32u(s, dst, src); 423b3dfd5fcSRichard Henderson } 424b3dfd5fcSRichard Henderson } 425b3dfd5fcSRichard Henderson break; 426b3dfd5fcSRichard Henderson case MO_UQ: 427b3dfd5fcSRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 64); 428b3dfd5fcSRichard Henderson if (dst_type == TCG_TYPE_I32) { 429b3dfd5fcSRichard Henderson tcg_out_extrl_i64_i32(s, dst, src); 430b3dfd5fcSRichard Henderson } else { 431b3dfd5fcSRichard Henderson tcg_out_mov(s, TCG_TYPE_I64, dst, src); 432b3dfd5fcSRichard Henderson } 433b3dfd5fcSRichard Henderson break; 434b3dfd5fcSRichard Henderson default: 435b3dfd5fcSRichard Henderson g_assert_not_reached(); 436b3dfd5fcSRichard Henderson } 437b3dfd5fcSRichard Henderson } 438b3dfd5fcSRichard Henderson 439129f1f9eSRichard Henderson /* Minor variations on a theme, using a structure. */ 440129f1f9eSRichard Henderson static void tcg_out_movext1_new_src(TCGContext *s, const TCGMovExtend *i, 441129f1f9eSRichard Henderson TCGReg src) 442129f1f9eSRichard Henderson { 443129f1f9eSRichard Henderson tcg_out_movext(s, i->dst_type, i->dst, i->src_type, i->src_ext, src); 444129f1f9eSRichard Henderson } 445129f1f9eSRichard Henderson 446129f1f9eSRichard Henderson static void tcg_out_movext1(TCGContext *s, const TCGMovExtend *i) 447129f1f9eSRichard Henderson { 448129f1f9eSRichard Henderson tcg_out_movext1_new_src(s, i, i->src); 449129f1f9eSRichard Henderson } 450129f1f9eSRichard Henderson 451129f1f9eSRichard Henderson /** 452129f1f9eSRichard Henderson * tcg_out_movext2 -- move and extend two pair 453129f1f9eSRichard Henderson * @s: tcg context 454129f1f9eSRichard Henderson * @i1: first move description 455129f1f9eSRichard Henderson * @i2: second move description 456129f1f9eSRichard Henderson * @scratch: temporary register, or -1 for none 457129f1f9eSRichard Henderson * 458129f1f9eSRichard Henderson * As tcg_out_movext, for both @i1 and @i2, caring for overlap 459129f1f9eSRichard Henderson * between the sources and destinations. 460129f1f9eSRichard Henderson */ 461129f1f9eSRichard Henderson 462129f1f9eSRichard Henderson static void __attribute__((unused)) 463129f1f9eSRichard Henderson tcg_out_movext2(TCGContext *s, const TCGMovExtend *i1, 464129f1f9eSRichard Henderson const TCGMovExtend *i2, int scratch) 465129f1f9eSRichard Henderson { 466129f1f9eSRichard Henderson TCGReg src1 = i1->src; 467129f1f9eSRichard Henderson TCGReg src2 = i2->src; 468129f1f9eSRichard Henderson 469129f1f9eSRichard Henderson if (i1->dst != src2) { 470129f1f9eSRichard Henderson tcg_out_movext1(s, i1); 471129f1f9eSRichard Henderson tcg_out_movext1(s, i2); 472129f1f9eSRichard Henderson return; 473129f1f9eSRichard Henderson } 474129f1f9eSRichard Henderson if (i2->dst == src1) { 475129f1f9eSRichard Henderson TCGType src1_type = i1->src_type; 476129f1f9eSRichard Henderson TCGType src2_type = i2->src_type; 477129f1f9eSRichard Henderson 478129f1f9eSRichard Henderson if (tcg_out_xchg(s, MAX(src1_type, src2_type), src1, src2)) { 479129f1f9eSRichard Henderson /* The data is now in the correct registers, now extend. */ 480129f1f9eSRichard Henderson src1 = i2->src; 481129f1f9eSRichard Henderson src2 = i1->src; 482129f1f9eSRichard Henderson } else { 483129f1f9eSRichard Henderson tcg_debug_assert(scratch >= 0); 484129f1f9eSRichard Henderson tcg_out_mov(s, src1_type, scratch, src1); 485129f1f9eSRichard Henderson src1 = scratch; 486129f1f9eSRichard Henderson } 487129f1f9eSRichard Henderson } 488129f1f9eSRichard Henderson tcg_out_movext1_new_src(s, i2, src2); 489129f1f9eSRichard Henderson tcg_out_movext1_new_src(s, i1, src1); 490129f1f9eSRichard Henderson } 491129f1f9eSRichard Henderson 4924c22e840SRichard Henderson #define C_PFX1(P, A) P##A 4934c22e840SRichard Henderson #define C_PFX2(P, A, B) P##A##_##B 4944c22e840SRichard Henderson #define C_PFX3(P, A, B, C) P##A##_##B##_##C 4954c22e840SRichard Henderson #define C_PFX4(P, A, B, C, D) P##A##_##B##_##C##_##D 4964c22e840SRichard Henderson #define C_PFX5(P, A, B, C, D, E) P##A##_##B##_##C##_##D##_##E 4974c22e840SRichard Henderson #define C_PFX6(P, A, B, C, D, E, F) P##A##_##B##_##C##_##D##_##E##_##F 4984c22e840SRichard Henderson 4994c22e840SRichard Henderson /* Define an enumeration for the various combinations. */ 5004c22e840SRichard Henderson 5014c22e840SRichard Henderson #define C_O0_I1(I1) C_PFX1(c_o0_i1_, I1), 5024c22e840SRichard Henderson #define C_O0_I2(I1, I2) C_PFX2(c_o0_i2_, I1, I2), 5034c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3) C_PFX3(c_o0_i3_, I1, I2, I3), 5044c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4) C_PFX4(c_o0_i4_, I1, I2, I3, I4), 5054c22e840SRichard Henderson 5064c22e840SRichard Henderson #define C_O1_I1(O1, I1) C_PFX2(c_o1_i1_, O1, I1), 5074c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2) C_PFX3(c_o1_i2_, O1, I1, I2), 5084c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3) C_PFX4(c_o1_i3_, O1, I1, I2, I3), 5094c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4) C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4), 5104c22e840SRichard Henderson 5114c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2) C_PFX3(c_n1_i2_, O1, I1, I2), 5124c22e840SRichard Henderson 5134c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1) C_PFX3(c_o2_i1_, O1, O2, I1), 5144c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2) C_PFX4(c_o2_i2_, O1, O2, I1, I2), 5154c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3) C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3), 5164c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4), 5174c22e840SRichard Henderson 5184c22e840SRichard Henderson typedef enum { 5194c22e840SRichard Henderson #include "tcg-target-con-set.h" 5204c22e840SRichard Henderson } TCGConstraintSetIndex; 5214c22e840SRichard Henderson 5224c22e840SRichard Henderson static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode); 5234c22e840SRichard Henderson 5244c22e840SRichard Henderson #undef C_O0_I1 5254c22e840SRichard Henderson #undef C_O0_I2 5264c22e840SRichard Henderson #undef C_O0_I3 5274c22e840SRichard Henderson #undef C_O0_I4 5284c22e840SRichard Henderson #undef C_O1_I1 5294c22e840SRichard Henderson #undef C_O1_I2 5304c22e840SRichard Henderson #undef C_O1_I3 5314c22e840SRichard Henderson #undef C_O1_I4 5324c22e840SRichard Henderson #undef C_N1_I2 5334c22e840SRichard Henderson #undef C_O2_I1 5344c22e840SRichard Henderson #undef C_O2_I2 5354c22e840SRichard Henderson #undef C_O2_I3 5364c22e840SRichard Henderson #undef C_O2_I4 5374c22e840SRichard Henderson 5384c22e840SRichard Henderson /* Put all of the constraint sets into an array, indexed by the enum. */ 5394c22e840SRichard Henderson 5404c22e840SRichard Henderson #define C_O0_I1(I1) { .args_ct_str = { #I1 } }, 5414c22e840SRichard Henderson #define C_O0_I2(I1, I2) { .args_ct_str = { #I1, #I2 } }, 5424c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3) { .args_ct_str = { #I1, #I2, #I3 } }, 5434c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4) { .args_ct_str = { #I1, #I2, #I3, #I4 } }, 5444c22e840SRichard Henderson 5454c22e840SRichard Henderson #define C_O1_I1(O1, I1) { .args_ct_str = { #O1, #I1 } }, 5464c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2) { .args_ct_str = { #O1, #I1, #I2 } }, 5474c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3) { .args_ct_str = { #O1, #I1, #I2, #I3 } }, 5484c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4) { .args_ct_str = { #O1, #I1, #I2, #I3, #I4 } }, 5494c22e840SRichard Henderson 5504c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2) { .args_ct_str = { "&" #O1, #I1, #I2 } }, 5514c22e840SRichard Henderson 5524c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1) { .args_ct_str = { #O1, #O2, #I1 } }, 5534c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2) { .args_ct_str = { #O1, #O2, #I1, #I2 } }, 5544c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3) { .args_ct_str = { #O1, #O2, #I1, #I2, #I3 } }, 5554c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) { .args_ct_str = { #O1, #O2, #I1, #I2, #I3, #I4 } }, 5564c22e840SRichard Henderson 5574c22e840SRichard Henderson static const TCGTargetOpDef constraint_sets[] = { 5584c22e840SRichard Henderson #include "tcg-target-con-set.h" 5594c22e840SRichard Henderson }; 5604c22e840SRichard Henderson 5614c22e840SRichard Henderson 5624c22e840SRichard Henderson #undef C_O0_I1 5634c22e840SRichard Henderson #undef C_O0_I2 5644c22e840SRichard Henderson #undef C_O0_I3 5654c22e840SRichard Henderson #undef C_O0_I4 5664c22e840SRichard Henderson #undef C_O1_I1 5674c22e840SRichard Henderson #undef C_O1_I2 5684c22e840SRichard Henderson #undef C_O1_I3 5694c22e840SRichard Henderson #undef C_O1_I4 5704c22e840SRichard Henderson #undef C_N1_I2 5714c22e840SRichard Henderson #undef C_O2_I1 5724c22e840SRichard Henderson #undef C_O2_I2 5734c22e840SRichard Henderson #undef C_O2_I3 5744c22e840SRichard Henderson #undef C_O2_I4 5754c22e840SRichard Henderson 5764c22e840SRichard Henderson /* Expand the enumerator to be returned from tcg_target_op_def(). */ 5774c22e840SRichard Henderson 5784c22e840SRichard Henderson #define C_O0_I1(I1) C_PFX1(c_o0_i1_, I1) 5794c22e840SRichard Henderson #define C_O0_I2(I1, I2) C_PFX2(c_o0_i2_, I1, I2) 5804c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3) C_PFX3(c_o0_i3_, I1, I2, I3) 5814c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4) C_PFX4(c_o0_i4_, I1, I2, I3, I4) 5824c22e840SRichard Henderson 5834c22e840SRichard Henderson #define C_O1_I1(O1, I1) C_PFX2(c_o1_i1_, O1, I1) 5844c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2) C_PFX3(c_o1_i2_, O1, I1, I2) 5854c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3) C_PFX4(c_o1_i3_, O1, I1, I2, I3) 5864c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4) C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4) 5874c22e840SRichard Henderson 5884c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2) C_PFX3(c_n1_i2_, O1, I1, I2) 5894c22e840SRichard Henderson 5904c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1) C_PFX3(c_o2_i1_, O1, O2, I1) 5914c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2) C_PFX4(c_o2_i2_, O1, O2, I1, I2) 5924c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3) C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3) 5934c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4) 5944c22e840SRichard Henderson 595139c1837SPaolo Bonzini #include "tcg-target.c.inc" 596c896fe29Sbellard 59738b47b19SEmilio G. Cota static void alloc_tcg_plugin_context(TCGContext *s) 59838b47b19SEmilio G. Cota { 59938b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN 60038b47b19SEmilio G. Cota s->plugin_tb = g_new0(struct qemu_plugin_tb, 1); 60138b47b19SEmilio G. Cota s->plugin_tb->insns = 60238b47b19SEmilio G. Cota g_ptr_array_new_with_free_func(qemu_plugin_insn_cleanup_fn); 60338b47b19SEmilio G. Cota #endif 60438b47b19SEmilio G. Cota } 60538b47b19SEmilio G. Cota 606e8feb96fSEmilio G. Cota /* 6073468b59eSEmilio G. Cota * All TCG threads except the parent (i.e. the one that called tcg_context_init 6083468b59eSEmilio G. Cota * and registered the target's TCG globals) must register with this function 6093468b59eSEmilio G. Cota * before initiating translation. 6103468b59eSEmilio G. Cota * 6113468b59eSEmilio G. Cota * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation 6123468b59eSEmilio G. Cota * of tcg_region_init() for the reasoning behind this. 6133468b59eSEmilio G. Cota * 6143468b59eSEmilio G. Cota * In softmmu each caller registers its context in tcg_ctxs[]. Note that in 6153468b59eSEmilio G. Cota * softmmu tcg_ctxs[] does not track tcg_ctx_init, since the initial context 6163468b59eSEmilio G. Cota * is not used anymore for translation once this function is called. 6173468b59eSEmilio G. Cota * 6183468b59eSEmilio G. Cota * Not tracking tcg_init_ctx in tcg_ctxs[] in softmmu keeps code that iterates 6193468b59eSEmilio G. Cota * over the array (e.g. tcg_code_size() the same for both softmmu and user-mode. 6203468b59eSEmilio G. Cota */ 6213468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY 6223468b59eSEmilio G. Cota void tcg_register_thread(void) 6233468b59eSEmilio G. Cota { 6243468b59eSEmilio G. Cota tcg_ctx = &tcg_init_ctx; 6253468b59eSEmilio G. Cota } 6263468b59eSEmilio G. Cota #else 6273468b59eSEmilio G. Cota void tcg_register_thread(void) 6283468b59eSEmilio G. Cota { 6293468b59eSEmilio G. Cota TCGContext *s = g_malloc(sizeof(*s)); 6303468b59eSEmilio G. Cota unsigned int i, n; 6313468b59eSEmilio G. Cota 6323468b59eSEmilio G. Cota *s = tcg_init_ctx; 6333468b59eSEmilio G. Cota 6343468b59eSEmilio G. Cota /* Relink mem_base. */ 6353468b59eSEmilio G. Cota for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) { 6363468b59eSEmilio G. Cota if (tcg_init_ctx.temps[i].mem_base) { 6373468b59eSEmilio G. Cota ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps; 6383468b59eSEmilio G. Cota tcg_debug_assert(b >= 0 && b < n); 6393468b59eSEmilio G. Cota s->temps[i].mem_base = &s->temps[b]; 6403468b59eSEmilio G. Cota } 6413468b59eSEmilio G. Cota } 6423468b59eSEmilio G. Cota 6433468b59eSEmilio G. Cota /* Claim an entry in tcg_ctxs */ 6440e2d61cfSRichard Henderson n = qatomic_fetch_inc(&tcg_cur_ctxs); 6450e2d61cfSRichard Henderson g_assert(n < tcg_max_ctxs); 646d73415a3SStefan Hajnoczi qatomic_set(&tcg_ctxs[n], s); 6473468b59eSEmilio G. Cota 64838b47b19SEmilio G. Cota if (n > 0) { 64938b47b19SEmilio G. Cota alloc_tcg_plugin_context(s); 650bf042e8eSRichard Henderson tcg_region_initial_alloc(s); 65138b47b19SEmilio G. Cota } 65238b47b19SEmilio G. Cota 6533468b59eSEmilio G. Cota tcg_ctx = s; 6543468b59eSEmilio G. Cota } 6553468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */ 6563468b59eSEmilio G. Cota 657c896fe29Sbellard /* pool based memory allocation */ 658c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size) 659c896fe29Sbellard { 660c896fe29Sbellard TCGPool *p; 661c896fe29Sbellard int pool_size; 662c896fe29Sbellard 663c896fe29Sbellard if (size > TCG_POOL_CHUNK_SIZE) { 664c896fe29Sbellard /* big malloc: insert a new pool (XXX: could optimize) */ 6657267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + size); 666c896fe29Sbellard p->size = size; 6674055299eSKirill Batuzov p->next = s->pool_first_large; 6684055299eSKirill Batuzov s->pool_first_large = p; 6694055299eSKirill Batuzov return p->data; 670c896fe29Sbellard } else { 671c896fe29Sbellard p = s->pool_current; 672c896fe29Sbellard if (!p) { 673c896fe29Sbellard p = s->pool_first; 674c896fe29Sbellard if (!p) 675c896fe29Sbellard goto new_pool; 676c896fe29Sbellard } else { 677c896fe29Sbellard if (!p->next) { 678c896fe29Sbellard new_pool: 679c896fe29Sbellard pool_size = TCG_POOL_CHUNK_SIZE; 6807267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + pool_size); 681c896fe29Sbellard p->size = pool_size; 682c896fe29Sbellard p->next = NULL; 683a813e36fSRichard Henderson if (s->pool_current) { 684c896fe29Sbellard s->pool_current->next = p; 685a813e36fSRichard Henderson } else { 686c896fe29Sbellard s->pool_first = p; 687a813e36fSRichard Henderson } 688c896fe29Sbellard } else { 689c896fe29Sbellard p = p->next; 690c896fe29Sbellard } 691c896fe29Sbellard } 692c896fe29Sbellard } 693c896fe29Sbellard s->pool_current = p; 694c896fe29Sbellard s->pool_cur = p->data + size; 695c896fe29Sbellard s->pool_end = p->data + p->size; 696c896fe29Sbellard return p->data; 697c896fe29Sbellard } 698c896fe29Sbellard 699c896fe29Sbellard void tcg_pool_reset(TCGContext *s) 700c896fe29Sbellard { 7014055299eSKirill Batuzov TCGPool *p, *t; 7024055299eSKirill Batuzov for (p = s->pool_first_large; p; p = t) { 7034055299eSKirill Batuzov t = p->next; 7044055299eSKirill Batuzov g_free(p); 7054055299eSKirill Batuzov } 7064055299eSKirill Batuzov s->pool_first_large = NULL; 707c896fe29Sbellard s->pool_cur = s->pool_end = NULL; 708c896fe29Sbellard s->pool_current = NULL; 709c896fe29Sbellard } 710c896fe29Sbellard 7112ef6175aSRichard Henderson #include "exec/helper-proto.h" 7122ef6175aSRichard Henderson 71339004a71SRichard Henderson static TCGHelperInfo all_helpers[] = { 7142ef6175aSRichard Henderson #include "exec/helper-tcg.h" 715100b5e01SRichard Henderson }; 716619205fdSEmilio G. Cota static GHashTable *helper_table; 717100b5e01SRichard Henderson 71822f15579SRichard Henderson #ifdef CONFIG_TCG_INTERPRETER 719c6ef8c7bSPhilippe Mathieu-Daudé static ffi_type *typecode_to_ffi(int argmask) 720c6ef8c7bSPhilippe Mathieu-Daudé { 721e9709e17SRichard Henderson /* 722e9709e17SRichard Henderson * libffi does not support __int128_t, so we have forced Int128 723e9709e17SRichard Henderson * to use the structure definition instead of the builtin type. 724e9709e17SRichard Henderson */ 725e9709e17SRichard Henderson static ffi_type *ffi_type_i128_elements[3] = { 726e9709e17SRichard Henderson &ffi_type_uint64, 727e9709e17SRichard Henderson &ffi_type_uint64, 728e9709e17SRichard Henderson NULL 729e9709e17SRichard Henderson }; 730e9709e17SRichard Henderson static ffi_type ffi_type_i128 = { 731e9709e17SRichard Henderson .size = 16, 732e9709e17SRichard Henderson .alignment = __alignof__(Int128), 733e9709e17SRichard Henderson .type = FFI_TYPE_STRUCT, 734e9709e17SRichard Henderson .elements = ffi_type_i128_elements, 735e9709e17SRichard Henderson }; 736e9709e17SRichard Henderson 737c6ef8c7bSPhilippe Mathieu-Daudé switch (argmask) { 738c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_void: 739c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_void; 740c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_i32: 741c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_uint32; 742c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_s32: 743c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_sint32; 744c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_i64: 745c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_uint64; 746c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_s64: 747c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_sint64; 748c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_ptr: 749c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_pointer; 750e9709e17SRichard Henderson case dh_typecode_i128: 751e9709e17SRichard Henderson return &ffi_type_i128; 752c6ef8c7bSPhilippe Mathieu-Daudé } 753c6ef8c7bSPhilippe Mathieu-Daudé g_assert_not_reached(); 754c6ef8c7bSPhilippe Mathieu-Daudé } 7550c22e176SPhilippe Mathieu-Daudé 7560c22e176SPhilippe Mathieu-Daudé static void init_ffi_layouts(void) 7570c22e176SPhilippe Mathieu-Daudé { 7580c22e176SPhilippe Mathieu-Daudé /* g_direct_hash/equal for direct comparisons on uint32_t. */ 759f9c4bb80SRichard Henderson GHashTable *ffi_table = g_hash_table_new(NULL, NULL); 760f9c4bb80SRichard Henderson 7610c22e176SPhilippe Mathieu-Daudé for (int i = 0; i < ARRAY_SIZE(all_helpers); ++i) { 762f9c4bb80SRichard Henderson TCGHelperInfo *info = &all_helpers[i]; 763f9c4bb80SRichard Henderson unsigned typemask = info->typemask; 7640c22e176SPhilippe Mathieu-Daudé gpointer hash = (gpointer)(uintptr_t)typemask; 7650c22e176SPhilippe Mathieu-Daudé struct { 7660c22e176SPhilippe Mathieu-Daudé ffi_cif cif; 7670c22e176SPhilippe Mathieu-Daudé ffi_type *args[]; 7680c22e176SPhilippe Mathieu-Daudé } *ca; 7690c22e176SPhilippe Mathieu-Daudé ffi_status status; 7700c22e176SPhilippe Mathieu-Daudé int nargs; 771f9c4bb80SRichard Henderson ffi_cif *cif; 7720c22e176SPhilippe Mathieu-Daudé 773f9c4bb80SRichard Henderson cif = g_hash_table_lookup(ffi_table, hash); 774f9c4bb80SRichard Henderson if (cif) { 775f9c4bb80SRichard Henderson info->cif = cif; 7760c22e176SPhilippe Mathieu-Daudé continue; 7770c22e176SPhilippe Mathieu-Daudé } 7780c22e176SPhilippe Mathieu-Daudé 7790c22e176SPhilippe Mathieu-Daudé /* Ignoring the return type, find the last non-zero field. */ 7800c22e176SPhilippe Mathieu-Daudé nargs = 32 - clz32(typemask >> 3); 7810c22e176SPhilippe Mathieu-Daudé nargs = DIV_ROUND_UP(nargs, 3); 782e9709e17SRichard Henderson assert(nargs <= MAX_CALL_IARGS); 7830c22e176SPhilippe Mathieu-Daudé 7840c22e176SPhilippe Mathieu-Daudé ca = g_malloc0(sizeof(*ca) + nargs * sizeof(ffi_type *)); 7850c22e176SPhilippe Mathieu-Daudé ca->cif.rtype = typecode_to_ffi(typemask & 7); 7860c22e176SPhilippe Mathieu-Daudé ca->cif.nargs = nargs; 7870c22e176SPhilippe Mathieu-Daudé 7880c22e176SPhilippe Mathieu-Daudé if (nargs != 0) { 7890c22e176SPhilippe Mathieu-Daudé ca->cif.arg_types = ca->args; 7900c22e176SPhilippe Mathieu-Daudé for (int j = 0; j < nargs; ++j) { 7910c22e176SPhilippe Mathieu-Daudé int typecode = extract32(typemask, (j + 1) * 3, 3); 7920c22e176SPhilippe Mathieu-Daudé ca->args[j] = typecode_to_ffi(typecode); 7930c22e176SPhilippe Mathieu-Daudé } 7940c22e176SPhilippe Mathieu-Daudé } 7950c22e176SPhilippe Mathieu-Daudé 7960c22e176SPhilippe Mathieu-Daudé status = ffi_prep_cif(&ca->cif, FFI_DEFAULT_ABI, nargs, 7970c22e176SPhilippe Mathieu-Daudé ca->cif.rtype, ca->cif.arg_types); 7980c22e176SPhilippe Mathieu-Daudé assert(status == FFI_OK); 7990c22e176SPhilippe Mathieu-Daudé 800f9c4bb80SRichard Henderson cif = &ca->cif; 801f9c4bb80SRichard Henderson info->cif = cif; 802f9c4bb80SRichard Henderson g_hash_table_insert(ffi_table, hash, (gpointer)cif); 8030c22e176SPhilippe Mathieu-Daudé } 804f9c4bb80SRichard Henderson 805f9c4bb80SRichard Henderson g_hash_table_destroy(ffi_table); 8060c22e176SPhilippe Mathieu-Daudé } 8070c22e176SPhilippe Mathieu-Daudé #endif /* CONFIG_TCG_INTERPRETER */ 80822f15579SRichard Henderson 809338b61e9SRichard Henderson static inline bool arg_slot_reg_p(unsigned arg_slot) 810338b61e9SRichard Henderson { 811338b61e9SRichard Henderson /* 812338b61e9SRichard Henderson * Split the sizeof away from the comparison to avoid Werror from 813338b61e9SRichard Henderson * "unsigned < 0 is always false", when iarg_regs is empty. 814338b61e9SRichard Henderson */ 815338b61e9SRichard Henderson unsigned nreg = ARRAY_SIZE(tcg_target_call_iarg_regs); 816338b61e9SRichard Henderson return arg_slot < nreg; 817338b61e9SRichard Henderson } 818338b61e9SRichard Henderson 819*d78e4a4fSRichard Henderson static inline int arg_slot_stk_ofs(unsigned arg_slot) 820*d78e4a4fSRichard Henderson { 821*d78e4a4fSRichard Henderson unsigned max = TCG_STATIC_CALL_ARGS_SIZE / sizeof(tcg_target_long); 822*d78e4a4fSRichard Henderson unsigned stk_slot = arg_slot - ARRAY_SIZE(tcg_target_call_iarg_regs); 823*d78e4a4fSRichard Henderson 824*d78e4a4fSRichard Henderson tcg_debug_assert(stk_slot < max); 825*d78e4a4fSRichard Henderson return TCG_TARGET_CALL_STACK_OFFSET + stk_slot * sizeof(tcg_target_long); 826*d78e4a4fSRichard Henderson } 827*d78e4a4fSRichard Henderson 82839004a71SRichard Henderson typedef struct TCGCumulativeArgs { 82939004a71SRichard Henderson int arg_idx; /* tcg_gen_callN args[] */ 83039004a71SRichard Henderson int info_in_idx; /* TCGHelperInfo in[] */ 83139004a71SRichard Henderson int arg_slot; /* regs+stack slot */ 83239004a71SRichard Henderson int ref_slot; /* stack slots for references */ 83339004a71SRichard Henderson } TCGCumulativeArgs; 83439004a71SRichard Henderson 83539004a71SRichard Henderson static void layout_arg_even(TCGCumulativeArgs *cum) 83639004a71SRichard Henderson { 83739004a71SRichard Henderson cum->arg_slot += cum->arg_slot & 1; 83839004a71SRichard Henderson } 83939004a71SRichard Henderson 84039004a71SRichard Henderson static void layout_arg_1(TCGCumulativeArgs *cum, TCGHelperInfo *info, 84139004a71SRichard Henderson TCGCallArgumentKind kind) 84239004a71SRichard Henderson { 84339004a71SRichard Henderson TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx]; 84439004a71SRichard Henderson 84539004a71SRichard Henderson *loc = (TCGCallArgumentLoc){ 84639004a71SRichard Henderson .kind = kind, 84739004a71SRichard Henderson .arg_idx = cum->arg_idx, 84839004a71SRichard Henderson .arg_slot = cum->arg_slot, 84939004a71SRichard Henderson }; 85039004a71SRichard Henderson cum->info_in_idx++; 85139004a71SRichard Henderson cum->arg_slot++; 85239004a71SRichard Henderson } 85339004a71SRichard Henderson 85439004a71SRichard Henderson static void layout_arg_normal_n(TCGCumulativeArgs *cum, 85539004a71SRichard Henderson TCGHelperInfo *info, int n) 85639004a71SRichard Henderson { 85739004a71SRichard Henderson TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx]; 85839004a71SRichard Henderson 85939004a71SRichard Henderson for (int i = 0; i < n; ++i) { 86039004a71SRichard Henderson /* Layout all using the same arg_idx, adjusting the subindex. */ 86139004a71SRichard Henderson loc[i] = (TCGCallArgumentLoc){ 86239004a71SRichard Henderson .kind = TCG_CALL_ARG_NORMAL, 86339004a71SRichard Henderson .arg_idx = cum->arg_idx, 86439004a71SRichard Henderson .tmp_subindex = i, 86539004a71SRichard Henderson .arg_slot = cum->arg_slot + i, 86639004a71SRichard Henderson }; 86739004a71SRichard Henderson } 86839004a71SRichard Henderson cum->info_in_idx += n; 86939004a71SRichard Henderson cum->arg_slot += n; 87039004a71SRichard Henderson } 87139004a71SRichard Henderson 872313bdea8SRichard Henderson static void layout_arg_by_ref(TCGCumulativeArgs *cum, TCGHelperInfo *info) 873313bdea8SRichard Henderson { 874313bdea8SRichard Henderson TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx]; 875313bdea8SRichard Henderson int n = 128 / TCG_TARGET_REG_BITS; 876313bdea8SRichard Henderson 877313bdea8SRichard Henderson /* The first subindex carries the pointer. */ 878313bdea8SRichard Henderson layout_arg_1(cum, info, TCG_CALL_ARG_BY_REF); 879313bdea8SRichard Henderson 880313bdea8SRichard Henderson /* 881313bdea8SRichard Henderson * The callee is allowed to clobber memory associated with 882313bdea8SRichard Henderson * structure pass by-reference. Therefore we must make copies. 883313bdea8SRichard Henderson * Allocate space from "ref_slot", which will be adjusted to 884313bdea8SRichard Henderson * follow the parameters on the stack. 885313bdea8SRichard Henderson */ 886313bdea8SRichard Henderson loc[0].ref_slot = cum->ref_slot; 887313bdea8SRichard Henderson 888313bdea8SRichard Henderson /* 889313bdea8SRichard Henderson * Subsequent words also go into the reference slot, but 890313bdea8SRichard Henderson * do not accumulate into the regular arguments. 891313bdea8SRichard Henderson */ 892313bdea8SRichard Henderson for (int i = 1; i < n; ++i) { 893313bdea8SRichard Henderson loc[i] = (TCGCallArgumentLoc){ 894313bdea8SRichard Henderson .kind = TCG_CALL_ARG_BY_REF_N, 895313bdea8SRichard Henderson .arg_idx = cum->arg_idx, 896313bdea8SRichard Henderson .tmp_subindex = i, 897313bdea8SRichard Henderson .ref_slot = cum->ref_slot + i, 898313bdea8SRichard Henderson }; 899313bdea8SRichard Henderson } 900313bdea8SRichard Henderson cum->info_in_idx += n; 901313bdea8SRichard Henderson cum->ref_slot += n; 902313bdea8SRichard Henderson } 903313bdea8SRichard Henderson 90439004a71SRichard Henderson static void init_call_layout(TCGHelperInfo *info) 90539004a71SRichard Henderson { 90639004a71SRichard Henderson int max_reg_slots = ARRAY_SIZE(tcg_target_call_iarg_regs); 90739004a71SRichard Henderson int max_stk_slots = TCG_STATIC_CALL_ARGS_SIZE / sizeof(tcg_target_long); 90839004a71SRichard Henderson unsigned typemask = info->typemask; 90939004a71SRichard Henderson unsigned typecode; 91039004a71SRichard Henderson TCGCumulativeArgs cum = { }; 91139004a71SRichard Henderson 91239004a71SRichard Henderson /* 91339004a71SRichard Henderson * Parse and place any function return value. 91439004a71SRichard Henderson */ 91539004a71SRichard Henderson typecode = typemask & 7; 91639004a71SRichard Henderson switch (typecode) { 91739004a71SRichard Henderson case dh_typecode_void: 91839004a71SRichard Henderson info->nr_out = 0; 91939004a71SRichard Henderson break; 92039004a71SRichard Henderson case dh_typecode_i32: 92139004a71SRichard Henderson case dh_typecode_s32: 92239004a71SRichard Henderson case dh_typecode_ptr: 92339004a71SRichard Henderson info->nr_out = 1; 92439004a71SRichard Henderson info->out_kind = TCG_CALL_RET_NORMAL; 92539004a71SRichard Henderson break; 92639004a71SRichard Henderson case dh_typecode_i64: 92739004a71SRichard Henderson case dh_typecode_s64: 92839004a71SRichard Henderson info->nr_out = 64 / TCG_TARGET_REG_BITS; 92939004a71SRichard Henderson info->out_kind = TCG_CALL_RET_NORMAL; 9305e3d0c19SRichard Henderson /* Query the last register now to trigger any assert early. */ 9315e3d0c19SRichard Henderson tcg_target_call_oarg_reg(info->out_kind, info->nr_out - 1); 932466d3759SRichard Henderson break; 933466d3759SRichard Henderson case dh_typecode_i128: 934466d3759SRichard Henderson info->nr_out = 128 / TCG_TARGET_REG_BITS; 9355427a9a7SRichard Henderson info->out_kind = TCG_TARGET_CALL_RET_I128; 9365427a9a7SRichard Henderson switch (TCG_TARGET_CALL_RET_I128) { 937466d3759SRichard Henderson case TCG_CALL_RET_NORMAL: 9385e3d0c19SRichard Henderson /* Query the last register now to trigger any assert early. */ 9395e3d0c19SRichard Henderson tcg_target_call_oarg_reg(info->out_kind, info->nr_out - 1); 940466d3759SRichard Henderson break; 941c6556aa0SRichard Henderson case TCG_CALL_RET_BY_VEC: 942c6556aa0SRichard Henderson /* Query the single register now to trigger any assert early. */ 943c6556aa0SRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0); 944c6556aa0SRichard Henderson break; 945313bdea8SRichard Henderson case TCG_CALL_RET_BY_REF: 946313bdea8SRichard Henderson /* 947313bdea8SRichard Henderson * Allocate the first argument to the output. 948313bdea8SRichard Henderson * We don't need to store this anywhere, just make it 949313bdea8SRichard Henderson * unavailable for use in the input loop below. 950313bdea8SRichard Henderson */ 951313bdea8SRichard Henderson cum.arg_slot = 1; 952313bdea8SRichard Henderson break; 953466d3759SRichard Henderson default: 954466d3759SRichard Henderson qemu_build_not_reached(); 955466d3759SRichard Henderson } 95639004a71SRichard Henderson break; 95739004a71SRichard Henderson default: 95839004a71SRichard Henderson g_assert_not_reached(); 95939004a71SRichard Henderson } 96039004a71SRichard Henderson 96139004a71SRichard Henderson /* 96239004a71SRichard Henderson * Parse and place function arguments. 96339004a71SRichard Henderson */ 96439004a71SRichard Henderson for (typemask >>= 3; typemask; typemask >>= 3, cum.arg_idx++) { 96539004a71SRichard Henderson TCGCallArgumentKind kind; 96639004a71SRichard Henderson TCGType type; 96739004a71SRichard Henderson 96839004a71SRichard Henderson typecode = typemask & 7; 96939004a71SRichard Henderson switch (typecode) { 97039004a71SRichard Henderson case dh_typecode_i32: 97139004a71SRichard Henderson case dh_typecode_s32: 97239004a71SRichard Henderson type = TCG_TYPE_I32; 97339004a71SRichard Henderson break; 97439004a71SRichard Henderson case dh_typecode_i64: 97539004a71SRichard Henderson case dh_typecode_s64: 97639004a71SRichard Henderson type = TCG_TYPE_I64; 97739004a71SRichard Henderson break; 97839004a71SRichard Henderson case dh_typecode_ptr: 97939004a71SRichard Henderson type = TCG_TYPE_PTR; 98039004a71SRichard Henderson break; 981466d3759SRichard Henderson case dh_typecode_i128: 982466d3759SRichard Henderson type = TCG_TYPE_I128; 983466d3759SRichard Henderson break; 98439004a71SRichard Henderson default: 98539004a71SRichard Henderson g_assert_not_reached(); 98639004a71SRichard Henderson } 98739004a71SRichard Henderson 98839004a71SRichard Henderson switch (type) { 98939004a71SRichard Henderson case TCG_TYPE_I32: 99039004a71SRichard Henderson switch (TCG_TARGET_CALL_ARG_I32) { 99139004a71SRichard Henderson case TCG_CALL_ARG_EVEN: 99239004a71SRichard Henderson layout_arg_even(&cum); 99339004a71SRichard Henderson /* fall through */ 99439004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 99539004a71SRichard Henderson layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL); 99639004a71SRichard Henderson break; 99739004a71SRichard Henderson case TCG_CALL_ARG_EXTEND: 99839004a71SRichard Henderson kind = TCG_CALL_ARG_EXTEND_U + (typecode & 1); 99939004a71SRichard Henderson layout_arg_1(&cum, info, kind); 100039004a71SRichard Henderson break; 100139004a71SRichard Henderson default: 100239004a71SRichard Henderson qemu_build_not_reached(); 100339004a71SRichard Henderson } 100439004a71SRichard Henderson break; 100539004a71SRichard Henderson 100639004a71SRichard Henderson case TCG_TYPE_I64: 100739004a71SRichard Henderson switch (TCG_TARGET_CALL_ARG_I64) { 100839004a71SRichard Henderson case TCG_CALL_ARG_EVEN: 100939004a71SRichard Henderson layout_arg_even(&cum); 101039004a71SRichard Henderson /* fall through */ 101139004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 101239004a71SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 101339004a71SRichard Henderson layout_arg_normal_n(&cum, info, 2); 101439004a71SRichard Henderson } else { 101539004a71SRichard Henderson layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL); 101639004a71SRichard Henderson } 101739004a71SRichard Henderson break; 101839004a71SRichard Henderson default: 101939004a71SRichard Henderson qemu_build_not_reached(); 102039004a71SRichard Henderson } 102139004a71SRichard Henderson break; 102239004a71SRichard Henderson 1023466d3759SRichard Henderson case TCG_TYPE_I128: 10245427a9a7SRichard Henderson switch (TCG_TARGET_CALL_ARG_I128) { 1025466d3759SRichard Henderson case TCG_CALL_ARG_EVEN: 1026466d3759SRichard Henderson layout_arg_even(&cum); 1027466d3759SRichard Henderson /* fall through */ 1028466d3759SRichard Henderson case TCG_CALL_ARG_NORMAL: 1029466d3759SRichard Henderson layout_arg_normal_n(&cum, info, 128 / TCG_TARGET_REG_BITS); 1030466d3759SRichard Henderson break; 1031313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF: 1032313bdea8SRichard Henderson layout_arg_by_ref(&cum, info); 1033313bdea8SRichard Henderson break; 1034466d3759SRichard Henderson default: 1035466d3759SRichard Henderson qemu_build_not_reached(); 1036466d3759SRichard Henderson } 1037466d3759SRichard Henderson break; 1038466d3759SRichard Henderson 103939004a71SRichard Henderson default: 104039004a71SRichard Henderson g_assert_not_reached(); 104139004a71SRichard Henderson } 104239004a71SRichard Henderson } 104339004a71SRichard Henderson info->nr_in = cum.info_in_idx; 104439004a71SRichard Henderson 104539004a71SRichard Henderson /* Validate that we didn't overrun the input array. */ 104639004a71SRichard Henderson assert(cum.info_in_idx <= ARRAY_SIZE(info->in)); 104739004a71SRichard Henderson /* Validate the backend has enough argument space. */ 104839004a71SRichard Henderson assert(cum.arg_slot <= max_reg_slots + max_stk_slots); 1049313bdea8SRichard Henderson 1050313bdea8SRichard Henderson /* 1051313bdea8SRichard Henderson * Relocate the "ref_slot" area to the end of the parameters. 1052313bdea8SRichard Henderson * Minimizing this stack offset helps code size for x86, 1053313bdea8SRichard Henderson * which has a signed 8-bit offset encoding. 1054313bdea8SRichard Henderson */ 1055313bdea8SRichard Henderson if (cum.ref_slot != 0) { 1056313bdea8SRichard Henderson int ref_base = 0; 1057313bdea8SRichard Henderson 1058313bdea8SRichard Henderson if (cum.arg_slot > max_reg_slots) { 1059313bdea8SRichard Henderson int align = __alignof(Int128) / sizeof(tcg_target_long); 1060313bdea8SRichard Henderson 1061313bdea8SRichard Henderson ref_base = cum.arg_slot - max_reg_slots; 1062313bdea8SRichard Henderson if (align > 1) { 1063313bdea8SRichard Henderson ref_base = ROUND_UP(ref_base, align); 1064313bdea8SRichard Henderson } 1065313bdea8SRichard Henderson } 1066313bdea8SRichard Henderson assert(ref_base + cum.ref_slot <= max_stk_slots); 1067*d78e4a4fSRichard Henderson ref_base += max_reg_slots; 1068313bdea8SRichard Henderson 1069313bdea8SRichard Henderson if (ref_base != 0) { 1070313bdea8SRichard Henderson for (int i = cum.info_in_idx - 1; i >= 0; --i) { 1071313bdea8SRichard Henderson TCGCallArgumentLoc *loc = &info->in[i]; 1072313bdea8SRichard Henderson switch (loc->kind) { 1073313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF: 1074313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF_N: 1075313bdea8SRichard Henderson loc->ref_slot += ref_base; 1076313bdea8SRichard Henderson break; 1077313bdea8SRichard Henderson default: 1078313bdea8SRichard Henderson break; 1079313bdea8SRichard Henderson } 1080313bdea8SRichard Henderson } 1081313bdea8SRichard Henderson } 1082313bdea8SRichard Henderson } 108339004a71SRichard Henderson } 108439004a71SRichard Henderson 108591478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)]; 1086f69d277eSRichard Henderson static void process_op_defs(TCGContext *s); 10871c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type, 10881c2adb95SRichard Henderson TCGReg reg, const char *name); 108991478cefSRichard Henderson 109043b972b7SRichard Henderson static void tcg_context_init(unsigned max_cpus) 1091c896fe29Sbellard { 1092a76aabd3SRichard Henderson TCGContext *s = &tcg_init_ctx; 1093100b5e01SRichard Henderson int op, total_args, n, i; 1094c896fe29Sbellard TCGOpDef *def; 1095c896fe29Sbellard TCGArgConstraint *args_ct; 10961c2adb95SRichard Henderson TCGTemp *ts; 1097c896fe29Sbellard 1098c896fe29Sbellard memset(s, 0, sizeof(*s)); 1099c896fe29Sbellard s->nb_globals = 0; 1100c896fe29Sbellard 1101c896fe29Sbellard /* Count total number of arguments and allocate the corresponding 1102c896fe29Sbellard space */ 1103c896fe29Sbellard total_args = 0; 1104c896fe29Sbellard for(op = 0; op < NB_OPS; op++) { 1105c896fe29Sbellard def = &tcg_op_defs[op]; 1106c896fe29Sbellard n = def->nb_iargs + def->nb_oargs; 1107c896fe29Sbellard total_args += n; 1108c896fe29Sbellard } 1109c896fe29Sbellard 1110bc2b17e6SRichard Henderson args_ct = g_new0(TCGArgConstraint, total_args); 1111c896fe29Sbellard 1112c896fe29Sbellard for(op = 0; op < NB_OPS; op++) { 1113c896fe29Sbellard def = &tcg_op_defs[op]; 1114c896fe29Sbellard def->args_ct = args_ct; 1115c896fe29Sbellard n = def->nb_iargs + def->nb_oargs; 1116c896fe29Sbellard args_ct += n; 1117c896fe29Sbellard } 1118c896fe29Sbellard 11195cd8f621SRichard Henderson /* Register helpers. */ 112084fd9dd3SRichard Henderson /* Use g_direct_hash/equal for direct pointer comparisons on func. */ 1121619205fdSEmilio G. Cota helper_table = g_hash_table_new(NULL, NULL); 112284fd9dd3SRichard Henderson 1123100b5e01SRichard Henderson for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) { 112439004a71SRichard Henderson init_call_layout(&all_helpers[i]); 112584fd9dd3SRichard Henderson g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func, 112672866e82SRichard Henderson (gpointer)&all_helpers[i]); 1127100b5e01SRichard Henderson } 11285cd8f621SRichard Henderson 112922f15579SRichard Henderson #ifdef CONFIG_TCG_INTERPRETER 11300c22e176SPhilippe Mathieu-Daudé init_ffi_layouts(); 113122f15579SRichard Henderson #endif 113222f15579SRichard Henderson 1133c896fe29Sbellard tcg_target_init(s); 1134f69d277eSRichard Henderson process_op_defs(s); 113591478cefSRichard Henderson 113691478cefSRichard Henderson /* Reverse the order of the saved registers, assuming they're all at 113791478cefSRichard Henderson the start of tcg_target_reg_alloc_order. */ 113891478cefSRichard Henderson for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) { 113991478cefSRichard Henderson int r = tcg_target_reg_alloc_order[n]; 114091478cefSRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) { 114191478cefSRichard Henderson break; 114291478cefSRichard Henderson } 114391478cefSRichard Henderson } 114491478cefSRichard Henderson for (i = 0; i < n; ++i) { 114591478cefSRichard Henderson indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i]; 114691478cefSRichard Henderson } 114791478cefSRichard Henderson for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) { 114891478cefSRichard Henderson indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i]; 114991478cefSRichard Henderson } 1150b1311c4aSEmilio G. Cota 115138b47b19SEmilio G. Cota alloc_tcg_plugin_context(s); 115238b47b19SEmilio G. Cota 1153b1311c4aSEmilio G. Cota tcg_ctx = s; 11543468b59eSEmilio G. Cota /* 11553468b59eSEmilio G. Cota * In user-mode we simply share the init context among threads, since we 11563468b59eSEmilio G. Cota * use a single region. See the documentation tcg_region_init() for the 11573468b59eSEmilio G. Cota * reasoning behind this. 11583468b59eSEmilio G. Cota * In softmmu we will have at most max_cpus TCG threads. 11593468b59eSEmilio G. Cota */ 11603468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY 1161df2cce29SEmilio G. Cota tcg_ctxs = &tcg_ctx; 11620e2d61cfSRichard Henderson tcg_cur_ctxs = 1; 11630e2d61cfSRichard Henderson tcg_max_ctxs = 1; 11643468b59eSEmilio G. Cota #else 11650e2d61cfSRichard Henderson tcg_max_ctxs = max_cpus; 11660e2d61cfSRichard Henderson tcg_ctxs = g_new0(TCGContext *, max_cpus); 11673468b59eSEmilio G. Cota #endif 11681c2adb95SRichard Henderson 11691c2adb95SRichard Henderson tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0)); 11701c2adb95SRichard Henderson ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env"); 11711c2adb95SRichard Henderson cpu_env = temp_tcgv_ptr(ts); 11729002ec79SRichard Henderson } 1173b03cce8eSbellard 117443b972b7SRichard Henderson void tcg_init(size_t tb_size, int splitwx, unsigned max_cpus) 1175a76aabd3SRichard Henderson { 117643b972b7SRichard Henderson tcg_context_init(max_cpus); 117743b972b7SRichard Henderson tcg_region_init(tb_size, splitwx, max_cpus); 1178a76aabd3SRichard Henderson } 1179a76aabd3SRichard Henderson 11806e3b2bfdSEmilio G. Cota /* 11816e3b2bfdSEmilio G. Cota * Allocate TBs right before their corresponding translated code, making 11826e3b2bfdSEmilio G. Cota * sure that TBs and code are on different cache lines. 11836e3b2bfdSEmilio G. Cota */ 11846e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s) 11856e3b2bfdSEmilio G. Cota { 11866e3b2bfdSEmilio G. Cota uintptr_t align = qemu_icache_linesize; 11876e3b2bfdSEmilio G. Cota TranslationBlock *tb; 11886e3b2bfdSEmilio G. Cota void *next; 11896e3b2bfdSEmilio G. Cota 1190e8feb96fSEmilio G. Cota retry: 11916e3b2bfdSEmilio G. Cota tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align); 11926e3b2bfdSEmilio G. Cota next = (void *)ROUND_UP((uintptr_t)(tb + 1), align); 11936e3b2bfdSEmilio G. Cota 11946e3b2bfdSEmilio G. Cota if (unlikely(next > s->code_gen_highwater)) { 1195e8feb96fSEmilio G. Cota if (tcg_region_alloc(s)) { 11966e3b2bfdSEmilio G. Cota return NULL; 11976e3b2bfdSEmilio G. Cota } 1198e8feb96fSEmilio G. Cota goto retry; 1199e8feb96fSEmilio G. Cota } 1200d73415a3SStefan Hajnoczi qatomic_set(&s->code_gen_ptr, next); 120157a26946SRichard Henderson s->data_gen_ptr = NULL; 12026e3b2bfdSEmilio G. Cota return tb; 12036e3b2bfdSEmilio G. Cota } 12046e3b2bfdSEmilio G. Cota 12059002ec79SRichard Henderson void tcg_prologue_init(TCGContext *s) 12069002ec79SRichard Henderson { 1207b0a0794aSRichard Henderson size_t prologue_size; 12088163b749SRichard Henderson 1209b0a0794aSRichard Henderson s->code_ptr = s->code_gen_ptr; 1210b0a0794aSRichard Henderson s->code_buf = s->code_gen_ptr; 12115b38ee31SRichard Henderson s->data_gen_ptr = NULL; 1212b91ccb31SRichard Henderson 1213b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 1214b0a0794aSRichard Henderson tcg_qemu_tb_exec = (tcg_prologue_fn *)tcg_splitwx_to_rx(s->code_ptr); 1215b91ccb31SRichard Henderson #endif 12168163b749SRichard Henderson 12175b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 12185b38ee31SRichard Henderson s->pool_labels = NULL; 12195b38ee31SRichard Henderson #endif 12205b38ee31SRichard Henderson 1221653b87ebSRoman Bolshakov qemu_thread_jit_write(); 12228163b749SRichard Henderson /* Generate the prologue. */ 1223b03cce8eSbellard tcg_target_qemu_prologue(s); 12245b38ee31SRichard Henderson 12255b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 12265b38ee31SRichard Henderson /* Allow the prologue to put e.g. guest_base into a pool entry. */ 12275b38ee31SRichard Henderson { 12281768987bSRichard Henderson int result = tcg_out_pool_finalize(s); 12291768987bSRichard Henderson tcg_debug_assert(result == 0); 12305b38ee31SRichard Henderson } 12315b38ee31SRichard Henderson #endif 12325b38ee31SRichard Henderson 1233b0a0794aSRichard Henderson prologue_size = tcg_current_code_size(s); 12345584e2dbSIlya Leoshkevich perf_report_prologue(s->code_gen_ptr, prologue_size); 1235b0a0794aSRichard Henderson 1236df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 1237b0a0794aSRichard Henderson flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf), 1238b0a0794aSRichard Henderson (uintptr_t)s->code_buf, prologue_size); 1239df5d2b16SRichard Henderson #endif 12408163b749SRichard Henderson 1241d6b64b2bSRichard Henderson #ifdef DEBUG_DISAS 1242d6b64b2bSRichard Henderson if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) { 1243c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock(); 124478b54858SRichard Henderson if (logfile) { 124578b54858SRichard Henderson fprintf(logfile, "PROLOGUE: [size=%zu]\n", prologue_size); 12465b38ee31SRichard Henderson if (s->data_gen_ptr) { 1247b0a0794aSRichard Henderson size_t code_size = s->data_gen_ptr - s->code_gen_ptr; 12485b38ee31SRichard Henderson size_t data_size = prologue_size - code_size; 12495b38ee31SRichard Henderson size_t i; 12505b38ee31SRichard Henderson 125178b54858SRichard Henderson disas(logfile, s->code_gen_ptr, code_size); 12525b38ee31SRichard Henderson 12535b38ee31SRichard Henderson for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) { 12545b38ee31SRichard Henderson if (sizeof(tcg_target_ulong) == 8) { 125578b54858SRichard Henderson fprintf(logfile, 125678b54858SRichard Henderson "0x%08" PRIxPTR ": .quad 0x%016" PRIx64 "\n", 12575b38ee31SRichard Henderson (uintptr_t)s->data_gen_ptr + i, 12585b38ee31SRichard Henderson *(uint64_t *)(s->data_gen_ptr + i)); 12595b38ee31SRichard Henderson } else { 126078b54858SRichard Henderson fprintf(logfile, 126178b54858SRichard Henderson "0x%08" PRIxPTR ": .long 0x%08x\n", 12625b38ee31SRichard Henderson (uintptr_t)s->data_gen_ptr + i, 12635b38ee31SRichard Henderson *(uint32_t *)(s->data_gen_ptr + i)); 12645b38ee31SRichard Henderson } 12655b38ee31SRichard Henderson } 12665b38ee31SRichard Henderson } else { 126778b54858SRichard Henderson disas(logfile, s->code_gen_ptr, prologue_size); 12685b38ee31SRichard Henderson } 126978b54858SRichard Henderson fprintf(logfile, "\n"); 1270fc59d2d8SRobert Foley qemu_log_unlock(logfile); 1271d6b64b2bSRichard Henderson } 127278b54858SRichard Henderson } 1273d6b64b2bSRichard Henderson #endif 1274cedbcb01SEmilio G. Cota 12756eea0434SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 12766eea0434SRichard Henderson /* 12776eea0434SRichard Henderson * Assert that goto_ptr is implemented completely, setting an epilogue. 12786eea0434SRichard Henderson * For tci, we use NULL as the signal to return from the interpreter, 12796eea0434SRichard Henderson * so skip this check. 12806eea0434SRichard Henderson */ 12818b5c2b62SRichard Henderson tcg_debug_assert(tcg_code_gen_epilogue != NULL); 12826eea0434SRichard Henderson #endif 1283d1c74ab3SRichard Henderson 1284d1c74ab3SRichard Henderson tcg_region_prologue_set(s); 1285c896fe29Sbellard } 1286c896fe29Sbellard 1287c896fe29Sbellard void tcg_func_start(TCGContext *s) 1288c896fe29Sbellard { 1289c896fe29Sbellard tcg_pool_reset(s); 1290c896fe29Sbellard s->nb_temps = s->nb_globals; 12910ec9eabcSRichard Henderson 12920ec9eabcSRichard Henderson /* No temps have been previously allocated for size or locality. */ 12930ec9eabcSRichard Henderson memset(s->free_temps, 0, sizeof(s->free_temps)); 12940ec9eabcSRichard Henderson 1295c0522136SRichard Henderson /* No constant temps have been previously allocated. */ 1296c0522136SRichard Henderson for (int i = 0; i < TCG_TYPE_COUNT; ++i) { 1297c0522136SRichard Henderson if (s->const_table[i]) { 1298c0522136SRichard Henderson g_hash_table_remove_all(s->const_table[i]); 1299c0522136SRichard Henderson } 1300c0522136SRichard Henderson } 1301c0522136SRichard Henderson 1302abebf925SRichard Henderson s->nb_ops = 0; 1303c896fe29Sbellard s->nb_labels = 0; 1304c896fe29Sbellard s->current_frame_offset = s->frame_start; 1305c896fe29Sbellard 13060a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG 13070a209d4bSRichard Henderson s->goto_tb_issue_mask = 0; 13080a209d4bSRichard Henderson #endif 13090a209d4bSRichard Henderson 131015fa08f8SRichard Henderson QTAILQ_INIT(&s->ops); 131115fa08f8SRichard Henderson QTAILQ_INIT(&s->free_ops); 1312bef16ab4SRichard Henderson QSIMPLEQ_INIT(&s->labels); 1313c896fe29Sbellard } 1314c896fe29Sbellard 1315ae30e866SRichard Henderson static TCGTemp *tcg_temp_alloc(TCGContext *s) 13167ca4b752SRichard Henderson { 13177ca4b752SRichard Henderson int n = s->nb_temps++; 1318ae30e866SRichard Henderson 1319ae30e866SRichard Henderson if (n >= TCG_MAX_TEMPS) { 1320db6b7d0cSRichard Henderson tcg_raise_tb_overflow(s); 1321ae30e866SRichard Henderson } 13227ca4b752SRichard Henderson return memset(&s->temps[n], 0, sizeof(TCGTemp)); 13237ca4b752SRichard Henderson } 13247ca4b752SRichard Henderson 1325ae30e866SRichard Henderson static TCGTemp *tcg_global_alloc(TCGContext *s) 13267ca4b752SRichard Henderson { 1327fa477d25SRichard Henderson TCGTemp *ts; 1328fa477d25SRichard Henderson 13297ca4b752SRichard Henderson tcg_debug_assert(s->nb_globals == s->nb_temps); 1330ae30e866SRichard Henderson tcg_debug_assert(s->nb_globals < TCG_MAX_TEMPS); 13317ca4b752SRichard Henderson s->nb_globals++; 1332fa477d25SRichard Henderson ts = tcg_temp_alloc(s); 1333ee17db83SRichard Henderson ts->kind = TEMP_GLOBAL; 1334fa477d25SRichard Henderson 1335fa477d25SRichard Henderson return ts; 1336c896fe29Sbellard } 1337c896fe29Sbellard 1338085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type, 1339b6638662SRichard Henderson TCGReg reg, const char *name) 1340c896fe29Sbellard { 1341c896fe29Sbellard TCGTemp *ts; 1342c896fe29Sbellard 13431a057554SRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 64 || type == TCG_TYPE_I32); 13447ca4b752SRichard Henderson 13457ca4b752SRichard Henderson ts = tcg_global_alloc(s); 1346c896fe29Sbellard ts->base_type = type; 1347c896fe29Sbellard ts->type = type; 1348ee17db83SRichard Henderson ts->kind = TEMP_FIXED; 1349c896fe29Sbellard ts->reg = reg; 1350c896fe29Sbellard ts->name = name; 1351c896fe29Sbellard tcg_regset_set_reg(s->reserved_regs, reg); 13527ca4b752SRichard Henderson 1353085272b3SRichard Henderson return ts; 1354a7812ae4Spbrook } 1355a7812ae4Spbrook 1356b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size) 1357a7812ae4Spbrook { 1358b3a62939SRichard Henderson s->frame_start = start; 1359b3a62939SRichard Henderson s->frame_end = start + size; 1360085272b3SRichard Henderson s->frame_temp 1361085272b3SRichard Henderson = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame"); 1362b3a62939SRichard Henderson } 1363a7812ae4Spbrook 1364085272b3SRichard Henderson TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base, 1365e1ccc054SRichard Henderson intptr_t offset, const char *name) 1366c896fe29Sbellard { 1367b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1368dc41aa7dSRichard Henderson TCGTemp *base_ts = tcgv_ptr_temp(base); 13697ca4b752SRichard Henderson TCGTemp *ts = tcg_global_alloc(s); 1370aef85402SRichard Henderson int indirect_reg = 0; 1371c896fe29Sbellard 1372c0522136SRichard Henderson switch (base_ts->kind) { 1373c0522136SRichard Henderson case TEMP_FIXED: 1374c0522136SRichard Henderson break; 1375c0522136SRichard Henderson case TEMP_GLOBAL: 13765a18407fSRichard Henderson /* We do not support double-indirect registers. */ 13775a18407fSRichard Henderson tcg_debug_assert(!base_ts->indirect_reg); 1378b3915dbbSRichard Henderson base_ts->indirect_base = 1; 13795a18407fSRichard Henderson s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64 13805a18407fSRichard Henderson ? 2 : 1); 13815a18407fSRichard Henderson indirect_reg = 1; 1382c0522136SRichard Henderson break; 1383c0522136SRichard Henderson default: 1384c0522136SRichard Henderson g_assert_not_reached(); 1385b3915dbbSRichard Henderson } 1386b3915dbbSRichard Henderson 13877ca4b752SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { 13887ca4b752SRichard Henderson TCGTemp *ts2 = tcg_global_alloc(s); 1389c896fe29Sbellard char buf[64]; 13907ca4b752SRichard Henderson 13917ca4b752SRichard Henderson ts->base_type = TCG_TYPE_I64; 1392c896fe29Sbellard ts->type = TCG_TYPE_I32; 1393b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg; 1394c896fe29Sbellard ts->mem_allocated = 1; 1395b3a62939SRichard Henderson ts->mem_base = base_ts; 1396aef85402SRichard Henderson ts->mem_offset = offset; 1397c896fe29Sbellard pstrcpy(buf, sizeof(buf), name); 1398c896fe29Sbellard pstrcat(buf, sizeof(buf), "_0"); 1399c896fe29Sbellard ts->name = strdup(buf); 1400c896fe29Sbellard 14017ca4b752SRichard Henderson tcg_debug_assert(ts2 == ts + 1); 14027ca4b752SRichard Henderson ts2->base_type = TCG_TYPE_I64; 14037ca4b752SRichard Henderson ts2->type = TCG_TYPE_I32; 1404b3915dbbSRichard Henderson ts2->indirect_reg = indirect_reg; 14057ca4b752SRichard Henderson ts2->mem_allocated = 1; 14067ca4b752SRichard Henderson ts2->mem_base = base_ts; 1407aef85402SRichard Henderson ts2->mem_offset = offset + 4; 1408fac87bd2SRichard Henderson ts2->temp_subindex = 1; 1409c896fe29Sbellard pstrcpy(buf, sizeof(buf), name); 1410c896fe29Sbellard pstrcat(buf, sizeof(buf), "_1"); 1411120c1084SRichard Henderson ts2->name = strdup(buf); 14127ca4b752SRichard Henderson } else { 1413c896fe29Sbellard ts->base_type = type; 1414c896fe29Sbellard ts->type = type; 1415b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg; 1416c896fe29Sbellard ts->mem_allocated = 1; 1417b3a62939SRichard Henderson ts->mem_base = base_ts; 1418c896fe29Sbellard ts->mem_offset = offset; 1419c896fe29Sbellard ts->name = name; 1420c896fe29Sbellard } 1421085272b3SRichard Henderson return ts; 1422c896fe29Sbellard } 1423c896fe29Sbellard 1424bbf989bfSRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, TCGTempKind kind) 1425c896fe29Sbellard { 1426b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1427c896fe29Sbellard TCGTemp *ts; 1428e1c08b00SRichard Henderson int n; 1429c896fe29Sbellard 1430e1c08b00SRichard Henderson if (kind == TEMP_EBB) { 1431e1c08b00SRichard Henderson int idx = find_first_bit(s->free_temps[type].l, TCG_MAX_TEMPS); 1432e1c08b00SRichard Henderson 14330ec9eabcSRichard Henderson if (idx < TCG_MAX_TEMPS) { 14340ec9eabcSRichard Henderson /* There is already an available temp with the right type. */ 1435e1c08b00SRichard Henderson clear_bit(idx, s->free_temps[type].l); 14360ec9eabcSRichard Henderson 1437e8996ee0Sbellard ts = &s->temps[idx]; 1438e8996ee0Sbellard ts->temp_allocated = 1; 14397ca4b752SRichard Henderson tcg_debug_assert(ts->base_type == type); 1440ee17db83SRichard Henderson tcg_debug_assert(ts->kind == kind); 14412f2e911dSRichard Henderson return ts; 1442e1c08b00SRichard Henderson } 1443e8996ee0Sbellard } else { 1444e1c08b00SRichard Henderson tcg_debug_assert(kind == TEMP_TB); 1445e1c08b00SRichard Henderson } 144643eef72fSRichard Henderson 144743eef72fSRichard Henderson switch (type) { 144843eef72fSRichard Henderson case TCG_TYPE_I32: 144943eef72fSRichard Henderson case TCG_TYPE_V64: 145043eef72fSRichard Henderson case TCG_TYPE_V128: 145143eef72fSRichard Henderson case TCG_TYPE_V256: 145243eef72fSRichard Henderson n = 1; 145343eef72fSRichard Henderson break; 145443eef72fSRichard Henderson case TCG_TYPE_I64: 145543eef72fSRichard Henderson n = 64 / TCG_TARGET_REG_BITS; 145643eef72fSRichard Henderson break; 145743eef72fSRichard Henderson case TCG_TYPE_I128: 145843eef72fSRichard Henderson n = 128 / TCG_TARGET_REG_BITS; 145943eef72fSRichard Henderson break; 146043eef72fSRichard Henderson default: 146143eef72fSRichard Henderson g_assert_not_reached(); 146243eef72fSRichard Henderson } 146343eef72fSRichard Henderson 14647ca4b752SRichard Henderson ts = tcg_temp_alloc(s); 146543eef72fSRichard Henderson ts->base_type = type; 146643eef72fSRichard Henderson ts->temp_allocated = 1; 146743eef72fSRichard Henderson ts->kind = kind; 146843eef72fSRichard Henderson 146943eef72fSRichard Henderson if (n == 1) { 147043eef72fSRichard Henderson ts->type = type; 147143eef72fSRichard Henderson } else { 147243eef72fSRichard Henderson ts->type = TCG_TYPE_REG; 147343eef72fSRichard Henderson 1474e1c08b00SRichard Henderson for (int i = 1; i < n; ++i) { 14757ca4b752SRichard Henderson TCGTemp *ts2 = tcg_temp_alloc(s); 14767ca4b752SRichard Henderson 147743eef72fSRichard Henderson tcg_debug_assert(ts2 == ts + i); 147843eef72fSRichard Henderson ts2->base_type = type; 147943eef72fSRichard Henderson ts2->type = TCG_TYPE_REG; 14807ca4b752SRichard Henderson ts2->temp_allocated = 1; 148143eef72fSRichard Henderson ts2->temp_subindex = i; 1482ee17db83SRichard Henderson ts2->kind = kind; 148343eef72fSRichard Henderson } 1484c896fe29Sbellard } 1485085272b3SRichard Henderson return ts; 1486c896fe29Sbellard } 1487c896fe29Sbellard 1488d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type) 1489d2fd745fSRichard Henderson { 1490d2fd745fSRichard Henderson TCGTemp *t; 1491d2fd745fSRichard Henderson 1492d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG 1493d2fd745fSRichard Henderson switch (type) { 1494d2fd745fSRichard Henderson case TCG_TYPE_V64: 1495d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v64); 1496d2fd745fSRichard Henderson break; 1497d2fd745fSRichard Henderson case TCG_TYPE_V128: 1498d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v128); 1499d2fd745fSRichard Henderson break; 1500d2fd745fSRichard Henderson case TCG_TYPE_V256: 1501d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v256); 1502d2fd745fSRichard Henderson break; 1503d2fd745fSRichard Henderson default: 1504d2fd745fSRichard Henderson g_assert_not_reached(); 1505d2fd745fSRichard Henderson } 1506d2fd745fSRichard Henderson #endif 1507d2fd745fSRichard Henderson 1508bbf989bfSRichard Henderson t = tcg_temp_new_internal(type, TEMP_EBB); 1509d2fd745fSRichard Henderson return temp_tcgv_vec(t); 1510d2fd745fSRichard Henderson } 1511d2fd745fSRichard Henderson 1512d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp. */ 1513d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match) 1514d2fd745fSRichard Henderson { 1515d2fd745fSRichard Henderson TCGTemp *t = tcgv_vec_temp(match); 1516d2fd745fSRichard Henderson 1517d2fd745fSRichard Henderson tcg_debug_assert(t->temp_allocated != 0); 1518d2fd745fSRichard Henderson 1519bbf989bfSRichard Henderson t = tcg_temp_new_internal(t->base_type, TEMP_EBB); 1520d2fd745fSRichard Henderson return temp_tcgv_vec(t); 1521d2fd745fSRichard Henderson } 1522d2fd745fSRichard Henderson 15235bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts) 1524c896fe29Sbellard { 1525b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1526c896fe29Sbellard 1527c7482438SRichard Henderson switch (ts->kind) { 1528c7482438SRichard Henderson case TEMP_CONST: 1529f57c6915SRichard Henderson case TEMP_TB: 15302f2e911dSRichard Henderson /* Silently ignore free. */ 1531c7482438SRichard Henderson break; 15322f2e911dSRichard Henderson case TEMP_EBB: 1533eabb7b91SAurelien Jarno tcg_debug_assert(ts->temp_allocated != 0); 1534e8996ee0Sbellard ts->temp_allocated = 0; 15352f2e911dSRichard Henderson set_bit(temp_idx(ts), s->free_temps[ts->base_type].l); 15362f2e911dSRichard Henderson break; 15372f2e911dSRichard Henderson default: 15382f2e911dSRichard Henderson /* It never made sense to free TEMP_FIXED or TEMP_GLOBAL. */ 15392f2e911dSRichard Henderson g_assert_not_reached(); 1540e1c08b00SRichard Henderson } 1541e8996ee0Sbellard } 1542e8996ee0Sbellard 1543c0522136SRichard Henderson TCGTemp *tcg_constant_internal(TCGType type, int64_t val) 1544c0522136SRichard Henderson { 1545c0522136SRichard Henderson TCGContext *s = tcg_ctx; 1546c0522136SRichard Henderson GHashTable *h = s->const_table[type]; 1547c0522136SRichard Henderson TCGTemp *ts; 1548c0522136SRichard Henderson 1549c0522136SRichard Henderson if (h == NULL) { 1550c0522136SRichard Henderson h = g_hash_table_new(g_int64_hash, g_int64_equal); 1551c0522136SRichard Henderson s->const_table[type] = h; 1552c0522136SRichard Henderson } 1553c0522136SRichard Henderson 1554c0522136SRichard Henderson ts = g_hash_table_lookup(h, &val); 1555c0522136SRichard Henderson if (ts == NULL) { 1556aef85402SRichard Henderson int64_t *val_ptr; 1557aef85402SRichard Henderson 1558c0522136SRichard Henderson ts = tcg_temp_alloc(s); 1559c0522136SRichard Henderson 1560c0522136SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { 1561c0522136SRichard Henderson TCGTemp *ts2 = tcg_temp_alloc(s); 1562c0522136SRichard Henderson 1563aef85402SRichard Henderson tcg_debug_assert(ts2 == ts + 1); 1564aef85402SRichard Henderson 1565c0522136SRichard Henderson ts->base_type = TCG_TYPE_I64; 1566c0522136SRichard Henderson ts->type = TCG_TYPE_I32; 1567c0522136SRichard Henderson ts->kind = TEMP_CONST; 1568c0522136SRichard Henderson ts->temp_allocated = 1; 1569c0522136SRichard Henderson 1570c0522136SRichard Henderson ts2->base_type = TCG_TYPE_I64; 1571c0522136SRichard Henderson ts2->type = TCG_TYPE_I32; 1572c0522136SRichard Henderson ts2->kind = TEMP_CONST; 1573c0522136SRichard Henderson ts2->temp_allocated = 1; 1574fac87bd2SRichard Henderson ts2->temp_subindex = 1; 1575aef85402SRichard Henderson 1576aef85402SRichard Henderson /* 1577aef85402SRichard Henderson * Retain the full value of the 64-bit constant in the low 1578aef85402SRichard Henderson * part, so that the hash table works. Actual uses will 1579aef85402SRichard Henderson * truncate the value to the low part. 1580aef85402SRichard Henderson */ 1581aef85402SRichard Henderson ts[HOST_BIG_ENDIAN].val = val; 1582aef85402SRichard Henderson ts[!HOST_BIG_ENDIAN].val = val >> 32; 1583aef85402SRichard Henderson val_ptr = &ts[HOST_BIG_ENDIAN].val; 1584c0522136SRichard Henderson } else { 1585c0522136SRichard Henderson ts->base_type = type; 1586c0522136SRichard Henderson ts->type = type; 1587c0522136SRichard Henderson ts->kind = TEMP_CONST; 1588c0522136SRichard Henderson ts->temp_allocated = 1; 1589c0522136SRichard Henderson ts->val = val; 1590aef85402SRichard Henderson val_ptr = &ts->val; 1591c0522136SRichard Henderson } 1592aef85402SRichard Henderson g_hash_table_insert(h, val_ptr, ts); 1593c0522136SRichard Henderson } 1594c0522136SRichard Henderson 1595c0522136SRichard Henderson return ts; 1596c0522136SRichard Henderson } 1597c0522136SRichard Henderson 1598c0522136SRichard Henderson TCGv_vec tcg_constant_vec(TCGType type, unsigned vece, int64_t val) 1599c0522136SRichard Henderson { 1600c0522136SRichard Henderson val = dup_const(vece, val); 1601c0522136SRichard Henderson return temp_tcgv_vec(tcg_constant_internal(type, val)); 1602c0522136SRichard Henderson } 1603c0522136SRichard Henderson 160488d4005bSRichard Henderson TCGv_vec tcg_constant_vec_matching(TCGv_vec match, unsigned vece, int64_t val) 160588d4005bSRichard Henderson { 160688d4005bSRichard Henderson TCGTemp *t = tcgv_vec_temp(match); 160788d4005bSRichard Henderson 160888d4005bSRichard Henderson tcg_debug_assert(t->temp_allocated != 0); 160988d4005bSRichard Henderson return tcg_constant_vec(t->base_type, vece, val); 161088d4005bSRichard Henderson } 161188d4005bSRichard Henderson 1612be0f34b5SRichard Henderson /* Return true if OP may appear in the opcode stream. 1613be0f34b5SRichard Henderson Test the runtime variable that controls each opcode. */ 1614be0f34b5SRichard Henderson bool tcg_op_supported(TCGOpcode op) 1615be0f34b5SRichard Henderson { 1616d2fd745fSRichard Henderson const bool have_vec 1617d2fd745fSRichard Henderson = TCG_TARGET_HAS_v64 | TCG_TARGET_HAS_v128 | TCG_TARGET_HAS_v256; 1618d2fd745fSRichard Henderson 1619be0f34b5SRichard Henderson switch (op) { 1620be0f34b5SRichard Henderson case INDEX_op_discard: 1621be0f34b5SRichard Henderson case INDEX_op_set_label: 1622be0f34b5SRichard Henderson case INDEX_op_call: 1623be0f34b5SRichard Henderson case INDEX_op_br: 1624be0f34b5SRichard Henderson case INDEX_op_mb: 1625be0f34b5SRichard Henderson case INDEX_op_insn_start: 1626be0f34b5SRichard Henderson case INDEX_op_exit_tb: 1627be0f34b5SRichard Henderson case INDEX_op_goto_tb: 1628f4e01e30SRichard Henderson case INDEX_op_goto_ptr: 1629be0f34b5SRichard Henderson case INDEX_op_qemu_ld_i32: 1630be0f34b5SRichard Henderson case INDEX_op_qemu_st_i32: 1631be0f34b5SRichard Henderson case INDEX_op_qemu_ld_i64: 1632be0f34b5SRichard Henderson case INDEX_op_qemu_st_i64: 1633be0f34b5SRichard Henderson return true; 1634be0f34b5SRichard Henderson 163507ce0b05SRichard Henderson case INDEX_op_qemu_st8_i32: 163607ce0b05SRichard Henderson return TCG_TARGET_HAS_qemu_st8_i32; 163707ce0b05SRichard Henderson 1638be0f34b5SRichard Henderson case INDEX_op_mov_i32: 1639be0f34b5SRichard Henderson case INDEX_op_setcond_i32: 1640be0f34b5SRichard Henderson case INDEX_op_brcond_i32: 1641be0f34b5SRichard Henderson case INDEX_op_ld8u_i32: 1642be0f34b5SRichard Henderson case INDEX_op_ld8s_i32: 1643be0f34b5SRichard Henderson case INDEX_op_ld16u_i32: 1644be0f34b5SRichard Henderson case INDEX_op_ld16s_i32: 1645be0f34b5SRichard Henderson case INDEX_op_ld_i32: 1646be0f34b5SRichard Henderson case INDEX_op_st8_i32: 1647be0f34b5SRichard Henderson case INDEX_op_st16_i32: 1648be0f34b5SRichard Henderson case INDEX_op_st_i32: 1649be0f34b5SRichard Henderson case INDEX_op_add_i32: 1650be0f34b5SRichard Henderson case INDEX_op_sub_i32: 1651be0f34b5SRichard Henderson case INDEX_op_mul_i32: 1652be0f34b5SRichard Henderson case INDEX_op_and_i32: 1653be0f34b5SRichard Henderson case INDEX_op_or_i32: 1654be0f34b5SRichard Henderson case INDEX_op_xor_i32: 1655be0f34b5SRichard Henderson case INDEX_op_shl_i32: 1656be0f34b5SRichard Henderson case INDEX_op_shr_i32: 1657be0f34b5SRichard Henderson case INDEX_op_sar_i32: 1658be0f34b5SRichard Henderson return true; 1659be0f34b5SRichard Henderson 1660be0f34b5SRichard Henderson case INDEX_op_movcond_i32: 1661be0f34b5SRichard Henderson return TCG_TARGET_HAS_movcond_i32; 1662be0f34b5SRichard Henderson case INDEX_op_div_i32: 1663be0f34b5SRichard Henderson case INDEX_op_divu_i32: 1664be0f34b5SRichard Henderson return TCG_TARGET_HAS_div_i32; 1665be0f34b5SRichard Henderson case INDEX_op_rem_i32: 1666be0f34b5SRichard Henderson case INDEX_op_remu_i32: 1667be0f34b5SRichard Henderson return TCG_TARGET_HAS_rem_i32; 1668be0f34b5SRichard Henderson case INDEX_op_div2_i32: 1669be0f34b5SRichard Henderson case INDEX_op_divu2_i32: 1670be0f34b5SRichard Henderson return TCG_TARGET_HAS_div2_i32; 1671be0f34b5SRichard Henderson case INDEX_op_rotl_i32: 1672be0f34b5SRichard Henderson case INDEX_op_rotr_i32: 1673be0f34b5SRichard Henderson return TCG_TARGET_HAS_rot_i32; 1674be0f34b5SRichard Henderson case INDEX_op_deposit_i32: 1675be0f34b5SRichard Henderson return TCG_TARGET_HAS_deposit_i32; 1676be0f34b5SRichard Henderson case INDEX_op_extract_i32: 1677be0f34b5SRichard Henderson return TCG_TARGET_HAS_extract_i32; 1678be0f34b5SRichard Henderson case INDEX_op_sextract_i32: 1679be0f34b5SRichard Henderson return TCG_TARGET_HAS_sextract_i32; 1680fce1296fSRichard Henderson case INDEX_op_extract2_i32: 1681fce1296fSRichard Henderson return TCG_TARGET_HAS_extract2_i32; 1682be0f34b5SRichard Henderson case INDEX_op_add2_i32: 1683be0f34b5SRichard Henderson return TCG_TARGET_HAS_add2_i32; 1684be0f34b5SRichard Henderson case INDEX_op_sub2_i32: 1685be0f34b5SRichard Henderson return TCG_TARGET_HAS_sub2_i32; 1686be0f34b5SRichard Henderson case INDEX_op_mulu2_i32: 1687be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulu2_i32; 1688be0f34b5SRichard Henderson case INDEX_op_muls2_i32: 1689be0f34b5SRichard Henderson return TCG_TARGET_HAS_muls2_i32; 1690be0f34b5SRichard Henderson case INDEX_op_muluh_i32: 1691be0f34b5SRichard Henderson return TCG_TARGET_HAS_muluh_i32; 1692be0f34b5SRichard Henderson case INDEX_op_mulsh_i32: 1693be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulsh_i32; 1694be0f34b5SRichard Henderson case INDEX_op_ext8s_i32: 1695be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8s_i32; 1696be0f34b5SRichard Henderson case INDEX_op_ext16s_i32: 1697be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16s_i32; 1698be0f34b5SRichard Henderson case INDEX_op_ext8u_i32: 1699be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8u_i32; 1700be0f34b5SRichard Henderson case INDEX_op_ext16u_i32: 1701be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16u_i32; 1702be0f34b5SRichard Henderson case INDEX_op_bswap16_i32: 1703be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap16_i32; 1704be0f34b5SRichard Henderson case INDEX_op_bswap32_i32: 1705be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap32_i32; 1706be0f34b5SRichard Henderson case INDEX_op_not_i32: 1707be0f34b5SRichard Henderson return TCG_TARGET_HAS_not_i32; 1708be0f34b5SRichard Henderson case INDEX_op_neg_i32: 1709be0f34b5SRichard Henderson return TCG_TARGET_HAS_neg_i32; 1710be0f34b5SRichard Henderson case INDEX_op_andc_i32: 1711be0f34b5SRichard Henderson return TCG_TARGET_HAS_andc_i32; 1712be0f34b5SRichard Henderson case INDEX_op_orc_i32: 1713be0f34b5SRichard Henderson return TCG_TARGET_HAS_orc_i32; 1714be0f34b5SRichard Henderson case INDEX_op_eqv_i32: 1715be0f34b5SRichard Henderson return TCG_TARGET_HAS_eqv_i32; 1716be0f34b5SRichard Henderson case INDEX_op_nand_i32: 1717be0f34b5SRichard Henderson return TCG_TARGET_HAS_nand_i32; 1718be0f34b5SRichard Henderson case INDEX_op_nor_i32: 1719be0f34b5SRichard Henderson return TCG_TARGET_HAS_nor_i32; 1720be0f34b5SRichard Henderson case INDEX_op_clz_i32: 1721be0f34b5SRichard Henderson return TCG_TARGET_HAS_clz_i32; 1722be0f34b5SRichard Henderson case INDEX_op_ctz_i32: 1723be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctz_i32; 1724be0f34b5SRichard Henderson case INDEX_op_ctpop_i32: 1725be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctpop_i32; 1726be0f34b5SRichard Henderson 1727be0f34b5SRichard Henderson case INDEX_op_brcond2_i32: 1728be0f34b5SRichard Henderson case INDEX_op_setcond2_i32: 1729be0f34b5SRichard Henderson return TCG_TARGET_REG_BITS == 32; 1730be0f34b5SRichard Henderson 1731be0f34b5SRichard Henderson case INDEX_op_mov_i64: 1732be0f34b5SRichard Henderson case INDEX_op_setcond_i64: 1733be0f34b5SRichard Henderson case INDEX_op_brcond_i64: 1734be0f34b5SRichard Henderson case INDEX_op_ld8u_i64: 1735be0f34b5SRichard Henderson case INDEX_op_ld8s_i64: 1736be0f34b5SRichard Henderson case INDEX_op_ld16u_i64: 1737be0f34b5SRichard Henderson case INDEX_op_ld16s_i64: 1738be0f34b5SRichard Henderson case INDEX_op_ld32u_i64: 1739be0f34b5SRichard Henderson case INDEX_op_ld32s_i64: 1740be0f34b5SRichard Henderson case INDEX_op_ld_i64: 1741be0f34b5SRichard Henderson case INDEX_op_st8_i64: 1742be0f34b5SRichard Henderson case INDEX_op_st16_i64: 1743be0f34b5SRichard Henderson case INDEX_op_st32_i64: 1744be0f34b5SRichard Henderson case INDEX_op_st_i64: 1745be0f34b5SRichard Henderson case INDEX_op_add_i64: 1746be0f34b5SRichard Henderson case INDEX_op_sub_i64: 1747be0f34b5SRichard Henderson case INDEX_op_mul_i64: 1748be0f34b5SRichard Henderson case INDEX_op_and_i64: 1749be0f34b5SRichard Henderson case INDEX_op_or_i64: 1750be0f34b5SRichard Henderson case INDEX_op_xor_i64: 1751be0f34b5SRichard Henderson case INDEX_op_shl_i64: 1752be0f34b5SRichard Henderson case INDEX_op_shr_i64: 1753be0f34b5SRichard Henderson case INDEX_op_sar_i64: 1754be0f34b5SRichard Henderson case INDEX_op_ext_i32_i64: 1755be0f34b5SRichard Henderson case INDEX_op_extu_i32_i64: 1756be0f34b5SRichard Henderson return TCG_TARGET_REG_BITS == 64; 1757be0f34b5SRichard Henderson 1758be0f34b5SRichard Henderson case INDEX_op_movcond_i64: 1759be0f34b5SRichard Henderson return TCG_TARGET_HAS_movcond_i64; 1760be0f34b5SRichard Henderson case INDEX_op_div_i64: 1761be0f34b5SRichard Henderson case INDEX_op_divu_i64: 1762be0f34b5SRichard Henderson return TCG_TARGET_HAS_div_i64; 1763be0f34b5SRichard Henderson case INDEX_op_rem_i64: 1764be0f34b5SRichard Henderson case INDEX_op_remu_i64: 1765be0f34b5SRichard Henderson return TCG_TARGET_HAS_rem_i64; 1766be0f34b5SRichard Henderson case INDEX_op_div2_i64: 1767be0f34b5SRichard Henderson case INDEX_op_divu2_i64: 1768be0f34b5SRichard Henderson return TCG_TARGET_HAS_div2_i64; 1769be0f34b5SRichard Henderson case INDEX_op_rotl_i64: 1770be0f34b5SRichard Henderson case INDEX_op_rotr_i64: 1771be0f34b5SRichard Henderson return TCG_TARGET_HAS_rot_i64; 1772be0f34b5SRichard Henderson case INDEX_op_deposit_i64: 1773be0f34b5SRichard Henderson return TCG_TARGET_HAS_deposit_i64; 1774be0f34b5SRichard Henderson case INDEX_op_extract_i64: 1775be0f34b5SRichard Henderson return TCG_TARGET_HAS_extract_i64; 1776be0f34b5SRichard Henderson case INDEX_op_sextract_i64: 1777be0f34b5SRichard Henderson return TCG_TARGET_HAS_sextract_i64; 1778fce1296fSRichard Henderson case INDEX_op_extract2_i64: 1779fce1296fSRichard Henderson return TCG_TARGET_HAS_extract2_i64; 1780be0f34b5SRichard Henderson case INDEX_op_extrl_i64_i32: 1781be0f34b5SRichard Henderson return TCG_TARGET_HAS_extrl_i64_i32; 1782be0f34b5SRichard Henderson case INDEX_op_extrh_i64_i32: 1783be0f34b5SRichard Henderson return TCG_TARGET_HAS_extrh_i64_i32; 1784be0f34b5SRichard Henderson case INDEX_op_ext8s_i64: 1785be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8s_i64; 1786be0f34b5SRichard Henderson case INDEX_op_ext16s_i64: 1787be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16s_i64; 1788be0f34b5SRichard Henderson case INDEX_op_ext32s_i64: 1789be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext32s_i64; 1790be0f34b5SRichard Henderson case INDEX_op_ext8u_i64: 1791be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8u_i64; 1792be0f34b5SRichard Henderson case INDEX_op_ext16u_i64: 1793be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16u_i64; 1794be0f34b5SRichard Henderson case INDEX_op_ext32u_i64: 1795be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext32u_i64; 1796be0f34b5SRichard Henderson case INDEX_op_bswap16_i64: 1797be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap16_i64; 1798be0f34b5SRichard Henderson case INDEX_op_bswap32_i64: 1799be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap32_i64; 1800be0f34b5SRichard Henderson case INDEX_op_bswap64_i64: 1801be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap64_i64; 1802be0f34b5SRichard Henderson case INDEX_op_not_i64: 1803be0f34b5SRichard Henderson return TCG_TARGET_HAS_not_i64; 1804be0f34b5SRichard Henderson case INDEX_op_neg_i64: 1805be0f34b5SRichard Henderson return TCG_TARGET_HAS_neg_i64; 1806be0f34b5SRichard Henderson case INDEX_op_andc_i64: 1807be0f34b5SRichard Henderson return TCG_TARGET_HAS_andc_i64; 1808be0f34b5SRichard Henderson case INDEX_op_orc_i64: 1809be0f34b5SRichard Henderson return TCG_TARGET_HAS_orc_i64; 1810be0f34b5SRichard Henderson case INDEX_op_eqv_i64: 1811be0f34b5SRichard Henderson return TCG_TARGET_HAS_eqv_i64; 1812be0f34b5SRichard Henderson case INDEX_op_nand_i64: 1813be0f34b5SRichard Henderson return TCG_TARGET_HAS_nand_i64; 1814be0f34b5SRichard Henderson case INDEX_op_nor_i64: 1815be0f34b5SRichard Henderson return TCG_TARGET_HAS_nor_i64; 1816be0f34b5SRichard Henderson case INDEX_op_clz_i64: 1817be0f34b5SRichard Henderson return TCG_TARGET_HAS_clz_i64; 1818be0f34b5SRichard Henderson case INDEX_op_ctz_i64: 1819be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctz_i64; 1820be0f34b5SRichard Henderson case INDEX_op_ctpop_i64: 1821be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctpop_i64; 1822be0f34b5SRichard Henderson case INDEX_op_add2_i64: 1823be0f34b5SRichard Henderson return TCG_TARGET_HAS_add2_i64; 1824be0f34b5SRichard Henderson case INDEX_op_sub2_i64: 1825be0f34b5SRichard Henderson return TCG_TARGET_HAS_sub2_i64; 1826be0f34b5SRichard Henderson case INDEX_op_mulu2_i64: 1827be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulu2_i64; 1828be0f34b5SRichard Henderson case INDEX_op_muls2_i64: 1829be0f34b5SRichard Henderson return TCG_TARGET_HAS_muls2_i64; 1830be0f34b5SRichard Henderson case INDEX_op_muluh_i64: 1831be0f34b5SRichard Henderson return TCG_TARGET_HAS_muluh_i64; 1832be0f34b5SRichard Henderson case INDEX_op_mulsh_i64: 1833be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulsh_i64; 1834be0f34b5SRichard Henderson 1835d2fd745fSRichard Henderson case INDEX_op_mov_vec: 1836d2fd745fSRichard Henderson case INDEX_op_dup_vec: 183737ee55a0SRichard Henderson case INDEX_op_dupm_vec: 1838d2fd745fSRichard Henderson case INDEX_op_ld_vec: 1839d2fd745fSRichard Henderson case INDEX_op_st_vec: 1840d2fd745fSRichard Henderson case INDEX_op_add_vec: 1841d2fd745fSRichard Henderson case INDEX_op_sub_vec: 1842d2fd745fSRichard Henderson case INDEX_op_and_vec: 1843d2fd745fSRichard Henderson case INDEX_op_or_vec: 1844d2fd745fSRichard Henderson case INDEX_op_xor_vec: 1845212be173SRichard Henderson case INDEX_op_cmp_vec: 1846d2fd745fSRichard Henderson return have_vec; 1847d2fd745fSRichard Henderson case INDEX_op_dup2_vec: 1848d2fd745fSRichard Henderson return have_vec && TCG_TARGET_REG_BITS == 32; 1849d2fd745fSRichard Henderson case INDEX_op_not_vec: 1850d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_not_vec; 1851d2fd745fSRichard Henderson case INDEX_op_neg_vec: 1852d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_neg_vec; 1853bcefc902SRichard Henderson case INDEX_op_abs_vec: 1854bcefc902SRichard Henderson return have_vec && TCG_TARGET_HAS_abs_vec; 1855d2fd745fSRichard Henderson case INDEX_op_andc_vec: 1856d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_andc_vec; 1857d2fd745fSRichard Henderson case INDEX_op_orc_vec: 1858d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_orc_vec; 1859ed523473SRichard Henderson case INDEX_op_nand_vec: 1860ed523473SRichard Henderson return have_vec && TCG_TARGET_HAS_nand_vec; 1861ed523473SRichard Henderson case INDEX_op_nor_vec: 1862ed523473SRichard Henderson return have_vec && TCG_TARGET_HAS_nor_vec; 1863ed523473SRichard Henderson case INDEX_op_eqv_vec: 1864ed523473SRichard Henderson return have_vec && TCG_TARGET_HAS_eqv_vec; 18653774030aSRichard Henderson case INDEX_op_mul_vec: 18663774030aSRichard Henderson return have_vec && TCG_TARGET_HAS_mul_vec; 1867d0ec9796SRichard Henderson case INDEX_op_shli_vec: 1868d0ec9796SRichard Henderson case INDEX_op_shri_vec: 1869d0ec9796SRichard Henderson case INDEX_op_sari_vec: 1870d0ec9796SRichard Henderson return have_vec && TCG_TARGET_HAS_shi_vec; 1871d0ec9796SRichard Henderson case INDEX_op_shls_vec: 1872d0ec9796SRichard Henderson case INDEX_op_shrs_vec: 1873d0ec9796SRichard Henderson case INDEX_op_sars_vec: 1874d0ec9796SRichard Henderson return have_vec && TCG_TARGET_HAS_shs_vec; 1875d0ec9796SRichard Henderson case INDEX_op_shlv_vec: 1876d0ec9796SRichard Henderson case INDEX_op_shrv_vec: 1877d0ec9796SRichard Henderson case INDEX_op_sarv_vec: 1878d0ec9796SRichard Henderson return have_vec && TCG_TARGET_HAS_shv_vec; 1879b0f7e744SRichard Henderson case INDEX_op_rotli_vec: 1880b0f7e744SRichard Henderson return have_vec && TCG_TARGET_HAS_roti_vec; 188123850a74SRichard Henderson case INDEX_op_rotls_vec: 188223850a74SRichard Henderson return have_vec && TCG_TARGET_HAS_rots_vec; 18835d0ceda9SRichard Henderson case INDEX_op_rotlv_vec: 18845d0ceda9SRichard Henderson case INDEX_op_rotrv_vec: 18855d0ceda9SRichard Henderson return have_vec && TCG_TARGET_HAS_rotv_vec; 18868afaf050SRichard Henderson case INDEX_op_ssadd_vec: 18878afaf050SRichard Henderson case INDEX_op_usadd_vec: 18888afaf050SRichard Henderson case INDEX_op_sssub_vec: 18898afaf050SRichard Henderson case INDEX_op_ussub_vec: 18908afaf050SRichard Henderson return have_vec && TCG_TARGET_HAS_sat_vec; 1891dd0a0fcdSRichard Henderson case INDEX_op_smin_vec: 1892dd0a0fcdSRichard Henderson case INDEX_op_umin_vec: 1893dd0a0fcdSRichard Henderson case INDEX_op_smax_vec: 1894dd0a0fcdSRichard Henderson case INDEX_op_umax_vec: 1895dd0a0fcdSRichard Henderson return have_vec && TCG_TARGET_HAS_minmax_vec; 189638dc1294SRichard Henderson case INDEX_op_bitsel_vec: 189738dc1294SRichard Henderson return have_vec && TCG_TARGET_HAS_bitsel_vec; 1898f75da298SRichard Henderson case INDEX_op_cmpsel_vec: 1899f75da298SRichard Henderson return have_vec && TCG_TARGET_HAS_cmpsel_vec; 1900d2fd745fSRichard Henderson 1901db432672SRichard Henderson default: 1902db432672SRichard Henderson tcg_debug_assert(op > INDEX_op_last_generic && op < NB_OPS); 1903db432672SRichard Henderson return true; 1904be0f34b5SRichard Henderson } 1905be0f34b5SRichard Henderson } 1906be0f34b5SRichard Henderson 190739004a71SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs); 190839004a71SRichard Henderson 1909ae8b75dcSRichard Henderson void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args) 1910c896fe29Sbellard { 19113e92aa34SRichard Henderson const TCGHelperInfo *info; 191239004a71SRichard Henderson TCGv_i64 extend_free[MAX_CALL_IARGS]; 191339004a71SRichard Henderson int n_extend = 0; 191475e8b9b7SRichard Henderson TCGOp *op; 191539004a71SRichard Henderson int i, n, pi = 0, total_args; 1916afb49896SRichard Henderson 1917619205fdSEmilio G. Cota info = g_hash_table_lookup(helper_table, (gpointer)func); 191839004a71SRichard Henderson total_args = info->nr_out + info->nr_in + 2; 191939004a71SRichard Henderson op = tcg_op_alloc(INDEX_op_call, total_args); 19202bece2c8SRichard Henderson 192138b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN 192217083f6fSEmilio Cota /* Flag helpers that may affect guest state */ 192317083f6fSEmilio Cota if (tcg_ctx->plugin_insn && 192417083f6fSEmilio Cota !(info->flags & TCG_CALL_PLUGIN) && 192517083f6fSEmilio Cota !(info->flags & TCG_CALL_NO_SIDE_EFFECTS)) { 192638b47b19SEmilio G. Cota tcg_ctx->plugin_insn->calls_helpers = true; 192738b47b19SEmilio G. Cota } 192838b47b19SEmilio G. Cota #endif 192938b47b19SEmilio G. Cota 193039004a71SRichard Henderson TCGOP_CALLO(op) = n = info->nr_out; 193139004a71SRichard Henderson switch (n) { 193239004a71SRichard Henderson case 0: 193339004a71SRichard Henderson tcg_debug_assert(ret == NULL); 193439004a71SRichard Henderson break; 193539004a71SRichard Henderson case 1: 193639004a71SRichard Henderson tcg_debug_assert(ret != NULL); 193739004a71SRichard Henderson op->args[pi++] = temp_arg(ret); 193839004a71SRichard Henderson break; 193939004a71SRichard Henderson case 2: 1940466d3759SRichard Henderson case 4: 194139004a71SRichard Henderson tcg_debug_assert(ret != NULL); 1942466d3759SRichard Henderson tcg_debug_assert(ret->base_type == ret->type + ctz32(n)); 194339004a71SRichard Henderson tcg_debug_assert(ret->temp_subindex == 0); 1944466d3759SRichard Henderson for (i = 0; i < n; ++i) { 1945466d3759SRichard Henderson op->args[pi++] = temp_arg(ret + i); 1946466d3759SRichard Henderson } 194739004a71SRichard Henderson break; 194839004a71SRichard Henderson default: 194939004a71SRichard Henderson g_assert_not_reached(); 195039004a71SRichard Henderson } 19517319d83aSRichard Henderson 195239004a71SRichard Henderson TCGOP_CALLI(op) = n = info->nr_in; 195339004a71SRichard Henderson for (i = 0; i < n; i++) { 195439004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i]; 195539004a71SRichard Henderson TCGTemp *ts = args[loc->arg_idx] + loc->tmp_subindex; 195639004a71SRichard Henderson 195739004a71SRichard Henderson switch (loc->kind) { 195839004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 1959313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF: 1960313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF_N: 196139004a71SRichard Henderson op->args[pi++] = temp_arg(ts); 196239004a71SRichard Henderson break; 196339004a71SRichard Henderson 196439004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 196539004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 196639004a71SRichard Henderson { 19675dd48602SRichard Henderson TCGv_i64 temp = tcg_temp_ebb_new_i64(); 196839004a71SRichard Henderson TCGv_i32 orig = temp_tcgv_i32(ts); 196939004a71SRichard Henderson 197039004a71SRichard Henderson if (loc->kind == TCG_CALL_ARG_EXTEND_S) { 197118cf3d07SRichard Henderson tcg_gen_ext_i32_i64(temp, orig); 19722bece2c8SRichard Henderson } else { 197318cf3d07SRichard Henderson tcg_gen_extu_i32_i64(temp, orig); 19742bece2c8SRichard Henderson } 197539004a71SRichard Henderson op->args[pi++] = tcgv_i64_arg(temp); 197639004a71SRichard Henderson extend_free[n_extend++] = temp; 19772bece2c8SRichard Henderson } 197839004a71SRichard Henderson break; 19792bece2c8SRichard Henderson 1980e2a9dd6bSRichard Henderson default: 1981e2a9dd6bSRichard Henderson g_assert_not_reached(); 1982e2a9dd6bSRichard Henderson } 1983c896fe29Sbellard } 198475e8b9b7SRichard Henderson op->args[pi++] = (uintptr_t)func; 19853e92aa34SRichard Henderson op->args[pi++] = (uintptr_t)info; 198639004a71SRichard Henderson tcg_debug_assert(pi == total_args); 1987a7812ae4Spbrook 198839004a71SRichard Henderson QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link); 19892bece2c8SRichard Henderson 199039004a71SRichard Henderson tcg_debug_assert(n_extend < ARRAY_SIZE(extend_free)); 199139004a71SRichard Henderson for (i = 0; i < n_extend; ++i) { 199239004a71SRichard Henderson tcg_temp_free_i64(extend_free[i]); 1993eb8b0224SRichard Henderson } 1994a7812ae4Spbrook } 1995c896fe29Sbellard 19968fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s) 1997c896fe29Sbellard { 1998ac3b8891SRichard Henderson int i, n; 1999ac3b8891SRichard Henderson 2000ee17db83SRichard Henderson for (i = 0, n = s->nb_temps; i < n; i++) { 2001ee17db83SRichard Henderson TCGTemp *ts = &s->temps[i]; 2002ee17db83SRichard Henderson TCGTempVal val = TEMP_VAL_MEM; 2003ee17db83SRichard Henderson 2004ee17db83SRichard Henderson switch (ts->kind) { 2005c0522136SRichard Henderson case TEMP_CONST: 2006c0522136SRichard Henderson val = TEMP_VAL_CONST; 2007c0522136SRichard Henderson break; 2008ee17db83SRichard Henderson case TEMP_FIXED: 2009ee17db83SRichard Henderson val = TEMP_VAL_REG; 2010ee17db83SRichard Henderson break; 2011ee17db83SRichard Henderson case TEMP_GLOBAL: 2012ee17db83SRichard Henderson break; 2013c7482438SRichard Henderson case TEMP_EBB: 2014ee17db83SRichard Henderson val = TEMP_VAL_DEAD; 2015ee17db83SRichard Henderson /* fall through */ 2016f57c6915SRichard Henderson case TEMP_TB: 2017e8996ee0Sbellard ts->mem_allocated = 0; 2018ee17db83SRichard Henderson break; 2019ee17db83SRichard Henderson default: 2020ee17db83SRichard Henderson g_assert_not_reached(); 2021ee17db83SRichard Henderson } 2022ee17db83SRichard Henderson ts->val_type = val; 2023e8996ee0Sbellard } 2024f8b2f202SRichard Henderson 2025f8b2f202SRichard Henderson memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp)); 2026c896fe29Sbellard } 2027c896fe29Sbellard 2028f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size, 2029f8b2f202SRichard Henderson TCGTemp *ts) 2030c896fe29Sbellard { 20311807f4c4SRichard Henderson int idx = temp_idx(ts); 2032ac56dd48Spbrook 2033ee17db83SRichard Henderson switch (ts->kind) { 2034ee17db83SRichard Henderson case TEMP_FIXED: 2035ee17db83SRichard Henderson case TEMP_GLOBAL: 2036ac56dd48Spbrook pstrcpy(buf, buf_size, ts->name); 2037ee17db83SRichard Henderson break; 2038f57c6915SRichard Henderson case TEMP_TB: 2039641d5fbeSbellard snprintf(buf, buf_size, "loc%d", idx - s->nb_globals); 2040ee17db83SRichard Henderson break; 2041c7482438SRichard Henderson case TEMP_EBB: 2042ac56dd48Spbrook snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals); 2043ee17db83SRichard Henderson break; 2044c0522136SRichard Henderson case TEMP_CONST: 2045c0522136SRichard Henderson switch (ts->type) { 2046c0522136SRichard Henderson case TCG_TYPE_I32: 2047c0522136SRichard Henderson snprintf(buf, buf_size, "$0x%x", (int32_t)ts->val); 2048c0522136SRichard Henderson break; 2049c0522136SRichard Henderson #if TCG_TARGET_REG_BITS > 32 2050c0522136SRichard Henderson case TCG_TYPE_I64: 2051c0522136SRichard Henderson snprintf(buf, buf_size, "$0x%" PRIx64, ts->val); 2052c0522136SRichard Henderson break; 2053c0522136SRichard Henderson #endif 2054c0522136SRichard Henderson case TCG_TYPE_V64: 2055c0522136SRichard Henderson case TCG_TYPE_V128: 2056c0522136SRichard Henderson case TCG_TYPE_V256: 2057c0522136SRichard Henderson snprintf(buf, buf_size, "v%d$0x%" PRIx64, 2058c0522136SRichard Henderson 64 << (ts->type - TCG_TYPE_V64), ts->val); 2059c0522136SRichard Henderson break; 2060c0522136SRichard Henderson default: 2061c0522136SRichard Henderson g_assert_not_reached(); 2062c0522136SRichard Henderson } 2063c0522136SRichard Henderson break; 2064c896fe29Sbellard } 2065c896fe29Sbellard return buf; 2066c896fe29Sbellard } 2067c896fe29Sbellard 206843439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf, 206943439139SRichard Henderson int buf_size, TCGArg arg) 2070f8b2f202SRichard Henderson { 207143439139SRichard Henderson return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg)); 2072f8b2f202SRichard Henderson } 2073f8b2f202SRichard Henderson 2074f48f3edeSblueswir1 static const char * const cond_name[] = 2075f48f3edeSblueswir1 { 20760aed257fSRichard Henderson [TCG_COND_NEVER] = "never", 20770aed257fSRichard Henderson [TCG_COND_ALWAYS] = "always", 2078f48f3edeSblueswir1 [TCG_COND_EQ] = "eq", 2079f48f3edeSblueswir1 [TCG_COND_NE] = "ne", 2080f48f3edeSblueswir1 [TCG_COND_LT] = "lt", 2081f48f3edeSblueswir1 [TCG_COND_GE] = "ge", 2082f48f3edeSblueswir1 [TCG_COND_LE] = "le", 2083f48f3edeSblueswir1 [TCG_COND_GT] = "gt", 2084f48f3edeSblueswir1 [TCG_COND_LTU] = "ltu", 2085f48f3edeSblueswir1 [TCG_COND_GEU] = "geu", 2086f48f3edeSblueswir1 [TCG_COND_LEU] = "leu", 2087f48f3edeSblueswir1 [TCG_COND_GTU] = "gtu" 2088f48f3edeSblueswir1 }; 2089f48f3edeSblueswir1 2090f713d6adSRichard Henderson static const char * const ldst_name[] = 2091f713d6adSRichard Henderson { 2092f713d6adSRichard Henderson [MO_UB] = "ub", 2093f713d6adSRichard Henderson [MO_SB] = "sb", 2094f713d6adSRichard Henderson [MO_LEUW] = "leuw", 2095f713d6adSRichard Henderson [MO_LESW] = "lesw", 2096f713d6adSRichard Henderson [MO_LEUL] = "leul", 2097f713d6adSRichard Henderson [MO_LESL] = "lesl", 2098fc313c64SFrédéric Pétrot [MO_LEUQ] = "leq", 2099f713d6adSRichard Henderson [MO_BEUW] = "beuw", 2100f713d6adSRichard Henderson [MO_BESW] = "besw", 2101f713d6adSRichard Henderson [MO_BEUL] = "beul", 2102f713d6adSRichard Henderson [MO_BESL] = "besl", 2103fc313c64SFrédéric Pétrot [MO_BEUQ] = "beq", 2104f713d6adSRichard Henderson }; 2105f713d6adSRichard Henderson 21061f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = { 210752bf9771Stony.nguyen@bt.com #ifdef TARGET_ALIGNED_ONLY 21081f00b27fSSergey Sorokin [MO_UNALN >> MO_ASHIFT] = "un+", 21091f00b27fSSergey Sorokin [MO_ALIGN >> MO_ASHIFT] = "", 21101f00b27fSSergey Sorokin #else 21111f00b27fSSergey Sorokin [MO_UNALN >> MO_ASHIFT] = "", 21121f00b27fSSergey Sorokin [MO_ALIGN >> MO_ASHIFT] = "al+", 21131f00b27fSSergey Sorokin #endif 21141f00b27fSSergey Sorokin [MO_ALIGN_2 >> MO_ASHIFT] = "al2+", 21151f00b27fSSergey Sorokin [MO_ALIGN_4 >> MO_ASHIFT] = "al4+", 21161f00b27fSSergey Sorokin [MO_ALIGN_8 >> MO_ASHIFT] = "al8+", 21171f00b27fSSergey Sorokin [MO_ALIGN_16 >> MO_ASHIFT] = "al16+", 21181f00b27fSSergey Sorokin [MO_ALIGN_32 >> MO_ASHIFT] = "al32+", 21191f00b27fSSergey Sorokin [MO_ALIGN_64 >> MO_ASHIFT] = "al64+", 21201f00b27fSSergey Sorokin }; 21211f00b27fSSergey Sorokin 2122587195bdSRichard Henderson static const char bswap_flag_name[][6] = { 2123587195bdSRichard Henderson [TCG_BSWAP_IZ] = "iz", 2124587195bdSRichard Henderson [TCG_BSWAP_OZ] = "oz", 2125587195bdSRichard Henderson [TCG_BSWAP_OS] = "os", 2126587195bdSRichard Henderson [TCG_BSWAP_IZ | TCG_BSWAP_OZ] = "iz,oz", 2127587195bdSRichard Henderson [TCG_BSWAP_IZ | TCG_BSWAP_OS] = "iz,os", 2128587195bdSRichard Henderson }; 2129587195bdSRichard Henderson 2130b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d) 2131b016486eSRichard Henderson { 2132b016486eSRichard Henderson return (d & (d - 1)) == 0; 2133b016486eSRichard Henderson } 2134b016486eSRichard Henderson 2135b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d) 2136b016486eSRichard Henderson { 2137b016486eSRichard Henderson if (TCG_TARGET_NB_REGS <= 32) { 2138b016486eSRichard Henderson return ctz32(d); 2139b016486eSRichard Henderson } else { 2140b016486eSRichard Henderson return ctz64(d); 2141b016486eSRichard Henderson } 2142b016486eSRichard Henderson } 2143b016486eSRichard Henderson 2144b7a83ff8SRichard Henderson /* Return only the number of characters output -- no error return. */ 2145b7a83ff8SRichard Henderson #define ne_fprintf(...) \ 2146b7a83ff8SRichard Henderson ({ int ret_ = fprintf(__VA_ARGS__); ret_ >= 0 ? ret_ : 0; }) 2147b7a83ff8SRichard Henderson 2148b7a83ff8SRichard Henderson static void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs) 2149c896fe29Sbellard { 2150c896fe29Sbellard char buf[128]; 2151c45cb8bbSRichard Henderson TCGOp *op; 2152c896fe29Sbellard 215315fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 2154c45cb8bbSRichard Henderson int i, k, nb_oargs, nb_iargs, nb_cargs; 2155c45cb8bbSRichard Henderson const TCGOpDef *def; 2156c45cb8bbSRichard Henderson TCGOpcode c; 2157bdfb460eSRichard Henderson int col = 0; 2158c45cb8bbSRichard Henderson 2159c45cb8bbSRichard Henderson c = op->opc; 2160c896fe29Sbellard def = &tcg_op_defs[c]; 2161c45cb8bbSRichard Henderson 2162765b842aSRichard Henderson if (c == INDEX_op_insn_start) { 2163b016486eSRichard Henderson nb_oargs = 0; 2164b7a83ff8SRichard Henderson col += ne_fprintf(f, "\n ----"); 21659aef40edSRichard Henderson 21669aef40edSRichard Henderson for (i = 0; i < TARGET_INSN_START_WORDS; ++i) { 21679aef40edSRichard Henderson target_ulong a; 21687e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS 2169efee3746SRichard Henderson a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]); 21707e4597d7Sbellard #else 2171efee3746SRichard Henderson a = op->args[i]; 21727e4597d7Sbellard #endif 2173b7a83ff8SRichard Henderson col += ne_fprintf(f, " " TARGET_FMT_lx, a); 2174eeacee4dSBlue Swirl } 21757e4597d7Sbellard } else if (c == INDEX_op_call) { 21763e92aa34SRichard Henderson const TCGHelperInfo *info = tcg_call_info(op); 2177fa52e660SRichard Henderson void *func = tcg_call_func(op); 21783e92aa34SRichard Henderson 2179c896fe29Sbellard /* variable number of arguments */ 2180cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 2181cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 2182c896fe29Sbellard nb_cargs = def->nb_cargs; 2183b03cce8eSbellard 2184b7a83ff8SRichard Henderson col += ne_fprintf(f, " %s ", def->name); 21853e92aa34SRichard Henderson 21863e92aa34SRichard Henderson /* 21873e92aa34SRichard Henderson * Print the function name from TCGHelperInfo, if available. 21883e92aa34SRichard Henderson * Note that plugins have a template function for the info, 21893e92aa34SRichard Henderson * but the actual function pointer comes from the plugin. 21903e92aa34SRichard Henderson */ 21913e92aa34SRichard Henderson if (func == info->func) { 2192b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s", info->name); 21933e92aa34SRichard Henderson } else { 2194b7a83ff8SRichard Henderson col += ne_fprintf(f, "plugin(%p)", func); 21953e92aa34SRichard Henderson } 21963e92aa34SRichard Henderson 2197b7a83ff8SRichard Henderson col += ne_fprintf(f, ",$0x%x,$%d", info->flags, nb_oargs); 2198b03cce8eSbellard for (i = 0; i < nb_oargs; i++) { 2199b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", tcg_get_arg_str(s, buf, sizeof(buf), 2200efee3746SRichard Henderson op->args[i])); 2201b03cce8eSbellard } 2202cf066674SRichard Henderson for (i = 0; i < nb_iargs; i++) { 2203efee3746SRichard Henderson TCGArg arg = op->args[nb_oargs + i]; 220439004a71SRichard Henderson const char *t = tcg_get_arg_str(s, buf, sizeof(buf), arg); 2205b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", t); 2206e8996ee0Sbellard } 2207b03cce8eSbellard } else { 2208b7a83ff8SRichard Henderson col += ne_fprintf(f, " %s ", def->name); 2209c45cb8bbSRichard Henderson 2210c896fe29Sbellard nb_oargs = def->nb_oargs; 2211c896fe29Sbellard nb_iargs = def->nb_iargs; 2212c896fe29Sbellard nb_cargs = def->nb_cargs; 2213c896fe29Sbellard 2214d2fd745fSRichard Henderson if (def->flags & TCG_OPF_VECTOR) { 2215b7a83ff8SRichard Henderson col += ne_fprintf(f, "v%d,e%d,", 64 << TCGOP_VECL(op), 2216d2fd745fSRichard Henderson 8 << TCGOP_VECE(op)); 2217d2fd745fSRichard Henderson } 2218d2fd745fSRichard Henderson 2219c896fe29Sbellard k = 0; 2220c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 2221b7a83ff8SRichard Henderson const char *sep = k ? "," : ""; 2222b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s%s", sep, 2223b7a83ff8SRichard Henderson tcg_get_arg_str(s, buf, sizeof(buf), 2224efee3746SRichard Henderson op->args[k++])); 2225c896fe29Sbellard } 2226c896fe29Sbellard for (i = 0; i < nb_iargs; i++) { 2227b7a83ff8SRichard Henderson const char *sep = k ? "," : ""; 2228b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s%s", sep, 2229b7a83ff8SRichard Henderson tcg_get_arg_str(s, buf, sizeof(buf), 2230efee3746SRichard Henderson op->args[k++])); 2231c896fe29Sbellard } 2232be210acbSRichard Henderson switch (c) { 2233be210acbSRichard Henderson case INDEX_op_brcond_i32: 2234ffc5ea09SRichard Henderson case INDEX_op_setcond_i32: 2235ffc5ea09SRichard Henderson case INDEX_op_movcond_i32: 2236be210acbSRichard Henderson case INDEX_op_brcond2_i32: 2237be210acbSRichard Henderson case INDEX_op_setcond2_i32: 2238ffc5ea09SRichard Henderson case INDEX_op_brcond_i64: 2239be210acbSRichard Henderson case INDEX_op_setcond_i64: 2240ffc5ea09SRichard Henderson case INDEX_op_movcond_i64: 2241212be173SRichard Henderson case INDEX_op_cmp_vec: 2242f75da298SRichard Henderson case INDEX_op_cmpsel_vec: 2243efee3746SRichard Henderson if (op->args[k] < ARRAY_SIZE(cond_name) 2244efee3746SRichard Henderson && cond_name[op->args[k]]) { 2245b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", cond_name[op->args[k++]]); 2246eeacee4dSBlue Swirl } else { 2247b7a83ff8SRichard Henderson col += ne_fprintf(f, ",$0x%" TCG_PRIlx, op->args[k++]); 2248eeacee4dSBlue Swirl } 2249f48f3edeSblueswir1 i = 1; 2250be210acbSRichard Henderson break; 2251f713d6adSRichard Henderson case INDEX_op_qemu_ld_i32: 2252f713d6adSRichard Henderson case INDEX_op_qemu_st_i32: 225307ce0b05SRichard Henderson case INDEX_op_qemu_st8_i32: 2254f713d6adSRichard Henderson case INDEX_op_qemu_ld_i64: 2255f713d6adSRichard Henderson case INDEX_op_qemu_st_i64: 225659227d5dSRichard Henderson { 22579002ffcbSRichard Henderson MemOpIdx oi = op->args[k++]; 225814776ab5STony Nguyen MemOp op = get_memop(oi); 225959227d5dSRichard Henderson unsigned ix = get_mmuidx(oi); 226059227d5dSRichard Henderson 226159c4b7e8SRichard Henderson if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) { 2262b7a83ff8SRichard Henderson col += ne_fprintf(f, ",$0x%x,%u", op, ix); 226359c4b7e8SRichard Henderson } else { 22641f00b27fSSergey Sorokin const char *s_al, *s_op; 22651f00b27fSSergey Sorokin s_al = alignment_name[(op & MO_AMASK) >> MO_ASHIFT]; 226659c4b7e8SRichard Henderson s_op = ldst_name[op & (MO_BSWAP | MO_SSIZE)]; 2267b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s%s,%u", s_al, s_op, ix); 2268f713d6adSRichard Henderson } 2269f713d6adSRichard Henderson i = 1; 227059227d5dSRichard Henderson } 2271f713d6adSRichard Henderson break; 2272587195bdSRichard Henderson case INDEX_op_bswap16_i32: 2273587195bdSRichard Henderson case INDEX_op_bswap16_i64: 2274587195bdSRichard Henderson case INDEX_op_bswap32_i32: 2275587195bdSRichard Henderson case INDEX_op_bswap32_i64: 2276587195bdSRichard Henderson case INDEX_op_bswap64_i64: 2277587195bdSRichard Henderson { 2278587195bdSRichard Henderson TCGArg flags = op->args[k]; 2279587195bdSRichard Henderson const char *name = NULL; 2280587195bdSRichard Henderson 2281587195bdSRichard Henderson if (flags < ARRAY_SIZE(bswap_flag_name)) { 2282587195bdSRichard Henderson name = bswap_flag_name[flags]; 2283587195bdSRichard Henderson } 2284587195bdSRichard Henderson if (name) { 2285b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", name); 2286587195bdSRichard Henderson } else { 2287b7a83ff8SRichard Henderson col += ne_fprintf(f, ",$0x%" TCG_PRIlx, flags); 2288587195bdSRichard Henderson } 2289587195bdSRichard Henderson i = k = 1; 2290587195bdSRichard Henderson } 2291587195bdSRichard Henderson break; 2292be210acbSRichard Henderson default: 2293f48f3edeSblueswir1 i = 0; 2294be210acbSRichard Henderson break; 2295be210acbSRichard Henderson } 229651e3972cSRichard Henderson switch (c) { 229751e3972cSRichard Henderson case INDEX_op_set_label: 229851e3972cSRichard Henderson case INDEX_op_br: 229951e3972cSRichard Henderson case INDEX_op_brcond_i32: 230051e3972cSRichard Henderson case INDEX_op_brcond_i64: 230151e3972cSRichard Henderson case INDEX_op_brcond2_i32: 2302b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s$L%d", k ? "," : "", 2303efee3746SRichard Henderson arg_label(op->args[k])->id); 230451e3972cSRichard Henderson i++, k++; 230551e3972cSRichard Henderson break; 23063470867bSRichard Henderson case INDEX_op_mb: 23073470867bSRichard Henderson { 23083470867bSRichard Henderson TCGBar membar = op->args[k]; 23093470867bSRichard Henderson const char *b_op, *m_op; 23103470867bSRichard Henderson 23113470867bSRichard Henderson switch (membar & TCG_BAR_SC) { 23123470867bSRichard Henderson case 0: 23133470867bSRichard Henderson b_op = "none"; 23143470867bSRichard Henderson break; 23153470867bSRichard Henderson case TCG_BAR_LDAQ: 23163470867bSRichard Henderson b_op = "acq"; 23173470867bSRichard Henderson break; 23183470867bSRichard Henderson case TCG_BAR_STRL: 23193470867bSRichard Henderson b_op = "rel"; 23203470867bSRichard Henderson break; 23213470867bSRichard Henderson case TCG_BAR_SC: 23223470867bSRichard Henderson b_op = "seq"; 23233470867bSRichard Henderson break; 23243470867bSRichard Henderson default: 23253470867bSRichard Henderson g_assert_not_reached(); 23263470867bSRichard Henderson } 23273470867bSRichard Henderson 23283470867bSRichard Henderson switch (membar & TCG_MO_ALL) { 23293470867bSRichard Henderson case 0: 23303470867bSRichard Henderson m_op = "none"; 23313470867bSRichard Henderson break; 23323470867bSRichard Henderson case TCG_MO_LD_LD: 23333470867bSRichard Henderson m_op = "rr"; 23343470867bSRichard Henderson break; 23353470867bSRichard Henderson case TCG_MO_LD_ST: 23363470867bSRichard Henderson m_op = "rw"; 23373470867bSRichard Henderson break; 23383470867bSRichard Henderson case TCG_MO_ST_LD: 23393470867bSRichard Henderson m_op = "wr"; 23403470867bSRichard Henderson break; 23413470867bSRichard Henderson case TCG_MO_ST_ST: 23423470867bSRichard Henderson m_op = "ww"; 23433470867bSRichard Henderson break; 23443470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_LD_ST: 23453470867bSRichard Henderson m_op = "rr+rw"; 23463470867bSRichard Henderson break; 23473470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_ST_LD: 23483470867bSRichard Henderson m_op = "rr+wr"; 23493470867bSRichard Henderson break; 23503470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_ST_ST: 23513470867bSRichard Henderson m_op = "rr+ww"; 23523470867bSRichard Henderson break; 23533470867bSRichard Henderson case TCG_MO_LD_ST | TCG_MO_ST_LD: 23543470867bSRichard Henderson m_op = "rw+wr"; 23553470867bSRichard Henderson break; 23563470867bSRichard Henderson case TCG_MO_LD_ST | TCG_MO_ST_ST: 23573470867bSRichard Henderson m_op = "rw+ww"; 23583470867bSRichard Henderson break; 23593470867bSRichard Henderson case TCG_MO_ST_LD | TCG_MO_ST_ST: 23603470867bSRichard Henderson m_op = "wr+ww"; 23613470867bSRichard Henderson break; 23623470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_MO_ST_LD: 23633470867bSRichard Henderson m_op = "rr+rw+wr"; 23643470867bSRichard Henderson break; 23653470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_MO_ST_ST: 23663470867bSRichard Henderson m_op = "rr+rw+ww"; 23673470867bSRichard Henderson break; 23683470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_ST_LD | TCG_MO_ST_ST: 23693470867bSRichard Henderson m_op = "rr+wr+ww"; 23703470867bSRichard Henderson break; 23713470867bSRichard Henderson case TCG_MO_LD_ST | TCG_MO_ST_LD | TCG_MO_ST_ST: 23723470867bSRichard Henderson m_op = "rw+wr+ww"; 23733470867bSRichard Henderson break; 23743470867bSRichard Henderson case TCG_MO_ALL: 23753470867bSRichard Henderson m_op = "all"; 23763470867bSRichard Henderson break; 23773470867bSRichard Henderson default: 23783470867bSRichard Henderson g_assert_not_reached(); 23793470867bSRichard Henderson } 23803470867bSRichard Henderson 23813470867bSRichard Henderson col += ne_fprintf(f, "%s%s:%s", (k ? "," : ""), b_op, m_op); 23823470867bSRichard Henderson i++, k++; 23833470867bSRichard Henderson } 23843470867bSRichard Henderson break; 238551e3972cSRichard Henderson default: 238651e3972cSRichard Henderson break; 2387eeacee4dSBlue Swirl } 238851e3972cSRichard Henderson for (; i < nb_cargs; i++, k++) { 2389b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s$0x%" TCG_PRIlx, k ? "," : "", 2390b7a83ff8SRichard Henderson op->args[k]); 2391bdfb460eSRichard Henderson } 2392bdfb460eSRichard Henderson } 2393bdfb460eSRichard Henderson 23941894f69aSRichard Henderson if (have_prefs || op->life) { 23951894f69aSRichard Henderson for (; col < 40; ++col) { 2396b7a83ff8SRichard Henderson putc(' ', f); 2397bdfb460eSRichard Henderson } 23981894f69aSRichard Henderson } 23991894f69aSRichard Henderson 24001894f69aSRichard Henderson if (op->life) { 24011894f69aSRichard Henderson unsigned life = op->life; 2402bdfb460eSRichard Henderson 2403bdfb460eSRichard Henderson if (life & (SYNC_ARG * 3)) { 2404b7a83ff8SRichard Henderson ne_fprintf(f, " sync:"); 2405bdfb460eSRichard Henderson for (i = 0; i < 2; ++i) { 2406bdfb460eSRichard Henderson if (life & (SYNC_ARG << i)) { 2407b7a83ff8SRichard Henderson ne_fprintf(f, " %d", i); 2408bdfb460eSRichard Henderson } 2409bdfb460eSRichard Henderson } 2410bdfb460eSRichard Henderson } 2411bdfb460eSRichard Henderson life /= DEAD_ARG; 2412bdfb460eSRichard Henderson if (life) { 2413b7a83ff8SRichard Henderson ne_fprintf(f, " dead:"); 2414bdfb460eSRichard Henderson for (i = 0; life; ++i, life >>= 1) { 2415bdfb460eSRichard Henderson if (life & 1) { 2416b7a83ff8SRichard Henderson ne_fprintf(f, " %d", i); 2417bdfb460eSRichard Henderson } 2418bdfb460eSRichard Henderson } 2419c896fe29Sbellard } 2420b03cce8eSbellard } 24211894f69aSRichard Henderson 24221894f69aSRichard Henderson if (have_prefs) { 24231894f69aSRichard Henderson for (i = 0; i < nb_oargs; ++i) { 242431fd884bSRichard Henderson TCGRegSet set = output_pref(op, i); 24251894f69aSRichard Henderson 24261894f69aSRichard Henderson if (i == 0) { 2427b7a83ff8SRichard Henderson ne_fprintf(f, " pref="); 24281894f69aSRichard Henderson } else { 2429b7a83ff8SRichard Henderson ne_fprintf(f, ","); 24301894f69aSRichard Henderson } 24311894f69aSRichard Henderson if (set == 0) { 2432b7a83ff8SRichard Henderson ne_fprintf(f, "none"); 24331894f69aSRichard Henderson } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) { 2434b7a83ff8SRichard Henderson ne_fprintf(f, "all"); 24351894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG 24361894f69aSRichard Henderson } else if (tcg_regset_single(set)) { 24371894f69aSRichard Henderson TCGReg reg = tcg_regset_first(set); 2438b7a83ff8SRichard Henderson ne_fprintf(f, "%s", tcg_target_reg_names[reg]); 24391894f69aSRichard Henderson #endif 24401894f69aSRichard Henderson } else if (TCG_TARGET_NB_REGS <= 32) { 2441b7a83ff8SRichard Henderson ne_fprintf(f, "0x%x", (uint32_t)set); 24421894f69aSRichard Henderson } else { 2443b7a83ff8SRichard Henderson ne_fprintf(f, "0x%" PRIx64, (uint64_t)set); 24441894f69aSRichard Henderson } 24451894f69aSRichard Henderson } 24461894f69aSRichard Henderson } 24471894f69aSRichard Henderson 2448b7a83ff8SRichard Henderson putc('\n', f); 2449c896fe29Sbellard } 2450c896fe29Sbellard } 2451c896fe29Sbellard 2452c896fe29Sbellard /* we give more priority to constraints with less registers */ 2453c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k) 2454c896fe29Sbellard { 245574a11790SRichard Henderson const TCGArgConstraint *arg_ct = &def->args_ct[k]; 245629f5e925SRichard Henderson int n = ctpop64(arg_ct->regs); 2457c896fe29Sbellard 245829f5e925SRichard Henderson /* 245929f5e925SRichard Henderson * Sort constraints of a single register first, which includes output 246029f5e925SRichard Henderson * aliases (which must exactly match the input already allocated). 246129f5e925SRichard Henderson */ 246229f5e925SRichard Henderson if (n == 1 || arg_ct->oalias) { 246329f5e925SRichard Henderson return INT_MAX; 2464c896fe29Sbellard } 246529f5e925SRichard Henderson 246629f5e925SRichard Henderson /* 246729f5e925SRichard Henderson * Sort register pairs next, first then second immediately after. 246829f5e925SRichard Henderson * Arbitrarily sort multiple pairs by the index of the first reg; 246929f5e925SRichard Henderson * there shouldn't be many pairs. 247029f5e925SRichard Henderson */ 247129f5e925SRichard Henderson switch (arg_ct->pair) { 247229f5e925SRichard Henderson case 1: 247329f5e925SRichard Henderson case 3: 247429f5e925SRichard Henderson return (k + 1) * 2; 247529f5e925SRichard Henderson case 2: 247629f5e925SRichard Henderson return (arg_ct->pair_index + 1) * 2 - 1; 247729f5e925SRichard Henderson } 247829f5e925SRichard Henderson 247929f5e925SRichard Henderson /* Finally, sort by decreasing register count. */ 248029f5e925SRichard Henderson assert(n > 1); 248129f5e925SRichard Henderson return -n; 2482c896fe29Sbellard } 2483c896fe29Sbellard 2484c896fe29Sbellard /* sort from highest priority to lowest */ 2485c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n) 2486c896fe29Sbellard { 248766792f90SRichard Henderson int i, j; 248866792f90SRichard Henderson TCGArgConstraint *a = def->args_ct; 2489c896fe29Sbellard 249066792f90SRichard Henderson for (i = 0; i < n; i++) { 249166792f90SRichard Henderson a[start + i].sort_index = start + i; 249266792f90SRichard Henderson } 249366792f90SRichard Henderson if (n <= 1) { 2494c896fe29Sbellard return; 249566792f90SRichard Henderson } 2496c896fe29Sbellard for (i = 0; i < n - 1; i++) { 2497c896fe29Sbellard for (j = i + 1; j < n; j++) { 249866792f90SRichard Henderson int p1 = get_constraint_priority(def, a[start + i].sort_index); 249966792f90SRichard Henderson int p2 = get_constraint_priority(def, a[start + j].sort_index); 2500c896fe29Sbellard if (p1 < p2) { 250166792f90SRichard Henderson int tmp = a[start + i].sort_index; 250266792f90SRichard Henderson a[start + i].sort_index = a[start + j].sort_index; 250366792f90SRichard Henderson a[start + j].sort_index = tmp; 2504c896fe29Sbellard } 2505c896fe29Sbellard } 2506c896fe29Sbellard } 2507c896fe29Sbellard } 2508c896fe29Sbellard 2509f69d277eSRichard Henderson static void process_op_defs(TCGContext *s) 2510c896fe29Sbellard { 2511a9751609SRichard Henderson TCGOpcode op; 2512c896fe29Sbellard 2513f69d277eSRichard Henderson for (op = 0; op < NB_OPS; op++) { 2514f69d277eSRichard Henderson TCGOpDef *def = &tcg_op_defs[op]; 2515f69d277eSRichard Henderson const TCGTargetOpDef *tdefs; 251629f5e925SRichard Henderson bool saw_alias_pair = false; 251729f5e925SRichard Henderson int i, o, i2, o2, nb_args; 2518f69d277eSRichard Henderson 2519f69d277eSRichard Henderson if (def->flags & TCG_OPF_NOT_PRESENT) { 2520f69d277eSRichard Henderson continue; 2521f69d277eSRichard Henderson } 2522f69d277eSRichard Henderson 2523c896fe29Sbellard nb_args = def->nb_iargs + def->nb_oargs; 2524f69d277eSRichard Henderson if (nb_args == 0) { 2525f69d277eSRichard Henderson continue; 2526f69d277eSRichard Henderson } 2527f69d277eSRichard Henderson 25284c22e840SRichard Henderson /* 25294c22e840SRichard Henderson * Macro magic should make it impossible, but double-check that 25304c22e840SRichard Henderson * the array index is in range. Since the signness of an enum 25314c22e840SRichard Henderson * is implementation defined, force the result to unsigned. 25324c22e840SRichard Henderson */ 25334c22e840SRichard Henderson unsigned con_set = tcg_target_op_def(op); 25344c22e840SRichard Henderson tcg_debug_assert(con_set < ARRAY_SIZE(constraint_sets)); 25354c22e840SRichard Henderson tdefs = &constraint_sets[con_set]; 2536f69d277eSRichard Henderson 2537c896fe29Sbellard for (i = 0; i < nb_args; i++) { 2538f69d277eSRichard Henderson const char *ct_str = tdefs->args_ct_str[i]; 25398940ea0dSPhilippe Mathieu-Daudé bool input_p = i >= def->nb_oargs; 25408940ea0dSPhilippe Mathieu-Daudé 2541f69d277eSRichard Henderson /* Incomplete TCGTargetOpDef entry. */ 2542eabb7b91SAurelien Jarno tcg_debug_assert(ct_str != NULL); 2543f69d277eSRichard Henderson 254417280ff4SRichard Henderson switch (*ct_str) { 254517280ff4SRichard Henderson case '0' ... '9': 25468940ea0dSPhilippe Mathieu-Daudé o = *ct_str - '0'; 25478940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(input_p); 25488940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(o < def->nb_oargs); 25498940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(def->args_ct[o].regs != 0); 25508940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(!def->args_ct[o].oalias); 25518940ea0dSPhilippe Mathieu-Daudé def->args_ct[i] = def->args_ct[o]; 2552bc2b17e6SRichard Henderson /* The output sets oalias. */ 25538940ea0dSPhilippe Mathieu-Daudé def->args_ct[o].oalias = 1; 25548940ea0dSPhilippe Mathieu-Daudé def->args_ct[o].alias_index = i; 2555bc2b17e6SRichard Henderson /* The input sets ialias. */ 25568940ea0dSPhilippe Mathieu-Daudé def->args_ct[i].ialias = 1; 25578940ea0dSPhilippe Mathieu-Daudé def->args_ct[i].alias_index = o; 255829f5e925SRichard Henderson if (def->args_ct[i].pair) { 255929f5e925SRichard Henderson saw_alias_pair = true; 256029f5e925SRichard Henderson } 25618940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(ct_str[1] == '\0'); 25628940ea0dSPhilippe Mathieu-Daudé continue; 25638940ea0dSPhilippe Mathieu-Daudé 256482790a87SRichard Henderson case '&': 25658940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(!input_p); 2566bc2b17e6SRichard Henderson def->args_ct[i].newreg = true; 256782790a87SRichard Henderson ct_str++; 256882790a87SRichard Henderson break; 256929f5e925SRichard Henderson 257029f5e925SRichard Henderson case 'p': /* plus */ 257129f5e925SRichard Henderson /* Allocate to the register after the previous. */ 257229f5e925SRichard Henderson tcg_debug_assert(i > (input_p ? def->nb_oargs : 0)); 257329f5e925SRichard Henderson o = i - 1; 257429f5e925SRichard Henderson tcg_debug_assert(!def->args_ct[o].pair); 257529f5e925SRichard Henderson tcg_debug_assert(!def->args_ct[o].ct); 257629f5e925SRichard Henderson def->args_ct[i] = (TCGArgConstraint){ 257729f5e925SRichard Henderson .pair = 2, 257829f5e925SRichard Henderson .pair_index = o, 257929f5e925SRichard Henderson .regs = def->args_ct[o].regs << 1, 258029f5e925SRichard Henderson }; 258129f5e925SRichard Henderson def->args_ct[o].pair = 1; 258229f5e925SRichard Henderson def->args_ct[o].pair_index = i; 258329f5e925SRichard Henderson tcg_debug_assert(ct_str[1] == '\0'); 258429f5e925SRichard Henderson continue; 258529f5e925SRichard Henderson 258629f5e925SRichard Henderson case 'm': /* minus */ 258729f5e925SRichard Henderson /* Allocate to the register before the previous. */ 258829f5e925SRichard Henderson tcg_debug_assert(i > (input_p ? def->nb_oargs : 0)); 258929f5e925SRichard Henderson o = i - 1; 259029f5e925SRichard Henderson tcg_debug_assert(!def->args_ct[o].pair); 259129f5e925SRichard Henderson tcg_debug_assert(!def->args_ct[o].ct); 259229f5e925SRichard Henderson def->args_ct[i] = (TCGArgConstraint){ 259329f5e925SRichard Henderson .pair = 1, 259429f5e925SRichard Henderson .pair_index = o, 259529f5e925SRichard Henderson .regs = def->args_ct[o].regs >> 1, 259629f5e925SRichard Henderson }; 259729f5e925SRichard Henderson def->args_ct[o].pair = 2; 259829f5e925SRichard Henderson def->args_ct[o].pair_index = i; 259929f5e925SRichard Henderson tcg_debug_assert(ct_str[1] == '\0'); 260029f5e925SRichard Henderson continue; 26018940ea0dSPhilippe Mathieu-Daudé } 26028940ea0dSPhilippe Mathieu-Daudé 26038940ea0dSPhilippe Mathieu-Daudé do { 26048940ea0dSPhilippe Mathieu-Daudé switch (*ct_str) { 2605c896fe29Sbellard case 'i': 2606c896fe29Sbellard def->args_ct[i].ct |= TCG_CT_CONST; 2607c896fe29Sbellard break; 2608358b4923SRichard Henderson 2609358b4923SRichard Henderson /* Include all of the target-specific constraints. */ 2610358b4923SRichard Henderson 2611358b4923SRichard Henderson #undef CONST 2612358b4923SRichard Henderson #define CONST(CASE, MASK) \ 26138940ea0dSPhilippe Mathieu-Daudé case CASE: def->args_ct[i].ct |= MASK; break; 2614358b4923SRichard Henderson #define REGS(CASE, MASK) \ 26158940ea0dSPhilippe Mathieu-Daudé case CASE: def->args_ct[i].regs |= MASK; break; 2616358b4923SRichard Henderson 2617358b4923SRichard Henderson #include "tcg-target-con-str.h" 2618358b4923SRichard Henderson 2619358b4923SRichard Henderson #undef REGS 2620358b4923SRichard Henderson #undef CONST 2621c896fe29Sbellard default: 26228940ea0dSPhilippe Mathieu-Daudé case '0' ... '9': 26238940ea0dSPhilippe Mathieu-Daudé case '&': 262429f5e925SRichard Henderson case 'p': 262529f5e925SRichard Henderson case 'm': 2626358b4923SRichard Henderson /* Typo in TCGTargetOpDef constraint. */ 2627358b4923SRichard Henderson g_assert_not_reached(); 2628358b4923SRichard Henderson } 26298940ea0dSPhilippe Mathieu-Daudé } while (*++ct_str != '\0'); 2630c896fe29Sbellard } 2631c896fe29Sbellard 2632c68aaa18SStefan Weil /* TCGTargetOpDef entry with too much information? */ 2633eabb7b91SAurelien Jarno tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL); 2634c68aaa18SStefan Weil 263529f5e925SRichard Henderson /* 263629f5e925SRichard Henderson * Fix up output pairs that are aliased with inputs. 263729f5e925SRichard Henderson * When we created the alias, we copied pair from the output. 263829f5e925SRichard Henderson * There are three cases: 263929f5e925SRichard Henderson * (1a) Pairs of inputs alias pairs of outputs. 264029f5e925SRichard Henderson * (1b) One input aliases the first of a pair of outputs. 264129f5e925SRichard Henderson * (2) One input aliases the second of a pair of outputs. 264229f5e925SRichard Henderson * 264329f5e925SRichard Henderson * Case 1a is handled by making sure that the pair_index'es are 264429f5e925SRichard Henderson * properly updated so that they appear the same as a pair of inputs. 264529f5e925SRichard Henderson * 264629f5e925SRichard Henderson * Case 1b is handled by setting the pair_index of the input to 264729f5e925SRichard Henderson * itself, simply so it doesn't point to an unrelated argument. 264829f5e925SRichard Henderson * Since we don't encounter the "second" during the input allocation 264929f5e925SRichard Henderson * phase, nothing happens with the second half of the input pair. 265029f5e925SRichard Henderson * 265129f5e925SRichard Henderson * Case 2 is handled by setting the second input to pair=3, the 265229f5e925SRichard Henderson * first output to pair=3, and the pair_index'es to match. 265329f5e925SRichard Henderson */ 265429f5e925SRichard Henderson if (saw_alias_pair) { 265529f5e925SRichard Henderson for (i = def->nb_oargs; i < nb_args; i++) { 265629f5e925SRichard Henderson /* 265729f5e925SRichard Henderson * Since [0-9pm] must be alone in the constraint string, 265829f5e925SRichard Henderson * the only way they can both be set is if the pair comes 265929f5e925SRichard Henderson * from the output alias. 266029f5e925SRichard Henderson */ 266129f5e925SRichard Henderson if (!def->args_ct[i].ialias) { 266229f5e925SRichard Henderson continue; 266329f5e925SRichard Henderson } 266429f5e925SRichard Henderson switch (def->args_ct[i].pair) { 266529f5e925SRichard Henderson case 0: 266629f5e925SRichard Henderson break; 266729f5e925SRichard Henderson case 1: 266829f5e925SRichard Henderson o = def->args_ct[i].alias_index; 266929f5e925SRichard Henderson o2 = def->args_ct[o].pair_index; 267029f5e925SRichard Henderson tcg_debug_assert(def->args_ct[o].pair == 1); 267129f5e925SRichard Henderson tcg_debug_assert(def->args_ct[o2].pair == 2); 267229f5e925SRichard Henderson if (def->args_ct[o2].oalias) { 267329f5e925SRichard Henderson /* Case 1a */ 267429f5e925SRichard Henderson i2 = def->args_ct[o2].alias_index; 267529f5e925SRichard Henderson tcg_debug_assert(def->args_ct[i2].pair == 2); 267629f5e925SRichard Henderson def->args_ct[i2].pair_index = i; 267729f5e925SRichard Henderson def->args_ct[i].pair_index = i2; 267829f5e925SRichard Henderson } else { 267929f5e925SRichard Henderson /* Case 1b */ 268029f5e925SRichard Henderson def->args_ct[i].pair_index = i; 268129f5e925SRichard Henderson } 268229f5e925SRichard Henderson break; 268329f5e925SRichard Henderson case 2: 268429f5e925SRichard Henderson o = def->args_ct[i].alias_index; 268529f5e925SRichard Henderson o2 = def->args_ct[o].pair_index; 268629f5e925SRichard Henderson tcg_debug_assert(def->args_ct[o].pair == 2); 268729f5e925SRichard Henderson tcg_debug_assert(def->args_ct[o2].pair == 1); 268829f5e925SRichard Henderson if (def->args_ct[o2].oalias) { 268929f5e925SRichard Henderson /* Case 1a */ 269029f5e925SRichard Henderson i2 = def->args_ct[o2].alias_index; 269129f5e925SRichard Henderson tcg_debug_assert(def->args_ct[i2].pair == 1); 269229f5e925SRichard Henderson def->args_ct[i2].pair_index = i; 269329f5e925SRichard Henderson def->args_ct[i].pair_index = i2; 269429f5e925SRichard Henderson } else { 269529f5e925SRichard Henderson /* Case 2 */ 269629f5e925SRichard Henderson def->args_ct[i].pair = 3; 269729f5e925SRichard Henderson def->args_ct[o2].pair = 3; 269829f5e925SRichard Henderson def->args_ct[i].pair_index = o2; 269929f5e925SRichard Henderson def->args_ct[o2].pair_index = i; 270029f5e925SRichard Henderson } 270129f5e925SRichard Henderson break; 270229f5e925SRichard Henderson default: 270329f5e925SRichard Henderson g_assert_not_reached(); 270429f5e925SRichard Henderson } 270529f5e925SRichard Henderson } 270629f5e925SRichard Henderson } 270729f5e925SRichard Henderson 2708c896fe29Sbellard /* sort the constraints (XXX: this is just an heuristic) */ 2709c896fe29Sbellard sort_constraints(def, 0, def->nb_oargs); 2710c896fe29Sbellard sort_constraints(def, def->nb_oargs, def->nb_iargs); 2711c896fe29Sbellard } 2712c896fe29Sbellard } 2713c896fe29Sbellard 2714f85b1fc4SRichard Henderson static void remove_label_use(TCGOp *op, int idx) 2715f85b1fc4SRichard Henderson { 2716f85b1fc4SRichard Henderson TCGLabel *label = arg_label(op->args[idx]); 2717f85b1fc4SRichard Henderson TCGLabelUse *use; 2718f85b1fc4SRichard Henderson 2719f85b1fc4SRichard Henderson QSIMPLEQ_FOREACH(use, &label->branches, next) { 2720f85b1fc4SRichard Henderson if (use->op == op) { 2721f85b1fc4SRichard Henderson QSIMPLEQ_REMOVE(&label->branches, use, TCGLabelUse, next); 2722f85b1fc4SRichard Henderson return; 2723f85b1fc4SRichard Henderson } 2724f85b1fc4SRichard Henderson } 2725f85b1fc4SRichard Henderson g_assert_not_reached(); 2726f85b1fc4SRichard Henderson } 2727f85b1fc4SRichard Henderson 27280c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op) 27290c627cdcSRichard Henderson { 2730d88a117eSRichard Henderson switch (op->opc) { 2731d88a117eSRichard Henderson case INDEX_op_br: 2732f85b1fc4SRichard Henderson remove_label_use(op, 0); 2733d88a117eSRichard Henderson break; 2734d88a117eSRichard Henderson case INDEX_op_brcond_i32: 2735d88a117eSRichard Henderson case INDEX_op_brcond_i64: 2736f85b1fc4SRichard Henderson remove_label_use(op, 3); 2737d88a117eSRichard Henderson break; 2738d88a117eSRichard Henderson case INDEX_op_brcond2_i32: 2739f85b1fc4SRichard Henderson remove_label_use(op, 5); 2740d88a117eSRichard Henderson break; 2741d88a117eSRichard Henderson default: 2742d88a117eSRichard Henderson break; 2743d88a117eSRichard Henderson } 2744d88a117eSRichard Henderson 274515fa08f8SRichard Henderson QTAILQ_REMOVE(&s->ops, op, link); 274615fa08f8SRichard Henderson QTAILQ_INSERT_TAIL(&s->free_ops, op, link); 2747abebf925SRichard Henderson s->nb_ops--; 27480c627cdcSRichard Henderson 27490c627cdcSRichard Henderson #ifdef CONFIG_PROFILER 2750d73415a3SStefan Hajnoczi qatomic_set(&s->prof.del_op_count, s->prof.del_op_count + 1); 27510c627cdcSRichard Henderson #endif 27520c627cdcSRichard Henderson } 27530c627cdcSRichard Henderson 2754a80cdd31SRichard Henderson void tcg_remove_ops_after(TCGOp *op) 2755a80cdd31SRichard Henderson { 2756a80cdd31SRichard Henderson TCGContext *s = tcg_ctx; 2757a80cdd31SRichard Henderson 2758a80cdd31SRichard Henderson while (true) { 2759a80cdd31SRichard Henderson TCGOp *last = tcg_last_op(); 2760a80cdd31SRichard Henderson if (last == op) { 2761a80cdd31SRichard Henderson return; 2762a80cdd31SRichard Henderson } 2763a80cdd31SRichard Henderson tcg_op_remove(s, last); 2764a80cdd31SRichard Henderson } 2765a80cdd31SRichard Henderson } 2766a80cdd31SRichard Henderson 2767d4478943SPhilippe Mathieu-Daudé static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs) 276815fa08f8SRichard Henderson { 276915fa08f8SRichard Henderson TCGContext *s = tcg_ctx; 2770cb10bc63SRichard Henderson TCGOp *op = NULL; 277115fa08f8SRichard Henderson 2772cb10bc63SRichard Henderson if (unlikely(!QTAILQ_EMPTY(&s->free_ops))) { 2773cb10bc63SRichard Henderson QTAILQ_FOREACH(op, &s->free_ops, link) { 2774cb10bc63SRichard Henderson if (nargs <= op->nargs) { 277515fa08f8SRichard Henderson QTAILQ_REMOVE(&s->free_ops, op, link); 2776cb10bc63SRichard Henderson nargs = op->nargs; 2777cb10bc63SRichard Henderson goto found; 277815fa08f8SRichard Henderson } 2779cb10bc63SRichard Henderson } 2780cb10bc63SRichard Henderson } 2781cb10bc63SRichard Henderson 2782cb10bc63SRichard Henderson /* Most opcodes have 3 or 4 operands: reduce fragmentation. */ 2783cb10bc63SRichard Henderson nargs = MAX(4, nargs); 2784cb10bc63SRichard Henderson op = tcg_malloc(sizeof(TCGOp) + sizeof(TCGArg) * nargs); 2785cb10bc63SRichard Henderson 2786cb10bc63SRichard Henderson found: 278715fa08f8SRichard Henderson memset(op, 0, offsetof(TCGOp, link)); 278815fa08f8SRichard Henderson op->opc = opc; 2789cb10bc63SRichard Henderson op->nargs = nargs; 279015fa08f8SRichard Henderson 2791cb10bc63SRichard Henderson /* Check for bitfield overflow. */ 2792cb10bc63SRichard Henderson tcg_debug_assert(op->nargs == nargs); 2793cb10bc63SRichard Henderson 2794cb10bc63SRichard Henderson s->nb_ops++; 279515fa08f8SRichard Henderson return op; 279615fa08f8SRichard Henderson } 279715fa08f8SRichard Henderson 2798d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_emit_op(TCGOpcode opc, unsigned nargs) 279915fa08f8SRichard Henderson { 2800d4478943SPhilippe Mathieu-Daudé TCGOp *op = tcg_op_alloc(opc, nargs); 280115fa08f8SRichard Henderson QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link); 280215fa08f8SRichard Henderson return op; 280315fa08f8SRichard Henderson } 280415fa08f8SRichard Henderson 2805d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op, 2806d4478943SPhilippe Mathieu-Daudé TCGOpcode opc, unsigned nargs) 28075a18407fSRichard Henderson { 2808d4478943SPhilippe Mathieu-Daudé TCGOp *new_op = tcg_op_alloc(opc, nargs); 280915fa08f8SRichard Henderson QTAILQ_INSERT_BEFORE(old_op, new_op, link); 28105a18407fSRichard Henderson return new_op; 28115a18407fSRichard Henderson } 28125a18407fSRichard Henderson 2813d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, 2814d4478943SPhilippe Mathieu-Daudé TCGOpcode opc, unsigned nargs) 28155a18407fSRichard Henderson { 2816d4478943SPhilippe Mathieu-Daudé TCGOp *new_op = tcg_op_alloc(opc, nargs); 281715fa08f8SRichard Henderson QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link); 28185a18407fSRichard Henderson return new_op; 28195a18407fSRichard Henderson } 28205a18407fSRichard Henderson 2821968f305eSRichard Henderson static void move_label_uses(TCGLabel *to, TCGLabel *from) 2822968f305eSRichard Henderson { 2823968f305eSRichard Henderson TCGLabelUse *u; 2824968f305eSRichard Henderson 2825968f305eSRichard Henderson QSIMPLEQ_FOREACH(u, &from->branches, next) { 2826968f305eSRichard Henderson TCGOp *op = u->op; 2827968f305eSRichard Henderson switch (op->opc) { 2828968f305eSRichard Henderson case INDEX_op_br: 2829968f305eSRichard Henderson op->args[0] = label_arg(to); 2830968f305eSRichard Henderson break; 2831968f305eSRichard Henderson case INDEX_op_brcond_i32: 2832968f305eSRichard Henderson case INDEX_op_brcond_i64: 2833968f305eSRichard Henderson op->args[3] = label_arg(to); 2834968f305eSRichard Henderson break; 2835968f305eSRichard Henderson case INDEX_op_brcond2_i32: 2836968f305eSRichard Henderson op->args[5] = label_arg(to); 2837968f305eSRichard Henderson break; 2838968f305eSRichard Henderson default: 2839968f305eSRichard Henderson g_assert_not_reached(); 2840968f305eSRichard Henderson } 2841968f305eSRichard Henderson } 2842968f305eSRichard Henderson 2843968f305eSRichard Henderson QSIMPLEQ_CONCAT(&to->branches, &from->branches); 2844968f305eSRichard Henderson } 2845968f305eSRichard Henderson 2846b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code. */ 28479bbee4c0SRichard Henderson static void __attribute__((noinline)) 28489bbee4c0SRichard Henderson reachable_code_pass(TCGContext *s) 2849b4fc67c7SRichard Henderson { 28504d89d0bbSRichard Henderson TCGOp *op, *op_next, *op_prev; 2851b4fc67c7SRichard Henderson bool dead = false; 2852b4fc67c7SRichard Henderson 2853b4fc67c7SRichard Henderson QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) { 2854b4fc67c7SRichard Henderson bool remove = dead; 2855b4fc67c7SRichard Henderson TCGLabel *label; 2856b4fc67c7SRichard Henderson 2857b4fc67c7SRichard Henderson switch (op->opc) { 2858b4fc67c7SRichard Henderson case INDEX_op_set_label: 2859b4fc67c7SRichard Henderson label = arg_label(op->args[0]); 28604d89d0bbSRichard Henderson 28614d89d0bbSRichard Henderson /* 2862968f305eSRichard Henderson * Note that the first op in the TB is always a load, 2863968f305eSRichard Henderson * so there is always something before a label. 2864968f305eSRichard Henderson */ 2865968f305eSRichard Henderson op_prev = QTAILQ_PREV(op, link); 2866968f305eSRichard Henderson 2867968f305eSRichard Henderson /* 2868968f305eSRichard Henderson * If we find two sequential labels, move all branches to 2869968f305eSRichard Henderson * reference the second label and remove the first label. 2870968f305eSRichard Henderson * Do this before branch to next optimization, so that the 2871968f305eSRichard Henderson * middle label is out of the way. 2872968f305eSRichard Henderson */ 2873968f305eSRichard Henderson if (op_prev->opc == INDEX_op_set_label) { 2874968f305eSRichard Henderson move_label_uses(label, arg_label(op_prev->args[0])); 2875968f305eSRichard Henderson tcg_op_remove(s, op_prev); 2876968f305eSRichard Henderson op_prev = QTAILQ_PREV(op, link); 2877968f305eSRichard Henderson } 2878968f305eSRichard Henderson 2879968f305eSRichard Henderson /* 28804d89d0bbSRichard Henderson * Optimization can fold conditional branches to unconditional. 28814d89d0bbSRichard Henderson * If we find a label which is preceded by an unconditional 28824d89d0bbSRichard Henderson * branch to next, remove the branch. We couldn't do this when 28834d89d0bbSRichard Henderson * processing the branch because any dead code between the branch 28844d89d0bbSRichard Henderson * and label had not yet been removed. 28854d89d0bbSRichard Henderson */ 28864d89d0bbSRichard Henderson if (op_prev->opc == INDEX_op_br && 28874d89d0bbSRichard Henderson label == arg_label(op_prev->args[0])) { 28884d89d0bbSRichard Henderson tcg_op_remove(s, op_prev); 28894d89d0bbSRichard Henderson /* Fall through means insns become live again. */ 28904d89d0bbSRichard Henderson dead = false; 28914d89d0bbSRichard Henderson } 28924d89d0bbSRichard Henderson 2893f85b1fc4SRichard Henderson if (QSIMPLEQ_EMPTY(&label->branches)) { 2894b4fc67c7SRichard Henderson /* 2895b4fc67c7SRichard Henderson * While there is an occasional backward branch, virtually 2896b4fc67c7SRichard Henderson * all branches generated by the translators are forward. 2897b4fc67c7SRichard Henderson * Which means that generally we will have already removed 2898b4fc67c7SRichard Henderson * all references to the label that will be, and there is 2899b4fc67c7SRichard Henderson * little to be gained by iterating. 2900b4fc67c7SRichard Henderson */ 2901b4fc67c7SRichard Henderson remove = true; 2902b4fc67c7SRichard Henderson } else { 2903b4fc67c7SRichard Henderson /* Once we see a label, insns become live again. */ 2904b4fc67c7SRichard Henderson dead = false; 2905b4fc67c7SRichard Henderson remove = false; 2906b4fc67c7SRichard Henderson } 2907b4fc67c7SRichard Henderson break; 2908b4fc67c7SRichard Henderson 2909b4fc67c7SRichard Henderson case INDEX_op_br: 2910b4fc67c7SRichard Henderson case INDEX_op_exit_tb: 2911b4fc67c7SRichard Henderson case INDEX_op_goto_ptr: 2912b4fc67c7SRichard Henderson /* Unconditional branches; everything following is dead. */ 2913b4fc67c7SRichard Henderson dead = true; 2914b4fc67c7SRichard Henderson break; 2915b4fc67c7SRichard Henderson 2916b4fc67c7SRichard Henderson case INDEX_op_call: 2917b4fc67c7SRichard Henderson /* Notice noreturn helper calls, raising exceptions. */ 291890163900SRichard Henderson if (tcg_call_flags(op) & TCG_CALL_NO_RETURN) { 2919b4fc67c7SRichard Henderson dead = true; 2920b4fc67c7SRichard Henderson } 2921b4fc67c7SRichard Henderson break; 2922b4fc67c7SRichard Henderson 2923b4fc67c7SRichard Henderson case INDEX_op_insn_start: 2924b4fc67c7SRichard Henderson /* Never remove -- we need to keep these for unwind. */ 2925b4fc67c7SRichard Henderson remove = false; 2926b4fc67c7SRichard Henderson break; 2927b4fc67c7SRichard Henderson 2928b4fc67c7SRichard Henderson default: 2929b4fc67c7SRichard Henderson break; 2930b4fc67c7SRichard Henderson } 2931b4fc67c7SRichard Henderson 2932b4fc67c7SRichard Henderson if (remove) { 2933b4fc67c7SRichard Henderson tcg_op_remove(s, op); 2934b4fc67c7SRichard Henderson } 2935b4fc67c7SRichard Henderson } 2936b4fc67c7SRichard Henderson } 2937b4fc67c7SRichard Henderson 2938c70fbf0aSRichard Henderson #define TS_DEAD 1 2939c70fbf0aSRichard Henderson #define TS_MEM 2 2940c70fbf0aSRichard Henderson 29415a18407fSRichard Henderson #define IS_DEAD_ARG(n) (arg_life & (DEAD_ARG << (n))) 29425a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n))) 29435a18407fSRichard Henderson 294425f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp. */ 294525f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts) 294625f49c5fSRichard Henderson { 294725f49c5fSRichard Henderson return ts->state_ptr; 294825f49c5fSRichard Henderson } 294925f49c5fSRichard Henderson 295025f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the 295125f49c5fSRichard Henderson * maximal regset for its type. 295225f49c5fSRichard Henderson */ 295325f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts) 295425f49c5fSRichard Henderson { 295525f49c5fSRichard Henderson *la_temp_pref(ts) 295625f49c5fSRichard Henderson = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]); 295725f49c5fSRichard Henderson } 295825f49c5fSRichard Henderson 29599c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals 29609c43b68dSAurelien Jarno should be in memory. */ 29612616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt) 2962c896fe29Sbellard { 2963b83eabeaSRichard Henderson int i; 2964b83eabeaSRichard Henderson 2965b83eabeaSRichard Henderson for (i = 0; i < ng; ++i) { 2966b83eabeaSRichard Henderson s->temps[i].state = TS_DEAD | TS_MEM; 296725f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 2968b83eabeaSRichard Henderson } 2969b83eabeaSRichard Henderson for (i = ng; i < nt; ++i) { 2970b83eabeaSRichard Henderson s->temps[i].state = TS_DEAD; 297125f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 2972b83eabeaSRichard Henderson } 2973c896fe29Sbellard } 2974c896fe29Sbellard 29759c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals 29769c43b68dSAurelien Jarno and local temps should be in memory. */ 29772616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt) 2978641d5fbeSbellard { 2979b83eabeaSRichard Henderson int i; 2980641d5fbeSbellard 2981ee17db83SRichard Henderson for (i = 0; i < nt; ++i) { 2982ee17db83SRichard Henderson TCGTemp *ts = &s->temps[i]; 2983ee17db83SRichard Henderson int state; 2984ee17db83SRichard Henderson 2985ee17db83SRichard Henderson switch (ts->kind) { 2986ee17db83SRichard Henderson case TEMP_FIXED: 2987ee17db83SRichard Henderson case TEMP_GLOBAL: 2988f57c6915SRichard Henderson case TEMP_TB: 2989ee17db83SRichard Henderson state = TS_DEAD | TS_MEM; 2990ee17db83SRichard Henderson break; 2991c7482438SRichard Henderson case TEMP_EBB: 2992c0522136SRichard Henderson case TEMP_CONST: 2993ee17db83SRichard Henderson state = TS_DEAD; 2994ee17db83SRichard Henderson break; 2995ee17db83SRichard Henderson default: 2996ee17db83SRichard Henderson g_assert_not_reached(); 2997c70fbf0aSRichard Henderson } 2998ee17db83SRichard Henderson ts->state = state; 2999ee17db83SRichard Henderson la_reset_pref(ts); 3000641d5fbeSbellard } 3001641d5fbeSbellard } 3002641d5fbeSbellard 3003f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory. */ 3004f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng) 3005f65a061cSRichard Henderson { 3006f65a061cSRichard Henderson int i; 3007f65a061cSRichard Henderson 3008f65a061cSRichard Henderson for (i = 0; i < ng; ++i) { 300925f49c5fSRichard Henderson int state = s->temps[i].state; 301025f49c5fSRichard Henderson s->temps[i].state = state | TS_MEM; 301125f49c5fSRichard Henderson if (state == TS_DEAD) { 301225f49c5fSRichard Henderson /* If the global was previously dead, reset prefs. */ 301325f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 301425f49c5fSRichard Henderson } 3015f65a061cSRichard Henderson } 3016f65a061cSRichard Henderson } 3017f65a061cSRichard Henderson 3018b4cb76e6SRichard Henderson /* 3019c7482438SRichard Henderson * liveness analysis: conditional branch: all temps are dead unless 3020c7482438SRichard Henderson * explicitly live-across-conditional-branch, globals and local temps 3021c7482438SRichard Henderson * should be synced. 3022b4cb76e6SRichard Henderson */ 3023b4cb76e6SRichard Henderson static void la_bb_sync(TCGContext *s, int ng, int nt) 3024b4cb76e6SRichard Henderson { 3025b4cb76e6SRichard Henderson la_global_sync(s, ng); 3026b4cb76e6SRichard Henderson 3027b4cb76e6SRichard Henderson for (int i = ng; i < nt; ++i) { 3028c0522136SRichard Henderson TCGTemp *ts = &s->temps[i]; 3029c0522136SRichard Henderson int state; 3030c0522136SRichard Henderson 3031c0522136SRichard Henderson switch (ts->kind) { 3032f57c6915SRichard Henderson case TEMP_TB: 3033c0522136SRichard Henderson state = ts->state; 3034c0522136SRichard Henderson ts->state = state | TS_MEM; 3035b4cb76e6SRichard Henderson if (state != TS_DEAD) { 3036b4cb76e6SRichard Henderson continue; 3037b4cb76e6SRichard Henderson } 3038c0522136SRichard Henderson break; 3039c7482438SRichard Henderson case TEMP_EBB: 3040c0522136SRichard Henderson case TEMP_CONST: 3041c0522136SRichard Henderson continue; 3042c0522136SRichard Henderson default: 3043c0522136SRichard Henderson g_assert_not_reached(); 3044b4cb76e6SRichard Henderson } 3045b4cb76e6SRichard Henderson la_reset_pref(&s->temps[i]); 3046b4cb76e6SRichard Henderson } 3047b4cb76e6SRichard Henderson } 3048b4cb76e6SRichard Henderson 3049f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill. */ 3050f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng) 3051f65a061cSRichard Henderson { 3052f65a061cSRichard Henderson int i; 3053f65a061cSRichard Henderson 3054f65a061cSRichard Henderson for (i = 0; i < ng; i++) { 3055f65a061cSRichard Henderson s->temps[i].state = TS_DEAD | TS_MEM; 305625f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 305725f49c5fSRichard Henderson } 305825f49c5fSRichard Henderson } 305925f49c5fSRichard Henderson 306025f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls. */ 306125f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt) 306225f49c5fSRichard Henderson { 306325f49c5fSRichard Henderson TCGRegSet mask = ~tcg_target_call_clobber_regs; 306425f49c5fSRichard Henderson int i; 306525f49c5fSRichard Henderson 306625f49c5fSRichard Henderson for (i = 0; i < nt; i++) { 306725f49c5fSRichard Henderson TCGTemp *ts = &s->temps[i]; 306825f49c5fSRichard Henderson if (!(ts->state & TS_DEAD)) { 306925f49c5fSRichard Henderson TCGRegSet *pset = la_temp_pref(ts); 307025f49c5fSRichard Henderson TCGRegSet set = *pset; 307125f49c5fSRichard Henderson 307225f49c5fSRichard Henderson set &= mask; 307325f49c5fSRichard Henderson /* If the combination is not possible, restart. */ 307425f49c5fSRichard Henderson if (set == 0) { 307525f49c5fSRichard Henderson set = tcg_target_available_regs[ts->type] & mask; 307625f49c5fSRichard Henderson } 307725f49c5fSRichard Henderson *pset = set; 307825f49c5fSRichard Henderson } 3079f65a061cSRichard Henderson } 3080f65a061cSRichard Henderson } 3081f65a061cSRichard Henderson 3082874b8574SRichard Henderson /* 3083874b8574SRichard Henderson * Liveness analysis: Verify the lifetime of TEMP_TB, and reduce 3084874b8574SRichard Henderson * to TEMP_EBB, if possible. 3085874b8574SRichard Henderson */ 3086874b8574SRichard Henderson static void __attribute__((noinline)) 3087874b8574SRichard Henderson liveness_pass_0(TCGContext *s) 3088874b8574SRichard Henderson { 3089874b8574SRichard Henderson void * const multiple_ebb = (void *)(uintptr_t)-1; 3090874b8574SRichard Henderson int nb_temps = s->nb_temps; 3091874b8574SRichard Henderson TCGOp *op, *ebb; 3092874b8574SRichard Henderson 3093874b8574SRichard Henderson for (int i = s->nb_globals; i < nb_temps; ++i) { 3094874b8574SRichard Henderson s->temps[i].state_ptr = NULL; 3095874b8574SRichard Henderson } 3096874b8574SRichard Henderson 3097874b8574SRichard Henderson /* 3098874b8574SRichard Henderson * Represent each EBB by the op at which it begins. In the case of 3099874b8574SRichard Henderson * the first EBB, this is the first op, otherwise it is a label. 3100874b8574SRichard Henderson * Collect the uses of each TEMP_TB: NULL for unused, EBB for use 3101874b8574SRichard Henderson * within a single EBB, else MULTIPLE_EBB. 3102874b8574SRichard Henderson */ 3103874b8574SRichard Henderson ebb = QTAILQ_FIRST(&s->ops); 3104874b8574SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 3105874b8574SRichard Henderson const TCGOpDef *def; 3106874b8574SRichard Henderson int nb_oargs, nb_iargs; 3107874b8574SRichard Henderson 3108874b8574SRichard Henderson switch (op->opc) { 3109874b8574SRichard Henderson case INDEX_op_set_label: 3110874b8574SRichard Henderson ebb = op; 3111874b8574SRichard Henderson continue; 3112874b8574SRichard Henderson case INDEX_op_discard: 3113874b8574SRichard Henderson continue; 3114874b8574SRichard Henderson case INDEX_op_call: 3115874b8574SRichard Henderson nb_oargs = TCGOP_CALLO(op); 3116874b8574SRichard Henderson nb_iargs = TCGOP_CALLI(op); 3117874b8574SRichard Henderson break; 3118874b8574SRichard Henderson default: 3119874b8574SRichard Henderson def = &tcg_op_defs[op->opc]; 3120874b8574SRichard Henderson nb_oargs = def->nb_oargs; 3121874b8574SRichard Henderson nb_iargs = def->nb_iargs; 3122874b8574SRichard Henderson break; 3123874b8574SRichard Henderson } 3124874b8574SRichard Henderson 3125874b8574SRichard Henderson for (int i = 0; i < nb_oargs + nb_iargs; ++i) { 3126874b8574SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]); 3127874b8574SRichard Henderson 3128874b8574SRichard Henderson if (ts->kind != TEMP_TB) { 3129874b8574SRichard Henderson continue; 3130874b8574SRichard Henderson } 3131874b8574SRichard Henderson if (ts->state_ptr == NULL) { 3132874b8574SRichard Henderson ts->state_ptr = ebb; 3133874b8574SRichard Henderson } else if (ts->state_ptr != ebb) { 3134874b8574SRichard Henderson ts->state_ptr = multiple_ebb; 3135874b8574SRichard Henderson } 3136874b8574SRichard Henderson } 3137874b8574SRichard Henderson } 3138874b8574SRichard Henderson 3139874b8574SRichard Henderson /* 3140874b8574SRichard Henderson * For TEMP_TB that turned out not to be used beyond one EBB, 3141874b8574SRichard Henderson * reduce the liveness to TEMP_EBB. 3142874b8574SRichard Henderson */ 3143874b8574SRichard Henderson for (int i = s->nb_globals; i < nb_temps; ++i) { 3144874b8574SRichard Henderson TCGTemp *ts = &s->temps[i]; 3145874b8574SRichard Henderson if (ts->kind == TEMP_TB && ts->state_ptr != multiple_ebb) { 3146874b8574SRichard Henderson ts->kind = TEMP_EBB; 3147874b8574SRichard Henderson } 3148874b8574SRichard Henderson } 3149874b8574SRichard Henderson } 3150874b8574SRichard Henderson 3151a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a 3152c896fe29Sbellard given input arguments is dead. Instructions updating dead 3153c896fe29Sbellard temporaries are removed. */ 31549bbee4c0SRichard Henderson static void __attribute__((noinline)) 31559bbee4c0SRichard Henderson liveness_pass_1(TCGContext *s) 3156c896fe29Sbellard { 3157c70fbf0aSRichard Henderson int nb_globals = s->nb_globals; 31582616c808SRichard Henderson int nb_temps = s->nb_temps; 315915fa08f8SRichard Henderson TCGOp *op, *op_prev; 316025f49c5fSRichard Henderson TCGRegSet *prefs; 316125f49c5fSRichard Henderson int i; 316225f49c5fSRichard Henderson 316325f49c5fSRichard Henderson prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps); 316425f49c5fSRichard Henderson for (i = 0; i < nb_temps; ++i) { 316525f49c5fSRichard Henderson s->temps[i].state_ptr = prefs + i; 316625f49c5fSRichard Henderson } 3167c896fe29Sbellard 3168ae36a246SRichard Henderson /* ??? Should be redundant with the exit_tb that ends the TB. */ 31692616c808SRichard Henderson la_func_end(s, nb_globals, nb_temps); 3170c896fe29Sbellard 3171eae3eb3eSPaolo Bonzini QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) { 317225f49c5fSRichard Henderson int nb_iargs, nb_oargs; 3173c45cb8bbSRichard Henderson TCGOpcode opc_new, opc_new2; 3174c45cb8bbSRichard Henderson bool have_opc_new2; 3175a1b3c48dSRichard Henderson TCGLifeData arg_life = 0; 317625f49c5fSRichard Henderson TCGTemp *ts; 3177c45cb8bbSRichard Henderson TCGOpcode opc = op->opc; 3178c45cb8bbSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 3179c45cb8bbSRichard Henderson 3180c45cb8bbSRichard Henderson switch (opc) { 3181c896fe29Sbellard case INDEX_op_call: 3182c6e113f5Sbellard { 318339004a71SRichard Henderson const TCGHelperInfo *info = tcg_call_info(op); 318439004a71SRichard Henderson int call_flags = tcg_call_flags(op); 3185c6e113f5Sbellard 3186cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 3187cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 3188c6e113f5Sbellard 3189c45cb8bbSRichard Henderson /* pure functions can be removed if their result is unused */ 319078505279SAurelien Jarno if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) { 3191c6e113f5Sbellard for (i = 0; i < nb_oargs; i++) { 319225f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 319325f49c5fSRichard Henderson if (ts->state != TS_DEAD) { 3194c6e113f5Sbellard goto do_not_remove_call; 3195c6e113f5Sbellard } 31969c43b68dSAurelien Jarno } 3197c45cb8bbSRichard Henderson goto do_remove; 3198152c35aaSRichard Henderson } 3199c6e113f5Sbellard do_not_remove_call: 3200c896fe29Sbellard 320125f49c5fSRichard Henderson /* Output args are dead. */ 3202c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 320325f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 320425f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 3205a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 32066b64b624SAurelien Jarno } 320725f49c5fSRichard Henderson if (ts->state & TS_MEM) { 3208a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i; 32099c43b68dSAurelien Jarno } 321025f49c5fSRichard Henderson ts->state = TS_DEAD; 321125f49c5fSRichard Henderson la_reset_pref(ts); 3212c896fe29Sbellard } 3213c896fe29Sbellard 321431fd884bSRichard Henderson /* Not used -- it will be tcg_target_call_oarg_reg(). */ 321531fd884bSRichard Henderson memset(op->output_pref, 0, sizeof(op->output_pref)); 321631fd884bSRichard Henderson 321778505279SAurelien Jarno if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS | 321878505279SAurelien Jarno TCG_CALL_NO_READ_GLOBALS))) { 3219f65a061cSRichard Henderson la_global_kill(s, nb_globals); 3220c70fbf0aSRichard Henderson } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) { 3221f65a061cSRichard Henderson la_global_sync(s, nb_globals); 3222b9c18f56Saurel32 } 3223c896fe29Sbellard 322425f49c5fSRichard Henderson /* Record arguments that die in this helper. */ 3225866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 322625f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 322739004a71SRichard Henderson if (ts->state & TS_DEAD) { 3228a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 3229c896fe29Sbellard } 3230c896fe29Sbellard } 323125f49c5fSRichard Henderson 323225f49c5fSRichard Henderson /* For all live registers, remove call-clobbered prefs. */ 323325f49c5fSRichard Henderson la_cross_call(s, nb_temps); 323425f49c5fSRichard Henderson 323539004a71SRichard Henderson /* 323639004a71SRichard Henderson * Input arguments are live for preceding opcodes. 323739004a71SRichard Henderson * 323839004a71SRichard Henderson * For those arguments that die, and will be allocated in 323939004a71SRichard Henderson * registers, clear the register set for that arg, to be 324039004a71SRichard Henderson * filled in below. For args that will be on the stack, 324139004a71SRichard Henderson * reset to any available reg. Process arguments in reverse 324239004a71SRichard Henderson * order so that if a temp is used more than once, the stack 324339004a71SRichard Henderson * reset to max happens before the register reset to 0. 324425f49c5fSRichard Henderson */ 324539004a71SRichard Henderson for (i = nb_iargs - 1; i >= 0; i--) { 324639004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i]; 324739004a71SRichard Henderson ts = arg_temp(op->args[nb_oargs + i]); 324839004a71SRichard Henderson 324939004a71SRichard Henderson if (ts->state & TS_DEAD) { 325039004a71SRichard Henderson switch (loc->kind) { 325139004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 325239004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 325339004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 3254338b61e9SRichard Henderson if (arg_slot_reg_p(loc->arg_slot)) { 325539004a71SRichard Henderson *la_temp_pref(ts) = 0; 325639004a71SRichard Henderson break; 325739004a71SRichard Henderson } 325839004a71SRichard Henderson /* fall through */ 325939004a71SRichard Henderson default: 326039004a71SRichard Henderson *la_temp_pref(ts) = 326139004a71SRichard Henderson tcg_target_available_regs[ts->type]; 326239004a71SRichard Henderson break; 326339004a71SRichard Henderson } 326425f49c5fSRichard Henderson ts->state &= ~TS_DEAD; 326525f49c5fSRichard Henderson } 326625f49c5fSRichard Henderson } 326725f49c5fSRichard Henderson 326839004a71SRichard Henderson /* 326939004a71SRichard Henderson * For each input argument, add its input register to prefs. 327039004a71SRichard Henderson * If a temp is used once, this produces a single set bit; 327139004a71SRichard Henderson * if a temp is used multiple times, this produces a set. 327239004a71SRichard Henderson */ 327339004a71SRichard Henderson for (i = 0; i < nb_iargs; i++) { 327439004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i]; 327539004a71SRichard Henderson ts = arg_temp(op->args[nb_oargs + i]); 327639004a71SRichard Henderson 327739004a71SRichard Henderson switch (loc->kind) { 327839004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 327939004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 328039004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 3281338b61e9SRichard Henderson if (arg_slot_reg_p(loc->arg_slot)) { 328225f49c5fSRichard Henderson tcg_regset_set_reg(*la_temp_pref(ts), 328339004a71SRichard Henderson tcg_target_call_iarg_regs[loc->arg_slot]); 328439004a71SRichard Henderson } 328539004a71SRichard Henderson break; 328639004a71SRichard Henderson default: 328739004a71SRichard Henderson break; 3288c70fbf0aSRichard Henderson } 3289c19f47bfSAurelien Jarno } 3290c6e113f5Sbellard } 3291c896fe29Sbellard break; 3292765b842aSRichard Henderson case INDEX_op_insn_start: 3293c896fe29Sbellard break; 32945ff9d6a4Sbellard case INDEX_op_discard: 32955ff9d6a4Sbellard /* mark the temporary as dead */ 329625f49c5fSRichard Henderson ts = arg_temp(op->args[0]); 329725f49c5fSRichard Henderson ts->state = TS_DEAD; 329825f49c5fSRichard Henderson la_reset_pref(ts); 32995ff9d6a4Sbellard break; 33001305c451SRichard Henderson 33011305c451SRichard Henderson case INDEX_op_add2_i32: 3302c45cb8bbSRichard Henderson opc_new = INDEX_op_add_i32; 3303f1fae40cSRichard Henderson goto do_addsub2; 33041305c451SRichard Henderson case INDEX_op_sub2_i32: 3305c45cb8bbSRichard Henderson opc_new = INDEX_op_sub_i32; 3306f1fae40cSRichard Henderson goto do_addsub2; 3307f1fae40cSRichard Henderson case INDEX_op_add2_i64: 3308c45cb8bbSRichard Henderson opc_new = INDEX_op_add_i64; 3309f1fae40cSRichard Henderson goto do_addsub2; 3310f1fae40cSRichard Henderson case INDEX_op_sub2_i64: 3311c45cb8bbSRichard Henderson opc_new = INDEX_op_sub_i64; 3312f1fae40cSRichard Henderson do_addsub2: 33131305c451SRichard Henderson nb_iargs = 4; 33141305c451SRichard Henderson nb_oargs = 2; 33151305c451SRichard Henderson /* Test if the high part of the operation is dead, but not 33161305c451SRichard Henderson the low part. The result can be optimized to a simple 33171305c451SRichard Henderson add or sub. This happens often for x86_64 guest when the 33181305c451SRichard Henderson cpu mode is set to 32 bit. */ 3319b83eabeaSRichard Henderson if (arg_temp(op->args[1])->state == TS_DEAD) { 3320b83eabeaSRichard Henderson if (arg_temp(op->args[0])->state == TS_DEAD) { 33211305c451SRichard Henderson goto do_remove; 33221305c451SRichard Henderson } 3323c45cb8bbSRichard Henderson /* Replace the opcode and adjust the args in place, 3324c45cb8bbSRichard Henderson leaving 3 unused args at the end. */ 3325c45cb8bbSRichard Henderson op->opc = opc = opc_new; 3326efee3746SRichard Henderson op->args[1] = op->args[2]; 3327efee3746SRichard Henderson op->args[2] = op->args[4]; 33281305c451SRichard Henderson /* Fall through and mark the single-word operation live. */ 33291305c451SRichard Henderson nb_iargs = 2; 33301305c451SRichard Henderson nb_oargs = 1; 33311305c451SRichard Henderson } 33321305c451SRichard Henderson goto do_not_remove; 33331305c451SRichard Henderson 33341414968aSRichard Henderson case INDEX_op_mulu2_i32: 3335c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i32; 3336c45cb8bbSRichard Henderson opc_new2 = INDEX_op_muluh_i32; 3337c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_muluh_i32; 333803271524SRichard Henderson goto do_mul2; 3339f1fae40cSRichard Henderson case INDEX_op_muls2_i32: 3340c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i32; 3341c45cb8bbSRichard Henderson opc_new2 = INDEX_op_mulsh_i32; 3342c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_mulsh_i32; 3343f1fae40cSRichard Henderson goto do_mul2; 3344f1fae40cSRichard Henderson case INDEX_op_mulu2_i64: 3345c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i64; 3346c45cb8bbSRichard Henderson opc_new2 = INDEX_op_muluh_i64; 3347c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_muluh_i64; 334803271524SRichard Henderson goto do_mul2; 3349f1fae40cSRichard Henderson case INDEX_op_muls2_i64: 3350c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i64; 3351c45cb8bbSRichard Henderson opc_new2 = INDEX_op_mulsh_i64; 3352c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_mulsh_i64; 335303271524SRichard Henderson goto do_mul2; 3354f1fae40cSRichard Henderson do_mul2: 33551414968aSRichard Henderson nb_iargs = 2; 33561414968aSRichard Henderson nb_oargs = 2; 3357b83eabeaSRichard Henderson if (arg_temp(op->args[1])->state == TS_DEAD) { 3358b83eabeaSRichard Henderson if (arg_temp(op->args[0])->state == TS_DEAD) { 335903271524SRichard Henderson /* Both parts of the operation are dead. */ 33601414968aSRichard Henderson goto do_remove; 33611414968aSRichard Henderson } 336203271524SRichard Henderson /* The high part of the operation is dead; generate the low. */ 3363c45cb8bbSRichard Henderson op->opc = opc = opc_new; 3364efee3746SRichard Henderson op->args[1] = op->args[2]; 3365efee3746SRichard Henderson op->args[2] = op->args[3]; 3366b83eabeaSRichard Henderson } else if (arg_temp(op->args[0])->state == TS_DEAD && have_opc_new2) { 336703271524SRichard Henderson /* The low part of the operation is dead; generate the high. */ 3368c45cb8bbSRichard Henderson op->opc = opc = opc_new2; 3369efee3746SRichard Henderson op->args[0] = op->args[1]; 3370efee3746SRichard Henderson op->args[1] = op->args[2]; 3371efee3746SRichard Henderson op->args[2] = op->args[3]; 337203271524SRichard Henderson } else { 337303271524SRichard Henderson goto do_not_remove; 337403271524SRichard Henderson } 337503271524SRichard Henderson /* Mark the single-word operation live. */ 33761414968aSRichard Henderson nb_oargs = 1; 33771414968aSRichard Henderson goto do_not_remove; 33781414968aSRichard Henderson 3379c896fe29Sbellard default: 33801305c451SRichard Henderson /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */ 3381c896fe29Sbellard nb_iargs = def->nb_iargs; 3382c896fe29Sbellard nb_oargs = def->nb_oargs; 3383c896fe29Sbellard 3384c896fe29Sbellard /* Test if the operation can be removed because all 33855ff9d6a4Sbellard its outputs are dead. We assume that nb_oargs == 0 33865ff9d6a4Sbellard implies side effects */ 33875ff9d6a4Sbellard if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) { 3388c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 3389b83eabeaSRichard Henderson if (arg_temp(op->args[i])->state != TS_DEAD) { 3390c896fe29Sbellard goto do_not_remove; 3391c896fe29Sbellard } 33929c43b68dSAurelien Jarno } 3393152c35aaSRichard Henderson goto do_remove; 3394152c35aaSRichard Henderson } 3395152c35aaSRichard Henderson goto do_not_remove; 3396152c35aaSRichard Henderson 33971305c451SRichard Henderson do_remove: 33980c627cdcSRichard Henderson tcg_op_remove(s, op); 3399152c35aaSRichard Henderson break; 3400152c35aaSRichard Henderson 3401c896fe29Sbellard do_not_remove: 3402c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 340325f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 340425f49c5fSRichard Henderson 340525f49c5fSRichard Henderson /* Remember the preference of the uses that followed. */ 340631fd884bSRichard Henderson if (i < ARRAY_SIZE(op->output_pref)) { 340725f49c5fSRichard Henderson op->output_pref[i] = *la_temp_pref(ts); 340831fd884bSRichard Henderson } 340925f49c5fSRichard Henderson 341025f49c5fSRichard Henderson /* Output args are dead. */ 341125f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 3412a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 34136b64b624SAurelien Jarno } 341425f49c5fSRichard Henderson if (ts->state & TS_MEM) { 3415a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i; 34169c43b68dSAurelien Jarno } 341725f49c5fSRichard Henderson ts->state = TS_DEAD; 341825f49c5fSRichard Henderson la_reset_pref(ts); 3419c896fe29Sbellard } 3420c896fe29Sbellard 342125f49c5fSRichard Henderson /* If end of basic block, update. */ 3422ae36a246SRichard Henderson if (def->flags & TCG_OPF_BB_EXIT) { 3423ae36a246SRichard Henderson la_func_end(s, nb_globals, nb_temps); 3424b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_COND_BRANCH) { 3425b4cb76e6SRichard Henderson la_bb_sync(s, nb_globals, nb_temps); 3426ae36a246SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 34272616c808SRichard Henderson la_bb_end(s, nb_globals, nb_temps); 34283d5c5f87SAurelien Jarno } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { 3429f65a061cSRichard Henderson la_global_sync(s, nb_globals); 343025f49c5fSRichard Henderson if (def->flags & TCG_OPF_CALL_CLOBBER) { 343125f49c5fSRichard Henderson la_cross_call(s, nb_temps); 343225f49c5fSRichard Henderson } 3433c896fe29Sbellard } 3434c896fe29Sbellard 343525f49c5fSRichard Henderson /* Record arguments that die in this opcode. */ 3436866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 343725f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 343825f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 3439a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 3440c896fe29Sbellard } 3441c19f47bfSAurelien Jarno } 344225f49c5fSRichard Henderson 344325f49c5fSRichard Henderson /* Input arguments are live for preceding opcodes. */ 3444c19f47bfSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 344525f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 344625f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 344725f49c5fSRichard Henderson /* For operands that were dead, initially allow 344825f49c5fSRichard Henderson all regs for the type. */ 344925f49c5fSRichard Henderson *la_temp_pref(ts) = tcg_target_available_regs[ts->type]; 345025f49c5fSRichard Henderson ts->state &= ~TS_DEAD; 345125f49c5fSRichard Henderson } 345225f49c5fSRichard Henderson } 345325f49c5fSRichard Henderson 345425f49c5fSRichard Henderson /* Incorporate constraints for this operand. */ 345525f49c5fSRichard Henderson switch (opc) { 345625f49c5fSRichard Henderson case INDEX_op_mov_i32: 345725f49c5fSRichard Henderson case INDEX_op_mov_i64: 345825f49c5fSRichard Henderson /* Note that these are TCG_OPF_NOT_PRESENT and do not 345925f49c5fSRichard Henderson have proper constraints. That said, special case 346025f49c5fSRichard Henderson moves to propagate preferences backward. */ 346125f49c5fSRichard Henderson if (IS_DEAD_ARG(1)) { 346225f49c5fSRichard Henderson *la_temp_pref(arg_temp(op->args[0])) 346325f49c5fSRichard Henderson = *la_temp_pref(arg_temp(op->args[1])); 346425f49c5fSRichard Henderson } 346525f49c5fSRichard Henderson break; 346625f49c5fSRichard Henderson 346725f49c5fSRichard Henderson default: 346825f49c5fSRichard Henderson for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 346925f49c5fSRichard Henderson const TCGArgConstraint *ct = &def->args_ct[i]; 347025f49c5fSRichard Henderson TCGRegSet set, *pset; 347125f49c5fSRichard Henderson 347225f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 347325f49c5fSRichard Henderson pset = la_temp_pref(ts); 347425f49c5fSRichard Henderson set = *pset; 347525f49c5fSRichard Henderson 34769be0d080SRichard Henderson set &= ct->regs; 3477bc2b17e6SRichard Henderson if (ct->ialias) { 347831fd884bSRichard Henderson set &= output_pref(op, ct->alias_index); 347925f49c5fSRichard Henderson } 348025f49c5fSRichard Henderson /* If the combination is not possible, restart. */ 348125f49c5fSRichard Henderson if (set == 0) { 34829be0d080SRichard Henderson set = ct->regs; 348325f49c5fSRichard Henderson } 348425f49c5fSRichard Henderson *pset = set; 348525f49c5fSRichard Henderson } 348625f49c5fSRichard Henderson break; 3487c896fe29Sbellard } 3488c896fe29Sbellard break; 3489c896fe29Sbellard } 3490bee158cbSRichard Henderson op->life = arg_life; 3491c896fe29Sbellard } 34921ff0a2c5SEvgeny Voevodin } 3493c896fe29Sbellard 34945a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries. */ 34959bbee4c0SRichard Henderson static bool __attribute__((noinline)) 34969bbee4c0SRichard Henderson liveness_pass_2(TCGContext *s) 34975a18407fSRichard Henderson { 34985a18407fSRichard Henderson int nb_globals = s->nb_globals; 349915fa08f8SRichard Henderson int nb_temps, i; 35005a18407fSRichard Henderson bool changes = false; 350115fa08f8SRichard Henderson TCGOp *op, *op_next; 35025a18407fSRichard Henderson 35035a18407fSRichard Henderson /* Create a temporary for each indirect global. */ 35045a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 35055a18407fSRichard Henderson TCGTemp *its = &s->temps[i]; 35065a18407fSRichard Henderson if (its->indirect_reg) { 35075a18407fSRichard Henderson TCGTemp *dts = tcg_temp_alloc(s); 35085a18407fSRichard Henderson dts->type = its->type; 35095a18407fSRichard Henderson dts->base_type = its->base_type; 3510e1e64652SRichard Henderson dts->temp_subindex = its->temp_subindex; 3511c7482438SRichard Henderson dts->kind = TEMP_EBB; 3512b83eabeaSRichard Henderson its->state_ptr = dts; 3513b83eabeaSRichard Henderson } else { 3514b83eabeaSRichard Henderson its->state_ptr = NULL; 35155a18407fSRichard Henderson } 3516b83eabeaSRichard Henderson /* All globals begin dead. */ 3517b83eabeaSRichard Henderson its->state = TS_DEAD; 35185a18407fSRichard Henderson } 3519b83eabeaSRichard Henderson for (nb_temps = s->nb_temps; i < nb_temps; ++i) { 3520b83eabeaSRichard Henderson TCGTemp *its = &s->temps[i]; 3521b83eabeaSRichard Henderson its->state_ptr = NULL; 3522b83eabeaSRichard Henderson its->state = TS_DEAD; 3523b83eabeaSRichard Henderson } 35245a18407fSRichard Henderson 352515fa08f8SRichard Henderson QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) { 35265a18407fSRichard Henderson TCGOpcode opc = op->opc; 35275a18407fSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 35285a18407fSRichard Henderson TCGLifeData arg_life = op->life; 35295a18407fSRichard Henderson int nb_iargs, nb_oargs, call_flags; 3530b83eabeaSRichard Henderson TCGTemp *arg_ts, *dir_ts; 35315a18407fSRichard Henderson 35325a18407fSRichard Henderson if (opc == INDEX_op_call) { 3533cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 3534cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 353590163900SRichard Henderson call_flags = tcg_call_flags(op); 35365a18407fSRichard Henderson } else { 35375a18407fSRichard Henderson nb_iargs = def->nb_iargs; 35385a18407fSRichard Henderson nb_oargs = def->nb_oargs; 35395a18407fSRichard Henderson 35405a18407fSRichard Henderson /* Set flags similar to how calls require. */ 3541b4cb76e6SRichard Henderson if (def->flags & TCG_OPF_COND_BRANCH) { 3542b4cb76e6SRichard Henderson /* Like reading globals: sync_globals */ 3543b4cb76e6SRichard Henderson call_flags = TCG_CALL_NO_WRITE_GLOBALS; 3544b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 35455a18407fSRichard Henderson /* Like writing globals: save_globals */ 35465a18407fSRichard Henderson call_flags = 0; 35475a18407fSRichard Henderson } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { 35485a18407fSRichard Henderson /* Like reading globals: sync_globals */ 35495a18407fSRichard Henderson call_flags = TCG_CALL_NO_WRITE_GLOBALS; 35505a18407fSRichard Henderson } else { 35515a18407fSRichard Henderson /* No effect on globals. */ 35525a18407fSRichard Henderson call_flags = (TCG_CALL_NO_READ_GLOBALS | 35535a18407fSRichard Henderson TCG_CALL_NO_WRITE_GLOBALS); 35545a18407fSRichard Henderson } 35555a18407fSRichard Henderson } 35565a18407fSRichard Henderson 35575a18407fSRichard Henderson /* Make sure that input arguments are available. */ 35585a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 3559b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 3560b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 3561b83eabeaSRichard Henderson if (dir_ts && arg_ts->state == TS_DEAD) { 3562b83eabeaSRichard Henderson TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32 35635a18407fSRichard Henderson ? INDEX_op_ld_i32 35645a18407fSRichard Henderson : INDEX_op_ld_i64); 3565d4478943SPhilippe Mathieu-Daudé TCGOp *lop = tcg_op_insert_before(s, op, lopc, 3); 35665a18407fSRichard Henderson 3567b83eabeaSRichard Henderson lop->args[0] = temp_arg(dir_ts); 3568b83eabeaSRichard Henderson lop->args[1] = temp_arg(arg_ts->mem_base); 3569b83eabeaSRichard Henderson lop->args[2] = arg_ts->mem_offset; 35705a18407fSRichard Henderson 35715a18407fSRichard Henderson /* Loaded, but synced with memory. */ 3572b83eabeaSRichard Henderson arg_ts->state = TS_MEM; 35735a18407fSRichard Henderson } 35745a18407fSRichard Henderson } 35755a18407fSRichard Henderson 35765a18407fSRichard Henderson /* Perform input replacement, and mark inputs that became dead. 35775a18407fSRichard Henderson No action is required except keeping temp_state up to date 35785a18407fSRichard Henderson so that we reload when needed. */ 35795a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 3580b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 3581b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 3582b83eabeaSRichard Henderson if (dir_ts) { 3583b83eabeaSRichard Henderson op->args[i] = temp_arg(dir_ts); 35845a18407fSRichard Henderson changes = true; 35855a18407fSRichard Henderson if (IS_DEAD_ARG(i)) { 3586b83eabeaSRichard Henderson arg_ts->state = TS_DEAD; 35875a18407fSRichard Henderson } 35885a18407fSRichard Henderson } 35895a18407fSRichard Henderson } 35905a18407fSRichard Henderson 35915a18407fSRichard Henderson /* Liveness analysis should ensure that the following are 35925a18407fSRichard Henderson all correct, for call sites and basic block end points. */ 35935a18407fSRichard Henderson if (call_flags & TCG_CALL_NO_READ_GLOBALS) { 35945a18407fSRichard Henderson /* Nothing to do */ 35955a18407fSRichard Henderson } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) { 35965a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 35975a18407fSRichard Henderson /* Liveness should see that globals are synced back, 35985a18407fSRichard Henderson that is, either TS_DEAD or TS_MEM. */ 3599b83eabeaSRichard Henderson arg_ts = &s->temps[i]; 3600b83eabeaSRichard Henderson tcg_debug_assert(arg_ts->state_ptr == 0 3601b83eabeaSRichard Henderson || arg_ts->state != 0); 36025a18407fSRichard Henderson } 36035a18407fSRichard Henderson } else { 36045a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 36055a18407fSRichard Henderson /* Liveness should see that globals are saved back, 36065a18407fSRichard Henderson that is, TS_DEAD, waiting to be reloaded. */ 3607b83eabeaSRichard Henderson arg_ts = &s->temps[i]; 3608b83eabeaSRichard Henderson tcg_debug_assert(arg_ts->state_ptr == 0 3609b83eabeaSRichard Henderson || arg_ts->state == TS_DEAD); 36105a18407fSRichard Henderson } 36115a18407fSRichard Henderson } 36125a18407fSRichard Henderson 36135a18407fSRichard Henderson /* Outputs become available. */ 361461f15c48SRichard Henderson if (opc == INDEX_op_mov_i32 || opc == INDEX_op_mov_i64) { 361561f15c48SRichard Henderson arg_ts = arg_temp(op->args[0]); 361661f15c48SRichard Henderson dir_ts = arg_ts->state_ptr; 361761f15c48SRichard Henderson if (dir_ts) { 361861f15c48SRichard Henderson op->args[0] = temp_arg(dir_ts); 361961f15c48SRichard Henderson changes = true; 362061f15c48SRichard Henderson 362161f15c48SRichard Henderson /* The output is now live and modified. */ 362261f15c48SRichard Henderson arg_ts->state = 0; 362361f15c48SRichard Henderson 362461f15c48SRichard Henderson if (NEED_SYNC_ARG(0)) { 362561f15c48SRichard Henderson TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 362661f15c48SRichard Henderson ? INDEX_op_st_i32 362761f15c48SRichard Henderson : INDEX_op_st_i64); 3628d4478943SPhilippe Mathieu-Daudé TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3); 362961f15c48SRichard Henderson TCGTemp *out_ts = dir_ts; 363061f15c48SRichard Henderson 363161f15c48SRichard Henderson if (IS_DEAD_ARG(0)) { 363261f15c48SRichard Henderson out_ts = arg_temp(op->args[1]); 363361f15c48SRichard Henderson arg_ts->state = TS_DEAD; 363461f15c48SRichard Henderson tcg_op_remove(s, op); 363561f15c48SRichard Henderson } else { 363661f15c48SRichard Henderson arg_ts->state = TS_MEM; 363761f15c48SRichard Henderson } 363861f15c48SRichard Henderson 363961f15c48SRichard Henderson sop->args[0] = temp_arg(out_ts); 364061f15c48SRichard Henderson sop->args[1] = temp_arg(arg_ts->mem_base); 364161f15c48SRichard Henderson sop->args[2] = arg_ts->mem_offset; 364261f15c48SRichard Henderson } else { 364361f15c48SRichard Henderson tcg_debug_assert(!IS_DEAD_ARG(0)); 364461f15c48SRichard Henderson } 364561f15c48SRichard Henderson } 364661f15c48SRichard Henderson } else { 36475a18407fSRichard Henderson for (i = 0; i < nb_oargs; i++) { 3648b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 3649b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 3650b83eabeaSRichard Henderson if (!dir_ts) { 36515a18407fSRichard Henderson continue; 36525a18407fSRichard Henderson } 3653b83eabeaSRichard Henderson op->args[i] = temp_arg(dir_ts); 36545a18407fSRichard Henderson changes = true; 36555a18407fSRichard Henderson 36565a18407fSRichard Henderson /* The output is now live and modified. */ 3657b83eabeaSRichard Henderson arg_ts->state = 0; 36585a18407fSRichard Henderson 36595a18407fSRichard Henderson /* Sync outputs upon their last write. */ 36605a18407fSRichard Henderson if (NEED_SYNC_ARG(i)) { 3661b83eabeaSRichard Henderson TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 36625a18407fSRichard Henderson ? INDEX_op_st_i32 36635a18407fSRichard Henderson : INDEX_op_st_i64); 3664d4478943SPhilippe Mathieu-Daudé TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3); 36655a18407fSRichard Henderson 3666b83eabeaSRichard Henderson sop->args[0] = temp_arg(dir_ts); 3667b83eabeaSRichard Henderson sop->args[1] = temp_arg(arg_ts->mem_base); 3668b83eabeaSRichard Henderson sop->args[2] = arg_ts->mem_offset; 36695a18407fSRichard Henderson 3670b83eabeaSRichard Henderson arg_ts->state = TS_MEM; 36715a18407fSRichard Henderson } 36725a18407fSRichard Henderson /* Drop outputs that are dead. */ 36735a18407fSRichard Henderson if (IS_DEAD_ARG(i)) { 3674b83eabeaSRichard Henderson arg_ts->state = TS_DEAD; 36755a18407fSRichard Henderson } 36765a18407fSRichard Henderson } 36775a18407fSRichard Henderson } 367861f15c48SRichard Henderson } 36795a18407fSRichard Henderson 36805a18407fSRichard Henderson return changes; 36815a18407fSRichard Henderson } 36825a18407fSRichard Henderson 36832272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts) 3684c896fe29Sbellard { 368531c96417SRichard Henderson intptr_t off; 3686273eb50cSRichard Henderson int size, align; 3687c1c09194SRichard Henderson 3688273eb50cSRichard Henderson /* When allocating an object, look at the full type. */ 3689273eb50cSRichard Henderson size = tcg_type_size(ts->base_type); 3690273eb50cSRichard Henderson switch (ts->base_type) { 3691c1c09194SRichard Henderson case TCG_TYPE_I32: 369231c96417SRichard Henderson align = 4; 3693c1c09194SRichard Henderson break; 3694c1c09194SRichard Henderson case TCG_TYPE_I64: 3695c1c09194SRichard Henderson case TCG_TYPE_V64: 369631c96417SRichard Henderson align = 8; 3697c1c09194SRichard Henderson break; 369843eef72fSRichard Henderson case TCG_TYPE_I128: 3699c1c09194SRichard Henderson case TCG_TYPE_V128: 3700c1c09194SRichard Henderson case TCG_TYPE_V256: 370143eef72fSRichard Henderson /* 370243eef72fSRichard Henderson * Note that we do not require aligned storage for V256, 370343eef72fSRichard Henderson * and that we provide alignment for I128 to match V128, 370443eef72fSRichard Henderson * even if that's above what the host ABI requires. 370543eef72fSRichard Henderson */ 370631c96417SRichard Henderson align = 16; 3707c1c09194SRichard Henderson break; 3708c1c09194SRichard Henderson default: 3709c1c09194SRichard Henderson g_assert_not_reached(); 3710b591dc59SBlue Swirl } 3711c1c09194SRichard Henderson 3712b9537d59SRichard Henderson /* 3713b9537d59SRichard Henderson * Assume the stack is sufficiently aligned. 3714b9537d59SRichard Henderson * This affects e.g. ARM NEON, where we have 8 byte stack alignment 3715b9537d59SRichard Henderson * and do not require 16 byte vector alignment. This seems slightly 3716b9537d59SRichard Henderson * easier than fully parameterizing the above switch statement. 3717b9537d59SRichard Henderson */ 3718b9537d59SRichard Henderson align = MIN(TCG_TARGET_STACK_ALIGN, align); 3719c1c09194SRichard Henderson off = ROUND_UP(s->current_frame_offset, align); 3720732d5897SRichard Henderson 3721732d5897SRichard Henderson /* If we've exhausted the stack frame, restart with a smaller TB. */ 3722732d5897SRichard Henderson if (off + size > s->frame_end) { 3723732d5897SRichard Henderson tcg_raise_tb_overflow(s); 3724732d5897SRichard Henderson } 3725c1c09194SRichard Henderson s->current_frame_offset = off + size; 37269defd1bdSRichard Henderson #if defined(__sparc__) 3727273eb50cSRichard Henderson off += TCG_TARGET_STACK_BIAS; 37289defd1bdSRichard Henderson #endif 3729273eb50cSRichard Henderson 3730273eb50cSRichard Henderson /* If the object was subdivided, assign memory to all the parts. */ 3731273eb50cSRichard Henderson if (ts->base_type != ts->type) { 3732273eb50cSRichard Henderson int part_size = tcg_type_size(ts->type); 3733273eb50cSRichard Henderson int part_count = size / part_size; 3734273eb50cSRichard Henderson 3735273eb50cSRichard Henderson /* 3736273eb50cSRichard Henderson * Each part is allocated sequentially in tcg_temp_new_internal. 3737273eb50cSRichard Henderson * Jump back to the first part by subtracting the current index. 3738273eb50cSRichard Henderson */ 3739273eb50cSRichard Henderson ts -= ts->temp_subindex; 3740273eb50cSRichard Henderson for (int i = 0; i < part_count; ++i) { 3741273eb50cSRichard Henderson ts[i].mem_offset = off + i * part_size; 3742273eb50cSRichard Henderson ts[i].mem_base = s->frame_temp; 3743273eb50cSRichard Henderson ts[i].mem_allocated = 1; 3744273eb50cSRichard Henderson } 3745273eb50cSRichard Henderson } else { 3746273eb50cSRichard Henderson ts->mem_offset = off; 3747b3a62939SRichard Henderson ts->mem_base = s->frame_temp; 3748c896fe29Sbellard ts->mem_allocated = 1; 3749c896fe29Sbellard } 3750273eb50cSRichard Henderson } 3751c896fe29Sbellard 3752098859f1SRichard Henderson /* Assign @reg to @ts, and update reg_to_temp[]. */ 3753098859f1SRichard Henderson static void set_temp_val_reg(TCGContext *s, TCGTemp *ts, TCGReg reg) 3754098859f1SRichard Henderson { 3755098859f1SRichard Henderson if (ts->val_type == TEMP_VAL_REG) { 3756098859f1SRichard Henderson TCGReg old = ts->reg; 3757098859f1SRichard Henderson tcg_debug_assert(s->reg_to_temp[old] == ts); 3758098859f1SRichard Henderson if (old == reg) { 3759098859f1SRichard Henderson return; 3760098859f1SRichard Henderson } 3761098859f1SRichard Henderson s->reg_to_temp[old] = NULL; 3762098859f1SRichard Henderson } 3763098859f1SRichard Henderson tcg_debug_assert(s->reg_to_temp[reg] == NULL); 3764098859f1SRichard Henderson s->reg_to_temp[reg] = ts; 3765098859f1SRichard Henderson ts->val_type = TEMP_VAL_REG; 3766098859f1SRichard Henderson ts->reg = reg; 3767098859f1SRichard Henderson } 3768098859f1SRichard Henderson 3769098859f1SRichard Henderson /* Assign a non-register value type to @ts, and update reg_to_temp[]. */ 3770098859f1SRichard Henderson static void set_temp_val_nonreg(TCGContext *s, TCGTemp *ts, TCGTempVal type) 3771098859f1SRichard Henderson { 3772098859f1SRichard Henderson tcg_debug_assert(type != TEMP_VAL_REG); 3773098859f1SRichard Henderson if (ts->val_type == TEMP_VAL_REG) { 3774098859f1SRichard Henderson TCGReg reg = ts->reg; 3775098859f1SRichard Henderson tcg_debug_assert(s->reg_to_temp[reg] == ts); 3776098859f1SRichard Henderson s->reg_to_temp[reg] = NULL; 3777098859f1SRichard Henderson } 3778098859f1SRichard Henderson ts->val_type = type; 3779098859f1SRichard Henderson } 3780098859f1SRichard Henderson 3781b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet); 3782b3915dbbSRichard Henderson 378359d7c14eSRichard Henderson /* Mark a temporary as free or dead. If 'free_or_dead' is negative, 378459d7c14eSRichard Henderson mark it free; otherwise mark it dead. */ 378559d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead) 3786c896fe29Sbellard { 3787c0522136SRichard Henderson TCGTempVal new_type; 3788c0522136SRichard Henderson 3789c0522136SRichard Henderson switch (ts->kind) { 3790c0522136SRichard Henderson case TEMP_FIXED: 379159d7c14eSRichard Henderson return; 3792c0522136SRichard Henderson case TEMP_GLOBAL: 3793f57c6915SRichard Henderson case TEMP_TB: 3794c0522136SRichard Henderson new_type = TEMP_VAL_MEM; 3795c0522136SRichard Henderson break; 3796c7482438SRichard Henderson case TEMP_EBB: 3797c0522136SRichard Henderson new_type = free_or_dead < 0 ? TEMP_VAL_MEM : TEMP_VAL_DEAD; 3798c0522136SRichard Henderson break; 3799c0522136SRichard Henderson case TEMP_CONST: 3800c0522136SRichard Henderson new_type = TEMP_VAL_CONST; 3801c0522136SRichard Henderson break; 3802c0522136SRichard Henderson default: 3803c0522136SRichard Henderson g_assert_not_reached(); 380459d7c14eSRichard Henderson } 3805098859f1SRichard Henderson set_temp_val_nonreg(s, ts, new_type); 380659d7c14eSRichard Henderson } 3807c896fe29Sbellard 380859d7c14eSRichard Henderson /* Mark a temporary as dead. */ 380959d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts) 381059d7c14eSRichard Henderson { 381159d7c14eSRichard Henderson temp_free_or_dead(s, ts, 1); 381259d7c14eSRichard Henderson } 381359d7c14eSRichard Henderson 381459d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary 381559d7c14eSRichard Henderson registers needs to be allocated to store a constant. If 'free_or_dead' 381659d7c14eSRichard Henderson is non-zero, subsequently release the temporary; if it is positive, the 381759d7c14eSRichard Henderson temp is dead; if it is negative, the temp is free. */ 381898b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs, 381998b4e186SRichard Henderson TCGRegSet preferred_regs, int free_or_dead) 382059d7c14eSRichard Henderson { 3821c0522136SRichard Henderson if (!temp_readonly(ts) && !ts->mem_coherent) { 38227f6ceedfSAurelien Jarno if (!ts->mem_allocated) { 38232272e4a7SRichard Henderson temp_allocate_frame(s, ts); 382459d7c14eSRichard Henderson } 382559d7c14eSRichard Henderson switch (ts->val_type) { 382659d7c14eSRichard Henderson case TEMP_VAL_CONST: 382759d7c14eSRichard Henderson /* If we're going to free the temp immediately, then we won't 382859d7c14eSRichard Henderson require it later in a register, so attempt to store the 382959d7c14eSRichard Henderson constant to memory directly. */ 383059d7c14eSRichard Henderson if (free_or_dead 383159d7c14eSRichard Henderson && tcg_out_sti(s, ts->type, ts->val, 383259d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset)) { 383359d7c14eSRichard Henderson break; 383459d7c14eSRichard Henderson } 383559d7c14eSRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 383698b4e186SRichard Henderson allocated_regs, preferred_regs); 383759d7c14eSRichard Henderson /* fallthrough */ 383859d7c14eSRichard Henderson 383959d7c14eSRichard Henderson case TEMP_VAL_REG: 384059d7c14eSRichard Henderson tcg_out_st(s, ts->type, ts->reg, 384159d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset); 384259d7c14eSRichard Henderson break; 384359d7c14eSRichard Henderson 384459d7c14eSRichard Henderson case TEMP_VAL_MEM: 384559d7c14eSRichard Henderson break; 384659d7c14eSRichard Henderson 384759d7c14eSRichard Henderson case TEMP_VAL_DEAD: 384859d7c14eSRichard Henderson default: 3849732e89f4SRichard Henderson g_assert_not_reached(); 3850c896fe29Sbellard } 38517f6ceedfSAurelien Jarno ts->mem_coherent = 1; 38527f6ceedfSAurelien Jarno } 385359d7c14eSRichard Henderson if (free_or_dead) { 385459d7c14eSRichard Henderson temp_free_or_dead(s, ts, free_or_dead); 385559d7c14eSRichard Henderson } 385659d7c14eSRichard Henderson } 38577f6ceedfSAurelien Jarno 38587f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */ 3859b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs) 38607f6ceedfSAurelien Jarno { 3861f8b2f202SRichard Henderson TCGTemp *ts = s->reg_to_temp[reg]; 3862f8b2f202SRichard Henderson if (ts != NULL) { 386398b4e186SRichard Henderson temp_sync(s, ts, allocated_regs, 0, -1); 3864c896fe29Sbellard } 3865c896fe29Sbellard } 3866c896fe29Sbellard 3867b016486eSRichard Henderson /** 3868b016486eSRichard Henderson * tcg_reg_alloc: 3869b016486eSRichard Henderson * @required_regs: Set of registers in which we must allocate. 3870b016486eSRichard Henderson * @allocated_regs: Set of registers which must be avoided. 3871b016486eSRichard Henderson * @preferred_regs: Set of registers we should prefer. 3872b016486eSRichard Henderson * @rev: True if we search the registers in "indirect" order. 3873b016486eSRichard Henderson * 3874b016486eSRichard Henderson * The allocated register must be in @required_regs & ~@allocated_regs, 3875b016486eSRichard Henderson * but if we can put it in @preferred_regs we may save a move later. 3876b016486eSRichard Henderson */ 3877b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs, 3878b016486eSRichard Henderson TCGRegSet allocated_regs, 3879b016486eSRichard Henderson TCGRegSet preferred_regs, bool rev) 3880c896fe29Sbellard { 3881b016486eSRichard Henderson int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order); 3882b016486eSRichard Henderson TCGRegSet reg_ct[2]; 388391478cefSRichard Henderson const int *order; 3884c896fe29Sbellard 3885b016486eSRichard Henderson reg_ct[1] = required_regs & ~allocated_regs; 3886b016486eSRichard Henderson tcg_debug_assert(reg_ct[1] != 0); 3887b016486eSRichard Henderson reg_ct[0] = reg_ct[1] & preferred_regs; 3888b016486eSRichard Henderson 3889b016486eSRichard Henderson /* Skip the preferred_regs option if it cannot be satisfied, 3890b016486eSRichard Henderson or if the preference made no difference. */ 3891b016486eSRichard Henderson f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1]; 3892b016486eSRichard Henderson 389391478cefSRichard Henderson order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order; 3894c896fe29Sbellard 3895b016486eSRichard Henderson /* Try free registers, preferences first. */ 3896b016486eSRichard Henderson for (j = f; j < 2; j++) { 3897b016486eSRichard Henderson TCGRegSet set = reg_ct[j]; 3898b016486eSRichard Henderson 3899b016486eSRichard Henderson if (tcg_regset_single(set)) { 3900b016486eSRichard Henderson /* One register in the set. */ 3901b016486eSRichard Henderson TCGReg reg = tcg_regset_first(set); 3902b016486eSRichard Henderson if (s->reg_to_temp[reg] == NULL) { 3903c896fe29Sbellard return reg; 3904c896fe29Sbellard } 3905b016486eSRichard Henderson } else { 390691478cefSRichard Henderson for (i = 0; i < n; i++) { 3907b016486eSRichard Henderson TCGReg reg = order[i]; 3908b016486eSRichard Henderson if (s->reg_to_temp[reg] == NULL && 3909b016486eSRichard Henderson tcg_regset_test_reg(set, reg)) { 3910b016486eSRichard Henderson return reg; 3911b016486eSRichard Henderson } 3912b016486eSRichard Henderson } 3913b016486eSRichard Henderson } 3914b016486eSRichard Henderson } 3915b016486eSRichard Henderson 3916b016486eSRichard Henderson /* We must spill something. */ 3917b016486eSRichard Henderson for (j = f; j < 2; j++) { 3918b016486eSRichard Henderson TCGRegSet set = reg_ct[j]; 3919b016486eSRichard Henderson 3920b016486eSRichard Henderson if (tcg_regset_single(set)) { 3921b016486eSRichard Henderson /* One register in the set. */ 3922b016486eSRichard Henderson TCGReg reg = tcg_regset_first(set); 3923b3915dbbSRichard Henderson tcg_reg_free(s, reg, allocated_regs); 3924c896fe29Sbellard return reg; 3925b016486eSRichard Henderson } else { 3926b016486eSRichard Henderson for (i = 0; i < n; i++) { 3927b016486eSRichard Henderson TCGReg reg = order[i]; 3928b016486eSRichard Henderson if (tcg_regset_test_reg(set, reg)) { 3929b016486eSRichard Henderson tcg_reg_free(s, reg, allocated_regs); 3930b016486eSRichard Henderson return reg; 3931b016486eSRichard Henderson } 3932b016486eSRichard Henderson } 3933c896fe29Sbellard } 3934c896fe29Sbellard } 3935c896fe29Sbellard 3936732e89f4SRichard Henderson g_assert_not_reached(); 3937c896fe29Sbellard } 3938c896fe29Sbellard 393929f5e925SRichard Henderson static TCGReg tcg_reg_alloc_pair(TCGContext *s, TCGRegSet required_regs, 394029f5e925SRichard Henderson TCGRegSet allocated_regs, 394129f5e925SRichard Henderson TCGRegSet preferred_regs, bool rev) 394229f5e925SRichard Henderson { 394329f5e925SRichard Henderson int i, j, k, fmin, n = ARRAY_SIZE(tcg_target_reg_alloc_order); 394429f5e925SRichard Henderson TCGRegSet reg_ct[2]; 394529f5e925SRichard Henderson const int *order; 394629f5e925SRichard Henderson 394729f5e925SRichard Henderson /* Ensure that if I is not in allocated_regs, I+1 is not either. */ 394829f5e925SRichard Henderson reg_ct[1] = required_regs & ~(allocated_regs | (allocated_regs >> 1)); 394929f5e925SRichard Henderson tcg_debug_assert(reg_ct[1] != 0); 395029f5e925SRichard Henderson reg_ct[0] = reg_ct[1] & preferred_regs; 395129f5e925SRichard Henderson 395229f5e925SRichard Henderson order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order; 395329f5e925SRichard Henderson 395429f5e925SRichard Henderson /* 395529f5e925SRichard Henderson * Skip the preferred_regs option if it cannot be satisfied, 395629f5e925SRichard Henderson * or if the preference made no difference. 395729f5e925SRichard Henderson */ 395829f5e925SRichard Henderson k = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1]; 395929f5e925SRichard Henderson 396029f5e925SRichard Henderson /* 396129f5e925SRichard Henderson * Minimize the number of flushes by looking for 2 free registers first, 396229f5e925SRichard Henderson * then a single flush, then two flushes. 396329f5e925SRichard Henderson */ 396429f5e925SRichard Henderson for (fmin = 2; fmin >= 0; fmin--) { 396529f5e925SRichard Henderson for (j = k; j < 2; j++) { 396629f5e925SRichard Henderson TCGRegSet set = reg_ct[j]; 396729f5e925SRichard Henderson 396829f5e925SRichard Henderson for (i = 0; i < n; i++) { 396929f5e925SRichard Henderson TCGReg reg = order[i]; 397029f5e925SRichard Henderson 397129f5e925SRichard Henderson if (tcg_regset_test_reg(set, reg)) { 397229f5e925SRichard Henderson int f = !s->reg_to_temp[reg] + !s->reg_to_temp[reg + 1]; 397329f5e925SRichard Henderson if (f >= fmin) { 397429f5e925SRichard Henderson tcg_reg_free(s, reg, allocated_regs); 397529f5e925SRichard Henderson tcg_reg_free(s, reg + 1, allocated_regs); 397629f5e925SRichard Henderson return reg; 397729f5e925SRichard Henderson } 397829f5e925SRichard Henderson } 397929f5e925SRichard Henderson } 398029f5e925SRichard Henderson } 398129f5e925SRichard Henderson } 3982732e89f4SRichard Henderson g_assert_not_reached(); 398329f5e925SRichard Henderson } 398429f5e925SRichard Henderson 398540ae5c62SRichard Henderson /* Make sure the temporary is in a register. If needed, allocate the register 398640ae5c62SRichard Henderson from DESIRED while avoiding ALLOCATED. */ 398740ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs, 3988b722452aSRichard Henderson TCGRegSet allocated_regs, TCGRegSet preferred_regs) 398940ae5c62SRichard Henderson { 399040ae5c62SRichard Henderson TCGReg reg; 399140ae5c62SRichard Henderson 399240ae5c62SRichard Henderson switch (ts->val_type) { 399340ae5c62SRichard Henderson case TEMP_VAL_REG: 399440ae5c62SRichard Henderson return; 399540ae5c62SRichard Henderson case TEMP_VAL_CONST: 3996b016486eSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs, 3997b722452aSRichard Henderson preferred_regs, ts->indirect_base); 39980a6a8bc8SRichard Henderson if (ts->type <= TCG_TYPE_I64) { 399940ae5c62SRichard Henderson tcg_out_movi(s, ts->type, reg, ts->val); 40000a6a8bc8SRichard Henderson } else { 40014e186175SRichard Henderson uint64_t val = ts->val; 40024e186175SRichard Henderson MemOp vece = MO_64; 40034e186175SRichard Henderson 40044e186175SRichard Henderson /* 40054e186175SRichard Henderson * Find the minimal vector element that matches the constant. 40064e186175SRichard Henderson * The targets will, in general, have to do this search anyway, 40074e186175SRichard Henderson * do this generically. 40084e186175SRichard Henderson */ 40094e186175SRichard Henderson if (val == dup_const(MO_8, val)) { 40104e186175SRichard Henderson vece = MO_8; 40114e186175SRichard Henderson } else if (val == dup_const(MO_16, val)) { 40124e186175SRichard Henderson vece = MO_16; 40130b4286ddSRichard Henderson } else if (val == dup_const(MO_32, val)) { 40144e186175SRichard Henderson vece = MO_32; 40154e186175SRichard Henderson } 40164e186175SRichard Henderson 40174e186175SRichard Henderson tcg_out_dupi_vec(s, ts->type, vece, reg, ts->val); 40180a6a8bc8SRichard Henderson } 401940ae5c62SRichard Henderson ts->mem_coherent = 0; 402040ae5c62SRichard Henderson break; 402140ae5c62SRichard Henderson case TEMP_VAL_MEM: 4022b016486eSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs, 4023b722452aSRichard Henderson preferred_regs, ts->indirect_base); 402440ae5c62SRichard Henderson tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset); 402540ae5c62SRichard Henderson ts->mem_coherent = 1; 402640ae5c62SRichard Henderson break; 402740ae5c62SRichard Henderson case TEMP_VAL_DEAD: 402840ae5c62SRichard Henderson default: 4029732e89f4SRichard Henderson g_assert_not_reached(); 403040ae5c62SRichard Henderson } 4031098859f1SRichard Henderson set_temp_val_reg(s, ts, reg); 403240ae5c62SRichard Henderson } 403340ae5c62SRichard Henderson 403459d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a 4035e8996ee0Sbellard temporary registers needs to be allocated to store a constant. */ 403659d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs) 40371ad80729SAurelien Jarno { 40382c0366f0SAurelien Jarno /* The liveness analysis already ensures that globals are back 4039eabb7b91SAurelien Jarno in memory. Keep an tcg_debug_assert for safety. */ 4040e01fa97dSRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || temp_readonly(ts)); 40411ad80729SAurelien Jarno } 40421ad80729SAurelien Jarno 40439814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be 4044641d5fbeSbellard modified be the following code. 'allocated_regs' is used in case a 4045641d5fbeSbellard temporary registers needs to be allocated to store a constant. */ 4046641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs) 4047641d5fbeSbellard { 4048ac3b8891SRichard Henderson int i, n; 4049641d5fbeSbellard 4050ac3b8891SRichard Henderson for (i = 0, n = s->nb_globals; i < n; i++) { 4051b13eb728SRichard Henderson temp_save(s, &s->temps[i], allocated_regs); 4052641d5fbeSbellard } 4053e5097dc8Sbellard } 4054e5097dc8Sbellard 40553d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be 40563d5c5f87SAurelien Jarno read by the following code. 'allocated_regs' is used in case a 40573d5c5f87SAurelien Jarno temporary registers needs to be allocated to store a constant. */ 40583d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs) 40593d5c5f87SAurelien Jarno { 4060ac3b8891SRichard Henderson int i, n; 40613d5c5f87SAurelien Jarno 4062ac3b8891SRichard Henderson for (i = 0, n = s->nb_globals; i < n; i++) { 406312b9b11aSRichard Henderson TCGTemp *ts = &s->temps[i]; 406412b9b11aSRichard Henderson tcg_debug_assert(ts->val_type != TEMP_VAL_REG 4065ee17db83SRichard Henderson || ts->kind == TEMP_FIXED 406612b9b11aSRichard Henderson || ts->mem_coherent); 40673d5c5f87SAurelien Jarno } 40683d5c5f87SAurelien Jarno } 40693d5c5f87SAurelien Jarno 4070e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and 4071e8996ee0Sbellard all globals are stored at their canonical location. */ 4072e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs) 4073e5097dc8Sbellard { 4074e5097dc8Sbellard int i; 4075e5097dc8Sbellard 4076c896fe29Sbellard for (i = s->nb_globals; i < s->nb_temps; i++) { 4077b13eb728SRichard Henderson TCGTemp *ts = &s->temps[i]; 4078c0522136SRichard Henderson 4079c0522136SRichard Henderson switch (ts->kind) { 4080f57c6915SRichard Henderson case TEMP_TB: 4081b13eb728SRichard Henderson temp_save(s, ts, allocated_regs); 4082c0522136SRichard Henderson break; 4083c7482438SRichard Henderson case TEMP_EBB: 40842c0366f0SAurelien Jarno /* The liveness analysis already ensures that temps are dead. 4085eabb7b91SAurelien Jarno Keep an tcg_debug_assert for safety. */ 4086eabb7b91SAurelien Jarno tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD); 4087c0522136SRichard Henderson break; 4088c0522136SRichard Henderson case TEMP_CONST: 4089c0522136SRichard Henderson /* Similarly, we should have freed any allocated register. */ 4090c0522136SRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_CONST); 4091c0522136SRichard Henderson break; 4092c0522136SRichard Henderson default: 4093c0522136SRichard Henderson g_assert_not_reached(); 4094c896fe29Sbellard } 4095641d5fbeSbellard } 4096e8996ee0Sbellard 4097e8996ee0Sbellard save_globals(s, allocated_regs); 4098c896fe29Sbellard } 4099c896fe29Sbellard 4100bab1671fSRichard Henderson /* 4101c7482438SRichard Henderson * At a conditional branch, we assume all temporaries are dead unless 4102c7482438SRichard Henderson * explicitly live-across-conditional-branch; all globals and local 4103c7482438SRichard Henderson * temps are synced to their location. 4104b4cb76e6SRichard Henderson */ 4105b4cb76e6SRichard Henderson static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs) 4106b4cb76e6SRichard Henderson { 4107b4cb76e6SRichard Henderson sync_globals(s, allocated_regs); 4108b4cb76e6SRichard Henderson 4109b4cb76e6SRichard Henderson for (int i = s->nb_globals; i < s->nb_temps; i++) { 4110b4cb76e6SRichard Henderson TCGTemp *ts = &s->temps[i]; 4111b4cb76e6SRichard Henderson /* 4112b4cb76e6SRichard Henderson * The liveness analysis already ensures that temps are dead. 4113b4cb76e6SRichard Henderson * Keep tcg_debug_asserts for safety. 4114b4cb76e6SRichard Henderson */ 4115c0522136SRichard Henderson switch (ts->kind) { 4116f57c6915SRichard Henderson case TEMP_TB: 4117b4cb76e6SRichard Henderson tcg_debug_assert(ts->val_type != TEMP_VAL_REG || ts->mem_coherent); 4118c0522136SRichard Henderson break; 4119c7482438SRichard Henderson case TEMP_EBB: 4120c0522136SRichard Henderson case TEMP_CONST: 4121c0522136SRichard Henderson break; 4122c0522136SRichard Henderson default: 4123c0522136SRichard Henderson g_assert_not_reached(); 4124b4cb76e6SRichard Henderson } 4125b4cb76e6SRichard Henderson } 4126b4cb76e6SRichard Henderson } 4127b4cb76e6SRichard Henderson 4128b4cb76e6SRichard Henderson /* 4129c58f4c97SRichard Henderson * Specialized code generation for INDEX_op_mov_* with a constant. 4130bab1671fSRichard Henderson */ 41310fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots, 4132ba87719cSRichard Henderson tcg_target_ulong val, TCGLifeData arg_life, 4133ba87719cSRichard Henderson TCGRegSet preferred_regs) 4134e8996ee0Sbellard { 4135d63e3b6eSRichard Henderson /* ENV should not be modified. */ 4136e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 413759d7c14eSRichard Henderson 413859d7c14eSRichard Henderson /* The movi is not explicitly generated here. */ 4139098859f1SRichard Henderson set_temp_val_nonreg(s, ots, TEMP_VAL_CONST); 4140e8996ee0Sbellard ots->val = val; 414159d7c14eSRichard Henderson ots->mem_coherent = 0; 4142ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) { 4143ba87719cSRichard Henderson temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0)); 414459d7c14eSRichard Henderson } else if (IS_DEAD_ARG(0)) { 4145f8bf00f1SRichard Henderson temp_dead(s, ots); 41464c4e1ab2SAurelien Jarno } 4147e8996ee0Sbellard } 4148e8996ee0Sbellard 4149bab1671fSRichard Henderson /* 4150bab1671fSRichard Henderson * Specialized code generation for INDEX_op_mov_*. 4151bab1671fSRichard Henderson */ 4152dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op) 4153c896fe29Sbellard { 4154dd186292SRichard Henderson const TCGLifeData arg_life = op->life; 415569e3706dSRichard Henderson TCGRegSet allocated_regs, preferred_regs; 4156c896fe29Sbellard TCGTemp *ts, *ots; 4157450445d5SRichard Henderson TCGType otype, itype; 4158098859f1SRichard Henderson TCGReg oreg, ireg; 4159c896fe29Sbellard 4160d21369f5SRichard Henderson allocated_regs = s->reserved_regs; 416131fd884bSRichard Henderson preferred_regs = output_pref(op, 0); 416243439139SRichard Henderson ots = arg_temp(op->args[0]); 416343439139SRichard Henderson ts = arg_temp(op->args[1]); 4164450445d5SRichard Henderson 4165d63e3b6eSRichard Henderson /* ENV should not be modified. */ 4166e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 4167d63e3b6eSRichard Henderson 4168450445d5SRichard Henderson /* Note that otype != itype for no-op truncation. */ 4169450445d5SRichard Henderson otype = ots->type; 4170450445d5SRichard Henderson itype = ts->type; 4171c896fe29Sbellard 41720fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_CONST) { 41730fe4fca4SPaolo Bonzini /* propagate constant or generate sti */ 41740fe4fca4SPaolo Bonzini tcg_target_ulong val = ts->val; 41750fe4fca4SPaolo Bonzini if (IS_DEAD_ARG(1)) { 41760fe4fca4SPaolo Bonzini temp_dead(s, ts); 41770fe4fca4SPaolo Bonzini } 417869e3706dSRichard Henderson tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs); 41790fe4fca4SPaolo Bonzini return; 41800fe4fca4SPaolo Bonzini } 41810fe4fca4SPaolo Bonzini 41820fe4fca4SPaolo Bonzini /* If the source value is in memory we're going to be forced 41830fe4fca4SPaolo Bonzini to have it in a register in order to perform the copy. Copy 41840fe4fca4SPaolo Bonzini the SOURCE value into its own register first, that way we 41850fe4fca4SPaolo Bonzini don't have to reload SOURCE the next time it is used. */ 41860fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_MEM) { 418769e3706dSRichard Henderson temp_load(s, ts, tcg_target_available_regs[itype], 418869e3706dSRichard Henderson allocated_regs, preferred_regs); 4189c29c1d7eSAurelien Jarno } 41900fe4fca4SPaolo Bonzini tcg_debug_assert(ts->val_type == TEMP_VAL_REG); 4191098859f1SRichard Henderson ireg = ts->reg; 4192098859f1SRichard Henderson 4193d63e3b6eSRichard Henderson if (IS_DEAD_ARG(0)) { 4194c29c1d7eSAurelien Jarno /* mov to a non-saved dead register makes no sense (even with 4195c29c1d7eSAurelien Jarno liveness analysis disabled). */ 4196eabb7b91SAurelien Jarno tcg_debug_assert(NEED_SYNC_ARG(0)); 4197c29c1d7eSAurelien Jarno if (!ots->mem_allocated) { 41982272e4a7SRichard Henderson temp_allocate_frame(s, ots); 4199c29c1d7eSAurelien Jarno } 4200098859f1SRichard Henderson tcg_out_st(s, otype, ireg, ots->mem_base->reg, ots->mem_offset); 4201c29c1d7eSAurelien Jarno if (IS_DEAD_ARG(1)) { 4202f8bf00f1SRichard Henderson temp_dead(s, ts); 4203c29c1d7eSAurelien Jarno } 4204f8bf00f1SRichard Henderson temp_dead(s, ots); 4205098859f1SRichard Henderson return; 4206098859f1SRichard Henderson } 4207098859f1SRichard Henderson 4208ee17db83SRichard Henderson if (IS_DEAD_ARG(1) && ts->kind != TEMP_FIXED) { 4209098859f1SRichard Henderson /* 4210098859f1SRichard Henderson * The mov can be suppressed. Kill input first, so that it 4211098859f1SRichard Henderson * is unlinked from reg_to_temp, then set the output to the 4212098859f1SRichard Henderson * reg that we saved from the input. 4213098859f1SRichard Henderson */ 4214f8bf00f1SRichard Henderson temp_dead(s, ts); 4215098859f1SRichard Henderson oreg = ireg; 4216c29c1d7eSAurelien Jarno } else { 4217098859f1SRichard Henderson if (ots->val_type == TEMP_VAL_REG) { 4218098859f1SRichard Henderson oreg = ots->reg; 4219098859f1SRichard Henderson } else { 4220098859f1SRichard Henderson /* Make sure to not spill the input register during allocation. */ 4221098859f1SRichard Henderson oreg = tcg_reg_alloc(s, tcg_target_available_regs[otype], 4222098859f1SRichard Henderson allocated_regs | ((TCGRegSet)1 << ireg), 4223098859f1SRichard Henderson preferred_regs, ots->indirect_base); 4224c29c1d7eSAurelien Jarno } 4225098859f1SRichard Henderson if (!tcg_out_mov(s, otype, oreg, ireg)) { 4226240c08d0SRichard Henderson /* 4227240c08d0SRichard Henderson * Cross register class move not supported. 4228240c08d0SRichard Henderson * Store the source register into the destination slot 4229240c08d0SRichard Henderson * and leave the destination temp as TEMP_VAL_MEM. 4230240c08d0SRichard Henderson */ 4231e01fa97dSRichard Henderson assert(!temp_readonly(ots)); 4232240c08d0SRichard Henderson if (!ts->mem_allocated) { 4233240c08d0SRichard Henderson temp_allocate_frame(s, ots); 4234240c08d0SRichard Henderson } 4235098859f1SRichard Henderson tcg_out_st(s, ts->type, ireg, ots->mem_base->reg, ots->mem_offset); 4236098859f1SRichard Henderson set_temp_val_nonreg(s, ts, TEMP_VAL_MEM); 4237240c08d0SRichard Henderson ots->mem_coherent = 1; 4238240c08d0SRichard Henderson return; 423978113e83SRichard Henderson } 4240c29c1d7eSAurelien Jarno } 4241098859f1SRichard Henderson set_temp_val_reg(s, ots, oreg); 4242c896fe29Sbellard ots->mem_coherent = 0; 4243098859f1SRichard Henderson 4244ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) { 424598b4e186SRichard Henderson temp_sync(s, ots, allocated_regs, 0, 0); 4246c29c1d7eSAurelien Jarno } 4247ec7a869dSAurelien Jarno } 4248c896fe29Sbellard 4249bab1671fSRichard Henderson /* 4250bab1671fSRichard Henderson * Specialized code generation for INDEX_op_dup_vec. 4251bab1671fSRichard Henderson */ 4252bab1671fSRichard Henderson static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op) 4253bab1671fSRichard Henderson { 4254bab1671fSRichard Henderson const TCGLifeData arg_life = op->life; 4255bab1671fSRichard Henderson TCGRegSet dup_out_regs, dup_in_regs; 4256bab1671fSRichard Henderson TCGTemp *its, *ots; 4257bab1671fSRichard Henderson TCGType itype, vtype; 4258bab1671fSRichard Henderson unsigned vece; 425931c96417SRichard Henderson int lowpart_ofs; 4260bab1671fSRichard Henderson bool ok; 4261bab1671fSRichard Henderson 4262bab1671fSRichard Henderson ots = arg_temp(op->args[0]); 4263bab1671fSRichard Henderson its = arg_temp(op->args[1]); 4264bab1671fSRichard Henderson 4265bab1671fSRichard Henderson /* ENV should not be modified. */ 4266e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 4267bab1671fSRichard Henderson 4268bab1671fSRichard Henderson itype = its->type; 4269bab1671fSRichard Henderson vece = TCGOP_VECE(op); 4270bab1671fSRichard Henderson vtype = TCGOP_VECL(op) + TCG_TYPE_V64; 4271bab1671fSRichard Henderson 4272bab1671fSRichard Henderson if (its->val_type == TEMP_VAL_CONST) { 4273bab1671fSRichard Henderson /* Propagate constant via movi -> dupi. */ 4274bab1671fSRichard Henderson tcg_target_ulong val = its->val; 4275bab1671fSRichard Henderson if (IS_DEAD_ARG(1)) { 4276bab1671fSRichard Henderson temp_dead(s, its); 4277bab1671fSRichard Henderson } 427831fd884bSRichard Henderson tcg_reg_alloc_do_movi(s, ots, val, arg_life, output_pref(op, 0)); 4279bab1671fSRichard Henderson return; 4280bab1671fSRichard Henderson } 4281bab1671fSRichard Henderson 42829be0d080SRichard Henderson dup_out_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs; 42839be0d080SRichard Henderson dup_in_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[1].regs; 4284bab1671fSRichard Henderson 4285bab1671fSRichard Henderson /* Allocate the output register now. */ 4286bab1671fSRichard Henderson if (ots->val_type != TEMP_VAL_REG) { 4287bab1671fSRichard Henderson TCGRegSet allocated_regs = s->reserved_regs; 4288098859f1SRichard Henderson TCGReg oreg; 4289bab1671fSRichard Henderson 4290bab1671fSRichard Henderson if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) { 4291bab1671fSRichard Henderson /* Make sure to not spill the input register. */ 4292bab1671fSRichard Henderson tcg_regset_set_reg(allocated_regs, its->reg); 4293bab1671fSRichard Henderson } 4294098859f1SRichard Henderson oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs, 429531fd884bSRichard Henderson output_pref(op, 0), ots->indirect_base); 4296098859f1SRichard Henderson set_temp_val_reg(s, ots, oreg); 4297bab1671fSRichard Henderson } 4298bab1671fSRichard Henderson 4299bab1671fSRichard Henderson switch (its->val_type) { 4300bab1671fSRichard Henderson case TEMP_VAL_REG: 4301bab1671fSRichard Henderson /* 4302bab1671fSRichard Henderson * The dup constriaints must be broad, covering all possible VECE. 4303bab1671fSRichard Henderson * However, tcg_op_dup_vec() gets to see the VECE and we allow it 4304bab1671fSRichard Henderson * to fail, indicating that extra moves are required for that case. 4305bab1671fSRichard Henderson */ 4306bab1671fSRichard Henderson if (tcg_regset_test_reg(dup_in_regs, its->reg)) { 4307bab1671fSRichard Henderson if (tcg_out_dup_vec(s, vtype, vece, ots->reg, its->reg)) { 4308bab1671fSRichard Henderson goto done; 4309bab1671fSRichard Henderson } 4310bab1671fSRichard Henderson /* Try again from memory or a vector input register. */ 4311bab1671fSRichard Henderson } 4312bab1671fSRichard Henderson if (!its->mem_coherent) { 4313bab1671fSRichard Henderson /* 4314bab1671fSRichard Henderson * The input register is not synced, and so an extra store 4315bab1671fSRichard Henderson * would be required to use memory. Attempt an integer-vector 4316bab1671fSRichard Henderson * register move first. We do not have a TCGRegSet for this. 4317bab1671fSRichard Henderson */ 4318bab1671fSRichard Henderson if (tcg_out_mov(s, itype, ots->reg, its->reg)) { 4319bab1671fSRichard Henderson break; 4320bab1671fSRichard Henderson } 4321bab1671fSRichard Henderson /* Sync the temp back to its slot and load from there. */ 4322bab1671fSRichard Henderson temp_sync(s, its, s->reserved_regs, 0, 0); 4323bab1671fSRichard Henderson } 4324bab1671fSRichard Henderson /* fall through */ 4325bab1671fSRichard Henderson 4326bab1671fSRichard Henderson case TEMP_VAL_MEM: 432731c96417SRichard Henderson lowpart_ofs = 0; 432831c96417SRichard Henderson if (HOST_BIG_ENDIAN) { 432931c96417SRichard Henderson lowpart_ofs = tcg_type_size(itype) - (1 << vece); 433031c96417SRichard Henderson } 4331d6ecb4a9SRichard Henderson if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg, 433231c96417SRichard Henderson its->mem_offset + lowpart_ofs)) { 4333d6ecb4a9SRichard Henderson goto done; 4334d6ecb4a9SRichard Henderson } 4335098859f1SRichard Henderson /* Load the input into the destination vector register. */ 4336bab1671fSRichard Henderson tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset); 4337bab1671fSRichard Henderson break; 4338bab1671fSRichard Henderson 4339bab1671fSRichard Henderson default: 4340bab1671fSRichard Henderson g_assert_not_reached(); 4341bab1671fSRichard Henderson } 4342bab1671fSRichard Henderson 4343bab1671fSRichard Henderson /* We now have a vector input register, so dup must succeed. */ 4344bab1671fSRichard Henderson ok = tcg_out_dup_vec(s, vtype, vece, ots->reg, ots->reg); 4345bab1671fSRichard Henderson tcg_debug_assert(ok); 4346bab1671fSRichard Henderson 4347bab1671fSRichard Henderson done: 434836f5539cSRichard Henderson ots->mem_coherent = 0; 4349bab1671fSRichard Henderson if (IS_DEAD_ARG(1)) { 4350bab1671fSRichard Henderson temp_dead(s, its); 4351bab1671fSRichard Henderson } 4352bab1671fSRichard Henderson if (NEED_SYNC_ARG(0)) { 4353bab1671fSRichard Henderson temp_sync(s, ots, s->reserved_regs, 0, 0); 4354bab1671fSRichard Henderson } 4355bab1671fSRichard Henderson if (IS_DEAD_ARG(0)) { 4356bab1671fSRichard Henderson temp_dead(s, ots); 4357bab1671fSRichard Henderson } 4358bab1671fSRichard Henderson } 4359bab1671fSRichard Henderson 4360dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) 4361c896fe29Sbellard { 4362dd186292SRichard Henderson const TCGLifeData arg_life = op->life; 4363dd186292SRichard Henderson const TCGOpDef * const def = &tcg_op_defs[op->opc]; 436482790a87SRichard Henderson TCGRegSet i_allocated_regs; 436582790a87SRichard Henderson TCGRegSet o_allocated_regs; 4366b6638662SRichard Henderson int i, k, nb_iargs, nb_oargs; 4367b6638662SRichard Henderson TCGReg reg; 4368c896fe29Sbellard TCGArg arg; 4369c896fe29Sbellard const TCGArgConstraint *arg_ct; 4370c896fe29Sbellard TCGTemp *ts; 4371c896fe29Sbellard TCGArg new_args[TCG_MAX_OP_ARGS]; 4372c896fe29Sbellard int const_args[TCG_MAX_OP_ARGS]; 4373c896fe29Sbellard 4374c896fe29Sbellard nb_oargs = def->nb_oargs; 4375c896fe29Sbellard nb_iargs = def->nb_iargs; 4376c896fe29Sbellard 4377c896fe29Sbellard /* copy constants */ 4378c896fe29Sbellard memcpy(new_args + nb_oargs + nb_iargs, 4379dd186292SRichard Henderson op->args + nb_oargs + nb_iargs, 4380c896fe29Sbellard sizeof(TCGArg) * def->nb_cargs); 4381c896fe29Sbellard 4382d21369f5SRichard Henderson i_allocated_regs = s->reserved_regs; 4383d21369f5SRichard Henderson o_allocated_regs = s->reserved_regs; 438482790a87SRichard Henderson 4385c896fe29Sbellard /* satisfy input constraints */ 4386c896fe29Sbellard for (k = 0; k < nb_iargs; k++) { 438729f5e925SRichard Henderson TCGRegSet i_preferred_regs, i_required_regs; 438829f5e925SRichard Henderson bool allocate_new_reg, copyto_new_reg; 438929f5e925SRichard Henderson TCGTemp *ts2; 439029f5e925SRichard Henderson int i1, i2; 4391d62816f2SRichard Henderson 439266792f90SRichard Henderson i = def->args_ct[nb_oargs + k].sort_index; 4393dd186292SRichard Henderson arg = op->args[i]; 4394c896fe29Sbellard arg_ct = &def->args_ct[i]; 439543439139SRichard Henderson ts = arg_temp(arg); 439640ae5c62SRichard Henderson 439740ae5c62SRichard Henderson if (ts->val_type == TEMP_VAL_CONST 4398a4fbbd77SRichard Henderson && tcg_target_const_match(ts->val, ts->type, arg_ct->ct)) { 4399c896fe29Sbellard /* constant is OK for instruction */ 4400c896fe29Sbellard const_args[i] = 1; 4401c896fe29Sbellard new_args[i] = ts->val; 4402d62816f2SRichard Henderson continue; 4403c896fe29Sbellard } 440440ae5c62SRichard Henderson 44051c1824dcSRichard Henderson reg = ts->reg; 44061c1824dcSRichard Henderson i_preferred_regs = 0; 440729f5e925SRichard Henderson i_required_regs = arg_ct->regs; 44081c1824dcSRichard Henderson allocate_new_reg = false; 440929f5e925SRichard Henderson copyto_new_reg = false; 44101c1824dcSRichard Henderson 441129f5e925SRichard Henderson switch (arg_ct->pair) { 441229f5e925SRichard Henderson case 0: /* not paired */ 4413bc2b17e6SRichard Henderson if (arg_ct->ialias) { 441431fd884bSRichard Henderson i_preferred_regs = output_pref(op, arg_ct->alias_index); 4415c0522136SRichard Henderson 4416c0522136SRichard Henderson /* 4417c0522136SRichard Henderson * If the input is readonly, then it cannot also be an 4418c0522136SRichard Henderson * output and aliased to itself. If the input is not 4419c0522136SRichard Henderson * dead after the instruction, we must allocate a new 4420c0522136SRichard Henderson * register and move it. 4421c0522136SRichard Henderson */ 4422c0522136SRichard Henderson if (temp_readonly(ts) || !IS_DEAD_ARG(i)) { 44231c1824dcSRichard Henderson allocate_new_reg = true; 44241c1824dcSRichard Henderson } else if (ts->val_type == TEMP_VAL_REG) { 4425c0522136SRichard Henderson /* 44261c1824dcSRichard Henderson * Check if the current register has already been 44271c1824dcSRichard Henderson * allocated for another input. 4428c0522136SRichard Henderson */ 442929f5e925SRichard Henderson allocate_new_reg = 443029f5e925SRichard Henderson tcg_regset_test_reg(i_allocated_regs, reg); 44317e1df267SAurelien Jarno } 44327e1df267SAurelien Jarno } 44331c1824dcSRichard Henderson if (!allocate_new_reg) { 443429f5e925SRichard Henderson temp_load(s, ts, i_required_regs, i_allocated_regs, 443529f5e925SRichard Henderson i_preferred_regs); 4436c896fe29Sbellard reg = ts->reg; 443729f5e925SRichard Henderson allocate_new_reg = !tcg_regset_test_reg(i_required_regs, reg); 44381c1824dcSRichard Henderson } 44391c1824dcSRichard Henderson if (allocate_new_reg) { 4440c0522136SRichard Henderson /* 4441c0522136SRichard Henderson * Allocate a new register matching the constraint 4442c0522136SRichard Henderson * and move the temporary register into it. 4443c0522136SRichard Henderson */ 4444d62816f2SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 4445d62816f2SRichard Henderson i_allocated_regs, 0); 444629f5e925SRichard Henderson reg = tcg_reg_alloc(s, i_required_regs, i_allocated_regs, 44471c1824dcSRichard Henderson i_preferred_regs, ts->indirect_base); 444829f5e925SRichard Henderson copyto_new_reg = true; 444929f5e925SRichard Henderson } 445029f5e925SRichard Henderson break; 445129f5e925SRichard Henderson 445229f5e925SRichard Henderson case 1: 445329f5e925SRichard Henderson /* First of an input pair; if i1 == i2, the second is an output. */ 445429f5e925SRichard Henderson i1 = i; 445529f5e925SRichard Henderson i2 = arg_ct->pair_index; 445629f5e925SRichard Henderson ts2 = i1 != i2 ? arg_temp(op->args[i2]) : NULL; 445729f5e925SRichard Henderson 445829f5e925SRichard Henderson /* 445929f5e925SRichard Henderson * It is easier to default to allocating a new pair 446029f5e925SRichard Henderson * and to identify a few cases where it's not required. 446129f5e925SRichard Henderson */ 446229f5e925SRichard Henderson if (arg_ct->ialias) { 446331fd884bSRichard Henderson i_preferred_regs = output_pref(op, arg_ct->alias_index); 446429f5e925SRichard Henderson if (IS_DEAD_ARG(i1) && 446529f5e925SRichard Henderson IS_DEAD_ARG(i2) && 446629f5e925SRichard Henderson !temp_readonly(ts) && 446729f5e925SRichard Henderson ts->val_type == TEMP_VAL_REG && 446829f5e925SRichard Henderson ts->reg < TCG_TARGET_NB_REGS - 1 && 446929f5e925SRichard Henderson tcg_regset_test_reg(i_required_regs, reg) && 447029f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg) && 447129f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg + 1) && 447229f5e925SRichard Henderson (ts2 447329f5e925SRichard Henderson ? ts2->val_type == TEMP_VAL_REG && 447429f5e925SRichard Henderson ts2->reg == reg + 1 && 447529f5e925SRichard Henderson !temp_readonly(ts2) 447629f5e925SRichard Henderson : s->reg_to_temp[reg + 1] == NULL)) { 447729f5e925SRichard Henderson break; 447829f5e925SRichard Henderson } 447929f5e925SRichard Henderson } else { 448029f5e925SRichard Henderson /* Without aliasing, the pair must also be an input. */ 448129f5e925SRichard Henderson tcg_debug_assert(ts2); 448229f5e925SRichard Henderson if (ts->val_type == TEMP_VAL_REG && 448329f5e925SRichard Henderson ts2->val_type == TEMP_VAL_REG && 448429f5e925SRichard Henderson ts2->reg == reg + 1 && 448529f5e925SRichard Henderson tcg_regset_test_reg(i_required_regs, reg)) { 448629f5e925SRichard Henderson break; 448729f5e925SRichard Henderson } 448829f5e925SRichard Henderson } 448929f5e925SRichard Henderson reg = tcg_reg_alloc_pair(s, i_required_regs, i_allocated_regs, 449029f5e925SRichard Henderson 0, ts->indirect_base); 449129f5e925SRichard Henderson goto do_pair; 449229f5e925SRichard Henderson 449329f5e925SRichard Henderson case 2: /* pair second */ 449429f5e925SRichard Henderson reg = new_args[arg_ct->pair_index] + 1; 449529f5e925SRichard Henderson goto do_pair; 449629f5e925SRichard Henderson 449729f5e925SRichard Henderson case 3: /* ialias with second output, no first input */ 449829f5e925SRichard Henderson tcg_debug_assert(arg_ct->ialias); 449931fd884bSRichard Henderson i_preferred_regs = output_pref(op, arg_ct->alias_index); 450029f5e925SRichard Henderson 450129f5e925SRichard Henderson if (IS_DEAD_ARG(i) && 450229f5e925SRichard Henderson !temp_readonly(ts) && 450329f5e925SRichard Henderson ts->val_type == TEMP_VAL_REG && 450429f5e925SRichard Henderson reg > 0 && 450529f5e925SRichard Henderson s->reg_to_temp[reg - 1] == NULL && 450629f5e925SRichard Henderson tcg_regset_test_reg(i_required_regs, reg) && 450729f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg) && 450829f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg - 1)) { 450929f5e925SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg - 1); 451029f5e925SRichard Henderson break; 451129f5e925SRichard Henderson } 451229f5e925SRichard Henderson reg = tcg_reg_alloc_pair(s, i_required_regs >> 1, 451329f5e925SRichard Henderson i_allocated_regs, 0, 451429f5e925SRichard Henderson ts->indirect_base); 451529f5e925SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg); 451629f5e925SRichard Henderson reg += 1; 451729f5e925SRichard Henderson goto do_pair; 451829f5e925SRichard Henderson 451929f5e925SRichard Henderson do_pair: 452029f5e925SRichard Henderson /* 452129f5e925SRichard Henderson * If an aliased input is not dead after the instruction, 452229f5e925SRichard Henderson * we must allocate a new register and move it. 452329f5e925SRichard Henderson */ 452429f5e925SRichard Henderson if (arg_ct->ialias && (!IS_DEAD_ARG(i) || temp_readonly(ts))) { 452529f5e925SRichard Henderson TCGRegSet t_allocated_regs = i_allocated_regs; 452629f5e925SRichard Henderson 452729f5e925SRichard Henderson /* 452829f5e925SRichard Henderson * Because of the alias, and the continued life, make sure 452929f5e925SRichard Henderson * that the temp is somewhere *other* than the reg pair, 453029f5e925SRichard Henderson * and we get a copy in reg. 453129f5e925SRichard Henderson */ 453229f5e925SRichard Henderson tcg_regset_set_reg(t_allocated_regs, reg); 453329f5e925SRichard Henderson tcg_regset_set_reg(t_allocated_regs, reg + 1); 453429f5e925SRichard Henderson if (ts->val_type == TEMP_VAL_REG && ts->reg == reg) { 453529f5e925SRichard Henderson /* If ts was already in reg, copy it somewhere else. */ 453629f5e925SRichard Henderson TCGReg nr; 453729f5e925SRichard Henderson bool ok; 453829f5e925SRichard Henderson 453929f5e925SRichard Henderson tcg_debug_assert(ts->kind != TEMP_FIXED); 454029f5e925SRichard Henderson nr = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], 454129f5e925SRichard Henderson t_allocated_regs, 0, ts->indirect_base); 454229f5e925SRichard Henderson ok = tcg_out_mov(s, ts->type, nr, reg); 454329f5e925SRichard Henderson tcg_debug_assert(ok); 454429f5e925SRichard Henderson 454529f5e925SRichard Henderson set_temp_val_reg(s, ts, nr); 454629f5e925SRichard Henderson } else { 454729f5e925SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 454829f5e925SRichard Henderson t_allocated_regs, 0); 454929f5e925SRichard Henderson copyto_new_reg = true; 455029f5e925SRichard Henderson } 455129f5e925SRichard Henderson } else { 455229f5e925SRichard Henderson /* Preferably allocate to reg, otherwise copy. */ 455329f5e925SRichard Henderson i_required_regs = (TCGRegSet)1 << reg; 455429f5e925SRichard Henderson temp_load(s, ts, i_required_regs, i_allocated_regs, 455529f5e925SRichard Henderson i_preferred_regs); 455629f5e925SRichard Henderson copyto_new_reg = ts->reg != reg; 455729f5e925SRichard Henderson } 455829f5e925SRichard Henderson break; 455929f5e925SRichard Henderson 456029f5e925SRichard Henderson default: 456129f5e925SRichard Henderson g_assert_not_reached(); 456229f5e925SRichard Henderson } 456329f5e925SRichard Henderson 456429f5e925SRichard Henderson if (copyto_new_reg) { 456578113e83SRichard Henderson if (!tcg_out_mov(s, ts->type, reg, ts->reg)) { 4566240c08d0SRichard Henderson /* 4567240c08d0SRichard Henderson * Cross register class move not supported. Sync the 4568240c08d0SRichard Henderson * temp back to its slot and load from there. 4569240c08d0SRichard Henderson */ 4570240c08d0SRichard Henderson temp_sync(s, ts, i_allocated_regs, 0, 0); 4571240c08d0SRichard Henderson tcg_out_ld(s, ts->type, reg, 4572240c08d0SRichard Henderson ts->mem_base->reg, ts->mem_offset); 457378113e83SRichard Henderson } 4574c896fe29Sbellard } 4575c896fe29Sbellard new_args[i] = reg; 4576c896fe29Sbellard const_args[i] = 0; 457782790a87SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg); 4578c896fe29Sbellard } 4579c896fe29Sbellard 4580c896fe29Sbellard /* mark dead temporaries and free the associated registers */ 4581866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 4582866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) { 458343439139SRichard Henderson temp_dead(s, arg_temp(op->args[i])); 4584c896fe29Sbellard } 4585c896fe29Sbellard } 4586c896fe29Sbellard 4587b4cb76e6SRichard Henderson if (def->flags & TCG_OPF_COND_BRANCH) { 4588b4cb76e6SRichard Henderson tcg_reg_alloc_cbranch(s, i_allocated_regs); 4589b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 459082790a87SRichard Henderson tcg_reg_alloc_bb_end(s, i_allocated_regs); 4591a52ad07eSAurelien Jarno } else { 4592c896fe29Sbellard if (def->flags & TCG_OPF_CALL_CLOBBER) { 4593b03cce8eSbellard /* XXX: permit generic clobber register list ? */ 4594c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) { 4595c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { 459682790a87SRichard Henderson tcg_reg_free(s, i, i_allocated_regs); 4597c896fe29Sbellard } 4598c896fe29Sbellard } 45993d5c5f87SAurelien Jarno } 46003d5c5f87SAurelien Jarno if (def->flags & TCG_OPF_SIDE_EFFECTS) { 46013d5c5f87SAurelien Jarno /* sync globals if the op has side effects and might trigger 46023d5c5f87SAurelien Jarno an exception. */ 460382790a87SRichard Henderson sync_globals(s, i_allocated_regs); 4604c896fe29Sbellard } 4605c896fe29Sbellard 4606c896fe29Sbellard /* satisfy the output constraints */ 4607c896fe29Sbellard for(k = 0; k < nb_oargs; k++) { 460866792f90SRichard Henderson i = def->args_ct[k].sort_index; 4609dd186292SRichard Henderson arg = op->args[i]; 4610c896fe29Sbellard arg_ct = &def->args_ct[i]; 461143439139SRichard Henderson ts = arg_temp(arg); 4612d63e3b6eSRichard Henderson 4613d63e3b6eSRichard Henderson /* ENV should not be modified. */ 4614e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ts)); 4615d63e3b6eSRichard Henderson 461629f5e925SRichard Henderson switch (arg_ct->pair) { 461729f5e925SRichard Henderson case 0: /* not paired */ 4618bc2b17e6SRichard Henderson if (arg_ct->oalias && !const_args[arg_ct->alias_index]) { 46195ff9d6a4Sbellard reg = new_args[arg_ct->alias_index]; 4620bc2b17e6SRichard Henderson } else if (arg_ct->newreg) { 46219be0d080SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->regs, 462282790a87SRichard Henderson i_allocated_regs | o_allocated_regs, 462331fd884bSRichard Henderson output_pref(op, k), ts->indirect_base); 4624c896fe29Sbellard } else { 46259be0d080SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs, 462631fd884bSRichard Henderson output_pref(op, k), ts->indirect_base); 4627c896fe29Sbellard } 462829f5e925SRichard Henderson break; 462929f5e925SRichard Henderson 463029f5e925SRichard Henderson case 1: /* first of pair */ 463129f5e925SRichard Henderson tcg_debug_assert(!arg_ct->newreg); 463229f5e925SRichard Henderson if (arg_ct->oalias) { 463329f5e925SRichard Henderson reg = new_args[arg_ct->alias_index]; 463429f5e925SRichard Henderson break; 463529f5e925SRichard Henderson } 463629f5e925SRichard Henderson reg = tcg_reg_alloc_pair(s, arg_ct->regs, o_allocated_regs, 463731fd884bSRichard Henderson output_pref(op, k), ts->indirect_base); 463829f5e925SRichard Henderson break; 463929f5e925SRichard Henderson 464029f5e925SRichard Henderson case 2: /* second of pair */ 464129f5e925SRichard Henderson tcg_debug_assert(!arg_ct->newreg); 464229f5e925SRichard Henderson if (arg_ct->oalias) { 464329f5e925SRichard Henderson reg = new_args[arg_ct->alias_index]; 464429f5e925SRichard Henderson } else { 464529f5e925SRichard Henderson reg = new_args[arg_ct->pair_index] + 1; 464629f5e925SRichard Henderson } 464729f5e925SRichard Henderson break; 464829f5e925SRichard Henderson 464929f5e925SRichard Henderson case 3: /* first of pair, aliasing with a second input */ 465029f5e925SRichard Henderson tcg_debug_assert(!arg_ct->newreg); 465129f5e925SRichard Henderson reg = new_args[arg_ct->pair_index] - 1; 465229f5e925SRichard Henderson break; 465329f5e925SRichard Henderson 465429f5e925SRichard Henderson default: 465529f5e925SRichard Henderson g_assert_not_reached(); 465629f5e925SRichard Henderson } 465782790a87SRichard Henderson tcg_regset_set_reg(o_allocated_regs, reg); 4658098859f1SRichard Henderson set_temp_val_reg(s, ts, reg); 4659c896fe29Sbellard ts->mem_coherent = 0; 4660c896fe29Sbellard new_args[i] = reg; 4661c896fe29Sbellard } 4662e8996ee0Sbellard } 4663c896fe29Sbellard 4664c896fe29Sbellard /* emit instruction */ 4665678155b2SRichard Henderson switch (op->opc) { 4666678155b2SRichard Henderson case INDEX_op_ext8s_i32: 4667678155b2SRichard Henderson tcg_out_ext8s(s, TCG_TYPE_I32, new_args[0], new_args[1]); 4668678155b2SRichard Henderson break; 4669678155b2SRichard Henderson case INDEX_op_ext8s_i64: 4670678155b2SRichard Henderson tcg_out_ext8s(s, TCG_TYPE_I64, new_args[0], new_args[1]); 4671678155b2SRichard Henderson break; 4672d0e66c89SRichard Henderson case INDEX_op_ext8u_i32: 4673d0e66c89SRichard Henderson case INDEX_op_ext8u_i64: 4674d0e66c89SRichard Henderson tcg_out_ext8u(s, new_args[0], new_args[1]); 4675d0e66c89SRichard Henderson break; 4676753e42eaSRichard Henderson case INDEX_op_ext16s_i32: 4677753e42eaSRichard Henderson tcg_out_ext16s(s, TCG_TYPE_I32, new_args[0], new_args[1]); 4678753e42eaSRichard Henderson break; 4679753e42eaSRichard Henderson case INDEX_op_ext16s_i64: 4680753e42eaSRichard Henderson tcg_out_ext16s(s, TCG_TYPE_I64, new_args[0], new_args[1]); 4681753e42eaSRichard Henderson break; 4682379afdffSRichard Henderson case INDEX_op_ext16u_i32: 4683379afdffSRichard Henderson case INDEX_op_ext16u_i64: 4684379afdffSRichard Henderson tcg_out_ext16u(s, new_args[0], new_args[1]); 4685379afdffSRichard Henderson break; 468652bf3398SRichard Henderson case INDEX_op_ext32s_i64: 468752bf3398SRichard Henderson tcg_out_ext32s(s, new_args[0], new_args[1]); 468852bf3398SRichard Henderson break; 46899ecf5f61SRichard Henderson case INDEX_op_ext32u_i64: 46909ecf5f61SRichard Henderson tcg_out_ext32u(s, new_args[0], new_args[1]); 46919ecf5f61SRichard Henderson break; 46929c6aa274SRichard Henderson case INDEX_op_ext_i32_i64: 46939c6aa274SRichard Henderson tcg_out_exts_i32_i64(s, new_args[0], new_args[1]); 46949c6aa274SRichard Henderson break; 4695b9bfe000SRichard Henderson case INDEX_op_extu_i32_i64: 4696b9bfe000SRichard Henderson tcg_out_extu_i32_i64(s, new_args[0], new_args[1]); 4697b9bfe000SRichard Henderson break; 4698b8b94ac6SRichard Henderson case INDEX_op_extrl_i64_i32: 4699b8b94ac6SRichard Henderson tcg_out_extrl_i64_i32(s, new_args[0], new_args[1]); 4700b8b94ac6SRichard Henderson break; 4701678155b2SRichard Henderson default: 4702d2fd745fSRichard Henderson if (def->flags & TCG_OPF_VECTOR) { 4703d2fd745fSRichard Henderson tcg_out_vec_op(s, op->opc, TCGOP_VECL(op), TCGOP_VECE(op), 4704d2fd745fSRichard Henderson new_args, const_args); 4705d2fd745fSRichard Henderson } else { 4706dd186292SRichard Henderson tcg_out_op(s, op->opc, new_args, const_args); 4707d2fd745fSRichard Henderson } 4708678155b2SRichard Henderson break; 4709678155b2SRichard Henderson } 4710c896fe29Sbellard 4711c896fe29Sbellard /* move the outputs in the correct register if needed */ 4712c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 471343439139SRichard Henderson ts = arg_temp(op->args[i]); 4714d63e3b6eSRichard Henderson 4715d63e3b6eSRichard Henderson /* ENV should not be modified. */ 4716e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ts)); 4717d63e3b6eSRichard Henderson 4718ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) { 471998b4e186SRichard Henderson temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i)); 472059d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) { 4721f8bf00f1SRichard Henderson temp_dead(s, ts); 4722ec7a869dSAurelien Jarno } 4723c896fe29Sbellard } 4724c896fe29Sbellard } 4725c896fe29Sbellard 4726efe86b21SRichard Henderson static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op) 4727efe86b21SRichard Henderson { 4728efe86b21SRichard Henderson const TCGLifeData arg_life = op->life; 4729efe86b21SRichard Henderson TCGTemp *ots, *itsl, *itsh; 4730efe86b21SRichard Henderson TCGType vtype = TCGOP_VECL(op) + TCG_TYPE_V64; 4731efe86b21SRichard Henderson 4732efe86b21SRichard Henderson /* This opcode is only valid for 32-bit hosts, for 64-bit elements. */ 4733efe86b21SRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 32); 4734efe86b21SRichard Henderson tcg_debug_assert(TCGOP_VECE(op) == MO_64); 4735efe86b21SRichard Henderson 4736efe86b21SRichard Henderson ots = arg_temp(op->args[0]); 4737efe86b21SRichard Henderson itsl = arg_temp(op->args[1]); 4738efe86b21SRichard Henderson itsh = arg_temp(op->args[2]); 4739efe86b21SRichard Henderson 4740efe86b21SRichard Henderson /* ENV should not be modified. */ 4741efe86b21SRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 4742efe86b21SRichard Henderson 4743efe86b21SRichard Henderson /* Allocate the output register now. */ 4744efe86b21SRichard Henderson if (ots->val_type != TEMP_VAL_REG) { 4745efe86b21SRichard Henderson TCGRegSet allocated_regs = s->reserved_regs; 4746efe86b21SRichard Henderson TCGRegSet dup_out_regs = 4747efe86b21SRichard Henderson tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs; 4748098859f1SRichard Henderson TCGReg oreg; 4749efe86b21SRichard Henderson 4750efe86b21SRichard Henderson /* Make sure to not spill the input registers. */ 4751efe86b21SRichard Henderson if (!IS_DEAD_ARG(1) && itsl->val_type == TEMP_VAL_REG) { 4752efe86b21SRichard Henderson tcg_regset_set_reg(allocated_regs, itsl->reg); 4753efe86b21SRichard Henderson } 4754efe86b21SRichard Henderson if (!IS_DEAD_ARG(2) && itsh->val_type == TEMP_VAL_REG) { 4755efe86b21SRichard Henderson tcg_regset_set_reg(allocated_regs, itsh->reg); 4756efe86b21SRichard Henderson } 4757efe86b21SRichard Henderson 4758098859f1SRichard Henderson oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs, 475931fd884bSRichard Henderson output_pref(op, 0), ots->indirect_base); 4760098859f1SRichard Henderson set_temp_val_reg(s, ots, oreg); 4761efe86b21SRichard Henderson } 4762efe86b21SRichard Henderson 4763efe86b21SRichard Henderson /* Promote dup2 of immediates to dupi_vec. */ 4764efe86b21SRichard Henderson if (itsl->val_type == TEMP_VAL_CONST && itsh->val_type == TEMP_VAL_CONST) { 4765efe86b21SRichard Henderson uint64_t val = deposit64(itsl->val, 32, 32, itsh->val); 4766efe86b21SRichard Henderson MemOp vece = MO_64; 4767efe86b21SRichard Henderson 4768efe86b21SRichard Henderson if (val == dup_const(MO_8, val)) { 4769efe86b21SRichard Henderson vece = MO_8; 4770efe86b21SRichard Henderson } else if (val == dup_const(MO_16, val)) { 4771efe86b21SRichard Henderson vece = MO_16; 4772efe86b21SRichard Henderson } else if (val == dup_const(MO_32, val)) { 4773efe86b21SRichard Henderson vece = MO_32; 4774efe86b21SRichard Henderson } 4775efe86b21SRichard Henderson 4776efe86b21SRichard Henderson tcg_out_dupi_vec(s, vtype, vece, ots->reg, val); 4777efe86b21SRichard Henderson goto done; 4778efe86b21SRichard Henderson } 4779efe86b21SRichard Henderson 4780efe86b21SRichard Henderson /* If the two inputs form one 64-bit value, try dupm_vec. */ 4781aef85402SRichard Henderson if (itsl->temp_subindex == HOST_BIG_ENDIAN && 4782aef85402SRichard Henderson itsh->temp_subindex == !HOST_BIG_ENDIAN && 4783aef85402SRichard Henderson itsl == itsh + (HOST_BIG_ENDIAN ? 1 : -1)) { 4784aef85402SRichard Henderson TCGTemp *its = itsl - HOST_BIG_ENDIAN; 4785aef85402SRichard Henderson 4786aef85402SRichard Henderson temp_sync(s, its + 0, s->reserved_regs, 0, 0); 4787aef85402SRichard Henderson temp_sync(s, its + 1, s->reserved_regs, 0, 0); 4788aef85402SRichard Henderson 4789efe86b21SRichard Henderson if (tcg_out_dupm_vec(s, vtype, MO_64, ots->reg, 4790efe86b21SRichard Henderson its->mem_base->reg, its->mem_offset)) { 4791efe86b21SRichard Henderson goto done; 4792efe86b21SRichard Henderson } 4793efe86b21SRichard Henderson } 4794efe86b21SRichard Henderson 4795efe86b21SRichard Henderson /* Fall back to generic expansion. */ 4796efe86b21SRichard Henderson return false; 4797efe86b21SRichard Henderson 4798efe86b21SRichard Henderson done: 479936f5539cSRichard Henderson ots->mem_coherent = 0; 4800efe86b21SRichard Henderson if (IS_DEAD_ARG(1)) { 4801efe86b21SRichard Henderson temp_dead(s, itsl); 4802efe86b21SRichard Henderson } 4803efe86b21SRichard Henderson if (IS_DEAD_ARG(2)) { 4804efe86b21SRichard Henderson temp_dead(s, itsh); 4805efe86b21SRichard Henderson } 4806efe86b21SRichard Henderson if (NEED_SYNC_ARG(0)) { 4807efe86b21SRichard Henderson temp_sync(s, ots, s->reserved_regs, 0, IS_DEAD_ARG(0)); 4808efe86b21SRichard Henderson } else if (IS_DEAD_ARG(0)) { 4809efe86b21SRichard Henderson temp_dead(s, ots); 4810efe86b21SRichard Henderson } 4811efe86b21SRichard Henderson return true; 4812efe86b21SRichard Henderson } 4813efe86b21SRichard Henderson 481439004a71SRichard Henderson static void load_arg_reg(TCGContext *s, TCGReg reg, TCGTemp *ts, 481539004a71SRichard Henderson TCGRegSet allocated_regs) 4816c896fe29Sbellard { 4817c896fe29Sbellard if (ts->val_type == TEMP_VAL_REG) { 4818c896fe29Sbellard if (ts->reg != reg) { 48194250da10SRichard Henderson tcg_reg_free(s, reg, allocated_regs); 482078113e83SRichard Henderson if (!tcg_out_mov(s, ts->type, reg, ts->reg)) { 4821240c08d0SRichard Henderson /* 4822240c08d0SRichard Henderson * Cross register class move not supported. Sync the 4823240c08d0SRichard Henderson * temp back to its slot and load from there. 4824240c08d0SRichard Henderson */ 4825240c08d0SRichard Henderson temp_sync(s, ts, allocated_regs, 0, 0); 4826240c08d0SRichard Henderson tcg_out_ld(s, ts->type, reg, 4827240c08d0SRichard Henderson ts->mem_base->reg, ts->mem_offset); 482878113e83SRichard Henderson } 4829c896fe29Sbellard } 4830c896fe29Sbellard } else { 4831ccb1bb66SRichard Henderson TCGRegSet arg_set = 0; 483240ae5c62SRichard Henderson 48334250da10SRichard Henderson tcg_reg_free(s, reg, allocated_regs); 483440ae5c62SRichard Henderson tcg_regset_set_reg(arg_set, reg); 4835b722452aSRichard Henderson temp_load(s, ts, arg_set, allocated_regs, 0); 4836c896fe29Sbellard } 483739004a71SRichard Henderson } 483840ae5c62SRichard Henderson 4839*d78e4a4fSRichard Henderson static void load_arg_stk(TCGContext *s, unsigned arg_slot, TCGTemp *ts, 484039004a71SRichard Henderson TCGRegSet allocated_regs) 484139004a71SRichard Henderson { 484239004a71SRichard Henderson /* 484339004a71SRichard Henderson * When the destination is on the stack, load up the temp and store. 484439004a71SRichard Henderson * If there are many call-saved registers, the temp might live to 484539004a71SRichard Henderson * see another use; otherwise it'll be discarded. 484639004a71SRichard Henderson */ 484739004a71SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], allocated_regs, 0); 484839004a71SRichard Henderson tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, 4849*d78e4a4fSRichard Henderson arg_slot_stk_ofs(arg_slot)); 485039004a71SRichard Henderson } 485139004a71SRichard Henderson 485239004a71SRichard Henderson static void load_arg_normal(TCGContext *s, const TCGCallArgumentLoc *l, 485339004a71SRichard Henderson TCGTemp *ts, TCGRegSet *allocated_regs) 485439004a71SRichard Henderson { 4855338b61e9SRichard Henderson if (arg_slot_reg_p(l->arg_slot)) { 485639004a71SRichard Henderson TCGReg reg = tcg_target_call_iarg_regs[l->arg_slot]; 485739004a71SRichard Henderson load_arg_reg(s, reg, ts, *allocated_regs); 485839004a71SRichard Henderson tcg_regset_set_reg(*allocated_regs, reg); 485939004a71SRichard Henderson } else { 4860*d78e4a4fSRichard Henderson load_arg_stk(s, l->arg_slot, ts, *allocated_regs); 4861c896fe29Sbellard } 486239cf05d3Sbellard } 4863c896fe29Sbellard 4864*d78e4a4fSRichard Henderson static void load_arg_ref(TCGContext *s, unsigned arg_slot, TCGReg ref_base, 4865313bdea8SRichard Henderson intptr_t ref_off, TCGRegSet *allocated_regs) 4866313bdea8SRichard Henderson { 4867313bdea8SRichard Henderson TCGReg reg; 4868313bdea8SRichard Henderson 4869*d78e4a4fSRichard Henderson if (arg_slot_reg_p(arg_slot)) { 4870313bdea8SRichard Henderson reg = tcg_target_call_iarg_regs[arg_slot]; 4871313bdea8SRichard Henderson tcg_reg_free(s, reg, *allocated_regs); 4872313bdea8SRichard Henderson tcg_out_addi_ptr(s, reg, ref_base, ref_off); 4873313bdea8SRichard Henderson tcg_regset_set_reg(*allocated_regs, reg); 4874313bdea8SRichard Henderson } else { 4875313bdea8SRichard Henderson reg = tcg_reg_alloc(s, tcg_target_available_regs[TCG_TYPE_PTR], 4876313bdea8SRichard Henderson *allocated_regs, 0, false); 4877313bdea8SRichard Henderson tcg_out_addi_ptr(s, reg, ref_base, ref_off); 4878313bdea8SRichard Henderson tcg_out_st(s, TCG_TYPE_PTR, reg, TCG_REG_CALL_STACK, 4879*d78e4a4fSRichard Henderson arg_slot_stk_ofs(arg_slot)); 4880313bdea8SRichard Henderson } 4881313bdea8SRichard Henderson } 4882313bdea8SRichard Henderson 488339004a71SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op) 488439004a71SRichard Henderson { 488539004a71SRichard Henderson const int nb_oargs = TCGOP_CALLO(op); 488639004a71SRichard Henderson const int nb_iargs = TCGOP_CALLI(op); 488739004a71SRichard Henderson const TCGLifeData arg_life = op->life; 488839004a71SRichard Henderson const TCGHelperInfo *info = tcg_call_info(op); 488939004a71SRichard Henderson TCGRegSet allocated_regs = s->reserved_regs; 489039004a71SRichard Henderson int i; 489139004a71SRichard Henderson 489239004a71SRichard Henderson /* 489339004a71SRichard Henderson * Move inputs into place in reverse order, 489439004a71SRichard Henderson * so that we place stacked arguments first. 489539004a71SRichard Henderson */ 489639004a71SRichard Henderson for (i = nb_iargs - 1; i >= 0; --i) { 489739004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i]; 489839004a71SRichard Henderson TCGTemp *ts = arg_temp(op->args[nb_oargs + i]); 489939004a71SRichard Henderson 490039004a71SRichard Henderson switch (loc->kind) { 490139004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 490239004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 490339004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 490439004a71SRichard Henderson load_arg_normal(s, loc, ts, &allocated_regs); 490539004a71SRichard Henderson break; 4906313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF: 4907313bdea8SRichard Henderson load_arg_stk(s, loc->ref_slot, ts, allocated_regs); 4908313bdea8SRichard Henderson load_arg_ref(s, loc->arg_slot, TCG_REG_CALL_STACK, 4909*d78e4a4fSRichard Henderson arg_slot_stk_ofs(loc->ref_slot), 4910313bdea8SRichard Henderson &allocated_regs); 4911313bdea8SRichard Henderson break; 4912313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF_N: 4913313bdea8SRichard Henderson load_arg_stk(s, loc->ref_slot, ts, allocated_regs); 4914313bdea8SRichard Henderson break; 491539004a71SRichard Henderson default: 491639004a71SRichard Henderson g_assert_not_reached(); 491739004a71SRichard Henderson } 491839004a71SRichard Henderson } 491939004a71SRichard Henderson 492039004a71SRichard Henderson /* Mark dead temporaries and free the associated registers. */ 4921866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 4922866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) { 492343439139SRichard Henderson temp_dead(s, arg_temp(op->args[i])); 4924c896fe29Sbellard } 4925c896fe29Sbellard } 4926c896fe29Sbellard 492739004a71SRichard Henderson /* Clobber call registers. */ 4928c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) { 4929c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { 4930b3915dbbSRichard Henderson tcg_reg_free(s, i, allocated_regs); 4931c896fe29Sbellard } 4932c896fe29Sbellard } 4933c896fe29Sbellard 493439004a71SRichard Henderson /* 493539004a71SRichard Henderson * Save globals if they might be written by the helper, 493639004a71SRichard Henderson * sync them if they might be read. 493739004a71SRichard Henderson */ 493839004a71SRichard Henderson if (info->flags & TCG_CALL_NO_READ_GLOBALS) { 493978505279SAurelien Jarno /* Nothing to do */ 494039004a71SRichard Henderson } else if (info->flags & TCG_CALL_NO_WRITE_GLOBALS) { 494178505279SAurelien Jarno sync_globals(s, allocated_regs); 494278505279SAurelien Jarno } else { 4943e8996ee0Sbellard save_globals(s, allocated_regs); 4944b9c18f56Saurel32 } 4945c896fe29Sbellard 4946313bdea8SRichard Henderson /* 4947313bdea8SRichard Henderson * If the ABI passes a pointer to the returned struct as the first 4948313bdea8SRichard Henderson * argument, load that now. Pass a pointer to the output home slot. 4949313bdea8SRichard Henderson */ 4950313bdea8SRichard Henderson if (info->out_kind == TCG_CALL_RET_BY_REF) { 4951313bdea8SRichard Henderson TCGTemp *ts = arg_temp(op->args[0]); 4952313bdea8SRichard Henderson 4953313bdea8SRichard Henderson if (!ts->mem_allocated) { 4954313bdea8SRichard Henderson temp_allocate_frame(s, ts); 4955313bdea8SRichard Henderson } 4956313bdea8SRichard Henderson load_arg_ref(s, 0, ts->mem_base->reg, ts->mem_offset, &allocated_regs); 4957313bdea8SRichard Henderson } 4958313bdea8SRichard Henderson 4959cee44b03SRichard Henderson tcg_out_call(s, tcg_call_func(op), info); 4960c896fe29Sbellard 496139004a71SRichard Henderson /* Assign output registers and emit moves if needed. */ 496239004a71SRichard Henderson switch (info->out_kind) { 496339004a71SRichard Henderson case TCG_CALL_RET_NORMAL: 4964c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 496539004a71SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]); 49665e3d0c19SRichard Henderson TCGReg reg = tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, i); 4967d63e3b6eSRichard Henderson 4968d63e3b6eSRichard Henderson /* ENV should not be modified. */ 4969e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ts)); 4970d63e3b6eSRichard Henderson 4971098859f1SRichard Henderson set_temp_val_reg(s, ts, reg); 4972c896fe29Sbellard ts->mem_coherent = 0; 497339004a71SRichard Henderson } 497439004a71SRichard Henderson break; 4975313bdea8SRichard Henderson 4976c6556aa0SRichard Henderson case TCG_CALL_RET_BY_VEC: 4977c6556aa0SRichard Henderson { 4978c6556aa0SRichard Henderson TCGTemp *ts = arg_temp(op->args[0]); 4979c6556aa0SRichard Henderson 4980c6556aa0SRichard Henderson tcg_debug_assert(ts->base_type == TCG_TYPE_I128); 4981c6556aa0SRichard Henderson tcg_debug_assert(ts->temp_subindex == 0); 4982c6556aa0SRichard Henderson if (!ts->mem_allocated) { 4983c6556aa0SRichard Henderson temp_allocate_frame(s, ts); 4984c6556aa0SRichard Henderson } 4985c6556aa0SRichard Henderson tcg_out_st(s, TCG_TYPE_V128, 4986c6556aa0SRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0), 4987c6556aa0SRichard Henderson ts->mem_base->reg, ts->mem_offset); 4988c6556aa0SRichard Henderson } 4989c6556aa0SRichard Henderson /* fall through to mark all parts in memory */ 4990c6556aa0SRichard Henderson 4991313bdea8SRichard Henderson case TCG_CALL_RET_BY_REF: 4992313bdea8SRichard Henderson /* The callee has performed a write through the reference. */ 4993313bdea8SRichard Henderson for (i = 0; i < nb_oargs; i++) { 4994313bdea8SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]); 4995313bdea8SRichard Henderson ts->val_type = TEMP_VAL_MEM; 4996313bdea8SRichard Henderson } 4997313bdea8SRichard Henderson break; 4998313bdea8SRichard Henderson 499939004a71SRichard Henderson default: 500039004a71SRichard Henderson g_assert_not_reached(); 500139004a71SRichard Henderson } 500239004a71SRichard Henderson 500339004a71SRichard Henderson /* Flush or discard output registers as needed. */ 500439004a71SRichard Henderson for (i = 0; i < nb_oargs; i++) { 500539004a71SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]); 5006ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) { 500739004a71SRichard Henderson temp_sync(s, ts, s->reserved_regs, 0, IS_DEAD_ARG(i)); 500859d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) { 5009f8bf00f1SRichard Henderson temp_dead(s, ts); 5010c896fe29Sbellard } 5011c896fe29Sbellard } 50128c11ad25SAurelien Jarno } 5013c896fe29Sbellard 5014c896fe29Sbellard #ifdef CONFIG_PROFILER 5015c896fe29Sbellard 5016c3fac113SEmilio G. Cota /* avoid copy/paste errors */ 5017c3fac113SEmilio G. Cota #define PROF_ADD(to, from, field) \ 5018c3fac113SEmilio G. Cota do { \ 5019d73415a3SStefan Hajnoczi (to)->field += qatomic_read(&((from)->field)); \ 5020c3fac113SEmilio G. Cota } while (0) 5021c896fe29Sbellard 5022c3fac113SEmilio G. Cota #define PROF_MAX(to, from, field) \ 5023c3fac113SEmilio G. Cota do { \ 5024d73415a3SStefan Hajnoczi typeof((from)->field) val__ = qatomic_read(&((from)->field)); \ 5025c3fac113SEmilio G. Cota if (val__ > (to)->field) { \ 5026c3fac113SEmilio G. Cota (to)->field = val__; \ 5027c3fac113SEmilio G. Cota } \ 5028c3fac113SEmilio G. Cota } while (0) 5029c3fac113SEmilio G. Cota 5030c3fac113SEmilio G. Cota /* Pass in a zero'ed @prof */ 5031c3fac113SEmilio G. Cota static inline 5032c3fac113SEmilio G. Cota void tcg_profile_snapshot(TCGProfile *prof, bool counters, bool table) 5033c896fe29Sbellard { 50340e2d61cfSRichard Henderson unsigned int n_ctxs = qatomic_read(&tcg_cur_ctxs); 5035c3fac113SEmilio G. Cota unsigned int i; 5036c3fac113SEmilio G. Cota 50373468b59eSEmilio G. Cota for (i = 0; i < n_ctxs; i++) { 5038d73415a3SStefan Hajnoczi TCGContext *s = qatomic_read(&tcg_ctxs[i]); 50393468b59eSEmilio G. Cota const TCGProfile *orig = &s->prof; 5040c3fac113SEmilio G. Cota 5041c3fac113SEmilio G. Cota if (counters) { 504272fd2efbSEmilio G. Cota PROF_ADD(prof, orig, cpu_exec_time); 5043c3fac113SEmilio G. Cota PROF_ADD(prof, orig, tb_count1); 5044c3fac113SEmilio G. Cota PROF_ADD(prof, orig, tb_count); 5045c3fac113SEmilio G. Cota PROF_ADD(prof, orig, op_count); 5046c3fac113SEmilio G. Cota PROF_MAX(prof, orig, op_count_max); 5047c3fac113SEmilio G. Cota PROF_ADD(prof, orig, temp_count); 5048c3fac113SEmilio G. Cota PROF_MAX(prof, orig, temp_count_max); 5049c3fac113SEmilio G. Cota PROF_ADD(prof, orig, del_op_count); 5050c3fac113SEmilio G. Cota PROF_ADD(prof, orig, code_in_len); 5051c3fac113SEmilio G. Cota PROF_ADD(prof, orig, code_out_len); 5052c3fac113SEmilio G. Cota PROF_ADD(prof, orig, search_out_len); 5053c3fac113SEmilio G. Cota PROF_ADD(prof, orig, interm_time); 5054c3fac113SEmilio G. Cota PROF_ADD(prof, orig, code_time); 5055c3fac113SEmilio G. Cota PROF_ADD(prof, orig, la_time); 5056c3fac113SEmilio G. Cota PROF_ADD(prof, orig, opt_time); 5057c3fac113SEmilio G. Cota PROF_ADD(prof, orig, restore_count); 5058c3fac113SEmilio G. Cota PROF_ADD(prof, orig, restore_time); 5059c3fac113SEmilio G. Cota } 5060c3fac113SEmilio G. Cota if (table) { 5061c896fe29Sbellard int i; 5062d70724ceSzhanghailiang 506315fc7daaSRichard Henderson for (i = 0; i < NB_OPS; i++) { 5064c3fac113SEmilio G. Cota PROF_ADD(prof, orig, table_op_count[i]); 5065c3fac113SEmilio G. Cota } 5066c3fac113SEmilio G. Cota } 5067c3fac113SEmilio G. Cota } 5068c3fac113SEmilio G. Cota } 5069c3fac113SEmilio G. Cota 5070c3fac113SEmilio G. Cota #undef PROF_ADD 5071c3fac113SEmilio G. Cota #undef PROF_MAX 5072c3fac113SEmilio G. Cota 5073c3fac113SEmilio G. Cota static void tcg_profile_snapshot_counters(TCGProfile *prof) 5074c3fac113SEmilio G. Cota { 5075c3fac113SEmilio G. Cota tcg_profile_snapshot(prof, true, false); 5076c3fac113SEmilio G. Cota } 5077c3fac113SEmilio G. Cota 5078c3fac113SEmilio G. Cota static void tcg_profile_snapshot_table(TCGProfile *prof) 5079c3fac113SEmilio G. Cota { 5080c3fac113SEmilio G. Cota tcg_profile_snapshot(prof, false, true); 5081c3fac113SEmilio G. Cota } 5082c3fac113SEmilio G. Cota 5083b6a7f3e0SDaniel P. Berrangé void tcg_dump_op_count(GString *buf) 5084c3fac113SEmilio G. Cota { 5085c3fac113SEmilio G. Cota TCGProfile prof = {}; 5086c3fac113SEmilio G. Cota int i; 5087c3fac113SEmilio G. Cota 5088c3fac113SEmilio G. Cota tcg_profile_snapshot_table(&prof); 5089c3fac113SEmilio G. Cota for (i = 0; i < NB_OPS; i++) { 5090b6a7f3e0SDaniel P. Berrangé g_string_append_printf(buf, "%s %" PRId64 "\n", tcg_op_defs[i].name, 5091c3fac113SEmilio G. Cota prof.table_op_count[i]); 5092c896fe29Sbellard } 5093c896fe29Sbellard } 509472fd2efbSEmilio G. Cota 509572fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void) 509672fd2efbSEmilio G. Cota { 50970e2d61cfSRichard Henderson unsigned int n_ctxs = qatomic_read(&tcg_cur_ctxs); 509872fd2efbSEmilio G. Cota unsigned int i; 509972fd2efbSEmilio G. Cota int64_t ret = 0; 510072fd2efbSEmilio G. Cota 510172fd2efbSEmilio G. Cota for (i = 0; i < n_ctxs; i++) { 5102d73415a3SStefan Hajnoczi const TCGContext *s = qatomic_read(&tcg_ctxs[i]); 510372fd2efbSEmilio G. Cota const TCGProfile *prof = &s->prof; 510472fd2efbSEmilio G. Cota 5105d73415a3SStefan Hajnoczi ret += qatomic_read(&prof->cpu_exec_time); 510672fd2efbSEmilio G. Cota } 510772fd2efbSEmilio G. Cota return ret; 510872fd2efbSEmilio G. Cota } 5109246ae24dSMax Filippov #else 5110b6a7f3e0SDaniel P. Berrangé void tcg_dump_op_count(GString *buf) 5111246ae24dSMax Filippov { 5112b6a7f3e0SDaniel P. Berrangé g_string_append_printf(buf, "[TCG profiler not compiled]\n"); 5113246ae24dSMax Filippov } 511472fd2efbSEmilio G. Cota 511572fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void) 511672fd2efbSEmilio G. Cota { 511772fd2efbSEmilio G. Cota error_report("%s: TCG profiler not compiled", __func__); 511872fd2efbSEmilio G. Cota exit(EXIT_FAILURE); 511972fd2efbSEmilio G. Cota } 5120c896fe29Sbellard #endif 5121c896fe29Sbellard 5122c896fe29Sbellard 5123fbf59aadSRichard Henderson int tcg_gen_code(TCGContext *s, TranslationBlock *tb, target_ulong pc_start) 5124c896fe29Sbellard { 5125c3fac113SEmilio G. Cota #ifdef CONFIG_PROFILER 5126c3fac113SEmilio G. Cota TCGProfile *prof = &s->prof; 5127c3fac113SEmilio G. Cota #endif 512815fa08f8SRichard Henderson int i, num_insns; 512915fa08f8SRichard Henderson TCGOp *op; 5130c896fe29Sbellard 513104fe6400SRichard Henderson #ifdef CONFIG_PROFILER 513204fe6400SRichard Henderson { 5133c1f543b7SEmilio G. Cota int n = 0; 513404fe6400SRichard Henderson 513515fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 513615fa08f8SRichard Henderson n++; 513715fa08f8SRichard Henderson } 5138d73415a3SStefan Hajnoczi qatomic_set(&prof->op_count, prof->op_count + n); 5139c3fac113SEmilio G. Cota if (n > prof->op_count_max) { 5140d73415a3SStefan Hajnoczi qatomic_set(&prof->op_count_max, n); 514104fe6400SRichard Henderson } 514204fe6400SRichard Henderson 514304fe6400SRichard Henderson n = s->nb_temps; 5144d73415a3SStefan Hajnoczi qatomic_set(&prof->temp_count, prof->temp_count + n); 5145c3fac113SEmilio G. Cota if (n > prof->temp_count_max) { 5146d73415a3SStefan Hajnoczi qatomic_set(&prof->temp_count_max, n); 514704fe6400SRichard Henderson } 514804fe6400SRichard Henderson } 514904fe6400SRichard Henderson #endif 515004fe6400SRichard Henderson 5151c896fe29Sbellard #ifdef DEBUG_DISAS 5152d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP) 5153fbf59aadSRichard Henderson && qemu_log_in_addr_range(pc_start))) { 5154c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock(); 515578b54858SRichard Henderson if (logfile) { 515678b54858SRichard Henderson fprintf(logfile, "OP:\n"); 5157b7a83ff8SRichard Henderson tcg_dump_ops(s, logfile, false); 515878b54858SRichard Henderson fprintf(logfile, "\n"); 5159fc59d2d8SRobert Foley qemu_log_unlock(logfile); 5160c896fe29Sbellard } 516178b54858SRichard Henderson } 5162c896fe29Sbellard #endif 5163c896fe29Sbellard 5164bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG 5165bef16ab4SRichard Henderson /* Ensure all labels referenced have been emitted. */ 5166bef16ab4SRichard Henderson { 5167bef16ab4SRichard Henderson TCGLabel *l; 5168bef16ab4SRichard Henderson bool error = false; 5169bef16ab4SRichard Henderson 5170bef16ab4SRichard Henderson QSIMPLEQ_FOREACH(l, &s->labels, next) { 5171f85b1fc4SRichard Henderson if (unlikely(!l->present) && !QSIMPLEQ_EMPTY(&l->branches)) { 5172bef16ab4SRichard Henderson qemu_log_mask(CPU_LOG_TB_OP, 5173bef16ab4SRichard Henderson "$L%d referenced but not present.\n", l->id); 5174bef16ab4SRichard Henderson error = true; 5175bef16ab4SRichard Henderson } 5176bef16ab4SRichard Henderson } 5177bef16ab4SRichard Henderson assert(!error); 5178bef16ab4SRichard Henderson } 5179bef16ab4SRichard Henderson #endif 5180bef16ab4SRichard Henderson 5181c5cc28ffSAurelien Jarno #ifdef CONFIG_PROFILER 5182d73415a3SStefan Hajnoczi qatomic_set(&prof->opt_time, prof->opt_time - profile_getclock()); 5183c5cc28ffSAurelien Jarno #endif 5184c5cc28ffSAurelien Jarno 51858f2e8c07SKirill Batuzov #ifdef USE_TCG_OPTIMIZATIONS 5186c45cb8bbSRichard Henderson tcg_optimize(s); 51878f2e8c07SKirill Batuzov #endif 51888f2e8c07SKirill Batuzov 5189a23a9ec6Sbellard #ifdef CONFIG_PROFILER 5190d73415a3SStefan Hajnoczi qatomic_set(&prof->opt_time, prof->opt_time + profile_getclock()); 5191d73415a3SStefan Hajnoczi qatomic_set(&prof->la_time, prof->la_time - profile_getclock()); 5192a23a9ec6Sbellard #endif 5193c5cc28ffSAurelien Jarno 5194b4fc67c7SRichard Henderson reachable_code_pass(s); 5195874b8574SRichard Henderson liveness_pass_0(s); 5196b83eabeaSRichard Henderson liveness_pass_1(s); 51975a18407fSRichard Henderson 51985a18407fSRichard Henderson if (s->nb_indirects > 0) { 51995a18407fSRichard Henderson #ifdef DEBUG_DISAS 52005a18407fSRichard Henderson if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND) 5201fbf59aadSRichard Henderson && qemu_log_in_addr_range(pc_start))) { 5202c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock(); 520378b54858SRichard Henderson if (logfile) { 520478b54858SRichard Henderson fprintf(logfile, "OP before indirect lowering:\n"); 5205b7a83ff8SRichard Henderson tcg_dump_ops(s, logfile, false); 520678b54858SRichard Henderson fprintf(logfile, "\n"); 5207fc59d2d8SRobert Foley qemu_log_unlock(logfile); 52085a18407fSRichard Henderson } 520978b54858SRichard Henderson } 52105a18407fSRichard Henderson #endif 52115a18407fSRichard Henderson /* Replace indirect temps with direct temps. */ 5212b83eabeaSRichard Henderson if (liveness_pass_2(s)) { 52135a18407fSRichard Henderson /* If changes were made, re-run liveness. */ 5214b83eabeaSRichard Henderson liveness_pass_1(s); 52155a18407fSRichard Henderson } 52165a18407fSRichard Henderson } 5217c5cc28ffSAurelien Jarno 5218a23a9ec6Sbellard #ifdef CONFIG_PROFILER 5219d73415a3SStefan Hajnoczi qatomic_set(&prof->la_time, prof->la_time + profile_getclock()); 5220a23a9ec6Sbellard #endif 5221c896fe29Sbellard 5222c896fe29Sbellard #ifdef DEBUG_DISAS 5223d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT) 5224fbf59aadSRichard Henderson && qemu_log_in_addr_range(pc_start))) { 5225c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock(); 522678b54858SRichard Henderson if (logfile) { 522778b54858SRichard Henderson fprintf(logfile, "OP after optimization and liveness analysis:\n"); 5228b7a83ff8SRichard Henderson tcg_dump_ops(s, logfile, true); 522978b54858SRichard Henderson fprintf(logfile, "\n"); 5230fc59d2d8SRobert Foley qemu_log_unlock(logfile); 5231c896fe29Sbellard } 523278b54858SRichard Henderson } 5233c896fe29Sbellard #endif 5234c896fe29Sbellard 523535abb009SRichard Henderson /* Initialize goto_tb jump offsets. */ 52363a50f424SRichard Henderson tb->jmp_reset_offset[0] = TB_JMP_OFFSET_INVALID; 52373a50f424SRichard Henderson tb->jmp_reset_offset[1] = TB_JMP_OFFSET_INVALID; 52389da6079bSRichard Henderson tb->jmp_insn_offset[0] = TB_JMP_OFFSET_INVALID; 52399da6079bSRichard Henderson tb->jmp_insn_offset[1] = TB_JMP_OFFSET_INVALID; 524035abb009SRichard Henderson 5241c896fe29Sbellard tcg_reg_alloc_start(s); 5242c896fe29Sbellard 5243db0c51a3SRichard Henderson /* 5244db0c51a3SRichard Henderson * Reset the buffer pointers when restarting after overflow. 5245db0c51a3SRichard Henderson * TODO: Move this into translate-all.c with the rest of the 5246db0c51a3SRichard Henderson * buffer management. Having only this done here is confusing. 5247db0c51a3SRichard Henderson */ 5248db0c51a3SRichard Henderson s->code_buf = tcg_splitwx_to_rw(tb->tc.ptr); 5249db0c51a3SRichard Henderson s->code_ptr = s->code_buf; 5250c896fe29Sbellard 5251659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS 52526001f772SLaurent Vivier QSIMPLEQ_INIT(&s->ldst_labels); 5253659ef5cbSRichard Henderson #endif 525457a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 525557a26946SRichard Henderson s->pool_labels = NULL; 525657a26946SRichard Henderson #endif 52579ecefc84SRichard Henderson 5258fca8a500SRichard Henderson num_insns = -1; 525915fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 5260c45cb8bbSRichard Henderson TCGOpcode opc = op->opc; 5261b3db8758Sblueswir1 5262c896fe29Sbellard #ifdef CONFIG_PROFILER 5263d73415a3SStefan Hajnoczi qatomic_set(&prof->table_op_count[opc], prof->table_op_count[opc] + 1); 5264c896fe29Sbellard #endif 5265c45cb8bbSRichard Henderson 5266c896fe29Sbellard switch (opc) { 5267c896fe29Sbellard case INDEX_op_mov_i32: 5268c896fe29Sbellard case INDEX_op_mov_i64: 5269d2fd745fSRichard Henderson case INDEX_op_mov_vec: 5270dd186292SRichard Henderson tcg_reg_alloc_mov(s, op); 5271c896fe29Sbellard break; 5272bab1671fSRichard Henderson case INDEX_op_dup_vec: 5273bab1671fSRichard Henderson tcg_reg_alloc_dup(s, op); 5274bab1671fSRichard Henderson break; 5275765b842aSRichard Henderson case INDEX_op_insn_start: 5276fca8a500SRichard Henderson if (num_insns >= 0) { 52779f754620SRichard Henderson size_t off = tcg_current_code_size(s); 52789f754620SRichard Henderson s->gen_insn_end_off[num_insns] = off; 52799f754620SRichard Henderson /* Assert that we do not overflow our stored offset. */ 52809f754620SRichard Henderson assert(s->gen_insn_end_off[num_insns] == off); 5281fca8a500SRichard Henderson } 5282fca8a500SRichard Henderson num_insns++; 5283bad729e2SRichard Henderson for (i = 0; i < TARGET_INSN_START_WORDS; ++i) { 5284bad729e2SRichard Henderson target_ulong a; 5285bad729e2SRichard Henderson #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS 5286efee3746SRichard Henderson a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]); 5287bad729e2SRichard Henderson #else 5288efee3746SRichard Henderson a = op->args[i]; 5289bad729e2SRichard Henderson #endif 5290fca8a500SRichard Henderson s->gen_insn_data[num_insns][i] = a; 5291bad729e2SRichard Henderson } 5292c896fe29Sbellard break; 52935ff9d6a4Sbellard case INDEX_op_discard: 529443439139SRichard Henderson temp_dead(s, arg_temp(op->args[0])); 52955ff9d6a4Sbellard break; 5296c896fe29Sbellard case INDEX_op_set_label: 5297e8996ee0Sbellard tcg_reg_alloc_bb_end(s, s->reserved_regs); 529892ab8e7dSRichard Henderson tcg_out_label(s, arg_label(op->args[0])); 5299c896fe29Sbellard break; 5300c896fe29Sbellard case INDEX_op_call: 5301dd186292SRichard Henderson tcg_reg_alloc_call(s, op); 5302c45cb8bbSRichard Henderson break; 5303b55a8d9dSRichard Henderson case INDEX_op_exit_tb: 5304b55a8d9dSRichard Henderson tcg_out_exit_tb(s, op->args[0]); 5305b55a8d9dSRichard Henderson break; 5306cf7d6b8eSRichard Henderson case INDEX_op_goto_tb: 5307cf7d6b8eSRichard Henderson tcg_out_goto_tb(s, op->args[0]); 5308cf7d6b8eSRichard Henderson break; 5309efe86b21SRichard Henderson case INDEX_op_dup2_vec: 5310efe86b21SRichard Henderson if (tcg_reg_alloc_dup2(s, op)) { 5311efe86b21SRichard Henderson break; 5312efe86b21SRichard Henderson } 5313efe86b21SRichard Henderson /* fall through */ 5314c896fe29Sbellard default: 531525c4d9ccSRichard Henderson /* Sanity check that we've not introduced any unhandled opcodes. */ 5316be0f34b5SRichard Henderson tcg_debug_assert(tcg_op_supported(opc)); 5317c896fe29Sbellard /* Note: in order to speed up the code, it would be much 5318c896fe29Sbellard faster to have specialized register allocator functions for 5319c896fe29Sbellard some common argument patterns */ 5320dd186292SRichard Henderson tcg_reg_alloc_op(s, op); 5321c896fe29Sbellard break; 5322c896fe29Sbellard } 5323b125f9dcSRichard Henderson /* Test for (pending) buffer overflow. The assumption is that any 5324b125f9dcSRichard Henderson one operation beginning below the high water mark cannot overrun 5325b125f9dcSRichard Henderson the buffer completely. Thus we can test for overflow after 5326b125f9dcSRichard Henderson generating code without having to check during generation. */ 5327644da9b3SJohn Clarke if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) { 5328b125f9dcSRichard Henderson return -1; 5329b125f9dcSRichard Henderson } 53306e6c4efeSRichard Henderson /* Test for TB overflow, as seen by gen_insn_end_off. */ 53316e6c4efeSRichard Henderson if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) { 53326e6c4efeSRichard Henderson return -2; 53336e6c4efeSRichard Henderson } 5334c896fe29Sbellard } 5335fca8a500SRichard Henderson tcg_debug_assert(num_insns >= 0); 5336fca8a500SRichard Henderson s->gen_insn_end_off[num_insns] = tcg_current_code_size(s); 5337c45cb8bbSRichard Henderson 5338b76f0d8cSYeongkyoon Lee /* Generate TB finalization at the end of block */ 5339659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS 5340aeee05f5SRichard Henderson i = tcg_out_ldst_finalize(s); 5341aeee05f5SRichard Henderson if (i < 0) { 5342aeee05f5SRichard Henderson return i; 534323dceda6SRichard Henderson } 5344659ef5cbSRichard Henderson #endif 534557a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 53461768987bSRichard Henderson i = tcg_out_pool_finalize(s); 53471768987bSRichard Henderson if (i < 0) { 53481768987bSRichard Henderson return i; 534957a26946SRichard Henderson } 535057a26946SRichard Henderson #endif 53517ecd02a0SRichard Henderson if (!tcg_resolve_relocs(s)) { 53527ecd02a0SRichard Henderson return -2; 53537ecd02a0SRichard Henderson } 5354c896fe29Sbellard 5355df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 5356c896fe29Sbellard /* flush instruction cache */ 5357db0c51a3SRichard Henderson flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf), 5358db0c51a3SRichard Henderson (uintptr_t)s->code_buf, 53591da8de39SRichard Henderson tcg_ptr_byte_diff(s->code_ptr, s->code_buf)); 5360df5d2b16SRichard Henderson #endif 53612aeabc08SStefan Weil 53621813e175SRichard Henderson return tcg_current_code_size(s); 5363c896fe29Sbellard } 5364c896fe29Sbellard 5365a23a9ec6Sbellard #ifdef CONFIG_PROFILER 53663a841ab5SDaniel P. Berrangé void tcg_dump_info(GString *buf) 5367a23a9ec6Sbellard { 5368c3fac113SEmilio G. Cota TCGProfile prof = {}; 5369c3fac113SEmilio G. Cota const TCGProfile *s; 5370c3fac113SEmilio G. Cota int64_t tb_count; 5371c3fac113SEmilio G. Cota int64_t tb_div_count; 5372c3fac113SEmilio G. Cota int64_t tot; 5373c3fac113SEmilio G. Cota 5374c3fac113SEmilio G. Cota tcg_profile_snapshot_counters(&prof); 5375c3fac113SEmilio G. Cota s = &prof; 5376c3fac113SEmilio G. Cota tb_count = s->tb_count; 5377c3fac113SEmilio G. Cota tb_div_count = tb_count ? tb_count : 1; 5378c3fac113SEmilio G. Cota tot = s->interm_time + s->code_time; 5379a23a9ec6Sbellard 53803a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "JIT cycles %" PRId64 53813a841ab5SDaniel P. Berrangé " (%0.3f s at 2.4 GHz)\n", 5382a23a9ec6Sbellard tot, tot / 2.4e9); 53833a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "translated TBs %" PRId64 53843a841ab5SDaniel P. Berrangé " (aborted=%" PRId64 " %0.1f%%)\n", 5385fca8a500SRichard Henderson tb_count, s->tb_count1 - tb_count, 5386fca8a500SRichard Henderson (double)(s->tb_count1 - s->tb_count) 5387fca8a500SRichard Henderson / (s->tb_count1 ? s->tb_count1 : 1) * 100.0); 53883a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "avg ops/TB %0.1f max=%d\n", 5389fca8a500SRichard Henderson (double)s->op_count / tb_div_count, s->op_count_max); 53903a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "deleted ops/TB %0.2f\n", 5391fca8a500SRichard Henderson (double)s->del_op_count / tb_div_count); 53923a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "avg temps/TB %0.2f max=%d\n", 53933a841ab5SDaniel P. Berrangé (double)s->temp_count / tb_div_count, 53943a841ab5SDaniel P. Berrangé s->temp_count_max); 53953a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "avg host code/TB %0.1f\n", 5396fca8a500SRichard Henderson (double)s->code_out_len / tb_div_count); 53973a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "avg search data/TB %0.1f\n", 5398fca8a500SRichard Henderson (double)s->search_out_len / tb_div_count); 5399a23a9ec6Sbellard 54003a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "cycles/op %0.1f\n", 5401a23a9ec6Sbellard s->op_count ? (double)tot / s->op_count : 0); 54023a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "cycles/in byte %0.1f\n", 5403a23a9ec6Sbellard s->code_in_len ? (double)tot / s->code_in_len : 0); 54043a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "cycles/out byte %0.1f\n", 5405a23a9ec6Sbellard s->code_out_len ? (double)tot / s->code_out_len : 0); 54063a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "cycles/search byte %0.1f\n", 54073a841ab5SDaniel P. Berrangé s->search_out_len ? 54083a841ab5SDaniel P. Berrangé (double)tot / s->search_out_len : 0); 5409fca8a500SRichard Henderson if (tot == 0) { 5410a23a9ec6Sbellard tot = 1; 5411fca8a500SRichard Henderson } 54123a841ab5SDaniel P. Berrangé g_string_append_printf(buf, " gen_interm time %0.1f%%\n", 5413a23a9ec6Sbellard (double)s->interm_time / tot * 100.0); 54143a841ab5SDaniel P. Berrangé g_string_append_printf(buf, " gen_code time %0.1f%%\n", 5415a23a9ec6Sbellard (double)s->code_time / tot * 100.0); 54163a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "optim./code time %0.1f%%\n", 54173a841ab5SDaniel P. Berrangé (double)s->opt_time / (s->code_time ? 54183a841ab5SDaniel P. Berrangé s->code_time : 1) 5419c5cc28ffSAurelien Jarno * 100.0); 54203a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "liveness/code time %0.1f%%\n", 54213a841ab5SDaniel P. Berrangé (double)s->la_time / (s->code_time ? 54223a841ab5SDaniel P. Berrangé s->code_time : 1) * 100.0); 54233a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "cpu_restore count %" PRId64 "\n", 5424a23a9ec6Sbellard s->restore_count); 54253a841ab5SDaniel P. Berrangé g_string_append_printf(buf, " avg cycles %0.1f\n", 54263a841ab5SDaniel P. Berrangé s->restore_count ? 54273a841ab5SDaniel P. Berrangé (double)s->restore_time / s->restore_count : 0); 5428a23a9ec6Sbellard } 5429a23a9ec6Sbellard #else 54303a841ab5SDaniel P. Berrangé void tcg_dump_info(GString *buf) 5431a23a9ec6Sbellard { 54323a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "[TCG profiler not compiled]\n"); 5433a23a9ec6Sbellard } 5434a23a9ec6Sbellard #endif 5435813da627SRichard Henderson 5436813da627SRichard Henderson #ifdef ELF_HOST_MACHINE 54375872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things: 54385872bbf2SRichard Henderson 54395872bbf2SRichard Henderson (1) Define ELF_HOST_MACHINE to indicate both what value to 54405872bbf2SRichard Henderson put into the ELF image and to indicate support for the feature. 54415872bbf2SRichard Henderson 54425872bbf2SRichard Henderson (2) Define tcg_register_jit. This should create a buffer containing 54435872bbf2SRichard Henderson the contents of a .debug_frame section that describes the post- 54445872bbf2SRichard Henderson prologue unwind info for the tcg machine. 54455872bbf2SRichard Henderson 54465872bbf2SRichard Henderson (3) Call tcg_register_jit_int, with the constructed .debug_frame. 54475872bbf2SRichard Henderson */ 5448813da627SRichard Henderson 5449813da627SRichard Henderson /* Begin GDB interface. THE FOLLOWING MUST MATCH GDB DOCS. */ 5450813da627SRichard Henderson typedef enum { 5451813da627SRichard Henderson JIT_NOACTION = 0, 5452813da627SRichard Henderson JIT_REGISTER_FN, 5453813da627SRichard Henderson JIT_UNREGISTER_FN 5454813da627SRichard Henderson } jit_actions_t; 5455813da627SRichard Henderson 5456813da627SRichard Henderson struct jit_code_entry { 5457813da627SRichard Henderson struct jit_code_entry *next_entry; 5458813da627SRichard Henderson struct jit_code_entry *prev_entry; 5459813da627SRichard Henderson const void *symfile_addr; 5460813da627SRichard Henderson uint64_t symfile_size; 5461813da627SRichard Henderson }; 5462813da627SRichard Henderson 5463813da627SRichard Henderson struct jit_descriptor { 5464813da627SRichard Henderson uint32_t version; 5465813da627SRichard Henderson uint32_t action_flag; 5466813da627SRichard Henderson struct jit_code_entry *relevant_entry; 5467813da627SRichard Henderson struct jit_code_entry *first_entry; 5468813da627SRichard Henderson }; 5469813da627SRichard Henderson 5470813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline)); 5471813da627SRichard Henderson void __jit_debug_register_code(void) 5472813da627SRichard Henderson { 5473813da627SRichard Henderson asm(""); 5474813da627SRichard Henderson } 5475813da627SRichard Henderson 5476813da627SRichard Henderson /* Must statically initialize the version, because GDB may check 5477813da627SRichard Henderson the version before we can set it. */ 5478813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 }; 5479813da627SRichard Henderson 5480813da627SRichard Henderson /* End GDB interface. */ 5481813da627SRichard Henderson 5482813da627SRichard Henderson static int find_string(const char *strtab, const char *str) 5483813da627SRichard Henderson { 5484813da627SRichard Henderson const char *p = strtab + 1; 5485813da627SRichard Henderson 5486813da627SRichard Henderson while (1) { 5487813da627SRichard Henderson if (strcmp(p, str) == 0) { 5488813da627SRichard Henderson return p - strtab; 5489813da627SRichard Henderson } 5490813da627SRichard Henderson p += strlen(p) + 1; 5491813da627SRichard Henderson } 5492813da627SRichard Henderson } 5493813da627SRichard Henderson 5494755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf_ptr, size_t buf_size, 54952c90784aSRichard Henderson const void *debug_frame, 54962c90784aSRichard Henderson size_t debug_frame_size) 5497813da627SRichard Henderson { 54985872bbf2SRichard Henderson struct __attribute__((packed)) DebugInfo { 54995872bbf2SRichard Henderson uint32_t len; 55005872bbf2SRichard Henderson uint16_t version; 55015872bbf2SRichard Henderson uint32_t abbrev; 55025872bbf2SRichard Henderson uint8_t ptr_size; 55035872bbf2SRichard Henderson uint8_t cu_die; 55045872bbf2SRichard Henderson uint16_t cu_lang; 55055872bbf2SRichard Henderson uintptr_t cu_low_pc; 55065872bbf2SRichard Henderson uintptr_t cu_high_pc; 55075872bbf2SRichard Henderson uint8_t fn_die; 55085872bbf2SRichard Henderson char fn_name[16]; 55095872bbf2SRichard Henderson uintptr_t fn_low_pc; 55105872bbf2SRichard Henderson uintptr_t fn_high_pc; 55115872bbf2SRichard Henderson uint8_t cu_eoc; 55125872bbf2SRichard Henderson }; 5513813da627SRichard Henderson 5514813da627SRichard Henderson struct ElfImage { 5515813da627SRichard Henderson ElfW(Ehdr) ehdr; 5516813da627SRichard Henderson ElfW(Phdr) phdr; 55175872bbf2SRichard Henderson ElfW(Shdr) shdr[7]; 55185872bbf2SRichard Henderson ElfW(Sym) sym[2]; 55195872bbf2SRichard Henderson struct DebugInfo di; 55205872bbf2SRichard Henderson uint8_t da[24]; 55215872bbf2SRichard Henderson char str[80]; 55225872bbf2SRichard Henderson }; 55235872bbf2SRichard Henderson 55245872bbf2SRichard Henderson struct ElfImage *img; 55255872bbf2SRichard Henderson 55265872bbf2SRichard Henderson static const struct ElfImage img_template = { 55275872bbf2SRichard Henderson .ehdr = { 55285872bbf2SRichard Henderson .e_ident[EI_MAG0] = ELFMAG0, 55295872bbf2SRichard Henderson .e_ident[EI_MAG1] = ELFMAG1, 55305872bbf2SRichard Henderson .e_ident[EI_MAG2] = ELFMAG2, 55315872bbf2SRichard Henderson .e_ident[EI_MAG3] = ELFMAG3, 55325872bbf2SRichard Henderson .e_ident[EI_CLASS] = ELF_CLASS, 55335872bbf2SRichard Henderson .e_ident[EI_DATA] = ELF_DATA, 55345872bbf2SRichard Henderson .e_ident[EI_VERSION] = EV_CURRENT, 55355872bbf2SRichard Henderson .e_type = ET_EXEC, 55365872bbf2SRichard Henderson .e_machine = ELF_HOST_MACHINE, 55375872bbf2SRichard Henderson .e_version = EV_CURRENT, 55385872bbf2SRichard Henderson .e_phoff = offsetof(struct ElfImage, phdr), 55395872bbf2SRichard Henderson .e_shoff = offsetof(struct ElfImage, shdr), 55405872bbf2SRichard Henderson .e_ehsize = sizeof(ElfW(Shdr)), 55415872bbf2SRichard Henderson .e_phentsize = sizeof(ElfW(Phdr)), 55425872bbf2SRichard Henderson .e_phnum = 1, 55435872bbf2SRichard Henderson .e_shentsize = sizeof(ElfW(Shdr)), 55445872bbf2SRichard Henderson .e_shnum = ARRAY_SIZE(img->shdr), 55455872bbf2SRichard Henderson .e_shstrndx = ARRAY_SIZE(img->shdr) - 1, 5546abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS 5547abbb3eaeSRichard Henderson .e_flags = ELF_HOST_FLAGS, 5548abbb3eaeSRichard Henderson #endif 5549abbb3eaeSRichard Henderson #ifdef ELF_OSABI 5550abbb3eaeSRichard Henderson .e_ident[EI_OSABI] = ELF_OSABI, 5551abbb3eaeSRichard Henderson #endif 55525872bbf2SRichard Henderson }, 55535872bbf2SRichard Henderson .phdr = { 55545872bbf2SRichard Henderson .p_type = PT_LOAD, 55555872bbf2SRichard Henderson .p_flags = PF_X, 55565872bbf2SRichard Henderson }, 55575872bbf2SRichard Henderson .shdr = { 55585872bbf2SRichard Henderson [0] = { .sh_type = SHT_NULL }, 55595872bbf2SRichard Henderson /* Trick: The contents of code_gen_buffer are not present in 55605872bbf2SRichard Henderson this fake ELF file; that got allocated elsewhere. Therefore 55615872bbf2SRichard Henderson we mark .text as SHT_NOBITS (similar to .bss) so that readers 55625872bbf2SRichard Henderson will not look for contents. We can record any address. */ 55635872bbf2SRichard Henderson [1] = { /* .text */ 55645872bbf2SRichard Henderson .sh_type = SHT_NOBITS, 55655872bbf2SRichard Henderson .sh_flags = SHF_EXECINSTR | SHF_ALLOC, 55665872bbf2SRichard Henderson }, 55675872bbf2SRichard Henderson [2] = { /* .debug_info */ 55685872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 55695872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, di), 55705872bbf2SRichard Henderson .sh_size = sizeof(struct DebugInfo), 55715872bbf2SRichard Henderson }, 55725872bbf2SRichard Henderson [3] = { /* .debug_abbrev */ 55735872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 55745872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, da), 55755872bbf2SRichard Henderson .sh_size = sizeof(img->da), 55765872bbf2SRichard Henderson }, 55775872bbf2SRichard Henderson [4] = { /* .debug_frame */ 55785872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 55795872bbf2SRichard Henderson .sh_offset = sizeof(struct ElfImage), 55805872bbf2SRichard Henderson }, 55815872bbf2SRichard Henderson [5] = { /* .symtab */ 55825872bbf2SRichard Henderson .sh_type = SHT_SYMTAB, 55835872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, sym), 55845872bbf2SRichard Henderson .sh_size = sizeof(img->sym), 55855872bbf2SRichard Henderson .sh_info = 1, 55865872bbf2SRichard Henderson .sh_link = ARRAY_SIZE(img->shdr) - 1, 55875872bbf2SRichard Henderson .sh_entsize = sizeof(ElfW(Sym)), 55885872bbf2SRichard Henderson }, 55895872bbf2SRichard Henderson [6] = { /* .strtab */ 55905872bbf2SRichard Henderson .sh_type = SHT_STRTAB, 55915872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, str), 55925872bbf2SRichard Henderson .sh_size = sizeof(img->str), 55935872bbf2SRichard Henderson } 55945872bbf2SRichard Henderson }, 55955872bbf2SRichard Henderson .sym = { 55965872bbf2SRichard Henderson [1] = { /* code_gen_buffer */ 55975872bbf2SRichard Henderson .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC), 55985872bbf2SRichard Henderson .st_shndx = 1, 55995872bbf2SRichard Henderson } 56005872bbf2SRichard Henderson }, 56015872bbf2SRichard Henderson .di = { 56025872bbf2SRichard Henderson .len = sizeof(struct DebugInfo) - 4, 56035872bbf2SRichard Henderson .version = 2, 56045872bbf2SRichard Henderson .ptr_size = sizeof(void *), 56055872bbf2SRichard Henderson .cu_die = 1, 56065872bbf2SRichard Henderson .cu_lang = 0x8001, /* DW_LANG_Mips_Assembler */ 56075872bbf2SRichard Henderson .fn_die = 2, 56085872bbf2SRichard Henderson .fn_name = "code_gen_buffer" 56095872bbf2SRichard Henderson }, 56105872bbf2SRichard Henderson .da = { 56115872bbf2SRichard Henderson 1, /* abbrev number (the cu) */ 56125872bbf2SRichard Henderson 0x11, 1, /* DW_TAG_compile_unit, has children */ 56135872bbf2SRichard Henderson 0x13, 0x5, /* DW_AT_language, DW_FORM_data2 */ 56145872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */ 56155872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */ 56165872bbf2SRichard Henderson 0, 0, /* end of abbrev */ 56175872bbf2SRichard Henderson 2, /* abbrev number (the fn) */ 56185872bbf2SRichard Henderson 0x2e, 0, /* DW_TAG_subprogram, no children */ 56195872bbf2SRichard Henderson 0x3, 0x8, /* DW_AT_name, DW_FORM_string */ 56205872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */ 56215872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */ 56225872bbf2SRichard Henderson 0, 0, /* end of abbrev */ 56235872bbf2SRichard Henderson 0 /* no more abbrev */ 56245872bbf2SRichard Henderson }, 56255872bbf2SRichard Henderson .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0" 56265872bbf2SRichard Henderson ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer", 5627813da627SRichard Henderson }; 5628813da627SRichard Henderson 5629813da627SRichard Henderson /* We only need a single jit entry; statically allocate it. */ 5630813da627SRichard Henderson static struct jit_code_entry one_entry; 5631813da627SRichard Henderson 56325872bbf2SRichard Henderson uintptr_t buf = (uintptr_t)buf_ptr; 5633813da627SRichard Henderson size_t img_size = sizeof(struct ElfImage) + debug_frame_size; 56342c90784aSRichard Henderson DebugFrameHeader *dfh; 5635813da627SRichard Henderson 56365872bbf2SRichard Henderson img = g_malloc(img_size); 56375872bbf2SRichard Henderson *img = img_template; 5638813da627SRichard Henderson 56395872bbf2SRichard Henderson img->phdr.p_vaddr = buf; 56405872bbf2SRichard Henderson img->phdr.p_paddr = buf; 56415872bbf2SRichard Henderson img->phdr.p_memsz = buf_size; 5642813da627SRichard Henderson 56435872bbf2SRichard Henderson img->shdr[1].sh_name = find_string(img->str, ".text"); 56445872bbf2SRichard Henderson img->shdr[1].sh_addr = buf; 56455872bbf2SRichard Henderson img->shdr[1].sh_size = buf_size; 5646813da627SRichard Henderson 56475872bbf2SRichard Henderson img->shdr[2].sh_name = find_string(img->str, ".debug_info"); 56485872bbf2SRichard Henderson img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev"); 56495872bbf2SRichard Henderson 56505872bbf2SRichard Henderson img->shdr[4].sh_name = find_string(img->str, ".debug_frame"); 56515872bbf2SRichard Henderson img->shdr[4].sh_size = debug_frame_size; 56525872bbf2SRichard Henderson 56535872bbf2SRichard Henderson img->shdr[5].sh_name = find_string(img->str, ".symtab"); 56545872bbf2SRichard Henderson img->shdr[6].sh_name = find_string(img->str, ".strtab"); 56555872bbf2SRichard Henderson 56565872bbf2SRichard Henderson img->sym[1].st_name = find_string(img->str, "code_gen_buffer"); 56575872bbf2SRichard Henderson img->sym[1].st_value = buf; 56585872bbf2SRichard Henderson img->sym[1].st_size = buf_size; 56595872bbf2SRichard Henderson 56605872bbf2SRichard Henderson img->di.cu_low_pc = buf; 566145aba097SRichard Henderson img->di.cu_high_pc = buf + buf_size; 56625872bbf2SRichard Henderson img->di.fn_low_pc = buf; 566345aba097SRichard Henderson img->di.fn_high_pc = buf + buf_size; 5664813da627SRichard Henderson 56652c90784aSRichard Henderson dfh = (DebugFrameHeader *)(img + 1); 56662c90784aSRichard Henderson memcpy(dfh, debug_frame, debug_frame_size); 56672c90784aSRichard Henderson dfh->fde.func_start = buf; 56682c90784aSRichard Henderson dfh->fde.func_len = buf_size; 56692c90784aSRichard Henderson 5670813da627SRichard Henderson #ifdef DEBUG_JIT 5671813da627SRichard Henderson /* Enable this block to be able to debug the ELF image file creation. 5672813da627SRichard Henderson One can use readelf, objdump, or other inspection utilities. */ 5673813da627SRichard Henderson { 5674eb6b2edfSBin Meng g_autofree char *jit = g_strdup_printf("%s/qemu.jit", g_get_tmp_dir()); 5675eb6b2edfSBin Meng FILE *f = fopen(jit, "w+b"); 5676813da627SRichard Henderson if (f) { 56775872bbf2SRichard Henderson if (fwrite(img, img_size, 1, f) != img_size) { 5678813da627SRichard Henderson /* Avoid stupid unused return value warning for fwrite. */ 5679813da627SRichard Henderson } 5680813da627SRichard Henderson fclose(f); 5681813da627SRichard Henderson } 5682813da627SRichard Henderson } 5683813da627SRichard Henderson #endif 5684813da627SRichard Henderson 5685813da627SRichard Henderson one_entry.symfile_addr = img; 5686813da627SRichard Henderson one_entry.symfile_size = img_size; 5687813da627SRichard Henderson 5688813da627SRichard Henderson __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; 5689813da627SRichard Henderson __jit_debug_descriptor.relevant_entry = &one_entry; 5690813da627SRichard Henderson __jit_debug_descriptor.first_entry = &one_entry; 5691813da627SRichard Henderson __jit_debug_register_code(); 5692813da627SRichard Henderson } 5693813da627SRichard Henderson #else 56945872bbf2SRichard Henderson /* No support for the feature. Provide the entry point expected by exec.c, 56955872bbf2SRichard Henderson and implement the internal function we declared earlier. */ 5696813da627SRichard Henderson 5697755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size, 56982c90784aSRichard Henderson const void *debug_frame, 56992c90784aSRichard Henderson size_t debug_frame_size) 5700813da627SRichard Henderson { 5701813da627SRichard Henderson } 5702813da627SRichard Henderson 5703755bf9e5SRichard Henderson void tcg_register_jit(const void *buf, size_t buf_size) 5704813da627SRichard Henderson { 5705813da627SRichard Henderson } 5706813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */ 5707db432672SRichard Henderson 5708db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec 5709db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...) 5710db432672SRichard Henderson { 5711db432672SRichard Henderson g_assert_not_reached(); 5712db432672SRichard Henderson } 5713db432672SRichard Henderson #endif 5714