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" 371de7afc9SPaolo Bonzini #include "qemu/timer.h" 38084cfca1SRichard Henderson #include "qemu/cacheflush.h" 39c896fe29Sbellard 40c5d3c498SStefan Weil /* Note: the long term plan is to reduce the dependencies on the QEMU 41c896fe29Sbellard CPU definitions. Currently they are used for qemu_ld/st 42c896fe29Sbellard instructions */ 43c896fe29Sbellard #define NO_CPU_IO_DEFS 44c896fe29Sbellard 4563c91552SPaolo Bonzini #include "exec/exec-all.h" 46dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h" 47813da627SRichard Henderson 48edee2579SRichard Henderson #if UINTPTR_MAX == UINT32_MAX 49813da627SRichard Henderson # define ELF_CLASS ELFCLASS32 50edee2579SRichard Henderson #else 51edee2579SRichard Henderson # define ELF_CLASS ELFCLASS64 52813da627SRichard Henderson #endif 53813da627SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 54813da627SRichard Henderson # define ELF_DATA ELFDATA2MSB 55813da627SRichard Henderson #else 56813da627SRichard Henderson # define ELF_DATA ELFDATA2LSB 57813da627SRichard Henderson #endif 58813da627SRichard Henderson 59c896fe29Sbellard #include "elf.h" 60508127e2SPaolo Bonzini #include "exec/log.h" 615ff7258cSRichard Henderson #include "tcg-internal.h" 62c896fe29Sbellard 6322f15579SRichard Henderson #ifdef CONFIG_TCG_INTERPRETER 6422f15579SRichard Henderson #include <ffi.h> 6522f15579SRichard Henderson #endif 6622f15579SRichard Henderson 67139c1837SPaolo Bonzini /* Forward declarations for functions declared in tcg-target.c.inc and 68ce151109SPeter Maydell used here. */ 69e4d58b41SRichard Henderson static void tcg_target_init(TCGContext *s); 70e4d58b41SRichard Henderson static void tcg_target_qemu_prologue(TCGContext *s); 716ac17786SRichard Henderson static bool patch_reloc(tcg_insn_unit *code_ptr, int type, 722ba7fae2SRichard Henderson intptr_t value, intptr_t addend); 73c896fe29Sbellard 74497a22ebSRichard Henderson /* The CIE and FDE header definitions will be common to all hosts. */ 75497a22ebSRichard Henderson typedef struct { 76497a22ebSRichard Henderson uint32_t len __attribute__((aligned((sizeof(void *))))); 77497a22ebSRichard Henderson uint32_t id; 78497a22ebSRichard Henderson uint8_t version; 79497a22ebSRichard Henderson char augmentation[1]; 80497a22ebSRichard Henderson uint8_t code_align; 81497a22ebSRichard Henderson uint8_t data_align; 82497a22ebSRichard Henderson uint8_t return_column; 83497a22ebSRichard Henderson } DebugFrameCIE; 84497a22ebSRichard Henderson 85497a22ebSRichard Henderson typedef struct QEMU_PACKED { 86497a22ebSRichard Henderson uint32_t len __attribute__((aligned((sizeof(void *))))); 87497a22ebSRichard Henderson uint32_t cie_offset; 88edee2579SRichard Henderson uintptr_t func_start; 89edee2579SRichard Henderson uintptr_t func_len; 90497a22ebSRichard Henderson } DebugFrameFDEHeader; 91497a22ebSRichard Henderson 922c90784aSRichard Henderson typedef struct QEMU_PACKED { 932c90784aSRichard Henderson DebugFrameCIE cie; 942c90784aSRichard Henderson DebugFrameFDEHeader fde; 952c90784aSRichard Henderson } DebugFrameHeader; 962c90784aSRichard Henderson 97755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size, 982c90784aSRichard Henderson const void *debug_frame, 992c90784aSRichard Henderson size_t debug_frame_size) 100813da627SRichard Henderson __attribute__((unused)); 101813da627SRichard Henderson 102139c1837SPaolo Bonzini /* Forward declarations for functions declared and used in tcg-target.c.inc. */ 1032a534affSRichard Henderson static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1, 104a05b5b9bSRichard Henderson intptr_t arg2); 10578113e83SRichard Henderson static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg); 106c0ad3001SStefan Weil static void tcg_out_movi(TCGContext *s, TCGType type, 1072a534affSRichard Henderson TCGReg ret, tcg_target_long arg); 1085e8892dbSMiroslav Rezanina static void tcg_out_op(TCGContext *s, TCGOpcode opc, 1095e8892dbSMiroslav Rezanina const TCGArg args[TCG_MAX_OP_ARGS], 1105e8892dbSMiroslav Rezanina const int const_args[TCG_MAX_OP_ARGS]); 111d2fd745fSRichard Henderson #if TCG_TARGET_MAYBE_vec 112e7632cfaSRichard Henderson static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece, 113e7632cfaSRichard Henderson TCGReg dst, TCGReg src); 114d6ecb4a9SRichard Henderson static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece, 115d6ecb4a9SRichard Henderson TCGReg dst, TCGReg base, intptr_t offset); 1164e186175SRichard Henderson static void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece, 1174e186175SRichard Henderson TCGReg dst, int64_t arg); 1185e8892dbSMiroslav Rezanina static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, 1195e8892dbSMiroslav Rezanina unsigned vecl, unsigned vece, 1205e8892dbSMiroslav Rezanina const TCGArg args[TCG_MAX_OP_ARGS], 1215e8892dbSMiroslav Rezanina const int const_args[TCG_MAX_OP_ARGS]); 122d2fd745fSRichard Henderson #else 123e7632cfaSRichard Henderson static inline bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece, 124e7632cfaSRichard Henderson TCGReg dst, TCGReg src) 125e7632cfaSRichard Henderson { 126e7632cfaSRichard Henderson g_assert_not_reached(); 127e7632cfaSRichard Henderson } 128d6ecb4a9SRichard Henderson static inline bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece, 129d6ecb4a9SRichard Henderson TCGReg dst, TCGReg base, intptr_t offset) 130d6ecb4a9SRichard Henderson { 131d6ecb4a9SRichard Henderson g_assert_not_reached(); 132d6ecb4a9SRichard Henderson } 1334e186175SRichard Henderson static inline void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece, 1344e186175SRichard Henderson TCGReg dst, int64_t arg) 135e7632cfaSRichard Henderson { 136e7632cfaSRichard Henderson g_assert_not_reached(); 137e7632cfaSRichard Henderson } 1385e8892dbSMiroslav Rezanina static inline void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, 1395e8892dbSMiroslav Rezanina unsigned vecl, unsigned vece, 1405e8892dbSMiroslav Rezanina const TCGArg args[TCG_MAX_OP_ARGS], 1415e8892dbSMiroslav Rezanina const int const_args[TCG_MAX_OP_ARGS]) 142d2fd745fSRichard Henderson { 143d2fd745fSRichard Henderson g_assert_not_reached(); 144d2fd745fSRichard Henderson } 145d2fd745fSRichard Henderson #endif 1462a534affSRichard Henderson static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1, 147a05b5b9bSRichard Henderson intptr_t arg2); 14859d7c14eSRichard Henderson static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val, 14959d7c14eSRichard Henderson TCGReg base, intptr_t ofs); 1507b7d8b2dSRichard Henderson #ifdef CONFIG_TCG_INTERPRETER 1517b7d8b2dSRichard Henderson static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target, 1527b7d8b2dSRichard Henderson ffi_cif *cif); 1537b7d8b2dSRichard Henderson #else 1542be7d76bSRichard Henderson static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target); 1557b7d8b2dSRichard Henderson #endif 156a4fbbd77SRichard Henderson static bool tcg_target_const_match(int64_t val, TCGType type, int ct); 157659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS 158aeee05f5SRichard Henderson static int tcg_out_ldst_finalize(TCGContext *s); 159659ef5cbSRichard Henderson #endif 160c896fe29Sbellard 16142eb6dfcSRichard Henderson TCGContext tcg_init_ctx; 16242eb6dfcSRichard Henderson __thread TCGContext *tcg_ctx; 16342eb6dfcSRichard Henderson 1645ff7258cSRichard Henderson TCGContext **tcg_ctxs; 1650e2d61cfSRichard Henderson unsigned int tcg_cur_ctxs; 1660e2d61cfSRichard Henderson unsigned int tcg_max_ctxs; 1671c2adb95SRichard Henderson TCGv_env cpu_env = 0; 168c8bc1168SRichard Henderson const void *tcg_code_gen_epilogue; 169db0c51a3SRichard Henderson uintptr_t tcg_splitwx_diff; 170df2cce29SEmilio G. Cota 171b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 172b91ccb31SRichard Henderson tcg_prologue_fn *tcg_qemu_tb_exec; 173b91ccb31SRichard Henderson #endif 174b91ccb31SRichard Henderson 175d2fd745fSRichard Henderson static TCGRegSet tcg_target_available_regs[TCG_TYPE_COUNT]; 176b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs; 177c896fe29Sbellard 1781813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1 1794196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v) 180c896fe29Sbellard { 181c896fe29Sbellard *s->code_ptr++ = v; 182c896fe29Sbellard } 183c896fe29Sbellard 1844196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p, 1854196dca6SPeter Maydell uint8_t v) 1865c53bb81SPeter Maydell { 1871813e175SRichard Henderson *p = v; 1885c53bb81SPeter Maydell } 1891813e175SRichard Henderson #endif 1905c53bb81SPeter Maydell 1911813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2 1924196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v) 193c896fe29Sbellard { 1941813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 2) { 1951813e175SRichard Henderson *s->code_ptr++ = v; 1961813e175SRichard Henderson } else { 1971813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 1984387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 1991813e175SRichard Henderson s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE); 2001813e175SRichard Henderson } 201c896fe29Sbellard } 202c896fe29Sbellard 2034196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p, 2044196dca6SPeter Maydell uint16_t v) 2055c53bb81SPeter Maydell { 2061813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 2) { 2071813e175SRichard Henderson *p = v; 2081813e175SRichard Henderson } else { 2095c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 2105c53bb81SPeter Maydell } 2111813e175SRichard Henderson } 2121813e175SRichard Henderson #endif 2135c53bb81SPeter Maydell 2141813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4 2154196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v) 216c896fe29Sbellard { 2171813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 4) { 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 + (4 / TCG_TARGET_INSN_UNIT_SIZE); 2231813e175SRichard Henderson } 224c896fe29Sbellard } 225c896fe29Sbellard 2264196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p, 2274196dca6SPeter Maydell uint32_t v) 2285c53bb81SPeter Maydell { 2291813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 4) { 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 <= 8 2384196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v) 239ac26eb69SRichard Henderson { 2401813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 8) { 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 + (8 / TCG_TARGET_INSN_UNIT_SIZE); 2461813e175SRichard Henderson } 247ac26eb69SRichard Henderson } 248ac26eb69SRichard Henderson 2494196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p, 2504196dca6SPeter Maydell uint64_t v) 2515c53bb81SPeter Maydell { 2521813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 8) { 2531813e175SRichard Henderson *p = v; 2541813e175SRichard Henderson } else { 2555c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 2565c53bb81SPeter Maydell } 2571813e175SRichard Henderson } 2581813e175SRichard Henderson #endif 2595c53bb81SPeter Maydell 260c896fe29Sbellard /* label relocation processing */ 261c896fe29Sbellard 2621813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type, 263bec16311SRichard Henderson TCGLabel *l, intptr_t addend) 264c896fe29Sbellard { 2657ecd02a0SRichard Henderson TCGRelocation *r = tcg_malloc(sizeof(TCGRelocation)); 266c896fe29Sbellard 267c896fe29Sbellard r->type = type; 268c896fe29Sbellard r->ptr = code_ptr; 269c896fe29Sbellard r->addend = addend; 2707ecd02a0SRichard Henderson QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next); 271c896fe29Sbellard } 272c896fe29Sbellard 27392ab8e7dSRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l) 274c896fe29Sbellard { 275eabb7b91SAurelien Jarno tcg_debug_assert(!l->has_value); 276c896fe29Sbellard l->has_value = 1; 27792ab8e7dSRichard Henderson l->u.value_ptr = tcg_splitwx_to_rx(s->code_ptr); 278c896fe29Sbellard } 279c896fe29Sbellard 28042a268c2SRichard Henderson TCGLabel *gen_new_label(void) 281c896fe29Sbellard { 282b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 28351e3972cSRichard Henderson TCGLabel *l = tcg_malloc(sizeof(TCGLabel)); 284c896fe29Sbellard 2857ecd02a0SRichard Henderson memset(l, 0, sizeof(TCGLabel)); 2867ecd02a0SRichard Henderson l->id = s->nb_labels++; 2877ecd02a0SRichard Henderson QSIMPLEQ_INIT(&l->relocs); 2887ecd02a0SRichard Henderson 289bef16ab4SRichard Henderson QSIMPLEQ_INSERT_TAIL(&s->labels, l, next); 29042a268c2SRichard Henderson 29142a268c2SRichard Henderson return l; 292c896fe29Sbellard } 293c896fe29Sbellard 2947ecd02a0SRichard Henderson static bool tcg_resolve_relocs(TCGContext *s) 2957ecd02a0SRichard Henderson { 2967ecd02a0SRichard Henderson TCGLabel *l; 2977ecd02a0SRichard Henderson 2987ecd02a0SRichard Henderson QSIMPLEQ_FOREACH(l, &s->labels, next) { 2997ecd02a0SRichard Henderson TCGRelocation *r; 3007ecd02a0SRichard Henderson uintptr_t value = l->u.value; 3017ecd02a0SRichard Henderson 3027ecd02a0SRichard Henderson QSIMPLEQ_FOREACH(r, &l->relocs, next) { 3037ecd02a0SRichard Henderson if (!patch_reloc(r->ptr, r->type, value, r->addend)) { 3047ecd02a0SRichard Henderson return false; 3057ecd02a0SRichard Henderson } 3067ecd02a0SRichard Henderson } 3077ecd02a0SRichard Henderson } 3087ecd02a0SRichard Henderson return true; 3097ecd02a0SRichard Henderson } 3107ecd02a0SRichard Henderson 3119f754620SRichard Henderson static void set_jmp_reset_offset(TCGContext *s, int which) 3129f754620SRichard Henderson { 313f14bed3fSRichard Henderson /* 314f14bed3fSRichard Henderson * We will check for overflow at the end of the opcode loop in 315f14bed3fSRichard Henderson * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX. 316f14bed3fSRichard Henderson */ 317f14bed3fSRichard Henderson s->tb_jmp_reset_offset[which] = tcg_current_code_size(s); 3189f754620SRichard Henderson } 3199f754620SRichard Henderson 320db6b7d0cSRichard Henderson /* Signal overflow, starting over with fewer guest insns. */ 321db6b7d0cSRichard Henderson static void QEMU_NORETURN tcg_raise_tb_overflow(TCGContext *s) 322db6b7d0cSRichard Henderson { 323db6b7d0cSRichard Henderson siglongjmp(s->jmp_trans, -2); 324db6b7d0cSRichard Henderson } 325db6b7d0cSRichard Henderson 3264c22e840SRichard Henderson #define C_PFX1(P, A) P##A 3274c22e840SRichard Henderson #define C_PFX2(P, A, B) P##A##_##B 3284c22e840SRichard Henderson #define C_PFX3(P, A, B, C) P##A##_##B##_##C 3294c22e840SRichard Henderson #define C_PFX4(P, A, B, C, D) P##A##_##B##_##C##_##D 3304c22e840SRichard Henderson #define C_PFX5(P, A, B, C, D, E) P##A##_##B##_##C##_##D##_##E 3314c22e840SRichard Henderson #define C_PFX6(P, A, B, C, D, E, F) P##A##_##B##_##C##_##D##_##E##_##F 3324c22e840SRichard Henderson 3334c22e840SRichard Henderson /* Define an enumeration for the various combinations. */ 3344c22e840SRichard Henderson 3354c22e840SRichard Henderson #define C_O0_I1(I1) C_PFX1(c_o0_i1_, I1), 3364c22e840SRichard Henderson #define C_O0_I2(I1, I2) C_PFX2(c_o0_i2_, I1, I2), 3374c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3) C_PFX3(c_o0_i3_, I1, I2, I3), 3384c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4) C_PFX4(c_o0_i4_, I1, I2, I3, I4), 3394c22e840SRichard Henderson 3404c22e840SRichard Henderson #define C_O1_I1(O1, I1) C_PFX2(c_o1_i1_, O1, I1), 3414c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2) C_PFX3(c_o1_i2_, O1, I1, I2), 3424c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3) C_PFX4(c_o1_i3_, O1, I1, I2, I3), 3434c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4) C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4), 3444c22e840SRichard Henderson 3454c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2) C_PFX3(c_n1_i2_, O1, I1, I2), 3464c22e840SRichard Henderson 3474c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1) C_PFX3(c_o2_i1_, O1, O2, I1), 3484c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2) C_PFX4(c_o2_i2_, O1, O2, I1, I2), 3494c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3) C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3), 3504c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4), 3514c22e840SRichard Henderson 3524c22e840SRichard Henderson typedef enum { 3534c22e840SRichard Henderson #include "tcg-target-con-set.h" 3544c22e840SRichard Henderson } TCGConstraintSetIndex; 3554c22e840SRichard Henderson 3564c22e840SRichard Henderson static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode); 3574c22e840SRichard Henderson 3584c22e840SRichard Henderson #undef C_O0_I1 3594c22e840SRichard Henderson #undef C_O0_I2 3604c22e840SRichard Henderson #undef C_O0_I3 3614c22e840SRichard Henderson #undef C_O0_I4 3624c22e840SRichard Henderson #undef C_O1_I1 3634c22e840SRichard Henderson #undef C_O1_I2 3644c22e840SRichard Henderson #undef C_O1_I3 3654c22e840SRichard Henderson #undef C_O1_I4 3664c22e840SRichard Henderson #undef C_N1_I2 3674c22e840SRichard Henderson #undef C_O2_I1 3684c22e840SRichard Henderson #undef C_O2_I2 3694c22e840SRichard Henderson #undef C_O2_I3 3704c22e840SRichard Henderson #undef C_O2_I4 3714c22e840SRichard Henderson 3724c22e840SRichard Henderson /* Put all of the constraint sets into an array, indexed by the enum. */ 3734c22e840SRichard Henderson 3744c22e840SRichard Henderson #define C_O0_I1(I1) { .args_ct_str = { #I1 } }, 3754c22e840SRichard Henderson #define C_O0_I2(I1, I2) { .args_ct_str = { #I1, #I2 } }, 3764c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3) { .args_ct_str = { #I1, #I2, #I3 } }, 3774c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4) { .args_ct_str = { #I1, #I2, #I3, #I4 } }, 3784c22e840SRichard Henderson 3794c22e840SRichard Henderson #define C_O1_I1(O1, I1) { .args_ct_str = { #O1, #I1 } }, 3804c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2) { .args_ct_str = { #O1, #I1, #I2 } }, 3814c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3) { .args_ct_str = { #O1, #I1, #I2, #I3 } }, 3824c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4) { .args_ct_str = { #O1, #I1, #I2, #I3, #I4 } }, 3834c22e840SRichard Henderson 3844c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2) { .args_ct_str = { "&" #O1, #I1, #I2 } }, 3854c22e840SRichard Henderson 3864c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1) { .args_ct_str = { #O1, #O2, #I1 } }, 3874c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2) { .args_ct_str = { #O1, #O2, #I1, #I2 } }, 3884c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3) { .args_ct_str = { #O1, #O2, #I1, #I2, #I3 } }, 3894c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) { .args_ct_str = { #O1, #O2, #I1, #I2, #I3, #I4 } }, 3904c22e840SRichard Henderson 3914c22e840SRichard Henderson static const TCGTargetOpDef constraint_sets[] = { 3924c22e840SRichard Henderson #include "tcg-target-con-set.h" 3934c22e840SRichard Henderson }; 3944c22e840SRichard Henderson 3954c22e840SRichard Henderson 3964c22e840SRichard Henderson #undef C_O0_I1 3974c22e840SRichard Henderson #undef C_O0_I2 3984c22e840SRichard Henderson #undef C_O0_I3 3994c22e840SRichard Henderson #undef C_O0_I4 4004c22e840SRichard Henderson #undef C_O1_I1 4014c22e840SRichard Henderson #undef C_O1_I2 4024c22e840SRichard Henderson #undef C_O1_I3 4034c22e840SRichard Henderson #undef C_O1_I4 4044c22e840SRichard Henderson #undef C_N1_I2 4054c22e840SRichard Henderson #undef C_O2_I1 4064c22e840SRichard Henderson #undef C_O2_I2 4074c22e840SRichard Henderson #undef C_O2_I3 4084c22e840SRichard Henderson #undef C_O2_I4 4094c22e840SRichard Henderson 4104c22e840SRichard Henderson /* Expand the enumerator to be returned from tcg_target_op_def(). */ 4114c22e840SRichard Henderson 4124c22e840SRichard Henderson #define C_O0_I1(I1) C_PFX1(c_o0_i1_, I1) 4134c22e840SRichard Henderson #define C_O0_I2(I1, I2) C_PFX2(c_o0_i2_, I1, I2) 4144c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3) C_PFX3(c_o0_i3_, I1, I2, I3) 4154c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4) C_PFX4(c_o0_i4_, I1, I2, I3, I4) 4164c22e840SRichard Henderson 4174c22e840SRichard Henderson #define C_O1_I1(O1, I1) C_PFX2(c_o1_i1_, O1, I1) 4184c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2) C_PFX3(c_o1_i2_, O1, I1, I2) 4194c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3) C_PFX4(c_o1_i3_, O1, I1, I2, I3) 4204c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4) C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4) 4214c22e840SRichard Henderson 4224c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2) C_PFX3(c_n1_i2_, O1, I1, I2) 4234c22e840SRichard Henderson 4244c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1) C_PFX3(c_o2_i1_, O1, O2, I1) 4254c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2) C_PFX4(c_o2_i2_, O1, O2, I1, I2) 4264c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3) C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3) 4274c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4) 4284c22e840SRichard Henderson 429139c1837SPaolo Bonzini #include "tcg-target.c.inc" 430c896fe29Sbellard 43138b47b19SEmilio G. Cota static void alloc_tcg_plugin_context(TCGContext *s) 43238b47b19SEmilio G. Cota { 43338b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN 43438b47b19SEmilio G. Cota s->plugin_tb = g_new0(struct qemu_plugin_tb, 1); 43538b47b19SEmilio G. Cota s->plugin_tb->insns = 43638b47b19SEmilio G. Cota g_ptr_array_new_with_free_func(qemu_plugin_insn_cleanup_fn); 43738b47b19SEmilio G. Cota #endif 43838b47b19SEmilio G. Cota } 43938b47b19SEmilio G. Cota 440e8feb96fSEmilio G. Cota /* 4413468b59eSEmilio G. Cota * All TCG threads except the parent (i.e. the one that called tcg_context_init 4423468b59eSEmilio G. Cota * and registered the target's TCG globals) must register with this function 4433468b59eSEmilio G. Cota * before initiating translation. 4443468b59eSEmilio G. Cota * 4453468b59eSEmilio G. Cota * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation 4463468b59eSEmilio G. Cota * of tcg_region_init() for the reasoning behind this. 4473468b59eSEmilio G. Cota * 4483468b59eSEmilio G. Cota * In softmmu each caller registers its context in tcg_ctxs[]. Note that in 4493468b59eSEmilio G. Cota * softmmu tcg_ctxs[] does not track tcg_ctx_init, since the initial context 4503468b59eSEmilio G. Cota * is not used anymore for translation once this function is called. 4513468b59eSEmilio G. Cota * 4523468b59eSEmilio G. Cota * Not tracking tcg_init_ctx in tcg_ctxs[] in softmmu keeps code that iterates 4533468b59eSEmilio G. Cota * over the array (e.g. tcg_code_size() the same for both softmmu and user-mode. 4543468b59eSEmilio G. Cota */ 4553468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY 4563468b59eSEmilio G. Cota void tcg_register_thread(void) 4573468b59eSEmilio G. Cota { 4583468b59eSEmilio G. Cota tcg_ctx = &tcg_init_ctx; 4593468b59eSEmilio G. Cota } 4603468b59eSEmilio G. Cota #else 4613468b59eSEmilio G. Cota void tcg_register_thread(void) 4623468b59eSEmilio G. Cota { 4633468b59eSEmilio G. Cota TCGContext *s = g_malloc(sizeof(*s)); 4643468b59eSEmilio G. Cota unsigned int i, n; 4653468b59eSEmilio G. Cota 4663468b59eSEmilio G. Cota *s = tcg_init_ctx; 4673468b59eSEmilio G. Cota 4683468b59eSEmilio G. Cota /* Relink mem_base. */ 4693468b59eSEmilio G. Cota for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) { 4703468b59eSEmilio G. Cota if (tcg_init_ctx.temps[i].mem_base) { 4713468b59eSEmilio G. Cota ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps; 4723468b59eSEmilio G. Cota tcg_debug_assert(b >= 0 && b < n); 4733468b59eSEmilio G. Cota s->temps[i].mem_base = &s->temps[b]; 4743468b59eSEmilio G. Cota } 4753468b59eSEmilio G. Cota } 4763468b59eSEmilio G. Cota 4773468b59eSEmilio G. Cota /* Claim an entry in tcg_ctxs */ 4780e2d61cfSRichard Henderson n = qatomic_fetch_inc(&tcg_cur_ctxs); 4790e2d61cfSRichard Henderson g_assert(n < tcg_max_ctxs); 480d73415a3SStefan Hajnoczi qatomic_set(&tcg_ctxs[n], s); 4813468b59eSEmilio G. Cota 48238b47b19SEmilio G. Cota if (n > 0) { 48338b47b19SEmilio G. Cota alloc_tcg_plugin_context(s); 484bf042e8eSRichard Henderson tcg_region_initial_alloc(s); 48538b47b19SEmilio G. Cota } 48638b47b19SEmilio G. Cota 4873468b59eSEmilio G. Cota tcg_ctx = s; 4883468b59eSEmilio G. Cota } 4893468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */ 4903468b59eSEmilio G. Cota 491c896fe29Sbellard /* pool based memory allocation */ 492c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size) 493c896fe29Sbellard { 494c896fe29Sbellard TCGPool *p; 495c896fe29Sbellard int pool_size; 496c896fe29Sbellard 497c896fe29Sbellard if (size > TCG_POOL_CHUNK_SIZE) { 498c896fe29Sbellard /* big malloc: insert a new pool (XXX: could optimize) */ 4997267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + size); 500c896fe29Sbellard p->size = size; 5014055299eSKirill Batuzov p->next = s->pool_first_large; 5024055299eSKirill Batuzov s->pool_first_large = p; 5034055299eSKirill Batuzov return p->data; 504c896fe29Sbellard } else { 505c896fe29Sbellard p = s->pool_current; 506c896fe29Sbellard if (!p) { 507c896fe29Sbellard p = s->pool_first; 508c896fe29Sbellard if (!p) 509c896fe29Sbellard goto new_pool; 510c896fe29Sbellard } else { 511c896fe29Sbellard if (!p->next) { 512c896fe29Sbellard new_pool: 513c896fe29Sbellard pool_size = TCG_POOL_CHUNK_SIZE; 5147267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + pool_size); 515c896fe29Sbellard p->size = pool_size; 516c896fe29Sbellard p->next = NULL; 517c896fe29Sbellard if (s->pool_current) 518c896fe29Sbellard s->pool_current->next = p; 519c896fe29Sbellard else 520c896fe29Sbellard s->pool_first = p; 521c896fe29Sbellard } else { 522c896fe29Sbellard p = p->next; 523c896fe29Sbellard } 524c896fe29Sbellard } 525c896fe29Sbellard } 526c896fe29Sbellard s->pool_current = p; 527c896fe29Sbellard s->pool_cur = p->data + size; 528c896fe29Sbellard s->pool_end = p->data + p->size; 529c896fe29Sbellard return p->data; 530c896fe29Sbellard } 531c896fe29Sbellard 532c896fe29Sbellard void tcg_pool_reset(TCGContext *s) 533c896fe29Sbellard { 5344055299eSKirill Batuzov TCGPool *p, *t; 5354055299eSKirill Batuzov for (p = s->pool_first_large; p; p = t) { 5364055299eSKirill Batuzov t = p->next; 5374055299eSKirill Batuzov g_free(p); 5384055299eSKirill Batuzov } 5394055299eSKirill Batuzov s->pool_first_large = NULL; 540c896fe29Sbellard s->pool_cur = s->pool_end = NULL; 541c896fe29Sbellard s->pool_current = NULL; 542c896fe29Sbellard } 543c896fe29Sbellard 5442ef6175aSRichard Henderson #include "exec/helper-proto.h" 5452ef6175aSRichard Henderson 546100b5e01SRichard Henderson static const TCGHelperInfo all_helpers[] = { 5472ef6175aSRichard Henderson #include "exec/helper-tcg.h" 548100b5e01SRichard Henderson }; 549619205fdSEmilio G. Cota static GHashTable *helper_table; 550100b5e01SRichard Henderson 55122f15579SRichard Henderson #ifdef CONFIG_TCG_INTERPRETER 55222f15579SRichard Henderson static GHashTable *ffi_table; 55322f15579SRichard Henderson 55422f15579SRichard Henderson static ffi_type * const typecode_to_ffi[8] = { 55522f15579SRichard Henderson [dh_typecode_void] = &ffi_type_void, 55622f15579SRichard Henderson [dh_typecode_i32] = &ffi_type_uint32, 55722f15579SRichard Henderson [dh_typecode_s32] = &ffi_type_sint32, 55822f15579SRichard Henderson [dh_typecode_i64] = &ffi_type_uint64, 55922f15579SRichard Henderson [dh_typecode_s64] = &ffi_type_sint64, 56022f15579SRichard Henderson [dh_typecode_ptr] = &ffi_type_pointer, 56122f15579SRichard Henderson }; 56222f15579SRichard Henderson #endif 56322f15579SRichard Henderson 56491478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)]; 565f69d277eSRichard Henderson static void process_op_defs(TCGContext *s); 5661c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type, 5671c2adb95SRichard Henderson TCGReg reg, const char *name); 56891478cefSRichard Henderson 56943b972b7SRichard Henderson static void tcg_context_init(unsigned max_cpus) 570c896fe29Sbellard { 571a76aabd3SRichard Henderson TCGContext *s = &tcg_init_ctx; 572100b5e01SRichard Henderson int op, total_args, n, i; 573c896fe29Sbellard TCGOpDef *def; 574c896fe29Sbellard TCGArgConstraint *args_ct; 5751c2adb95SRichard Henderson TCGTemp *ts; 576c896fe29Sbellard 577c896fe29Sbellard memset(s, 0, sizeof(*s)); 578c896fe29Sbellard s->nb_globals = 0; 579c896fe29Sbellard 580c896fe29Sbellard /* Count total number of arguments and allocate the corresponding 581c896fe29Sbellard space */ 582c896fe29Sbellard total_args = 0; 583c896fe29Sbellard for(op = 0; op < NB_OPS; op++) { 584c896fe29Sbellard def = &tcg_op_defs[op]; 585c896fe29Sbellard n = def->nb_iargs + def->nb_oargs; 586c896fe29Sbellard total_args += n; 587c896fe29Sbellard } 588c896fe29Sbellard 589bc2b17e6SRichard Henderson args_ct = g_new0(TCGArgConstraint, total_args); 590c896fe29Sbellard 591c896fe29Sbellard for(op = 0; op < NB_OPS; op++) { 592c896fe29Sbellard def = &tcg_op_defs[op]; 593c896fe29Sbellard def->args_ct = args_ct; 594c896fe29Sbellard n = def->nb_iargs + def->nb_oargs; 595c896fe29Sbellard args_ct += n; 596c896fe29Sbellard } 597c896fe29Sbellard 5985cd8f621SRichard Henderson /* Register helpers. */ 59984fd9dd3SRichard Henderson /* Use g_direct_hash/equal for direct pointer comparisons on func. */ 600619205fdSEmilio G. Cota helper_table = g_hash_table_new(NULL, NULL); 60184fd9dd3SRichard Henderson 602100b5e01SRichard Henderson for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) { 60384fd9dd3SRichard Henderson g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func, 60472866e82SRichard Henderson (gpointer)&all_helpers[i]); 605100b5e01SRichard Henderson } 6065cd8f621SRichard Henderson 60722f15579SRichard Henderson #ifdef CONFIG_TCG_INTERPRETER 60822f15579SRichard Henderson /* g_direct_hash/equal for direct comparisons on uint32_t. */ 60922f15579SRichard Henderson ffi_table = g_hash_table_new(NULL, NULL); 61022f15579SRichard Henderson for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) { 61122f15579SRichard Henderson struct { 61222f15579SRichard Henderson ffi_cif cif; 61322f15579SRichard Henderson ffi_type *args[]; 61422f15579SRichard Henderson } *ca; 61522f15579SRichard Henderson uint32_t typemask = all_helpers[i].typemask; 61622f15579SRichard Henderson gpointer hash = (gpointer)(uintptr_t)typemask; 61722f15579SRichard Henderson ffi_status status; 61822f15579SRichard Henderson int nargs; 61922f15579SRichard Henderson 62022f15579SRichard Henderson if (g_hash_table_lookup(ffi_table, hash)) { 62122f15579SRichard Henderson continue; 62222f15579SRichard Henderson } 62322f15579SRichard Henderson 62422f15579SRichard Henderson /* Ignoring the return type, find the last non-zero field. */ 62522f15579SRichard Henderson nargs = 32 - clz32(typemask >> 3); 62622f15579SRichard Henderson nargs = DIV_ROUND_UP(nargs, 3); 62722f15579SRichard Henderson 62822f15579SRichard Henderson ca = g_malloc0(sizeof(*ca) + nargs * sizeof(ffi_type *)); 62922f15579SRichard Henderson ca->cif.rtype = typecode_to_ffi[typemask & 7]; 63022f15579SRichard Henderson ca->cif.nargs = nargs; 63122f15579SRichard Henderson 63222f15579SRichard Henderson if (nargs != 0) { 63322f15579SRichard Henderson ca->cif.arg_types = ca->args; 63422f15579SRichard Henderson for (i = 0; i < nargs; ++i) { 63522f15579SRichard Henderson int typecode = extract32(typemask, (i + 1) * 3, 3); 63622f15579SRichard Henderson ca->args[i] = typecode_to_ffi[typecode]; 63722f15579SRichard Henderson } 63822f15579SRichard Henderson } 63922f15579SRichard Henderson 64022f15579SRichard Henderson status = ffi_prep_cif(&ca->cif, FFI_DEFAULT_ABI, nargs, 64122f15579SRichard Henderson ca->cif.rtype, ca->cif.arg_types); 64222f15579SRichard Henderson assert(status == FFI_OK); 64322f15579SRichard Henderson 64422f15579SRichard Henderson g_hash_table_insert(ffi_table, hash, (gpointer)&ca->cif); 64522f15579SRichard Henderson } 64622f15579SRichard Henderson #endif 64722f15579SRichard Henderson 648c896fe29Sbellard tcg_target_init(s); 649f69d277eSRichard Henderson process_op_defs(s); 65091478cefSRichard Henderson 65191478cefSRichard Henderson /* Reverse the order of the saved registers, assuming they're all at 65291478cefSRichard Henderson the start of tcg_target_reg_alloc_order. */ 65391478cefSRichard Henderson for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) { 65491478cefSRichard Henderson int r = tcg_target_reg_alloc_order[n]; 65591478cefSRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) { 65691478cefSRichard Henderson break; 65791478cefSRichard Henderson } 65891478cefSRichard Henderson } 65991478cefSRichard Henderson for (i = 0; i < n; ++i) { 66091478cefSRichard Henderson indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i]; 66191478cefSRichard Henderson } 66291478cefSRichard Henderson for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) { 66391478cefSRichard Henderson indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i]; 66491478cefSRichard Henderson } 665b1311c4aSEmilio G. Cota 66638b47b19SEmilio G. Cota alloc_tcg_plugin_context(s); 66738b47b19SEmilio G. Cota 668b1311c4aSEmilio G. Cota tcg_ctx = s; 6693468b59eSEmilio G. Cota /* 6703468b59eSEmilio G. Cota * In user-mode we simply share the init context among threads, since we 6713468b59eSEmilio G. Cota * use a single region. See the documentation tcg_region_init() for the 6723468b59eSEmilio G. Cota * reasoning behind this. 6733468b59eSEmilio G. Cota * In softmmu we will have at most max_cpus TCG threads. 6743468b59eSEmilio G. Cota */ 6753468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY 676df2cce29SEmilio G. Cota tcg_ctxs = &tcg_ctx; 6770e2d61cfSRichard Henderson tcg_cur_ctxs = 1; 6780e2d61cfSRichard Henderson tcg_max_ctxs = 1; 6793468b59eSEmilio G. Cota #else 6800e2d61cfSRichard Henderson tcg_max_ctxs = max_cpus; 6810e2d61cfSRichard Henderson tcg_ctxs = g_new0(TCGContext *, max_cpus); 6823468b59eSEmilio G. Cota #endif 6831c2adb95SRichard Henderson 6841c2adb95SRichard Henderson tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0)); 6851c2adb95SRichard Henderson ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env"); 6861c2adb95SRichard Henderson cpu_env = temp_tcgv_ptr(ts); 6879002ec79SRichard Henderson } 688b03cce8eSbellard 68943b972b7SRichard Henderson void tcg_init(size_t tb_size, int splitwx, unsigned max_cpus) 690a76aabd3SRichard Henderson { 69143b972b7SRichard Henderson tcg_context_init(max_cpus); 69243b972b7SRichard Henderson tcg_region_init(tb_size, splitwx, max_cpus); 693a76aabd3SRichard Henderson } 694a76aabd3SRichard Henderson 6956e3b2bfdSEmilio G. Cota /* 6966e3b2bfdSEmilio G. Cota * Allocate TBs right before their corresponding translated code, making 6976e3b2bfdSEmilio G. Cota * sure that TBs and code are on different cache lines. 6986e3b2bfdSEmilio G. Cota */ 6996e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s) 7006e3b2bfdSEmilio G. Cota { 7016e3b2bfdSEmilio G. Cota uintptr_t align = qemu_icache_linesize; 7026e3b2bfdSEmilio G. Cota TranslationBlock *tb; 7036e3b2bfdSEmilio G. Cota void *next; 7046e3b2bfdSEmilio G. Cota 705e8feb96fSEmilio G. Cota retry: 7066e3b2bfdSEmilio G. Cota tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align); 7076e3b2bfdSEmilio G. Cota next = (void *)ROUND_UP((uintptr_t)(tb + 1), align); 7086e3b2bfdSEmilio G. Cota 7096e3b2bfdSEmilio G. Cota if (unlikely(next > s->code_gen_highwater)) { 710e8feb96fSEmilio G. Cota if (tcg_region_alloc(s)) { 7116e3b2bfdSEmilio G. Cota return NULL; 7126e3b2bfdSEmilio G. Cota } 713e8feb96fSEmilio G. Cota goto retry; 714e8feb96fSEmilio G. Cota } 715d73415a3SStefan Hajnoczi qatomic_set(&s->code_gen_ptr, next); 71657a26946SRichard Henderson s->data_gen_ptr = NULL; 7176e3b2bfdSEmilio G. Cota return tb; 7186e3b2bfdSEmilio G. Cota } 7196e3b2bfdSEmilio G. Cota 7209002ec79SRichard Henderson void tcg_prologue_init(TCGContext *s) 7219002ec79SRichard Henderson { 722b0a0794aSRichard Henderson size_t prologue_size; 7238163b749SRichard Henderson 724b0a0794aSRichard Henderson s->code_ptr = s->code_gen_ptr; 725b0a0794aSRichard Henderson s->code_buf = s->code_gen_ptr; 7265b38ee31SRichard Henderson s->data_gen_ptr = NULL; 727b91ccb31SRichard Henderson 728b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 729b0a0794aSRichard Henderson tcg_qemu_tb_exec = (tcg_prologue_fn *)tcg_splitwx_to_rx(s->code_ptr); 730b91ccb31SRichard Henderson #endif 7318163b749SRichard Henderson 7325b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 7335b38ee31SRichard Henderson s->pool_labels = NULL; 7345b38ee31SRichard Henderson #endif 7355b38ee31SRichard Henderson 736653b87ebSRoman Bolshakov qemu_thread_jit_write(); 7378163b749SRichard Henderson /* Generate the prologue. */ 738b03cce8eSbellard tcg_target_qemu_prologue(s); 7395b38ee31SRichard Henderson 7405b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 7415b38ee31SRichard Henderson /* Allow the prologue to put e.g. guest_base into a pool entry. */ 7425b38ee31SRichard Henderson { 7431768987bSRichard Henderson int result = tcg_out_pool_finalize(s); 7441768987bSRichard Henderson tcg_debug_assert(result == 0); 7455b38ee31SRichard Henderson } 7465b38ee31SRichard Henderson #endif 7475b38ee31SRichard Henderson 748b0a0794aSRichard Henderson prologue_size = tcg_current_code_size(s); 749b0a0794aSRichard Henderson 750df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 751b0a0794aSRichard Henderson flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf), 752b0a0794aSRichard Henderson (uintptr_t)s->code_buf, prologue_size); 753df5d2b16SRichard Henderson #endif 7548163b749SRichard Henderson 755bf042e8eSRichard Henderson tcg_region_prologue_set(s); 756d6b64b2bSRichard Henderson 757d6b64b2bSRichard Henderson #ifdef DEBUG_DISAS 758d6b64b2bSRichard Henderson if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) { 759fc59d2d8SRobert Foley FILE *logfile = qemu_log_lock(); 7608163b749SRichard Henderson qemu_log("PROLOGUE: [size=%zu]\n", prologue_size); 7615b38ee31SRichard Henderson if (s->data_gen_ptr) { 762b0a0794aSRichard Henderson size_t code_size = s->data_gen_ptr - s->code_gen_ptr; 7635b38ee31SRichard Henderson size_t data_size = prologue_size - code_size; 7645b38ee31SRichard Henderson size_t i; 7655b38ee31SRichard Henderson 766b0a0794aSRichard Henderson log_disas(s->code_gen_ptr, code_size); 7675b38ee31SRichard Henderson 7685b38ee31SRichard Henderson for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) { 7695b38ee31SRichard Henderson if (sizeof(tcg_target_ulong) == 8) { 7705b38ee31SRichard Henderson qemu_log("0x%08" PRIxPTR ": .quad 0x%016" PRIx64 "\n", 7715b38ee31SRichard Henderson (uintptr_t)s->data_gen_ptr + i, 7725b38ee31SRichard Henderson *(uint64_t *)(s->data_gen_ptr + i)); 7735b38ee31SRichard Henderson } else { 7745b38ee31SRichard Henderson qemu_log("0x%08" PRIxPTR ": .long 0x%08x\n", 7755b38ee31SRichard Henderson (uintptr_t)s->data_gen_ptr + i, 7765b38ee31SRichard Henderson *(uint32_t *)(s->data_gen_ptr + i)); 7775b38ee31SRichard Henderson } 7785b38ee31SRichard Henderson } 7795b38ee31SRichard Henderson } else { 780b0a0794aSRichard Henderson log_disas(s->code_gen_ptr, prologue_size); 7815b38ee31SRichard Henderson } 782d6b64b2bSRichard Henderson qemu_log("\n"); 783d6b64b2bSRichard Henderson qemu_log_flush(); 784fc59d2d8SRobert Foley qemu_log_unlock(logfile); 785d6b64b2bSRichard Henderson } 786d6b64b2bSRichard Henderson #endif 787cedbcb01SEmilio G. Cota 7886eea0434SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 7896eea0434SRichard Henderson /* 7906eea0434SRichard Henderson * Assert that goto_ptr is implemented completely, setting an epilogue. 7916eea0434SRichard Henderson * For tci, we use NULL as the signal to return from the interpreter, 7926eea0434SRichard Henderson * so skip this check. 7936eea0434SRichard Henderson */ 794cedbcb01SEmilio G. Cota if (TCG_TARGET_HAS_goto_ptr) { 7958b5c2b62SRichard Henderson tcg_debug_assert(tcg_code_gen_epilogue != NULL); 796cedbcb01SEmilio G. Cota } 7976eea0434SRichard Henderson #endif 798c896fe29Sbellard } 799c896fe29Sbellard 800c896fe29Sbellard void tcg_func_start(TCGContext *s) 801c896fe29Sbellard { 802c896fe29Sbellard tcg_pool_reset(s); 803c896fe29Sbellard s->nb_temps = s->nb_globals; 8040ec9eabcSRichard Henderson 8050ec9eabcSRichard Henderson /* No temps have been previously allocated for size or locality. */ 8060ec9eabcSRichard Henderson memset(s->free_temps, 0, sizeof(s->free_temps)); 8070ec9eabcSRichard Henderson 808c0522136SRichard Henderson /* No constant temps have been previously allocated. */ 809c0522136SRichard Henderson for (int i = 0; i < TCG_TYPE_COUNT; ++i) { 810c0522136SRichard Henderson if (s->const_table[i]) { 811c0522136SRichard Henderson g_hash_table_remove_all(s->const_table[i]); 812c0522136SRichard Henderson } 813c0522136SRichard Henderson } 814c0522136SRichard Henderson 815abebf925SRichard Henderson s->nb_ops = 0; 816c896fe29Sbellard s->nb_labels = 0; 817c896fe29Sbellard s->current_frame_offset = s->frame_start; 818c896fe29Sbellard 8190a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG 8200a209d4bSRichard Henderson s->goto_tb_issue_mask = 0; 8210a209d4bSRichard Henderson #endif 8220a209d4bSRichard Henderson 82315fa08f8SRichard Henderson QTAILQ_INIT(&s->ops); 82415fa08f8SRichard Henderson QTAILQ_INIT(&s->free_ops); 825bef16ab4SRichard Henderson QSIMPLEQ_INIT(&s->labels); 826c896fe29Sbellard } 827c896fe29Sbellard 828ae30e866SRichard Henderson static TCGTemp *tcg_temp_alloc(TCGContext *s) 8297ca4b752SRichard Henderson { 8307ca4b752SRichard Henderson int n = s->nb_temps++; 831ae30e866SRichard Henderson 832ae30e866SRichard Henderson if (n >= TCG_MAX_TEMPS) { 833db6b7d0cSRichard Henderson tcg_raise_tb_overflow(s); 834ae30e866SRichard Henderson } 8357ca4b752SRichard Henderson return memset(&s->temps[n], 0, sizeof(TCGTemp)); 8367ca4b752SRichard Henderson } 8377ca4b752SRichard Henderson 838ae30e866SRichard Henderson static TCGTemp *tcg_global_alloc(TCGContext *s) 8397ca4b752SRichard Henderson { 840fa477d25SRichard Henderson TCGTemp *ts; 841fa477d25SRichard Henderson 8427ca4b752SRichard Henderson tcg_debug_assert(s->nb_globals == s->nb_temps); 843ae30e866SRichard Henderson tcg_debug_assert(s->nb_globals < TCG_MAX_TEMPS); 8447ca4b752SRichard Henderson s->nb_globals++; 845fa477d25SRichard Henderson ts = tcg_temp_alloc(s); 846ee17db83SRichard Henderson ts->kind = TEMP_GLOBAL; 847fa477d25SRichard Henderson 848fa477d25SRichard Henderson return ts; 849c896fe29Sbellard } 850c896fe29Sbellard 851085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type, 852b6638662SRichard Henderson TCGReg reg, const char *name) 853c896fe29Sbellard { 854c896fe29Sbellard TCGTemp *ts; 855c896fe29Sbellard 856b3a62939SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type != TCG_TYPE_I32) { 857c896fe29Sbellard tcg_abort(); 858b3a62939SRichard Henderson } 8597ca4b752SRichard Henderson 8607ca4b752SRichard Henderson ts = tcg_global_alloc(s); 861c896fe29Sbellard ts->base_type = type; 862c896fe29Sbellard ts->type = type; 863ee17db83SRichard Henderson ts->kind = TEMP_FIXED; 864c896fe29Sbellard ts->reg = reg; 865c896fe29Sbellard ts->name = name; 866c896fe29Sbellard tcg_regset_set_reg(s->reserved_regs, reg); 8677ca4b752SRichard Henderson 868085272b3SRichard Henderson return ts; 869a7812ae4Spbrook } 870a7812ae4Spbrook 871b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size) 872a7812ae4Spbrook { 873b3a62939SRichard Henderson s->frame_start = start; 874b3a62939SRichard Henderson s->frame_end = start + size; 875085272b3SRichard Henderson s->frame_temp 876085272b3SRichard Henderson = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame"); 877b3a62939SRichard Henderson } 878a7812ae4Spbrook 879085272b3SRichard Henderson TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base, 880e1ccc054SRichard Henderson intptr_t offset, const char *name) 881c896fe29Sbellard { 882b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 883dc41aa7dSRichard Henderson TCGTemp *base_ts = tcgv_ptr_temp(base); 8847ca4b752SRichard Henderson TCGTemp *ts = tcg_global_alloc(s); 885b3915dbbSRichard Henderson int indirect_reg = 0, bigendian = 0; 8867ca4b752SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 8877ca4b752SRichard Henderson bigendian = 1; 8887ca4b752SRichard Henderson #endif 889c896fe29Sbellard 890c0522136SRichard Henderson switch (base_ts->kind) { 891c0522136SRichard Henderson case TEMP_FIXED: 892c0522136SRichard Henderson break; 893c0522136SRichard Henderson case TEMP_GLOBAL: 8945a18407fSRichard Henderson /* We do not support double-indirect registers. */ 8955a18407fSRichard Henderson tcg_debug_assert(!base_ts->indirect_reg); 896b3915dbbSRichard Henderson base_ts->indirect_base = 1; 8975a18407fSRichard Henderson s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64 8985a18407fSRichard Henderson ? 2 : 1); 8995a18407fSRichard Henderson indirect_reg = 1; 900c0522136SRichard Henderson break; 901c0522136SRichard Henderson default: 902c0522136SRichard Henderson g_assert_not_reached(); 903b3915dbbSRichard Henderson } 904b3915dbbSRichard Henderson 9057ca4b752SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { 9067ca4b752SRichard Henderson TCGTemp *ts2 = tcg_global_alloc(s); 907c896fe29Sbellard char buf[64]; 9087ca4b752SRichard Henderson 9097ca4b752SRichard Henderson ts->base_type = TCG_TYPE_I64; 910c896fe29Sbellard ts->type = TCG_TYPE_I32; 911b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg; 912c896fe29Sbellard ts->mem_allocated = 1; 913b3a62939SRichard Henderson ts->mem_base = base_ts; 9147ca4b752SRichard Henderson ts->mem_offset = offset + bigendian * 4; 915c896fe29Sbellard pstrcpy(buf, sizeof(buf), name); 916c896fe29Sbellard pstrcat(buf, sizeof(buf), "_0"); 917c896fe29Sbellard ts->name = strdup(buf); 918c896fe29Sbellard 9197ca4b752SRichard Henderson tcg_debug_assert(ts2 == ts + 1); 9207ca4b752SRichard Henderson ts2->base_type = TCG_TYPE_I64; 9217ca4b752SRichard Henderson ts2->type = TCG_TYPE_I32; 922b3915dbbSRichard Henderson ts2->indirect_reg = indirect_reg; 9237ca4b752SRichard Henderson ts2->mem_allocated = 1; 9247ca4b752SRichard Henderson ts2->mem_base = base_ts; 9257ca4b752SRichard Henderson ts2->mem_offset = offset + (1 - bigendian) * 4; 926c896fe29Sbellard pstrcpy(buf, sizeof(buf), name); 927c896fe29Sbellard pstrcat(buf, sizeof(buf), "_1"); 928120c1084SRichard Henderson ts2->name = strdup(buf); 9297ca4b752SRichard Henderson } else { 930c896fe29Sbellard ts->base_type = type; 931c896fe29Sbellard ts->type = type; 932b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg; 933c896fe29Sbellard ts->mem_allocated = 1; 934b3a62939SRichard Henderson ts->mem_base = base_ts; 935c896fe29Sbellard ts->mem_offset = offset; 936c896fe29Sbellard ts->name = name; 937c896fe29Sbellard } 938085272b3SRichard Henderson return ts; 939c896fe29Sbellard } 940c896fe29Sbellard 9415bfa8034SRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, bool temp_local) 942c896fe29Sbellard { 943b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 944ee17db83SRichard Henderson TCGTempKind kind = temp_local ? TEMP_LOCAL : TEMP_NORMAL; 945c896fe29Sbellard TCGTemp *ts; 946641d5fbeSbellard int idx, k; 947c896fe29Sbellard 9480ec9eabcSRichard Henderson k = type + (temp_local ? TCG_TYPE_COUNT : 0); 9490ec9eabcSRichard Henderson idx = find_first_bit(s->free_temps[k].l, TCG_MAX_TEMPS); 9500ec9eabcSRichard Henderson if (idx < TCG_MAX_TEMPS) { 9510ec9eabcSRichard Henderson /* There is already an available temp with the right type. */ 9520ec9eabcSRichard Henderson clear_bit(idx, s->free_temps[k].l); 9530ec9eabcSRichard Henderson 954e8996ee0Sbellard ts = &s->temps[idx]; 955e8996ee0Sbellard ts->temp_allocated = 1; 9567ca4b752SRichard Henderson tcg_debug_assert(ts->base_type == type); 957ee17db83SRichard Henderson tcg_debug_assert(ts->kind == kind); 958e8996ee0Sbellard } else { 9597ca4b752SRichard Henderson ts = tcg_temp_alloc(s); 9607ca4b752SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { 9617ca4b752SRichard Henderson TCGTemp *ts2 = tcg_temp_alloc(s); 9627ca4b752SRichard Henderson 963c896fe29Sbellard ts->base_type = type; 964c896fe29Sbellard ts->type = TCG_TYPE_I32; 965e8996ee0Sbellard ts->temp_allocated = 1; 966ee17db83SRichard Henderson ts->kind = kind; 9677ca4b752SRichard Henderson 9687ca4b752SRichard Henderson tcg_debug_assert(ts2 == ts + 1); 9697ca4b752SRichard Henderson ts2->base_type = TCG_TYPE_I64; 9707ca4b752SRichard Henderson ts2->type = TCG_TYPE_I32; 9717ca4b752SRichard Henderson ts2->temp_allocated = 1; 972ee17db83SRichard Henderson ts2->kind = kind; 9737ca4b752SRichard Henderson } else { 974c896fe29Sbellard ts->base_type = type; 975c896fe29Sbellard ts->type = type; 976e8996ee0Sbellard ts->temp_allocated = 1; 977ee17db83SRichard Henderson ts->kind = kind; 978c896fe29Sbellard } 979e8996ee0Sbellard } 98027bfd83cSPeter Maydell 98127bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG) 98227bfd83cSPeter Maydell s->temps_in_use++; 98327bfd83cSPeter Maydell #endif 984085272b3SRichard Henderson return ts; 985c896fe29Sbellard } 986c896fe29Sbellard 987d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type) 988d2fd745fSRichard Henderson { 989d2fd745fSRichard Henderson TCGTemp *t; 990d2fd745fSRichard Henderson 991d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG 992d2fd745fSRichard Henderson switch (type) { 993d2fd745fSRichard Henderson case TCG_TYPE_V64: 994d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v64); 995d2fd745fSRichard Henderson break; 996d2fd745fSRichard Henderson case TCG_TYPE_V128: 997d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v128); 998d2fd745fSRichard Henderson break; 999d2fd745fSRichard Henderson case TCG_TYPE_V256: 1000d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v256); 1001d2fd745fSRichard Henderson break; 1002d2fd745fSRichard Henderson default: 1003d2fd745fSRichard Henderson g_assert_not_reached(); 1004d2fd745fSRichard Henderson } 1005d2fd745fSRichard Henderson #endif 1006d2fd745fSRichard Henderson 1007d2fd745fSRichard Henderson t = tcg_temp_new_internal(type, 0); 1008d2fd745fSRichard Henderson return temp_tcgv_vec(t); 1009d2fd745fSRichard Henderson } 1010d2fd745fSRichard Henderson 1011d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp. */ 1012d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match) 1013d2fd745fSRichard Henderson { 1014d2fd745fSRichard Henderson TCGTemp *t = tcgv_vec_temp(match); 1015d2fd745fSRichard Henderson 1016d2fd745fSRichard Henderson tcg_debug_assert(t->temp_allocated != 0); 1017d2fd745fSRichard Henderson 1018d2fd745fSRichard Henderson t = tcg_temp_new_internal(t->base_type, 0); 1019d2fd745fSRichard Henderson return temp_tcgv_vec(t); 1020d2fd745fSRichard Henderson } 1021d2fd745fSRichard Henderson 10225bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts) 1023c896fe29Sbellard { 1024b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1025085272b3SRichard Henderson int k, idx; 1026c896fe29Sbellard 1027c0522136SRichard Henderson /* In order to simplify users of tcg_constant_*, silently ignore free. */ 1028c0522136SRichard Henderson if (ts->kind == TEMP_CONST) { 1029c0522136SRichard Henderson return; 1030c0522136SRichard Henderson } 1031c0522136SRichard Henderson 103227bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG) 103327bfd83cSPeter Maydell s->temps_in_use--; 103427bfd83cSPeter Maydell if (s->temps_in_use < 0) { 103527bfd83cSPeter Maydell fprintf(stderr, "More temporaries freed than allocated!\n"); 103627bfd83cSPeter Maydell } 103727bfd83cSPeter Maydell #endif 103827bfd83cSPeter Maydell 1039ee17db83SRichard Henderson tcg_debug_assert(ts->kind < TEMP_GLOBAL); 1040eabb7b91SAurelien Jarno tcg_debug_assert(ts->temp_allocated != 0); 1041e8996ee0Sbellard ts->temp_allocated = 0; 10420ec9eabcSRichard Henderson 1043085272b3SRichard Henderson idx = temp_idx(ts); 1044ee17db83SRichard Henderson k = ts->base_type + (ts->kind == TEMP_NORMAL ? 0 : TCG_TYPE_COUNT); 10450ec9eabcSRichard Henderson set_bit(idx, s->free_temps[k].l); 1046e8996ee0Sbellard } 1047e8996ee0Sbellard 1048c0522136SRichard Henderson TCGTemp *tcg_constant_internal(TCGType type, int64_t val) 1049c0522136SRichard Henderson { 1050c0522136SRichard Henderson TCGContext *s = tcg_ctx; 1051c0522136SRichard Henderson GHashTable *h = s->const_table[type]; 1052c0522136SRichard Henderson TCGTemp *ts; 1053c0522136SRichard Henderson 1054c0522136SRichard Henderson if (h == NULL) { 1055c0522136SRichard Henderson h = g_hash_table_new(g_int64_hash, g_int64_equal); 1056c0522136SRichard Henderson s->const_table[type] = h; 1057c0522136SRichard Henderson } 1058c0522136SRichard Henderson 1059c0522136SRichard Henderson ts = g_hash_table_lookup(h, &val); 1060c0522136SRichard Henderson if (ts == NULL) { 1061c0522136SRichard Henderson ts = tcg_temp_alloc(s); 1062c0522136SRichard Henderson 1063c0522136SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { 1064c0522136SRichard Henderson TCGTemp *ts2 = tcg_temp_alloc(s); 1065c0522136SRichard Henderson 1066c0522136SRichard Henderson ts->base_type = TCG_TYPE_I64; 1067c0522136SRichard Henderson ts->type = TCG_TYPE_I32; 1068c0522136SRichard Henderson ts->kind = TEMP_CONST; 1069c0522136SRichard Henderson ts->temp_allocated = 1; 1070c0522136SRichard Henderson /* 1071c0522136SRichard Henderson * Retain the full value of the 64-bit constant in the low 1072c0522136SRichard Henderson * part, so that the hash table works. Actual uses will 1073c0522136SRichard Henderson * truncate the value to the low part. 1074c0522136SRichard Henderson */ 1075c0522136SRichard Henderson ts->val = val; 1076c0522136SRichard Henderson 1077c0522136SRichard Henderson tcg_debug_assert(ts2 == ts + 1); 1078c0522136SRichard Henderson ts2->base_type = TCG_TYPE_I64; 1079c0522136SRichard Henderson ts2->type = TCG_TYPE_I32; 1080c0522136SRichard Henderson ts2->kind = TEMP_CONST; 1081c0522136SRichard Henderson ts2->temp_allocated = 1; 1082c0522136SRichard Henderson ts2->val = val >> 32; 1083c0522136SRichard Henderson } else { 1084c0522136SRichard Henderson ts->base_type = type; 1085c0522136SRichard Henderson ts->type = type; 1086c0522136SRichard Henderson ts->kind = TEMP_CONST; 1087c0522136SRichard Henderson ts->temp_allocated = 1; 1088c0522136SRichard Henderson ts->val = val; 1089c0522136SRichard Henderson } 1090c0522136SRichard Henderson g_hash_table_insert(h, &ts->val, ts); 1091c0522136SRichard Henderson } 1092c0522136SRichard Henderson 1093c0522136SRichard Henderson return ts; 1094c0522136SRichard Henderson } 1095c0522136SRichard Henderson 1096c0522136SRichard Henderson TCGv_vec tcg_constant_vec(TCGType type, unsigned vece, int64_t val) 1097c0522136SRichard Henderson { 1098c0522136SRichard Henderson val = dup_const(vece, val); 1099c0522136SRichard Henderson return temp_tcgv_vec(tcg_constant_internal(type, val)); 1100c0522136SRichard Henderson } 1101c0522136SRichard Henderson 110288d4005bSRichard Henderson TCGv_vec tcg_constant_vec_matching(TCGv_vec match, unsigned vece, int64_t val) 110388d4005bSRichard Henderson { 110488d4005bSRichard Henderson TCGTemp *t = tcgv_vec_temp(match); 110588d4005bSRichard Henderson 110688d4005bSRichard Henderson tcg_debug_assert(t->temp_allocated != 0); 110788d4005bSRichard Henderson return tcg_constant_vec(t->base_type, vece, val); 110888d4005bSRichard Henderson } 110988d4005bSRichard Henderson 1110a7812ae4Spbrook TCGv_i32 tcg_const_i32(int32_t val) 1111a7812ae4Spbrook { 1112a7812ae4Spbrook TCGv_i32 t0; 1113a7812ae4Spbrook t0 = tcg_temp_new_i32(); 1114e8996ee0Sbellard tcg_gen_movi_i32(t0, val); 1115e8996ee0Sbellard return t0; 1116c896fe29Sbellard } 1117c896fe29Sbellard 1118a7812ae4Spbrook TCGv_i64 tcg_const_i64(int64_t val) 1119c896fe29Sbellard { 1120a7812ae4Spbrook TCGv_i64 t0; 1121a7812ae4Spbrook t0 = tcg_temp_new_i64(); 1122e8996ee0Sbellard tcg_gen_movi_i64(t0, val); 1123e8996ee0Sbellard return t0; 1124c896fe29Sbellard } 1125c896fe29Sbellard 1126a7812ae4Spbrook TCGv_i32 tcg_const_local_i32(int32_t val) 1127bdffd4a9Saurel32 { 1128a7812ae4Spbrook TCGv_i32 t0; 1129a7812ae4Spbrook t0 = tcg_temp_local_new_i32(); 1130bdffd4a9Saurel32 tcg_gen_movi_i32(t0, val); 1131bdffd4a9Saurel32 return t0; 1132bdffd4a9Saurel32 } 1133bdffd4a9Saurel32 1134a7812ae4Spbrook TCGv_i64 tcg_const_local_i64(int64_t val) 1135bdffd4a9Saurel32 { 1136a7812ae4Spbrook TCGv_i64 t0; 1137a7812ae4Spbrook t0 = tcg_temp_local_new_i64(); 1138bdffd4a9Saurel32 tcg_gen_movi_i64(t0, val); 1139bdffd4a9Saurel32 return t0; 1140bdffd4a9Saurel32 } 1141bdffd4a9Saurel32 114227bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG) 114327bfd83cSPeter Maydell void tcg_clear_temp_count(void) 114427bfd83cSPeter Maydell { 1145b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 114627bfd83cSPeter Maydell s->temps_in_use = 0; 114727bfd83cSPeter Maydell } 114827bfd83cSPeter Maydell 114927bfd83cSPeter Maydell int tcg_check_temp_count(void) 115027bfd83cSPeter Maydell { 1151b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 115227bfd83cSPeter Maydell if (s->temps_in_use) { 115327bfd83cSPeter Maydell /* Clear the count so that we don't give another 115427bfd83cSPeter Maydell * warning immediately next time around. 115527bfd83cSPeter Maydell */ 115627bfd83cSPeter Maydell s->temps_in_use = 0; 115727bfd83cSPeter Maydell return 1; 115827bfd83cSPeter Maydell } 115927bfd83cSPeter Maydell return 0; 116027bfd83cSPeter Maydell } 116127bfd83cSPeter Maydell #endif 116227bfd83cSPeter Maydell 1163be0f34b5SRichard Henderson /* Return true if OP may appear in the opcode stream. 1164be0f34b5SRichard Henderson Test the runtime variable that controls each opcode. */ 1165be0f34b5SRichard Henderson bool tcg_op_supported(TCGOpcode op) 1166be0f34b5SRichard Henderson { 1167d2fd745fSRichard Henderson const bool have_vec 1168d2fd745fSRichard Henderson = TCG_TARGET_HAS_v64 | TCG_TARGET_HAS_v128 | TCG_TARGET_HAS_v256; 1169d2fd745fSRichard Henderson 1170be0f34b5SRichard Henderson switch (op) { 1171be0f34b5SRichard Henderson case INDEX_op_discard: 1172be0f34b5SRichard Henderson case INDEX_op_set_label: 1173be0f34b5SRichard Henderson case INDEX_op_call: 1174be0f34b5SRichard Henderson case INDEX_op_br: 1175be0f34b5SRichard Henderson case INDEX_op_mb: 1176be0f34b5SRichard Henderson case INDEX_op_insn_start: 1177be0f34b5SRichard Henderson case INDEX_op_exit_tb: 1178be0f34b5SRichard Henderson case INDEX_op_goto_tb: 1179be0f34b5SRichard Henderson case INDEX_op_qemu_ld_i32: 1180be0f34b5SRichard Henderson case INDEX_op_qemu_st_i32: 1181be0f34b5SRichard Henderson case INDEX_op_qemu_ld_i64: 1182be0f34b5SRichard Henderson case INDEX_op_qemu_st_i64: 1183be0f34b5SRichard Henderson return true; 1184be0f34b5SRichard Henderson 118507ce0b05SRichard Henderson case INDEX_op_qemu_st8_i32: 118607ce0b05SRichard Henderson return TCG_TARGET_HAS_qemu_st8_i32; 118707ce0b05SRichard Henderson 1188be0f34b5SRichard Henderson case INDEX_op_goto_ptr: 1189be0f34b5SRichard Henderson return TCG_TARGET_HAS_goto_ptr; 1190be0f34b5SRichard Henderson 1191be0f34b5SRichard Henderson case INDEX_op_mov_i32: 1192be0f34b5SRichard Henderson case INDEX_op_setcond_i32: 1193be0f34b5SRichard Henderson case INDEX_op_brcond_i32: 1194be0f34b5SRichard Henderson case INDEX_op_ld8u_i32: 1195be0f34b5SRichard Henderson case INDEX_op_ld8s_i32: 1196be0f34b5SRichard Henderson case INDEX_op_ld16u_i32: 1197be0f34b5SRichard Henderson case INDEX_op_ld16s_i32: 1198be0f34b5SRichard Henderson case INDEX_op_ld_i32: 1199be0f34b5SRichard Henderson case INDEX_op_st8_i32: 1200be0f34b5SRichard Henderson case INDEX_op_st16_i32: 1201be0f34b5SRichard Henderson case INDEX_op_st_i32: 1202be0f34b5SRichard Henderson case INDEX_op_add_i32: 1203be0f34b5SRichard Henderson case INDEX_op_sub_i32: 1204be0f34b5SRichard Henderson case INDEX_op_mul_i32: 1205be0f34b5SRichard Henderson case INDEX_op_and_i32: 1206be0f34b5SRichard Henderson case INDEX_op_or_i32: 1207be0f34b5SRichard Henderson case INDEX_op_xor_i32: 1208be0f34b5SRichard Henderson case INDEX_op_shl_i32: 1209be0f34b5SRichard Henderson case INDEX_op_shr_i32: 1210be0f34b5SRichard Henderson case INDEX_op_sar_i32: 1211be0f34b5SRichard Henderson return true; 1212be0f34b5SRichard Henderson 1213be0f34b5SRichard Henderson case INDEX_op_movcond_i32: 1214be0f34b5SRichard Henderson return TCG_TARGET_HAS_movcond_i32; 1215be0f34b5SRichard Henderson case INDEX_op_div_i32: 1216be0f34b5SRichard Henderson case INDEX_op_divu_i32: 1217be0f34b5SRichard Henderson return TCG_TARGET_HAS_div_i32; 1218be0f34b5SRichard Henderson case INDEX_op_rem_i32: 1219be0f34b5SRichard Henderson case INDEX_op_remu_i32: 1220be0f34b5SRichard Henderson return TCG_TARGET_HAS_rem_i32; 1221be0f34b5SRichard Henderson case INDEX_op_div2_i32: 1222be0f34b5SRichard Henderson case INDEX_op_divu2_i32: 1223be0f34b5SRichard Henderson return TCG_TARGET_HAS_div2_i32; 1224be0f34b5SRichard Henderson case INDEX_op_rotl_i32: 1225be0f34b5SRichard Henderson case INDEX_op_rotr_i32: 1226be0f34b5SRichard Henderson return TCG_TARGET_HAS_rot_i32; 1227be0f34b5SRichard Henderson case INDEX_op_deposit_i32: 1228be0f34b5SRichard Henderson return TCG_TARGET_HAS_deposit_i32; 1229be0f34b5SRichard Henderson case INDEX_op_extract_i32: 1230be0f34b5SRichard Henderson return TCG_TARGET_HAS_extract_i32; 1231be0f34b5SRichard Henderson case INDEX_op_sextract_i32: 1232be0f34b5SRichard Henderson return TCG_TARGET_HAS_sextract_i32; 1233fce1296fSRichard Henderson case INDEX_op_extract2_i32: 1234fce1296fSRichard Henderson return TCG_TARGET_HAS_extract2_i32; 1235be0f34b5SRichard Henderson case INDEX_op_add2_i32: 1236be0f34b5SRichard Henderson return TCG_TARGET_HAS_add2_i32; 1237be0f34b5SRichard Henderson case INDEX_op_sub2_i32: 1238be0f34b5SRichard Henderson return TCG_TARGET_HAS_sub2_i32; 1239be0f34b5SRichard Henderson case INDEX_op_mulu2_i32: 1240be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulu2_i32; 1241be0f34b5SRichard Henderson case INDEX_op_muls2_i32: 1242be0f34b5SRichard Henderson return TCG_TARGET_HAS_muls2_i32; 1243be0f34b5SRichard Henderson case INDEX_op_muluh_i32: 1244be0f34b5SRichard Henderson return TCG_TARGET_HAS_muluh_i32; 1245be0f34b5SRichard Henderson case INDEX_op_mulsh_i32: 1246be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulsh_i32; 1247be0f34b5SRichard Henderson case INDEX_op_ext8s_i32: 1248be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8s_i32; 1249be0f34b5SRichard Henderson case INDEX_op_ext16s_i32: 1250be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16s_i32; 1251be0f34b5SRichard Henderson case INDEX_op_ext8u_i32: 1252be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8u_i32; 1253be0f34b5SRichard Henderson case INDEX_op_ext16u_i32: 1254be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16u_i32; 1255be0f34b5SRichard Henderson case INDEX_op_bswap16_i32: 1256be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap16_i32; 1257be0f34b5SRichard Henderson case INDEX_op_bswap32_i32: 1258be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap32_i32; 1259be0f34b5SRichard Henderson case INDEX_op_not_i32: 1260be0f34b5SRichard Henderson return TCG_TARGET_HAS_not_i32; 1261be0f34b5SRichard Henderson case INDEX_op_neg_i32: 1262be0f34b5SRichard Henderson return TCG_TARGET_HAS_neg_i32; 1263be0f34b5SRichard Henderson case INDEX_op_andc_i32: 1264be0f34b5SRichard Henderson return TCG_TARGET_HAS_andc_i32; 1265be0f34b5SRichard Henderson case INDEX_op_orc_i32: 1266be0f34b5SRichard Henderson return TCG_TARGET_HAS_orc_i32; 1267be0f34b5SRichard Henderson case INDEX_op_eqv_i32: 1268be0f34b5SRichard Henderson return TCG_TARGET_HAS_eqv_i32; 1269be0f34b5SRichard Henderson case INDEX_op_nand_i32: 1270be0f34b5SRichard Henderson return TCG_TARGET_HAS_nand_i32; 1271be0f34b5SRichard Henderson case INDEX_op_nor_i32: 1272be0f34b5SRichard Henderson return TCG_TARGET_HAS_nor_i32; 1273be0f34b5SRichard Henderson case INDEX_op_clz_i32: 1274be0f34b5SRichard Henderson return TCG_TARGET_HAS_clz_i32; 1275be0f34b5SRichard Henderson case INDEX_op_ctz_i32: 1276be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctz_i32; 1277be0f34b5SRichard Henderson case INDEX_op_ctpop_i32: 1278be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctpop_i32; 1279be0f34b5SRichard Henderson 1280be0f34b5SRichard Henderson case INDEX_op_brcond2_i32: 1281be0f34b5SRichard Henderson case INDEX_op_setcond2_i32: 1282be0f34b5SRichard Henderson return TCG_TARGET_REG_BITS == 32; 1283be0f34b5SRichard Henderson 1284be0f34b5SRichard Henderson case INDEX_op_mov_i64: 1285be0f34b5SRichard Henderson case INDEX_op_setcond_i64: 1286be0f34b5SRichard Henderson case INDEX_op_brcond_i64: 1287be0f34b5SRichard Henderson case INDEX_op_ld8u_i64: 1288be0f34b5SRichard Henderson case INDEX_op_ld8s_i64: 1289be0f34b5SRichard Henderson case INDEX_op_ld16u_i64: 1290be0f34b5SRichard Henderson case INDEX_op_ld16s_i64: 1291be0f34b5SRichard Henderson case INDEX_op_ld32u_i64: 1292be0f34b5SRichard Henderson case INDEX_op_ld32s_i64: 1293be0f34b5SRichard Henderson case INDEX_op_ld_i64: 1294be0f34b5SRichard Henderson case INDEX_op_st8_i64: 1295be0f34b5SRichard Henderson case INDEX_op_st16_i64: 1296be0f34b5SRichard Henderson case INDEX_op_st32_i64: 1297be0f34b5SRichard Henderson case INDEX_op_st_i64: 1298be0f34b5SRichard Henderson case INDEX_op_add_i64: 1299be0f34b5SRichard Henderson case INDEX_op_sub_i64: 1300be0f34b5SRichard Henderson case INDEX_op_mul_i64: 1301be0f34b5SRichard Henderson case INDEX_op_and_i64: 1302be0f34b5SRichard Henderson case INDEX_op_or_i64: 1303be0f34b5SRichard Henderson case INDEX_op_xor_i64: 1304be0f34b5SRichard Henderson case INDEX_op_shl_i64: 1305be0f34b5SRichard Henderson case INDEX_op_shr_i64: 1306be0f34b5SRichard Henderson case INDEX_op_sar_i64: 1307be0f34b5SRichard Henderson case INDEX_op_ext_i32_i64: 1308be0f34b5SRichard Henderson case INDEX_op_extu_i32_i64: 1309be0f34b5SRichard Henderson return TCG_TARGET_REG_BITS == 64; 1310be0f34b5SRichard Henderson 1311be0f34b5SRichard Henderson case INDEX_op_movcond_i64: 1312be0f34b5SRichard Henderson return TCG_TARGET_HAS_movcond_i64; 1313be0f34b5SRichard Henderson case INDEX_op_div_i64: 1314be0f34b5SRichard Henderson case INDEX_op_divu_i64: 1315be0f34b5SRichard Henderson return TCG_TARGET_HAS_div_i64; 1316be0f34b5SRichard Henderson case INDEX_op_rem_i64: 1317be0f34b5SRichard Henderson case INDEX_op_remu_i64: 1318be0f34b5SRichard Henderson return TCG_TARGET_HAS_rem_i64; 1319be0f34b5SRichard Henderson case INDEX_op_div2_i64: 1320be0f34b5SRichard Henderson case INDEX_op_divu2_i64: 1321be0f34b5SRichard Henderson return TCG_TARGET_HAS_div2_i64; 1322be0f34b5SRichard Henderson case INDEX_op_rotl_i64: 1323be0f34b5SRichard Henderson case INDEX_op_rotr_i64: 1324be0f34b5SRichard Henderson return TCG_TARGET_HAS_rot_i64; 1325be0f34b5SRichard Henderson case INDEX_op_deposit_i64: 1326be0f34b5SRichard Henderson return TCG_TARGET_HAS_deposit_i64; 1327be0f34b5SRichard Henderson case INDEX_op_extract_i64: 1328be0f34b5SRichard Henderson return TCG_TARGET_HAS_extract_i64; 1329be0f34b5SRichard Henderson case INDEX_op_sextract_i64: 1330be0f34b5SRichard Henderson return TCG_TARGET_HAS_sextract_i64; 1331fce1296fSRichard Henderson case INDEX_op_extract2_i64: 1332fce1296fSRichard Henderson return TCG_TARGET_HAS_extract2_i64; 1333be0f34b5SRichard Henderson case INDEX_op_extrl_i64_i32: 1334be0f34b5SRichard Henderson return TCG_TARGET_HAS_extrl_i64_i32; 1335be0f34b5SRichard Henderson case INDEX_op_extrh_i64_i32: 1336be0f34b5SRichard Henderson return TCG_TARGET_HAS_extrh_i64_i32; 1337be0f34b5SRichard Henderson case INDEX_op_ext8s_i64: 1338be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8s_i64; 1339be0f34b5SRichard Henderson case INDEX_op_ext16s_i64: 1340be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16s_i64; 1341be0f34b5SRichard Henderson case INDEX_op_ext32s_i64: 1342be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext32s_i64; 1343be0f34b5SRichard Henderson case INDEX_op_ext8u_i64: 1344be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8u_i64; 1345be0f34b5SRichard Henderson case INDEX_op_ext16u_i64: 1346be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16u_i64; 1347be0f34b5SRichard Henderson case INDEX_op_ext32u_i64: 1348be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext32u_i64; 1349be0f34b5SRichard Henderson case INDEX_op_bswap16_i64: 1350be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap16_i64; 1351be0f34b5SRichard Henderson case INDEX_op_bswap32_i64: 1352be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap32_i64; 1353be0f34b5SRichard Henderson case INDEX_op_bswap64_i64: 1354be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap64_i64; 1355be0f34b5SRichard Henderson case INDEX_op_not_i64: 1356be0f34b5SRichard Henderson return TCG_TARGET_HAS_not_i64; 1357be0f34b5SRichard Henderson case INDEX_op_neg_i64: 1358be0f34b5SRichard Henderson return TCG_TARGET_HAS_neg_i64; 1359be0f34b5SRichard Henderson case INDEX_op_andc_i64: 1360be0f34b5SRichard Henderson return TCG_TARGET_HAS_andc_i64; 1361be0f34b5SRichard Henderson case INDEX_op_orc_i64: 1362be0f34b5SRichard Henderson return TCG_TARGET_HAS_orc_i64; 1363be0f34b5SRichard Henderson case INDEX_op_eqv_i64: 1364be0f34b5SRichard Henderson return TCG_TARGET_HAS_eqv_i64; 1365be0f34b5SRichard Henderson case INDEX_op_nand_i64: 1366be0f34b5SRichard Henderson return TCG_TARGET_HAS_nand_i64; 1367be0f34b5SRichard Henderson case INDEX_op_nor_i64: 1368be0f34b5SRichard Henderson return TCG_TARGET_HAS_nor_i64; 1369be0f34b5SRichard Henderson case INDEX_op_clz_i64: 1370be0f34b5SRichard Henderson return TCG_TARGET_HAS_clz_i64; 1371be0f34b5SRichard Henderson case INDEX_op_ctz_i64: 1372be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctz_i64; 1373be0f34b5SRichard Henderson case INDEX_op_ctpop_i64: 1374be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctpop_i64; 1375be0f34b5SRichard Henderson case INDEX_op_add2_i64: 1376be0f34b5SRichard Henderson return TCG_TARGET_HAS_add2_i64; 1377be0f34b5SRichard Henderson case INDEX_op_sub2_i64: 1378be0f34b5SRichard Henderson return TCG_TARGET_HAS_sub2_i64; 1379be0f34b5SRichard Henderson case INDEX_op_mulu2_i64: 1380be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulu2_i64; 1381be0f34b5SRichard Henderson case INDEX_op_muls2_i64: 1382be0f34b5SRichard Henderson return TCG_TARGET_HAS_muls2_i64; 1383be0f34b5SRichard Henderson case INDEX_op_muluh_i64: 1384be0f34b5SRichard Henderson return TCG_TARGET_HAS_muluh_i64; 1385be0f34b5SRichard Henderson case INDEX_op_mulsh_i64: 1386be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulsh_i64; 1387be0f34b5SRichard Henderson 1388d2fd745fSRichard Henderson case INDEX_op_mov_vec: 1389d2fd745fSRichard Henderson case INDEX_op_dup_vec: 139037ee55a0SRichard Henderson case INDEX_op_dupm_vec: 1391d2fd745fSRichard Henderson case INDEX_op_ld_vec: 1392d2fd745fSRichard Henderson case INDEX_op_st_vec: 1393d2fd745fSRichard Henderson case INDEX_op_add_vec: 1394d2fd745fSRichard Henderson case INDEX_op_sub_vec: 1395d2fd745fSRichard Henderson case INDEX_op_and_vec: 1396d2fd745fSRichard Henderson case INDEX_op_or_vec: 1397d2fd745fSRichard Henderson case INDEX_op_xor_vec: 1398212be173SRichard Henderson case INDEX_op_cmp_vec: 1399d2fd745fSRichard Henderson return have_vec; 1400d2fd745fSRichard Henderson case INDEX_op_dup2_vec: 1401d2fd745fSRichard Henderson return have_vec && TCG_TARGET_REG_BITS == 32; 1402d2fd745fSRichard Henderson case INDEX_op_not_vec: 1403d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_not_vec; 1404d2fd745fSRichard Henderson case INDEX_op_neg_vec: 1405d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_neg_vec; 1406bcefc902SRichard Henderson case INDEX_op_abs_vec: 1407bcefc902SRichard Henderson return have_vec && TCG_TARGET_HAS_abs_vec; 1408d2fd745fSRichard Henderson case INDEX_op_andc_vec: 1409d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_andc_vec; 1410d2fd745fSRichard Henderson case INDEX_op_orc_vec: 1411d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_orc_vec; 14123774030aSRichard Henderson case INDEX_op_mul_vec: 14133774030aSRichard Henderson return have_vec && TCG_TARGET_HAS_mul_vec; 1414d0ec9796SRichard Henderson case INDEX_op_shli_vec: 1415d0ec9796SRichard Henderson case INDEX_op_shri_vec: 1416d0ec9796SRichard Henderson case INDEX_op_sari_vec: 1417d0ec9796SRichard Henderson return have_vec && TCG_TARGET_HAS_shi_vec; 1418d0ec9796SRichard Henderson case INDEX_op_shls_vec: 1419d0ec9796SRichard Henderson case INDEX_op_shrs_vec: 1420d0ec9796SRichard Henderson case INDEX_op_sars_vec: 1421d0ec9796SRichard Henderson return have_vec && TCG_TARGET_HAS_shs_vec; 1422d0ec9796SRichard Henderson case INDEX_op_shlv_vec: 1423d0ec9796SRichard Henderson case INDEX_op_shrv_vec: 1424d0ec9796SRichard Henderson case INDEX_op_sarv_vec: 1425d0ec9796SRichard Henderson return have_vec && TCG_TARGET_HAS_shv_vec; 1426b0f7e744SRichard Henderson case INDEX_op_rotli_vec: 1427b0f7e744SRichard Henderson return have_vec && TCG_TARGET_HAS_roti_vec; 142823850a74SRichard Henderson case INDEX_op_rotls_vec: 142923850a74SRichard Henderson return have_vec && TCG_TARGET_HAS_rots_vec; 14305d0ceda9SRichard Henderson case INDEX_op_rotlv_vec: 14315d0ceda9SRichard Henderson case INDEX_op_rotrv_vec: 14325d0ceda9SRichard Henderson return have_vec && TCG_TARGET_HAS_rotv_vec; 14338afaf050SRichard Henderson case INDEX_op_ssadd_vec: 14348afaf050SRichard Henderson case INDEX_op_usadd_vec: 14358afaf050SRichard Henderson case INDEX_op_sssub_vec: 14368afaf050SRichard Henderson case INDEX_op_ussub_vec: 14378afaf050SRichard Henderson return have_vec && TCG_TARGET_HAS_sat_vec; 1438dd0a0fcdSRichard Henderson case INDEX_op_smin_vec: 1439dd0a0fcdSRichard Henderson case INDEX_op_umin_vec: 1440dd0a0fcdSRichard Henderson case INDEX_op_smax_vec: 1441dd0a0fcdSRichard Henderson case INDEX_op_umax_vec: 1442dd0a0fcdSRichard Henderson return have_vec && TCG_TARGET_HAS_minmax_vec; 144338dc1294SRichard Henderson case INDEX_op_bitsel_vec: 144438dc1294SRichard Henderson return have_vec && TCG_TARGET_HAS_bitsel_vec; 1445f75da298SRichard Henderson case INDEX_op_cmpsel_vec: 1446f75da298SRichard Henderson return have_vec && TCG_TARGET_HAS_cmpsel_vec; 1447d2fd745fSRichard Henderson 1448db432672SRichard Henderson default: 1449db432672SRichard Henderson tcg_debug_assert(op > INDEX_op_last_generic && op < NB_OPS); 1450db432672SRichard Henderson return true; 1451be0f34b5SRichard Henderson } 1452be0f34b5SRichard Henderson } 1453be0f34b5SRichard Henderson 145439cf05d3Sbellard /* Note: we convert the 64 bit args to 32 bit and do some alignment 145539cf05d3Sbellard and endian swap. Maybe it would be better to do the alignment 145639cf05d3Sbellard and endian swap in tcg_reg_alloc_call(). */ 1457ae8b75dcSRichard Henderson void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args) 1458c896fe29Sbellard { 145975e8b9b7SRichard Henderson int i, real_args, nb_rets, pi; 14603e92aa34SRichard Henderson unsigned typemask; 14613e92aa34SRichard Henderson const TCGHelperInfo *info; 146275e8b9b7SRichard Henderson TCGOp *op; 1463afb49896SRichard Henderson 1464619205fdSEmilio G. Cota info = g_hash_table_lookup(helper_table, (gpointer)func); 14657319d83aSRichard Henderson typemask = info->typemask; 14662bece2c8SRichard Henderson 146738b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN 146838b47b19SEmilio G. Cota /* detect non-plugin helpers */ 146938b47b19SEmilio G. Cota if (tcg_ctx->plugin_insn && unlikely(strncmp(info->name, "plugin_", 7))) { 147038b47b19SEmilio G. Cota tcg_ctx->plugin_insn->calls_helpers = true; 147138b47b19SEmilio G. Cota } 147238b47b19SEmilio G. Cota #endif 147338b47b19SEmilio G. Cota 147434b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \ 147534b1a49cSRichard Henderson && !defined(CONFIG_TCG_INTERPRETER) 147634b1a49cSRichard Henderson /* We have 64-bit values in one register, but need to pass as two 147734b1a49cSRichard Henderson separate parameters. Split them. */ 14787319d83aSRichard Henderson int orig_typemask = typemask; 147934b1a49cSRichard Henderson int orig_nargs = nargs; 148034b1a49cSRichard Henderson TCGv_i64 retl, reth; 1481ae8b75dcSRichard Henderson TCGTemp *split_args[MAX_OPC_PARAM]; 148234b1a49cSRichard Henderson 1483f764718dSRichard Henderson retl = NULL; 1484f764718dSRichard Henderson reth = NULL; 14857319d83aSRichard Henderson typemask = 0; 148634b1a49cSRichard Henderson for (i = real_args = 0; i < nargs; ++i) { 14877319d83aSRichard Henderson int argtype = extract32(orig_typemask, (i + 1) * 3, 3); 14887319d83aSRichard Henderson bool is_64bit = (argtype & ~1) == dh_typecode_i64; 14897319d83aSRichard Henderson 149034b1a49cSRichard Henderson if (is_64bit) { 1491085272b3SRichard Henderson TCGv_i64 orig = temp_tcgv_i64(args[i]); 149234b1a49cSRichard Henderson TCGv_i32 h = tcg_temp_new_i32(); 149334b1a49cSRichard Henderson TCGv_i32 l = tcg_temp_new_i32(); 149434b1a49cSRichard Henderson tcg_gen_extr_i64_i32(l, h, orig); 1495ae8b75dcSRichard Henderson split_args[real_args++] = tcgv_i32_temp(h); 14967319d83aSRichard Henderson typemask |= dh_typecode_i32 << (real_args * 3); 1497ae8b75dcSRichard Henderson split_args[real_args++] = tcgv_i32_temp(l); 14987319d83aSRichard Henderson typemask |= dh_typecode_i32 << (real_args * 3); 149934b1a49cSRichard Henderson } else { 150034b1a49cSRichard Henderson split_args[real_args++] = args[i]; 15017319d83aSRichard Henderson typemask |= argtype << (real_args * 3); 150234b1a49cSRichard Henderson } 150334b1a49cSRichard Henderson } 150434b1a49cSRichard Henderson nargs = real_args; 150534b1a49cSRichard Henderson args = split_args; 150634b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64 15072bece2c8SRichard Henderson for (i = 0; i < nargs; ++i) { 15087319d83aSRichard Henderson int argtype = extract32(typemask, (i + 1) * 3, 3); 15097319d83aSRichard Henderson bool is_32bit = (argtype & ~1) == dh_typecode_i32; 15107319d83aSRichard Henderson bool is_signed = argtype & 1; 15117319d83aSRichard Henderson 15127319d83aSRichard Henderson if (is_32bit) { 15132bece2c8SRichard Henderson TCGv_i64 temp = tcg_temp_new_i64(); 1514085272b3SRichard Henderson TCGv_i64 orig = temp_tcgv_i64(args[i]); 15152bece2c8SRichard Henderson if (is_signed) { 15162bece2c8SRichard Henderson tcg_gen_ext32s_i64(temp, orig); 15172bece2c8SRichard Henderson } else { 15182bece2c8SRichard Henderson tcg_gen_ext32u_i64(temp, orig); 15192bece2c8SRichard Henderson } 1520ae8b75dcSRichard Henderson args[i] = tcgv_i64_temp(temp); 15212bece2c8SRichard Henderson } 15222bece2c8SRichard Henderson } 15232bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */ 15242bece2c8SRichard Henderson 152515fa08f8SRichard Henderson op = tcg_emit_op(INDEX_op_call); 152675e8b9b7SRichard Henderson 152775e8b9b7SRichard Henderson pi = 0; 1528ae8b75dcSRichard Henderson if (ret != NULL) { 152934b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \ 153034b1a49cSRichard Henderson && !defined(CONFIG_TCG_INTERPRETER) 15317319d83aSRichard Henderson if ((typemask & 6) == dh_typecode_i64) { 153234b1a49cSRichard Henderson /* The 32-bit ABI is going to return the 64-bit value in 153334b1a49cSRichard Henderson the %o0/%o1 register pair. Prepare for this by using 153434b1a49cSRichard Henderson two return temporaries, and reassemble below. */ 153534b1a49cSRichard Henderson retl = tcg_temp_new_i64(); 153634b1a49cSRichard Henderson reth = tcg_temp_new_i64(); 1537ae8b75dcSRichard Henderson op->args[pi++] = tcgv_i64_arg(reth); 1538ae8b75dcSRichard Henderson op->args[pi++] = tcgv_i64_arg(retl); 153934b1a49cSRichard Henderson nb_rets = 2; 154034b1a49cSRichard Henderson } else { 1541ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(ret); 154234b1a49cSRichard Henderson nb_rets = 1; 154334b1a49cSRichard Henderson } 154434b1a49cSRichard Henderson #else 15457319d83aSRichard Henderson if (TCG_TARGET_REG_BITS < 64 && (typemask & 6) == dh_typecode_i64) { 154602eb19d0SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 1547ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(ret + 1); 1548ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(ret); 1549a7812ae4Spbrook #else 1550ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(ret); 1551ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(ret + 1); 1552a7812ae4Spbrook #endif 1553a7812ae4Spbrook nb_rets = 2; 155434b1a49cSRichard Henderson } else { 1555ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(ret); 1556a7812ae4Spbrook nb_rets = 1; 1557a7812ae4Spbrook } 155834b1a49cSRichard Henderson #endif 1559a7812ae4Spbrook } else { 1560a7812ae4Spbrook nb_rets = 0; 1561a7812ae4Spbrook } 1562cd9090aaSRichard Henderson TCGOP_CALLO(op) = nb_rets; 156375e8b9b7SRichard Henderson 1564a7812ae4Spbrook real_args = 0; 1565a7812ae4Spbrook for (i = 0; i < nargs; i++) { 15667319d83aSRichard Henderson int argtype = extract32(typemask, (i + 1) * 3, 3); 15677319d83aSRichard Henderson bool is_64bit = (argtype & ~1) == dh_typecode_i64; 15687b7d8b2dSRichard Henderson bool want_align = false; 15697319d83aSRichard Henderson 15707b7d8b2dSRichard Henderson #if defined(CONFIG_TCG_INTERPRETER) 15717b7d8b2dSRichard Henderson /* 15727b7d8b2dSRichard Henderson * Align all arguments, so that they land in predictable places 15737b7d8b2dSRichard Henderson * for passing off to ffi_call. 15747b7d8b2dSRichard Henderson */ 15757b7d8b2dSRichard Henderson want_align = true; 15767b7d8b2dSRichard Henderson #elif defined(TCG_TARGET_CALL_ALIGN_ARGS) 15777b7d8b2dSRichard Henderson /* Some targets want aligned 64 bit args */ 15787b7d8b2dSRichard Henderson want_align = is_64bit; 15797b7d8b2dSRichard Henderson #endif 15807b7d8b2dSRichard Henderson 15817b7d8b2dSRichard Henderson if (TCG_TARGET_REG_BITS < 64 && want_align && (real_args & 1)) { 158275e8b9b7SRichard Henderson op->args[pi++] = TCG_CALL_DUMMY_ARG; 1583ebd486d5Smalc real_args++; 158439cf05d3Sbellard } 15857b7d8b2dSRichard Henderson 15867b7d8b2dSRichard Henderson if (TCG_TARGET_REG_BITS < 64 && is_64bit) { 15877b7d8b2dSRichard Henderson /* 15887b7d8b2dSRichard Henderson * If stack grows up, then we will be placing successive 15897b7d8b2dSRichard Henderson * arguments at lower addresses, which means we need to 15907b7d8b2dSRichard Henderson * reverse the order compared to how we would normally 15917b7d8b2dSRichard Henderson * treat either big or little-endian. For those arguments 15927b7d8b2dSRichard Henderson * that will wind up in registers, this still works for 15937b7d8b2dSRichard Henderson * HPPA (the only current STACK_GROWSUP target) since the 15947b7d8b2dSRichard Henderson * argument registers are *also* allocated in decreasing 15957b7d8b2dSRichard Henderson * order. If another such target is added, this logic may 15967b7d8b2dSRichard Henderson * have to get more complicated to differentiate between 15977b7d8b2dSRichard Henderson * stack arguments and register arguments. 15987b7d8b2dSRichard Henderson */ 159902eb19d0SRichard Henderson #if defined(HOST_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP) 1600ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(args[i] + 1); 1601ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(args[i]); 1602c896fe29Sbellard #else 1603ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(args[i]); 1604ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(args[i] + 1); 1605c896fe29Sbellard #endif 1606a7812ae4Spbrook real_args += 2; 16072bece2c8SRichard Henderson continue; 16082bece2c8SRichard Henderson } 16092bece2c8SRichard Henderson 1610ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(args[i]); 1611a7812ae4Spbrook real_args++; 1612c896fe29Sbellard } 161375e8b9b7SRichard Henderson op->args[pi++] = (uintptr_t)func; 16143e92aa34SRichard Henderson op->args[pi++] = (uintptr_t)info; 1615cd9090aaSRichard Henderson TCGOP_CALLI(op) = real_args; 1616a7812ae4Spbrook 161775e8b9b7SRichard Henderson /* Make sure the fields didn't overflow. */ 1618cd9090aaSRichard Henderson tcg_debug_assert(TCGOP_CALLI(op) == real_args); 161975e8b9b7SRichard Henderson tcg_debug_assert(pi <= ARRAY_SIZE(op->args)); 16202bece2c8SRichard Henderson 162134b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \ 162234b1a49cSRichard Henderson && !defined(CONFIG_TCG_INTERPRETER) 162334b1a49cSRichard Henderson /* Free all of the parts we allocated above. */ 162434b1a49cSRichard Henderson for (i = real_args = 0; i < orig_nargs; ++i) { 16257319d83aSRichard Henderson int argtype = extract32(orig_typemask, (i + 1) * 3, 3); 16267319d83aSRichard Henderson bool is_64bit = (argtype & ~1) == dh_typecode_i64; 16277319d83aSRichard Henderson 162834b1a49cSRichard Henderson if (is_64bit) { 1629085272b3SRichard Henderson tcg_temp_free_internal(args[real_args++]); 1630085272b3SRichard Henderson tcg_temp_free_internal(args[real_args++]); 163134b1a49cSRichard Henderson } else { 163234b1a49cSRichard Henderson real_args++; 163334b1a49cSRichard Henderson } 163434b1a49cSRichard Henderson } 16357319d83aSRichard Henderson if ((orig_typemask & 6) == dh_typecode_i64) { 163634b1a49cSRichard Henderson /* The 32-bit ABI returned two 32-bit pieces. Re-assemble them. 163734b1a49cSRichard Henderson Note that describing these as TCGv_i64 eliminates an unnecessary 163834b1a49cSRichard Henderson zero-extension that tcg_gen_concat_i32_i64 would create. */ 1639085272b3SRichard Henderson tcg_gen_concat32_i64(temp_tcgv_i64(ret), retl, reth); 164034b1a49cSRichard Henderson tcg_temp_free_i64(retl); 164134b1a49cSRichard Henderson tcg_temp_free_i64(reth); 164234b1a49cSRichard Henderson } 164334b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64 16442bece2c8SRichard Henderson for (i = 0; i < nargs; ++i) { 16457319d83aSRichard Henderson int argtype = extract32(typemask, (i + 1) * 3, 3); 16467319d83aSRichard Henderson bool is_32bit = (argtype & ~1) == dh_typecode_i32; 16477319d83aSRichard Henderson 16487319d83aSRichard Henderson if (is_32bit) { 1649085272b3SRichard Henderson tcg_temp_free_internal(args[i]); 16502bece2c8SRichard Henderson } 16512bece2c8SRichard Henderson } 16522bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */ 1653a7812ae4Spbrook } 1654c896fe29Sbellard 16558fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s) 1656c896fe29Sbellard { 1657ac3b8891SRichard Henderson int i, n; 1658ac3b8891SRichard Henderson 1659ee17db83SRichard Henderson for (i = 0, n = s->nb_temps; i < n; i++) { 1660ee17db83SRichard Henderson TCGTemp *ts = &s->temps[i]; 1661ee17db83SRichard Henderson TCGTempVal val = TEMP_VAL_MEM; 1662ee17db83SRichard Henderson 1663ee17db83SRichard Henderson switch (ts->kind) { 1664c0522136SRichard Henderson case TEMP_CONST: 1665c0522136SRichard Henderson val = TEMP_VAL_CONST; 1666c0522136SRichard Henderson break; 1667ee17db83SRichard Henderson case TEMP_FIXED: 1668ee17db83SRichard Henderson val = TEMP_VAL_REG; 1669ee17db83SRichard Henderson break; 1670ee17db83SRichard Henderson case TEMP_GLOBAL: 1671ee17db83SRichard Henderson break; 1672ee17db83SRichard Henderson case TEMP_NORMAL: 1673ee17db83SRichard Henderson val = TEMP_VAL_DEAD; 1674ee17db83SRichard Henderson /* fall through */ 1675ee17db83SRichard Henderson case TEMP_LOCAL: 1676e8996ee0Sbellard ts->mem_allocated = 0; 1677ee17db83SRichard Henderson break; 1678ee17db83SRichard Henderson default: 1679ee17db83SRichard Henderson g_assert_not_reached(); 1680ee17db83SRichard Henderson } 1681ee17db83SRichard Henderson ts->val_type = val; 1682e8996ee0Sbellard } 1683f8b2f202SRichard Henderson 1684f8b2f202SRichard Henderson memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp)); 1685c896fe29Sbellard } 1686c896fe29Sbellard 1687f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size, 1688f8b2f202SRichard Henderson TCGTemp *ts) 1689c896fe29Sbellard { 16901807f4c4SRichard Henderson int idx = temp_idx(ts); 1691ac56dd48Spbrook 1692ee17db83SRichard Henderson switch (ts->kind) { 1693ee17db83SRichard Henderson case TEMP_FIXED: 1694ee17db83SRichard Henderson case TEMP_GLOBAL: 1695ac56dd48Spbrook pstrcpy(buf, buf_size, ts->name); 1696ee17db83SRichard Henderson break; 1697ee17db83SRichard Henderson case TEMP_LOCAL: 1698641d5fbeSbellard snprintf(buf, buf_size, "loc%d", idx - s->nb_globals); 1699ee17db83SRichard Henderson break; 1700ee17db83SRichard Henderson case TEMP_NORMAL: 1701ac56dd48Spbrook snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals); 1702ee17db83SRichard Henderson break; 1703c0522136SRichard Henderson case TEMP_CONST: 1704c0522136SRichard Henderson switch (ts->type) { 1705c0522136SRichard Henderson case TCG_TYPE_I32: 1706c0522136SRichard Henderson snprintf(buf, buf_size, "$0x%x", (int32_t)ts->val); 1707c0522136SRichard Henderson break; 1708c0522136SRichard Henderson #if TCG_TARGET_REG_BITS > 32 1709c0522136SRichard Henderson case TCG_TYPE_I64: 1710c0522136SRichard Henderson snprintf(buf, buf_size, "$0x%" PRIx64, ts->val); 1711c0522136SRichard Henderson break; 1712c0522136SRichard Henderson #endif 1713c0522136SRichard Henderson case TCG_TYPE_V64: 1714c0522136SRichard Henderson case TCG_TYPE_V128: 1715c0522136SRichard Henderson case TCG_TYPE_V256: 1716c0522136SRichard Henderson snprintf(buf, buf_size, "v%d$0x%" PRIx64, 1717c0522136SRichard Henderson 64 << (ts->type - TCG_TYPE_V64), ts->val); 1718c0522136SRichard Henderson break; 1719c0522136SRichard Henderson default: 1720c0522136SRichard Henderson g_assert_not_reached(); 1721c0522136SRichard Henderson } 1722c0522136SRichard Henderson break; 1723c896fe29Sbellard } 1724c896fe29Sbellard return buf; 1725c896fe29Sbellard } 1726c896fe29Sbellard 172743439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf, 172843439139SRichard Henderson int buf_size, TCGArg arg) 1729f8b2f202SRichard Henderson { 173043439139SRichard Henderson return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg)); 1731f8b2f202SRichard Henderson } 1732f8b2f202SRichard Henderson 1733f48f3edeSblueswir1 static const char * const cond_name[] = 1734f48f3edeSblueswir1 { 17350aed257fSRichard Henderson [TCG_COND_NEVER] = "never", 17360aed257fSRichard Henderson [TCG_COND_ALWAYS] = "always", 1737f48f3edeSblueswir1 [TCG_COND_EQ] = "eq", 1738f48f3edeSblueswir1 [TCG_COND_NE] = "ne", 1739f48f3edeSblueswir1 [TCG_COND_LT] = "lt", 1740f48f3edeSblueswir1 [TCG_COND_GE] = "ge", 1741f48f3edeSblueswir1 [TCG_COND_LE] = "le", 1742f48f3edeSblueswir1 [TCG_COND_GT] = "gt", 1743f48f3edeSblueswir1 [TCG_COND_LTU] = "ltu", 1744f48f3edeSblueswir1 [TCG_COND_GEU] = "geu", 1745f48f3edeSblueswir1 [TCG_COND_LEU] = "leu", 1746f48f3edeSblueswir1 [TCG_COND_GTU] = "gtu" 1747f48f3edeSblueswir1 }; 1748f48f3edeSblueswir1 1749f713d6adSRichard Henderson static const char * const ldst_name[] = 1750f713d6adSRichard Henderson { 1751f713d6adSRichard Henderson [MO_UB] = "ub", 1752f713d6adSRichard Henderson [MO_SB] = "sb", 1753f713d6adSRichard Henderson [MO_LEUW] = "leuw", 1754f713d6adSRichard Henderson [MO_LESW] = "lesw", 1755f713d6adSRichard Henderson [MO_LEUL] = "leul", 1756f713d6adSRichard Henderson [MO_LESL] = "lesl", 1757f713d6adSRichard Henderson [MO_LEQ] = "leq", 1758f713d6adSRichard Henderson [MO_BEUW] = "beuw", 1759f713d6adSRichard Henderson [MO_BESW] = "besw", 1760f713d6adSRichard Henderson [MO_BEUL] = "beul", 1761f713d6adSRichard Henderson [MO_BESL] = "besl", 1762f713d6adSRichard Henderson [MO_BEQ] = "beq", 1763f713d6adSRichard Henderson }; 1764f713d6adSRichard Henderson 17651f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = { 176652bf9771Stony.nguyen@bt.com #ifdef TARGET_ALIGNED_ONLY 17671f00b27fSSergey Sorokin [MO_UNALN >> MO_ASHIFT] = "un+", 17681f00b27fSSergey Sorokin [MO_ALIGN >> MO_ASHIFT] = "", 17691f00b27fSSergey Sorokin #else 17701f00b27fSSergey Sorokin [MO_UNALN >> MO_ASHIFT] = "", 17711f00b27fSSergey Sorokin [MO_ALIGN >> MO_ASHIFT] = "al+", 17721f00b27fSSergey Sorokin #endif 17731f00b27fSSergey Sorokin [MO_ALIGN_2 >> MO_ASHIFT] = "al2+", 17741f00b27fSSergey Sorokin [MO_ALIGN_4 >> MO_ASHIFT] = "al4+", 17751f00b27fSSergey Sorokin [MO_ALIGN_8 >> MO_ASHIFT] = "al8+", 17761f00b27fSSergey Sorokin [MO_ALIGN_16 >> MO_ASHIFT] = "al16+", 17771f00b27fSSergey Sorokin [MO_ALIGN_32 >> MO_ASHIFT] = "al32+", 17781f00b27fSSergey Sorokin [MO_ALIGN_64 >> MO_ASHIFT] = "al64+", 17791f00b27fSSergey Sorokin }; 17801f00b27fSSergey Sorokin 1781b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d) 1782b016486eSRichard Henderson { 1783b016486eSRichard Henderson return (d & (d - 1)) == 0; 1784b016486eSRichard Henderson } 1785b016486eSRichard Henderson 1786b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d) 1787b016486eSRichard Henderson { 1788b016486eSRichard Henderson if (TCG_TARGET_NB_REGS <= 32) { 1789b016486eSRichard Henderson return ctz32(d); 1790b016486eSRichard Henderson } else { 1791b016486eSRichard Henderson return ctz64(d); 1792b016486eSRichard Henderson } 1793b016486eSRichard Henderson } 1794b016486eSRichard Henderson 17951894f69aSRichard Henderson static void tcg_dump_ops(TCGContext *s, bool have_prefs) 1796c896fe29Sbellard { 1797c896fe29Sbellard char buf[128]; 1798c45cb8bbSRichard Henderson TCGOp *op; 1799c896fe29Sbellard 180015fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 1801c45cb8bbSRichard Henderson int i, k, nb_oargs, nb_iargs, nb_cargs; 1802c45cb8bbSRichard Henderson const TCGOpDef *def; 1803c45cb8bbSRichard Henderson TCGOpcode c; 1804bdfb460eSRichard Henderson int col = 0; 1805c45cb8bbSRichard Henderson 1806c45cb8bbSRichard Henderson c = op->opc; 1807c896fe29Sbellard def = &tcg_op_defs[c]; 1808c45cb8bbSRichard Henderson 1809765b842aSRichard Henderson if (c == INDEX_op_insn_start) { 1810b016486eSRichard Henderson nb_oargs = 0; 181115fa08f8SRichard Henderson col += qemu_log("\n ----"); 18129aef40edSRichard Henderson 18139aef40edSRichard Henderson for (i = 0; i < TARGET_INSN_START_WORDS; ++i) { 18149aef40edSRichard Henderson target_ulong a; 18157e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS 1816efee3746SRichard Henderson a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]); 18177e4597d7Sbellard #else 1818efee3746SRichard Henderson a = op->args[i]; 18197e4597d7Sbellard #endif 1820bdfb460eSRichard Henderson col += qemu_log(" " TARGET_FMT_lx, a); 1821eeacee4dSBlue Swirl } 18227e4597d7Sbellard } else if (c == INDEX_op_call) { 18233e92aa34SRichard Henderson const TCGHelperInfo *info = tcg_call_info(op); 1824fa52e660SRichard Henderson void *func = tcg_call_func(op); 18253e92aa34SRichard Henderson 1826c896fe29Sbellard /* variable number of arguments */ 1827cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 1828cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 1829c896fe29Sbellard nb_cargs = def->nb_cargs; 1830b03cce8eSbellard 18313e92aa34SRichard Henderson col += qemu_log(" %s ", def->name); 18323e92aa34SRichard Henderson 18333e92aa34SRichard Henderson /* 18343e92aa34SRichard Henderson * Print the function name from TCGHelperInfo, if available. 18353e92aa34SRichard Henderson * Note that plugins have a template function for the info, 18363e92aa34SRichard Henderson * but the actual function pointer comes from the plugin. 18373e92aa34SRichard Henderson */ 18383e92aa34SRichard Henderson if (func == info->func) { 18393e92aa34SRichard Henderson col += qemu_log("%s", info->name); 18403e92aa34SRichard Henderson } else { 18413e92aa34SRichard Henderson col += qemu_log("plugin(%p)", func); 18423e92aa34SRichard Henderson } 18433e92aa34SRichard Henderson 18443e92aa34SRichard Henderson col += qemu_log("$0x%x,$%d", info->flags, nb_oargs); 1845b03cce8eSbellard for (i = 0; i < nb_oargs; i++) { 184643439139SRichard Henderson col += qemu_log(",%s", tcg_get_arg_str(s, buf, sizeof(buf), 1847efee3746SRichard Henderson op->args[i])); 1848b03cce8eSbellard } 1849cf066674SRichard Henderson for (i = 0; i < nb_iargs; i++) { 1850efee3746SRichard Henderson TCGArg arg = op->args[nb_oargs + i]; 1851cf066674SRichard Henderson const char *t = "<dummy>"; 1852cf066674SRichard Henderson if (arg != TCG_CALL_DUMMY_ARG) { 185343439139SRichard Henderson t = tcg_get_arg_str(s, buf, sizeof(buf), arg); 1854b03cce8eSbellard } 1855bdfb460eSRichard Henderson col += qemu_log(",%s", t); 1856e8996ee0Sbellard } 1857b03cce8eSbellard } else { 1858bdfb460eSRichard Henderson col += qemu_log(" %s ", def->name); 1859c45cb8bbSRichard Henderson 1860c896fe29Sbellard nb_oargs = def->nb_oargs; 1861c896fe29Sbellard nb_iargs = def->nb_iargs; 1862c896fe29Sbellard nb_cargs = def->nb_cargs; 1863c896fe29Sbellard 1864d2fd745fSRichard Henderson if (def->flags & TCG_OPF_VECTOR) { 1865d2fd745fSRichard Henderson col += qemu_log("v%d,e%d,", 64 << TCGOP_VECL(op), 1866d2fd745fSRichard Henderson 8 << TCGOP_VECE(op)); 1867d2fd745fSRichard Henderson } 1868d2fd745fSRichard Henderson 1869c896fe29Sbellard k = 0; 1870c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 1871eeacee4dSBlue Swirl if (k != 0) { 1872bdfb460eSRichard Henderson col += qemu_log(","); 1873eeacee4dSBlue Swirl } 187443439139SRichard Henderson col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf), 1875efee3746SRichard Henderson op->args[k++])); 1876c896fe29Sbellard } 1877c896fe29Sbellard for (i = 0; i < nb_iargs; i++) { 1878eeacee4dSBlue Swirl if (k != 0) { 1879bdfb460eSRichard Henderson col += qemu_log(","); 1880eeacee4dSBlue Swirl } 188143439139SRichard Henderson col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf), 1882efee3746SRichard Henderson op->args[k++])); 1883c896fe29Sbellard } 1884be210acbSRichard Henderson switch (c) { 1885be210acbSRichard Henderson case INDEX_op_brcond_i32: 1886ffc5ea09SRichard Henderson case INDEX_op_setcond_i32: 1887ffc5ea09SRichard Henderson case INDEX_op_movcond_i32: 1888be210acbSRichard Henderson case INDEX_op_brcond2_i32: 1889be210acbSRichard Henderson case INDEX_op_setcond2_i32: 1890ffc5ea09SRichard Henderson case INDEX_op_brcond_i64: 1891be210acbSRichard Henderson case INDEX_op_setcond_i64: 1892ffc5ea09SRichard Henderson case INDEX_op_movcond_i64: 1893212be173SRichard Henderson case INDEX_op_cmp_vec: 1894f75da298SRichard Henderson case INDEX_op_cmpsel_vec: 1895efee3746SRichard Henderson if (op->args[k] < ARRAY_SIZE(cond_name) 1896efee3746SRichard Henderson && cond_name[op->args[k]]) { 1897efee3746SRichard Henderson col += qemu_log(",%s", cond_name[op->args[k++]]); 1898eeacee4dSBlue Swirl } else { 1899efee3746SRichard Henderson col += qemu_log(",$0x%" TCG_PRIlx, op->args[k++]); 1900eeacee4dSBlue Swirl } 1901f48f3edeSblueswir1 i = 1; 1902be210acbSRichard Henderson break; 1903f713d6adSRichard Henderson case INDEX_op_qemu_ld_i32: 1904f713d6adSRichard Henderson case INDEX_op_qemu_st_i32: 190507ce0b05SRichard Henderson case INDEX_op_qemu_st8_i32: 1906f713d6adSRichard Henderson case INDEX_op_qemu_ld_i64: 1907f713d6adSRichard Henderson case INDEX_op_qemu_st_i64: 190859227d5dSRichard Henderson { 1909efee3746SRichard Henderson TCGMemOpIdx oi = op->args[k++]; 191014776ab5STony Nguyen MemOp op = get_memop(oi); 191159227d5dSRichard Henderson unsigned ix = get_mmuidx(oi); 191259227d5dSRichard Henderson 191359c4b7e8SRichard Henderson if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) { 1914bdfb460eSRichard Henderson col += qemu_log(",$0x%x,%u", op, ix); 191559c4b7e8SRichard Henderson } else { 19161f00b27fSSergey Sorokin const char *s_al, *s_op; 19171f00b27fSSergey Sorokin s_al = alignment_name[(op & MO_AMASK) >> MO_ASHIFT]; 191859c4b7e8SRichard Henderson s_op = ldst_name[op & (MO_BSWAP | MO_SSIZE)]; 1919bdfb460eSRichard Henderson col += qemu_log(",%s%s,%u", s_al, s_op, ix); 1920f713d6adSRichard Henderson } 1921f713d6adSRichard Henderson i = 1; 192259227d5dSRichard Henderson } 1923f713d6adSRichard Henderson break; 1924be210acbSRichard Henderson default: 1925f48f3edeSblueswir1 i = 0; 1926be210acbSRichard Henderson break; 1927be210acbSRichard Henderson } 192851e3972cSRichard Henderson switch (c) { 192951e3972cSRichard Henderson case INDEX_op_set_label: 193051e3972cSRichard Henderson case INDEX_op_br: 193151e3972cSRichard Henderson case INDEX_op_brcond_i32: 193251e3972cSRichard Henderson case INDEX_op_brcond_i64: 193351e3972cSRichard Henderson case INDEX_op_brcond2_i32: 1934efee3746SRichard Henderson col += qemu_log("%s$L%d", k ? "," : "", 1935efee3746SRichard Henderson arg_label(op->args[k])->id); 193651e3972cSRichard Henderson i++, k++; 193751e3972cSRichard Henderson break; 193851e3972cSRichard Henderson default: 193951e3972cSRichard Henderson break; 1940eeacee4dSBlue Swirl } 194151e3972cSRichard Henderson for (; i < nb_cargs; i++, k++) { 1942efee3746SRichard Henderson col += qemu_log("%s$0x%" TCG_PRIlx, k ? "," : "", op->args[k]); 1943bdfb460eSRichard Henderson } 1944bdfb460eSRichard Henderson } 1945bdfb460eSRichard Henderson 19461894f69aSRichard Henderson if (have_prefs || op->life) { 19477606488cSRobert Foley 19487606488cSRobert Foley QemuLogFile *logfile; 19497606488cSRobert Foley 19507606488cSRobert Foley rcu_read_lock(); 1951d73415a3SStefan Hajnoczi logfile = qatomic_rcu_read(&qemu_logfile); 19527606488cSRobert Foley if (logfile) { 19531894f69aSRichard Henderson for (; col < 40; ++col) { 19547606488cSRobert Foley putc(' ', logfile->fd); 1955bdfb460eSRichard Henderson } 19561894f69aSRichard Henderson } 19577606488cSRobert Foley rcu_read_unlock(); 19587606488cSRobert Foley } 19591894f69aSRichard Henderson 19601894f69aSRichard Henderson if (op->life) { 19611894f69aSRichard Henderson unsigned life = op->life; 1962bdfb460eSRichard Henderson 1963bdfb460eSRichard Henderson if (life & (SYNC_ARG * 3)) { 1964bdfb460eSRichard Henderson qemu_log(" sync:"); 1965bdfb460eSRichard Henderson for (i = 0; i < 2; ++i) { 1966bdfb460eSRichard Henderson if (life & (SYNC_ARG << i)) { 1967bdfb460eSRichard Henderson qemu_log(" %d", i); 1968bdfb460eSRichard Henderson } 1969bdfb460eSRichard Henderson } 1970bdfb460eSRichard Henderson } 1971bdfb460eSRichard Henderson life /= DEAD_ARG; 1972bdfb460eSRichard Henderson if (life) { 1973bdfb460eSRichard Henderson qemu_log(" dead:"); 1974bdfb460eSRichard Henderson for (i = 0; life; ++i, life >>= 1) { 1975bdfb460eSRichard Henderson if (life & 1) { 1976bdfb460eSRichard Henderson qemu_log(" %d", i); 1977bdfb460eSRichard Henderson } 1978bdfb460eSRichard Henderson } 1979c896fe29Sbellard } 1980b03cce8eSbellard } 19811894f69aSRichard Henderson 19821894f69aSRichard Henderson if (have_prefs) { 19831894f69aSRichard Henderson for (i = 0; i < nb_oargs; ++i) { 19841894f69aSRichard Henderson TCGRegSet set = op->output_pref[i]; 19851894f69aSRichard Henderson 19861894f69aSRichard Henderson if (i == 0) { 19871894f69aSRichard Henderson qemu_log(" pref="); 19881894f69aSRichard Henderson } else { 19891894f69aSRichard Henderson qemu_log(","); 19901894f69aSRichard Henderson } 19911894f69aSRichard Henderson if (set == 0) { 19921894f69aSRichard Henderson qemu_log("none"); 19931894f69aSRichard Henderson } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) { 19941894f69aSRichard Henderson qemu_log("all"); 19951894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG 19961894f69aSRichard Henderson } else if (tcg_regset_single(set)) { 19971894f69aSRichard Henderson TCGReg reg = tcg_regset_first(set); 19981894f69aSRichard Henderson qemu_log("%s", tcg_target_reg_names[reg]); 19991894f69aSRichard Henderson #endif 20001894f69aSRichard Henderson } else if (TCG_TARGET_NB_REGS <= 32) { 20011894f69aSRichard Henderson qemu_log("%#x", (uint32_t)set); 20021894f69aSRichard Henderson } else { 20031894f69aSRichard Henderson qemu_log("%#" PRIx64, (uint64_t)set); 20041894f69aSRichard Henderson } 20051894f69aSRichard Henderson } 20061894f69aSRichard Henderson } 20071894f69aSRichard Henderson 2008eeacee4dSBlue Swirl qemu_log("\n"); 2009c896fe29Sbellard } 2010c896fe29Sbellard } 2011c896fe29Sbellard 2012c896fe29Sbellard /* we give more priority to constraints with less registers */ 2013c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k) 2014c896fe29Sbellard { 201574a11790SRichard Henderson const TCGArgConstraint *arg_ct = &def->args_ct[k]; 201674a11790SRichard Henderson int n; 2017c896fe29Sbellard 2018bc2b17e6SRichard Henderson if (arg_ct->oalias) { 2019c896fe29Sbellard /* an alias is equivalent to a single register */ 2020c896fe29Sbellard n = 1; 2021c896fe29Sbellard } else { 202274a11790SRichard Henderson n = ctpop64(arg_ct->regs); 2023c896fe29Sbellard } 2024c896fe29Sbellard return TCG_TARGET_NB_REGS - n + 1; 2025c896fe29Sbellard } 2026c896fe29Sbellard 2027c896fe29Sbellard /* sort from highest priority to lowest */ 2028c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n) 2029c896fe29Sbellard { 203066792f90SRichard Henderson int i, j; 203166792f90SRichard Henderson TCGArgConstraint *a = def->args_ct; 2032c896fe29Sbellard 203366792f90SRichard Henderson for (i = 0; i < n; i++) { 203466792f90SRichard Henderson a[start + i].sort_index = start + i; 203566792f90SRichard Henderson } 203666792f90SRichard Henderson if (n <= 1) { 2037c896fe29Sbellard return; 203866792f90SRichard Henderson } 2039c896fe29Sbellard for (i = 0; i < n - 1; i++) { 2040c896fe29Sbellard for (j = i + 1; j < n; j++) { 204166792f90SRichard Henderson int p1 = get_constraint_priority(def, a[start + i].sort_index); 204266792f90SRichard Henderson int p2 = get_constraint_priority(def, a[start + j].sort_index); 2043c896fe29Sbellard if (p1 < p2) { 204466792f90SRichard Henderson int tmp = a[start + i].sort_index; 204566792f90SRichard Henderson a[start + i].sort_index = a[start + j].sort_index; 204666792f90SRichard Henderson a[start + j].sort_index = tmp; 2047c896fe29Sbellard } 2048c896fe29Sbellard } 2049c896fe29Sbellard } 2050c896fe29Sbellard } 2051c896fe29Sbellard 2052f69d277eSRichard Henderson static void process_op_defs(TCGContext *s) 2053c896fe29Sbellard { 2054a9751609SRichard Henderson TCGOpcode op; 2055c896fe29Sbellard 2056f69d277eSRichard Henderson for (op = 0; op < NB_OPS; op++) { 2057f69d277eSRichard Henderson TCGOpDef *def = &tcg_op_defs[op]; 2058f69d277eSRichard Henderson const TCGTargetOpDef *tdefs; 2059069ea736SRichard Henderson int i, nb_args; 2060f69d277eSRichard Henderson 2061f69d277eSRichard Henderson if (def->flags & TCG_OPF_NOT_PRESENT) { 2062f69d277eSRichard Henderson continue; 2063f69d277eSRichard Henderson } 2064f69d277eSRichard Henderson 2065c896fe29Sbellard nb_args = def->nb_iargs + def->nb_oargs; 2066f69d277eSRichard Henderson if (nb_args == 0) { 2067f69d277eSRichard Henderson continue; 2068f69d277eSRichard Henderson } 2069f69d277eSRichard Henderson 20704c22e840SRichard Henderson /* 20714c22e840SRichard Henderson * Macro magic should make it impossible, but double-check that 20724c22e840SRichard Henderson * the array index is in range. Since the signness of an enum 20734c22e840SRichard Henderson * is implementation defined, force the result to unsigned. 20744c22e840SRichard Henderson */ 20754c22e840SRichard Henderson unsigned con_set = tcg_target_op_def(op); 20764c22e840SRichard Henderson tcg_debug_assert(con_set < ARRAY_SIZE(constraint_sets)); 20774c22e840SRichard Henderson tdefs = &constraint_sets[con_set]; 2078f69d277eSRichard Henderson 2079c896fe29Sbellard for (i = 0; i < nb_args; i++) { 2080f69d277eSRichard Henderson const char *ct_str = tdefs->args_ct_str[i]; 2081f69d277eSRichard Henderson /* Incomplete TCGTargetOpDef entry. */ 2082eabb7b91SAurelien Jarno tcg_debug_assert(ct_str != NULL); 2083f69d277eSRichard Henderson 208417280ff4SRichard Henderson while (*ct_str != '\0') { 208517280ff4SRichard Henderson switch(*ct_str) { 208617280ff4SRichard Henderson case '0' ... '9': 208717280ff4SRichard Henderson { 208817280ff4SRichard Henderson int oarg = *ct_str - '0'; 208917280ff4SRichard Henderson tcg_debug_assert(ct_str == tdefs->args_ct_str[i]); 2090eabb7b91SAurelien Jarno tcg_debug_assert(oarg < def->nb_oargs); 209174a11790SRichard Henderson tcg_debug_assert(def->args_ct[oarg].regs != 0); 2092c896fe29Sbellard def->args_ct[i] = def->args_ct[oarg]; 2093bc2b17e6SRichard Henderson /* The output sets oalias. */ 2094bc2b17e6SRichard Henderson def->args_ct[oarg].oalias = true; 20955ff9d6a4Sbellard def->args_ct[oarg].alias_index = i; 2096bc2b17e6SRichard Henderson /* The input sets ialias. */ 2097bc2b17e6SRichard Henderson def->args_ct[i].ialias = true; 20985ff9d6a4Sbellard def->args_ct[i].alias_index = oarg; 209917280ff4SRichard Henderson } 210017280ff4SRichard Henderson ct_str++; 2101c896fe29Sbellard break; 210282790a87SRichard Henderson case '&': 2103bc2b17e6SRichard Henderson def->args_ct[i].newreg = true; 210482790a87SRichard Henderson ct_str++; 210582790a87SRichard Henderson break; 2106c896fe29Sbellard case 'i': 2107c896fe29Sbellard def->args_ct[i].ct |= TCG_CT_CONST; 2108c896fe29Sbellard ct_str++; 2109c896fe29Sbellard break; 2110358b4923SRichard Henderson 2111358b4923SRichard Henderson /* Include all of the target-specific constraints. */ 2112358b4923SRichard Henderson 2113358b4923SRichard Henderson #undef CONST 2114358b4923SRichard Henderson #define CONST(CASE, MASK) \ 2115358b4923SRichard Henderson case CASE: def->args_ct[i].ct |= MASK; ct_str++; break; 2116358b4923SRichard Henderson #define REGS(CASE, MASK) \ 2117358b4923SRichard Henderson case CASE: def->args_ct[i].regs |= MASK; ct_str++; break; 2118358b4923SRichard Henderson 2119358b4923SRichard Henderson #include "tcg-target-con-str.h" 2120358b4923SRichard Henderson 2121358b4923SRichard Henderson #undef REGS 2122358b4923SRichard Henderson #undef CONST 2123c896fe29Sbellard default: 2124358b4923SRichard Henderson /* Typo in TCGTargetOpDef constraint. */ 2125358b4923SRichard Henderson g_assert_not_reached(); 2126358b4923SRichard Henderson } 2127c896fe29Sbellard } 2128c896fe29Sbellard } 2129c896fe29Sbellard 2130c68aaa18SStefan Weil /* TCGTargetOpDef entry with too much information? */ 2131eabb7b91SAurelien Jarno tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL); 2132c68aaa18SStefan Weil 2133c896fe29Sbellard /* sort the constraints (XXX: this is just an heuristic) */ 2134c896fe29Sbellard sort_constraints(def, 0, def->nb_oargs); 2135c896fe29Sbellard sort_constraints(def, def->nb_oargs, def->nb_iargs); 2136c896fe29Sbellard } 2137c896fe29Sbellard } 2138c896fe29Sbellard 21390c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op) 21400c627cdcSRichard Henderson { 2141d88a117eSRichard Henderson TCGLabel *label; 2142d88a117eSRichard Henderson 2143d88a117eSRichard Henderson switch (op->opc) { 2144d88a117eSRichard Henderson case INDEX_op_br: 2145d88a117eSRichard Henderson label = arg_label(op->args[0]); 2146d88a117eSRichard Henderson label->refs--; 2147d88a117eSRichard Henderson break; 2148d88a117eSRichard Henderson case INDEX_op_brcond_i32: 2149d88a117eSRichard Henderson case INDEX_op_brcond_i64: 2150d88a117eSRichard Henderson label = arg_label(op->args[3]); 2151d88a117eSRichard Henderson label->refs--; 2152d88a117eSRichard Henderson break; 2153d88a117eSRichard Henderson case INDEX_op_brcond2_i32: 2154d88a117eSRichard Henderson label = arg_label(op->args[5]); 2155d88a117eSRichard Henderson label->refs--; 2156d88a117eSRichard Henderson break; 2157d88a117eSRichard Henderson default: 2158d88a117eSRichard Henderson break; 2159d88a117eSRichard Henderson } 2160d88a117eSRichard Henderson 216115fa08f8SRichard Henderson QTAILQ_REMOVE(&s->ops, op, link); 216215fa08f8SRichard Henderson QTAILQ_INSERT_TAIL(&s->free_ops, op, link); 2163abebf925SRichard Henderson s->nb_ops--; 21640c627cdcSRichard Henderson 21650c627cdcSRichard Henderson #ifdef CONFIG_PROFILER 2166d73415a3SStefan Hajnoczi qatomic_set(&s->prof.del_op_count, s->prof.del_op_count + 1); 21670c627cdcSRichard Henderson #endif 21680c627cdcSRichard Henderson } 21690c627cdcSRichard Henderson 2170a80cdd31SRichard Henderson void tcg_remove_ops_after(TCGOp *op) 2171a80cdd31SRichard Henderson { 2172a80cdd31SRichard Henderson TCGContext *s = tcg_ctx; 2173a80cdd31SRichard Henderson 2174a80cdd31SRichard Henderson while (true) { 2175a80cdd31SRichard Henderson TCGOp *last = tcg_last_op(); 2176a80cdd31SRichard Henderson if (last == op) { 2177a80cdd31SRichard Henderson return; 2178a80cdd31SRichard Henderson } 2179a80cdd31SRichard Henderson tcg_op_remove(s, last); 2180a80cdd31SRichard Henderson } 2181a80cdd31SRichard Henderson } 2182a80cdd31SRichard Henderson 218315fa08f8SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc) 218415fa08f8SRichard Henderson { 218515fa08f8SRichard Henderson TCGContext *s = tcg_ctx; 218615fa08f8SRichard Henderson TCGOp *op; 218715fa08f8SRichard Henderson 218815fa08f8SRichard Henderson if (likely(QTAILQ_EMPTY(&s->free_ops))) { 218915fa08f8SRichard Henderson op = tcg_malloc(sizeof(TCGOp)); 219015fa08f8SRichard Henderson } else { 219115fa08f8SRichard Henderson op = QTAILQ_FIRST(&s->free_ops); 219215fa08f8SRichard Henderson QTAILQ_REMOVE(&s->free_ops, op, link); 219315fa08f8SRichard Henderson } 219415fa08f8SRichard Henderson memset(op, 0, offsetof(TCGOp, link)); 219515fa08f8SRichard Henderson op->opc = opc; 2196abebf925SRichard Henderson s->nb_ops++; 219715fa08f8SRichard Henderson 219815fa08f8SRichard Henderson return op; 219915fa08f8SRichard Henderson } 220015fa08f8SRichard Henderson 220115fa08f8SRichard Henderson TCGOp *tcg_emit_op(TCGOpcode opc) 220215fa08f8SRichard Henderson { 220315fa08f8SRichard Henderson TCGOp *op = tcg_op_alloc(opc); 220415fa08f8SRichard Henderson QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link); 220515fa08f8SRichard Henderson return op; 220615fa08f8SRichard Henderson } 220715fa08f8SRichard Henderson 2208ac1043f6SEmilio G. Cota TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op, TCGOpcode opc) 22095a18407fSRichard Henderson { 221015fa08f8SRichard Henderson TCGOp *new_op = tcg_op_alloc(opc); 221115fa08f8SRichard Henderson QTAILQ_INSERT_BEFORE(old_op, new_op, link); 22125a18407fSRichard Henderson return new_op; 22135a18407fSRichard Henderson } 22145a18407fSRichard Henderson 2215ac1043f6SEmilio G. Cota TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, TCGOpcode opc) 22165a18407fSRichard Henderson { 221715fa08f8SRichard Henderson TCGOp *new_op = tcg_op_alloc(opc); 221815fa08f8SRichard Henderson QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link); 22195a18407fSRichard Henderson return new_op; 22205a18407fSRichard Henderson } 22215a18407fSRichard Henderson 2222b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code. */ 2223b4fc67c7SRichard Henderson static void reachable_code_pass(TCGContext *s) 2224b4fc67c7SRichard Henderson { 2225b4fc67c7SRichard Henderson TCGOp *op, *op_next; 2226b4fc67c7SRichard Henderson bool dead = false; 2227b4fc67c7SRichard Henderson 2228b4fc67c7SRichard Henderson QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) { 2229b4fc67c7SRichard Henderson bool remove = dead; 2230b4fc67c7SRichard Henderson TCGLabel *label; 2231b4fc67c7SRichard Henderson 2232b4fc67c7SRichard Henderson switch (op->opc) { 2233b4fc67c7SRichard Henderson case INDEX_op_set_label: 2234b4fc67c7SRichard Henderson label = arg_label(op->args[0]); 2235b4fc67c7SRichard Henderson if (label->refs == 0) { 2236b4fc67c7SRichard Henderson /* 2237b4fc67c7SRichard Henderson * While there is an occasional backward branch, virtually 2238b4fc67c7SRichard Henderson * all branches generated by the translators are forward. 2239b4fc67c7SRichard Henderson * Which means that generally we will have already removed 2240b4fc67c7SRichard Henderson * all references to the label that will be, and there is 2241b4fc67c7SRichard Henderson * little to be gained by iterating. 2242b4fc67c7SRichard Henderson */ 2243b4fc67c7SRichard Henderson remove = true; 2244b4fc67c7SRichard Henderson } else { 2245b4fc67c7SRichard Henderson /* Once we see a label, insns become live again. */ 2246b4fc67c7SRichard Henderson dead = false; 2247b4fc67c7SRichard Henderson remove = false; 2248b4fc67c7SRichard Henderson 2249b4fc67c7SRichard Henderson /* 2250b4fc67c7SRichard Henderson * Optimization can fold conditional branches to unconditional. 2251b4fc67c7SRichard Henderson * If we find a label with one reference which is preceded by 2252b4fc67c7SRichard Henderson * an unconditional branch to it, remove both. This needed to 2253b4fc67c7SRichard Henderson * wait until the dead code in between them was removed. 2254b4fc67c7SRichard Henderson */ 2255b4fc67c7SRichard Henderson if (label->refs == 1) { 2256eae3eb3eSPaolo Bonzini TCGOp *op_prev = QTAILQ_PREV(op, link); 2257b4fc67c7SRichard Henderson if (op_prev->opc == INDEX_op_br && 2258b4fc67c7SRichard Henderson label == arg_label(op_prev->args[0])) { 2259b4fc67c7SRichard Henderson tcg_op_remove(s, op_prev); 2260b4fc67c7SRichard Henderson remove = true; 2261b4fc67c7SRichard Henderson } 2262b4fc67c7SRichard Henderson } 2263b4fc67c7SRichard Henderson } 2264b4fc67c7SRichard Henderson break; 2265b4fc67c7SRichard Henderson 2266b4fc67c7SRichard Henderson case INDEX_op_br: 2267b4fc67c7SRichard Henderson case INDEX_op_exit_tb: 2268b4fc67c7SRichard Henderson case INDEX_op_goto_ptr: 2269b4fc67c7SRichard Henderson /* Unconditional branches; everything following is dead. */ 2270b4fc67c7SRichard Henderson dead = true; 2271b4fc67c7SRichard Henderson break; 2272b4fc67c7SRichard Henderson 2273b4fc67c7SRichard Henderson case INDEX_op_call: 2274b4fc67c7SRichard Henderson /* Notice noreturn helper calls, raising exceptions. */ 227590163900SRichard Henderson if (tcg_call_flags(op) & TCG_CALL_NO_RETURN) { 2276b4fc67c7SRichard Henderson dead = true; 2277b4fc67c7SRichard Henderson } 2278b4fc67c7SRichard Henderson break; 2279b4fc67c7SRichard Henderson 2280b4fc67c7SRichard Henderson case INDEX_op_insn_start: 2281b4fc67c7SRichard Henderson /* Never remove -- we need to keep these for unwind. */ 2282b4fc67c7SRichard Henderson remove = false; 2283b4fc67c7SRichard Henderson break; 2284b4fc67c7SRichard Henderson 2285b4fc67c7SRichard Henderson default: 2286b4fc67c7SRichard Henderson break; 2287b4fc67c7SRichard Henderson } 2288b4fc67c7SRichard Henderson 2289b4fc67c7SRichard Henderson if (remove) { 2290b4fc67c7SRichard Henderson tcg_op_remove(s, op); 2291b4fc67c7SRichard Henderson } 2292b4fc67c7SRichard Henderson } 2293b4fc67c7SRichard Henderson } 2294b4fc67c7SRichard Henderson 2295c70fbf0aSRichard Henderson #define TS_DEAD 1 2296c70fbf0aSRichard Henderson #define TS_MEM 2 2297c70fbf0aSRichard Henderson 22985a18407fSRichard Henderson #define IS_DEAD_ARG(n) (arg_life & (DEAD_ARG << (n))) 22995a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n))) 23005a18407fSRichard Henderson 230125f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp. */ 230225f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts) 230325f49c5fSRichard Henderson { 230425f49c5fSRichard Henderson return ts->state_ptr; 230525f49c5fSRichard Henderson } 230625f49c5fSRichard Henderson 230725f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the 230825f49c5fSRichard Henderson * maximal regset for its type. 230925f49c5fSRichard Henderson */ 231025f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts) 231125f49c5fSRichard Henderson { 231225f49c5fSRichard Henderson *la_temp_pref(ts) 231325f49c5fSRichard Henderson = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]); 231425f49c5fSRichard Henderson } 231525f49c5fSRichard Henderson 23169c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals 23179c43b68dSAurelien Jarno should be in memory. */ 23182616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt) 2319c896fe29Sbellard { 2320b83eabeaSRichard Henderson int i; 2321b83eabeaSRichard Henderson 2322b83eabeaSRichard Henderson for (i = 0; i < ng; ++i) { 2323b83eabeaSRichard Henderson s->temps[i].state = TS_DEAD | TS_MEM; 232425f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 2325b83eabeaSRichard Henderson } 2326b83eabeaSRichard Henderson for (i = ng; i < nt; ++i) { 2327b83eabeaSRichard Henderson s->temps[i].state = TS_DEAD; 232825f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 2329b83eabeaSRichard Henderson } 2330c896fe29Sbellard } 2331c896fe29Sbellard 23329c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals 23339c43b68dSAurelien Jarno and local temps should be in memory. */ 23342616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt) 2335641d5fbeSbellard { 2336b83eabeaSRichard Henderson int i; 2337641d5fbeSbellard 2338ee17db83SRichard Henderson for (i = 0; i < nt; ++i) { 2339ee17db83SRichard Henderson TCGTemp *ts = &s->temps[i]; 2340ee17db83SRichard Henderson int state; 2341ee17db83SRichard Henderson 2342ee17db83SRichard Henderson switch (ts->kind) { 2343ee17db83SRichard Henderson case TEMP_FIXED: 2344ee17db83SRichard Henderson case TEMP_GLOBAL: 2345ee17db83SRichard Henderson case TEMP_LOCAL: 2346ee17db83SRichard Henderson state = TS_DEAD | TS_MEM; 2347ee17db83SRichard Henderson break; 2348ee17db83SRichard Henderson case TEMP_NORMAL: 2349c0522136SRichard Henderson case TEMP_CONST: 2350ee17db83SRichard Henderson state = TS_DEAD; 2351ee17db83SRichard Henderson break; 2352ee17db83SRichard Henderson default: 2353ee17db83SRichard Henderson g_assert_not_reached(); 2354c70fbf0aSRichard Henderson } 2355ee17db83SRichard Henderson ts->state = state; 2356ee17db83SRichard Henderson la_reset_pref(ts); 2357641d5fbeSbellard } 2358641d5fbeSbellard } 2359641d5fbeSbellard 2360f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory. */ 2361f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng) 2362f65a061cSRichard Henderson { 2363f65a061cSRichard Henderson int i; 2364f65a061cSRichard Henderson 2365f65a061cSRichard Henderson for (i = 0; i < ng; ++i) { 236625f49c5fSRichard Henderson int state = s->temps[i].state; 236725f49c5fSRichard Henderson s->temps[i].state = state | TS_MEM; 236825f49c5fSRichard Henderson if (state == TS_DEAD) { 236925f49c5fSRichard Henderson /* If the global was previously dead, reset prefs. */ 237025f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 237125f49c5fSRichard Henderson } 2372f65a061cSRichard Henderson } 2373f65a061cSRichard Henderson } 2374f65a061cSRichard Henderson 2375b4cb76e6SRichard Henderson /* 2376b4cb76e6SRichard Henderson * liveness analysis: conditional branch: all temps are dead, 2377b4cb76e6SRichard Henderson * globals and local temps should be synced. 2378b4cb76e6SRichard Henderson */ 2379b4cb76e6SRichard Henderson static void la_bb_sync(TCGContext *s, int ng, int nt) 2380b4cb76e6SRichard Henderson { 2381b4cb76e6SRichard Henderson la_global_sync(s, ng); 2382b4cb76e6SRichard Henderson 2383b4cb76e6SRichard Henderson for (int i = ng; i < nt; ++i) { 2384c0522136SRichard Henderson TCGTemp *ts = &s->temps[i]; 2385c0522136SRichard Henderson int state; 2386c0522136SRichard Henderson 2387c0522136SRichard Henderson switch (ts->kind) { 2388c0522136SRichard Henderson case TEMP_LOCAL: 2389c0522136SRichard Henderson state = ts->state; 2390c0522136SRichard Henderson ts->state = state | TS_MEM; 2391b4cb76e6SRichard Henderson if (state != TS_DEAD) { 2392b4cb76e6SRichard Henderson continue; 2393b4cb76e6SRichard Henderson } 2394c0522136SRichard Henderson break; 2395c0522136SRichard Henderson case TEMP_NORMAL: 2396b4cb76e6SRichard Henderson s->temps[i].state = TS_DEAD; 2397c0522136SRichard Henderson break; 2398c0522136SRichard Henderson case TEMP_CONST: 2399c0522136SRichard Henderson continue; 2400c0522136SRichard Henderson default: 2401c0522136SRichard Henderson g_assert_not_reached(); 2402b4cb76e6SRichard Henderson } 2403b4cb76e6SRichard Henderson la_reset_pref(&s->temps[i]); 2404b4cb76e6SRichard Henderson } 2405b4cb76e6SRichard Henderson } 2406b4cb76e6SRichard Henderson 2407f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill. */ 2408f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng) 2409f65a061cSRichard Henderson { 2410f65a061cSRichard Henderson int i; 2411f65a061cSRichard Henderson 2412f65a061cSRichard Henderson for (i = 0; i < ng; i++) { 2413f65a061cSRichard Henderson s->temps[i].state = TS_DEAD | TS_MEM; 241425f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 241525f49c5fSRichard Henderson } 241625f49c5fSRichard Henderson } 241725f49c5fSRichard Henderson 241825f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls. */ 241925f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt) 242025f49c5fSRichard Henderson { 242125f49c5fSRichard Henderson TCGRegSet mask = ~tcg_target_call_clobber_regs; 242225f49c5fSRichard Henderson int i; 242325f49c5fSRichard Henderson 242425f49c5fSRichard Henderson for (i = 0; i < nt; i++) { 242525f49c5fSRichard Henderson TCGTemp *ts = &s->temps[i]; 242625f49c5fSRichard Henderson if (!(ts->state & TS_DEAD)) { 242725f49c5fSRichard Henderson TCGRegSet *pset = la_temp_pref(ts); 242825f49c5fSRichard Henderson TCGRegSet set = *pset; 242925f49c5fSRichard Henderson 243025f49c5fSRichard Henderson set &= mask; 243125f49c5fSRichard Henderson /* If the combination is not possible, restart. */ 243225f49c5fSRichard Henderson if (set == 0) { 243325f49c5fSRichard Henderson set = tcg_target_available_regs[ts->type] & mask; 243425f49c5fSRichard Henderson } 243525f49c5fSRichard Henderson *pset = set; 243625f49c5fSRichard Henderson } 2437f65a061cSRichard Henderson } 2438f65a061cSRichard Henderson } 2439f65a061cSRichard Henderson 2440a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a 2441c896fe29Sbellard given input arguments is dead. Instructions updating dead 2442c896fe29Sbellard temporaries are removed. */ 2443b83eabeaSRichard Henderson static void liveness_pass_1(TCGContext *s) 2444c896fe29Sbellard { 2445c70fbf0aSRichard Henderson int nb_globals = s->nb_globals; 24462616c808SRichard Henderson int nb_temps = s->nb_temps; 244715fa08f8SRichard Henderson TCGOp *op, *op_prev; 244825f49c5fSRichard Henderson TCGRegSet *prefs; 244925f49c5fSRichard Henderson int i; 245025f49c5fSRichard Henderson 245125f49c5fSRichard Henderson prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps); 245225f49c5fSRichard Henderson for (i = 0; i < nb_temps; ++i) { 245325f49c5fSRichard Henderson s->temps[i].state_ptr = prefs + i; 245425f49c5fSRichard Henderson } 2455c896fe29Sbellard 2456ae36a246SRichard Henderson /* ??? Should be redundant with the exit_tb that ends the TB. */ 24572616c808SRichard Henderson la_func_end(s, nb_globals, nb_temps); 2458c896fe29Sbellard 2459eae3eb3eSPaolo Bonzini QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) { 246025f49c5fSRichard Henderson int nb_iargs, nb_oargs; 2461c45cb8bbSRichard Henderson TCGOpcode opc_new, opc_new2; 2462c45cb8bbSRichard Henderson bool have_opc_new2; 2463a1b3c48dSRichard Henderson TCGLifeData arg_life = 0; 246425f49c5fSRichard Henderson TCGTemp *ts; 2465c45cb8bbSRichard Henderson TCGOpcode opc = op->opc; 2466c45cb8bbSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 2467c45cb8bbSRichard Henderson 2468c45cb8bbSRichard Henderson switch (opc) { 2469c896fe29Sbellard case INDEX_op_call: 2470c6e113f5Sbellard { 2471c6e113f5Sbellard int call_flags; 247225f49c5fSRichard Henderson int nb_call_regs; 2473c6e113f5Sbellard 2474cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 2475cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 247690163900SRichard Henderson call_flags = tcg_call_flags(op); 2477c6e113f5Sbellard 2478c45cb8bbSRichard Henderson /* pure functions can be removed if their result is unused */ 247978505279SAurelien Jarno if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) { 2480c6e113f5Sbellard for (i = 0; i < nb_oargs; i++) { 248125f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 248225f49c5fSRichard Henderson if (ts->state != TS_DEAD) { 2483c6e113f5Sbellard goto do_not_remove_call; 2484c6e113f5Sbellard } 24859c43b68dSAurelien Jarno } 2486c45cb8bbSRichard Henderson goto do_remove; 2487152c35aaSRichard Henderson } 2488c6e113f5Sbellard do_not_remove_call: 2489c896fe29Sbellard 249025f49c5fSRichard Henderson /* Output args are dead. */ 2491c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 249225f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 249325f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 2494a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 24956b64b624SAurelien Jarno } 249625f49c5fSRichard Henderson if (ts->state & TS_MEM) { 2497a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i; 24989c43b68dSAurelien Jarno } 249925f49c5fSRichard Henderson ts->state = TS_DEAD; 250025f49c5fSRichard Henderson la_reset_pref(ts); 250125f49c5fSRichard Henderson 250225f49c5fSRichard Henderson /* Not used -- it will be tcg_target_call_oarg_regs[i]. */ 250325f49c5fSRichard Henderson op->output_pref[i] = 0; 2504c896fe29Sbellard } 2505c896fe29Sbellard 250678505279SAurelien Jarno if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS | 250778505279SAurelien Jarno TCG_CALL_NO_READ_GLOBALS))) { 2508f65a061cSRichard Henderson la_global_kill(s, nb_globals); 2509c70fbf0aSRichard Henderson } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) { 2510f65a061cSRichard Henderson la_global_sync(s, nb_globals); 2511b9c18f56Saurel32 } 2512c896fe29Sbellard 251325f49c5fSRichard Henderson /* Record arguments that die in this helper. */ 2514866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 251525f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 251625f49c5fSRichard Henderson if (ts && ts->state & TS_DEAD) { 2517a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 2518c896fe29Sbellard } 2519c896fe29Sbellard } 252025f49c5fSRichard Henderson 252125f49c5fSRichard Henderson /* For all live registers, remove call-clobbered prefs. */ 252225f49c5fSRichard Henderson la_cross_call(s, nb_temps); 252325f49c5fSRichard Henderson 252425f49c5fSRichard Henderson nb_call_regs = ARRAY_SIZE(tcg_target_call_iarg_regs); 252525f49c5fSRichard Henderson 252625f49c5fSRichard Henderson /* Input arguments are live for preceding opcodes. */ 252725f49c5fSRichard Henderson for (i = 0; i < nb_iargs; i++) { 252825f49c5fSRichard Henderson ts = arg_temp(op->args[i + nb_oargs]); 252925f49c5fSRichard Henderson if (ts && ts->state & TS_DEAD) { 253025f49c5fSRichard Henderson /* For those arguments that die, and will be allocated 253125f49c5fSRichard Henderson * in registers, clear the register set for that arg, 253225f49c5fSRichard Henderson * to be filled in below. For args that will be on 253325f49c5fSRichard Henderson * the stack, reset to any available reg. 253425f49c5fSRichard Henderson */ 253525f49c5fSRichard Henderson *la_temp_pref(ts) 253625f49c5fSRichard Henderson = (i < nb_call_regs ? 0 : 253725f49c5fSRichard Henderson tcg_target_available_regs[ts->type]); 253825f49c5fSRichard Henderson ts->state &= ~TS_DEAD; 253925f49c5fSRichard Henderson } 254025f49c5fSRichard Henderson } 254125f49c5fSRichard Henderson 254225f49c5fSRichard Henderson /* For each input argument, add its input register to prefs. 254325f49c5fSRichard Henderson If a temp is used once, this produces a single set bit. */ 254425f49c5fSRichard Henderson for (i = 0; i < MIN(nb_call_regs, nb_iargs); i++) { 254525f49c5fSRichard Henderson ts = arg_temp(op->args[i + nb_oargs]); 254625f49c5fSRichard Henderson if (ts) { 254725f49c5fSRichard Henderson tcg_regset_set_reg(*la_temp_pref(ts), 254825f49c5fSRichard Henderson tcg_target_call_iarg_regs[i]); 2549c70fbf0aSRichard Henderson } 2550c19f47bfSAurelien Jarno } 2551c6e113f5Sbellard } 2552c896fe29Sbellard break; 2553765b842aSRichard Henderson case INDEX_op_insn_start: 2554c896fe29Sbellard break; 25555ff9d6a4Sbellard case INDEX_op_discard: 25565ff9d6a4Sbellard /* mark the temporary as dead */ 255725f49c5fSRichard Henderson ts = arg_temp(op->args[0]); 255825f49c5fSRichard Henderson ts->state = TS_DEAD; 255925f49c5fSRichard Henderson la_reset_pref(ts); 25605ff9d6a4Sbellard break; 25611305c451SRichard Henderson 25621305c451SRichard Henderson case INDEX_op_add2_i32: 2563c45cb8bbSRichard Henderson opc_new = INDEX_op_add_i32; 2564f1fae40cSRichard Henderson goto do_addsub2; 25651305c451SRichard Henderson case INDEX_op_sub2_i32: 2566c45cb8bbSRichard Henderson opc_new = INDEX_op_sub_i32; 2567f1fae40cSRichard Henderson goto do_addsub2; 2568f1fae40cSRichard Henderson case INDEX_op_add2_i64: 2569c45cb8bbSRichard Henderson opc_new = INDEX_op_add_i64; 2570f1fae40cSRichard Henderson goto do_addsub2; 2571f1fae40cSRichard Henderson case INDEX_op_sub2_i64: 2572c45cb8bbSRichard Henderson opc_new = INDEX_op_sub_i64; 2573f1fae40cSRichard Henderson do_addsub2: 25741305c451SRichard Henderson nb_iargs = 4; 25751305c451SRichard Henderson nb_oargs = 2; 25761305c451SRichard Henderson /* Test if the high part of the operation is dead, but not 25771305c451SRichard Henderson the low part. The result can be optimized to a simple 25781305c451SRichard Henderson add or sub. This happens often for x86_64 guest when the 25791305c451SRichard Henderson cpu mode is set to 32 bit. */ 2580b83eabeaSRichard Henderson if (arg_temp(op->args[1])->state == TS_DEAD) { 2581b83eabeaSRichard Henderson if (arg_temp(op->args[0])->state == TS_DEAD) { 25821305c451SRichard Henderson goto do_remove; 25831305c451SRichard Henderson } 2584c45cb8bbSRichard Henderson /* Replace the opcode and adjust the args in place, 2585c45cb8bbSRichard Henderson leaving 3 unused args at the end. */ 2586c45cb8bbSRichard Henderson op->opc = opc = opc_new; 2587efee3746SRichard Henderson op->args[1] = op->args[2]; 2588efee3746SRichard Henderson op->args[2] = op->args[4]; 25891305c451SRichard Henderson /* Fall through and mark the single-word operation live. */ 25901305c451SRichard Henderson nb_iargs = 2; 25911305c451SRichard Henderson nb_oargs = 1; 25921305c451SRichard Henderson } 25931305c451SRichard Henderson goto do_not_remove; 25941305c451SRichard Henderson 25951414968aSRichard Henderson case INDEX_op_mulu2_i32: 2596c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i32; 2597c45cb8bbSRichard Henderson opc_new2 = INDEX_op_muluh_i32; 2598c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_muluh_i32; 259903271524SRichard Henderson goto do_mul2; 2600f1fae40cSRichard Henderson case INDEX_op_muls2_i32: 2601c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i32; 2602c45cb8bbSRichard Henderson opc_new2 = INDEX_op_mulsh_i32; 2603c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_mulsh_i32; 2604f1fae40cSRichard Henderson goto do_mul2; 2605f1fae40cSRichard Henderson case INDEX_op_mulu2_i64: 2606c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i64; 2607c45cb8bbSRichard Henderson opc_new2 = INDEX_op_muluh_i64; 2608c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_muluh_i64; 260903271524SRichard Henderson goto do_mul2; 2610f1fae40cSRichard Henderson case INDEX_op_muls2_i64: 2611c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i64; 2612c45cb8bbSRichard Henderson opc_new2 = INDEX_op_mulsh_i64; 2613c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_mulsh_i64; 261403271524SRichard Henderson goto do_mul2; 2615f1fae40cSRichard Henderson do_mul2: 26161414968aSRichard Henderson nb_iargs = 2; 26171414968aSRichard Henderson nb_oargs = 2; 2618b83eabeaSRichard Henderson if (arg_temp(op->args[1])->state == TS_DEAD) { 2619b83eabeaSRichard Henderson if (arg_temp(op->args[0])->state == TS_DEAD) { 262003271524SRichard Henderson /* Both parts of the operation are dead. */ 26211414968aSRichard Henderson goto do_remove; 26221414968aSRichard Henderson } 262303271524SRichard Henderson /* The high part of the operation is dead; generate the low. */ 2624c45cb8bbSRichard Henderson op->opc = opc = opc_new; 2625efee3746SRichard Henderson op->args[1] = op->args[2]; 2626efee3746SRichard Henderson op->args[2] = op->args[3]; 2627b83eabeaSRichard Henderson } else if (arg_temp(op->args[0])->state == TS_DEAD && have_opc_new2) { 262803271524SRichard Henderson /* The low part of the operation is dead; generate the high. */ 2629c45cb8bbSRichard Henderson op->opc = opc = opc_new2; 2630efee3746SRichard Henderson op->args[0] = op->args[1]; 2631efee3746SRichard Henderson op->args[1] = op->args[2]; 2632efee3746SRichard Henderson op->args[2] = op->args[3]; 263303271524SRichard Henderson } else { 263403271524SRichard Henderson goto do_not_remove; 263503271524SRichard Henderson } 263603271524SRichard Henderson /* Mark the single-word operation live. */ 26371414968aSRichard Henderson nb_oargs = 1; 26381414968aSRichard Henderson goto do_not_remove; 26391414968aSRichard Henderson 2640c896fe29Sbellard default: 26411305c451SRichard Henderson /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */ 2642c896fe29Sbellard nb_iargs = def->nb_iargs; 2643c896fe29Sbellard nb_oargs = def->nb_oargs; 2644c896fe29Sbellard 2645c896fe29Sbellard /* Test if the operation can be removed because all 26465ff9d6a4Sbellard its outputs are dead. We assume that nb_oargs == 0 26475ff9d6a4Sbellard implies side effects */ 26485ff9d6a4Sbellard if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) { 2649c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 2650b83eabeaSRichard Henderson if (arg_temp(op->args[i])->state != TS_DEAD) { 2651c896fe29Sbellard goto do_not_remove; 2652c896fe29Sbellard } 26539c43b68dSAurelien Jarno } 2654152c35aaSRichard Henderson goto do_remove; 2655152c35aaSRichard Henderson } 2656152c35aaSRichard Henderson goto do_not_remove; 2657152c35aaSRichard Henderson 26581305c451SRichard Henderson do_remove: 26590c627cdcSRichard Henderson tcg_op_remove(s, op); 2660152c35aaSRichard Henderson break; 2661152c35aaSRichard Henderson 2662c896fe29Sbellard do_not_remove: 2663c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 266425f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 266525f49c5fSRichard Henderson 266625f49c5fSRichard Henderson /* Remember the preference of the uses that followed. */ 266725f49c5fSRichard Henderson op->output_pref[i] = *la_temp_pref(ts); 266825f49c5fSRichard Henderson 266925f49c5fSRichard Henderson /* Output args are dead. */ 267025f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 2671a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 26726b64b624SAurelien Jarno } 267325f49c5fSRichard Henderson if (ts->state & TS_MEM) { 2674a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i; 26759c43b68dSAurelien Jarno } 267625f49c5fSRichard Henderson ts->state = TS_DEAD; 267725f49c5fSRichard Henderson la_reset_pref(ts); 2678c896fe29Sbellard } 2679c896fe29Sbellard 268025f49c5fSRichard Henderson /* If end of basic block, update. */ 2681ae36a246SRichard Henderson if (def->flags & TCG_OPF_BB_EXIT) { 2682ae36a246SRichard Henderson la_func_end(s, nb_globals, nb_temps); 2683b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_COND_BRANCH) { 2684b4cb76e6SRichard Henderson la_bb_sync(s, nb_globals, nb_temps); 2685ae36a246SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 26862616c808SRichard Henderson la_bb_end(s, nb_globals, nb_temps); 26873d5c5f87SAurelien Jarno } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { 2688f65a061cSRichard Henderson la_global_sync(s, nb_globals); 268925f49c5fSRichard Henderson if (def->flags & TCG_OPF_CALL_CLOBBER) { 269025f49c5fSRichard Henderson la_cross_call(s, nb_temps); 269125f49c5fSRichard Henderson } 2692c896fe29Sbellard } 2693c896fe29Sbellard 269425f49c5fSRichard Henderson /* Record arguments that die in this opcode. */ 2695866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 269625f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 269725f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 2698a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 2699c896fe29Sbellard } 2700c19f47bfSAurelien Jarno } 270125f49c5fSRichard Henderson 270225f49c5fSRichard Henderson /* Input arguments are live for preceding opcodes. */ 2703c19f47bfSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 270425f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 270525f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 270625f49c5fSRichard Henderson /* For operands that were dead, initially allow 270725f49c5fSRichard Henderson all regs for the type. */ 270825f49c5fSRichard Henderson *la_temp_pref(ts) = tcg_target_available_regs[ts->type]; 270925f49c5fSRichard Henderson ts->state &= ~TS_DEAD; 271025f49c5fSRichard Henderson } 271125f49c5fSRichard Henderson } 271225f49c5fSRichard Henderson 271325f49c5fSRichard Henderson /* Incorporate constraints for this operand. */ 271425f49c5fSRichard Henderson switch (opc) { 271525f49c5fSRichard Henderson case INDEX_op_mov_i32: 271625f49c5fSRichard Henderson case INDEX_op_mov_i64: 271725f49c5fSRichard Henderson /* Note that these are TCG_OPF_NOT_PRESENT and do not 271825f49c5fSRichard Henderson have proper constraints. That said, special case 271925f49c5fSRichard Henderson moves to propagate preferences backward. */ 272025f49c5fSRichard Henderson if (IS_DEAD_ARG(1)) { 272125f49c5fSRichard Henderson *la_temp_pref(arg_temp(op->args[0])) 272225f49c5fSRichard Henderson = *la_temp_pref(arg_temp(op->args[1])); 272325f49c5fSRichard Henderson } 272425f49c5fSRichard Henderson break; 272525f49c5fSRichard Henderson 272625f49c5fSRichard Henderson default: 272725f49c5fSRichard Henderson for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 272825f49c5fSRichard Henderson const TCGArgConstraint *ct = &def->args_ct[i]; 272925f49c5fSRichard Henderson TCGRegSet set, *pset; 273025f49c5fSRichard Henderson 273125f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 273225f49c5fSRichard Henderson pset = la_temp_pref(ts); 273325f49c5fSRichard Henderson set = *pset; 273425f49c5fSRichard Henderson 27359be0d080SRichard Henderson set &= ct->regs; 2736bc2b17e6SRichard Henderson if (ct->ialias) { 273725f49c5fSRichard Henderson set &= op->output_pref[ct->alias_index]; 273825f49c5fSRichard Henderson } 273925f49c5fSRichard Henderson /* If the combination is not possible, restart. */ 274025f49c5fSRichard Henderson if (set == 0) { 27419be0d080SRichard Henderson set = ct->regs; 274225f49c5fSRichard Henderson } 274325f49c5fSRichard Henderson *pset = set; 274425f49c5fSRichard Henderson } 274525f49c5fSRichard Henderson break; 2746c896fe29Sbellard } 2747c896fe29Sbellard break; 2748c896fe29Sbellard } 2749bee158cbSRichard Henderson op->life = arg_life; 2750c896fe29Sbellard } 27511ff0a2c5SEvgeny Voevodin } 2752c896fe29Sbellard 27535a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries. */ 2754b83eabeaSRichard Henderson static bool liveness_pass_2(TCGContext *s) 27555a18407fSRichard Henderson { 27565a18407fSRichard Henderson int nb_globals = s->nb_globals; 275715fa08f8SRichard Henderson int nb_temps, i; 27585a18407fSRichard Henderson bool changes = false; 275915fa08f8SRichard Henderson TCGOp *op, *op_next; 27605a18407fSRichard Henderson 27615a18407fSRichard Henderson /* Create a temporary for each indirect global. */ 27625a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 27635a18407fSRichard Henderson TCGTemp *its = &s->temps[i]; 27645a18407fSRichard Henderson if (its->indirect_reg) { 27655a18407fSRichard Henderson TCGTemp *dts = tcg_temp_alloc(s); 27665a18407fSRichard Henderson dts->type = its->type; 27675a18407fSRichard Henderson dts->base_type = its->base_type; 2768b83eabeaSRichard Henderson its->state_ptr = dts; 2769b83eabeaSRichard Henderson } else { 2770b83eabeaSRichard Henderson its->state_ptr = NULL; 27715a18407fSRichard Henderson } 2772b83eabeaSRichard Henderson /* All globals begin dead. */ 2773b83eabeaSRichard Henderson its->state = TS_DEAD; 27745a18407fSRichard Henderson } 2775b83eabeaSRichard Henderson for (nb_temps = s->nb_temps; i < nb_temps; ++i) { 2776b83eabeaSRichard Henderson TCGTemp *its = &s->temps[i]; 2777b83eabeaSRichard Henderson its->state_ptr = NULL; 2778b83eabeaSRichard Henderson its->state = TS_DEAD; 2779b83eabeaSRichard Henderson } 27805a18407fSRichard Henderson 278115fa08f8SRichard Henderson QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) { 27825a18407fSRichard Henderson TCGOpcode opc = op->opc; 27835a18407fSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 27845a18407fSRichard Henderson TCGLifeData arg_life = op->life; 27855a18407fSRichard Henderson int nb_iargs, nb_oargs, call_flags; 2786b83eabeaSRichard Henderson TCGTemp *arg_ts, *dir_ts; 27875a18407fSRichard Henderson 27885a18407fSRichard Henderson if (opc == INDEX_op_call) { 2789cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 2790cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 279190163900SRichard Henderson call_flags = tcg_call_flags(op); 27925a18407fSRichard Henderson } else { 27935a18407fSRichard Henderson nb_iargs = def->nb_iargs; 27945a18407fSRichard Henderson nb_oargs = def->nb_oargs; 27955a18407fSRichard Henderson 27965a18407fSRichard Henderson /* Set flags similar to how calls require. */ 2797b4cb76e6SRichard Henderson if (def->flags & TCG_OPF_COND_BRANCH) { 2798b4cb76e6SRichard Henderson /* Like reading globals: sync_globals */ 2799b4cb76e6SRichard Henderson call_flags = TCG_CALL_NO_WRITE_GLOBALS; 2800b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 28015a18407fSRichard Henderson /* Like writing globals: save_globals */ 28025a18407fSRichard Henderson call_flags = 0; 28035a18407fSRichard Henderson } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { 28045a18407fSRichard Henderson /* Like reading globals: sync_globals */ 28055a18407fSRichard Henderson call_flags = TCG_CALL_NO_WRITE_GLOBALS; 28065a18407fSRichard Henderson } else { 28075a18407fSRichard Henderson /* No effect on globals. */ 28085a18407fSRichard Henderson call_flags = (TCG_CALL_NO_READ_GLOBALS | 28095a18407fSRichard Henderson TCG_CALL_NO_WRITE_GLOBALS); 28105a18407fSRichard Henderson } 28115a18407fSRichard Henderson } 28125a18407fSRichard Henderson 28135a18407fSRichard Henderson /* Make sure that input arguments are available. */ 28145a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 2815b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 2816b83eabeaSRichard Henderson if (arg_ts) { 2817b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 2818b83eabeaSRichard Henderson if (dir_ts && arg_ts->state == TS_DEAD) { 2819b83eabeaSRichard Henderson TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32 28205a18407fSRichard Henderson ? INDEX_op_ld_i32 28215a18407fSRichard Henderson : INDEX_op_ld_i64); 2822ac1043f6SEmilio G. Cota TCGOp *lop = tcg_op_insert_before(s, op, lopc); 28235a18407fSRichard Henderson 2824b83eabeaSRichard Henderson lop->args[0] = temp_arg(dir_ts); 2825b83eabeaSRichard Henderson lop->args[1] = temp_arg(arg_ts->mem_base); 2826b83eabeaSRichard Henderson lop->args[2] = arg_ts->mem_offset; 28275a18407fSRichard Henderson 28285a18407fSRichard Henderson /* Loaded, but synced with memory. */ 2829b83eabeaSRichard Henderson arg_ts->state = TS_MEM; 28305a18407fSRichard Henderson } 28315a18407fSRichard Henderson } 28325a18407fSRichard Henderson } 28335a18407fSRichard Henderson 28345a18407fSRichard Henderson /* Perform input replacement, and mark inputs that became dead. 28355a18407fSRichard Henderson No action is required except keeping temp_state up to date 28365a18407fSRichard Henderson so that we reload when needed. */ 28375a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 2838b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 2839b83eabeaSRichard Henderson if (arg_ts) { 2840b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 2841b83eabeaSRichard Henderson if (dir_ts) { 2842b83eabeaSRichard Henderson op->args[i] = temp_arg(dir_ts); 28435a18407fSRichard Henderson changes = true; 28445a18407fSRichard Henderson if (IS_DEAD_ARG(i)) { 2845b83eabeaSRichard Henderson arg_ts->state = TS_DEAD; 28465a18407fSRichard Henderson } 28475a18407fSRichard Henderson } 28485a18407fSRichard Henderson } 28495a18407fSRichard Henderson } 28505a18407fSRichard Henderson 28515a18407fSRichard Henderson /* Liveness analysis should ensure that the following are 28525a18407fSRichard Henderson all correct, for call sites and basic block end points. */ 28535a18407fSRichard Henderson if (call_flags & TCG_CALL_NO_READ_GLOBALS) { 28545a18407fSRichard Henderson /* Nothing to do */ 28555a18407fSRichard Henderson } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) { 28565a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 28575a18407fSRichard Henderson /* Liveness should see that globals are synced back, 28585a18407fSRichard Henderson that is, either TS_DEAD or TS_MEM. */ 2859b83eabeaSRichard Henderson arg_ts = &s->temps[i]; 2860b83eabeaSRichard Henderson tcg_debug_assert(arg_ts->state_ptr == 0 2861b83eabeaSRichard Henderson || arg_ts->state != 0); 28625a18407fSRichard Henderson } 28635a18407fSRichard Henderson } else { 28645a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 28655a18407fSRichard Henderson /* Liveness should see that globals are saved back, 28665a18407fSRichard Henderson that is, TS_DEAD, waiting to be reloaded. */ 2867b83eabeaSRichard Henderson arg_ts = &s->temps[i]; 2868b83eabeaSRichard Henderson tcg_debug_assert(arg_ts->state_ptr == 0 2869b83eabeaSRichard Henderson || arg_ts->state == TS_DEAD); 28705a18407fSRichard Henderson } 28715a18407fSRichard Henderson } 28725a18407fSRichard Henderson 28735a18407fSRichard Henderson /* Outputs become available. */ 287461f15c48SRichard Henderson if (opc == INDEX_op_mov_i32 || opc == INDEX_op_mov_i64) { 287561f15c48SRichard Henderson arg_ts = arg_temp(op->args[0]); 287661f15c48SRichard Henderson dir_ts = arg_ts->state_ptr; 287761f15c48SRichard Henderson if (dir_ts) { 287861f15c48SRichard Henderson op->args[0] = temp_arg(dir_ts); 287961f15c48SRichard Henderson changes = true; 288061f15c48SRichard Henderson 288161f15c48SRichard Henderson /* The output is now live and modified. */ 288261f15c48SRichard Henderson arg_ts->state = 0; 288361f15c48SRichard Henderson 288461f15c48SRichard Henderson if (NEED_SYNC_ARG(0)) { 288561f15c48SRichard Henderson TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 288661f15c48SRichard Henderson ? INDEX_op_st_i32 288761f15c48SRichard Henderson : INDEX_op_st_i64); 288861f15c48SRichard Henderson TCGOp *sop = tcg_op_insert_after(s, op, sopc); 288961f15c48SRichard Henderson TCGTemp *out_ts = dir_ts; 289061f15c48SRichard Henderson 289161f15c48SRichard Henderson if (IS_DEAD_ARG(0)) { 289261f15c48SRichard Henderson out_ts = arg_temp(op->args[1]); 289361f15c48SRichard Henderson arg_ts->state = TS_DEAD; 289461f15c48SRichard Henderson tcg_op_remove(s, op); 289561f15c48SRichard Henderson } else { 289661f15c48SRichard Henderson arg_ts->state = TS_MEM; 289761f15c48SRichard Henderson } 289861f15c48SRichard Henderson 289961f15c48SRichard Henderson sop->args[0] = temp_arg(out_ts); 290061f15c48SRichard Henderson sop->args[1] = temp_arg(arg_ts->mem_base); 290161f15c48SRichard Henderson sop->args[2] = arg_ts->mem_offset; 290261f15c48SRichard Henderson } else { 290361f15c48SRichard Henderson tcg_debug_assert(!IS_DEAD_ARG(0)); 290461f15c48SRichard Henderson } 290561f15c48SRichard Henderson } 290661f15c48SRichard Henderson } else { 29075a18407fSRichard Henderson for (i = 0; i < nb_oargs; i++) { 2908b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 2909b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 2910b83eabeaSRichard Henderson if (!dir_ts) { 29115a18407fSRichard Henderson continue; 29125a18407fSRichard Henderson } 2913b83eabeaSRichard Henderson op->args[i] = temp_arg(dir_ts); 29145a18407fSRichard Henderson changes = true; 29155a18407fSRichard Henderson 29165a18407fSRichard Henderson /* The output is now live and modified. */ 2917b83eabeaSRichard Henderson arg_ts->state = 0; 29185a18407fSRichard Henderson 29195a18407fSRichard Henderson /* Sync outputs upon their last write. */ 29205a18407fSRichard Henderson if (NEED_SYNC_ARG(i)) { 2921b83eabeaSRichard Henderson TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 29225a18407fSRichard Henderson ? INDEX_op_st_i32 29235a18407fSRichard Henderson : INDEX_op_st_i64); 2924ac1043f6SEmilio G. Cota TCGOp *sop = tcg_op_insert_after(s, op, sopc); 29255a18407fSRichard Henderson 2926b83eabeaSRichard Henderson sop->args[0] = temp_arg(dir_ts); 2927b83eabeaSRichard Henderson sop->args[1] = temp_arg(arg_ts->mem_base); 2928b83eabeaSRichard Henderson sop->args[2] = arg_ts->mem_offset; 29295a18407fSRichard Henderson 2930b83eabeaSRichard Henderson arg_ts->state = TS_MEM; 29315a18407fSRichard Henderson } 29325a18407fSRichard Henderson /* Drop outputs that are dead. */ 29335a18407fSRichard Henderson if (IS_DEAD_ARG(i)) { 2934b83eabeaSRichard Henderson arg_ts->state = TS_DEAD; 29355a18407fSRichard Henderson } 29365a18407fSRichard Henderson } 29375a18407fSRichard Henderson } 293861f15c48SRichard Henderson } 29395a18407fSRichard Henderson 29405a18407fSRichard Henderson return changes; 29415a18407fSRichard Henderson } 29425a18407fSRichard Henderson 29438d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG 2944c896fe29Sbellard static void dump_regs(TCGContext *s) 2945c896fe29Sbellard { 2946c896fe29Sbellard TCGTemp *ts; 2947c896fe29Sbellard int i; 2948c896fe29Sbellard char buf[64]; 2949c896fe29Sbellard 2950c896fe29Sbellard for(i = 0; i < s->nb_temps; i++) { 2951c896fe29Sbellard ts = &s->temps[i]; 295243439139SRichard Henderson printf(" %10s: ", tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts)); 2953c896fe29Sbellard switch(ts->val_type) { 2954c896fe29Sbellard case TEMP_VAL_REG: 2955c896fe29Sbellard printf("%s", tcg_target_reg_names[ts->reg]); 2956c896fe29Sbellard break; 2957c896fe29Sbellard case TEMP_VAL_MEM: 2958b3a62939SRichard Henderson printf("%d(%s)", (int)ts->mem_offset, 2959b3a62939SRichard Henderson tcg_target_reg_names[ts->mem_base->reg]); 2960c896fe29Sbellard break; 2961c896fe29Sbellard case TEMP_VAL_CONST: 2962bdb38b95SRichard Henderson printf("$0x%" PRIx64, ts->val); 2963c896fe29Sbellard break; 2964c896fe29Sbellard case TEMP_VAL_DEAD: 2965c896fe29Sbellard printf("D"); 2966c896fe29Sbellard break; 2967c896fe29Sbellard default: 2968c896fe29Sbellard printf("???"); 2969c896fe29Sbellard break; 2970c896fe29Sbellard } 2971c896fe29Sbellard printf("\n"); 2972c896fe29Sbellard } 2973c896fe29Sbellard 2974c896fe29Sbellard for(i = 0; i < TCG_TARGET_NB_REGS; i++) { 2975f8b2f202SRichard Henderson if (s->reg_to_temp[i] != NULL) { 2976c896fe29Sbellard printf("%s: %s\n", 2977c896fe29Sbellard tcg_target_reg_names[i], 2978f8b2f202SRichard Henderson tcg_get_arg_str_ptr(s, buf, sizeof(buf), s->reg_to_temp[i])); 2979c896fe29Sbellard } 2980c896fe29Sbellard } 2981c896fe29Sbellard } 2982c896fe29Sbellard 2983c896fe29Sbellard static void check_regs(TCGContext *s) 2984c896fe29Sbellard { 2985869938aeSRichard Henderson int reg; 2986b6638662SRichard Henderson int k; 2987c896fe29Sbellard TCGTemp *ts; 2988c896fe29Sbellard char buf[64]; 2989c896fe29Sbellard 2990c896fe29Sbellard for (reg = 0; reg < TCG_TARGET_NB_REGS; reg++) { 2991f8b2f202SRichard Henderson ts = s->reg_to_temp[reg]; 2992f8b2f202SRichard Henderson if (ts != NULL) { 2993f8b2f202SRichard Henderson if (ts->val_type != TEMP_VAL_REG || ts->reg != reg) { 2994c896fe29Sbellard printf("Inconsistency for register %s:\n", 2995c896fe29Sbellard tcg_target_reg_names[reg]); 2996b03cce8eSbellard goto fail; 2997c896fe29Sbellard } 2998c896fe29Sbellard } 2999c896fe29Sbellard } 3000c896fe29Sbellard for (k = 0; k < s->nb_temps; k++) { 3001c896fe29Sbellard ts = &s->temps[k]; 3002ee17db83SRichard Henderson if (ts->val_type == TEMP_VAL_REG 3003ee17db83SRichard Henderson && ts->kind != TEMP_FIXED 3004f8b2f202SRichard Henderson && s->reg_to_temp[ts->reg] != ts) { 3005c896fe29Sbellard printf("Inconsistency for temp %s:\n", 3006f8b2f202SRichard Henderson tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts)); 3007b03cce8eSbellard fail: 3008c896fe29Sbellard printf("reg state:\n"); 3009c896fe29Sbellard dump_regs(s); 3010c896fe29Sbellard tcg_abort(); 3011c896fe29Sbellard } 3012c896fe29Sbellard } 3013c896fe29Sbellard } 3014c896fe29Sbellard #endif 3015c896fe29Sbellard 30162272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts) 3017c896fe29Sbellard { 3018c1c09194SRichard Henderson intptr_t off, size, align; 3019c1c09194SRichard Henderson 3020c1c09194SRichard Henderson switch (ts->type) { 3021c1c09194SRichard Henderson case TCG_TYPE_I32: 3022c1c09194SRichard Henderson size = align = 4; 3023c1c09194SRichard Henderson break; 3024c1c09194SRichard Henderson case TCG_TYPE_I64: 3025c1c09194SRichard Henderson case TCG_TYPE_V64: 3026c1c09194SRichard Henderson size = align = 8; 3027c1c09194SRichard Henderson break; 3028c1c09194SRichard Henderson case TCG_TYPE_V128: 3029c1c09194SRichard Henderson size = align = 16; 3030c1c09194SRichard Henderson break; 3031c1c09194SRichard Henderson case TCG_TYPE_V256: 3032c1c09194SRichard Henderson /* Note that we do not require aligned storage for V256. */ 3033c1c09194SRichard Henderson size = 32, align = 16; 3034c1c09194SRichard Henderson break; 3035c1c09194SRichard Henderson default: 3036c1c09194SRichard Henderson g_assert_not_reached(); 3037b591dc59SBlue Swirl } 3038c1c09194SRichard Henderson 3039c1c09194SRichard Henderson assert(align <= TCG_TARGET_STACK_ALIGN); 3040c1c09194SRichard Henderson off = ROUND_UP(s->current_frame_offset, align); 3041*732d5897SRichard Henderson 3042*732d5897SRichard Henderson /* If we've exhausted the stack frame, restart with a smaller TB. */ 3043*732d5897SRichard Henderson if (off + size > s->frame_end) { 3044*732d5897SRichard Henderson tcg_raise_tb_overflow(s); 3045*732d5897SRichard Henderson } 3046c1c09194SRichard Henderson s->current_frame_offset = off + size; 3047c1c09194SRichard Henderson 3048c1c09194SRichard Henderson ts->mem_offset = off; 30499defd1bdSRichard Henderson #if defined(__sparc__) 30509defd1bdSRichard Henderson ts->mem_offset += TCG_TARGET_STACK_BIAS; 30519defd1bdSRichard Henderson #endif 3052b3a62939SRichard Henderson ts->mem_base = s->frame_temp; 3053c896fe29Sbellard ts->mem_allocated = 1; 3054c896fe29Sbellard } 3055c896fe29Sbellard 3056b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet); 3057b3915dbbSRichard Henderson 305859d7c14eSRichard Henderson /* Mark a temporary as free or dead. If 'free_or_dead' is negative, 305959d7c14eSRichard Henderson mark it free; otherwise mark it dead. */ 306059d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead) 3061c896fe29Sbellard { 3062c0522136SRichard Henderson TCGTempVal new_type; 3063c0522136SRichard Henderson 3064c0522136SRichard Henderson switch (ts->kind) { 3065c0522136SRichard Henderson case TEMP_FIXED: 306659d7c14eSRichard Henderson return; 3067c0522136SRichard Henderson case TEMP_GLOBAL: 3068c0522136SRichard Henderson case TEMP_LOCAL: 3069c0522136SRichard Henderson new_type = TEMP_VAL_MEM; 3070c0522136SRichard Henderson break; 3071c0522136SRichard Henderson case TEMP_NORMAL: 3072c0522136SRichard Henderson new_type = free_or_dead < 0 ? TEMP_VAL_MEM : TEMP_VAL_DEAD; 3073c0522136SRichard Henderson break; 3074c0522136SRichard Henderson case TEMP_CONST: 3075c0522136SRichard Henderson new_type = TEMP_VAL_CONST; 3076c0522136SRichard Henderson break; 3077c0522136SRichard Henderson default: 3078c0522136SRichard Henderson g_assert_not_reached(); 307959d7c14eSRichard Henderson } 308059d7c14eSRichard Henderson if (ts->val_type == TEMP_VAL_REG) { 308159d7c14eSRichard Henderson s->reg_to_temp[ts->reg] = NULL; 308259d7c14eSRichard Henderson } 3083c0522136SRichard Henderson ts->val_type = new_type; 308459d7c14eSRichard Henderson } 3085c896fe29Sbellard 308659d7c14eSRichard Henderson /* Mark a temporary as dead. */ 308759d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts) 308859d7c14eSRichard Henderson { 308959d7c14eSRichard Henderson temp_free_or_dead(s, ts, 1); 309059d7c14eSRichard Henderson } 309159d7c14eSRichard Henderson 309259d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary 309359d7c14eSRichard Henderson registers needs to be allocated to store a constant. If 'free_or_dead' 309459d7c14eSRichard Henderson is non-zero, subsequently release the temporary; if it is positive, the 309559d7c14eSRichard Henderson temp is dead; if it is negative, the temp is free. */ 309698b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs, 309798b4e186SRichard Henderson TCGRegSet preferred_regs, int free_or_dead) 309859d7c14eSRichard Henderson { 3099c0522136SRichard Henderson if (!temp_readonly(ts) && !ts->mem_coherent) { 31007f6ceedfSAurelien Jarno if (!ts->mem_allocated) { 31012272e4a7SRichard Henderson temp_allocate_frame(s, ts); 310259d7c14eSRichard Henderson } 310359d7c14eSRichard Henderson switch (ts->val_type) { 310459d7c14eSRichard Henderson case TEMP_VAL_CONST: 310559d7c14eSRichard Henderson /* If we're going to free the temp immediately, then we won't 310659d7c14eSRichard Henderson require it later in a register, so attempt to store the 310759d7c14eSRichard Henderson constant to memory directly. */ 310859d7c14eSRichard Henderson if (free_or_dead 310959d7c14eSRichard Henderson && tcg_out_sti(s, ts->type, ts->val, 311059d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset)) { 311159d7c14eSRichard Henderson break; 311259d7c14eSRichard Henderson } 311359d7c14eSRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 311498b4e186SRichard Henderson allocated_regs, preferred_regs); 311559d7c14eSRichard Henderson /* fallthrough */ 311659d7c14eSRichard Henderson 311759d7c14eSRichard Henderson case TEMP_VAL_REG: 311859d7c14eSRichard Henderson tcg_out_st(s, ts->type, ts->reg, 311959d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset); 312059d7c14eSRichard Henderson break; 312159d7c14eSRichard Henderson 312259d7c14eSRichard Henderson case TEMP_VAL_MEM: 312359d7c14eSRichard Henderson break; 312459d7c14eSRichard Henderson 312559d7c14eSRichard Henderson case TEMP_VAL_DEAD: 312659d7c14eSRichard Henderson default: 312759d7c14eSRichard Henderson tcg_abort(); 3128c896fe29Sbellard } 31297f6ceedfSAurelien Jarno ts->mem_coherent = 1; 31307f6ceedfSAurelien Jarno } 313159d7c14eSRichard Henderson if (free_or_dead) { 313259d7c14eSRichard Henderson temp_free_or_dead(s, ts, free_or_dead); 313359d7c14eSRichard Henderson } 313459d7c14eSRichard Henderson } 31357f6ceedfSAurelien Jarno 31367f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */ 3137b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs) 31387f6ceedfSAurelien Jarno { 3139f8b2f202SRichard Henderson TCGTemp *ts = s->reg_to_temp[reg]; 3140f8b2f202SRichard Henderson if (ts != NULL) { 314198b4e186SRichard Henderson temp_sync(s, ts, allocated_regs, 0, -1); 3142c896fe29Sbellard } 3143c896fe29Sbellard } 3144c896fe29Sbellard 3145b016486eSRichard Henderson /** 3146b016486eSRichard Henderson * tcg_reg_alloc: 3147b016486eSRichard Henderson * @required_regs: Set of registers in which we must allocate. 3148b016486eSRichard Henderson * @allocated_regs: Set of registers which must be avoided. 3149b016486eSRichard Henderson * @preferred_regs: Set of registers we should prefer. 3150b016486eSRichard Henderson * @rev: True if we search the registers in "indirect" order. 3151b016486eSRichard Henderson * 3152b016486eSRichard Henderson * The allocated register must be in @required_regs & ~@allocated_regs, 3153b016486eSRichard Henderson * but if we can put it in @preferred_regs we may save a move later. 3154b016486eSRichard Henderson */ 3155b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs, 3156b016486eSRichard Henderson TCGRegSet allocated_regs, 3157b016486eSRichard Henderson TCGRegSet preferred_regs, bool rev) 3158c896fe29Sbellard { 3159b016486eSRichard Henderson int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order); 3160b016486eSRichard Henderson TCGRegSet reg_ct[2]; 316191478cefSRichard Henderson const int *order; 3162c896fe29Sbellard 3163b016486eSRichard Henderson reg_ct[1] = required_regs & ~allocated_regs; 3164b016486eSRichard Henderson tcg_debug_assert(reg_ct[1] != 0); 3165b016486eSRichard Henderson reg_ct[0] = reg_ct[1] & preferred_regs; 3166b016486eSRichard Henderson 3167b016486eSRichard Henderson /* Skip the preferred_regs option if it cannot be satisfied, 3168b016486eSRichard Henderson or if the preference made no difference. */ 3169b016486eSRichard Henderson f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1]; 3170b016486eSRichard Henderson 317191478cefSRichard Henderson order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order; 3172c896fe29Sbellard 3173b016486eSRichard Henderson /* Try free registers, preferences first. */ 3174b016486eSRichard Henderson for (j = f; j < 2; j++) { 3175b016486eSRichard Henderson TCGRegSet set = reg_ct[j]; 3176b016486eSRichard Henderson 3177b016486eSRichard Henderson if (tcg_regset_single(set)) { 3178b016486eSRichard Henderson /* One register in the set. */ 3179b016486eSRichard Henderson TCGReg reg = tcg_regset_first(set); 3180b016486eSRichard Henderson if (s->reg_to_temp[reg] == NULL) { 3181c896fe29Sbellard return reg; 3182c896fe29Sbellard } 3183b016486eSRichard Henderson } else { 318491478cefSRichard Henderson for (i = 0; i < n; i++) { 3185b016486eSRichard Henderson TCGReg reg = order[i]; 3186b016486eSRichard Henderson if (s->reg_to_temp[reg] == NULL && 3187b016486eSRichard Henderson tcg_regset_test_reg(set, reg)) { 3188b016486eSRichard Henderson return reg; 3189b016486eSRichard Henderson } 3190b016486eSRichard Henderson } 3191b016486eSRichard Henderson } 3192b016486eSRichard Henderson } 3193b016486eSRichard Henderson 3194b016486eSRichard Henderson /* We must spill something. */ 3195b016486eSRichard Henderson for (j = f; j < 2; j++) { 3196b016486eSRichard Henderson TCGRegSet set = reg_ct[j]; 3197b016486eSRichard Henderson 3198b016486eSRichard Henderson if (tcg_regset_single(set)) { 3199b016486eSRichard Henderson /* One register in the set. */ 3200b016486eSRichard Henderson TCGReg reg = tcg_regset_first(set); 3201b3915dbbSRichard Henderson tcg_reg_free(s, reg, allocated_regs); 3202c896fe29Sbellard return reg; 3203b016486eSRichard Henderson } else { 3204b016486eSRichard Henderson for (i = 0; i < n; i++) { 3205b016486eSRichard Henderson TCGReg reg = order[i]; 3206b016486eSRichard Henderson if (tcg_regset_test_reg(set, reg)) { 3207b016486eSRichard Henderson tcg_reg_free(s, reg, allocated_regs); 3208b016486eSRichard Henderson return reg; 3209b016486eSRichard Henderson } 3210b016486eSRichard Henderson } 3211c896fe29Sbellard } 3212c896fe29Sbellard } 3213c896fe29Sbellard 3214c896fe29Sbellard tcg_abort(); 3215c896fe29Sbellard } 3216c896fe29Sbellard 321740ae5c62SRichard Henderson /* Make sure the temporary is in a register. If needed, allocate the register 321840ae5c62SRichard Henderson from DESIRED while avoiding ALLOCATED. */ 321940ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs, 3220b722452aSRichard Henderson TCGRegSet allocated_regs, TCGRegSet preferred_regs) 322140ae5c62SRichard Henderson { 322240ae5c62SRichard Henderson TCGReg reg; 322340ae5c62SRichard Henderson 322440ae5c62SRichard Henderson switch (ts->val_type) { 322540ae5c62SRichard Henderson case TEMP_VAL_REG: 322640ae5c62SRichard Henderson return; 322740ae5c62SRichard Henderson case TEMP_VAL_CONST: 3228b016486eSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs, 3229b722452aSRichard Henderson preferred_regs, ts->indirect_base); 32300a6a8bc8SRichard Henderson if (ts->type <= TCG_TYPE_I64) { 323140ae5c62SRichard Henderson tcg_out_movi(s, ts->type, reg, ts->val); 32320a6a8bc8SRichard Henderson } else { 32334e186175SRichard Henderson uint64_t val = ts->val; 32344e186175SRichard Henderson MemOp vece = MO_64; 32354e186175SRichard Henderson 32364e186175SRichard Henderson /* 32374e186175SRichard Henderson * Find the minimal vector element that matches the constant. 32384e186175SRichard Henderson * The targets will, in general, have to do this search anyway, 32394e186175SRichard Henderson * do this generically. 32404e186175SRichard Henderson */ 32414e186175SRichard Henderson if (val == dup_const(MO_8, val)) { 32424e186175SRichard Henderson vece = MO_8; 32434e186175SRichard Henderson } else if (val == dup_const(MO_16, val)) { 32444e186175SRichard Henderson vece = MO_16; 32450b4286ddSRichard Henderson } else if (val == dup_const(MO_32, val)) { 32464e186175SRichard Henderson vece = MO_32; 32474e186175SRichard Henderson } 32484e186175SRichard Henderson 32494e186175SRichard Henderson tcg_out_dupi_vec(s, ts->type, vece, reg, ts->val); 32500a6a8bc8SRichard Henderson } 325140ae5c62SRichard Henderson ts->mem_coherent = 0; 325240ae5c62SRichard Henderson break; 325340ae5c62SRichard Henderson case TEMP_VAL_MEM: 3254b016486eSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs, 3255b722452aSRichard Henderson preferred_regs, ts->indirect_base); 325640ae5c62SRichard Henderson tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset); 325740ae5c62SRichard Henderson ts->mem_coherent = 1; 325840ae5c62SRichard Henderson break; 325940ae5c62SRichard Henderson case TEMP_VAL_DEAD: 326040ae5c62SRichard Henderson default: 326140ae5c62SRichard Henderson tcg_abort(); 326240ae5c62SRichard Henderson } 326340ae5c62SRichard Henderson ts->reg = reg; 326440ae5c62SRichard Henderson ts->val_type = TEMP_VAL_REG; 326540ae5c62SRichard Henderson s->reg_to_temp[reg] = ts; 326640ae5c62SRichard Henderson } 326740ae5c62SRichard Henderson 326859d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a 3269e8996ee0Sbellard temporary registers needs to be allocated to store a constant. */ 327059d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs) 32711ad80729SAurelien Jarno { 32722c0366f0SAurelien Jarno /* The liveness analysis already ensures that globals are back 3273eabb7b91SAurelien Jarno in memory. Keep an tcg_debug_assert for safety. */ 3274e01fa97dSRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || temp_readonly(ts)); 32751ad80729SAurelien Jarno } 32761ad80729SAurelien Jarno 32779814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be 3278641d5fbeSbellard modified be the following code. 'allocated_regs' is used in case a 3279641d5fbeSbellard temporary registers needs to be allocated to store a constant. */ 3280641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs) 3281641d5fbeSbellard { 3282ac3b8891SRichard Henderson int i, n; 3283641d5fbeSbellard 3284ac3b8891SRichard Henderson for (i = 0, n = s->nb_globals; i < n; i++) { 3285b13eb728SRichard Henderson temp_save(s, &s->temps[i], allocated_regs); 3286641d5fbeSbellard } 3287e5097dc8Sbellard } 3288e5097dc8Sbellard 32893d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be 32903d5c5f87SAurelien Jarno read by the following code. 'allocated_regs' is used in case a 32913d5c5f87SAurelien Jarno temporary registers needs to be allocated to store a constant. */ 32923d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs) 32933d5c5f87SAurelien Jarno { 3294ac3b8891SRichard Henderson int i, n; 32953d5c5f87SAurelien Jarno 3296ac3b8891SRichard Henderson for (i = 0, n = s->nb_globals; i < n; i++) { 329712b9b11aSRichard Henderson TCGTemp *ts = &s->temps[i]; 329812b9b11aSRichard Henderson tcg_debug_assert(ts->val_type != TEMP_VAL_REG 3299ee17db83SRichard Henderson || ts->kind == TEMP_FIXED 330012b9b11aSRichard Henderson || ts->mem_coherent); 33013d5c5f87SAurelien Jarno } 33023d5c5f87SAurelien Jarno } 33033d5c5f87SAurelien Jarno 3304e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and 3305e8996ee0Sbellard all globals are stored at their canonical location. */ 3306e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs) 3307e5097dc8Sbellard { 3308e5097dc8Sbellard int i; 3309e5097dc8Sbellard 3310c896fe29Sbellard for (i = s->nb_globals; i < s->nb_temps; i++) { 3311b13eb728SRichard Henderson TCGTemp *ts = &s->temps[i]; 3312c0522136SRichard Henderson 3313c0522136SRichard Henderson switch (ts->kind) { 3314c0522136SRichard Henderson case TEMP_LOCAL: 3315b13eb728SRichard Henderson temp_save(s, ts, allocated_regs); 3316c0522136SRichard Henderson break; 3317c0522136SRichard Henderson case TEMP_NORMAL: 33182c0366f0SAurelien Jarno /* The liveness analysis already ensures that temps are dead. 3319eabb7b91SAurelien Jarno Keep an tcg_debug_assert for safety. */ 3320eabb7b91SAurelien Jarno tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD); 3321c0522136SRichard Henderson break; 3322c0522136SRichard Henderson case TEMP_CONST: 3323c0522136SRichard Henderson /* Similarly, we should have freed any allocated register. */ 3324c0522136SRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_CONST); 3325c0522136SRichard Henderson break; 3326c0522136SRichard Henderson default: 3327c0522136SRichard Henderson g_assert_not_reached(); 3328c896fe29Sbellard } 3329641d5fbeSbellard } 3330e8996ee0Sbellard 3331e8996ee0Sbellard save_globals(s, allocated_regs); 3332c896fe29Sbellard } 3333c896fe29Sbellard 3334bab1671fSRichard Henderson /* 3335b4cb76e6SRichard Henderson * At a conditional branch, we assume all temporaries are dead and 3336b4cb76e6SRichard Henderson * all globals and local temps are synced to their location. 3337b4cb76e6SRichard Henderson */ 3338b4cb76e6SRichard Henderson static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs) 3339b4cb76e6SRichard Henderson { 3340b4cb76e6SRichard Henderson sync_globals(s, allocated_regs); 3341b4cb76e6SRichard Henderson 3342b4cb76e6SRichard Henderson for (int i = s->nb_globals; i < s->nb_temps; i++) { 3343b4cb76e6SRichard Henderson TCGTemp *ts = &s->temps[i]; 3344b4cb76e6SRichard Henderson /* 3345b4cb76e6SRichard Henderson * The liveness analysis already ensures that temps are dead. 3346b4cb76e6SRichard Henderson * Keep tcg_debug_asserts for safety. 3347b4cb76e6SRichard Henderson */ 3348c0522136SRichard Henderson switch (ts->kind) { 3349c0522136SRichard Henderson case TEMP_LOCAL: 3350b4cb76e6SRichard Henderson tcg_debug_assert(ts->val_type != TEMP_VAL_REG || ts->mem_coherent); 3351c0522136SRichard Henderson break; 3352c0522136SRichard Henderson case TEMP_NORMAL: 3353b4cb76e6SRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD); 3354c0522136SRichard Henderson break; 3355c0522136SRichard Henderson case TEMP_CONST: 3356c0522136SRichard Henderson break; 3357c0522136SRichard Henderson default: 3358c0522136SRichard Henderson g_assert_not_reached(); 3359b4cb76e6SRichard Henderson } 3360b4cb76e6SRichard Henderson } 3361b4cb76e6SRichard Henderson } 3362b4cb76e6SRichard Henderson 3363b4cb76e6SRichard Henderson /* 3364c58f4c97SRichard Henderson * Specialized code generation for INDEX_op_mov_* with a constant. 3365bab1671fSRichard Henderson */ 33660fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots, 3367ba87719cSRichard Henderson tcg_target_ulong val, TCGLifeData arg_life, 3368ba87719cSRichard Henderson TCGRegSet preferred_regs) 3369e8996ee0Sbellard { 3370d63e3b6eSRichard Henderson /* ENV should not be modified. */ 3371e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 337259d7c14eSRichard Henderson 337359d7c14eSRichard Henderson /* The movi is not explicitly generated here. */ 3374f8b2f202SRichard Henderson if (ots->val_type == TEMP_VAL_REG) { 3375f8b2f202SRichard Henderson s->reg_to_temp[ots->reg] = NULL; 3376f8b2f202SRichard Henderson } 3377e8996ee0Sbellard ots->val_type = TEMP_VAL_CONST; 3378e8996ee0Sbellard ots->val = val; 337959d7c14eSRichard Henderson ots->mem_coherent = 0; 3380ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) { 3381ba87719cSRichard Henderson temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0)); 338259d7c14eSRichard Henderson } else if (IS_DEAD_ARG(0)) { 3383f8bf00f1SRichard Henderson temp_dead(s, ots); 33844c4e1ab2SAurelien Jarno } 3385e8996ee0Sbellard } 3386e8996ee0Sbellard 3387bab1671fSRichard Henderson /* 3388bab1671fSRichard Henderson * Specialized code generation for INDEX_op_mov_*. 3389bab1671fSRichard Henderson */ 3390dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op) 3391c896fe29Sbellard { 3392dd186292SRichard Henderson const TCGLifeData arg_life = op->life; 339369e3706dSRichard Henderson TCGRegSet allocated_regs, preferred_regs; 3394c896fe29Sbellard TCGTemp *ts, *ots; 3395450445d5SRichard Henderson TCGType otype, itype; 3396c896fe29Sbellard 3397d21369f5SRichard Henderson allocated_regs = s->reserved_regs; 339869e3706dSRichard Henderson preferred_regs = op->output_pref[0]; 339943439139SRichard Henderson ots = arg_temp(op->args[0]); 340043439139SRichard Henderson ts = arg_temp(op->args[1]); 3401450445d5SRichard Henderson 3402d63e3b6eSRichard Henderson /* ENV should not be modified. */ 3403e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 3404d63e3b6eSRichard Henderson 3405450445d5SRichard Henderson /* Note that otype != itype for no-op truncation. */ 3406450445d5SRichard Henderson otype = ots->type; 3407450445d5SRichard Henderson itype = ts->type; 3408c896fe29Sbellard 34090fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_CONST) { 34100fe4fca4SPaolo Bonzini /* propagate constant or generate sti */ 34110fe4fca4SPaolo Bonzini tcg_target_ulong val = ts->val; 34120fe4fca4SPaolo Bonzini if (IS_DEAD_ARG(1)) { 34130fe4fca4SPaolo Bonzini temp_dead(s, ts); 34140fe4fca4SPaolo Bonzini } 341569e3706dSRichard Henderson tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs); 34160fe4fca4SPaolo Bonzini return; 34170fe4fca4SPaolo Bonzini } 34180fe4fca4SPaolo Bonzini 34190fe4fca4SPaolo Bonzini /* If the source value is in memory we're going to be forced 34200fe4fca4SPaolo Bonzini to have it in a register in order to perform the copy. Copy 34210fe4fca4SPaolo Bonzini the SOURCE value into its own register first, that way we 34220fe4fca4SPaolo Bonzini don't have to reload SOURCE the next time it is used. */ 34230fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_MEM) { 342469e3706dSRichard Henderson temp_load(s, ts, tcg_target_available_regs[itype], 342569e3706dSRichard Henderson allocated_regs, preferred_regs); 3426c29c1d7eSAurelien Jarno } 3427c29c1d7eSAurelien Jarno 34280fe4fca4SPaolo Bonzini tcg_debug_assert(ts->val_type == TEMP_VAL_REG); 3429d63e3b6eSRichard Henderson if (IS_DEAD_ARG(0)) { 3430c29c1d7eSAurelien Jarno /* mov to a non-saved dead register makes no sense (even with 3431c29c1d7eSAurelien Jarno liveness analysis disabled). */ 3432eabb7b91SAurelien Jarno tcg_debug_assert(NEED_SYNC_ARG(0)); 3433c29c1d7eSAurelien Jarno if (!ots->mem_allocated) { 34342272e4a7SRichard Henderson temp_allocate_frame(s, ots); 3435c29c1d7eSAurelien Jarno } 3436b3a62939SRichard Henderson tcg_out_st(s, otype, ts->reg, ots->mem_base->reg, ots->mem_offset); 3437c29c1d7eSAurelien Jarno if (IS_DEAD_ARG(1)) { 3438f8bf00f1SRichard Henderson temp_dead(s, ts); 3439c29c1d7eSAurelien Jarno } 3440f8bf00f1SRichard Henderson temp_dead(s, ots); 3441e8996ee0Sbellard } else { 3442ee17db83SRichard Henderson if (IS_DEAD_ARG(1) && ts->kind != TEMP_FIXED) { 3443c29c1d7eSAurelien Jarno /* the mov can be suppressed */ 3444c29c1d7eSAurelien Jarno if (ots->val_type == TEMP_VAL_REG) { 3445f8b2f202SRichard Henderson s->reg_to_temp[ots->reg] = NULL; 3446c896fe29Sbellard } 3447c29c1d7eSAurelien Jarno ots->reg = ts->reg; 3448f8bf00f1SRichard Henderson temp_dead(s, ts); 3449c29c1d7eSAurelien Jarno } else { 3450c29c1d7eSAurelien Jarno if (ots->val_type != TEMP_VAL_REG) { 3451c29c1d7eSAurelien Jarno /* When allocating a new register, make sure to not spill the 3452c29c1d7eSAurelien Jarno input one. */ 3453c29c1d7eSAurelien Jarno tcg_regset_set_reg(allocated_regs, ts->reg); 3454450445d5SRichard Henderson ots->reg = tcg_reg_alloc(s, tcg_target_available_regs[otype], 345569e3706dSRichard Henderson allocated_regs, preferred_regs, 3456b016486eSRichard Henderson ots->indirect_base); 3457c29c1d7eSAurelien Jarno } 345878113e83SRichard Henderson if (!tcg_out_mov(s, otype, ots->reg, ts->reg)) { 3459240c08d0SRichard Henderson /* 3460240c08d0SRichard Henderson * Cross register class move not supported. 3461240c08d0SRichard Henderson * Store the source register into the destination slot 3462240c08d0SRichard Henderson * and leave the destination temp as TEMP_VAL_MEM. 3463240c08d0SRichard Henderson */ 3464e01fa97dSRichard Henderson assert(!temp_readonly(ots)); 3465240c08d0SRichard Henderson if (!ts->mem_allocated) { 3466240c08d0SRichard Henderson temp_allocate_frame(s, ots); 3467240c08d0SRichard Henderson } 3468240c08d0SRichard Henderson tcg_out_st(s, ts->type, ts->reg, 3469240c08d0SRichard Henderson ots->mem_base->reg, ots->mem_offset); 3470240c08d0SRichard Henderson ots->mem_coherent = 1; 3471240c08d0SRichard Henderson temp_free_or_dead(s, ots, -1); 3472240c08d0SRichard Henderson return; 347378113e83SRichard Henderson } 3474c29c1d7eSAurelien Jarno } 3475c896fe29Sbellard ots->val_type = TEMP_VAL_REG; 3476c896fe29Sbellard ots->mem_coherent = 0; 3477f8b2f202SRichard Henderson s->reg_to_temp[ots->reg] = ots; 3478ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) { 347998b4e186SRichard Henderson temp_sync(s, ots, allocated_regs, 0, 0); 3480c29c1d7eSAurelien Jarno } 3481ec7a869dSAurelien Jarno } 3482c896fe29Sbellard } 3483c896fe29Sbellard 3484bab1671fSRichard Henderson /* 3485bab1671fSRichard Henderson * Specialized code generation for INDEX_op_dup_vec. 3486bab1671fSRichard Henderson */ 3487bab1671fSRichard Henderson static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op) 3488bab1671fSRichard Henderson { 3489bab1671fSRichard Henderson const TCGLifeData arg_life = op->life; 3490bab1671fSRichard Henderson TCGRegSet dup_out_regs, dup_in_regs; 3491bab1671fSRichard Henderson TCGTemp *its, *ots; 3492bab1671fSRichard Henderson TCGType itype, vtype; 3493d6ecb4a9SRichard Henderson intptr_t endian_fixup; 3494bab1671fSRichard Henderson unsigned vece; 3495bab1671fSRichard Henderson bool ok; 3496bab1671fSRichard Henderson 3497bab1671fSRichard Henderson ots = arg_temp(op->args[0]); 3498bab1671fSRichard Henderson its = arg_temp(op->args[1]); 3499bab1671fSRichard Henderson 3500bab1671fSRichard Henderson /* ENV should not be modified. */ 3501e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 3502bab1671fSRichard Henderson 3503bab1671fSRichard Henderson itype = its->type; 3504bab1671fSRichard Henderson vece = TCGOP_VECE(op); 3505bab1671fSRichard Henderson vtype = TCGOP_VECL(op) + TCG_TYPE_V64; 3506bab1671fSRichard Henderson 3507bab1671fSRichard Henderson if (its->val_type == TEMP_VAL_CONST) { 3508bab1671fSRichard Henderson /* Propagate constant via movi -> dupi. */ 3509bab1671fSRichard Henderson tcg_target_ulong val = its->val; 3510bab1671fSRichard Henderson if (IS_DEAD_ARG(1)) { 3511bab1671fSRichard Henderson temp_dead(s, its); 3512bab1671fSRichard Henderson } 3513bab1671fSRichard Henderson tcg_reg_alloc_do_movi(s, ots, val, arg_life, op->output_pref[0]); 3514bab1671fSRichard Henderson return; 3515bab1671fSRichard Henderson } 3516bab1671fSRichard Henderson 35179be0d080SRichard Henderson dup_out_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs; 35189be0d080SRichard Henderson dup_in_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[1].regs; 3519bab1671fSRichard Henderson 3520bab1671fSRichard Henderson /* Allocate the output register now. */ 3521bab1671fSRichard Henderson if (ots->val_type != TEMP_VAL_REG) { 3522bab1671fSRichard Henderson TCGRegSet allocated_regs = s->reserved_regs; 3523bab1671fSRichard Henderson 3524bab1671fSRichard Henderson if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) { 3525bab1671fSRichard Henderson /* Make sure to not spill the input register. */ 3526bab1671fSRichard Henderson tcg_regset_set_reg(allocated_regs, its->reg); 3527bab1671fSRichard Henderson } 3528bab1671fSRichard Henderson ots->reg = tcg_reg_alloc(s, dup_out_regs, allocated_regs, 3529bab1671fSRichard Henderson op->output_pref[0], ots->indirect_base); 3530bab1671fSRichard Henderson ots->val_type = TEMP_VAL_REG; 3531bab1671fSRichard Henderson ots->mem_coherent = 0; 3532bab1671fSRichard Henderson s->reg_to_temp[ots->reg] = ots; 3533bab1671fSRichard Henderson } 3534bab1671fSRichard Henderson 3535bab1671fSRichard Henderson switch (its->val_type) { 3536bab1671fSRichard Henderson case TEMP_VAL_REG: 3537bab1671fSRichard Henderson /* 3538bab1671fSRichard Henderson * The dup constriaints must be broad, covering all possible VECE. 3539bab1671fSRichard Henderson * However, tcg_op_dup_vec() gets to see the VECE and we allow it 3540bab1671fSRichard Henderson * to fail, indicating that extra moves are required for that case. 3541bab1671fSRichard Henderson */ 3542bab1671fSRichard Henderson if (tcg_regset_test_reg(dup_in_regs, its->reg)) { 3543bab1671fSRichard Henderson if (tcg_out_dup_vec(s, vtype, vece, ots->reg, its->reg)) { 3544bab1671fSRichard Henderson goto done; 3545bab1671fSRichard Henderson } 3546bab1671fSRichard Henderson /* Try again from memory or a vector input register. */ 3547bab1671fSRichard Henderson } 3548bab1671fSRichard Henderson if (!its->mem_coherent) { 3549bab1671fSRichard Henderson /* 3550bab1671fSRichard Henderson * The input register is not synced, and so an extra store 3551bab1671fSRichard Henderson * would be required to use memory. Attempt an integer-vector 3552bab1671fSRichard Henderson * register move first. We do not have a TCGRegSet for this. 3553bab1671fSRichard Henderson */ 3554bab1671fSRichard Henderson if (tcg_out_mov(s, itype, ots->reg, its->reg)) { 3555bab1671fSRichard Henderson break; 3556bab1671fSRichard Henderson } 3557bab1671fSRichard Henderson /* Sync the temp back to its slot and load from there. */ 3558bab1671fSRichard Henderson temp_sync(s, its, s->reserved_regs, 0, 0); 3559bab1671fSRichard Henderson } 3560bab1671fSRichard Henderson /* fall through */ 3561bab1671fSRichard Henderson 3562bab1671fSRichard Henderson case TEMP_VAL_MEM: 3563d6ecb4a9SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 3564d6ecb4a9SRichard Henderson endian_fixup = itype == TCG_TYPE_I32 ? 4 : 8; 3565d6ecb4a9SRichard Henderson endian_fixup -= 1 << vece; 3566d6ecb4a9SRichard Henderson #else 3567d6ecb4a9SRichard Henderson endian_fixup = 0; 3568d6ecb4a9SRichard Henderson #endif 3569d6ecb4a9SRichard Henderson if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg, 3570d6ecb4a9SRichard Henderson its->mem_offset + endian_fixup)) { 3571d6ecb4a9SRichard Henderson goto done; 3572d6ecb4a9SRichard Henderson } 3573bab1671fSRichard Henderson tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset); 3574bab1671fSRichard Henderson break; 3575bab1671fSRichard Henderson 3576bab1671fSRichard Henderson default: 3577bab1671fSRichard Henderson g_assert_not_reached(); 3578bab1671fSRichard Henderson } 3579bab1671fSRichard Henderson 3580bab1671fSRichard Henderson /* We now have a vector input register, so dup must succeed. */ 3581bab1671fSRichard Henderson ok = tcg_out_dup_vec(s, vtype, vece, ots->reg, ots->reg); 3582bab1671fSRichard Henderson tcg_debug_assert(ok); 3583bab1671fSRichard Henderson 3584bab1671fSRichard Henderson done: 3585bab1671fSRichard Henderson if (IS_DEAD_ARG(1)) { 3586bab1671fSRichard Henderson temp_dead(s, its); 3587bab1671fSRichard Henderson } 3588bab1671fSRichard Henderson if (NEED_SYNC_ARG(0)) { 3589bab1671fSRichard Henderson temp_sync(s, ots, s->reserved_regs, 0, 0); 3590bab1671fSRichard Henderson } 3591bab1671fSRichard Henderson if (IS_DEAD_ARG(0)) { 3592bab1671fSRichard Henderson temp_dead(s, ots); 3593bab1671fSRichard Henderson } 3594bab1671fSRichard Henderson } 3595bab1671fSRichard Henderson 3596dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) 3597c896fe29Sbellard { 3598dd186292SRichard Henderson const TCGLifeData arg_life = op->life; 3599dd186292SRichard Henderson const TCGOpDef * const def = &tcg_op_defs[op->opc]; 360082790a87SRichard Henderson TCGRegSet i_allocated_regs; 360182790a87SRichard Henderson TCGRegSet o_allocated_regs; 3602b6638662SRichard Henderson int i, k, nb_iargs, nb_oargs; 3603b6638662SRichard Henderson TCGReg reg; 3604c896fe29Sbellard TCGArg arg; 3605c896fe29Sbellard const TCGArgConstraint *arg_ct; 3606c896fe29Sbellard TCGTemp *ts; 3607c896fe29Sbellard TCGArg new_args[TCG_MAX_OP_ARGS]; 3608c896fe29Sbellard int const_args[TCG_MAX_OP_ARGS]; 3609c896fe29Sbellard 3610c896fe29Sbellard nb_oargs = def->nb_oargs; 3611c896fe29Sbellard nb_iargs = def->nb_iargs; 3612c896fe29Sbellard 3613c896fe29Sbellard /* copy constants */ 3614c896fe29Sbellard memcpy(new_args + nb_oargs + nb_iargs, 3615dd186292SRichard Henderson op->args + nb_oargs + nb_iargs, 3616c896fe29Sbellard sizeof(TCGArg) * def->nb_cargs); 3617c896fe29Sbellard 3618d21369f5SRichard Henderson i_allocated_regs = s->reserved_regs; 3619d21369f5SRichard Henderson o_allocated_regs = s->reserved_regs; 362082790a87SRichard Henderson 3621c896fe29Sbellard /* satisfy input constraints */ 3622c896fe29Sbellard for (k = 0; k < nb_iargs; k++) { 3623d62816f2SRichard Henderson TCGRegSet i_preferred_regs, o_preferred_regs; 3624d62816f2SRichard Henderson 362566792f90SRichard Henderson i = def->args_ct[nb_oargs + k].sort_index; 3626dd186292SRichard Henderson arg = op->args[i]; 3627c896fe29Sbellard arg_ct = &def->args_ct[i]; 362843439139SRichard Henderson ts = arg_temp(arg); 362940ae5c62SRichard Henderson 363040ae5c62SRichard Henderson if (ts->val_type == TEMP_VAL_CONST 3631a4fbbd77SRichard Henderson && tcg_target_const_match(ts->val, ts->type, arg_ct->ct)) { 3632c896fe29Sbellard /* constant is OK for instruction */ 3633c896fe29Sbellard const_args[i] = 1; 3634c896fe29Sbellard new_args[i] = ts->val; 3635d62816f2SRichard Henderson continue; 3636c896fe29Sbellard } 363740ae5c62SRichard Henderson 3638d62816f2SRichard Henderson i_preferred_regs = o_preferred_regs = 0; 3639bc2b17e6SRichard Henderson if (arg_ct->ialias) { 3640d62816f2SRichard Henderson o_preferred_regs = op->output_pref[arg_ct->alias_index]; 3641c0522136SRichard Henderson 3642c0522136SRichard Henderson /* 3643c0522136SRichard Henderson * If the input is readonly, then it cannot also be an 3644c0522136SRichard Henderson * output and aliased to itself. If the input is not 3645c0522136SRichard Henderson * dead after the instruction, we must allocate a new 3646c0522136SRichard Henderson * register and move it. 3647c0522136SRichard Henderson */ 3648c0522136SRichard Henderson if (temp_readonly(ts) || !IS_DEAD_ARG(i)) { 3649c896fe29Sbellard goto allocate_in_reg; 3650c896fe29Sbellard } 3651d62816f2SRichard Henderson 3652c0522136SRichard Henderson /* 3653c0522136SRichard Henderson * Check if the current register has already been allocated 3654c0522136SRichard Henderson * for another input aliased to an output. 3655c0522136SRichard Henderson */ 3656d62816f2SRichard Henderson if (ts->val_type == TEMP_VAL_REG) { 3657d62816f2SRichard Henderson reg = ts->reg; 3658c0522136SRichard Henderson for (int k2 = 0; k2 < k; k2++) { 3659c0522136SRichard Henderson int i2 = def->args_ct[nb_oargs + k2].sort_index; 3660bc2b17e6SRichard Henderson if (def->args_ct[i2].ialias && reg == new_args[i2]) { 36617e1df267SAurelien Jarno goto allocate_in_reg; 36627e1df267SAurelien Jarno } 36637e1df267SAurelien Jarno } 36645ff9d6a4Sbellard } 3665d62816f2SRichard Henderson i_preferred_regs = o_preferred_regs; 3666866cb6cbSAurelien Jarno } 3667d62816f2SRichard Henderson 36689be0d080SRichard Henderson temp_load(s, ts, arg_ct->regs, i_allocated_regs, i_preferred_regs); 3669c896fe29Sbellard reg = ts->reg; 3670d62816f2SRichard Henderson 3671c0522136SRichard Henderson if (!tcg_regset_test_reg(arg_ct->regs, reg)) { 3672c896fe29Sbellard allocate_in_reg: 3673c0522136SRichard Henderson /* 3674c0522136SRichard Henderson * Allocate a new register matching the constraint 3675c0522136SRichard Henderson * and move the temporary register into it. 3676c0522136SRichard Henderson */ 3677d62816f2SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 3678d62816f2SRichard Henderson i_allocated_regs, 0); 36799be0d080SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->regs, i_allocated_regs, 3680d62816f2SRichard Henderson o_preferred_regs, ts->indirect_base); 368178113e83SRichard Henderson if (!tcg_out_mov(s, ts->type, reg, ts->reg)) { 3682240c08d0SRichard Henderson /* 3683240c08d0SRichard Henderson * Cross register class move not supported. Sync the 3684240c08d0SRichard Henderson * temp back to its slot and load from there. 3685240c08d0SRichard Henderson */ 3686240c08d0SRichard Henderson temp_sync(s, ts, i_allocated_regs, 0, 0); 3687240c08d0SRichard Henderson tcg_out_ld(s, ts->type, reg, 3688240c08d0SRichard Henderson ts->mem_base->reg, ts->mem_offset); 368978113e83SRichard Henderson } 3690c896fe29Sbellard } 3691c896fe29Sbellard new_args[i] = reg; 3692c896fe29Sbellard const_args[i] = 0; 369382790a87SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg); 3694c896fe29Sbellard } 3695c896fe29Sbellard 3696c896fe29Sbellard /* mark dead temporaries and free the associated registers */ 3697866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 3698866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) { 369943439139SRichard Henderson temp_dead(s, arg_temp(op->args[i])); 3700c896fe29Sbellard } 3701c896fe29Sbellard } 3702c896fe29Sbellard 3703b4cb76e6SRichard Henderson if (def->flags & TCG_OPF_COND_BRANCH) { 3704b4cb76e6SRichard Henderson tcg_reg_alloc_cbranch(s, i_allocated_regs); 3705b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 370682790a87SRichard Henderson tcg_reg_alloc_bb_end(s, i_allocated_regs); 3707a52ad07eSAurelien Jarno } else { 3708c896fe29Sbellard if (def->flags & TCG_OPF_CALL_CLOBBER) { 3709b03cce8eSbellard /* XXX: permit generic clobber register list ? */ 3710c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) { 3711c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { 371282790a87SRichard Henderson tcg_reg_free(s, i, i_allocated_regs); 3713c896fe29Sbellard } 3714c896fe29Sbellard } 37153d5c5f87SAurelien Jarno } 37163d5c5f87SAurelien Jarno if (def->flags & TCG_OPF_SIDE_EFFECTS) { 37173d5c5f87SAurelien Jarno /* sync globals if the op has side effects and might trigger 37183d5c5f87SAurelien Jarno an exception. */ 371982790a87SRichard Henderson sync_globals(s, i_allocated_regs); 3720c896fe29Sbellard } 3721c896fe29Sbellard 3722c896fe29Sbellard /* satisfy the output constraints */ 3723c896fe29Sbellard for(k = 0; k < nb_oargs; k++) { 372466792f90SRichard Henderson i = def->args_ct[k].sort_index; 3725dd186292SRichard Henderson arg = op->args[i]; 3726c896fe29Sbellard arg_ct = &def->args_ct[i]; 372743439139SRichard Henderson ts = arg_temp(arg); 3728d63e3b6eSRichard Henderson 3729d63e3b6eSRichard Henderson /* ENV should not be modified. */ 3730e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ts)); 3731d63e3b6eSRichard Henderson 3732bc2b17e6SRichard Henderson if (arg_ct->oalias && !const_args[arg_ct->alias_index]) { 37335ff9d6a4Sbellard reg = new_args[arg_ct->alias_index]; 3734bc2b17e6SRichard Henderson } else if (arg_ct->newreg) { 37359be0d080SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->regs, 373682790a87SRichard Henderson i_allocated_regs | o_allocated_regs, 373769e3706dSRichard Henderson op->output_pref[k], ts->indirect_base); 3738c896fe29Sbellard } else { 37399be0d080SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs, 374069e3706dSRichard Henderson op->output_pref[k], ts->indirect_base); 3741c896fe29Sbellard } 374282790a87SRichard Henderson tcg_regset_set_reg(o_allocated_regs, reg); 3743639368ddSAurelien Jarno if (ts->val_type == TEMP_VAL_REG) { 3744f8b2f202SRichard Henderson s->reg_to_temp[ts->reg] = NULL; 3745639368ddSAurelien Jarno } 3746c896fe29Sbellard ts->val_type = TEMP_VAL_REG; 3747c896fe29Sbellard ts->reg = reg; 3748d63e3b6eSRichard Henderson /* 3749d63e3b6eSRichard Henderson * Temp value is modified, so the value kept in memory is 3750d63e3b6eSRichard Henderson * potentially not the same. 3751d63e3b6eSRichard Henderson */ 3752c896fe29Sbellard ts->mem_coherent = 0; 3753f8b2f202SRichard Henderson s->reg_to_temp[reg] = ts; 3754c896fe29Sbellard new_args[i] = reg; 3755c896fe29Sbellard } 3756e8996ee0Sbellard } 3757c896fe29Sbellard 3758c896fe29Sbellard /* emit instruction */ 3759d2fd745fSRichard Henderson if (def->flags & TCG_OPF_VECTOR) { 3760d2fd745fSRichard Henderson tcg_out_vec_op(s, op->opc, TCGOP_VECL(op), TCGOP_VECE(op), 3761d2fd745fSRichard Henderson new_args, const_args); 3762d2fd745fSRichard Henderson } else { 3763dd186292SRichard Henderson tcg_out_op(s, op->opc, new_args, const_args); 3764d2fd745fSRichard Henderson } 3765c896fe29Sbellard 3766c896fe29Sbellard /* move the outputs in the correct register if needed */ 3767c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 376843439139SRichard Henderson ts = arg_temp(op->args[i]); 3769d63e3b6eSRichard Henderson 3770d63e3b6eSRichard Henderson /* ENV should not be modified. */ 3771e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ts)); 3772d63e3b6eSRichard Henderson 3773ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) { 377498b4e186SRichard Henderson temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i)); 377559d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) { 3776f8bf00f1SRichard Henderson temp_dead(s, ts); 3777ec7a869dSAurelien Jarno } 3778c896fe29Sbellard } 3779c896fe29Sbellard } 3780c896fe29Sbellard 3781efe86b21SRichard Henderson static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op) 3782efe86b21SRichard Henderson { 3783efe86b21SRichard Henderson const TCGLifeData arg_life = op->life; 3784efe86b21SRichard Henderson TCGTemp *ots, *itsl, *itsh; 3785efe86b21SRichard Henderson TCGType vtype = TCGOP_VECL(op) + TCG_TYPE_V64; 3786efe86b21SRichard Henderson 3787efe86b21SRichard Henderson /* This opcode is only valid for 32-bit hosts, for 64-bit elements. */ 3788efe86b21SRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 32); 3789efe86b21SRichard Henderson tcg_debug_assert(TCGOP_VECE(op) == MO_64); 3790efe86b21SRichard Henderson 3791efe86b21SRichard Henderson ots = arg_temp(op->args[0]); 3792efe86b21SRichard Henderson itsl = arg_temp(op->args[1]); 3793efe86b21SRichard Henderson itsh = arg_temp(op->args[2]); 3794efe86b21SRichard Henderson 3795efe86b21SRichard Henderson /* ENV should not be modified. */ 3796efe86b21SRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 3797efe86b21SRichard Henderson 3798efe86b21SRichard Henderson /* Allocate the output register now. */ 3799efe86b21SRichard Henderson if (ots->val_type != TEMP_VAL_REG) { 3800efe86b21SRichard Henderson TCGRegSet allocated_regs = s->reserved_regs; 3801efe86b21SRichard Henderson TCGRegSet dup_out_regs = 3802efe86b21SRichard Henderson tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs; 3803efe86b21SRichard Henderson 3804efe86b21SRichard Henderson /* Make sure to not spill the input registers. */ 3805efe86b21SRichard Henderson if (!IS_DEAD_ARG(1) && itsl->val_type == TEMP_VAL_REG) { 3806efe86b21SRichard Henderson tcg_regset_set_reg(allocated_regs, itsl->reg); 3807efe86b21SRichard Henderson } 3808efe86b21SRichard Henderson if (!IS_DEAD_ARG(2) && itsh->val_type == TEMP_VAL_REG) { 3809efe86b21SRichard Henderson tcg_regset_set_reg(allocated_regs, itsh->reg); 3810efe86b21SRichard Henderson } 3811efe86b21SRichard Henderson 3812efe86b21SRichard Henderson ots->reg = tcg_reg_alloc(s, dup_out_regs, allocated_regs, 3813efe86b21SRichard Henderson op->output_pref[0], ots->indirect_base); 3814efe86b21SRichard Henderson ots->val_type = TEMP_VAL_REG; 3815efe86b21SRichard Henderson ots->mem_coherent = 0; 3816efe86b21SRichard Henderson s->reg_to_temp[ots->reg] = ots; 3817efe86b21SRichard Henderson } 3818efe86b21SRichard Henderson 3819efe86b21SRichard Henderson /* Promote dup2 of immediates to dupi_vec. */ 3820efe86b21SRichard Henderson if (itsl->val_type == TEMP_VAL_CONST && itsh->val_type == TEMP_VAL_CONST) { 3821efe86b21SRichard Henderson uint64_t val = deposit64(itsl->val, 32, 32, itsh->val); 3822efe86b21SRichard Henderson MemOp vece = MO_64; 3823efe86b21SRichard Henderson 3824efe86b21SRichard Henderson if (val == dup_const(MO_8, val)) { 3825efe86b21SRichard Henderson vece = MO_8; 3826efe86b21SRichard Henderson } else if (val == dup_const(MO_16, val)) { 3827efe86b21SRichard Henderson vece = MO_16; 3828efe86b21SRichard Henderson } else if (val == dup_const(MO_32, val)) { 3829efe86b21SRichard Henderson vece = MO_32; 3830efe86b21SRichard Henderson } 3831efe86b21SRichard Henderson 3832efe86b21SRichard Henderson tcg_out_dupi_vec(s, vtype, vece, ots->reg, val); 3833efe86b21SRichard Henderson goto done; 3834efe86b21SRichard Henderson } 3835efe86b21SRichard Henderson 3836efe86b21SRichard Henderson /* If the two inputs form one 64-bit value, try dupm_vec. */ 3837efe86b21SRichard Henderson if (itsl + 1 == itsh && itsl->base_type == TCG_TYPE_I64) { 3838efe86b21SRichard Henderson if (!itsl->mem_coherent) { 3839efe86b21SRichard Henderson temp_sync(s, itsl, s->reserved_regs, 0, 0); 3840efe86b21SRichard Henderson } 3841efe86b21SRichard Henderson if (!itsh->mem_coherent) { 3842efe86b21SRichard Henderson temp_sync(s, itsh, s->reserved_regs, 0, 0); 3843efe86b21SRichard Henderson } 3844efe86b21SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 3845efe86b21SRichard Henderson TCGTemp *its = itsh; 3846efe86b21SRichard Henderson #else 3847efe86b21SRichard Henderson TCGTemp *its = itsl; 3848efe86b21SRichard Henderson #endif 3849efe86b21SRichard Henderson if (tcg_out_dupm_vec(s, vtype, MO_64, ots->reg, 3850efe86b21SRichard Henderson its->mem_base->reg, its->mem_offset)) { 3851efe86b21SRichard Henderson goto done; 3852efe86b21SRichard Henderson } 3853efe86b21SRichard Henderson } 3854efe86b21SRichard Henderson 3855efe86b21SRichard Henderson /* Fall back to generic expansion. */ 3856efe86b21SRichard Henderson return false; 3857efe86b21SRichard Henderson 3858efe86b21SRichard Henderson done: 3859efe86b21SRichard Henderson if (IS_DEAD_ARG(1)) { 3860efe86b21SRichard Henderson temp_dead(s, itsl); 3861efe86b21SRichard Henderson } 3862efe86b21SRichard Henderson if (IS_DEAD_ARG(2)) { 3863efe86b21SRichard Henderson temp_dead(s, itsh); 3864efe86b21SRichard Henderson } 3865efe86b21SRichard Henderson if (NEED_SYNC_ARG(0)) { 3866efe86b21SRichard Henderson temp_sync(s, ots, s->reserved_regs, 0, IS_DEAD_ARG(0)); 3867efe86b21SRichard Henderson } else if (IS_DEAD_ARG(0)) { 3868efe86b21SRichard Henderson temp_dead(s, ots); 3869efe86b21SRichard Henderson } 3870efe86b21SRichard Henderson return true; 3871efe86b21SRichard Henderson } 3872efe86b21SRichard Henderson 3873b03cce8eSbellard #ifdef TCG_TARGET_STACK_GROWSUP 3874b03cce8eSbellard #define STACK_DIR(x) (-(x)) 3875b03cce8eSbellard #else 3876b03cce8eSbellard #define STACK_DIR(x) (x) 3877b03cce8eSbellard #endif 3878b03cce8eSbellard 3879dd186292SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op) 3880c896fe29Sbellard { 3881cd9090aaSRichard Henderson const int nb_oargs = TCGOP_CALLO(op); 3882cd9090aaSRichard Henderson const int nb_iargs = TCGOP_CALLI(op); 3883dd186292SRichard Henderson const TCGLifeData arg_life = op->life; 38847b7d8b2dSRichard Henderson const TCGHelperInfo *info; 3885b6638662SRichard Henderson int flags, nb_regs, i; 3886b6638662SRichard Henderson TCGReg reg; 3887cf066674SRichard Henderson TCGArg arg; 3888c896fe29Sbellard TCGTemp *ts; 3889d3452f1fSRichard Henderson intptr_t stack_offset; 3890d3452f1fSRichard Henderson size_t call_stack_size; 3891cf066674SRichard Henderson tcg_insn_unit *func_addr; 3892cf066674SRichard Henderson int allocate_args; 3893c896fe29Sbellard TCGRegSet allocated_regs; 3894c896fe29Sbellard 3895fa52e660SRichard Henderson func_addr = tcg_call_func(op); 38967b7d8b2dSRichard Henderson info = tcg_call_info(op); 38977b7d8b2dSRichard Henderson flags = info->flags; 3898c896fe29Sbellard 38996e17d0c5SStefan Weil nb_regs = ARRAY_SIZE(tcg_target_call_iarg_regs); 3900c45cb8bbSRichard Henderson if (nb_regs > nb_iargs) { 3901c45cb8bbSRichard Henderson nb_regs = nb_iargs; 3902cf066674SRichard Henderson } 3903c896fe29Sbellard 3904c896fe29Sbellard /* assign stack slots first */ 3905c45cb8bbSRichard Henderson call_stack_size = (nb_iargs - nb_regs) * sizeof(tcg_target_long); 3906c896fe29Sbellard call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) & 3907c896fe29Sbellard ~(TCG_TARGET_STACK_ALIGN - 1); 3908b03cce8eSbellard allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE); 3909b03cce8eSbellard if (allocate_args) { 3910345649c0SBlue Swirl /* XXX: if more than TCG_STATIC_CALL_ARGS_SIZE is needed, 3911345649c0SBlue Swirl preallocate call stack */ 3912345649c0SBlue Swirl tcg_abort(); 3913b03cce8eSbellard } 391439cf05d3Sbellard 391539cf05d3Sbellard stack_offset = TCG_TARGET_CALL_STACK_OFFSET; 3916c45cb8bbSRichard Henderson for (i = nb_regs; i < nb_iargs; i++) { 3917dd186292SRichard Henderson arg = op->args[nb_oargs + i]; 391839cf05d3Sbellard #ifdef TCG_TARGET_STACK_GROWSUP 391939cf05d3Sbellard stack_offset -= sizeof(tcg_target_long); 392039cf05d3Sbellard #endif 392139cf05d3Sbellard if (arg != TCG_CALL_DUMMY_ARG) { 392243439139SRichard Henderson ts = arg_temp(arg); 392340ae5c62SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 3924b722452aSRichard Henderson s->reserved_regs, 0); 3925e4d5434cSblueswir1 tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset); 392639cf05d3Sbellard } 392739cf05d3Sbellard #ifndef TCG_TARGET_STACK_GROWSUP 392839cf05d3Sbellard stack_offset += sizeof(tcg_target_long); 392939cf05d3Sbellard #endif 3930c896fe29Sbellard } 3931c896fe29Sbellard 3932c896fe29Sbellard /* assign input registers */ 3933d21369f5SRichard Henderson allocated_regs = s->reserved_regs; 3934c896fe29Sbellard for (i = 0; i < nb_regs; i++) { 3935dd186292SRichard Henderson arg = op->args[nb_oargs + i]; 393639cf05d3Sbellard if (arg != TCG_CALL_DUMMY_ARG) { 393743439139SRichard Henderson ts = arg_temp(arg); 3938c896fe29Sbellard reg = tcg_target_call_iarg_regs[i]; 393940ae5c62SRichard Henderson 3940c896fe29Sbellard if (ts->val_type == TEMP_VAL_REG) { 3941c896fe29Sbellard if (ts->reg != reg) { 39424250da10SRichard Henderson tcg_reg_free(s, reg, allocated_regs); 394378113e83SRichard Henderson if (!tcg_out_mov(s, ts->type, reg, ts->reg)) { 3944240c08d0SRichard Henderson /* 3945240c08d0SRichard Henderson * Cross register class move not supported. Sync the 3946240c08d0SRichard Henderson * temp back to its slot and load from there. 3947240c08d0SRichard Henderson */ 3948240c08d0SRichard Henderson temp_sync(s, ts, allocated_regs, 0, 0); 3949240c08d0SRichard Henderson tcg_out_ld(s, ts->type, reg, 3950240c08d0SRichard Henderson ts->mem_base->reg, ts->mem_offset); 395178113e83SRichard Henderson } 3952c896fe29Sbellard } 3953c896fe29Sbellard } else { 3954ccb1bb66SRichard Henderson TCGRegSet arg_set = 0; 395540ae5c62SRichard Henderson 39564250da10SRichard Henderson tcg_reg_free(s, reg, allocated_regs); 395740ae5c62SRichard Henderson tcg_regset_set_reg(arg_set, reg); 3958b722452aSRichard Henderson temp_load(s, ts, arg_set, allocated_regs, 0); 3959c896fe29Sbellard } 396040ae5c62SRichard Henderson 3961c896fe29Sbellard tcg_regset_set_reg(allocated_regs, reg); 3962c896fe29Sbellard } 396339cf05d3Sbellard } 3964c896fe29Sbellard 3965c896fe29Sbellard /* mark dead temporaries and free the associated registers */ 3966866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 3967866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) { 396843439139SRichard Henderson temp_dead(s, arg_temp(op->args[i])); 3969c896fe29Sbellard } 3970c896fe29Sbellard } 3971c896fe29Sbellard 3972c896fe29Sbellard /* clobber call registers */ 3973c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) { 3974c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { 3975b3915dbbSRichard Henderson tcg_reg_free(s, i, allocated_regs); 3976c896fe29Sbellard } 3977c896fe29Sbellard } 3978c896fe29Sbellard 397978505279SAurelien Jarno /* Save globals if they might be written by the helper, sync them if 398078505279SAurelien Jarno they might be read. */ 398178505279SAurelien Jarno if (flags & TCG_CALL_NO_READ_GLOBALS) { 398278505279SAurelien Jarno /* Nothing to do */ 398378505279SAurelien Jarno } else if (flags & TCG_CALL_NO_WRITE_GLOBALS) { 398478505279SAurelien Jarno sync_globals(s, allocated_regs); 398578505279SAurelien Jarno } else { 3986e8996ee0Sbellard save_globals(s, allocated_regs); 3987b9c18f56Saurel32 } 3988c896fe29Sbellard 39897b7d8b2dSRichard Henderson #ifdef CONFIG_TCG_INTERPRETER 39907b7d8b2dSRichard Henderson { 39917b7d8b2dSRichard Henderson gpointer hash = (gpointer)(uintptr_t)info->typemask; 39927b7d8b2dSRichard Henderson ffi_cif *cif = g_hash_table_lookup(ffi_table, hash); 39937b7d8b2dSRichard Henderson assert(cif != NULL); 39947b7d8b2dSRichard Henderson tcg_out_call(s, func_addr, cif); 39957b7d8b2dSRichard Henderson } 39967b7d8b2dSRichard Henderson #else 3997cf066674SRichard Henderson tcg_out_call(s, func_addr); 39987b7d8b2dSRichard Henderson #endif 3999c896fe29Sbellard 4000c896fe29Sbellard /* assign output registers and emit moves if needed */ 4001c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 4002dd186292SRichard Henderson arg = op->args[i]; 400343439139SRichard Henderson ts = arg_temp(arg); 4004d63e3b6eSRichard Henderson 4005d63e3b6eSRichard Henderson /* ENV should not be modified. */ 4006e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ts)); 4007d63e3b6eSRichard Henderson 4008c896fe29Sbellard reg = tcg_target_call_oarg_regs[i]; 4009eabb7b91SAurelien Jarno tcg_debug_assert(s->reg_to_temp[reg] == NULL); 4010639368ddSAurelien Jarno if (ts->val_type == TEMP_VAL_REG) { 4011f8b2f202SRichard Henderson s->reg_to_temp[ts->reg] = NULL; 4012639368ddSAurelien Jarno } 4013c896fe29Sbellard ts->val_type = TEMP_VAL_REG; 4014c896fe29Sbellard ts->reg = reg; 4015c896fe29Sbellard ts->mem_coherent = 0; 4016f8b2f202SRichard Henderson s->reg_to_temp[reg] = ts; 4017ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) { 401898b4e186SRichard Henderson temp_sync(s, ts, allocated_regs, 0, IS_DEAD_ARG(i)); 401959d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) { 4020f8bf00f1SRichard Henderson temp_dead(s, ts); 4021c896fe29Sbellard } 4022c896fe29Sbellard } 40238c11ad25SAurelien Jarno } 4024c896fe29Sbellard 4025c896fe29Sbellard #ifdef CONFIG_PROFILER 4026c896fe29Sbellard 4027c3fac113SEmilio G. Cota /* avoid copy/paste errors */ 4028c3fac113SEmilio G. Cota #define PROF_ADD(to, from, field) \ 4029c3fac113SEmilio G. Cota do { \ 4030d73415a3SStefan Hajnoczi (to)->field += qatomic_read(&((from)->field)); \ 4031c3fac113SEmilio G. Cota } while (0) 4032c896fe29Sbellard 4033c3fac113SEmilio G. Cota #define PROF_MAX(to, from, field) \ 4034c3fac113SEmilio G. Cota do { \ 4035d73415a3SStefan Hajnoczi typeof((from)->field) val__ = qatomic_read(&((from)->field)); \ 4036c3fac113SEmilio G. Cota if (val__ > (to)->field) { \ 4037c3fac113SEmilio G. Cota (to)->field = val__; \ 4038c3fac113SEmilio G. Cota } \ 4039c3fac113SEmilio G. Cota } while (0) 4040c3fac113SEmilio G. Cota 4041c3fac113SEmilio G. Cota /* Pass in a zero'ed @prof */ 4042c3fac113SEmilio G. Cota static inline 4043c3fac113SEmilio G. Cota void tcg_profile_snapshot(TCGProfile *prof, bool counters, bool table) 4044c896fe29Sbellard { 40450e2d61cfSRichard Henderson unsigned int n_ctxs = qatomic_read(&tcg_cur_ctxs); 4046c3fac113SEmilio G. Cota unsigned int i; 4047c3fac113SEmilio G. Cota 40483468b59eSEmilio G. Cota for (i = 0; i < n_ctxs; i++) { 4049d73415a3SStefan Hajnoczi TCGContext *s = qatomic_read(&tcg_ctxs[i]); 40503468b59eSEmilio G. Cota const TCGProfile *orig = &s->prof; 4051c3fac113SEmilio G. Cota 4052c3fac113SEmilio G. Cota if (counters) { 405372fd2efbSEmilio G. Cota PROF_ADD(prof, orig, cpu_exec_time); 4054c3fac113SEmilio G. Cota PROF_ADD(prof, orig, tb_count1); 4055c3fac113SEmilio G. Cota PROF_ADD(prof, orig, tb_count); 4056c3fac113SEmilio G. Cota PROF_ADD(prof, orig, op_count); 4057c3fac113SEmilio G. Cota PROF_MAX(prof, orig, op_count_max); 4058c3fac113SEmilio G. Cota PROF_ADD(prof, orig, temp_count); 4059c3fac113SEmilio G. Cota PROF_MAX(prof, orig, temp_count_max); 4060c3fac113SEmilio G. Cota PROF_ADD(prof, orig, del_op_count); 4061c3fac113SEmilio G. Cota PROF_ADD(prof, orig, code_in_len); 4062c3fac113SEmilio G. Cota PROF_ADD(prof, orig, code_out_len); 4063c3fac113SEmilio G. Cota PROF_ADD(prof, orig, search_out_len); 4064c3fac113SEmilio G. Cota PROF_ADD(prof, orig, interm_time); 4065c3fac113SEmilio G. Cota PROF_ADD(prof, orig, code_time); 4066c3fac113SEmilio G. Cota PROF_ADD(prof, orig, la_time); 4067c3fac113SEmilio G. Cota PROF_ADD(prof, orig, opt_time); 4068c3fac113SEmilio G. Cota PROF_ADD(prof, orig, restore_count); 4069c3fac113SEmilio G. Cota PROF_ADD(prof, orig, restore_time); 4070c3fac113SEmilio G. Cota } 4071c3fac113SEmilio G. Cota if (table) { 4072c896fe29Sbellard int i; 4073d70724ceSzhanghailiang 407415fc7daaSRichard Henderson for (i = 0; i < NB_OPS; i++) { 4075c3fac113SEmilio G. Cota PROF_ADD(prof, orig, table_op_count[i]); 4076c3fac113SEmilio G. Cota } 4077c3fac113SEmilio G. Cota } 4078c3fac113SEmilio G. Cota } 4079c3fac113SEmilio G. Cota } 4080c3fac113SEmilio G. Cota 4081c3fac113SEmilio G. Cota #undef PROF_ADD 4082c3fac113SEmilio G. Cota #undef PROF_MAX 4083c3fac113SEmilio G. Cota 4084c3fac113SEmilio G. Cota static void tcg_profile_snapshot_counters(TCGProfile *prof) 4085c3fac113SEmilio G. Cota { 4086c3fac113SEmilio G. Cota tcg_profile_snapshot(prof, true, false); 4087c3fac113SEmilio G. Cota } 4088c3fac113SEmilio G. Cota 4089c3fac113SEmilio G. Cota static void tcg_profile_snapshot_table(TCGProfile *prof) 4090c3fac113SEmilio G. Cota { 4091c3fac113SEmilio G. Cota tcg_profile_snapshot(prof, false, true); 4092c3fac113SEmilio G. Cota } 4093c3fac113SEmilio G. Cota 4094d4c51a0aSMarkus Armbruster void tcg_dump_op_count(void) 4095c3fac113SEmilio G. Cota { 4096c3fac113SEmilio G. Cota TCGProfile prof = {}; 4097c3fac113SEmilio G. Cota int i; 4098c3fac113SEmilio G. Cota 4099c3fac113SEmilio G. Cota tcg_profile_snapshot_table(&prof); 4100c3fac113SEmilio G. Cota for (i = 0; i < NB_OPS; i++) { 4101d4c51a0aSMarkus Armbruster qemu_printf("%s %" PRId64 "\n", tcg_op_defs[i].name, 4102c3fac113SEmilio G. Cota prof.table_op_count[i]); 4103c896fe29Sbellard } 4104c896fe29Sbellard } 410572fd2efbSEmilio G. Cota 410672fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void) 410772fd2efbSEmilio G. Cota { 41080e2d61cfSRichard Henderson unsigned int n_ctxs = qatomic_read(&tcg_cur_ctxs); 410972fd2efbSEmilio G. Cota unsigned int i; 411072fd2efbSEmilio G. Cota int64_t ret = 0; 411172fd2efbSEmilio G. Cota 411272fd2efbSEmilio G. Cota for (i = 0; i < n_ctxs; i++) { 4113d73415a3SStefan Hajnoczi const TCGContext *s = qatomic_read(&tcg_ctxs[i]); 411472fd2efbSEmilio G. Cota const TCGProfile *prof = &s->prof; 411572fd2efbSEmilio G. Cota 4116d73415a3SStefan Hajnoczi ret += qatomic_read(&prof->cpu_exec_time); 411772fd2efbSEmilio G. Cota } 411872fd2efbSEmilio G. Cota return ret; 411972fd2efbSEmilio G. Cota } 4120246ae24dSMax Filippov #else 4121d4c51a0aSMarkus Armbruster void tcg_dump_op_count(void) 4122246ae24dSMax Filippov { 4123d4c51a0aSMarkus Armbruster qemu_printf("[TCG profiler not compiled]\n"); 4124246ae24dSMax Filippov } 412572fd2efbSEmilio G. Cota 412672fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void) 412772fd2efbSEmilio G. Cota { 412872fd2efbSEmilio G. Cota error_report("%s: TCG profiler not compiled", __func__); 412972fd2efbSEmilio G. Cota exit(EXIT_FAILURE); 413072fd2efbSEmilio G. Cota } 4131c896fe29Sbellard #endif 4132c896fe29Sbellard 4133c896fe29Sbellard 41345bd2ec3dSAlex Bennée int tcg_gen_code(TCGContext *s, TranslationBlock *tb) 4135c896fe29Sbellard { 4136c3fac113SEmilio G. Cota #ifdef CONFIG_PROFILER 4137c3fac113SEmilio G. Cota TCGProfile *prof = &s->prof; 4138c3fac113SEmilio G. Cota #endif 413915fa08f8SRichard Henderson int i, num_insns; 414015fa08f8SRichard Henderson TCGOp *op; 4141c896fe29Sbellard 414204fe6400SRichard Henderson #ifdef CONFIG_PROFILER 414304fe6400SRichard Henderson { 4144c1f543b7SEmilio G. Cota int n = 0; 414504fe6400SRichard Henderson 414615fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 414715fa08f8SRichard Henderson n++; 414815fa08f8SRichard Henderson } 4149d73415a3SStefan Hajnoczi qatomic_set(&prof->op_count, prof->op_count + n); 4150c3fac113SEmilio G. Cota if (n > prof->op_count_max) { 4151d73415a3SStefan Hajnoczi qatomic_set(&prof->op_count_max, n); 415204fe6400SRichard Henderson } 415304fe6400SRichard Henderson 415404fe6400SRichard Henderson n = s->nb_temps; 4155d73415a3SStefan Hajnoczi qatomic_set(&prof->temp_count, prof->temp_count + n); 4156c3fac113SEmilio G. Cota if (n > prof->temp_count_max) { 4157d73415a3SStefan Hajnoczi qatomic_set(&prof->temp_count_max, n); 415804fe6400SRichard Henderson } 415904fe6400SRichard Henderson } 416004fe6400SRichard Henderson #endif 416104fe6400SRichard Henderson 4162c896fe29Sbellard #ifdef DEBUG_DISAS 4163d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP) 4164d977e1c2SAlex Bennée && qemu_log_in_addr_range(tb->pc))) { 4165fc59d2d8SRobert Foley FILE *logfile = qemu_log_lock(); 416693fcfe39Saliguori qemu_log("OP:\n"); 41671894f69aSRichard Henderson tcg_dump_ops(s, false); 416893fcfe39Saliguori qemu_log("\n"); 4169fc59d2d8SRobert Foley qemu_log_unlock(logfile); 4170c896fe29Sbellard } 4171c896fe29Sbellard #endif 4172c896fe29Sbellard 4173bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG 4174bef16ab4SRichard Henderson /* Ensure all labels referenced have been emitted. */ 4175bef16ab4SRichard Henderson { 4176bef16ab4SRichard Henderson TCGLabel *l; 4177bef16ab4SRichard Henderson bool error = false; 4178bef16ab4SRichard Henderson 4179bef16ab4SRichard Henderson QSIMPLEQ_FOREACH(l, &s->labels, next) { 4180bef16ab4SRichard Henderson if (unlikely(!l->present) && l->refs) { 4181bef16ab4SRichard Henderson qemu_log_mask(CPU_LOG_TB_OP, 4182bef16ab4SRichard Henderson "$L%d referenced but not present.\n", l->id); 4183bef16ab4SRichard Henderson error = true; 4184bef16ab4SRichard Henderson } 4185bef16ab4SRichard Henderson } 4186bef16ab4SRichard Henderson assert(!error); 4187bef16ab4SRichard Henderson } 4188bef16ab4SRichard Henderson #endif 4189bef16ab4SRichard Henderson 4190c5cc28ffSAurelien Jarno #ifdef CONFIG_PROFILER 4191d73415a3SStefan Hajnoczi qatomic_set(&prof->opt_time, prof->opt_time - profile_getclock()); 4192c5cc28ffSAurelien Jarno #endif 4193c5cc28ffSAurelien Jarno 41948f2e8c07SKirill Batuzov #ifdef USE_TCG_OPTIMIZATIONS 4195c45cb8bbSRichard Henderson tcg_optimize(s); 41968f2e8c07SKirill Batuzov #endif 41978f2e8c07SKirill Batuzov 4198a23a9ec6Sbellard #ifdef CONFIG_PROFILER 4199d73415a3SStefan Hajnoczi qatomic_set(&prof->opt_time, prof->opt_time + profile_getclock()); 4200d73415a3SStefan Hajnoczi qatomic_set(&prof->la_time, prof->la_time - profile_getclock()); 4201a23a9ec6Sbellard #endif 4202c5cc28ffSAurelien Jarno 4203b4fc67c7SRichard Henderson reachable_code_pass(s); 4204b83eabeaSRichard Henderson liveness_pass_1(s); 42055a18407fSRichard Henderson 42065a18407fSRichard Henderson if (s->nb_indirects > 0) { 42075a18407fSRichard Henderson #ifdef DEBUG_DISAS 42085a18407fSRichard Henderson if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND) 42095a18407fSRichard Henderson && qemu_log_in_addr_range(tb->pc))) { 4210fc59d2d8SRobert Foley FILE *logfile = qemu_log_lock(); 42115a18407fSRichard Henderson qemu_log("OP before indirect lowering:\n"); 42121894f69aSRichard Henderson tcg_dump_ops(s, false); 42135a18407fSRichard Henderson qemu_log("\n"); 4214fc59d2d8SRobert Foley qemu_log_unlock(logfile); 42155a18407fSRichard Henderson } 42165a18407fSRichard Henderson #endif 42175a18407fSRichard Henderson /* Replace indirect temps with direct temps. */ 4218b83eabeaSRichard Henderson if (liveness_pass_2(s)) { 42195a18407fSRichard Henderson /* If changes were made, re-run liveness. */ 4220b83eabeaSRichard Henderson liveness_pass_1(s); 42215a18407fSRichard Henderson } 42225a18407fSRichard Henderson } 4223c5cc28ffSAurelien Jarno 4224a23a9ec6Sbellard #ifdef CONFIG_PROFILER 4225d73415a3SStefan Hajnoczi qatomic_set(&prof->la_time, prof->la_time + profile_getclock()); 4226a23a9ec6Sbellard #endif 4227c896fe29Sbellard 4228c896fe29Sbellard #ifdef DEBUG_DISAS 4229d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT) 4230d977e1c2SAlex Bennée && qemu_log_in_addr_range(tb->pc))) { 4231fc59d2d8SRobert Foley FILE *logfile = qemu_log_lock(); 4232c5cc28ffSAurelien Jarno qemu_log("OP after optimization and liveness analysis:\n"); 42331894f69aSRichard Henderson tcg_dump_ops(s, true); 423493fcfe39Saliguori qemu_log("\n"); 4235fc59d2d8SRobert Foley qemu_log_unlock(logfile); 4236c896fe29Sbellard } 4237c896fe29Sbellard #endif 4238c896fe29Sbellard 4239c896fe29Sbellard tcg_reg_alloc_start(s); 4240c896fe29Sbellard 4241db0c51a3SRichard Henderson /* 4242db0c51a3SRichard Henderson * Reset the buffer pointers when restarting after overflow. 4243db0c51a3SRichard Henderson * TODO: Move this into translate-all.c with the rest of the 4244db0c51a3SRichard Henderson * buffer management. Having only this done here is confusing. 4245db0c51a3SRichard Henderson */ 4246db0c51a3SRichard Henderson s->code_buf = tcg_splitwx_to_rw(tb->tc.ptr); 4247db0c51a3SRichard Henderson s->code_ptr = s->code_buf; 4248c896fe29Sbellard 4249659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS 42506001f772SLaurent Vivier QSIMPLEQ_INIT(&s->ldst_labels); 4251659ef5cbSRichard Henderson #endif 425257a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 425357a26946SRichard Henderson s->pool_labels = NULL; 425457a26946SRichard Henderson #endif 42559ecefc84SRichard Henderson 4256fca8a500SRichard Henderson num_insns = -1; 425715fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 4258c45cb8bbSRichard Henderson TCGOpcode opc = op->opc; 4259b3db8758Sblueswir1 4260c896fe29Sbellard #ifdef CONFIG_PROFILER 4261d73415a3SStefan Hajnoczi qatomic_set(&prof->table_op_count[opc], prof->table_op_count[opc] + 1); 4262c896fe29Sbellard #endif 4263c45cb8bbSRichard Henderson 4264c896fe29Sbellard switch (opc) { 4265c896fe29Sbellard case INDEX_op_mov_i32: 4266c896fe29Sbellard case INDEX_op_mov_i64: 4267d2fd745fSRichard Henderson case INDEX_op_mov_vec: 4268dd186292SRichard Henderson tcg_reg_alloc_mov(s, op); 4269c896fe29Sbellard break; 4270bab1671fSRichard Henderson case INDEX_op_dup_vec: 4271bab1671fSRichard Henderson tcg_reg_alloc_dup(s, op); 4272bab1671fSRichard Henderson break; 4273765b842aSRichard Henderson case INDEX_op_insn_start: 4274fca8a500SRichard Henderson if (num_insns >= 0) { 42759f754620SRichard Henderson size_t off = tcg_current_code_size(s); 42769f754620SRichard Henderson s->gen_insn_end_off[num_insns] = off; 42779f754620SRichard Henderson /* Assert that we do not overflow our stored offset. */ 42789f754620SRichard Henderson assert(s->gen_insn_end_off[num_insns] == off); 4279fca8a500SRichard Henderson } 4280fca8a500SRichard Henderson num_insns++; 4281bad729e2SRichard Henderson for (i = 0; i < TARGET_INSN_START_WORDS; ++i) { 4282bad729e2SRichard Henderson target_ulong a; 4283bad729e2SRichard Henderson #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS 4284efee3746SRichard Henderson a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]); 4285bad729e2SRichard Henderson #else 4286efee3746SRichard Henderson a = op->args[i]; 4287bad729e2SRichard Henderson #endif 4288fca8a500SRichard Henderson s->gen_insn_data[num_insns][i] = a; 4289bad729e2SRichard Henderson } 4290c896fe29Sbellard break; 42915ff9d6a4Sbellard case INDEX_op_discard: 429243439139SRichard Henderson temp_dead(s, arg_temp(op->args[0])); 42935ff9d6a4Sbellard break; 4294c896fe29Sbellard case INDEX_op_set_label: 4295e8996ee0Sbellard tcg_reg_alloc_bb_end(s, s->reserved_regs); 429692ab8e7dSRichard Henderson tcg_out_label(s, arg_label(op->args[0])); 4297c896fe29Sbellard break; 4298c896fe29Sbellard case INDEX_op_call: 4299dd186292SRichard Henderson tcg_reg_alloc_call(s, op); 4300c45cb8bbSRichard Henderson break; 4301efe86b21SRichard Henderson case INDEX_op_dup2_vec: 4302efe86b21SRichard Henderson if (tcg_reg_alloc_dup2(s, op)) { 4303efe86b21SRichard Henderson break; 4304efe86b21SRichard Henderson } 4305efe86b21SRichard Henderson /* fall through */ 4306c896fe29Sbellard default: 430725c4d9ccSRichard Henderson /* Sanity check that we've not introduced any unhandled opcodes. */ 4308be0f34b5SRichard Henderson tcg_debug_assert(tcg_op_supported(opc)); 4309c896fe29Sbellard /* Note: in order to speed up the code, it would be much 4310c896fe29Sbellard faster to have specialized register allocator functions for 4311c896fe29Sbellard some common argument patterns */ 4312dd186292SRichard Henderson tcg_reg_alloc_op(s, op); 4313c896fe29Sbellard break; 4314c896fe29Sbellard } 43158d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG 4316c896fe29Sbellard check_regs(s); 4317c896fe29Sbellard #endif 4318b125f9dcSRichard Henderson /* Test for (pending) buffer overflow. The assumption is that any 4319b125f9dcSRichard Henderson one operation beginning below the high water mark cannot overrun 4320b125f9dcSRichard Henderson the buffer completely. Thus we can test for overflow after 4321b125f9dcSRichard Henderson generating code without having to check during generation. */ 4322644da9b3SJohn Clarke if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) { 4323b125f9dcSRichard Henderson return -1; 4324b125f9dcSRichard Henderson } 43256e6c4efeSRichard Henderson /* Test for TB overflow, as seen by gen_insn_end_off. */ 43266e6c4efeSRichard Henderson if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) { 43276e6c4efeSRichard Henderson return -2; 43286e6c4efeSRichard Henderson } 4329c896fe29Sbellard } 4330fca8a500SRichard Henderson tcg_debug_assert(num_insns >= 0); 4331fca8a500SRichard Henderson s->gen_insn_end_off[num_insns] = tcg_current_code_size(s); 4332c45cb8bbSRichard Henderson 4333b76f0d8cSYeongkyoon Lee /* Generate TB finalization at the end of block */ 4334659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS 4335aeee05f5SRichard Henderson i = tcg_out_ldst_finalize(s); 4336aeee05f5SRichard Henderson if (i < 0) { 4337aeee05f5SRichard Henderson return i; 433823dceda6SRichard Henderson } 4339659ef5cbSRichard Henderson #endif 434057a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 43411768987bSRichard Henderson i = tcg_out_pool_finalize(s); 43421768987bSRichard Henderson if (i < 0) { 43431768987bSRichard Henderson return i; 434457a26946SRichard Henderson } 434557a26946SRichard Henderson #endif 43467ecd02a0SRichard Henderson if (!tcg_resolve_relocs(s)) { 43477ecd02a0SRichard Henderson return -2; 43487ecd02a0SRichard Henderson } 4349c896fe29Sbellard 4350df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 4351c896fe29Sbellard /* flush instruction cache */ 4352db0c51a3SRichard Henderson flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf), 4353db0c51a3SRichard Henderson (uintptr_t)s->code_buf, 43541da8de39SRichard Henderson tcg_ptr_byte_diff(s->code_ptr, s->code_buf)); 4355df5d2b16SRichard Henderson #endif 43562aeabc08SStefan Weil 43571813e175SRichard Henderson return tcg_current_code_size(s); 4358c896fe29Sbellard } 4359c896fe29Sbellard 4360a23a9ec6Sbellard #ifdef CONFIG_PROFILER 43613de2faa9SMarkus Armbruster void tcg_dump_info(void) 4362a23a9ec6Sbellard { 4363c3fac113SEmilio G. Cota TCGProfile prof = {}; 4364c3fac113SEmilio G. Cota const TCGProfile *s; 4365c3fac113SEmilio G. Cota int64_t tb_count; 4366c3fac113SEmilio G. Cota int64_t tb_div_count; 4367c3fac113SEmilio G. Cota int64_t tot; 4368c3fac113SEmilio G. Cota 4369c3fac113SEmilio G. Cota tcg_profile_snapshot_counters(&prof); 4370c3fac113SEmilio G. Cota s = &prof; 4371c3fac113SEmilio G. Cota tb_count = s->tb_count; 4372c3fac113SEmilio G. Cota tb_div_count = tb_count ? tb_count : 1; 4373c3fac113SEmilio G. Cota tot = s->interm_time + s->code_time; 4374a23a9ec6Sbellard 43753de2faa9SMarkus Armbruster qemu_printf("JIT cycles %" PRId64 " (%0.3f s at 2.4 GHz)\n", 4376a23a9ec6Sbellard tot, tot / 2.4e9); 43773de2faa9SMarkus Armbruster qemu_printf("translated TBs %" PRId64 " (aborted=%" PRId64 43783de2faa9SMarkus Armbruster " %0.1f%%)\n", 4379fca8a500SRichard Henderson tb_count, s->tb_count1 - tb_count, 4380fca8a500SRichard Henderson (double)(s->tb_count1 - s->tb_count) 4381fca8a500SRichard Henderson / (s->tb_count1 ? s->tb_count1 : 1) * 100.0); 43823de2faa9SMarkus Armbruster qemu_printf("avg ops/TB %0.1f max=%d\n", 4383fca8a500SRichard Henderson (double)s->op_count / tb_div_count, s->op_count_max); 43843de2faa9SMarkus Armbruster qemu_printf("deleted ops/TB %0.2f\n", 4385fca8a500SRichard Henderson (double)s->del_op_count / tb_div_count); 43863de2faa9SMarkus Armbruster qemu_printf("avg temps/TB %0.2f max=%d\n", 4387fca8a500SRichard Henderson (double)s->temp_count / tb_div_count, s->temp_count_max); 43883de2faa9SMarkus Armbruster qemu_printf("avg host code/TB %0.1f\n", 4389fca8a500SRichard Henderson (double)s->code_out_len / tb_div_count); 43903de2faa9SMarkus Armbruster qemu_printf("avg search data/TB %0.1f\n", 4391fca8a500SRichard Henderson (double)s->search_out_len / tb_div_count); 4392a23a9ec6Sbellard 43933de2faa9SMarkus Armbruster qemu_printf("cycles/op %0.1f\n", 4394a23a9ec6Sbellard s->op_count ? (double)tot / s->op_count : 0); 43953de2faa9SMarkus Armbruster qemu_printf("cycles/in byte %0.1f\n", 4396a23a9ec6Sbellard s->code_in_len ? (double)tot / s->code_in_len : 0); 43973de2faa9SMarkus Armbruster qemu_printf("cycles/out byte %0.1f\n", 4398a23a9ec6Sbellard s->code_out_len ? (double)tot / s->code_out_len : 0); 43993de2faa9SMarkus Armbruster qemu_printf("cycles/search byte %0.1f\n", 4400fca8a500SRichard Henderson s->search_out_len ? (double)tot / s->search_out_len : 0); 4401fca8a500SRichard Henderson if (tot == 0) { 4402a23a9ec6Sbellard tot = 1; 4403fca8a500SRichard Henderson } 44043de2faa9SMarkus Armbruster qemu_printf(" gen_interm time %0.1f%%\n", 4405a23a9ec6Sbellard (double)s->interm_time / tot * 100.0); 44063de2faa9SMarkus Armbruster qemu_printf(" gen_code time %0.1f%%\n", 4407a23a9ec6Sbellard (double)s->code_time / tot * 100.0); 44083de2faa9SMarkus Armbruster qemu_printf("optim./code time %0.1f%%\n", 4409c5cc28ffSAurelien Jarno (double)s->opt_time / (s->code_time ? s->code_time : 1) 4410c5cc28ffSAurelien Jarno * 100.0); 44113de2faa9SMarkus Armbruster qemu_printf("liveness/code time %0.1f%%\n", 4412a23a9ec6Sbellard (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0); 44133de2faa9SMarkus Armbruster qemu_printf("cpu_restore count %" PRId64 "\n", 4414a23a9ec6Sbellard s->restore_count); 44153de2faa9SMarkus Armbruster qemu_printf(" avg cycles %0.1f\n", 4416a23a9ec6Sbellard s->restore_count ? (double)s->restore_time / s->restore_count : 0); 4417a23a9ec6Sbellard } 4418a23a9ec6Sbellard #else 44193de2faa9SMarkus Armbruster void tcg_dump_info(void) 4420a23a9ec6Sbellard { 44213de2faa9SMarkus Armbruster qemu_printf("[TCG profiler not compiled]\n"); 4422a23a9ec6Sbellard } 4423a23a9ec6Sbellard #endif 4424813da627SRichard Henderson 4425813da627SRichard Henderson #ifdef ELF_HOST_MACHINE 44265872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things: 44275872bbf2SRichard Henderson 44285872bbf2SRichard Henderson (1) Define ELF_HOST_MACHINE to indicate both what value to 44295872bbf2SRichard Henderson put into the ELF image and to indicate support for the feature. 44305872bbf2SRichard Henderson 44315872bbf2SRichard Henderson (2) Define tcg_register_jit. This should create a buffer containing 44325872bbf2SRichard Henderson the contents of a .debug_frame section that describes the post- 44335872bbf2SRichard Henderson prologue unwind info for the tcg machine. 44345872bbf2SRichard Henderson 44355872bbf2SRichard Henderson (3) Call tcg_register_jit_int, with the constructed .debug_frame. 44365872bbf2SRichard Henderson */ 4437813da627SRichard Henderson 4438813da627SRichard Henderson /* Begin GDB interface. THE FOLLOWING MUST MATCH GDB DOCS. */ 4439813da627SRichard Henderson typedef enum { 4440813da627SRichard Henderson JIT_NOACTION = 0, 4441813da627SRichard Henderson JIT_REGISTER_FN, 4442813da627SRichard Henderson JIT_UNREGISTER_FN 4443813da627SRichard Henderson } jit_actions_t; 4444813da627SRichard Henderson 4445813da627SRichard Henderson struct jit_code_entry { 4446813da627SRichard Henderson struct jit_code_entry *next_entry; 4447813da627SRichard Henderson struct jit_code_entry *prev_entry; 4448813da627SRichard Henderson const void *symfile_addr; 4449813da627SRichard Henderson uint64_t symfile_size; 4450813da627SRichard Henderson }; 4451813da627SRichard Henderson 4452813da627SRichard Henderson struct jit_descriptor { 4453813da627SRichard Henderson uint32_t version; 4454813da627SRichard Henderson uint32_t action_flag; 4455813da627SRichard Henderson struct jit_code_entry *relevant_entry; 4456813da627SRichard Henderson struct jit_code_entry *first_entry; 4457813da627SRichard Henderson }; 4458813da627SRichard Henderson 4459813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline)); 4460813da627SRichard Henderson void __jit_debug_register_code(void) 4461813da627SRichard Henderson { 4462813da627SRichard Henderson asm(""); 4463813da627SRichard Henderson } 4464813da627SRichard Henderson 4465813da627SRichard Henderson /* Must statically initialize the version, because GDB may check 4466813da627SRichard Henderson the version before we can set it. */ 4467813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 }; 4468813da627SRichard Henderson 4469813da627SRichard Henderson /* End GDB interface. */ 4470813da627SRichard Henderson 4471813da627SRichard Henderson static int find_string(const char *strtab, const char *str) 4472813da627SRichard Henderson { 4473813da627SRichard Henderson const char *p = strtab + 1; 4474813da627SRichard Henderson 4475813da627SRichard Henderson while (1) { 4476813da627SRichard Henderson if (strcmp(p, str) == 0) { 4477813da627SRichard Henderson return p - strtab; 4478813da627SRichard Henderson } 4479813da627SRichard Henderson p += strlen(p) + 1; 4480813da627SRichard Henderson } 4481813da627SRichard Henderson } 4482813da627SRichard Henderson 4483755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf_ptr, size_t buf_size, 44842c90784aSRichard Henderson const void *debug_frame, 44852c90784aSRichard Henderson size_t debug_frame_size) 4486813da627SRichard Henderson { 44875872bbf2SRichard Henderson struct __attribute__((packed)) DebugInfo { 44885872bbf2SRichard Henderson uint32_t len; 44895872bbf2SRichard Henderson uint16_t version; 44905872bbf2SRichard Henderson uint32_t abbrev; 44915872bbf2SRichard Henderson uint8_t ptr_size; 44925872bbf2SRichard Henderson uint8_t cu_die; 44935872bbf2SRichard Henderson uint16_t cu_lang; 44945872bbf2SRichard Henderson uintptr_t cu_low_pc; 44955872bbf2SRichard Henderson uintptr_t cu_high_pc; 44965872bbf2SRichard Henderson uint8_t fn_die; 44975872bbf2SRichard Henderson char fn_name[16]; 44985872bbf2SRichard Henderson uintptr_t fn_low_pc; 44995872bbf2SRichard Henderson uintptr_t fn_high_pc; 45005872bbf2SRichard Henderson uint8_t cu_eoc; 45015872bbf2SRichard Henderson }; 4502813da627SRichard Henderson 4503813da627SRichard Henderson struct ElfImage { 4504813da627SRichard Henderson ElfW(Ehdr) ehdr; 4505813da627SRichard Henderson ElfW(Phdr) phdr; 45065872bbf2SRichard Henderson ElfW(Shdr) shdr[7]; 45075872bbf2SRichard Henderson ElfW(Sym) sym[2]; 45085872bbf2SRichard Henderson struct DebugInfo di; 45095872bbf2SRichard Henderson uint8_t da[24]; 45105872bbf2SRichard Henderson char str[80]; 45115872bbf2SRichard Henderson }; 45125872bbf2SRichard Henderson 45135872bbf2SRichard Henderson struct ElfImage *img; 45145872bbf2SRichard Henderson 45155872bbf2SRichard Henderson static const struct ElfImage img_template = { 45165872bbf2SRichard Henderson .ehdr = { 45175872bbf2SRichard Henderson .e_ident[EI_MAG0] = ELFMAG0, 45185872bbf2SRichard Henderson .e_ident[EI_MAG1] = ELFMAG1, 45195872bbf2SRichard Henderson .e_ident[EI_MAG2] = ELFMAG2, 45205872bbf2SRichard Henderson .e_ident[EI_MAG3] = ELFMAG3, 45215872bbf2SRichard Henderson .e_ident[EI_CLASS] = ELF_CLASS, 45225872bbf2SRichard Henderson .e_ident[EI_DATA] = ELF_DATA, 45235872bbf2SRichard Henderson .e_ident[EI_VERSION] = EV_CURRENT, 45245872bbf2SRichard Henderson .e_type = ET_EXEC, 45255872bbf2SRichard Henderson .e_machine = ELF_HOST_MACHINE, 45265872bbf2SRichard Henderson .e_version = EV_CURRENT, 45275872bbf2SRichard Henderson .e_phoff = offsetof(struct ElfImage, phdr), 45285872bbf2SRichard Henderson .e_shoff = offsetof(struct ElfImage, shdr), 45295872bbf2SRichard Henderson .e_ehsize = sizeof(ElfW(Shdr)), 45305872bbf2SRichard Henderson .e_phentsize = sizeof(ElfW(Phdr)), 45315872bbf2SRichard Henderson .e_phnum = 1, 45325872bbf2SRichard Henderson .e_shentsize = sizeof(ElfW(Shdr)), 45335872bbf2SRichard Henderson .e_shnum = ARRAY_SIZE(img->shdr), 45345872bbf2SRichard Henderson .e_shstrndx = ARRAY_SIZE(img->shdr) - 1, 4535abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS 4536abbb3eaeSRichard Henderson .e_flags = ELF_HOST_FLAGS, 4537abbb3eaeSRichard Henderson #endif 4538abbb3eaeSRichard Henderson #ifdef ELF_OSABI 4539abbb3eaeSRichard Henderson .e_ident[EI_OSABI] = ELF_OSABI, 4540abbb3eaeSRichard Henderson #endif 45415872bbf2SRichard Henderson }, 45425872bbf2SRichard Henderson .phdr = { 45435872bbf2SRichard Henderson .p_type = PT_LOAD, 45445872bbf2SRichard Henderson .p_flags = PF_X, 45455872bbf2SRichard Henderson }, 45465872bbf2SRichard Henderson .shdr = { 45475872bbf2SRichard Henderson [0] = { .sh_type = SHT_NULL }, 45485872bbf2SRichard Henderson /* Trick: The contents of code_gen_buffer are not present in 45495872bbf2SRichard Henderson this fake ELF file; that got allocated elsewhere. Therefore 45505872bbf2SRichard Henderson we mark .text as SHT_NOBITS (similar to .bss) so that readers 45515872bbf2SRichard Henderson will not look for contents. We can record any address. */ 45525872bbf2SRichard Henderson [1] = { /* .text */ 45535872bbf2SRichard Henderson .sh_type = SHT_NOBITS, 45545872bbf2SRichard Henderson .sh_flags = SHF_EXECINSTR | SHF_ALLOC, 45555872bbf2SRichard Henderson }, 45565872bbf2SRichard Henderson [2] = { /* .debug_info */ 45575872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 45585872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, di), 45595872bbf2SRichard Henderson .sh_size = sizeof(struct DebugInfo), 45605872bbf2SRichard Henderson }, 45615872bbf2SRichard Henderson [3] = { /* .debug_abbrev */ 45625872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 45635872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, da), 45645872bbf2SRichard Henderson .sh_size = sizeof(img->da), 45655872bbf2SRichard Henderson }, 45665872bbf2SRichard Henderson [4] = { /* .debug_frame */ 45675872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 45685872bbf2SRichard Henderson .sh_offset = sizeof(struct ElfImage), 45695872bbf2SRichard Henderson }, 45705872bbf2SRichard Henderson [5] = { /* .symtab */ 45715872bbf2SRichard Henderson .sh_type = SHT_SYMTAB, 45725872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, sym), 45735872bbf2SRichard Henderson .sh_size = sizeof(img->sym), 45745872bbf2SRichard Henderson .sh_info = 1, 45755872bbf2SRichard Henderson .sh_link = ARRAY_SIZE(img->shdr) - 1, 45765872bbf2SRichard Henderson .sh_entsize = sizeof(ElfW(Sym)), 45775872bbf2SRichard Henderson }, 45785872bbf2SRichard Henderson [6] = { /* .strtab */ 45795872bbf2SRichard Henderson .sh_type = SHT_STRTAB, 45805872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, str), 45815872bbf2SRichard Henderson .sh_size = sizeof(img->str), 45825872bbf2SRichard Henderson } 45835872bbf2SRichard Henderson }, 45845872bbf2SRichard Henderson .sym = { 45855872bbf2SRichard Henderson [1] = { /* code_gen_buffer */ 45865872bbf2SRichard Henderson .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC), 45875872bbf2SRichard Henderson .st_shndx = 1, 45885872bbf2SRichard Henderson } 45895872bbf2SRichard Henderson }, 45905872bbf2SRichard Henderson .di = { 45915872bbf2SRichard Henderson .len = sizeof(struct DebugInfo) - 4, 45925872bbf2SRichard Henderson .version = 2, 45935872bbf2SRichard Henderson .ptr_size = sizeof(void *), 45945872bbf2SRichard Henderson .cu_die = 1, 45955872bbf2SRichard Henderson .cu_lang = 0x8001, /* DW_LANG_Mips_Assembler */ 45965872bbf2SRichard Henderson .fn_die = 2, 45975872bbf2SRichard Henderson .fn_name = "code_gen_buffer" 45985872bbf2SRichard Henderson }, 45995872bbf2SRichard Henderson .da = { 46005872bbf2SRichard Henderson 1, /* abbrev number (the cu) */ 46015872bbf2SRichard Henderson 0x11, 1, /* DW_TAG_compile_unit, has children */ 46025872bbf2SRichard Henderson 0x13, 0x5, /* DW_AT_language, DW_FORM_data2 */ 46035872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */ 46045872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */ 46055872bbf2SRichard Henderson 0, 0, /* end of abbrev */ 46065872bbf2SRichard Henderson 2, /* abbrev number (the fn) */ 46075872bbf2SRichard Henderson 0x2e, 0, /* DW_TAG_subprogram, no children */ 46085872bbf2SRichard Henderson 0x3, 0x8, /* DW_AT_name, DW_FORM_string */ 46095872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */ 46105872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */ 46115872bbf2SRichard Henderson 0, 0, /* end of abbrev */ 46125872bbf2SRichard Henderson 0 /* no more abbrev */ 46135872bbf2SRichard Henderson }, 46145872bbf2SRichard Henderson .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0" 46155872bbf2SRichard Henderson ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer", 4616813da627SRichard Henderson }; 4617813da627SRichard Henderson 4618813da627SRichard Henderson /* We only need a single jit entry; statically allocate it. */ 4619813da627SRichard Henderson static struct jit_code_entry one_entry; 4620813da627SRichard Henderson 46215872bbf2SRichard Henderson uintptr_t buf = (uintptr_t)buf_ptr; 4622813da627SRichard Henderson size_t img_size = sizeof(struct ElfImage) + debug_frame_size; 46232c90784aSRichard Henderson DebugFrameHeader *dfh; 4624813da627SRichard Henderson 46255872bbf2SRichard Henderson img = g_malloc(img_size); 46265872bbf2SRichard Henderson *img = img_template; 4627813da627SRichard Henderson 46285872bbf2SRichard Henderson img->phdr.p_vaddr = buf; 46295872bbf2SRichard Henderson img->phdr.p_paddr = buf; 46305872bbf2SRichard Henderson img->phdr.p_memsz = buf_size; 4631813da627SRichard Henderson 46325872bbf2SRichard Henderson img->shdr[1].sh_name = find_string(img->str, ".text"); 46335872bbf2SRichard Henderson img->shdr[1].sh_addr = buf; 46345872bbf2SRichard Henderson img->shdr[1].sh_size = buf_size; 4635813da627SRichard Henderson 46365872bbf2SRichard Henderson img->shdr[2].sh_name = find_string(img->str, ".debug_info"); 46375872bbf2SRichard Henderson img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev"); 46385872bbf2SRichard Henderson 46395872bbf2SRichard Henderson img->shdr[4].sh_name = find_string(img->str, ".debug_frame"); 46405872bbf2SRichard Henderson img->shdr[4].sh_size = debug_frame_size; 46415872bbf2SRichard Henderson 46425872bbf2SRichard Henderson img->shdr[5].sh_name = find_string(img->str, ".symtab"); 46435872bbf2SRichard Henderson img->shdr[6].sh_name = find_string(img->str, ".strtab"); 46445872bbf2SRichard Henderson 46455872bbf2SRichard Henderson img->sym[1].st_name = find_string(img->str, "code_gen_buffer"); 46465872bbf2SRichard Henderson img->sym[1].st_value = buf; 46475872bbf2SRichard Henderson img->sym[1].st_size = buf_size; 46485872bbf2SRichard Henderson 46495872bbf2SRichard Henderson img->di.cu_low_pc = buf; 465045aba097SRichard Henderson img->di.cu_high_pc = buf + buf_size; 46515872bbf2SRichard Henderson img->di.fn_low_pc = buf; 465245aba097SRichard Henderson img->di.fn_high_pc = buf + buf_size; 4653813da627SRichard Henderson 46542c90784aSRichard Henderson dfh = (DebugFrameHeader *)(img + 1); 46552c90784aSRichard Henderson memcpy(dfh, debug_frame, debug_frame_size); 46562c90784aSRichard Henderson dfh->fde.func_start = buf; 46572c90784aSRichard Henderson dfh->fde.func_len = buf_size; 46582c90784aSRichard Henderson 4659813da627SRichard Henderson #ifdef DEBUG_JIT 4660813da627SRichard Henderson /* Enable this block to be able to debug the ELF image file creation. 4661813da627SRichard Henderson One can use readelf, objdump, or other inspection utilities. */ 4662813da627SRichard Henderson { 4663813da627SRichard Henderson FILE *f = fopen("/tmp/qemu.jit", "w+b"); 4664813da627SRichard Henderson if (f) { 46655872bbf2SRichard Henderson if (fwrite(img, img_size, 1, f) != img_size) { 4666813da627SRichard Henderson /* Avoid stupid unused return value warning for fwrite. */ 4667813da627SRichard Henderson } 4668813da627SRichard Henderson fclose(f); 4669813da627SRichard Henderson } 4670813da627SRichard Henderson } 4671813da627SRichard Henderson #endif 4672813da627SRichard Henderson 4673813da627SRichard Henderson one_entry.symfile_addr = img; 4674813da627SRichard Henderson one_entry.symfile_size = img_size; 4675813da627SRichard Henderson 4676813da627SRichard Henderson __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; 4677813da627SRichard Henderson __jit_debug_descriptor.relevant_entry = &one_entry; 4678813da627SRichard Henderson __jit_debug_descriptor.first_entry = &one_entry; 4679813da627SRichard Henderson __jit_debug_register_code(); 4680813da627SRichard Henderson } 4681813da627SRichard Henderson #else 46825872bbf2SRichard Henderson /* No support for the feature. Provide the entry point expected by exec.c, 46835872bbf2SRichard Henderson and implement the internal function we declared earlier. */ 4684813da627SRichard Henderson 4685755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size, 46862c90784aSRichard Henderson const void *debug_frame, 46872c90784aSRichard Henderson size_t debug_frame_size) 4688813da627SRichard Henderson { 4689813da627SRichard Henderson } 4690813da627SRichard Henderson 4691755bf9e5SRichard Henderson void tcg_register_jit(const void *buf, size_t buf_size) 4692813da627SRichard Henderson { 4693813da627SRichard Henderson } 4694813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */ 4695db432672SRichard Henderson 4696db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec 4697db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...) 4698db432672SRichard Henderson { 4699db432672SRichard Henderson g_assert_not_reached(); 4700db432672SRichard Henderson } 4701db432672SRichard Henderson #endif 4702