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 #include "cpu.h" 45c896fe29Sbellard 4663c91552SPaolo Bonzini #include "exec/exec-all.h" 4763c91552SPaolo Bonzini 485cc8767dSLike Xu #if !defined(CONFIG_USER_ONLY) 495cc8767dSLike Xu #include "hw/boards.h" 505cc8767dSLike Xu #endif 515cc8767dSLike Xu 52dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h" 53813da627SRichard Henderson 54edee2579SRichard Henderson #if UINTPTR_MAX == UINT32_MAX 55813da627SRichard Henderson # define ELF_CLASS ELFCLASS32 56edee2579SRichard Henderson #else 57edee2579SRichard Henderson # define ELF_CLASS ELFCLASS64 58813da627SRichard Henderson #endif 59813da627SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 60813da627SRichard Henderson # define ELF_DATA ELFDATA2MSB 61813da627SRichard Henderson #else 62813da627SRichard Henderson # define ELF_DATA ELFDATA2LSB 63813da627SRichard Henderson #endif 64813da627SRichard Henderson 65c896fe29Sbellard #include "elf.h" 66508127e2SPaolo Bonzini #include "exec/log.h" 673468b59eSEmilio G. Cota #include "sysemu/sysemu.h" 68c896fe29Sbellard 69139c1837SPaolo Bonzini /* Forward declarations for functions declared in tcg-target.c.inc and 70ce151109SPeter Maydell used here. */ 71e4d58b41SRichard Henderson static void tcg_target_init(TCGContext *s); 72e4d58b41SRichard Henderson static void tcg_target_qemu_prologue(TCGContext *s); 736ac17786SRichard Henderson static bool patch_reloc(tcg_insn_unit *code_ptr, int type, 742ba7fae2SRichard Henderson intptr_t value, intptr_t addend); 75c896fe29Sbellard 76497a22ebSRichard Henderson /* The CIE and FDE header definitions will be common to all hosts. */ 77497a22ebSRichard Henderson typedef struct { 78497a22ebSRichard Henderson uint32_t len __attribute__((aligned((sizeof(void *))))); 79497a22ebSRichard Henderson uint32_t id; 80497a22ebSRichard Henderson uint8_t version; 81497a22ebSRichard Henderson char augmentation[1]; 82497a22ebSRichard Henderson uint8_t code_align; 83497a22ebSRichard Henderson uint8_t data_align; 84497a22ebSRichard Henderson uint8_t return_column; 85497a22ebSRichard Henderson } DebugFrameCIE; 86497a22ebSRichard Henderson 87497a22ebSRichard Henderson typedef struct QEMU_PACKED { 88497a22ebSRichard Henderson uint32_t len __attribute__((aligned((sizeof(void *))))); 89497a22ebSRichard Henderson uint32_t cie_offset; 90edee2579SRichard Henderson uintptr_t func_start; 91edee2579SRichard Henderson uintptr_t func_len; 92497a22ebSRichard Henderson } DebugFrameFDEHeader; 93497a22ebSRichard Henderson 942c90784aSRichard Henderson typedef struct QEMU_PACKED { 952c90784aSRichard Henderson DebugFrameCIE cie; 962c90784aSRichard Henderson DebugFrameFDEHeader fde; 972c90784aSRichard Henderson } DebugFrameHeader; 982c90784aSRichard Henderson 99755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size, 1002c90784aSRichard Henderson const void *debug_frame, 1012c90784aSRichard Henderson size_t debug_frame_size) 102813da627SRichard Henderson __attribute__((unused)); 103813da627SRichard Henderson 104139c1837SPaolo Bonzini /* Forward declarations for functions declared and used in tcg-target.c.inc. */ 1052a534affSRichard Henderson static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1, 106a05b5b9bSRichard Henderson intptr_t arg2); 10778113e83SRichard Henderson static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg); 108c0ad3001SStefan Weil static void tcg_out_movi(TCGContext *s, TCGType type, 1092a534affSRichard Henderson TCGReg ret, tcg_target_long arg); 110c0ad3001SStefan Weil static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, 111c0ad3001SStefan Weil const int *const_args); 112d2fd745fSRichard Henderson #if TCG_TARGET_MAYBE_vec 113e7632cfaSRichard Henderson static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece, 114e7632cfaSRichard Henderson TCGReg dst, TCGReg src); 115d6ecb4a9SRichard Henderson static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece, 116d6ecb4a9SRichard Henderson TCGReg dst, TCGReg base, intptr_t offset); 1174e186175SRichard Henderson static void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece, 1184e186175SRichard Henderson TCGReg dst, int64_t arg); 119d2fd745fSRichard Henderson static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, unsigned vecl, 120d2fd745fSRichard Henderson unsigned vece, const TCGArg *args, 121d2fd745fSRichard Henderson const int *const_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 } 138d2fd745fSRichard Henderson static inline void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, unsigned vecl, 139d2fd745fSRichard Henderson unsigned vece, const TCGArg *args, 140d2fd745fSRichard Henderson const int *const_args) 141d2fd745fSRichard Henderson { 142d2fd745fSRichard Henderson g_assert_not_reached(); 143d2fd745fSRichard Henderson } 144d2fd745fSRichard Henderson #endif 1452a534affSRichard Henderson static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1, 146a05b5b9bSRichard Henderson intptr_t arg2); 14759d7c14eSRichard Henderson static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val, 14859d7c14eSRichard Henderson TCGReg base, intptr_t ofs); 1492be7d76bSRichard Henderson static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target); 150f6c6afc1SRichard Henderson static int tcg_target_const_match(tcg_target_long val, TCGType type, 151c0ad3001SStefan Weil const TCGArgConstraint *arg_ct); 152659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS 153aeee05f5SRichard Henderson static int tcg_out_ldst_finalize(TCGContext *s); 154659ef5cbSRichard Henderson #endif 155c896fe29Sbellard 156a505785cSEmilio G. Cota #define TCG_HIGHWATER 1024 157a505785cSEmilio G. Cota 158df2cce29SEmilio G. Cota static TCGContext **tcg_ctxs; 159df2cce29SEmilio G. Cota static unsigned int n_tcg_ctxs; 1601c2adb95SRichard Henderson TCGv_env cpu_env = 0; 161c8bc1168SRichard Henderson const void *tcg_code_gen_epilogue; 162db0c51a3SRichard Henderson uintptr_t tcg_splitwx_diff; 163df2cce29SEmilio G. Cota 164b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 165b91ccb31SRichard Henderson tcg_prologue_fn *tcg_qemu_tb_exec; 166b91ccb31SRichard Henderson #endif 167b91ccb31SRichard Henderson 168be2cdc5eSEmilio G. Cota struct tcg_region_tree { 169be2cdc5eSEmilio G. Cota QemuMutex lock; 170be2cdc5eSEmilio G. Cota GTree *tree; 171be2cdc5eSEmilio G. Cota /* padding to avoid false sharing is computed at run-time */ 172be2cdc5eSEmilio G. Cota }; 173be2cdc5eSEmilio G. Cota 174e8feb96fSEmilio G. Cota /* 175e8feb96fSEmilio G. Cota * We divide code_gen_buffer into equally-sized "regions" that TCG threads 176e8feb96fSEmilio G. Cota * dynamically allocate from as demand dictates. Given appropriate region 177e8feb96fSEmilio G. Cota * sizing, this minimizes flushes even when some TCG threads generate a lot 178e8feb96fSEmilio G. Cota * more code than others. 179e8feb96fSEmilio G. Cota */ 180e8feb96fSEmilio G. Cota struct tcg_region_state { 181e8feb96fSEmilio G. Cota QemuMutex lock; 182e8feb96fSEmilio G. Cota 183e8feb96fSEmilio G. Cota /* fields set at init time */ 184e8feb96fSEmilio G. Cota void *start; 185e8feb96fSEmilio G. Cota void *start_aligned; 186e8feb96fSEmilio G. Cota void *end; 187e8feb96fSEmilio G. Cota size_t n; 188e8feb96fSEmilio G. Cota size_t size; /* size of one region */ 189e8feb96fSEmilio G. Cota size_t stride; /* .size + guard size */ 190e8feb96fSEmilio G. Cota 191e8feb96fSEmilio G. Cota /* fields protected by the lock */ 192e8feb96fSEmilio G. Cota size_t current; /* current region index */ 193e8feb96fSEmilio G. Cota size_t agg_size_full; /* aggregate size of full regions */ 194e8feb96fSEmilio G. Cota }; 195e8feb96fSEmilio G. Cota 196e8feb96fSEmilio G. Cota static struct tcg_region_state region; 197be2cdc5eSEmilio G. Cota /* 198be2cdc5eSEmilio G. Cota * This is an array of struct tcg_region_tree's, with padding. 199be2cdc5eSEmilio G. Cota * We use void * to simplify the computation of region_trees[i]; each 200be2cdc5eSEmilio G. Cota * struct is found every tree_size bytes. 201be2cdc5eSEmilio G. Cota */ 202be2cdc5eSEmilio G. Cota static void *region_trees; 203be2cdc5eSEmilio G. Cota static size_t tree_size; 204d2fd745fSRichard Henderson static TCGRegSet tcg_target_available_regs[TCG_TYPE_COUNT]; 205b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs; 206c896fe29Sbellard 2071813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1 2084196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v) 209c896fe29Sbellard { 210c896fe29Sbellard *s->code_ptr++ = v; 211c896fe29Sbellard } 212c896fe29Sbellard 2134196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p, 2144196dca6SPeter Maydell uint8_t v) 2155c53bb81SPeter Maydell { 2161813e175SRichard Henderson *p = v; 2175c53bb81SPeter Maydell } 2181813e175SRichard Henderson #endif 2195c53bb81SPeter Maydell 2201813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2 2214196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v) 222c896fe29Sbellard { 2231813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 2) { 2241813e175SRichard Henderson *s->code_ptr++ = v; 2251813e175SRichard Henderson } else { 2261813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 2274387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 2281813e175SRichard Henderson s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE); 2291813e175SRichard Henderson } 230c896fe29Sbellard } 231c896fe29Sbellard 2324196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p, 2334196dca6SPeter Maydell uint16_t v) 2345c53bb81SPeter Maydell { 2351813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 2) { 2361813e175SRichard Henderson *p = v; 2371813e175SRichard Henderson } else { 2385c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 2395c53bb81SPeter Maydell } 2401813e175SRichard Henderson } 2411813e175SRichard Henderson #endif 2425c53bb81SPeter Maydell 2431813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4 2444196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v) 245c896fe29Sbellard { 2461813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 4) { 2471813e175SRichard Henderson *s->code_ptr++ = v; 2481813e175SRichard Henderson } else { 2491813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 2504387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 2511813e175SRichard Henderson s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE); 2521813e175SRichard Henderson } 253c896fe29Sbellard } 254c896fe29Sbellard 2554196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p, 2564196dca6SPeter Maydell uint32_t v) 2575c53bb81SPeter Maydell { 2581813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 4) { 2591813e175SRichard Henderson *p = v; 2601813e175SRichard Henderson } else { 2615c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 2625c53bb81SPeter Maydell } 2631813e175SRichard Henderson } 2641813e175SRichard Henderson #endif 2655c53bb81SPeter Maydell 2661813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 8 2674196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v) 268ac26eb69SRichard Henderson { 2691813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 8) { 2701813e175SRichard Henderson *s->code_ptr++ = v; 2711813e175SRichard Henderson } else { 2721813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 2734387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 2741813e175SRichard Henderson s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE); 2751813e175SRichard Henderson } 276ac26eb69SRichard Henderson } 277ac26eb69SRichard Henderson 2784196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p, 2794196dca6SPeter Maydell uint64_t v) 2805c53bb81SPeter Maydell { 2811813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 8) { 2821813e175SRichard Henderson *p = v; 2831813e175SRichard Henderson } else { 2845c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 2855c53bb81SPeter Maydell } 2861813e175SRichard Henderson } 2871813e175SRichard Henderson #endif 2885c53bb81SPeter Maydell 289c896fe29Sbellard /* label relocation processing */ 290c896fe29Sbellard 2911813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type, 292bec16311SRichard Henderson TCGLabel *l, intptr_t addend) 293c896fe29Sbellard { 2947ecd02a0SRichard Henderson TCGRelocation *r = tcg_malloc(sizeof(TCGRelocation)); 295c896fe29Sbellard 296c896fe29Sbellard r->type = type; 297c896fe29Sbellard r->ptr = code_ptr; 298c896fe29Sbellard r->addend = addend; 2997ecd02a0SRichard Henderson QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next); 300c896fe29Sbellard } 301c896fe29Sbellard 30292ab8e7dSRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l) 303c896fe29Sbellard { 304eabb7b91SAurelien Jarno tcg_debug_assert(!l->has_value); 305c896fe29Sbellard l->has_value = 1; 30692ab8e7dSRichard Henderson l->u.value_ptr = tcg_splitwx_to_rx(s->code_ptr); 307c896fe29Sbellard } 308c896fe29Sbellard 30942a268c2SRichard Henderson TCGLabel *gen_new_label(void) 310c896fe29Sbellard { 311b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 31251e3972cSRichard Henderson TCGLabel *l = tcg_malloc(sizeof(TCGLabel)); 313c896fe29Sbellard 3147ecd02a0SRichard Henderson memset(l, 0, sizeof(TCGLabel)); 3157ecd02a0SRichard Henderson l->id = s->nb_labels++; 3167ecd02a0SRichard Henderson QSIMPLEQ_INIT(&l->relocs); 3177ecd02a0SRichard Henderson 318bef16ab4SRichard Henderson QSIMPLEQ_INSERT_TAIL(&s->labels, l, next); 31942a268c2SRichard Henderson 32042a268c2SRichard Henderson return l; 321c896fe29Sbellard } 322c896fe29Sbellard 3237ecd02a0SRichard Henderson static bool tcg_resolve_relocs(TCGContext *s) 3247ecd02a0SRichard Henderson { 3257ecd02a0SRichard Henderson TCGLabel *l; 3267ecd02a0SRichard Henderson 3277ecd02a0SRichard Henderson QSIMPLEQ_FOREACH(l, &s->labels, next) { 3287ecd02a0SRichard Henderson TCGRelocation *r; 3297ecd02a0SRichard Henderson uintptr_t value = l->u.value; 3307ecd02a0SRichard Henderson 3317ecd02a0SRichard Henderson QSIMPLEQ_FOREACH(r, &l->relocs, next) { 3327ecd02a0SRichard Henderson if (!patch_reloc(r->ptr, r->type, value, r->addend)) { 3337ecd02a0SRichard Henderson return false; 3347ecd02a0SRichard Henderson } 3357ecd02a0SRichard Henderson } 3367ecd02a0SRichard Henderson } 3377ecd02a0SRichard Henderson return true; 3387ecd02a0SRichard Henderson } 3397ecd02a0SRichard Henderson 3409f754620SRichard Henderson static void set_jmp_reset_offset(TCGContext *s, int which) 3419f754620SRichard Henderson { 342f14bed3fSRichard Henderson /* 343f14bed3fSRichard Henderson * We will check for overflow at the end of the opcode loop in 344f14bed3fSRichard Henderson * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX. 345f14bed3fSRichard Henderson */ 346f14bed3fSRichard Henderson s->tb_jmp_reset_offset[which] = tcg_current_code_size(s); 3479f754620SRichard Henderson } 3489f754620SRichard Henderson 349db6b7d0cSRichard Henderson /* Signal overflow, starting over with fewer guest insns. */ 350db6b7d0cSRichard Henderson static void QEMU_NORETURN tcg_raise_tb_overflow(TCGContext *s) 351db6b7d0cSRichard Henderson { 352db6b7d0cSRichard Henderson siglongjmp(s->jmp_trans, -2); 353db6b7d0cSRichard Henderson } 354db6b7d0cSRichard Henderson 3554c22e840SRichard Henderson #define C_PFX1(P, A) P##A 3564c22e840SRichard Henderson #define C_PFX2(P, A, B) P##A##_##B 3574c22e840SRichard Henderson #define C_PFX3(P, A, B, C) P##A##_##B##_##C 3584c22e840SRichard Henderson #define C_PFX4(P, A, B, C, D) P##A##_##B##_##C##_##D 3594c22e840SRichard Henderson #define C_PFX5(P, A, B, C, D, E) P##A##_##B##_##C##_##D##_##E 3604c22e840SRichard Henderson #define C_PFX6(P, A, B, C, D, E, F) P##A##_##B##_##C##_##D##_##E##_##F 3614c22e840SRichard Henderson 3624c22e840SRichard Henderson /* Define an enumeration for the various combinations. */ 3634c22e840SRichard Henderson 3644c22e840SRichard Henderson #define C_O0_I1(I1) C_PFX1(c_o0_i1_, I1), 3654c22e840SRichard Henderson #define C_O0_I2(I1, I2) C_PFX2(c_o0_i2_, I1, I2), 3664c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3) C_PFX3(c_o0_i3_, I1, I2, I3), 3674c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4) C_PFX4(c_o0_i4_, I1, I2, I3, I4), 3684c22e840SRichard Henderson 3694c22e840SRichard Henderson #define C_O1_I1(O1, I1) C_PFX2(c_o1_i1_, O1, I1), 3704c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2) C_PFX3(c_o1_i2_, O1, I1, I2), 3714c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3) C_PFX4(c_o1_i3_, O1, I1, I2, I3), 3724c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4) C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4), 3734c22e840SRichard Henderson 3744c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2) C_PFX3(c_n1_i2_, O1, I1, I2), 3754c22e840SRichard Henderson 3764c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1) C_PFX3(c_o2_i1_, O1, O2, I1), 3774c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2) C_PFX4(c_o2_i2_, O1, O2, I1, I2), 3784c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3) C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3), 3794c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4), 3804c22e840SRichard Henderson 3814c22e840SRichard Henderson typedef enum { 3824c22e840SRichard Henderson #include "tcg-target-con-set.h" 3834c22e840SRichard Henderson } TCGConstraintSetIndex; 3844c22e840SRichard Henderson 3854c22e840SRichard Henderson static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode); 3864c22e840SRichard Henderson 3874c22e840SRichard Henderson #undef C_O0_I1 3884c22e840SRichard Henderson #undef C_O0_I2 3894c22e840SRichard Henderson #undef C_O0_I3 3904c22e840SRichard Henderson #undef C_O0_I4 3914c22e840SRichard Henderson #undef C_O1_I1 3924c22e840SRichard Henderson #undef C_O1_I2 3934c22e840SRichard Henderson #undef C_O1_I3 3944c22e840SRichard Henderson #undef C_O1_I4 3954c22e840SRichard Henderson #undef C_N1_I2 3964c22e840SRichard Henderson #undef C_O2_I1 3974c22e840SRichard Henderson #undef C_O2_I2 3984c22e840SRichard Henderson #undef C_O2_I3 3994c22e840SRichard Henderson #undef C_O2_I4 4004c22e840SRichard Henderson 4014c22e840SRichard Henderson /* Put all of the constraint sets into an array, indexed by the enum. */ 4024c22e840SRichard Henderson 4034c22e840SRichard Henderson #define C_O0_I1(I1) { .args_ct_str = { #I1 } }, 4044c22e840SRichard Henderson #define C_O0_I2(I1, I2) { .args_ct_str = { #I1, #I2 } }, 4054c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3) { .args_ct_str = { #I1, #I2, #I3 } }, 4064c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4) { .args_ct_str = { #I1, #I2, #I3, #I4 } }, 4074c22e840SRichard Henderson 4084c22e840SRichard Henderson #define C_O1_I1(O1, I1) { .args_ct_str = { #O1, #I1 } }, 4094c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2) { .args_ct_str = { #O1, #I1, #I2 } }, 4104c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3) { .args_ct_str = { #O1, #I1, #I2, #I3 } }, 4114c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4) { .args_ct_str = { #O1, #I1, #I2, #I3, #I4 } }, 4124c22e840SRichard Henderson 4134c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2) { .args_ct_str = { "&" #O1, #I1, #I2 } }, 4144c22e840SRichard Henderson 4154c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1) { .args_ct_str = { #O1, #O2, #I1 } }, 4164c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2) { .args_ct_str = { #O1, #O2, #I1, #I2 } }, 4174c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3) { .args_ct_str = { #O1, #O2, #I1, #I2, #I3 } }, 4184c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) { .args_ct_str = { #O1, #O2, #I1, #I2, #I3, #I4 } }, 4194c22e840SRichard Henderson 4204c22e840SRichard Henderson static const TCGTargetOpDef constraint_sets[] = { 4214c22e840SRichard Henderson #include "tcg-target-con-set.h" 4224c22e840SRichard Henderson }; 4234c22e840SRichard Henderson 4244c22e840SRichard Henderson 4254c22e840SRichard Henderson #undef C_O0_I1 4264c22e840SRichard Henderson #undef C_O0_I2 4274c22e840SRichard Henderson #undef C_O0_I3 4284c22e840SRichard Henderson #undef C_O0_I4 4294c22e840SRichard Henderson #undef C_O1_I1 4304c22e840SRichard Henderson #undef C_O1_I2 4314c22e840SRichard Henderson #undef C_O1_I3 4324c22e840SRichard Henderson #undef C_O1_I4 4334c22e840SRichard Henderson #undef C_N1_I2 4344c22e840SRichard Henderson #undef C_O2_I1 4354c22e840SRichard Henderson #undef C_O2_I2 4364c22e840SRichard Henderson #undef C_O2_I3 4374c22e840SRichard Henderson #undef C_O2_I4 4384c22e840SRichard Henderson 4394c22e840SRichard Henderson /* Expand the enumerator to be returned from tcg_target_op_def(). */ 4404c22e840SRichard Henderson 4414c22e840SRichard Henderson #define C_O0_I1(I1) C_PFX1(c_o0_i1_, I1) 4424c22e840SRichard Henderson #define C_O0_I2(I1, I2) C_PFX2(c_o0_i2_, I1, I2) 4434c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3) C_PFX3(c_o0_i3_, I1, I2, I3) 4444c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4) C_PFX4(c_o0_i4_, I1, I2, I3, I4) 4454c22e840SRichard Henderson 4464c22e840SRichard Henderson #define C_O1_I1(O1, I1) C_PFX2(c_o1_i1_, O1, I1) 4474c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2) C_PFX3(c_o1_i2_, O1, I1, I2) 4484c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3) C_PFX4(c_o1_i3_, O1, I1, I2, I3) 4494c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4) C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4) 4504c22e840SRichard Henderson 4514c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2) C_PFX3(c_n1_i2_, O1, I1, I2) 4524c22e840SRichard Henderson 4534c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1) C_PFX3(c_o2_i1_, O1, O2, I1) 4544c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2) C_PFX4(c_o2_i2_, O1, O2, I1, I2) 4554c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3) C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3) 4564c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4) 4574c22e840SRichard Henderson 458139c1837SPaolo Bonzini #include "tcg-target.c.inc" 459c896fe29Sbellard 460be2cdc5eSEmilio G. Cota /* compare a pointer @ptr and a tb_tc @s */ 461be2cdc5eSEmilio G. Cota static int ptr_cmp_tb_tc(const void *ptr, const struct tb_tc *s) 462be2cdc5eSEmilio G. Cota { 463be2cdc5eSEmilio G. Cota if (ptr >= s->ptr + s->size) { 464be2cdc5eSEmilio G. Cota return 1; 465be2cdc5eSEmilio G. Cota } else if (ptr < s->ptr) { 466be2cdc5eSEmilio G. Cota return -1; 467be2cdc5eSEmilio G. Cota } 468be2cdc5eSEmilio G. Cota return 0; 469be2cdc5eSEmilio G. Cota } 470be2cdc5eSEmilio G. Cota 471be2cdc5eSEmilio G. Cota static gint tb_tc_cmp(gconstpointer ap, gconstpointer bp) 472be2cdc5eSEmilio G. Cota { 473be2cdc5eSEmilio G. Cota const struct tb_tc *a = ap; 474be2cdc5eSEmilio G. Cota const struct tb_tc *b = bp; 475be2cdc5eSEmilio G. Cota 476be2cdc5eSEmilio G. Cota /* 477be2cdc5eSEmilio G. Cota * When both sizes are set, we know this isn't a lookup. 478be2cdc5eSEmilio G. Cota * This is the most likely case: every TB must be inserted; lookups 479be2cdc5eSEmilio G. Cota * are a lot less frequent. 480be2cdc5eSEmilio G. Cota */ 481be2cdc5eSEmilio G. Cota if (likely(a->size && b->size)) { 482be2cdc5eSEmilio G. Cota if (a->ptr > b->ptr) { 483be2cdc5eSEmilio G. Cota return 1; 484be2cdc5eSEmilio G. Cota } else if (a->ptr < b->ptr) { 485be2cdc5eSEmilio G. Cota return -1; 486be2cdc5eSEmilio G. Cota } 487be2cdc5eSEmilio G. Cota /* a->ptr == b->ptr should happen only on deletions */ 488be2cdc5eSEmilio G. Cota g_assert(a->size == b->size); 489be2cdc5eSEmilio G. Cota return 0; 490be2cdc5eSEmilio G. Cota } 491be2cdc5eSEmilio G. Cota /* 492be2cdc5eSEmilio G. Cota * All lookups have either .size field set to 0. 493be2cdc5eSEmilio G. Cota * From the glib sources we see that @ap is always the lookup key. However 494be2cdc5eSEmilio G. Cota * the docs provide no guarantee, so we just mark this case as likely. 495be2cdc5eSEmilio G. Cota */ 496be2cdc5eSEmilio G. Cota if (likely(a->size == 0)) { 497be2cdc5eSEmilio G. Cota return ptr_cmp_tb_tc(a->ptr, b); 498be2cdc5eSEmilio G. Cota } 499be2cdc5eSEmilio G. Cota return ptr_cmp_tb_tc(b->ptr, a); 500be2cdc5eSEmilio G. Cota } 501be2cdc5eSEmilio G. Cota 502be2cdc5eSEmilio G. Cota static void tcg_region_trees_init(void) 503be2cdc5eSEmilio G. Cota { 504be2cdc5eSEmilio G. Cota size_t i; 505be2cdc5eSEmilio G. Cota 506be2cdc5eSEmilio G. Cota tree_size = ROUND_UP(sizeof(struct tcg_region_tree), qemu_dcache_linesize); 507be2cdc5eSEmilio G. Cota region_trees = qemu_memalign(qemu_dcache_linesize, region.n * tree_size); 508be2cdc5eSEmilio G. Cota for (i = 0; i < region.n; i++) { 509be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = region_trees + i * tree_size; 510be2cdc5eSEmilio G. Cota 511be2cdc5eSEmilio G. Cota qemu_mutex_init(&rt->lock); 512be2cdc5eSEmilio G. Cota rt->tree = g_tree_new(tb_tc_cmp); 513be2cdc5eSEmilio G. Cota } 514be2cdc5eSEmilio G. Cota } 515be2cdc5eSEmilio G. Cota 516*0610067eSRichard Henderson static struct tcg_region_tree *tc_ptr_to_region_tree(const void *p) 517be2cdc5eSEmilio G. Cota { 518be2cdc5eSEmilio G. Cota size_t region_idx; 519be2cdc5eSEmilio G. Cota 520*0610067eSRichard Henderson /* 521*0610067eSRichard Henderson * Like tcg_splitwx_to_rw, with no assert. The pc may come from 522*0610067eSRichard Henderson * a signal handler over which the caller has no control. 523*0610067eSRichard Henderson */ 524*0610067eSRichard Henderson if (!in_code_gen_buffer(p)) { 525*0610067eSRichard Henderson p -= tcg_splitwx_diff; 526*0610067eSRichard Henderson if (!in_code_gen_buffer(p)) { 527*0610067eSRichard Henderson return NULL; 528*0610067eSRichard Henderson } 529*0610067eSRichard Henderson } 530*0610067eSRichard Henderson 531be2cdc5eSEmilio G. Cota if (p < region.start_aligned) { 532be2cdc5eSEmilio G. Cota region_idx = 0; 533be2cdc5eSEmilio G. Cota } else { 534be2cdc5eSEmilio G. Cota ptrdiff_t offset = p - region.start_aligned; 535be2cdc5eSEmilio G. Cota 536be2cdc5eSEmilio G. Cota if (offset > region.stride * (region.n - 1)) { 537be2cdc5eSEmilio G. Cota region_idx = region.n - 1; 538be2cdc5eSEmilio G. Cota } else { 539be2cdc5eSEmilio G. Cota region_idx = offset / region.stride; 540be2cdc5eSEmilio G. Cota } 541be2cdc5eSEmilio G. Cota } 542be2cdc5eSEmilio G. Cota return region_trees + region_idx * tree_size; 543be2cdc5eSEmilio G. Cota } 544be2cdc5eSEmilio G. Cota 545be2cdc5eSEmilio G. Cota void tcg_tb_insert(TranslationBlock *tb) 546be2cdc5eSEmilio G. Cota { 547be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr); 548be2cdc5eSEmilio G. Cota 549*0610067eSRichard Henderson g_assert(rt != NULL); 550be2cdc5eSEmilio G. Cota qemu_mutex_lock(&rt->lock); 551be2cdc5eSEmilio G. Cota g_tree_insert(rt->tree, &tb->tc, tb); 552be2cdc5eSEmilio G. Cota qemu_mutex_unlock(&rt->lock); 553be2cdc5eSEmilio G. Cota } 554be2cdc5eSEmilio G. Cota 555be2cdc5eSEmilio G. Cota void tcg_tb_remove(TranslationBlock *tb) 556be2cdc5eSEmilio G. Cota { 557be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr); 558be2cdc5eSEmilio G. Cota 559*0610067eSRichard Henderson g_assert(rt != NULL); 560be2cdc5eSEmilio G. Cota qemu_mutex_lock(&rt->lock); 561be2cdc5eSEmilio G. Cota g_tree_remove(rt->tree, &tb->tc); 562be2cdc5eSEmilio G. Cota qemu_mutex_unlock(&rt->lock); 563be2cdc5eSEmilio G. Cota } 564be2cdc5eSEmilio G. Cota 565be2cdc5eSEmilio G. Cota /* 566be2cdc5eSEmilio G. Cota * Find the TB 'tb' such that 567be2cdc5eSEmilio G. Cota * tb->tc.ptr <= tc_ptr < tb->tc.ptr + tb->tc.size 568be2cdc5eSEmilio G. Cota * Return NULL if not found. 569be2cdc5eSEmilio G. Cota */ 570be2cdc5eSEmilio G. Cota TranslationBlock *tcg_tb_lookup(uintptr_t tc_ptr) 571be2cdc5eSEmilio G. Cota { 572be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = tc_ptr_to_region_tree((void *)tc_ptr); 573be2cdc5eSEmilio G. Cota TranslationBlock *tb; 574be2cdc5eSEmilio G. Cota struct tb_tc s = { .ptr = (void *)tc_ptr }; 575be2cdc5eSEmilio G. Cota 576*0610067eSRichard Henderson if (rt == NULL) { 577*0610067eSRichard Henderson return NULL; 578*0610067eSRichard Henderson } 579*0610067eSRichard Henderson 580be2cdc5eSEmilio G. Cota qemu_mutex_lock(&rt->lock); 581be2cdc5eSEmilio G. Cota tb = g_tree_lookup(rt->tree, &s); 582be2cdc5eSEmilio G. Cota qemu_mutex_unlock(&rt->lock); 583be2cdc5eSEmilio G. Cota return tb; 584be2cdc5eSEmilio G. Cota } 585be2cdc5eSEmilio G. Cota 586be2cdc5eSEmilio G. Cota static void tcg_region_tree_lock_all(void) 587be2cdc5eSEmilio G. Cota { 588be2cdc5eSEmilio G. Cota size_t i; 589be2cdc5eSEmilio G. Cota 590be2cdc5eSEmilio G. Cota for (i = 0; i < region.n; i++) { 591be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = region_trees + i * tree_size; 592be2cdc5eSEmilio G. Cota 593be2cdc5eSEmilio G. Cota qemu_mutex_lock(&rt->lock); 594be2cdc5eSEmilio G. Cota } 595be2cdc5eSEmilio G. Cota } 596be2cdc5eSEmilio G. Cota 597be2cdc5eSEmilio G. Cota static void tcg_region_tree_unlock_all(void) 598be2cdc5eSEmilio G. Cota { 599be2cdc5eSEmilio G. Cota size_t i; 600be2cdc5eSEmilio G. Cota 601be2cdc5eSEmilio G. Cota for (i = 0; i < region.n; i++) { 602be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = region_trees + i * tree_size; 603be2cdc5eSEmilio G. Cota 604be2cdc5eSEmilio G. Cota qemu_mutex_unlock(&rt->lock); 605be2cdc5eSEmilio G. Cota } 606be2cdc5eSEmilio G. Cota } 607be2cdc5eSEmilio G. Cota 608be2cdc5eSEmilio G. Cota void tcg_tb_foreach(GTraverseFunc func, gpointer user_data) 609be2cdc5eSEmilio G. Cota { 610be2cdc5eSEmilio G. Cota size_t i; 611be2cdc5eSEmilio G. Cota 612be2cdc5eSEmilio G. Cota tcg_region_tree_lock_all(); 613be2cdc5eSEmilio G. Cota for (i = 0; i < region.n; i++) { 614be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = region_trees + i * tree_size; 615be2cdc5eSEmilio G. Cota 616be2cdc5eSEmilio G. Cota g_tree_foreach(rt->tree, func, user_data); 617be2cdc5eSEmilio G. Cota } 618be2cdc5eSEmilio G. Cota tcg_region_tree_unlock_all(); 619be2cdc5eSEmilio G. Cota } 620be2cdc5eSEmilio G. Cota 621be2cdc5eSEmilio G. Cota size_t tcg_nb_tbs(void) 622be2cdc5eSEmilio G. Cota { 623be2cdc5eSEmilio G. Cota size_t nb_tbs = 0; 624be2cdc5eSEmilio G. Cota size_t i; 625be2cdc5eSEmilio G. Cota 626be2cdc5eSEmilio G. Cota tcg_region_tree_lock_all(); 627be2cdc5eSEmilio G. Cota for (i = 0; i < region.n; i++) { 628be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = region_trees + i * tree_size; 629be2cdc5eSEmilio G. Cota 630be2cdc5eSEmilio G. Cota nb_tbs += g_tree_nnodes(rt->tree); 631be2cdc5eSEmilio G. Cota } 632be2cdc5eSEmilio G. Cota tcg_region_tree_unlock_all(); 633be2cdc5eSEmilio G. Cota return nb_tbs; 634be2cdc5eSEmilio G. Cota } 635be2cdc5eSEmilio G. Cota 636938e897aSEmilio G. Cota static gboolean tcg_region_tree_traverse(gpointer k, gpointer v, gpointer data) 637938e897aSEmilio G. Cota { 638938e897aSEmilio G. Cota TranslationBlock *tb = v; 639938e897aSEmilio G. Cota 640938e897aSEmilio G. Cota tb_destroy(tb); 641938e897aSEmilio G. Cota return FALSE; 642938e897aSEmilio G. Cota } 643938e897aSEmilio G. Cota 644be2cdc5eSEmilio G. Cota static void tcg_region_tree_reset_all(void) 645be2cdc5eSEmilio G. Cota { 646be2cdc5eSEmilio G. Cota size_t i; 647be2cdc5eSEmilio G. Cota 648be2cdc5eSEmilio G. Cota tcg_region_tree_lock_all(); 649be2cdc5eSEmilio G. Cota for (i = 0; i < region.n; i++) { 650be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = region_trees + i * tree_size; 651be2cdc5eSEmilio G. Cota 652938e897aSEmilio G. Cota g_tree_foreach(rt->tree, tcg_region_tree_traverse, NULL); 653be2cdc5eSEmilio G. Cota /* Increment the refcount first so that destroy acts as a reset */ 654be2cdc5eSEmilio G. Cota g_tree_ref(rt->tree); 655be2cdc5eSEmilio G. Cota g_tree_destroy(rt->tree); 656be2cdc5eSEmilio G. Cota } 657be2cdc5eSEmilio G. Cota tcg_region_tree_unlock_all(); 658be2cdc5eSEmilio G. Cota } 659be2cdc5eSEmilio G. Cota 660e8feb96fSEmilio G. Cota static void tcg_region_bounds(size_t curr_region, void **pstart, void **pend) 661e8feb96fSEmilio G. Cota { 662e8feb96fSEmilio G. Cota void *start, *end; 663e8feb96fSEmilio G. Cota 664e8feb96fSEmilio G. Cota start = region.start_aligned + curr_region * region.stride; 665e8feb96fSEmilio G. Cota end = start + region.size; 666e8feb96fSEmilio G. Cota 667e8feb96fSEmilio G. Cota if (curr_region == 0) { 668e8feb96fSEmilio G. Cota start = region.start; 669e8feb96fSEmilio G. Cota } 670e8feb96fSEmilio G. Cota if (curr_region == region.n - 1) { 671e8feb96fSEmilio G. Cota end = region.end; 672e8feb96fSEmilio G. Cota } 673e8feb96fSEmilio G. Cota 674e8feb96fSEmilio G. Cota *pstart = start; 675e8feb96fSEmilio G. Cota *pend = end; 676e8feb96fSEmilio G. Cota } 677e8feb96fSEmilio G. Cota 678e8feb96fSEmilio G. Cota static void tcg_region_assign(TCGContext *s, size_t curr_region) 679e8feb96fSEmilio G. Cota { 680e8feb96fSEmilio G. Cota void *start, *end; 681e8feb96fSEmilio G. Cota 682e8feb96fSEmilio G. Cota tcg_region_bounds(curr_region, &start, &end); 683e8feb96fSEmilio G. Cota 684e8feb96fSEmilio G. Cota s->code_gen_buffer = start; 685e8feb96fSEmilio G. Cota s->code_gen_ptr = start; 686e8feb96fSEmilio G. Cota s->code_gen_buffer_size = end - start; 687e8feb96fSEmilio G. Cota s->code_gen_highwater = end - TCG_HIGHWATER; 688e8feb96fSEmilio G. Cota } 689e8feb96fSEmilio G. Cota 690e8feb96fSEmilio G. Cota static bool tcg_region_alloc__locked(TCGContext *s) 691e8feb96fSEmilio G. Cota { 692e8feb96fSEmilio G. Cota if (region.current == region.n) { 693e8feb96fSEmilio G. Cota return true; 694e8feb96fSEmilio G. Cota } 695e8feb96fSEmilio G. Cota tcg_region_assign(s, region.current); 696e8feb96fSEmilio G. Cota region.current++; 697e8feb96fSEmilio G. Cota return false; 698e8feb96fSEmilio G. Cota } 699e8feb96fSEmilio G. Cota 700e8feb96fSEmilio G. Cota /* 701e8feb96fSEmilio G. Cota * Request a new region once the one in use has filled up. 702e8feb96fSEmilio G. Cota * Returns true on error. 703e8feb96fSEmilio G. Cota */ 704e8feb96fSEmilio G. Cota static bool tcg_region_alloc(TCGContext *s) 705e8feb96fSEmilio G. Cota { 706e8feb96fSEmilio G. Cota bool err; 707e8feb96fSEmilio G. Cota /* read the region size now; alloc__locked will overwrite it on success */ 708e8feb96fSEmilio G. Cota size_t size_full = s->code_gen_buffer_size; 709e8feb96fSEmilio G. Cota 710e8feb96fSEmilio G. Cota qemu_mutex_lock(®ion.lock); 711e8feb96fSEmilio G. Cota err = tcg_region_alloc__locked(s); 712e8feb96fSEmilio G. Cota if (!err) { 713e8feb96fSEmilio G. Cota region.agg_size_full += size_full - TCG_HIGHWATER; 714e8feb96fSEmilio G. Cota } 715e8feb96fSEmilio G. Cota qemu_mutex_unlock(®ion.lock); 716e8feb96fSEmilio G. Cota return err; 717e8feb96fSEmilio G. Cota } 718e8feb96fSEmilio G. Cota 719e8feb96fSEmilio G. Cota /* 720e8feb96fSEmilio G. Cota * Perform a context's first region allocation. 721e8feb96fSEmilio G. Cota * This function does _not_ increment region.agg_size_full. 722e8feb96fSEmilio G. Cota */ 723e8feb96fSEmilio G. Cota static inline bool tcg_region_initial_alloc__locked(TCGContext *s) 724e8feb96fSEmilio G. Cota { 725e8feb96fSEmilio G. Cota return tcg_region_alloc__locked(s); 726e8feb96fSEmilio G. Cota } 727e8feb96fSEmilio G. Cota 728e8feb96fSEmilio G. Cota /* Call from a safe-work context */ 729e8feb96fSEmilio G. Cota void tcg_region_reset_all(void) 730e8feb96fSEmilio G. Cota { 731d73415a3SStefan Hajnoczi unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs); 732e8feb96fSEmilio G. Cota unsigned int i; 733e8feb96fSEmilio G. Cota 734e8feb96fSEmilio G. Cota qemu_mutex_lock(®ion.lock); 735e8feb96fSEmilio G. Cota region.current = 0; 736e8feb96fSEmilio G. Cota region.agg_size_full = 0; 737e8feb96fSEmilio G. Cota 7383468b59eSEmilio G. Cota for (i = 0; i < n_ctxs; i++) { 739d73415a3SStefan Hajnoczi TCGContext *s = qatomic_read(&tcg_ctxs[i]); 7403468b59eSEmilio G. Cota bool err = tcg_region_initial_alloc__locked(s); 741e8feb96fSEmilio G. Cota 742e8feb96fSEmilio G. Cota g_assert(!err); 743e8feb96fSEmilio G. Cota } 744e8feb96fSEmilio G. Cota qemu_mutex_unlock(®ion.lock); 745be2cdc5eSEmilio G. Cota 746be2cdc5eSEmilio G. Cota tcg_region_tree_reset_all(); 747e8feb96fSEmilio G. Cota } 748e8feb96fSEmilio G. Cota 7493468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY 7503468b59eSEmilio G. Cota static size_t tcg_n_regions(void) 7513468b59eSEmilio G. Cota { 7523468b59eSEmilio G. Cota return 1; 7533468b59eSEmilio G. Cota } 7543468b59eSEmilio G. Cota #else 7553468b59eSEmilio G. Cota /* 7563468b59eSEmilio G. Cota * It is likely that some vCPUs will translate more code than others, so we 7573468b59eSEmilio G. Cota * first try to set more regions than max_cpus, with those regions being of 7583468b59eSEmilio G. Cota * reasonable size. If that's not possible we make do by evenly dividing 7593468b59eSEmilio G. Cota * the code_gen_buffer among the vCPUs. 7603468b59eSEmilio G. Cota */ 7613468b59eSEmilio G. Cota static size_t tcg_n_regions(void) 7623468b59eSEmilio G. Cota { 7633468b59eSEmilio G. Cota size_t i; 7643468b59eSEmilio G. Cota 7653468b59eSEmilio G. Cota /* Use a single region if all we have is one vCPU thread */ 7665cc8767dSLike Xu #if !defined(CONFIG_USER_ONLY) 7675cc8767dSLike Xu MachineState *ms = MACHINE(qdev_get_machine()); 7685cc8767dSLike Xu unsigned int max_cpus = ms->smp.max_cpus; 7695cc8767dSLike Xu #endif 7703468b59eSEmilio G. Cota if (max_cpus == 1 || !qemu_tcg_mttcg_enabled()) { 7713468b59eSEmilio G. Cota return 1; 7723468b59eSEmilio G. Cota } 7733468b59eSEmilio G. Cota 7743468b59eSEmilio G. Cota /* Try to have more regions than max_cpus, with each region being >= 2 MB */ 7753468b59eSEmilio G. Cota for (i = 8; i > 0; i--) { 7763468b59eSEmilio G. Cota size_t regions_per_thread = i; 7773468b59eSEmilio G. Cota size_t region_size; 7783468b59eSEmilio G. Cota 7793468b59eSEmilio G. Cota region_size = tcg_init_ctx.code_gen_buffer_size; 7803468b59eSEmilio G. Cota region_size /= max_cpus * regions_per_thread; 7813468b59eSEmilio G. Cota 7823468b59eSEmilio G. Cota if (region_size >= 2 * 1024u * 1024) { 7833468b59eSEmilio G. Cota return max_cpus * regions_per_thread; 7843468b59eSEmilio G. Cota } 7853468b59eSEmilio G. Cota } 7863468b59eSEmilio G. Cota /* If we can't, then just allocate one region per vCPU thread */ 7873468b59eSEmilio G. Cota return max_cpus; 7883468b59eSEmilio G. Cota } 7893468b59eSEmilio G. Cota #endif 7903468b59eSEmilio G. Cota 791e8feb96fSEmilio G. Cota /* 792e8feb96fSEmilio G. Cota * Initializes region partitioning. 793e8feb96fSEmilio G. Cota * 794e8feb96fSEmilio G. Cota * Called at init time from the parent thread (i.e. the one calling 795e8feb96fSEmilio G. Cota * tcg_context_init), after the target's TCG globals have been set. 7963468b59eSEmilio G. Cota * 7973468b59eSEmilio G. Cota * Region partitioning works by splitting code_gen_buffer into separate regions, 7983468b59eSEmilio G. Cota * and then assigning regions to TCG threads so that the threads can translate 7993468b59eSEmilio G. Cota * code in parallel without synchronization. 8003468b59eSEmilio G. Cota * 8013468b59eSEmilio G. Cota * In softmmu the number of TCG threads is bounded by max_cpus, so we use at 8023468b59eSEmilio G. Cota * least max_cpus regions in MTTCG. In !MTTCG we use a single region. 8033468b59eSEmilio G. Cota * Note that the TCG options from the command-line (i.e. -accel accel=tcg,[...]) 8043468b59eSEmilio G. Cota * must have been parsed before calling this function, since it calls 8053468b59eSEmilio G. Cota * qemu_tcg_mttcg_enabled(). 8063468b59eSEmilio G. Cota * 8073468b59eSEmilio G. Cota * In user-mode we use a single region. Having multiple regions in user-mode 8083468b59eSEmilio G. Cota * is not supported, because the number of vCPU threads (recall that each thread 8093468b59eSEmilio G. Cota * spawned by the guest corresponds to a vCPU thread) is only bounded by the 8103468b59eSEmilio G. Cota * OS, and usually this number is huge (tens of thousands is not uncommon). 8113468b59eSEmilio G. Cota * Thus, given this large bound on the number of vCPU threads and the fact 8123468b59eSEmilio G. Cota * that code_gen_buffer is allocated at compile-time, we cannot guarantee 8133468b59eSEmilio G. Cota * that the availability of at least one region per vCPU thread. 8143468b59eSEmilio G. Cota * 8153468b59eSEmilio G. Cota * However, this user-mode limitation is unlikely to be a significant problem 8163468b59eSEmilio G. Cota * in practice. Multi-threaded guests share most if not all of their translated 8173468b59eSEmilio G. Cota * code, which makes parallel code generation less appealing than in softmmu. 818e8feb96fSEmilio G. Cota */ 819e8feb96fSEmilio G. Cota void tcg_region_init(void) 820e8feb96fSEmilio G. Cota { 821e8feb96fSEmilio G. Cota void *buf = tcg_init_ctx.code_gen_buffer; 822e8feb96fSEmilio G. Cota void *aligned; 823e8feb96fSEmilio G. Cota size_t size = tcg_init_ctx.code_gen_buffer_size; 824e8feb96fSEmilio G. Cota size_t page_size = qemu_real_host_page_size; 825e8feb96fSEmilio G. Cota size_t region_size; 826e8feb96fSEmilio G. Cota size_t n_regions; 827e8feb96fSEmilio G. Cota size_t i; 828db0c51a3SRichard Henderson uintptr_t splitwx_diff; 829e8feb96fSEmilio G. Cota 8303468b59eSEmilio G. Cota n_regions = tcg_n_regions(); 831e8feb96fSEmilio G. Cota 832e8feb96fSEmilio G. Cota /* The first region will be 'aligned - buf' bytes larger than the others */ 833e8feb96fSEmilio G. Cota aligned = QEMU_ALIGN_PTR_UP(buf, page_size); 834e8feb96fSEmilio G. Cota g_assert(aligned < tcg_init_ctx.code_gen_buffer + size); 835e8feb96fSEmilio G. Cota /* 836e8feb96fSEmilio G. Cota * Make region_size a multiple of page_size, using aligned as the start. 837e8feb96fSEmilio G. Cota * As a result of this we might end up with a few extra pages at the end of 838e8feb96fSEmilio G. Cota * the buffer; we will assign those to the last region. 839e8feb96fSEmilio G. Cota */ 840e8feb96fSEmilio G. Cota region_size = (size - (aligned - buf)) / n_regions; 841e8feb96fSEmilio G. Cota region_size = QEMU_ALIGN_DOWN(region_size, page_size); 842e8feb96fSEmilio G. Cota 843e8feb96fSEmilio G. Cota /* A region must have at least 2 pages; one code, one guard */ 844e8feb96fSEmilio G. Cota g_assert(region_size >= 2 * page_size); 845e8feb96fSEmilio G. Cota 846e8feb96fSEmilio G. Cota /* init the region struct */ 847e8feb96fSEmilio G. Cota qemu_mutex_init(®ion.lock); 848e8feb96fSEmilio G. Cota region.n = n_regions; 849e8feb96fSEmilio G. Cota region.size = region_size - page_size; 850e8feb96fSEmilio G. Cota region.stride = region_size; 851e8feb96fSEmilio G. Cota region.start = buf; 852e8feb96fSEmilio G. Cota region.start_aligned = aligned; 853e8feb96fSEmilio G. Cota /* page-align the end, since its last page will be a guard page */ 854e8feb96fSEmilio G. Cota region.end = QEMU_ALIGN_PTR_DOWN(buf + size, page_size); 855e8feb96fSEmilio G. Cota /* account for that last guard page */ 856e8feb96fSEmilio G. Cota region.end -= page_size; 857e8feb96fSEmilio G. Cota 858e8feb96fSEmilio G. Cota /* set guard pages */ 859db0c51a3SRichard Henderson splitwx_diff = tcg_splitwx_diff; 860e8feb96fSEmilio G. Cota for (i = 0; i < region.n; i++) { 861e8feb96fSEmilio G. Cota void *start, *end; 862e8feb96fSEmilio G. Cota int rc; 863e8feb96fSEmilio G. Cota 864e8feb96fSEmilio G. Cota tcg_region_bounds(i, &start, &end); 865e8feb96fSEmilio G. Cota rc = qemu_mprotect_none(end, page_size); 866e8feb96fSEmilio G. Cota g_assert(!rc); 867db0c51a3SRichard Henderson if (splitwx_diff) { 868db0c51a3SRichard Henderson rc = qemu_mprotect_none(end + splitwx_diff, page_size); 869db0c51a3SRichard Henderson g_assert(!rc); 870db0c51a3SRichard Henderson } 871e8feb96fSEmilio G. Cota } 872e8feb96fSEmilio G. Cota 873be2cdc5eSEmilio G. Cota tcg_region_trees_init(); 874be2cdc5eSEmilio G. Cota 8753468b59eSEmilio G. Cota /* In user-mode we support only one ctx, so do the initial allocation now */ 8763468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY 877e8feb96fSEmilio G. Cota { 878e8feb96fSEmilio G. Cota bool err = tcg_region_initial_alloc__locked(tcg_ctx); 879e8feb96fSEmilio G. Cota 880e8feb96fSEmilio G. Cota g_assert(!err); 881e8feb96fSEmilio G. Cota } 8823468b59eSEmilio G. Cota #endif 883e8feb96fSEmilio G. Cota } 884e8feb96fSEmilio G. Cota 885db0c51a3SRichard Henderson #ifdef CONFIG_DEBUG_TCG 886db0c51a3SRichard Henderson const void *tcg_splitwx_to_rx(void *rw) 887db0c51a3SRichard Henderson { 888db0c51a3SRichard Henderson /* Pass NULL pointers unchanged. */ 889db0c51a3SRichard Henderson if (rw) { 890db0c51a3SRichard Henderson g_assert(in_code_gen_buffer(rw)); 891db0c51a3SRichard Henderson rw += tcg_splitwx_diff; 892db0c51a3SRichard Henderson } 893db0c51a3SRichard Henderson return rw; 894db0c51a3SRichard Henderson } 895db0c51a3SRichard Henderson 896db0c51a3SRichard Henderson void *tcg_splitwx_to_rw(const void *rx) 897db0c51a3SRichard Henderson { 898db0c51a3SRichard Henderson /* Pass NULL pointers unchanged. */ 899db0c51a3SRichard Henderson if (rx) { 900db0c51a3SRichard Henderson rx -= tcg_splitwx_diff; 901db0c51a3SRichard Henderson /* Assert that we end with a pointer in the rw region. */ 902db0c51a3SRichard Henderson g_assert(in_code_gen_buffer(rx)); 903db0c51a3SRichard Henderson } 904db0c51a3SRichard Henderson return (void *)rx; 905db0c51a3SRichard Henderson } 906db0c51a3SRichard Henderson #endif /* CONFIG_DEBUG_TCG */ 907db0c51a3SRichard Henderson 90838b47b19SEmilio G. Cota static void alloc_tcg_plugin_context(TCGContext *s) 90938b47b19SEmilio G. Cota { 91038b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN 91138b47b19SEmilio G. Cota s->plugin_tb = g_new0(struct qemu_plugin_tb, 1); 91238b47b19SEmilio G. Cota s->plugin_tb->insns = 91338b47b19SEmilio G. Cota g_ptr_array_new_with_free_func(qemu_plugin_insn_cleanup_fn); 91438b47b19SEmilio G. Cota #endif 91538b47b19SEmilio G. Cota } 91638b47b19SEmilio G. Cota 917e8feb96fSEmilio G. Cota /* 9183468b59eSEmilio G. Cota * All TCG threads except the parent (i.e. the one that called tcg_context_init 9193468b59eSEmilio G. Cota * and registered the target's TCG globals) must register with this function 9203468b59eSEmilio G. Cota * before initiating translation. 9213468b59eSEmilio G. Cota * 9223468b59eSEmilio G. Cota * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation 9233468b59eSEmilio G. Cota * of tcg_region_init() for the reasoning behind this. 9243468b59eSEmilio G. Cota * 9253468b59eSEmilio G. Cota * In softmmu each caller registers its context in tcg_ctxs[]. Note that in 9263468b59eSEmilio G. Cota * softmmu tcg_ctxs[] does not track tcg_ctx_init, since the initial context 9273468b59eSEmilio G. Cota * is not used anymore for translation once this function is called. 9283468b59eSEmilio G. Cota * 9293468b59eSEmilio G. Cota * Not tracking tcg_init_ctx in tcg_ctxs[] in softmmu keeps code that iterates 9303468b59eSEmilio G. Cota * over the array (e.g. tcg_code_size() the same for both softmmu and user-mode. 9313468b59eSEmilio G. Cota */ 9323468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY 9333468b59eSEmilio G. Cota void tcg_register_thread(void) 9343468b59eSEmilio G. Cota { 9353468b59eSEmilio G. Cota tcg_ctx = &tcg_init_ctx; 9363468b59eSEmilio G. Cota } 9373468b59eSEmilio G. Cota #else 9383468b59eSEmilio G. Cota void tcg_register_thread(void) 9393468b59eSEmilio G. Cota { 9405cc8767dSLike Xu MachineState *ms = MACHINE(qdev_get_machine()); 9413468b59eSEmilio G. Cota TCGContext *s = g_malloc(sizeof(*s)); 9423468b59eSEmilio G. Cota unsigned int i, n; 9433468b59eSEmilio G. Cota bool err; 9443468b59eSEmilio G. Cota 9453468b59eSEmilio G. Cota *s = tcg_init_ctx; 9463468b59eSEmilio G. Cota 9473468b59eSEmilio G. Cota /* Relink mem_base. */ 9483468b59eSEmilio G. Cota for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) { 9493468b59eSEmilio G. Cota if (tcg_init_ctx.temps[i].mem_base) { 9503468b59eSEmilio G. Cota ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps; 9513468b59eSEmilio G. Cota tcg_debug_assert(b >= 0 && b < n); 9523468b59eSEmilio G. Cota s->temps[i].mem_base = &s->temps[b]; 9533468b59eSEmilio G. Cota } 9543468b59eSEmilio G. Cota } 9553468b59eSEmilio G. Cota 9563468b59eSEmilio G. Cota /* Claim an entry in tcg_ctxs */ 957d73415a3SStefan Hajnoczi n = qatomic_fetch_inc(&n_tcg_ctxs); 9585cc8767dSLike Xu g_assert(n < ms->smp.max_cpus); 959d73415a3SStefan Hajnoczi qatomic_set(&tcg_ctxs[n], s); 9603468b59eSEmilio G. Cota 96138b47b19SEmilio G. Cota if (n > 0) { 96238b47b19SEmilio G. Cota alloc_tcg_plugin_context(s); 96338b47b19SEmilio G. Cota } 96438b47b19SEmilio G. Cota 9653468b59eSEmilio G. Cota tcg_ctx = s; 9663468b59eSEmilio G. Cota qemu_mutex_lock(®ion.lock); 9673468b59eSEmilio G. Cota err = tcg_region_initial_alloc__locked(tcg_ctx); 9683468b59eSEmilio G. Cota g_assert(!err); 9693468b59eSEmilio G. Cota qemu_mutex_unlock(®ion.lock); 9703468b59eSEmilio G. Cota } 9713468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */ 9723468b59eSEmilio G. Cota 9733468b59eSEmilio G. Cota /* 974e8feb96fSEmilio G. Cota * Returns the size (in bytes) of all translated code (i.e. from all regions) 975e8feb96fSEmilio G. Cota * currently in the cache. 976e8feb96fSEmilio G. Cota * See also: tcg_code_capacity() 977e8feb96fSEmilio G. Cota * Do not confuse with tcg_current_code_size(); that one applies to a single 978e8feb96fSEmilio G. Cota * TCG context. 979e8feb96fSEmilio G. Cota */ 980e8feb96fSEmilio G. Cota size_t tcg_code_size(void) 981e8feb96fSEmilio G. Cota { 982d73415a3SStefan Hajnoczi unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs); 983e8feb96fSEmilio G. Cota unsigned int i; 984e8feb96fSEmilio G. Cota size_t total; 985e8feb96fSEmilio G. Cota 986e8feb96fSEmilio G. Cota qemu_mutex_lock(®ion.lock); 987e8feb96fSEmilio G. Cota total = region.agg_size_full; 9883468b59eSEmilio G. Cota for (i = 0; i < n_ctxs; i++) { 989d73415a3SStefan Hajnoczi const TCGContext *s = qatomic_read(&tcg_ctxs[i]); 990e8feb96fSEmilio G. Cota size_t size; 991e8feb96fSEmilio G. Cota 992d73415a3SStefan Hajnoczi size = qatomic_read(&s->code_gen_ptr) - s->code_gen_buffer; 993e8feb96fSEmilio G. Cota g_assert(size <= s->code_gen_buffer_size); 994e8feb96fSEmilio G. Cota total += size; 995e8feb96fSEmilio G. Cota } 996e8feb96fSEmilio G. Cota qemu_mutex_unlock(®ion.lock); 997e8feb96fSEmilio G. Cota return total; 998e8feb96fSEmilio G. Cota } 999e8feb96fSEmilio G. Cota 1000e8feb96fSEmilio G. Cota /* 1001e8feb96fSEmilio G. Cota * Returns the code capacity (in bytes) of the entire cache, i.e. including all 1002e8feb96fSEmilio G. Cota * regions. 1003e8feb96fSEmilio G. Cota * See also: tcg_code_size() 1004e8feb96fSEmilio G. Cota */ 1005e8feb96fSEmilio G. Cota size_t tcg_code_capacity(void) 1006e8feb96fSEmilio G. Cota { 1007e8feb96fSEmilio G. Cota size_t guard_size, capacity; 1008e8feb96fSEmilio G. Cota 1009e8feb96fSEmilio G. Cota /* no need for synchronization; these variables are set at init time */ 1010e8feb96fSEmilio G. Cota guard_size = region.stride - region.size; 1011e8feb96fSEmilio G. Cota capacity = region.end + guard_size - region.start; 1012e8feb96fSEmilio G. Cota capacity -= region.n * (guard_size + TCG_HIGHWATER); 1013e8feb96fSEmilio G. Cota return capacity; 1014e8feb96fSEmilio G. Cota } 1015e8feb96fSEmilio G. Cota 1016128ed227SEmilio G. Cota size_t tcg_tb_phys_invalidate_count(void) 1017128ed227SEmilio G. Cota { 1018d73415a3SStefan Hajnoczi unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs); 1019128ed227SEmilio G. Cota unsigned int i; 1020128ed227SEmilio G. Cota size_t total = 0; 1021128ed227SEmilio G. Cota 1022128ed227SEmilio G. Cota for (i = 0; i < n_ctxs; i++) { 1023d73415a3SStefan Hajnoczi const TCGContext *s = qatomic_read(&tcg_ctxs[i]); 1024128ed227SEmilio G. Cota 1025d73415a3SStefan Hajnoczi total += qatomic_read(&s->tb_phys_invalidate_count); 1026128ed227SEmilio G. Cota } 1027128ed227SEmilio G. Cota return total; 1028128ed227SEmilio G. Cota } 1029128ed227SEmilio G. Cota 1030c896fe29Sbellard /* pool based memory allocation */ 1031c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size) 1032c896fe29Sbellard { 1033c896fe29Sbellard TCGPool *p; 1034c896fe29Sbellard int pool_size; 1035c896fe29Sbellard 1036c896fe29Sbellard if (size > TCG_POOL_CHUNK_SIZE) { 1037c896fe29Sbellard /* big malloc: insert a new pool (XXX: could optimize) */ 10387267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + size); 1039c896fe29Sbellard p->size = size; 10404055299eSKirill Batuzov p->next = s->pool_first_large; 10414055299eSKirill Batuzov s->pool_first_large = p; 10424055299eSKirill Batuzov return p->data; 1043c896fe29Sbellard } else { 1044c896fe29Sbellard p = s->pool_current; 1045c896fe29Sbellard if (!p) { 1046c896fe29Sbellard p = s->pool_first; 1047c896fe29Sbellard if (!p) 1048c896fe29Sbellard goto new_pool; 1049c896fe29Sbellard } else { 1050c896fe29Sbellard if (!p->next) { 1051c896fe29Sbellard new_pool: 1052c896fe29Sbellard pool_size = TCG_POOL_CHUNK_SIZE; 10537267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + pool_size); 1054c896fe29Sbellard p->size = pool_size; 1055c896fe29Sbellard p->next = NULL; 1056c896fe29Sbellard if (s->pool_current) 1057c896fe29Sbellard s->pool_current->next = p; 1058c896fe29Sbellard else 1059c896fe29Sbellard s->pool_first = p; 1060c896fe29Sbellard } else { 1061c896fe29Sbellard p = p->next; 1062c896fe29Sbellard } 1063c896fe29Sbellard } 1064c896fe29Sbellard } 1065c896fe29Sbellard s->pool_current = p; 1066c896fe29Sbellard s->pool_cur = p->data + size; 1067c896fe29Sbellard s->pool_end = p->data + p->size; 1068c896fe29Sbellard return p->data; 1069c896fe29Sbellard } 1070c896fe29Sbellard 1071c896fe29Sbellard void tcg_pool_reset(TCGContext *s) 1072c896fe29Sbellard { 10734055299eSKirill Batuzov TCGPool *p, *t; 10744055299eSKirill Batuzov for (p = s->pool_first_large; p; p = t) { 10754055299eSKirill Batuzov t = p->next; 10764055299eSKirill Batuzov g_free(p); 10774055299eSKirill Batuzov } 10784055299eSKirill Batuzov s->pool_first_large = NULL; 1079c896fe29Sbellard s->pool_cur = s->pool_end = NULL; 1080c896fe29Sbellard s->pool_current = NULL; 1081c896fe29Sbellard } 1082c896fe29Sbellard 1083100b5e01SRichard Henderson typedef struct TCGHelperInfo { 1084100b5e01SRichard Henderson void *func; 1085100b5e01SRichard Henderson const char *name; 1086afb49896SRichard Henderson unsigned flags; 1087afb49896SRichard Henderson unsigned sizemask; 1088100b5e01SRichard Henderson } TCGHelperInfo; 1089100b5e01SRichard Henderson 10902ef6175aSRichard Henderson #include "exec/helper-proto.h" 10912ef6175aSRichard Henderson 1092100b5e01SRichard Henderson static const TCGHelperInfo all_helpers[] = { 10932ef6175aSRichard Henderson #include "exec/helper-tcg.h" 1094100b5e01SRichard Henderson }; 1095619205fdSEmilio G. Cota static GHashTable *helper_table; 1096100b5e01SRichard Henderson 109791478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)]; 1098f69d277eSRichard Henderson static void process_op_defs(TCGContext *s); 10991c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type, 11001c2adb95SRichard Henderson TCGReg reg, const char *name); 110191478cefSRichard Henderson 1102c896fe29Sbellard void tcg_context_init(TCGContext *s) 1103c896fe29Sbellard { 1104100b5e01SRichard Henderson int op, total_args, n, i; 1105c896fe29Sbellard TCGOpDef *def; 1106c896fe29Sbellard TCGArgConstraint *args_ct; 11071c2adb95SRichard Henderson TCGTemp *ts; 1108c896fe29Sbellard 1109c896fe29Sbellard memset(s, 0, sizeof(*s)); 1110c896fe29Sbellard s->nb_globals = 0; 1111c896fe29Sbellard 1112c896fe29Sbellard /* Count total number of arguments and allocate the corresponding 1113c896fe29Sbellard space */ 1114c896fe29Sbellard total_args = 0; 1115c896fe29Sbellard for(op = 0; op < NB_OPS; op++) { 1116c896fe29Sbellard def = &tcg_op_defs[op]; 1117c896fe29Sbellard n = def->nb_iargs + def->nb_oargs; 1118c896fe29Sbellard total_args += n; 1119c896fe29Sbellard } 1120c896fe29Sbellard 1121bc2b17e6SRichard Henderson args_ct = g_new0(TCGArgConstraint, total_args); 1122c896fe29Sbellard 1123c896fe29Sbellard for(op = 0; op < NB_OPS; op++) { 1124c896fe29Sbellard def = &tcg_op_defs[op]; 1125c896fe29Sbellard def->args_ct = args_ct; 1126c896fe29Sbellard n = def->nb_iargs + def->nb_oargs; 1127c896fe29Sbellard args_ct += n; 1128c896fe29Sbellard } 1129c896fe29Sbellard 11305cd8f621SRichard Henderson /* Register helpers. */ 113184fd9dd3SRichard Henderson /* Use g_direct_hash/equal for direct pointer comparisons on func. */ 1132619205fdSEmilio G. Cota helper_table = g_hash_table_new(NULL, NULL); 113384fd9dd3SRichard Henderson 1134100b5e01SRichard Henderson for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) { 113584fd9dd3SRichard Henderson g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func, 113672866e82SRichard Henderson (gpointer)&all_helpers[i]); 1137100b5e01SRichard Henderson } 11385cd8f621SRichard Henderson 1139c896fe29Sbellard tcg_target_init(s); 1140f69d277eSRichard Henderson process_op_defs(s); 114191478cefSRichard Henderson 114291478cefSRichard Henderson /* Reverse the order of the saved registers, assuming they're all at 114391478cefSRichard Henderson the start of tcg_target_reg_alloc_order. */ 114491478cefSRichard Henderson for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) { 114591478cefSRichard Henderson int r = tcg_target_reg_alloc_order[n]; 114691478cefSRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) { 114791478cefSRichard Henderson break; 114891478cefSRichard Henderson } 114991478cefSRichard Henderson } 115091478cefSRichard Henderson for (i = 0; i < n; ++i) { 115191478cefSRichard Henderson indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i]; 115291478cefSRichard Henderson } 115391478cefSRichard Henderson for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) { 115491478cefSRichard Henderson indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i]; 115591478cefSRichard Henderson } 1156b1311c4aSEmilio G. Cota 115738b47b19SEmilio G. Cota alloc_tcg_plugin_context(s); 115838b47b19SEmilio G. Cota 1159b1311c4aSEmilio G. Cota tcg_ctx = s; 11603468b59eSEmilio G. Cota /* 11613468b59eSEmilio G. Cota * In user-mode we simply share the init context among threads, since we 11623468b59eSEmilio G. Cota * use a single region. See the documentation tcg_region_init() for the 11633468b59eSEmilio G. Cota * reasoning behind this. 11643468b59eSEmilio G. Cota * In softmmu we will have at most max_cpus TCG threads. 11653468b59eSEmilio G. Cota */ 11663468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY 1167df2cce29SEmilio G. Cota tcg_ctxs = &tcg_ctx; 1168df2cce29SEmilio G. Cota n_tcg_ctxs = 1; 11693468b59eSEmilio G. Cota #else 11705cc8767dSLike Xu MachineState *ms = MACHINE(qdev_get_machine()); 11715cc8767dSLike Xu unsigned int max_cpus = ms->smp.max_cpus; 11723468b59eSEmilio G. Cota tcg_ctxs = g_new(TCGContext *, max_cpus); 11733468b59eSEmilio G. Cota #endif 11741c2adb95SRichard Henderson 11751c2adb95SRichard Henderson tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0)); 11761c2adb95SRichard Henderson ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env"); 11771c2adb95SRichard Henderson cpu_env = temp_tcgv_ptr(ts); 11789002ec79SRichard Henderson } 1179b03cce8eSbellard 11806e3b2bfdSEmilio G. Cota /* 11816e3b2bfdSEmilio G. Cota * Allocate TBs right before their corresponding translated code, making 11826e3b2bfdSEmilio G. Cota * sure that TBs and code are on different cache lines. 11836e3b2bfdSEmilio G. Cota */ 11846e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s) 11856e3b2bfdSEmilio G. Cota { 11866e3b2bfdSEmilio G. Cota uintptr_t align = qemu_icache_linesize; 11876e3b2bfdSEmilio G. Cota TranslationBlock *tb; 11886e3b2bfdSEmilio G. Cota void *next; 11896e3b2bfdSEmilio G. Cota 1190e8feb96fSEmilio G. Cota retry: 11916e3b2bfdSEmilio G. Cota tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align); 11926e3b2bfdSEmilio G. Cota next = (void *)ROUND_UP((uintptr_t)(tb + 1), align); 11936e3b2bfdSEmilio G. Cota 11946e3b2bfdSEmilio G. Cota if (unlikely(next > s->code_gen_highwater)) { 1195e8feb96fSEmilio G. Cota if (tcg_region_alloc(s)) { 11966e3b2bfdSEmilio G. Cota return NULL; 11976e3b2bfdSEmilio G. Cota } 1198e8feb96fSEmilio G. Cota goto retry; 1199e8feb96fSEmilio G. Cota } 1200d73415a3SStefan Hajnoczi qatomic_set(&s->code_gen_ptr, next); 120157a26946SRichard Henderson s->data_gen_ptr = NULL; 12026e3b2bfdSEmilio G. Cota return tb; 12036e3b2bfdSEmilio G. Cota } 12046e3b2bfdSEmilio G. Cota 12059002ec79SRichard Henderson void tcg_prologue_init(TCGContext *s) 12069002ec79SRichard Henderson { 12078163b749SRichard Henderson size_t prologue_size, total_size; 12088163b749SRichard Henderson void *buf0, *buf1; 12098163b749SRichard Henderson 12108163b749SRichard Henderson /* Put the prologue at the beginning of code_gen_buffer. */ 12118163b749SRichard Henderson buf0 = s->code_gen_buffer; 12125b38ee31SRichard Henderson total_size = s->code_gen_buffer_size; 12138163b749SRichard Henderson s->code_ptr = buf0; 12148163b749SRichard Henderson s->code_buf = buf0; 12155b38ee31SRichard Henderson s->data_gen_ptr = NULL; 1216b91ccb31SRichard Henderson 1217db0c51a3SRichard Henderson /* 1218db0c51a3SRichard Henderson * The region trees are not yet configured, but tcg_splitwx_to_rx 1219db0c51a3SRichard Henderson * needs the bounds for an assert. 1220db0c51a3SRichard Henderson */ 1221db0c51a3SRichard Henderson region.start = buf0; 1222db0c51a3SRichard Henderson region.end = buf0 + total_size; 1223db0c51a3SRichard Henderson 1224b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 1225db0c51a3SRichard Henderson tcg_qemu_tb_exec = (tcg_prologue_fn *)tcg_splitwx_to_rx(buf0); 1226b91ccb31SRichard Henderson #endif 12278163b749SRichard Henderson 12285b38ee31SRichard Henderson /* Compute a high-water mark, at which we voluntarily flush the buffer 12295b38ee31SRichard Henderson and start over. The size here is arbitrary, significantly larger 12305b38ee31SRichard Henderson than we expect the code generation for any one opcode to require. */ 12315b38ee31SRichard Henderson s->code_gen_highwater = s->code_gen_buffer + (total_size - TCG_HIGHWATER); 12325b38ee31SRichard Henderson 12335b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 12345b38ee31SRichard Henderson s->pool_labels = NULL; 12355b38ee31SRichard Henderson #endif 12365b38ee31SRichard Henderson 1237653b87ebSRoman Bolshakov qemu_thread_jit_write(); 12388163b749SRichard Henderson /* Generate the prologue. */ 1239b03cce8eSbellard tcg_target_qemu_prologue(s); 12405b38ee31SRichard Henderson 12415b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 12425b38ee31SRichard Henderson /* Allow the prologue to put e.g. guest_base into a pool entry. */ 12435b38ee31SRichard Henderson { 12441768987bSRichard Henderson int result = tcg_out_pool_finalize(s); 12451768987bSRichard Henderson tcg_debug_assert(result == 0); 12465b38ee31SRichard Henderson } 12475b38ee31SRichard Henderson #endif 12485b38ee31SRichard Henderson 12498163b749SRichard Henderson buf1 = s->code_ptr; 1250df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 1251db0c51a3SRichard Henderson flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(buf0), (uintptr_t)buf0, 12521da8de39SRichard Henderson tcg_ptr_byte_diff(buf1, buf0)); 1253df5d2b16SRichard Henderson #endif 12548163b749SRichard Henderson 12558163b749SRichard Henderson /* Deduct the prologue from the buffer. */ 12568163b749SRichard Henderson prologue_size = tcg_current_code_size(s); 12578163b749SRichard Henderson s->code_gen_ptr = buf1; 12588163b749SRichard Henderson s->code_gen_buffer = buf1; 12598163b749SRichard Henderson s->code_buf = buf1; 12605b38ee31SRichard Henderson total_size -= prologue_size; 12618163b749SRichard Henderson s->code_gen_buffer_size = total_size; 12628163b749SRichard Henderson 1263755bf9e5SRichard Henderson tcg_register_jit(tcg_splitwx_to_rx(s->code_gen_buffer), total_size); 1264d6b64b2bSRichard Henderson 1265d6b64b2bSRichard Henderson #ifdef DEBUG_DISAS 1266d6b64b2bSRichard Henderson if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) { 1267fc59d2d8SRobert Foley FILE *logfile = qemu_log_lock(); 12688163b749SRichard Henderson qemu_log("PROLOGUE: [size=%zu]\n", prologue_size); 12695b38ee31SRichard Henderson if (s->data_gen_ptr) { 12705b38ee31SRichard Henderson size_t code_size = s->data_gen_ptr - buf0; 12715b38ee31SRichard Henderson size_t data_size = prologue_size - code_size; 12725b38ee31SRichard Henderson size_t i; 12735b38ee31SRichard Henderson 12744c389f6eSRichard Henderson log_disas(buf0, code_size); 12755b38ee31SRichard Henderson 12765b38ee31SRichard Henderson for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) { 12775b38ee31SRichard Henderson if (sizeof(tcg_target_ulong) == 8) { 12785b38ee31SRichard Henderson qemu_log("0x%08" PRIxPTR ": .quad 0x%016" PRIx64 "\n", 12795b38ee31SRichard Henderson (uintptr_t)s->data_gen_ptr + i, 12805b38ee31SRichard Henderson *(uint64_t *)(s->data_gen_ptr + i)); 12815b38ee31SRichard Henderson } else { 12825b38ee31SRichard Henderson qemu_log("0x%08" PRIxPTR ": .long 0x%08x\n", 12835b38ee31SRichard Henderson (uintptr_t)s->data_gen_ptr + i, 12845b38ee31SRichard Henderson *(uint32_t *)(s->data_gen_ptr + i)); 12855b38ee31SRichard Henderson } 12865b38ee31SRichard Henderson } 12875b38ee31SRichard Henderson } else { 12884c389f6eSRichard Henderson log_disas(buf0, prologue_size); 12895b38ee31SRichard Henderson } 1290d6b64b2bSRichard Henderson qemu_log("\n"); 1291d6b64b2bSRichard Henderson qemu_log_flush(); 1292fc59d2d8SRobert Foley qemu_log_unlock(logfile); 1293d6b64b2bSRichard Henderson } 1294d6b64b2bSRichard Henderson #endif 1295cedbcb01SEmilio G. Cota 1296cedbcb01SEmilio G. Cota /* Assert that goto_ptr is implemented completely. */ 1297cedbcb01SEmilio G. Cota if (TCG_TARGET_HAS_goto_ptr) { 12988b5c2b62SRichard Henderson tcg_debug_assert(tcg_code_gen_epilogue != NULL); 1299cedbcb01SEmilio G. Cota } 1300c896fe29Sbellard } 1301c896fe29Sbellard 1302c896fe29Sbellard void tcg_func_start(TCGContext *s) 1303c896fe29Sbellard { 1304c896fe29Sbellard tcg_pool_reset(s); 1305c896fe29Sbellard s->nb_temps = s->nb_globals; 13060ec9eabcSRichard Henderson 13070ec9eabcSRichard Henderson /* No temps have been previously allocated for size or locality. */ 13080ec9eabcSRichard Henderson memset(s->free_temps, 0, sizeof(s->free_temps)); 13090ec9eabcSRichard Henderson 1310c0522136SRichard Henderson /* No constant temps have been previously allocated. */ 1311c0522136SRichard Henderson for (int i = 0; i < TCG_TYPE_COUNT; ++i) { 1312c0522136SRichard Henderson if (s->const_table[i]) { 1313c0522136SRichard Henderson g_hash_table_remove_all(s->const_table[i]); 1314c0522136SRichard Henderson } 1315c0522136SRichard Henderson } 1316c0522136SRichard Henderson 1317abebf925SRichard Henderson s->nb_ops = 0; 1318c896fe29Sbellard s->nb_labels = 0; 1319c896fe29Sbellard s->current_frame_offset = s->frame_start; 1320c896fe29Sbellard 13210a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG 13220a209d4bSRichard Henderson s->goto_tb_issue_mask = 0; 13230a209d4bSRichard Henderson #endif 13240a209d4bSRichard Henderson 132515fa08f8SRichard Henderson QTAILQ_INIT(&s->ops); 132615fa08f8SRichard Henderson QTAILQ_INIT(&s->free_ops); 1327bef16ab4SRichard Henderson QSIMPLEQ_INIT(&s->labels); 1328c896fe29Sbellard } 1329c896fe29Sbellard 1330ae30e866SRichard Henderson static TCGTemp *tcg_temp_alloc(TCGContext *s) 13317ca4b752SRichard Henderson { 13327ca4b752SRichard Henderson int n = s->nb_temps++; 1333ae30e866SRichard Henderson 1334ae30e866SRichard Henderson if (n >= TCG_MAX_TEMPS) { 1335db6b7d0cSRichard Henderson tcg_raise_tb_overflow(s); 1336ae30e866SRichard Henderson } 13377ca4b752SRichard Henderson return memset(&s->temps[n], 0, sizeof(TCGTemp)); 13387ca4b752SRichard Henderson } 13397ca4b752SRichard Henderson 1340ae30e866SRichard Henderson static TCGTemp *tcg_global_alloc(TCGContext *s) 13417ca4b752SRichard Henderson { 1342fa477d25SRichard Henderson TCGTemp *ts; 1343fa477d25SRichard Henderson 13447ca4b752SRichard Henderson tcg_debug_assert(s->nb_globals == s->nb_temps); 1345ae30e866SRichard Henderson tcg_debug_assert(s->nb_globals < TCG_MAX_TEMPS); 13467ca4b752SRichard Henderson s->nb_globals++; 1347fa477d25SRichard Henderson ts = tcg_temp_alloc(s); 1348ee17db83SRichard Henderson ts->kind = TEMP_GLOBAL; 1349fa477d25SRichard Henderson 1350fa477d25SRichard Henderson return ts; 1351c896fe29Sbellard } 1352c896fe29Sbellard 1353085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type, 1354b6638662SRichard Henderson TCGReg reg, const char *name) 1355c896fe29Sbellard { 1356c896fe29Sbellard TCGTemp *ts; 1357c896fe29Sbellard 1358b3a62939SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type != TCG_TYPE_I32) { 1359c896fe29Sbellard tcg_abort(); 1360b3a62939SRichard Henderson } 13617ca4b752SRichard Henderson 13627ca4b752SRichard Henderson ts = tcg_global_alloc(s); 1363c896fe29Sbellard ts->base_type = type; 1364c896fe29Sbellard ts->type = type; 1365ee17db83SRichard Henderson ts->kind = TEMP_FIXED; 1366c896fe29Sbellard ts->reg = reg; 1367c896fe29Sbellard ts->name = name; 1368c896fe29Sbellard tcg_regset_set_reg(s->reserved_regs, reg); 13697ca4b752SRichard Henderson 1370085272b3SRichard Henderson return ts; 1371a7812ae4Spbrook } 1372a7812ae4Spbrook 1373b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size) 1374a7812ae4Spbrook { 1375b3a62939SRichard Henderson s->frame_start = start; 1376b3a62939SRichard Henderson s->frame_end = start + size; 1377085272b3SRichard Henderson s->frame_temp 1378085272b3SRichard Henderson = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame"); 1379b3a62939SRichard Henderson } 1380a7812ae4Spbrook 1381085272b3SRichard Henderson TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base, 1382e1ccc054SRichard Henderson intptr_t offset, const char *name) 1383c896fe29Sbellard { 1384b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1385dc41aa7dSRichard Henderson TCGTemp *base_ts = tcgv_ptr_temp(base); 13867ca4b752SRichard Henderson TCGTemp *ts = tcg_global_alloc(s); 1387b3915dbbSRichard Henderson int indirect_reg = 0, bigendian = 0; 13887ca4b752SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 13897ca4b752SRichard Henderson bigendian = 1; 13907ca4b752SRichard Henderson #endif 1391c896fe29Sbellard 1392c0522136SRichard Henderson switch (base_ts->kind) { 1393c0522136SRichard Henderson case TEMP_FIXED: 1394c0522136SRichard Henderson break; 1395c0522136SRichard Henderson case TEMP_GLOBAL: 13965a18407fSRichard Henderson /* We do not support double-indirect registers. */ 13975a18407fSRichard Henderson tcg_debug_assert(!base_ts->indirect_reg); 1398b3915dbbSRichard Henderson base_ts->indirect_base = 1; 13995a18407fSRichard Henderson s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64 14005a18407fSRichard Henderson ? 2 : 1); 14015a18407fSRichard Henderson indirect_reg = 1; 1402c0522136SRichard Henderson break; 1403c0522136SRichard Henderson default: 1404c0522136SRichard Henderson g_assert_not_reached(); 1405b3915dbbSRichard Henderson } 1406b3915dbbSRichard Henderson 14077ca4b752SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { 14087ca4b752SRichard Henderson TCGTemp *ts2 = tcg_global_alloc(s); 1409c896fe29Sbellard char buf[64]; 14107ca4b752SRichard Henderson 14117ca4b752SRichard Henderson ts->base_type = TCG_TYPE_I64; 1412c896fe29Sbellard ts->type = TCG_TYPE_I32; 1413b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg; 1414c896fe29Sbellard ts->mem_allocated = 1; 1415b3a62939SRichard Henderson ts->mem_base = base_ts; 14167ca4b752SRichard Henderson ts->mem_offset = offset + bigendian * 4; 1417c896fe29Sbellard pstrcpy(buf, sizeof(buf), name); 1418c896fe29Sbellard pstrcat(buf, sizeof(buf), "_0"); 1419c896fe29Sbellard ts->name = strdup(buf); 1420c896fe29Sbellard 14217ca4b752SRichard Henderson tcg_debug_assert(ts2 == ts + 1); 14227ca4b752SRichard Henderson ts2->base_type = TCG_TYPE_I64; 14237ca4b752SRichard Henderson ts2->type = TCG_TYPE_I32; 1424b3915dbbSRichard Henderson ts2->indirect_reg = indirect_reg; 14257ca4b752SRichard Henderson ts2->mem_allocated = 1; 14267ca4b752SRichard Henderson ts2->mem_base = base_ts; 14277ca4b752SRichard Henderson ts2->mem_offset = offset + (1 - bigendian) * 4; 1428c896fe29Sbellard pstrcpy(buf, sizeof(buf), name); 1429c896fe29Sbellard pstrcat(buf, sizeof(buf), "_1"); 1430120c1084SRichard Henderson ts2->name = strdup(buf); 14317ca4b752SRichard Henderson } else { 1432c896fe29Sbellard ts->base_type = type; 1433c896fe29Sbellard ts->type = type; 1434b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg; 1435c896fe29Sbellard ts->mem_allocated = 1; 1436b3a62939SRichard Henderson ts->mem_base = base_ts; 1437c896fe29Sbellard ts->mem_offset = offset; 1438c896fe29Sbellard ts->name = name; 1439c896fe29Sbellard } 1440085272b3SRichard Henderson return ts; 1441c896fe29Sbellard } 1442c896fe29Sbellard 14435bfa8034SRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, bool temp_local) 1444c896fe29Sbellard { 1445b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1446ee17db83SRichard Henderson TCGTempKind kind = temp_local ? TEMP_LOCAL : TEMP_NORMAL; 1447c896fe29Sbellard TCGTemp *ts; 1448641d5fbeSbellard int idx, k; 1449c896fe29Sbellard 14500ec9eabcSRichard Henderson k = type + (temp_local ? TCG_TYPE_COUNT : 0); 14510ec9eabcSRichard Henderson idx = find_first_bit(s->free_temps[k].l, TCG_MAX_TEMPS); 14520ec9eabcSRichard Henderson if (idx < TCG_MAX_TEMPS) { 14530ec9eabcSRichard Henderson /* There is already an available temp with the right type. */ 14540ec9eabcSRichard Henderson clear_bit(idx, s->free_temps[k].l); 14550ec9eabcSRichard Henderson 1456e8996ee0Sbellard ts = &s->temps[idx]; 1457e8996ee0Sbellard ts->temp_allocated = 1; 14587ca4b752SRichard Henderson tcg_debug_assert(ts->base_type == type); 1459ee17db83SRichard Henderson tcg_debug_assert(ts->kind == kind); 1460e8996ee0Sbellard } else { 14617ca4b752SRichard Henderson ts = tcg_temp_alloc(s); 14627ca4b752SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { 14637ca4b752SRichard Henderson TCGTemp *ts2 = tcg_temp_alloc(s); 14647ca4b752SRichard Henderson 1465c896fe29Sbellard ts->base_type = type; 1466c896fe29Sbellard ts->type = TCG_TYPE_I32; 1467e8996ee0Sbellard ts->temp_allocated = 1; 1468ee17db83SRichard Henderson ts->kind = kind; 14697ca4b752SRichard Henderson 14707ca4b752SRichard Henderson tcg_debug_assert(ts2 == ts + 1); 14717ca4b752SRichard Henderson ts2->base_type = TCG_TYPE_I64; 14727ca4b752SRichard Henderson ts2->type = TCG_TYPE_I32; 14737ca4b752SRichard Henderson ts2->temp_allocated = 1; 1474ee17db83SRichard Henderson ts2->kind = kind; 14757ca4b752SRichard Henderson } else { 1476c896fe29Sbellard ts->base_type = type; 1477c896fe29Sbellard ts->type = type; 1478e8996ee0Sbellard ts->temp_allocated = 1; 1479ee17db83SRichard Henderson ts->kind = kind; 1480c896fe29Sbellard } 1481e8996ee0Sbellard } 148227bfd83cSPeter Maydell 148327bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG) 148427bfd83cSPeter Maydell s->temps_in_use++; 148527bfd83cSPeter Maydell #endif 1486085272b3SRichard Henderson return ts; 1487c896fe29Sbellard } 1488c896fe29Sbellard 1489d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type) 1490d2fd745fSRichard Henderson { 1491d2fd745fSRichard Henderson TCGTemp *t; 1492d2fd745fSRichard Henderson 1493d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG 1494d2fd745fSRichard Henderson switch (type) { 1495d2fd745fSRichard Henderson case TCG_TYPE_V64: 1496d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v64); 1497d2fd745fSRichard Henderson break; 1498d2fd745fSRichard Henderson case TCG_TYPE_V128: 1499d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v128); 1500d2fd745fSRichard Henderson break; 1501d2fd745fSRichard Henderson case TCG_TYPE_V256: 1502d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v256); 1503d2fd745fSRichard Henderson break; 1504d2fd745fSRichard Henderson default: 1505d2fd745fSRichard Henderson g_assert_not_reached(); 1506d2fd745fSRichard Henderson } 1507d2fd745fSRichard Henderson #endif 1508d2fd745fSRichard Henderson 1509d2fd745fSRichard Henderson t = tcg_temp_new_internal(type, 0); 1510d2fd745fSRichard Henderson return temp_tcgv_vec(t); 1511d2fd745fSRichard Henderson } 1512d2fd745fSRichard Henderson 1513d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp. */ 1514d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match) 1515d2fd745fSRichard Henderson { 1516d2fd745fSRichard Henderson TCGTemp *t = tcgv_vec_temp(match); 1517d2fd745fSRichard Henderson 1518d2fd745fSRichard Henderson tcg_debug_assert(t->temp_allocated != 0); 1519d2fd745fSRichard Henderson 1520d2fd745fSRichard Henderson t = tcg_temp_new_internal(t->base_type, 0); 1521d2fd745fSRichard Henderson return temp_tcgv_vec(t); 1522d2fd745fSRichard Henderson } 1523d2fd745fSRichard Henderson 15245bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts) 1525c896fe29Sbellard { 1526b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1527085272b3SRichard Henderson int k, idx; 1528c896fe29Sbellard 1529c0522136SRichard Henderson /* In order to simplify users of tcg_constant_*, silently ignore free. */ 1530c0522136SRichard Henderson if (ts->kind == TEMP_CONST) { 1531c0522136SRichard Henderson return; 1532c0522136SRichard Henderson } 1533c0522136SRichard Henderson 153427bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG) 153527bfd83cSPeter Maydell s->temps_in_use--; 153627bfd83cSPeter Maydell if (s->temps_in_use < 0) { 153727bfd83cSPeter Maydell fprintf(stderr, "More temporaries freed than allocated!\n"); 153827bfd83cSPeter Maydell } 153927bfd83cSPeter Maydell #endif 154027bfd83cSPeter Maydell 1541ee17db83SRichard Henderson tcg_debug_assert(ts->kind < TEMP_GLOBAL); 1542eabb7b91SAurelien Jarno tcg_debug_assert(ts->temp_allocated != 0); 1543e8996ee0Sbellard ts->temp_allocated = 0; 15440ec9eabcSRichard Henderson 1545085272b3SRichard Henderson idx = temp_idx(ts); 1546ee17db83SRichard Henderson k = ts->base_type + (ts->kind == TEMP_NORMAL ? 0 : TCG_TYPE_COUNT); 15470ec9eabcSRichard Henderson set_bit(idx, s->free_temps[k].l); 1548e8996ee0Sbellard } 1549e8996ee0Sbellard 1550c0522136SRichard Henderson TCGTemp *tcg_constant_internal(TCGType type, int64_t val) 1551c0522136SRichard Henderson { 1552c0522136SRichard Henderson TCGContext *s = tcg_ctx; 1553c0522136SRichard Henderson GHashTable *h = s->const_table[type]; 1554c0522136SRichard Henderson TCGTemp *ts; 1555c0522136SRichard Henderson 1556c0522136SRichard Henderson if (h == NULL) { 1557c0522136SRichard Henderson h = g_hash_table_new(g_int64_hash, g_int64_equal); 1558c0522136SRichard Henderson s->const_table[type] = h; 1559c0522136SRichard Henderson } 1560c0522136SRichard Henderson 1561c0522136SRichard Henderson ts = g_hash_table_lookup(h, &val); 1562c0522136SRichard Henderson if (ts == NULL) { 1563c0522136SRichard Henderson ts = tcg_temp_alloc(s); 1564c0522136SRichard Henderson 1565c0522136SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { 1566c0522136SRichard Henderson TCGTemp *ts2 = tcg_temp_alloc(s); 1567c0522136SRichard Henderson 1568c0522136SRichard Henderson ts->base_type = TCG_TYPE_I64; 1569c0522136SRichard Henderson ts->type = TCG_TYPE_I32; 1570c0522136SRichard Henderson ts->kind = TEMP_CONST; 1571c0522136SRichard Henderson ts->temp_allocated = 1; 1572c0522136SRichard Henderson /* 1573c0522136SRichard Henderson * Retain the full value of the 64-bit constant in the low 1574c0522136SRichard Henderson * part, so that the hash table works. Actual uses will 1575c0522136SRichard Henderson * truncate the value to the low part. 1576c0522136SRichard Henderson */ 1577c0522136SRichard Henderson ts->val = val; 1578c0522136SRichard Henderson 1579c0522136SRichard Henderson tcg_debug_assert(ts2 == ts + 1); 1580c0522136SRichard Henderson ts2->base_type = TCG_TYPE_I64; 1581c0522136SRichard Henderson ts2->type = TCG_TYPE_I32; 1582c0522136SRichard Henderson ts2->kind = TEMP_CONST; 1583c0522136SRichard Henderson ts2->temp_allocated = 1; 1584c0522136SRichard Henderson ts2->val = val >> 32; 1585c0522136SRichard Henderson } else { 1586c0522136SRichard Henderson ts->base_type = type; 1587c0522136SRichard Henderson ts->type = type; 1588c0522136SRichard Henderson ts->kind = TEMP_CONST; 1589c0522136SRichard Henderson ts->temp_allocated = 1; 1590c0522136SRichard Henderson ts->val = val; 1591c0522136SRichard Henderson } 1592c0522136SRichard Henderson g_hash_table_insert(h, &ts->val, ts); 1593c0522136SRichard Henderson } 1594c0522136SRichard Henderson 1595c0522136SRichard Henderson return ts; 1596c0522136SRichard Henderson } 1597c0522136SRichard Henderson 1598c0522136SRichard Henderson TCGv_vec tcg_constant_vec(TCGType type, unsigned vece, int64_t val) 1599c0522136SRichard Henderson { 1600c0522136SRichard Henderson val = dup_const(vece, val); 1601c0522136SRichard Henderson return temp_tcgv_vec(tcg_constant_internal(type, val)); 1602c0522136SRichard Henderson } 1603c0522136SRichard Henderson 160488d4005bSRichard Henderson TCGv_vec tcg_constant_vec_matching(TCGv_vec match, unsigned vece, int64_t val) 160588d4005bSRichard Henderson { 160688d4005bSRichard Henderson TCGTemp *t = tcgv_vec_temp(match); 160788d4005bSRichard Henderson 160888d4005bSRichard Henderson tcg_debug_assert(t->temp_allocated != 0); 160988d4005bSRichard Henderson return tcg_constant_vec(t->base_type, vece, val); 161088d4005bSRichard Henderson } 161188d4005bSRichard Henderson 1612a7812ae4Spbrook TCGv_i32 tcg_const_i32(int32_t val) 1613a7812ae4Spbrook { 1614a7812ae4Spbrook TCGv_i32 t0; 1615a7812ae4Spbrook t0 = tcg_temp_new_i32(); 1616e8996ee0Sbellard tcg_gen_movi_i32(t0, val); 1617e8996ee0Sbellard return t0; 1618c896fe29Sbellard } 1619c896fe29Sbellard 1620a7812ae4Spbrook TCGv_i64 tcg_const_i64(int64_t val) 1621c896fe29Sbellard { 1622a7812ae4Spbrook TCGv_i64 t0; 1623a7812ae4Spbrook t0 = tcg_temp_new_i64(); 1624e8996ee0Sbellard tcg_gen_movi_i64(t0, val); 1625e8996ee0Sbellard return t0; 1626c896fe29Sbellard } 1627c896fe29Sbellard 1628a7812ae4Spbrook TCGv_i32 tcg_const_local_i32(int32_t val) 1629bdffd4a9Saurel32 { 1630a7812ae4Spbrook TCGv_i32 t0; 1631a7812ae4Spbrook t0 = tcg_temp_local_new_i32(); 1632bdffd4a9Saurel32 tcg_gen_movi_i32(t0, val); 1633bdffd4a9Saurel32 return t0; 1634bdffd4a9Saurel32 } 1635bdffd4a9Saurel32 1636a7812ae4Spbrook TCGv_i64 tcg_const_local_i64(int64_t val) 1637bdffd4a9Saurel32 { 1638a7812ae4Spbrook TCGv_i64 t0; 1639a7812ae4Spbrook t0 = tcg_temp_local_new_i64(); 1640bdffd4a9Saurel32 tcg_gen_movi_i64(t0, val); 1641bdffd4a9Saurel32 return t0; 1642bdffd4a9Saurel32 } 1643bdffd4a9Saurel32 164427bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG) 164527bfd83cSPeter Maydell void tcg_clear_temp_count(void) 164627bfd83cSPeter Maydell { 1647b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 164827bfd83cSPeter Maydell s->temps_in_use = 0; 164927bfd83cSPeter Maydell } 165027bfd83cSPeter Maydell 165127bfd83cSPeter Maydell int tcg_check_temp_count(void) 165227bfd83cSPeter Maydell { 1653b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 165427bfd83cSPeter Maydell if (s->temps_in_use) { 165527bfd83cSPeter Maydell /* Clear the count so that we don't give another 165627bfd83cSPeter Maydell * warning immediately next time around. 165727bfd83cSPeter Maydell */ 165827bfd83cSPeter Maydell s->temps_in_use = 0; 165927bfd83cSPeter Maydell return 1; 166027bfd83cSPeter Maydell } 166127bfd83cSPeter Maydell return 0; 166227bfd83cSPeter Maydell } 166327bfd83cSPeter Maydell #endif 166427bfd83cSPeter Maydell 1665be0f34b5SRichard Henderson /* Return true if OP may appear in the opcode stream. 1666be0f34b5SRichard Henderson Test the runtime variable that controls each opcode. */ 1667be0f34b5SRichard Henderson bool tcg_op_supported(TCGOpcode op) 1668be0f34b5SRichard Henderson { 1669d2fd745fSRichard Henderson const bool have_vec 1670d2fd745fSRichard Henderson = TCG_TARGET_HAS_v64 | TCG_TARGET_HAS_v128 | TCG_TARGET_HAS_v256; 1671d2fd745fSRichard Henderson 1672be0f34b5SRichard Henderson switch (op) { 1673be0f34b5SRichard Henderson case INDEX_op_discard: 1674be0f34b5SRichard Henderson case INDEX_op_set_label: 1675be0f34b5SRichard Henderson case INDEX_op_call: 1676be0f34b5SRichard Henderson case INDEX_op_br: 1677be0f34b5SRichard Henderson case INDEX_op_mb: 1678be0f34b5SRichard Henderson case INDEX_op_insn_start: 1679be0f34b5SRichard Henderson case INDEX_op_exit_tb: 1680be0f34b5SRichard Henderson case INDEX_op_goto_tb: 1681be0f34b5SRichard Henderson case INDEX_op_qemu_ld_i32: 1682be0f34b5SRichard Henderson case INDEX_op_qemu_st_i32: 1683be0f34b5SRichard Henderson case INDEX_op_qemu_ld_i64: 1684be0f34b5SRichard Henderson case INDEX_op_qemu_st_i64: 1685be0f34b5SRichard Henderson return true; 1686be0f34b5SRichard Henderson 168707ce0b05SRichard Henderson case INDEX_op_qemu_st8_i32: 168807ce0b05SRichard Henderson return TCG_TARGET_HAS_qemu_st8_i32; 168907ce0b05SRichard Henderson 1690be0f34b5SRichard Henderson case INDEX_op_goto_ptr: 1691be0f34b5SRichard Henderson return TCG_TARGET_HAS_goto_ptr; 1692be0f34b5SRichard Henderson 1693be0f34b5SRichard Henderson case INDEX_op_mov_i32: 1694be0f34b5SRichard Henderson case INDEX_op_setcond_i32: 1695be0f34b5SRichard Henderson case INDEX_op_brcond_i32: 1696be0f34b5SRichard Henderson case INDEX_op_ld8u_i32: 1697be0f34b5SRichard Henderson case INDEX_op_ld8s_i32: 1698be0f34b5SRichard Henderson case INDEX_op_ld16u_i32: 1699be0f34b5SRichard Henderson case INDEX_op_ld16s_i32: 1700be0f34b5SRichard Henderson case INDEX_op_ld_i32: 1701be0f34b5SRichard Henderson case INDEX_op_st8_i32: 1702be0f34b5SRichard Henderson case INDEX_op_st16_i32: 1703be0f34b5SRichard Henderson case INDEX_op_st_i32: 1704be0f34b5SRichard Henderson case INDEX_op_add_i32: 1705be0f34b5SRichard Henderson case INDEX_op_sub_i32: 1706be0f34b5SRichard Henderson case INDEX_op_mul_i32: 1707be0f34b5SRichard Henderson case INDEX_op_and_i32: 1708be0f34b5SRichard Henderson case INDEX_op_or_i32: 1709be0f34b5SRichard Henderson case INDEX_op_xor_i32: 1710be0f34b5SRichard Henderson case INDEX_op_shl_i32: 1711be0f34b5SRichard Henderson case INDEX_op_shr_i32: 1712be0f34b5SRichard Henderson case INDEX_op_sar_i32: 1713be0f34b5SRichard Henderson return true; 1714be0f34b5SRichard Henderson 1715be0f34b5SRichard Henderson case INDEX_op_movcond_i32: 1716be0f34b5SRichard Henderson return TCG_TARGET_HAS_movcond_i32; 1717be0f34b5SRichard Henderson case INDEX_op_div_i32: 1718be0f34b5SRichard Henderson case INDEX_op_divu_i32: 1719be0f34b5SRichard Henderson return TCG_TARGET_HAS_div_i32; 1720be0f34b5SRichard Henderson case INDEX_op_rem_i32: 1721be0f34b5SRichard Henderson case INDEX_op_remu_i32: 1722be0f34b5SRichard Henderson return TCG_TARGET_HAS_rem_i32; 1723be0f34b5SRichard Henderson case INDEX_op_div2_i32: 1724be0f34b5SRichard Henderson case INDEX_op_divu2_i32: 1725be0f34b5SRichard Henderson return TCG_TARGET_HAS_div2_i32; 1726be0f34b5SRichard Henderson case INDEX_op_rotl_i32: 1727be0f34b5SRichard Henderson case INDEX_op_rotr_i32: 1728be0f34b5SRichard Henderson return TCG_TARGET_HAS_rot_i32; 1729be0f34b5SRichard Henderson case INDEX_op_deposit_i32: 1730be0f34b5SRichard Henderson return TCG_TARGET_HAS_deposit_i32; 1731be0f34b5SRichard Henderson case INDEX_op_extract_i32: 1732be0f34b5SRichard Henderson return TCG_TARGET_HAS_extract_i32; 1733be0f34b5SRichard Henderson case INDEX_op_sextract_i32: 1734be0f34b5SRichard Henderson return TCG_TARGET_HAS_sextract_i32; 1735fce1296fSRichard Henderson case INDEX_op_extract2_i32: 1736fce1296fSRichard Henderson return TCG_TARGET_HAS_extract2_i32; 1737be0f34b5SRichard Henderson case INDEX_op_add2_i32: 1738be0f34b5SRichard Henderson return TCG_TARGET_HAS_add2_i32; 1739be0f34b5SRichard Henderson case INDEX_op_sub2_i32: 1740be0f34b5SRichard Henderson return TCG_TARGET_HAS_sub2_i32; 1741be0f34b5SRichard Henderson case INDEX_op_mulu2_i32: 1742be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulu2_i32; 1743be0f34b5SRichard Henderson case INDEX_op_muls2_i32: 1744be0f34b5SRichard Henderson return TCG_TARGET_HAS_muls2_i32; 1745be0f34b5SRichard Henderson case INDEX_op_muluh_i32: 1746be0f34b5SRichard Henderson return TCG_TARGET_HAS_muluh_i32; 1747be0f34b5SRichard Henderson case INDEX_op_mulsh_i32: 1748be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulsh_i32; 1749be0f34b5SRichard Henderson case INDEX_op_ext8s_i32: 1750be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8s_i32; 1751be0f34b5SRichard Henderson case INDEX_op_ext16s_i32: 1752be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16s_i32; 1753be0f34b5SRichard Henderson case INDEX_op_ext8u_i32: 1754be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8u_i32; 1755be0f34b5SRichard Henderson case INDEX_op_ext16u_i32: 1756be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16u_i32; 1757be0f34b5SRichard Henderson case INDEX_op_bswap16_i32: 1758be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap16_i32; 1759be0f34b5SRichard Henderson case INDEX_op_bswap32_i32: 1760be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap32_i32; 1761be0f34b5SRichard Henderson case INDEX_op_not_i32: 1762be0f34b5SRichard Henderson return TCG_TARGET_HAS_not_i32; 1763be0f34b5SRichard Henderson case INDEX_op_neg_i32: 1764be0f34b5SRichard Henderson return TCG_TARGET_HAS_neg_i32; 1765be0f34b5SRichard Henderson case INDEX_op_andc_i32: 1766be0f34b5SRichard Henderson return TCG_TARGET_HAS_andc_i32; 1767be0f34b5SRichard Henderson case INDEX_op_orc_i32: 1768be0f34b5SRichard Henderson return TCG_TARGET_HAS_orc_i32; 1769be0f34b5SRichard Henderson case INDEX_op_eqv_i32: 1770be0f34b5SRichard Henderson return TCG_TARGET_HAS_eqv_i32; 1771be0f34b5SRichard Henderson case INDEX_op_nand_i32: 1772be0f34b5SRichard Henderson return TCG_TARGET_HAS_nand_i32; 1773be0f34b5SRichard Henderson case INDEX_op_nor_i32: 1774be0f34b5SRichard Henderson return TCG_TARGET_HAS_nor_i32; 1775be0f34b5SRichard Henderson case INDEX_op_clz_i32: 1776be0f34b5SRichard Henderson return TCG_TARGET_HAS_clz_i32; 1777be0f34b5SRichard Henderson case INDEX_op_ctz_i32: 1778be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctz_i32; 1779be0f34b5SRichard Henderson case INDEX_op_ctpop_i32: 1780be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctpop_i32; 1781be0f34b5SRichard Henderson 1782be0f34b5SRichard Henderson case INDEX_op_brcond2_i32: 1783be0f34b5SRichard Henderson case INDEX_op_setcond2_i32: 1784be0f34b5SRichard Henderson return TCG_TARGET_REG_BITS == 32; 1785be0f34b5SRichard Henderson 1786be0f34b5SRichard Henderson case INDEX_op_mov_i64: 1787be0f34b5SRichard Henderson case INDEX_op_setcond_i64: 1788be0f34b5SRichard Henderson case INDEX_op_brcond_i64: 1789be0f34b5SRichard Henderson case INDEX_op_ld8u_i64: 1790be0f34b5SRichard Henderson case INDEX_op_ld8s_i64: 1791be0f34b5SRichard Henderson case INDEX_op_ld16u_i64: 1792be0f34b5SRichard Henderson case INDEX_op_ld16s_i64: 1793be0f34b5SRichard Henderson case INDEX_op_ld32u_i64: 1794be0f34b5SRichard Henderson case INDEX_op_ld32s_i64: 1795be0f34b5SRichard Henderson case INDEX_op_ld_i64: 1796be0f34b5SRichard Henderson case INDEX_op_st8_i64: 1797be0f34b5SRichard Henderson case INDEX_op_st16_i64: 1798be0f34b5SRichard Henderson case INDEX_op_st32_i64: 1799be0f34b5SRichard Henderson case INDEX_op_st_i64: 1800be0f34b5SRichard Henderson case INDEX_op_add_i64: 1801be0f34b5SRichard Henderson case INDEX_op_sub_i64: 1802be0f34b5SRichard Henderson case INDEX_op_mul_i64: 1803be0f34b5SRichard Henderson case INDEX_op_and_i64: 1804be0f34b5SRichard Henderson case INDEX_op_or_i64: 1805be0f34b5SRichard Henderson case INDEX_op_xor_i64: 1806be0f34b5SRichard Henderson case INDEX_op_shl_i64: 1807be0f34b5SRichard Henderson case INDEX_op_shr_i64: 1808be0f34b5SRichard Henderson case INDEX_op_sar_i64: 1809be0f34b5SRichard Henderson case INDEX_op_ext_i32_i64: 1810be0f34b5SRichard Henderson case INDEX_op_extu_i32_i64: 1811be0f34b5SRichard Henderson return TCG_TARGET_REG_BITS == 64; 1812be0f34b5SRichard Henderson 1813be0f34b5SRichard Henderson case INDEX_op_movcond_i64: 1814be0f34b5SRichard Henderson return TCG_TARGET_HAS_movcond_i64; 1815be0f34b5SRichard Henderson case INDEX_op_div_i64: 1816be0f34b5SRichard Henderson case INDEX_op_divu_i64: 1817be0f34b5SRichard Henderson return TCG_TARGET_HAS_div_i64; 1818be0f34b5SRichard Henderson case INDEX_op_rem_i64: 1819be0f34b5SRichard Henderson case INDEX_op_remu_i64: 1820be0f34b5SRichard Henderson return TCG_TARGET_HAS_rem_i64; 1821be0f34b5SRichard Henderson case INDEX_op_div2_i64: 1822be0f34b5SRichard Henderson case INDEX_op_divu2_i64: 1823be0f34b5SRichard Henderson return TCG_TARGET_HAS_div2_i64; 1824be0f34b5SRichard Henderson case INDEX_op_rotl_i64: 1825be0f34b5SRichard Henderson case INDEX_op_rotr_i64: 1826be0f34b5SRichard Henderson return TCG_TARGET_HAS_rot_i64; 1827be0f34b5SRichard Henderson case INDEX_op_deposit_i64: 1828be0f34b5SRichard Henderson return TCG_TARGET_HAS_deposit_i64; 1829be0f34b5SRichard Henderson case INDEX_op_extract_i64: 1830be0f34b5SRichard Henderson return TCG_TARGET_HAS_extract_i64; 1831be0f34b5SRichard Henderson case INDEX_op_sextract_i64: 1832be0f34b5SRichard Henderson return TCG_TARGET_HAS_sextract_i64; 1833fce1296fSRichard Henderson case INDEX_op_extract2_i64: 1834fce1296fSRichard Henderson return TCG_TARGET_HAS_extract2_i64; 1835be0f34b5SRichard Henderson case INDEX_op_extrl_i64_i32: 1836be0f34b5SRichard Henderson return TCG_TARGET_HAS_extrl_i64_i32; 1837be0f34b5SRichard Henderson case INDEX_op_extrh_i64_i32: 1838be0f34b5SRichard Henderson return TCG_TARGET_HAS_extrh_i64_i32; 1839be0f34b5SRichard Henderson case INDEX_op_ext8s_i64: 1840be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8s_i64; 1841be0f34b5SRichard Henderson case INDEX_op_ext16s_i64: 1842be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16s_i64; 1843be0f34b5SRichard Henderson case INDEX_op_ext32s_i64: 1844be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext32s_i64; 1845be0f34b5SRichard Henderson case INDEX_op_ext8u_i64: 1846be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8u_i64; 1847be0f34b5SRichard Henderson case INDEX_op_ext16u_i64: 1848be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16u_i64; 1849be0f34b5SRichard Henderson case INDEX_op_ext32u_i64: 1850be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext32u_i64; 1851be0f34b5SRichard Henderson case INDEX_op_bswap16_i64: 1852be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap16_i64; 1853be0f34b5SRichard Henderson case INDEX_op_bswap32_i64: 1854be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap32_i64; 1855be0f34b5SRichard Henderson case INDEX_op_bswap64_i64: 1856be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap64_i64; 1857be0f34b5SRichard Henderson case INDEX_op_not_i64: 1858be0f34b5SRichard Henderson return TCG_TARGET_HAS_not_i64; 1859be0f34b5SRichard Henderson case INDEX_op_neg_i64: 1860be0f34b5SRichard Henderson return TCG_TARGET_HAS_neg_i64; 1861be0f34b5SRichard Henderson case INDEX_op_andc_i64: 1862be0f34b5SRichard Henderson return TCG_TARGET_HAS_andc_i64; 1863be0f34b5SRichard Henderson case INDEX_op_orc_i64: 1864be0f34b5SRichard Henderson return TCG_TARGET_HAS_orc_i64; 1865be0f34b5SRichard Henderson case INDEX_op_eqv_i64: 1866be0f34b5SRichard Henderson return TCG_TARGET_HAS_eqv_i64; 1867be0f34b5SRichard Henderson case INDEX_op_nand_i64: 1868be0f34b5SRichard Henderson return TCG_TARGET_HAS_nand_i64; 1869be0f34b5SRichard Henderson case INDEX_op_nor_i64: 1870be0f34b5SRichard Henderson return TCG_TARGET_HAS_nor_i64; 1871be0f34b5SRichard Henderson case INDEX_op_clz_i64: 1872be0f34b5SRichard Henderson return TCG_TARGET_HAS_clz_i64; 1873be0f34b5SRichard Henderson case INDEX_op_ctz_i64: 1874be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctz_i64; 1875be0f34b5SRichard Henderson case INDEX_op_ctpop_i64: 1876be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctpop_i64; 1877be0f34b5SRichard Henderson case INDEX_op_add2_i64: 1878be0f34b5SRichard Henderson return TCG_TARGET_HAS_add2_i64; 1879be0f34b5SRichard Henderson case INDEX_op_sub2_i64: 1880be0f34b5SRichard Henderson return TCG_TARGET_HAS_sub2_i64; 1881be0f34b5SRichard Henderson case INDEX_op_mulu2_i64: 1882be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulu2_i64; 1883be0f34b5SRichard Henderson case INDEX_op_muls2_i64: 1884be0f34b5SRichard Henderson return TCG_TARGET_HAS_muls2_i64; 1885be0f34b5SRichard Henderson case INDEX_op_muluh_i64: 1886be0f34b5SRichard Henderson return TCG_TARGET_HAS_muluh_i64; 1887be0f34b5SRichard Henderson case INDEX_op_mulsh_i64: 1888be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulsh_i64; 1889be0f34b5SRichard Henderson 1890d2fd745fSRichard Henderson case INDEX_op_mov_vec: 1891d2fd745fSRichard Henderson case INDEX_op_dup_vec: 189237ee55a0SRichard Henderson case INDEX_op_dupm_vec: 1893d2fd745fSRichard Henderson case INDEX_op_ld_vec: 1894d2fd745fSRichard Henderson case INDEX_op_st_vec: 1895d2fd745fSRichard Henderson case INDEX_op_add_vec: 1896d2fd745fSRichard Henderson case INDEX_op_sub_vec: 1897d2fd745fSRichard Henderson case INDEX_op_and_vec: 1898d2fd745fSRichard Henderson case INDEX_op_or_vec: 1899d2fd745fSRichard Henderson case INDEX_op_xor_vec: 1900212be173SRichard Henderson case INDEX_op_cmp_vec: 1901d2fd745fSRichard Henderson return have_vec; 1902d2fd745fSRichard Henderson case INDEX_op_dup2_vec: 1903d2fd745fSRichard Henderson return have_vec && TCG_TARGET_REG_BITS == 32; 1904d2fd745fSRichard Henderson case INDEX_op_not_vec: 1905d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_not_vec; 1906d2fd745fSRichard Henderson case INDEX_op_neg_vec: 1907d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_neg_vec; 1908bcefc902SRichard Henderson case INDEX_op_abs_vec: 1909bcefc902SRichard Henderson return have_vec && TCG_TARGET_HAS_abs_vec; 1910d2fd745fSRichard Henderson case INDEX_op_andc_vec: 1911d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_andc_vec; 1912d2fd745fSRichard Henderson case INDEX_op_orc_vec: 1913d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_orc_vec; 19143774030aSRichard Henderson case INDEX_op_mul_vec: 19153774030aSRichard Henderson return have_vec && TCG_TARGET_HAS_mul_vec; 1916d0ec9796SRichard Henderson case INDEX_op_shli_vec: 1917d0ec9796SRichard Henderson case INDEX_op_shri_vec: 1918d0ec9796SRichard Henderson case INDEX_op_sari_vec: 1919d0ec9796SRichard Henderson return have_vec && TCG_TARGET_HAS_shi_vec; 1920d0ec9796SRichard Henderson case INDEX_op_shls_vec: 1921d0ec9796SRichard Henderson case INDEX_op_shrs_vec: 1922d0ec9796SRichard Henderson case INDEX_op_sars_vec: 1923d0ec9796SRichard Henderson return have_vec && TCG_TARGET_HAS_shs_vec; 1924d0ec9796SRichard Henderson case INDEX_op_shlv_vec: 1925d0ec9796SRichard Henderson case INDEX_op_shrv_vec: 1926d0ec9796SRichard Henderson case INDEX_op_sarv_vec: 1927d0ec9796SRichard Henderson return have_vec && TCG_TARGET_HAS_shv_vec; 1928b0f7e744SRichard Henderson case INDEX_op_rotli_vec: 1929b0f7e744SRichard Henderson return have_vec && TCG_TARGET_HAS_roti_vec; 193023850a74SRichard Henderson case INDEX_op_rotls_vec: 193123850a74SRichard Henderson return have_vec && TCG_TARGET_HAS_rots_vec; 19325d0ceda9SRichard Henderson case INDEX_op_rotlv_vec: 19335d0ceda9SRichard Henderson case INDEX_op_rotrv_vec: 19345d0ceda9SRichard Henderson return have_vec && TCG_TARGET_HAS_rotv_vec; 19358afaf050SRichard Henderson case INDEX_op_ssadd_vec: 19368afaf050SRichard Henderson case INDEX_op_usadd_vec: 19378afaf050SRichard Henderson case INDEX_op_sssub_vec: 19388afaf050SRichard Henderson case INDEX_op_ussub_vec: 19398afaf050SRichard Henderson return have_vec && TCG_TARGET_HAS_sat_vec; 1940dd0a0fcdSRichard Henderson case INDEX_op_smin_vec: 1941dd0a0fcdSRichard Henderson case INDEX_op_umin_vec: 1942dd0a0fcdSRichard Henderson case INDEX_op_smax_vec: 1943dd0a0fcdSRichard Henderson case INDEX_op_umax_vec: 1944dd0a0fcdSRichard Henderson return have_vec && TCG_TARGET_HAS_minmax_vec; 194538dc1294SRichard Henderson case INDEX_op_bitsel_vec: 194638dc1294SRichard Henderson return have_vec && TCG_TARGET_HAS_bitsel_vec; 1947f75da298SRichard Henderson case INDEX_op_cmpsel_vec: 1948f75da298SRichard Henderson return have_vec && TCG_TARGET_HAS_cmpsel_vec; 1949d2fd745fSRichard Henderson 1950db432672SRichard Henderson default: 1951db432672SRichard Henderson tcg_debug_assert(op > INDEX_op_last_generic && op < NB_OPS); 1952db432672SRichard Henderson return true; 1953be0f34b5SRichard Henderson } 1954be0f34b5SRichard Henderson } 1955be0f34b5SRichard Henderson 195639cf05d3Sbellard /* Note: we convert the 64 bit args to 32 bit and do some alignment 195739cf05d3Sbellard and endian swap. Maybe it would be better to do the alignment 195839cf05d3Sbellard and endian swap in tcg_reg_alloc_call(). */ 1959ae8b75dcSRichard Henderson void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args) 1960c896fe29Sbellard { 196175e8b9b7SRichard Henderson int i, real_args, nb_rets, pi; 1962bbb8a1b4SRichard Henderson unsigned sizemask, flags; 1963afb49896SRichard Henderson TCGHelperInfo *info; 196475e8b9b7SRichard Henderson TCGOp *op; 1965afb49896SRichard Henderson 1966619205fdSEmilio G. Cota info = g_hash_table_lookup(helper_table, (gpointer)func); 1967bbb8a1b4SRichard Henderson flags = info->flags; 1968bbb8a1b4SRichard Henderson sizemask = info->sizemask; 19692bece2c8SRichard Henderson 197038b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN 197138b47b19SEmilio G. Cota /* detect non-plugin helpers */ 197238b47b19SEmilio G. Cota if (tcg_ctx->plugin_insn && unlikely(strncmp(info->name, "plugin_", 7))) { 197338b47b19SEmilio G. Cota tcg_ctx->plugin_insn->calls_helpers = true; 197438b47b19SEmilio G. Cota } 197538b47b19SEmilio G. Cota #endif 197638b47b19SEmilio G. Cota 197734b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \ 197834b1a49cSRichard Henderson && !defined(CONFIG_TCG_INTERPRETER) 197934b1a49cSRichard Henderson /* We have 64-bit values in one register, but need to pass as two 198034b1a49cSRichard Henderson separate parameters. Split them. */ 198134b1a49cSRichard Henderson int orig_sizemask = sizemask; 198234b1a49cSRichard Henderson int orig_nargs = nargs; 198334b1a49cSRichard Henderson TCGv_i64 retl, reth; 1984ae8b75dcSRichard Henderson TCGTemp *split_args[MAX_OPC_PARAM]; 198534b1a49cSRichard Henderson 1986f764718dSRichard Henderson retl = NULL; 1987f764718dSRichard Henderson reth = NULL; 198834b1a49cSRichard Henderson if (sizemask != 0) { 198934b1a49cSRichard Henderson for (i = real_args = 0; i < nargs; ++i) { 199034b1a49cSRichard Henderson int is_64bit = sizemask & (1 << (i+1)*2); 199134b1a49cSRichard Henderson if (is_64bit) { 1992085272b3SRichard Henderson TCGv_i64 orig = temp_tcgv_i64(args[i]); 199334b1a49cSRichard Henderson TCGv_i32 h = tcg_temp_new_i32(); 199434b1a49cSRichard Henderson TCGv_i32 l = tcg_temp_new_i32(); 199534b1a49cSRichard Henderson tcg_gen_extr_i64_i32(l, h, orig); 1996ae8b75dcSRichard Henderson split_args[real_args++] = tcgv_i32_temp(h); 1997ae8b75dcSRichard Henderson split_args[real_args++] = tcgv_i32_temp(l); 199834b1a49cSRichard Henderson } else { 199934b1a49cSRichard Henderson split_args[real_args++] = args[i]; 200034b1a49cSRichard Henderson } 200134b1a49cSRichard Henderson } 200234b1a49cSRichard Henderson nargs = real_args; 200334b1a49cSRichard Henderson args = split_args; 200434b1a49cSRichard Henderson sizemask = 0; 200534b1a49cSRichard Henderson } 200634b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64 20072bece2c8SRichard Henderson for (i = 0; i < nargs; ++i) { 20082bece2c8SRichard Henderson int is_64bit = sizemask & (1 << (i+1)*2); 20092bece2c8SRichard Henderson int is_signed = sizemask & (2 << (i+1)*2); 20102bece2c8SRichard Henderson if (!is_64bit) { 20112bece2c8SRichard Henderson TCGv_i64 temp = tcg_temp_new_i64(); 2012085272b3SRichard Henderson TCGv_i64 orig = temp_tcgv_i64(args[i]); 20132bece2c8SRichard Henderson if (is_signed) { 20142bece2c8SRichard Henderson tcg_gen_ext32s_i64(temp, orig); 20152bece2c8SRichard Henderson } else { 20162bece2c8SRichard Henderson tcg_gen_ext32u_i64(temp, orig); 20172bece2c8SRichard Henderson } 2018ae8b75dcSRichard Henderson args[i] = tcgv_i64_temp(temp); 20192bece2c8SRichard Henderson } 20202bece2c8SRichard Henderson } 20212bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */ 20222bece2c8SRichard Henderson 202315fa08f8SRichard Henderson op = tcg_emit_op(INDEX_op_call); 202475e8b9b7SRichard Henderson 202575e8b9b7SRichard Henderson pi = 0; 2026ae8b75dcSRichard Henderson if (ret != NULL) { 202734b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \ 202834b1a49cSRichard Henderson && !defined(CONFIG_TCG_INTERPRETER) 202934b1a49cSRichard Henderson if (orig_sizemask & 1) { 203034b1a49cSRichard Henderson /* The 32-bit ABI is going to return the 64-bit value in 203134b1a49cSRichard Henderson the %o0/%o1 register pair. Prepare for this by using 203234b1a49cSRichard Henderson two return temporaries, and reassemble below. */ 203334b1a49cSRichard Henderson retl = tcg_temp_new_i64(); 203434b1a49cSRichard Henderson reth = tcg_temp_new_i64(); 2035ae8b75dcSRichard Henderson op->args[pi++] = tcgv_i64_arg(reth); 2036ae8b75dcSRichard Henderson op->args[pi++] = tcgv_i64_arg(retl); 203734b1a49cSRichard Henderson nb_rets = 2; 203834b1a49cSRichard Henderson } else { 2039ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(ret); 204034b1a49cSRichard Henderson nb_rets = 1; 204134b1a49cSRichard Henderson } 204234b1a49cSRichard Henderson #else 204334b1a49cSRichard Henderson if (TCG_TARGET_REG_BITS < 64 && (sizemask & 1)) { 204402eb19d0SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 2045ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(ret + 1); 2046ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(ret); 2047a7812ae4Spbrook #else 2048ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(ret); 2049ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(ret + 1); 2050a7812ae4Spbrook #endif 2051a7812ae4Spbrook nb_rets = 2; 205234b1a49cSRichard Henderson } else { 2053ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(ret); 2054a7812ae4Spbrook nb_rets = 1; 2055a7812ae4Spbrook } 205634b1a49cSRichard Henderson #endif 2057a7812ae4Spbrook } else { 2058a7812ae4Spbrook nb_rets = 0; 2059a7812ae4Spbrook } 2060cd9090aaSRichard Henderson TCGOP_CALLO(op) = nb_rets; 206175e8b9b7SRichard Henderson 2062a7812ae4Spbrook real_args = 0; 2063a7812ae4Spbrook for (i = 0; i < nargs; i++) { 20642bece2c8SRichard Henderson int is_64bit = sizemask & (1 << (i+1)*2); 2065bbb8a1b4SRichard Henderson if (TCG_TARGET_REG_BITS < 64 && is_64bit) { 206639cf05d3Sbellard #ifdef TCG_TARGET_CALL_ALIGN_ARGS 206739cf05d3Sbellard /* some targets want aligned 64 bit args */ 2068ebd486d5Smalc if (real_args & 1) { 206975e8b9b7SRichard Henderson op->args[pi++] = TCG_CALL_DUMMY_ARG; 2070ebd486d5Smalc real_args++; 207139cf05d3Sbellard } 207239cf05d3Sbellard #endif 20733f90f252SRichard Henderson /* If stack grows up, then we will be placing successive 20743f90f252SRichard Henderson arguments at lower addresses, which means we need to 20753f90f252SRichard Henderson reverse the order compared to how we would normally 20763f90f252SRichard Henderson treat either big or little-endian. For those arguments 20773f90f252SRichard Henderson that will wind up in registers, this still works for 20783f90f252SRichard Henderson HPPA (the only current STACK_GROWSUP target) since the 20793f90f252SRichard Henderson argument registers are *also* allocated in decreasing 20803f90f252SRichard Henderson order. If another such target is added, this logic may 20813f90f252SRichard Henderson have to get more complicated to differentiate between 20823f90f252SRichard Henderson stack arguments and register arguments. */ 208302eb19d0SRichard Henderson #if defined(HOST_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP) 2084ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(args[i] + 1); 2085ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(args[i]); 2086c896fe29Sbellard #else 2087ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(args[i]); 2088ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(args[i] + 1); 2089c896fe29Sbellard #endif 2090a7812ae4Spbrook real_args += 2; 20912bece2c8SRichard Henderson continue; 20922bece2c8SRichard Henderson } 20932bece2c8SRichard Henderson 2094ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(args[i]); 2095a7812ae4Spbrook real_args++; 2096c896fe29Sbellard } 209775e8b9b7SRichard Henderson op->args[pi++] = (uintptr_t)func; 209875e8b9b7SRichard Henderson op->args[pi++] = flags; 2099cd9090aaSRichard Henderson TCGOP_CALLI(op) = real_args; 2100a7812ae4Spbrook 210175e8b9b7SRichard Henderson /* Make sure the fields didn't overflow. */ 2102cd9090aaSRichard Henderson tcg_debug_assert(TCGOP_CALLI(op) == real_args); 210375e8b9b7SRichard Henderson tcg_debug_assert(pi <= ARRAY_SIZE(op->args)); 21042bece2c8SRichard Henderson 210534b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \ 210634b1a49cSRichard Henderson && !defined(CONFIG_TCG_INTERPRETER) 210734b1a49cSRichard Henderson /* Free all of the parts we allocated above. */ 210834b1a49cSRichard Henderson for (i = real_args = 0; i < orig_nargs; ++i) { 210934b1a49cSRichard Henderson int is_64bit = orig_sizemask & (1 << (i+1)*2); 211034b1a49cSRichard Henderson if (is_64bit) { 2111085272b3SRichard Henderson tcg_temp_free_internal(args[real_args++]); 2112085272b3SRichard Henderson tcg_temp_free_internal(args[real_args++]); 211334b1a49cSRichard Henderson } else { 211434b1a49cSRichard Henderson real_args++; 211534b1a49cSRichard Henderson } 211634b1a49cSRichard Henderson } 211734b1a49cSRichard Henderson if (orig_sizemask & 1) { 211834b1a49cSRichard Henderson /* The 32-bit ABI returned two 32-bit pieces. Re-assemble them. 211934b1a49cSRichard Henderson Note that describing these as TCGv_i64 eliminates an unnecessary 212034b1a49cSRichard Henderson zero-extension that tcg_gen_concat_i32_i64 would create. */ 2121085272b3SRichard Henderson tcg_gen_concat32_i64(temp_tcgv_i64(ret), retl, reth); 212234b1a49cSRichard Henderson tcg_temp_free_i64(retl); 212334b1a49cSRichard Henderson tcg_temp_free_i64(reth); 212434b1a49cSRichard Henderson } 212534b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64 21262bece2c8SRichard Henderson for (i = 0; i < nargs; ++i) { 21272bece2c8SRichard Henderson int is_64bit = sizemask & (1 << (i+1)*2); 21282bece2c8SRichard Henderson if (!is_64bit) { 2129085272b3SRichard Henderson tcg_temp_free_internal(args[i]); 21302bece2c8SRichard Henderson } 21312bece2c8SRichard Henderson } 21322bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */ 2133a7812ae4Spbrook } 2134c896fe29Sbellard 21358fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s) 2136c896fe29Sbellard { 2137ac3b8891SRichard Henderson int i, n; 2138ac3b8891SRichard Henderson 2139ee17db83SRichard Henderson for (i = 0, n = s->nb_temps; i < n; i++) { 2140ee17db83SRichard Henderson TCGTemp *ts = &s->temps[i]; 2141ee17db83SRichard Henderson TCGTempVal val = TEMP_VAL_MEM; 2142ee17db83SRichard Henderson 2143ee17db83SRichard Henderson switch (ts->kind) { 2144c0522136SRichard Henderson case TEMP_CONST: 2145c0522136SRichard Henderson val = TEMP_VAL_CONST; 2146c0522136SRichard Henderson break; 2147ee17db83SRichard Henderson case TEMP_FIXED: 2148ee17db83SRichard Henderson val = TEMP_VAL_REG; 2149ee17db83SRichard Henderson break; 2150ee17db83SRichard Henderson case TEMP_GLOBAL: 2151ee17db83SRichard Henderson break; 2152ee17db83SRichard Henderson case TEMP_NORMAL: 2153ee17db83SRichard Henderson val = TEMP_VAL_DEAD; 2154ee17db83SRichard Henderson /* fall through */ 2155ee17db83SRichard Henderson case TEMP_LOCAL: 2156e8996ee0Sbellard ts->mem_allocated = 0; 2157ee17db83SRichard Henderson break; 2158ee17db83SRichard Henderson default: 2159ee17db83SRichard Henderson g_assert_not_reached(); 2160ee17db83SRichard Henderson } 2161ee17db83SRichard Henderson ts->val_type = val; 2162e8996ee0Sbellard } 2163f8b2f202SRichard Henderson 2164f8b2f202SRichard Henderson memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp)); 2165c896fe29Sbellard } 2166c896fe29Sbellard 2167f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size, 2168f8b2f202SRichard Henderson TCGTemp *ts) 2169c896fe29Sbellard { 21701807f4c4SRichard Henderson int idx = temp_idx(ts); 2171ac56dd48Spbrook 2172ee17db83SRichard Henderson switch (ts->kind) { 2173ee17db83SRichard Henderson case TEMP_FIXED: 2174ee17db83SRichard Henderson case TEMP_GLOBAL: 2175ac56dd48Spbrook pstrcpy(buf, buf_size, ts->name); 2176ee17db83SRichard Henderson break; 2177ee17db83SRichard Henderson case TEMP_LOCAL: 2178641d5fbeSbellard snprintf(buf, buf_size, "loc%d", idx - s->nb_globals); 2179ee17db83SRichard Henderson break; 2180ee17db83SRichard Henderson case TEMP_NORMAL: 2181ac56dd48Spbrook snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals); 2182ee17db83SRichard Henderson break; 2183c0522136SRichard Henderson case TEMP_CONST: 2184c0522136SRichard Henderson switch (ts->type) { 2185c0522136SRichard Henderson case TCG_TYPE_I32: 2186c0522136SRichard Henderson snprintf(buf, buf_size, "$0x%x", (int32_t)ts->val); 2187c0522136SRichard Henderson break; 2188c0522136SRichard Henderson #if TCG_TARGET_REG_BITS > 32 2189c0522136SRichard Henderson case TCG_TYPE_I64: 2190c0522136SRichard Henderson snprintf(buf, buf_size, "$0x%" PRIx64, ts->val); 2191c0522136SRichard Henderson break; 2192c0522136SRichard Henderson #endif 2193c0522136SRichard Henderson case TCG_TYPE_V64: 2194c0522136SRichard Henderson case TCG_TYPE_V128: 2195c0522136SRichard Henderson case TCG_TYPE_V256: 2196c0522136SRichard Henderson snprintf(buf, buf_size, "v%d$0x%" PRIx64, 2197c0522136SRichard Henderson 64 << (ts->type - TCG_TYPE_V64), ts->val); 2198c0522136SRichard Henderson break; 2199c0522136SRichard Henderson default: 2200c0522136SRichard Henderson g_assert_not_reached(); 2201c0522136SRichard Henderson } 2202c0522136SRichard Henderson break; 2203c896fe29Sbellard } 2204c896fe29Sbellard return buf; 2205c896fe29Sbellard } 2206c896fe29Sbellard 220743439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf, 220843439139SRichard Henderson int buf_size, TCGArg arg) 2209f8b2f202SRichard Henderson { 221043439139SRichard Henderson return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg)); 2211f8b2f202SRichard Henderson } 2212f8b2f202SRichard Henderson 22136e085f72SRichard Henderson /* Find helper name. */ 22146e085f72SRichard Henderson static inline const char *tcg_find_helper(TCGContext *s, uintptr_t val) 2215e8996ee0Sbellard { 22166e085f72SRichard Henderson const char *ret = NULL; 2217619205fdSEmilio G. Cota if (helper_table) { 2218619205fdSEmilio G. Cota TCGHelperInfo *info = g_hash_table_lookup(helper_table, (gpointer)val); 221972866e82SRichard Henderson if (info) { 222072866e82SRichard Henderson ret = info->name; 222172866e82SRichard Henderson } 2222e8996ee0Sbellard } 22236e085f72SRichard Henderson return ret; 22244dc81f28Sbellard } 22254dc81f28Sbellard 2226f48f3edeSblueswir1 static const char * const cond_name[] = 2227f48f3edeSblueswir1 { 22280aed257fSRichard Henderson [TCG_COND_NEVER] = "never", 22290aed257fSRichard Henderson [TCG_COND_ALWAYS] = "always", 2230f48f3edeSblueswir1 [TCG_COND_EQ] = "eq", 2231f48f3edeSblueswir1 [TCG_COND_NE] = "ne", 2232f48f3edeSblueswir1 [TCG_COND_LT] = "lt", 2233f48f3edeSblueswir1 [TCG_COND_GE] = "ge", 2234f48f3edeSblueswir1 [TCG_COND_LE] = "le", 2235f48f3edeSblueswir1 [TCG_COND_GT] = "gt", 2236f48f3edeSblueswir1 [TCG_COND_LTU] = "ltu", 2237f48f3edeSblueswir1 [TCG_COND_GEU] = "geu", 2238f48f3edeSblueswir1 [TCG_COND_LEU] = "leu", 2239f48f3edeSblueswir1 [TCG_COND_GTU] = "gtu" 2240f48f3edeSblueswir1 }; 2241f48f3edeSblueswir1 2242f713d6adSRichard Henderson static const char * const ldst_name[] = 2243f713d6adSRichard Henderson { 2244f713d6adSRichard Henderson [MO_UB] = "ub", 2245f713d6adSRichard Henderson [MO_SB] = "sb", 2246f713d6adSRichard Henderson [MO_LEUW] = "leuw", 2247f713d6adSRichard Henderson [MO_LESW] = "lesw", 2248f713d6adSRichard Henderson [MO_LEUL] = "leul", 2249f713d6adSRichard Henderson [MO_LESL] = "lesl", 2250f713d6adSRichard Henderson [MO_LEQ] = "leq", 2251f713d6adSRichard Henderson [MO_BEUW] = "beuw", 2252f713d6adSRichard Henderson [MO_BESW] = "besw", 2253f713d6adSRichard Henderson [MO_BEUL] = "beul", 2254f713d6adSRichard Henderson [MO_BESL] = "besl", 2255f713d6adSRichard Henderson [MO_BEQ] = "beq", 2256f713d6adSRichard Henderson }; 2257f713d6adSRichard Henderson 22581f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = { 225952bf9771Stony.nguyen@bt.com #ifdef TARGET_ALIGNED_ONLY 22601f00b27fSSergey Sorokin [MO_UNALN >> MO_ASHIFT] = "un+", 22611f00b27fSSergey Sorokin [MO_ALIGN >> MO_ASHIFT] = "", 22621f00b27fSSergey Sorokin #else 22631f00b27fSSergey Sorokin [MO_UNALN >> MO_ASHIFT] = "", 22641f00b27fSSergey Sorokin [MO_ALIGN >> MO_ASHIFT] = "al+", 22651f00b27fSSergey Sorokin #endif 22661f00b27fSSergey Sorokin [MO_ALIGN_2 >> MO_ASHIFT] = "al2+", 22671f00b27fSSergey Sorokin [MO_ALIGN_4 >> MO_ASHIFT] = "al4+", 22681f00b27fSSergey Sorokin [MO_ALIGN_8 >> MO_ASHIFT] = "al8+", 22691f00b27fSSergey Sorokin [MO_ALIGN_16 >> MO_ASHIFT] = "al16+", 22701f00b27fSSergey Sorokin [MO_ALIGN_32 >> MO_ASHIFT] = "al32+", 22711f00b27fSSergey Sorokin [MO_ALIGN_64 >> MO_ASHIFT] = "al64+", 22721f00b27fSSergey Sorokin }; 22731f00b27fSSergey Sorokin 2274b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d) 2275b016486eSRichard Henderson { 2276b016486eSRichard Henderson return (d & (d - 1)) == 0; 2277b016486eSRichard Henderson } 2278b016486eSRichard Henderson 2279b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d) 2280b016486eSRichard Henderson { 2281b016486eSRichard Henderson if (TCG_TARGET_NB_REGS <= 32) { 2282b016486eSRichard Henderson return ctz32(d); 2283b016486eSRichard Henderson } else { 2284b016486eSRichard Henderson return ctz64(d); 2285b016486eSRichard Henderson } 2286b016486eSRichard Henderson } 2287b016486eSRichard Henderson 22881894f69aSRichard Henderson static void tcg_dump_ops(TCGContext *s, bool have_prefs) 2289c896fe29Sbellard { 2290c896fe29Sbellard char buf[128]; 2291c45cb8bbSRichard Henderson TCGOp *op; 2292c896fe29Sbellard 229315fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 2294c45cb8bbSRichard Henderson int i, k, nb_oargs, nb_iargs, nb_cargs; 2295c45cb8bbSRichard Henderson const TCGOpDef *def; 2296c45cb8bbSRichard Henderson TCGOpcode c; 2297bdfb460eSRichard Henderson int col = 0; 2298c45cb8bbSRichard Henderson 2299c45cb8bbSRichard Henderson c = op->opc; 2300c896fe29Sbellard def = &tcg_op_defs[c]; 2301c45cb8bbSRichard Henderson 2302765b842aSRichard Henderson if (c == INDEX_op_insn_start) { 2303b016486eSRichard Henderson nb_oargs = 0; 230415fa08f8SRichard Henderson col += qemu_log("\n ----"); 23059aef40edSRichard Henderson 23069aef40edSRichard Henderson for (i = 0; i < TARGET_INSN_START_WORDS; ++i) { 23079aef40edSRichard Henderson target_ulong a; 23087e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS 2309efee3746SRichard Henderson a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]); 23107e4597d7Sbellard #else 2311efee3746SRichard Henderson a = op->args[i]; 23127e4597d7Sbellard #endif 2313bdfb460eSRichard Henderson col += qemu_log(" " TARGET_FMT_lx, a); 2314eeacee4dSBlue Swirl } 23157e4597d7Sbellard } else if (c == INDEX_op_call) { 2316c896fe29Sbellard /* variable number of arguments */ 2317cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 2318cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 2319c896fe29Sbellard nb_cargs = def->nb_cargs; 2320b03cce8eSbellard 2321cf066674SRichard Henderson /* function name, flags, out args */ 2322bdfb460eSRichard Henderson col += qemu_log(" %s %s,$0x%" TCG_PRIlx ",$%d", def->name, 2323efee3746SRichard Henderson tcg_find_helper(s, op->args[nb_oargs + nb_iargs]), 2324efee3746SRichard Henderson op->args[nb_oargs + nb_iargs + 1], nb_oargs); 2325b03cce8eSbellard for (i = 0; i < nb_oargs; i++) { 232643439139SRichard Henderson col += qemu_log(",%s", tcg_get_arg_str(s, buf, sizeof(buf), 2327efee3746SRichard Henderson op->args[i])); 2328b03cce8eSbellard } 2329cf066674SRichard Henderson for (i = 0; i < nb_iargs; i++) { 2330efee3746SRichard Henderson TCGArg arg = op->args[nb_oargs + i]; 2331cf066674SRichard Henderson const char *t = "<dummy>"; 2332cf066674SRichard Henderson if (arg != TCG_CALL_DUMMY_ARG) { 233343439139SRichard Henderson t = tcg_get_arg_str(s, buf, sizeof(buf), arg); 2334b03cce8eSbellard } 2335bdfb460eSRichard Henderson col += qemu_log(",%s", t); 2336e8996ee0Sbellard } 2337b03cce8eSbellard } else { 2338bdfb460eSRichard Henderson col += qemu_log(" %s ", def->name); 2339c45cb8bbSRichard Henderson 2340c896fe29Sbellard nb_oargs = def->nb_oargs; 2341c896fe29Sbellard nb_iargs = def->nb_iargs; 2342c896fe29Sbellard nb_cargs = def->nb_cargs; 2343c896fe29Sbellard 2344d2fd745fSRichard Henderson if (def->flags & TCG_OPF_VECTOR) { 2345d2fd745fSRichard Henderson col += qemu_log("v%d,e%d,", 64 << TCGOP_VECL(op), 2346d2fd745fSRichard Henderson 8 << TCGOP_VECE(op)); 2347d2fd745fSRichard Henderson } 2348d2fd745fSRichard Henderson 2349c896fe29Sbellard k = 0; 2350c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 2351eeacee4dSBlue Swirl if (k != 0) { 2352bdfb460eSRichard Henderson col += qemu_log(","); 2353eeacee4dSBlue Swirl } 235443439139SRichard Henderson col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf), 2355efee3746SRichard Henderson op->args[k++])); 2356c896fe29Sbellard } 2357c896fe29Sbellard for (i = 0; i < nb_iargs; i++) { 2358eeacee4dSBlue Swirl if (k != 0) { 2359bdfb460eSRichard Henderson col += qemu_log(","); 2360eeacee4dSBlue Swirl } 236143439139SRichard Henderson col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf), 2362efee3746SRichard Henderson op->args[k++])); 2363c896fe29Sbellard } 2364be210acbSRichard Henderson switch (c) { 2365be210acbSRichard Henderson case INDEX_op_brcond_i32: 2366ffc5ea09SRichard Henderson case INDEX_op_setcond_i32: 2367ffc5ea09SRichard Henderson case INDEX_op_movcond_i32: 2368be210acbSRichard Henderson case INDEX_op_brcond2_i32: 2369be210acbSRichard Henderson case INDEX_op_setcond2_i32: 2370ffc5ea09SRichard Henderson case INDEX_op_brcond_i64: 2371be210acbSRichard Henderson case INDEX_op_setcond_i64: 2372ffc5ea09SRichard Henderson case INDEX_op_movcond_i64: 2373212be173SRichard Henderson case INDEX_op_cmp_vec: 2374f75da298SRichard Henderson case INDEX_op_cmpsel_vec: 2375efee3746SRichard Henderson if (op->args[k] < ARRAY_SIZE(cond_name) 2376efee3746SRichard Henderson && cond_name[op->args[k]]) { 2377efee3746SRichard Henderson col += qemu_log(",%s", cond_name[op->args[k++]]); 2378eeacee4dSBlue Swirl } else { 2379efee3746SRichard Henderson col += qemu_log(",$0x%" TCG_PRIlx, op->args[k++]); 2380eeacee4dSBlue Swirl } 2381f48f3edeSblueswir1 i = 1; 2382be210acbSRichard Henderson break; 2383f713d6adSRichard Henderson case INDEX_op_qemu_ld_i32: 2384f713d6adSRichard Henderson case INDEX_op_qemu_st_i32: 238507ce0b05SRichard Henderson case INDEX_op_qemu_st8_i32: 2386f713d6adSRichard Henderson case INDEX_op_qemu_ld_i64: 2387f713d6adSRichard Henderson case INDEX_op_qemu_st_i64: 238859227d5dSRichard Henderson { 2389efee3746SRichard Henderson TCGMemOpIdx oi = op->args[k++]; 239014776ab5STony Nguyen MemOp op = get_memop(oi); 239159227d5dSRichard Henderson unsigned ix = get_mmuidx(oi); 239259227d5dSRichard Henderson 239359c4b7e8SRichard Henderson if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) { 2394bdfb460eSRichard Henderson col += qemu_log(",$0x%x,%u", op, ix); 239559c4b7e8SRichard Henderson } else { 23961f00b27fSSergey Sorokin const char *s_al, *s_op; 23971f00b27fSSergey Sorokin s_al = alignment_name[(op & MO_AMASK) >> MO_ASHIFT]; 239859c4b7e8SRichard Henderson s_op = ldst_name[op & (MO_BSWAP | MO_SSIZE)]; 2399bdfb460eSRichard Henderson col += qemu_log(",%s%s,%u", s_al, s_op, ix); 2400f713d6adSRichard Henderson } 2401f713d6adSRichard Henderson i = 1; 240259227d5dSRichard Henderson } 2403f713d6adSRichard Henderson break; 2404be210acbSRichard Henderson default: 2405f48f3edeSblueswir1 i = 0; 2406be210acbSRichard Henderson break; 2407be210acbSRichard Henderson } 240851e3972cSRichard Henderson switch (c) { 240951e3972cSRichard Henderson case INDEX_op_set_label: 241051e3972cSRichard Henderson case INDEX_op_br: 241151e3972cSRichard Henderson case INDEX_op_brcond_i32: 241251e3972cSRichard Henderson case INDEX_op_brcond_i64: 241351e3972cSRichard Henderson case INDEX_op_brcond2_i32: 2414efee3746SRichard Henderson col += qemu_log("%s$L%d", k ? "," : "", 2415efee3746SRichard Henderson arg_label(op->args[k])->id); 241651e3972cSRichard Henderson i++, k++; 241751e3972cSRichard Henderson break; 241851e3972cSRichard Henderson default: 241951e3972cSRichard Henderson break; 2420eeacee4dSBlue Swirl } 242151e3972cSRichard Henderson for (; i < nb_cargs; i++, k++) { 2422efee3746SRichard Henderson col += qemu_log("%s$0x%" TCG_PRIlx, k ? "," : "", op->args[k]); 2423bdfb460eSRichard Henderson } 2424bdfb460eSRichard Henderson } 2425bdfb460eSRichard Henderson 24261894f69aSRichard Henderson if (have_prefs || op->life) { 24277606488cSRobert Foley 24287606488cSRobert Foley QemuLogFile *logfile; 24297606488cSRobert Foley 24307606488cSRobert Foley rcu_read_lock(); 2431d73415a3SStefan Hajnoczi logfile = qatomic_rcu_read(&qemu_logfile); 24327606488cSRobert Foley if (logfile) { 24331894f69aSRichard Henderson for (; col < 40; ++col) { 24347606488cSRobert Foley putc(' ', logfile->fd); 2435bdfb460eSRichard Henderson } 24361894f69aSRichard Henderson } 24377606488cSRobert Foley rcu_read_unlock(); 24387606488cSRobert Foley } 24391894f69aSRichard Henderson 24401894f69aSRichard Henderson if (op->life) { 24411894f69aSRichard Henderson unsigned life = op->life; 2442bdfb460eSRichard Henderson 2443bdfb460eSRichard Henderson if (life & (SYNC_ARG * 3)) { 2444bdfb460eSRichard Henderson qemu_log(" sync:"); 2445bdfb460eSRichard Henderson for (i = 0; i < 2; ++i) { 2446bdfb460eSRichard Henderson if (life & (SYNC_ARG << i)) { 2447bdfb460eSRichard Henderson qemu_log(" %d", i); 2448bdfb460eSRichard Henderson } 2449bdfb460eSRichard Henderson } 2450bdfb460eSRichard Henderson } 2451bdfb460eSRichard Henderson life /= DEAD_ARG; 2452bdfb460eSRichard Henderson if (life) { 2453bdfb460eSRichard Henderson qemu_log(" dead:"); 2454bdfb460eSRichard Henderson for (i = 0; life; ++i, life >>= 1) { 2455bdfb460eSRichard Henderson if (life & 1) { 2456bdfb460eSRichard Henderson qemu_log(" %d", i); 2457bdfb460eSRichard Henderson } 2458bdfb460eSRichard Henderson } 2459c896fe29Sbellard } 2460b03cce8eSbellard } 24611894f69aSRichard Henderson 24621894f69aSRichard Henderson if (have_prefs) { 24631894f69aSRichard Henderson for (i = 0; i < nb_oargs; ++i) { 24641894f69aSRichard Henderson TCGRegSet set = op->output_pref[i]; 24651894f69aSRichard Henderson 24661894f69aSRichard Henderson if (i == 0) { 24671894f69aSRichard Henderson qemu_log(" pref="); 24681894f69aSRichard Henderson } else { 24691894f69aSRichard Henderson qemu_log(","); 24701894f69aSRichard Henderson } 24711894f69aSRichard Henderson if (set == 0) { 24721894f69aSRichard Henderson qemu_log("none"); 24731894f69aSRichard Henderson } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) { 24741894f69aSRichard Henderson qemu_log("all"); 24751894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG 24761894f69aSRichard Henderson } else if (tcg_regset_single(set)) { 24771894f69aSRichard Henderson TCGReg reg = tcg_regset_first(set); 24781894f69aSRichard Henderson qemu_log("%s", tcg_target_reg_names[reg]); 24791894f69aSRichard Henderson #endif 24801894f69aSRichard Henderson } else if (TCG_TARGET_NB_REGS <= 32) { 24811894f69aSRichard Henderson qemu_log("%#x", (uint32_t)set); 24821894f69aSRichard Henderson } else { 24831894f69aSRichard Henderson qemu_log("%#" PRIx64, (uint64_t)set); 24841894f69aSRichard Henderson } 24851894f69aSRichard Henderson } 24861894f69aSRichard Henderson } 24871894f69aSRichard Henderson 2488eeacee4dSBlue Swirl qemu_log("\n"); 2489c896fe29Sbellard } 2490c896fe29Sbellard } 2491c896fe29Sbellard 2492c896fe29Sbellard /* we give more priority to constraints with less registers */ 2493c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k) 2494c896fe29Sbellard { 249574a11790SRichard Henderson const TCGArgConstraint *arg_ct = &def->args_ct[k]; 249674a11790SRichard Henderson int n; 2497c896fe29Sbellard 2498bc2b17e6SRichard Henderson if (arg_ct->oalias) { 2499c896fe29Sbellard /* an alias is equivalent to a single register */ 2500c896fe29Sbellard n = 1; 2501c896fe29Sbellard } else { 250274a11790SRichard Henderson n = ctpop64(arg_ct->regs); 2503c896fe29Sbellard } 2504c896fe29Sbellard return TCG_TARGET_NB_REGS - n + 1; 2505c896fe29Sbellard } 2506c896fe29Sbellard 2507c896fe29Sbellard /* sort from highest priority to lowest */ 2508c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n) 2509c896fe29Sbellard { 251066792f90SRichard Henderson int i, j; 251166792f90SRichard Henderson TCGArgConstraint *a = def->args_ct; 2512c896fe29Sbellard 251366792f90SRichard Henderson for (i = 0; i < n; i++) { 251466792f90SRichard Henderson a[start + i].sort_index = start + i; 251566792f90SRichard Henderson } 251666792f90SRichard Henderson if (n <= 1) { 2517c896fe29Sbellard return; 251866792f90SRichard Henderson } 2519c896fe29Sbellard for (i = 0; i < n - 1; i++) { 2520c896fe29Sbellard for (j = i + 1; j < n; j++) { 252166792f90SRichard Henderson int p1 = get_constraint_priority(def, a[start + i].sort_index); 252266792f90SRichard Henderson int p2 = get_constraint_priority(def, a[start + j].sort_index); 2523c896fe29Sbellard if (p1 < p2) { 252466792f90SRichard Henderson int tmp = a[start + i].sort_index; 252566792f90SRichard Henderson a[start + i].sort_index = a[start + j].sort_index; 252666792f90SRichard Henderson a[start + j].sort_index = tmp; 2527c896fe29Sbellard } 2528c896fe29Sbellard } 2529c896fe29Sbellard } 2530c896fe29Sbellard } 2531c896fe29Sbellard 2532f69d277eSRichard Henderson static void process_op_defs(TCGContext *s) 2533c896fe29Sbellard { 2534a9751609SRichard Henderson TCGOpcode op; 2535c896fe29Sbellard 2536f69d277eSRichard Henderson for (op = 0; op < NB_OPS; op++) { 2537f69d277eSRichard Henderson TCGOpDef *def = &tcg_op_defs[op]; 2538f69d277eSRichard Henderson const TCGTargetOpDef *tdefs; 2539069ea736SRichard Henderson int i, nb_args; 2540f69d277eSRichard Henderson 2541f69d277eSRichard Henderson if (def->flags & TCG_OPF_NOT_PRESENT) { 2542f69d277eSRichard Henderson continue; 2543f69d277eSRichard Henderson } 2544f69d277eSRichard Henderson 2545c896fe29Sbellard nb_args = def->nb_iargs + def->nb_oargs; 2546f69d277eSRichard Henderson if (nb_args == 0) { 2547f69d277eSRichard Henderson continue; 2548f69d277eSRichard Henderson } 2549f69d277eSRichard Henderson 25504c22e840SRichard Henderson /* 25514c22e840SRichard Henderson * Macro magic should make it impossible, but double-check that 25524c22e840SRichard Henderson * the array index is in range. Since the signness of an enum 25534c22e840SRichard Henderson * is implementation defined, force the result to unsigned. 25544c22e840SRichard Henderson */ 25554c22e840SRichard Henderson unsigned con_set = tcg_target_op_def(op); 25564c22e840SRichard Henderson tcg_debug_assert(con_set < ARRAY_SIZE(constraint_sets)); 25574c22e840SRichard Henderson tdefs = &constraint_sets[con_set]; 2558f69d277eSRichard Henderson 2559c896fe29Sbellard for (i = 0; i < nb_args; i++) { 2560f69d277eSRichard Henderson const char *ct_str = tdefs->args_ct_str[i]; 2561f69d277eSRichard Henderson /* Incomplete TCGTargetOpDef entry. */ 2562eabb7b91SAurelien Jarno tcg_debug_assert(ct_str != NULL); 2563f69d277eSRichard Henderson 256417280ff4SRichard Henderson while (*ct_str != '\0') { 256517280ff4SRichard Henderson switch(*ct_str) { 256617280ff4SRichard Henderson case '0' ... '9': 256717280ff4SRichard Henderson { 256817280ff4SRichard Henderson int oarg = *ct_str - '0'; 256917280ff4SRichard Henderson tcg_debug_assert(ct_str == tdefs->args_ct_str[i]); 2570eabb7b91SAurelien Jarno tcg_debug_assert(oarg < def->nb_oargs); 257174a11790SRichard Henderson tcg_debug_assert(def->args_ct[oarg].regs != 0); 2572c896fe29Sbellard def->args_ct[i] = def->args_ct[oarg]; 2573bc2b17e6SRichard Henderson /* The output sets oalias. */ 2574bc2b17e6SRichard Henderson def->args_ct[oarg].oalias = true; 25755ff9d6a4Sbellard def->args_ct[oarg].alias_index = i; 2576bc2b17e6SRichard Henderson /* The input sets ialias. */ 2577bc2b17e6SRichard Henderson def->args_ct[i].ialias = true; 25785ff9d6a4Sbellard def->args_ct[i].alias_index = oarg; 257917280ff4SRichard Henderson } 258017280ff4SRichard Henderson ct_str++; 2581c896fe29Sbellard break; 258282790a87SRichard Henderson case '&': 2583bc2b17e6SRichard Henderson def->args_ct[i].newreg = true; 258482790a87SRichard Henderson ct_str++; 258582790a87SRichard Henderson break; 2586c896fe29Sbellard case 'i': 2587c896fe29Sbellard def->args_ct[i].ct |= TCG_CT_CONST; 2588c896fe29Sbellard ct_str++; 2589c896fe29Sbellard break; 2590358b4923SRichard Henderson 2591358b4923SRichard Henderson /* Include all of the target-specific constraints. */ 2592358b4923SRichard Henderson 2593358b4923SRichard Henderson #undef CONST 2594358b4923SRichard Henderson #define CONST(CASE, MASK) \ 2595358b4923SRichard Henderson case CASE: def->args_ct[i].ct |= MASK; ct_str++; break; 2596358b4923SRichard Henderson #define REGS(CASE, MASK) \ 2597358b4923SRichard Henderson case CASE: def->args_ct[i].regs |= MASK; ct_str++; break; 2598358b4923SRichard Henderson 2599358b4923SRichard Henderson #include "tcg-target-con-str.h" 2600358b4923SRichard Henderson 2601358b4923SRichard Henderson #undef REGS 2602358b4923SRichard Henderson #undef CONST 2603c896fe29Sbellard default: 2604358b4923SRichard Henderson /* Typo in TCGTargetOpDef constraint. */ 2605358b4923SRichard Henderson g_assert_not_reached(); 2606358b4923SRichard Henderson } 2607c896fe29Sbellard } 2608c896fe29Sbellard } 2609c896fe29Sbellard 2610c68aaa18SStefan Weil /* TCGTargetOpDef entry with too much information? */ 2611eabb7b91SAurelien Jarno tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL); 2612c68aaa18SStefan Weil 2613c896fe29Sbellard /* sort the constraints (XXX: this is just an heuristic) */ 2614c896fe29Sbellard sort_constraints(def, 0, def->nb_oargs); 2615c896fe29Sbellard sort_constraints(def, def->nb_oargs, def->nb_iargs); 2616c896fe29Sbellard } 2617c896fe29Sbellard } 2618c896fe29Sbellard 26190c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op) 26200c627cdcSRichard Henderson { 2621d88a117eSRichard Henderson TCGLabel *label; 2622d88a117eSRichard Henderson 2623d88a117eSRichard Henderson switch (op->opc) { 2624d88a117eSRichard Henderson case INDEX_op_br: 2625d88a117eSRichard Henderson label = arg_label(op->args[0]); 2626d88a117eSRichard Henderson label->refs--; 2627d88a117eSRichard Henderson break; 2628d88a117eSRichard Henderson case INDEX_op_brcond_i32: 2629d88a117eSRichard Henderson case INDEX_op_brcond_i64: 2630d88a117eSRichard Henderson label = arg_label(op->args[3]); 2631d88a117eSRichard Henderson label->refs--; 2632d88a117eSRichard Henderson break; 2633d88a117eSRichard Henderson case INDEX_op_brcond2_i32: 2634d88a117eSRichard Henderson label = arg_label(op->args[5]); 2635d88a117eSRichard Henderson label->refs--; 2636d88a117eSRichard Henderson break; 2637d88a117eSRichard Henderson default: 2638d88a117eSRichard Henderson break; 2639d88a117eSRichard Henderson } 2640d88a117eSRichard Henderson 264115fa08f8SRichard Henderson QTAILQ_REMOVE(&s->ops, op, link); 264215fa08f8SRichard Henderson QTAILQ_INSERT_TAIL(&s->free_ops, op, link); 2643abebf925SRichard Henderson s->nb_ops--; 26440c627cdcSRichard Henderson 26450c627cdcSRichard Henderson #ifdef CONFIG_PROFILER 2646d73415a3SStefan Hajnoczi qatomic_set(&s->prof.del_op_count, s->prof.del_op_count + 1); 26470c627cdcSRichard Henderson #endif 26480c627cdcSRichard Henderson } 26490c627cdcSRichard Henderson 265015fa08f8SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc) 265115fa08f8SRichard Henderson { 265215fa08f8SRichard Henderson TCGContext *s = tcg_ctx; 265315fa08f8SRichard Henderson TCGOp *op; 265415fa08f8SRichard Henderson 265515fa08f8SRichard Henderson if (likely(QTAILQ_EMPTY(&s->free_ops))) { 265615fa08f8SRichard Henderson op = tcg_malloc(sizeof(TCGOp)); 265715fa08f8SRichard Henderson } else { 265815fa08f8SRichard Henderson op = QTAILQ_FIRST(&s->free_ops); 265915fa08f8SRichard Henderson QTAILQ_REMOVE(&s->free_ops, op, link); 266015fa08f8SRichard Henderson } 266115fa08f8SRichard Henderson memset(op, 0, offsetof(TCGOp, link)); 266215fa08f8SRichard Henderson op->opc = opc; 2663abebf925SRichard Henderson s->nb_ops++; 266415fa08f8SRichard Henderson 266515fa08f8SRichard Henderson return op; 266615fa08f8SRichard Henderson } 266715fa08f8SRichard Henderson 266815fa08f8SRichard Henderson TCGOp *tcg_emit_op(TCGOpcode opc) 266915fa08f8SRichard Henderson { 267015fa08f8SRichard Henderson TCGOp *op = tcg_op_alloc(opc); 267115fa08f8SRichard Henderson QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link); 267215fa08f8SRichard Henderson return op; 267315fa08f8SRichard Henderson } 267415fa08f8SRichard Henderson 2675ac1043f6SEmilio G. Cota TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op, TCGOpcode opc) 26765a18407fSRichard Henderson { 267715fa08f8SRichard Henderson TCGOp *new_op = tcg_op_alloc(opc); 267815fa08f8SRichard Henderson QTAILQ_INSERT_BEFORE(old_op, new_op, link); 26795a18407fSRichard Henderson return new_op; 26805a18407fSRichard Henderson } 26815a18407fSRichard Henderson 2682ac1043f6SEmilio G. Cota TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, TCGOpcode opc) 26835a18407fSRichard Henderson { 268415fa08f8SRichard Henderson TCGOp *new_op = tcg_op_alloc(opc); 268515fa08f8SRichard Henderson QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link); 26865a18407fSRichard Henderson return new_op; 26875a18407fSRichard Henderson } 26885a18407fSRichard Henderson 2689b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code. */ 2690b4fc67c7SRichard Henderson static void reachable_code_pass(TCGContext *s) 2691b4fc67c7SRichard Henderson { 2692b4fc67c7SRichard Henderson TCGOp *op, *op_next; 2693b4fc67c7SRichard Henderson bool dead = false; 2694b4fc67c7SRichard Henderson 2695b4fc67c7SRichard Henderson QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) { 2696b4fc67c7SRichard Henderson bool remove = dead; 2697b4fc67c7SRichard Henderson TCGLabel *label; 2698b4fc67c7SRichard Henderson int call_flags; 2699b4fc67c7SRichard Henderson 2700b4fc67c7SRichard Henderson switch (op->opc) { 2701b4fc67c7SRichard Henderson case INDEX_op_set_label: 2702b4fc67c7SRichard Henderson label = arg_label(op->args[0]); 2703b4fc67c7SRichard Henderson if (label->refs == 0) { 2704b4fc67c7SRichard Henderson /* 2705b4fc67c7SRichard Henderson * While there is an occasional backward branch, virtually 2706b4fc67c7SRichard Henderson * all branches generated by the translators are forward. 2707b4fc67c7SRichard Henderson * Which means that generally we will have already removed 2708b4fc67c7SRichard Henderson * all references to the label that will be, and there is 2709b4fc67c7SRichard Henderson * little to be gained by iterating. 2710b4fc67c7SRichard Henderson */ 2711b4fc67c7SRichard Henderson remove = true; 2712b4fc67c7SRichard Henderson } else { 2713b4fc67c7SRichard Henderson /* Once we see a label, insns become live again. */ 2714b4fc67c7SRichard Henderson dead = false; 2715b4fc67c7SRichard Henderson remove = false; 2716b4fc67c7SRichard Henderson 2717b4fc67c7SRichard Henderson /* 2718b4fc67c7SRichard Henderson * Optimization can fold conditional branches to unconditional. 2719b4fc67c7SRichard Henderson * If we find a label with one reference which is preceded by 2720b4fc67c7SRichard Henderson * an unconditional branch to it, remove both. This needed to 2721b4fc67c7SRichard Henderson * wait until the dead code in between them was removed. 2722b4fc67c7SRichard Henderson */ 2723b4fc67c7SRichard Henderson if (label->refs == 1) { 2724eae3eb3eSPaolo Bonzini TCGOp *op_prev = QTAILQ_PREV(op, link); 2725b4fc67c7SRichard Henderson if (op_prev->opc == INDEX_op_br && 2726b4fc67c7SRichard Henderson label == arg_label(op_prev->args[0])) { 2727b4fc67c7SRichard Henderson tcg_op_remove(s, op_prev); 2728b4fc67c7SRichard Henderson remove = true; 2729b4fc67c7SRichard Henderson } 2730b4fc67c7SRichard Henderson } 2731b4fc67c7SRichard Henderson } 2732b4fc67c7SRichard Henderson break; 2733b4fc67c7SRichard Henderson 2734b4fc67c7SRichard Henderson case INDEX_op_br: 2735b4fc67c7SRichard Henderson case INDEX_op_exit_tb: 2736b4fc67c7SRichard Henderson case INDEX_op_goto_ptr: 2737b4fc67c7SRichard Henderson /* Unconditional branches; everything following is dead. */ 2738b4fc67c7SRichard Henderson dead = true; 2739b4fc67c7SRichard Henderson break; 2740b4fc67c7SRichard Henderson 2741b4fc67c7SRichard Henderson case INDEX_op_call: 2742b4fc67c7SRichard Henderson /* Notice noreturn helper calls, raising exceptions. */ 2743b4fc67c7SRichard Henderson call_flags = op->args[TCGOP_CALLO(op) + TCGOP_CALLI(op) + 1]; 2744b4fc67c7SRichard Henderson if (call_flags & TCG_CALL_NO_RETURN) { 2745b4fc67c7SRichard Henderson dead = true; 2746b4fc67c7SRichard Henderson } 2747b4fc67c7SRichard Henderson break; 2748b4fc67c7SRichard Henderson 2749b4fc67c7SRichard Henderson case INDEX_op_insn_start: 2750b4fc67c7SRichard Henderson /* Never remove -- we need to keep these for unwind. */ 2751b4fc67c7SRichard Henderson remove = false; 2752b4fc67c7SRichard Henderson break; 2753b4fc67c7SRichard Henderson 2754b4fc67c7SRichard Henderson default: 2755b4fc67c7SRichard Henderson break; 2756b4fc67c7SRichard Henderson } 2757b4fc67c7SRichard Henderson 2758b4fc67c7SRichard Henderson if (remove) { 2759b4fc67c7SRichard Henderson tcg_op_remove(s, op); 2760b4fc67c7SRichard Henderson } 2761b4fc67c7SRichard Henderson } 2762b4fc67c7SRichard Henderson } 2763b4fc67c7SRichard Henderson 2764c70fbf0aSRichard Henderson #define TS_DEAD 1 2765c70fbf0aSRichard Henderson #define TS_MEM 2 2766c70fbf0aSRichard Henderson 27675a18407fSRichard Henderson #define IS_DEAD_ARG(n) (arg_life & (DEAD_ARG << (n))) 27685a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n))) 27695a18407fSRichard Henderson 277025f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp. */ 277125f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts) 277225f49c5fSRichard Henderson { 277325f49c5fSRichard Henderson return ts->state_ptr; 277425f49c5fSRichard Henderson } 277525f49c5fSRichard Henderson 277625f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the 277725f49c5fSRichard Henderson * maximal regset for its type. 277825f49c5fSRichard Henderson */ 277925f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts) 278025f49c5fSRichard Henderson { 278125f49c5fSRichard Henderson *la_temp_pref(ts) 278225f49c5fSRichard Henderson = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]); 278325f49c5fSRichard Henderson } 278425f49c5fSRichard Henderson 27859c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals 27869c43b68dSAurelien Jarno should be in memory. */ 27872616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt) 2788c896fe29Sbellard { 2789b83eabeaSRichard Henderson int i; 2790b83eabeaSRichard Henderson 2791b83eabeaSRichard Henderson for (i = 0; i < ng; ++i) { 2792b83eabeaSRichard Henderson s->temps[i].state = TS_DEAD | TS_MEM; 279325f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 2794b83eabeaSRichard Henderson } 2795b83eabeaSRichard Henderson for (i = ng; i < nt; ++i) { 2796b83eabeaSRichard Henderson s->temps[i].state = TS_DEAD; 279725f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 2798b83eabeaSRichard Henderson } 2799c896fe29Sbellard } 2800c896fe29Sbellard 28019c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals 28029c43b68dSAurelien Jarno and local temps should be in memory. */ 28032616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt) 2804641d5fbeSbellard { 2805b83eabeaSRichard Henderson int i; 2806641d5fbeSbellard 2807ee17db83SRichard Henderson for (i = 0; i < nt; ++i) { 2808ee17db83SRichard Henderson TCGTemp *ts = &s->temps[i]; 2809ee17db83SRichard Henderson int state; 2810ee17db83SRichard Henderson 2811ee17db83SRichard Henderson switch (ts->kind) { 2812ee17db83SRichard Henderson case TEMP_FIXED: 2813ee17db83SRichard Henderson case TEMP_GLOBAL: 2814ee17db83SRichard Henderson case TEMP_LOCAL: 2815ee17db83SRichard Henderson state = TS_DEAD | TS_MEM; 2816ee17db83SRichard Henderson break; 2817ee17db83SRichard Henderson case TEMP_NORMAL: 2818c0522136SRichard Henderson case TEMP_CONST: 2819ee17db83SRichard Henderson state = TS_DEAD; 2820ee17db83SRichard Henderson break; 2821ee17db83SRichard Henderson default: 2822ee17db83SRichard Henderson g_assert_not_reached(); 2823c70fbf0aSRichard Henderson } 2824ee17db83SRichard Henderson ts->state = state; 2825ee17db83SRichard Henderson la_reset_pref(ts); 2826641d5fbeSbellard } 2827641d5fbeSbellard } 2828641d5fbeSbellard 2829f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory. */ 2830f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng) 2831f65a061cSRichard Henderson { 2832f65a061cSRichard Henderson int i; 2833f65a061cSRichard Henderson 2834f65a061cSRichard Henderson for (i = 0; i < ng; ++i) { 283525f49c5fSRichard Henderson int state = s->temps[i].state; 283625f49c5fSRichard Henderson s->temps[i].state = state | TS_MEM; 283725f49c5fSRichard Henderson if (state == TS_DEAD) { 283825f49c5fSRichard Henderson /* If the global was previously dead, reset prefs. */ 283925f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 284025f49c5fSRichard Henderson } 2841f65a061cSRichard Henderson } 2842f65a061cSRichard Henderson } 2843f65a061cSRichard Henderson 2844b4cb76e6SRichard Henderson /* 2845b4cb76e6SRichard Henderson * liveness analysis: conditional branch: all temps are dead, 2846b4cb76e6SRichard Henderson * globals and local temps should be synced. 2847b4cb76e6SRichard Henderson */ 2848b4cb76e6SRichard Henderson static void la_bb_sync(TCGContext *s, int ng, int nt) 2849b4cb76e6SRichard Henderson { 2850b4cb76e6SRichard Henderson la_global_sync(s, ng); 2851b4cb76e6SRichard Henderson 2852b4cb76e6SRichard Henderson for (int i = ng; i < nt; ++i) { 2853c0522136SRichard Henderson TCGTemp *ts = &s->temps[i]; 2854c0522136SRichard Henderson int state; 2855c0522136SRichard Henderson 2856c0522136SRichard Henderson switch (ts->kind) { 2857c0522136SRichard Henderson case TEMP_LOCAL: 2858c0522136SRichard Henderson state = ts->state; 2859c0522136SRichard Henderson ts->state = state | TS_MEM; 2860b4cb76e6SRichard Henderson if (state != TS_DEAD) { 2861b4cb76e6SRichard Henderson continue; 2862b4cb76e6SRichard Henderson } 2863c0522136SRichard Henderson break; 2864c0522136SRichard Henderson case TEMP_NORMAL: 2865b4cb76e6SRichard Henderson s->temps[i].state = TS_DEAD; 2866c0522136SRichard Henderson break; 2867c0522136SRichard Henderson case TEMP_CONST: 2868c0522136SRichard Henderson continue; 2869c0522136SRichard Henderson default: 2870c0522136SRichard Henderson g_assert_not_reached(); 2871b4cb76e6SRichard Henderson } 2872b4cb76e6SRichard Henderson la_reset_pref(&s->temps[i]); 2873b4cb76e6SRichard Henderson } 2874b4cb76e6SRichard Henderson } 2875b4cb76e6SRichard Henderson 2876f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill. */ 2877f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng) 2878f65a061cSRichard Henderson { 2879f65a061cSRichard Henderson int i; 2880f65a061cSRichard Henderson 2881f65a061cSRichard Henderson for (i = 0; i < ng; i++) { 2882f65a061cSRichard Henderson s->temps[i].state = TS_DEAD | TS_MEM; 288325f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 288425f49c5fSRichard Henderson } 288525f49c5fSRichard Henderson } 288625f49c5fSRichard Henderson 288725f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls. */ 288825f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt) 288925f49c5fSRichard Henderson { 289025f49c5fSRichard Henderson TCGRegSet mask = ~tcg_target_call_clobber_regs; 289125f49c5fSRichard Henderson int i; 289225f49c5fSRichard Henderson 289325f49c5fSRichard Henderson for (i = 0; i < nt; i++) { 289425f49c5fSRichard Henderson TCGTemp *ts = &s->temps[i]; 289525f49c5fSRichard Henderson if (!(ts->state & TS_DEAD)) { 289625f49c5fSRichard Henderson TCGRegSet *pset = la_temp_pref(ts); 289725f49c5fSRichard Henderson TCGRegSet set = *pset; 289825f49c5fSRichard Henderson 289925f49c5fSRichard Henderson set &= mask; 290025f49c5fSRichard Henderson /* If the combination is not possible, restart. */ 290125f49c5fSRichard Henderson if (set == 0) { 290225f49c5fSRichard Henderson set = tcg_target_available_regs[ts->type] & mask; 290325f49c5fSRichard Henderson } 290425f49c5fSRichard Henderson *pset = set; 290525f49c5fSRichard Henderson } 2906f65a061cSRichard Henderson } 2907f65a061cSRichard Henderson } 2908f65a061cSRichard Henderson 2909a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a 2910c896fe29Sbellard given input arguments is dead. Instructions updating dead 2911c896fe29Sbellard temporaries are removed. */ 2912b83eabeaSRichard Henderson static void liveness_pass_1(TCGContext *s) 2913c896fe29Sbellard { 2914c70fbf0aSRichard Henderson int nb_globals = s->nb_globals; 29152616c808SRichard Henderson int nb_temps = s->nb_temps; 291615fa08f8SRichard Henderson TCGOp *op, *op_prev; 291725f49c5fSRichard Henderson TCGRegSet *prefs; 291825f49c5fSRichard Henderson int i; 291925f49c5fSRichard Henderson 292025f49c5fSRichard Henderson prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps); 292125f49c5fSRichard Henderson for (i = 0; i < nb_temps; ++i) { 292225f49c5fSRichard Henderson s->temps[i].state_ptr = prefs + i; 292325f49c5fSRichard Henderson } 2924c896fe29Sbellard 2925ae36a246SRichard Henderson /* ??? Should be redundant with the exit_tb that ends the TB. */ 29262616c808SRichard Henderson la_func_end(s, nb_globals, nb_temps); 2927c896fe29Sbellard 2928eae3eb3eSPaolo Bonzini QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) { 292925f49c5fSRichard Henderson int nb_iargs, nb_oargs; 2930c45cb8bbSRichard Henderson TCGOpcode opc_new, opc_new2; 2931c45cb8bbSRichard Henderson bool have_opc_new2; 2932a1b3c48dSRichard Henderson TCGLifeData arg_life = 0; 293325f49c5fSRichard Henderson TCGTemp *ts; 2934c45cb8bbSRichard Henderson TCGOpcode opc = op->opc; 2935c45cb8bbSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 2936c45cb8bbSRichard Henderson 2937c45cb8bbSRichard Henderson switch (opc) { 2938c896fe29Sbellard case INDEX_op_call: 2939c6e113f5Sbellard { 2940c6e113f5Sbellard int call_flags; 294125f49c5fSRichard Henderson int nb_call_regs; 2942c6e113f5Sbellard 2943cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 2944cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 2945efee3746SRichard Henderson call_flags = op->args[nb_oargs + nb_iargs + 1]; 2946c6e113f5Sbellard 2947c45cb8bbSRichard Henderson /* pure functions can be removed if their result is unused */ 294878505279SAurelien Jarno if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) { 2949c6e113f5Sbellard for (i = 0; i < nb_oargs; i++) { 295025f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 295125f49c5fSRichard Henderson if (ts->state != TS_DEAD) { 2952c6e113f5Sbellard goto do_not_remove_call; 2953c6e113f5Sbellard } 29549c43b68dSAurelien Jarno } 2955c45cb8bbSRichard Henderson goto do_remove; 2956152c35aaSRichard Henderson } 2957c6e113f5Sbellard do_not_remove_call: 2958c896fe29Sbellard 295925f49c5fSRichard Henderson /* Output args are dead. */ 2960c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 296125f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 296225f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 2963a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 29646b64b624SAurelien Jarno } 296525f49c5fSRichard Henderson if (ts->state & TS_MEM) { 2966a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i; 29679c43b68dSAurelien Jarno } 296825f49c5fSRichard Henderson ts->state = TS_DEAD; 296925f49c5fSRichard Henderson la_reset_pref(ts); 297025f49c5fSRichard Henderson 297125f49c5fSRichard Henderson /* Not used -- it will be tcg_target_call_oarg_regs[i]. */ 297225f49c5fSRichard Henderson op->output_pref[i] = 0; 2973c896fe29Sbellard } 2974c896fe29Sbellard 297578505279SAurelien Jarno if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS | 297678505279SAurelien Jarno TCG_CALL_NO_READ_GLOBALS))) { 2977f65a061cSRichard Henderson la_global_kill(s, nb_globals); 2978c70fbf0aSRichard Henderson } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) { 2979f65a061cSRichard Henderson la_global_sync(s, nb_globals); 2980b9c18f56Saurel32 } 2981c896fe29Sbellard 298225f49c5fSRichard Henderson /* Record arguments that die in this helper. */ 2983866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 298425f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 298525f49c5fSRichard Henderson if (ts && ts->state & TS_DEAD) { 2986a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 2987c896fe29Sbellard } 2988c896fe29Sbellard } 298925f49c5fSRichard Henderson 299025f49c5fSRichard Henderson /* For all live registers, remove call-clobbered prefs. */ 299125f49c5fSRichard Henderson la_cross_call(s, nb_temps); 299225f49c5fSRichard Henderson 299325f49c5fSRichard Henderson nb_call_regs = ARRAY_SIZE(tcg_target_call_iarg_regs); 299425f49c5fSRichard Henderson 299525f49c5fSRichard Henderson /* Input arguments are live for preceding opcodes. */ 299625f49c5fSRichard Henderson for (i = 0; i < nb_iargs; i++) { 299725f49c5fSRichard Henderson ts = arg_temp(op->args[i + nb_oargs]); 299825f49c5fSRichard Henderson if (ts && ts->state & TS_DEAD) { 299925f49c5fSRichard Henderson /* For those arguments that die, and will be allocated 300025f49c5fSRichard Henderson * in registers, clear the register set for that arg, 300125f49c5fSRichard Henderson * to be filled in below. For args that will be on 300225f49c5fSRichard Henderson * the stack, reset to any available reg. 300325f49c5fSRichard Henderson */ 300425f49c5fSRichard Henderson *la_temp_pref(ts) 300525f49c5fSRichard Henderson = (i < nb_call_regs ? 0 : 300625f49c5fSRichard Henderson tcg_target_available_regs[ts->type]); 300725f49c5fSRichard Henderson ts->state &= ~TS_DEAD; 300825f49c5fSRichard Henderson } 300925f49c5fSRichard Henderson } 301025f49c5fSRichard Henderson 301125f49c5fSRichard Henderson /* For each input argument, add its input register to prefs. 301225f49c5fSRichard Henderson If a temp is used once, this produces a single set bit. */ 301325f49c5fSRichard Henderson for (i = 0; i < MIN(nb_call_regs, nb_iargs); i++) { 301425f49c5fSRichard Henderson ts = arg_temp(op->args[i + nb_oargs]); 301525f49c5fSRichard Henderson if (ts) { 301625f49c5fSRichard Henderson tcg_regset_set_reg(*la_temp_pref(ts), 301725f49c5fSRichard Henderson tcg_target_call_iarg_regs[i]); 3018c70fbf0aSRichard Henderson } 3019c19f47bfSAurelien Jarno } 3020c6e113f5Sbellard } 3021c896fe29Sbellard break; 3022765b842aSRichard Henderson case INDEX_op_insn_start: 3023c896fe29Sbellard break; 30245ff9d6a4Sbellard case INDEX_op_discard: 30255ff9d6a4Sbellard /* mark the temporary as dead */ 302625f49c5fSRichard Henderson ts = arg_temp(op->args[0]); 302725f49c5fSRichard Henderson ts->state = TS_DEAD; 302825f49c5fSRichard Henderson la_reset_pref(ts); 30295ff9d6a4Sbellard break; 30301305c451SRichard Henderson 30311305c451SRichard Henderson case INDEX_op_add2_i32: 3032c45cb8bbSRichard Henderson opc_new = INDEX_op_add_i32; 3033f1fae40cSRichard Henderson goto do_addsub2; 30341305c451SRichard Henderson case INDEX_op_sub2_i32: 3035c45cb8bbSRichard Henderson opc_new = INDEX_op_sub_i32; 3036f1fae40cSRichard Henderson goto do_addsub2; 3037f1fae40cSRichard Henderson case INDEX_op_add2_i64: 3038c45cb8bbSRichard Henderson opc_new = INDEX_op_add_i64; 3039f1fae40cSRichard Henderson goto do_addsub2; 3040f1fae40cSRichard Henderson case INDEX_op_sub2_i64: 3041c45cb8bbSRichard Henderson opc_new = INDEX_op_sub_i64; 3042f1fae40cSRichard Henderson do_addsub2: 30431305c451SRichard Henderson nb_iargs = 4; 30441305c451SRichard Henderson nb_oargs = 2; 30451305c451SRichard Henderson /* Test if the high part of the operation is dead, but not 30461305c451SRichard Henderson the low part. The result can be optimized to a simple 30471305c451SRichard Henderson add or sub. This happens often for x86_64 guest when the 30481305c451SRichard Henderson cpu mode is set to 32 bit. */ 3049b83eabeaSRichard Henderson if (arg_temp(op->args[1])->state == TS_DEAD) { 3050b83eabeaSRichard Henderson if (arg_temp(op->args[0])->state == TS_DEAD) { 30511305c451SRichard Henderson goto do_remove; 30521305c451SRichard Henderson } 3053c45cb8bbSRichard Henderson /* Replace the opcode and adjust the args in place, 3054c45cb8bbSRichard Henderson leaving 3 unused args at the end. */ 3055c45cb8bbSRichard Henderson op->opc = opc = opc_new; 3056efee3746SRichard Henderson op->args[1] = op->args[2]; 3057efee3746SRichard Henderson op->args[2] = op->args[4]; 30581305c451SRichard Henderson /* Fall through and mark the single-word operation live. */ 30591305c451SRichard Henderson nb_iargs = 2; 30601305c451SRichard Henderson nb_oargs = 1; 30611305c451SRichard Henderson } 30621305c451SRichard Henderson goto do_not_remove; 30631305c451SRichard Henderson 30641414968aSRichard Henderson case INDEX_op_mulu2_i32: 3065c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i32; 3066c45cb8bbSRichard Henderson opc_new2 = INDEX_op_muluh_i32; 3067c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_muluh_i32; 306803271524SRichard Henderson goto do_mul2; 3069f1fae40cSRichard Henderson case INDEX_op_muls2_i32: 3070c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i32; 3071c45cb8bbSRichard Henderson opc_new2 = INDEX_op_mulsh_i32; 3072c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_mulsh_i32; 3073f1fae40cSRichard Henderson goto do_mul2; 3074f1fae40cSRichard Henderson case INDEX_op_mulu2_i64: 3075c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i64; 3076c45cb8bbSRichard Henderson opc_new2 = INDEX_op_muluh_i64; 3077c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_muluh_i64; 307803271524SRichard Henderson goto do_mul2; 3079f1fae40cSRichard Henderson case INDEX_op_muls2_i64: 3080c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i64; 3081c45cb8bbSRichard Henderson opc_new2 = INDEX_op_mulsh_i64; 3082c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_mulsh_i64; 308303271524SRichard Henderson goto do_mul2; 3084f1fae40cSRichard Henderson do_mul2: 30851414968aSRichard Henderson nb_iargs = 2; 30861414968aSRichard Henderson nb_oargs = 2; 3087b83eabeaSRichard Henderson if (arg_temp(op->args[1])->state == TS_DEAD) { 3088b83eabeaSRichard Henderson if (arg_temp(op->args[0])->state == TS_DEAD) { 308903271524SRichard Henderson /* Both parts of the operation are dead. */ 30901414968aSRichard Henderson goto do_remove; 30911414968aSRichard Henderson } 309203271524SRichard Henderson /* The high part of the operation is dead; generate the low. */ 3093c45cb8bbSRichard Henderson op->opc = opc = opc_new; 3094efee3746SRichard Henderson op->args[1] = op->args[2]; 3095efee3746SRichard Henderson op->args[2] = op->args[3]; 3096b83eabeaSRichard Henderson } else if (arg_temp(op->args[0])->state == TS_DEAD && have_opc_new2) { 309703271524SRichard Henderson /* The low part of the operation is dead; generate the high. */ 3098c45cb8bbSRichard Henderson op->opc = opc = opc_new2; 3099efee3746SRichard Henderson op->args[0] = op->args[1]; 3100efee3746SRichard Henderson op->args[1] = op->args[2]; 3101efee3746SRichard Henderson op->args[2] = op->args[3]; 310203271524SRichard Henderson } else { 310303271524SRichard Henderson goto do_not_remove; 310403271524SRichard Henderson } 310503271524SRichard Henderson /* Mark the single-word operation live. */ 31061414968aSRichard Henderson nb_oargs = 1; 31071414968aSRichard Henderson goto do_not_remove; 31081414968aSRichard Henderson 3109c896fe29Sbellard default: 31101305c451SRichard Henderson /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */ 3111c896fe29Sbellard nb_iargs = def->nb_iargs; 3112c896fe29Sbellard nb_oargs = def->nb_oargs; 3113c896fe29Sbellard 3114c896fe29Sbellard /* Test if the operation can be removed because all 31155ff9d6a4Sbellard its outputs are dead. We assume that nb_oargs == 0 31165ff9d6a4Sbellard implies side effects */ 31175ff9d6a4Sbellard if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) { 3118c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 3119b83eabeaSRichard Henderson if (arg_temp(op->args[i])->state != TS_DEAD) { 3120c896fe29Sbellard goto do_not_remove; 3121c896fe29Sbellard } 31229c43b68dSAurelien Jarno } 3123152c35aaSRichard Henderson goto do_remove; 3124152c35aaSRichard Henderson } 3125152c35aaSRichard Henderson goto do_not_remove; 3126152c35aaSRichard Henderson 31271305c451SRichard Henderson do_remove: 31280c627cdcSRichard Henderson tcg_op_remove(s, op); 3129152c35aaSRichard Henderson break; 3130152c35aaSRichard Henderson 3131c896fe29Sbellard do_not_remove: 3132c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 313325f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 313425f49c5fSRichard Henderson 313525f49c5fSRichard Henderson /* Remember the preference of the uses that followed. */ 313625f49c5fSRichard Henderson op->output_pref[i] = *la_temp_pref(ts); 313725f49c5fSRichard Henderson 313825f49c5fSRichard Henderson /* Output args are dead. */ 313925f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 3140a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 31416b64b624SAurelien Jarno } 314225f49c5fSRichard Henderson if (ts->state & TS_MEM) { 3143a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i; 31449c43b68dSAurelien Jarno } 314525f49c5fSRichard Henderson ts->state = TS_DEAD; 314625f49c5fSRichard Henderson la_reset_pref(ts); 3147c896fe29Sbellard } 3148c896fe29Sbellard 314925f49c5fSRichard Henderson /* If end of basic block, update. */ 3150ae36a246SRichard Henderson if (def->flags & TCG_OPF_BB_EXIT) { 3151ae36a246SRichard Henderson la_func_end(s, nb_globals, nb_temps); 3152b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_COND_BRANCH) { 3153b4cb76e6SRichard Henderson la_bb_sync(s, nb_globals, nb_temps); 3154ae36a246SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 31552616c808SRichard Henderson la_bb_end(s, nb_globals, nb_temps); 31563d5c5f87SAurelien Jarno } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { 3157f65a061cSRichard Henderson la_global_sync(s, nb_globals); 315825f49c5fSRichard Henderson if (def->flags & TCG_OPF_CALL_CLOBBER) { 315925f49c5fSRichard Henderson la_cross_call(s, nb_temps); 316025f49c5fSRichard Henderson } 3161c896fe29Sbellard } 3162c896fe29Sbellard 316325f49c5fSRichard Henderson /* Record arguments that die in this opcode. */ 3164866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 316525f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 316625f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 3167a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 3168c896fe29Sbellard } 3169c19f47bfSAurelien Jarno } 317025f49c5fSRichard Henderson 317125f49c5fSRichard Henderson /* Input arguments are live for preceding opcodes. */ 3172c19f47bfSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 317325f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 317425f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 317525f49c5fSRichard Henderson /* For operands that were dead, initially allow 317625f49c5fSRichard Henderson all regs for the type. */ 317725f49c5fSRichard Henderson *la_temp_pref(ts) = tcg_target_available_regs[ts->type]; 317825f49c5fSRichard Henderson ts->state &= ~TS_DEAD; 317925f49c5fSRichard Henderson } 318025f49c5fSRichard Henderson } 318125f49c5fSRichard Henderson 318225f49c5fSRichard Henderson /* Incorporate constraints for this operand. */ 318325f49c5fSRichard Henderson switch (opc) { 318425f49c5fSRichard Henderson case INDEX_op_mov_i32: 318525f49c5fSRichard Henderson case INDEX_op_mov_i64: 318625f49c5fSRichard Henderson /* Note that these are TCG_OPF_NOT_PRESENT and do not 318725f49c5fSRichard Henderson have proper constraints. That said, special case 318825f49c5fSRichard Henderson moves to propagate preferences backward. */ 318925f49c5fSRichard Henderson if (IS_DEAD_ARG(1)) { 319025f49c5fSRichard Henderson *la_temp_pref(arg_temp(op->args[0])) 319125f49c5fSRichard Henderson = *la_temp_pref(arg_temp(op->args[1])); 319225f49c5fSRichard Henderson } 319325f49c5fSRichard Henderson break; 319425f49c5fSRichard Henderson 319525f49c5fSRichard Henderson default: 319625f49c5fSRichard Henderson for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 319725f49c5fSRichard Henderson const TCGArgConstraint *ct = &def->args_ct[i]; 319825f49c5fSRichard Henderson TCGRegSet set, *pset; 319925f49c5fSRichard Henderson 320025f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 320125f49c5fSRichard Henderson pset = la_temp_pref(ts); 320225f49c5fSRichard Henderson set = *pset; 320325f49c5fSRichard Henderson 32049be0d080SRichard Henderson set &= ct->regs; 3205bc2b17e6SRichard Henderson if (ct->ialias) { 320625f49c5fSRichard Henderson set &= op->output_pref[ct->alias_index]; 320725f49c5fSRichard Henderson } 320825f49c5fSRichard Henderson /* If the combination is not possible, restart. */ 320925f49c5fSRichard Henderson if (set == 0) { 32109be0d080SRichard Henderson set = ct->regs; 321125f49c5fSRichard Henderson } 321225f49c5fSRichard Henderson *pset = set; 321325f49c5fSRichard Henderson } 321425f49c5fSRichard Henderson break; 3215c896fe29Sbellard } 3216c896fe29Sbellard break; 3217c896fe29Sbellard } 3218bee158cbSRichard Henderson op->life = arg_life; 3219c896fe29Sbellard } 32201ff0a2c5SEvgeny Voevodin } 3221c896fe29Sbellard 32225a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries. */ 3223b83eabeaSRichard Henderson static bool liveness_pass_2(TCGContext *s) 32245a18407fSRichard Henderson { 32255a18407fSRichard Henderson int nb_globals = s->nb_globals; 322615fa08f8SRichard Henderson int nb_temps, i; 32275a18407fSRichard Henderson bool changes = false; 322815fa08f8SRichard Henderson TCGOp *op, *op_next; 32295a18407fSRichard Henderson 32305a18407fSRichard Henderson /* Create a temporary for each indirect global. */ 32315a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 32325a18407fSRichard Henderson TCGTemp *its = &s->temps[i]; 32335a18407fSRichard Henderson if (its->indirect_reg) { 32345a18407fSRichard Henderson TCGTemp *dts = tcg_temp_alloc(s); 32355a18407fSRichard Henderson dts->type = its->type; 32365a18407fSRichard Henderson dts->base_type = its->base_type; 3237b83eabeaSRichard Henderson its->state_ptr = dts; 3238b83eabeaSRichard Henderson } else { 3239b83eabeaSRichard Henderson its->state_ptr = NULL; 32405a18407fSRichard Henderson } 3241b83eabeaSRichard Henderson /* All globals begin dead. */ 3242b83eabeaSRichard Henderson its->state = TS_DEAD; 32435a18407fSRichard Henderson } 3244b83eabeaSRichard Henderson for (nb_temps = s->nb_temps; i < nb_temps; ++i) { 3245b83eabeaSRichard Henderson TCGTemp *its = &s->temps[i]; 3246b83eabeaSRichard Henderson its->state_ptr = NULL; 3247b83eabeaSRichard Henderson its->state = TS_DEAD; 3248b83eabeaSRichard Henderson } 32495a18407fSRichard Henderson 325015fa08f8SRichard Henderson QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) { 32515a18407fSRichard Henderson TCGOpcode opc = op->opc; 32525a18407fSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 32535a18407fSRichard Henderson TCGLifeData arg_life = op->life; 32545a18407fSRichard Henderson int nb_iargs, nb_oargs, call_flags; 3255b83eabeaSRichard Henderson TCGTemp *arg_ts, *dir_ts; 32565a18407fSRichard Henderson 32575a18407fSRichard Henderson if (opc == INDEX_op_call) { 3258cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 3259cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 3260efee3746SRichard Henderson call_flags = op->args[nb_oargs + nb_iargs + 1]; 32615a18407fSRichard Henderson } else { 32625a18407fSRichard Henderson nb_iargs = def->nb_iargs; 32635a18407fSRichard Henderson nb_oargs = def->nb_oargs; 32645a18407fSRichard Henderson 32655a18407fSRichard Henderson /* Set flags similar to how calls require. */ 3266b4cb76e6SRichard Henderson if (def->flags & TCG_OPF_COND_BRANCH) { 3267b4cb76e6SRichard Henderson /* Like reading globals: sync_globals */ 3268b4cb76e6SRichard Henderson call_flags = TCG_CALL_NO_WRITE_GLOBALS; 3269b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 32705a18407fSRichard Henderson /* Like writing globals: save_globals */ 32715a18407fSRichard Henderson call_flags = 0; 32725a18407fSRichard Henderson } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { 32735a18407fSRichard Henderson /* Like reading globals: sync_globals */ 32745a18407fSRichard Henderson call_flags = TCG_CALL_NO_WRITE_GLOBALS; 32755a18407fSRichard Henderson } else { 32765a18407fSRichard Henderson /* No effect on globals. */ 32775a18407fSRichard Henderson call_flags = (TCG_CALL_NO_READ_GLOBALS | 32785a18407fSRichard Henderson TCG_CALL_NO_WRITE_GLOBALS); 32795a18407fSRichard Henderson } 32805a18407fSRichard Henderson } 32815a18407fSRichard Henderson 32825a18407fSRichard Henderson /* Make sure that input arguments are available. */ 32835a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 3284b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 3285b83eabeaSRichard Henderson if (arg_ts) { 3286b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 3287b83eabeaSRichard Henderson if (dir_ts && arg_ts->state == TS_DEAD) { 3288b83eabeaSRichard Henderson TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32 32895a18407fSRichard Henderson ? INDEX_op_ld_i32 32905a18407fSRichard Henderson : INDEX_op_ld_i64); 3291ac1043f6SEmilio G. Cota TCGOp *lop = tcg_op_insert_before(s, op, lopc); 32925a18407fSRichard Henderson 3293b83eabeaSRichard Henderson lop->args[0] = temp_arg(dir_ts); 3294b83eabeaSRichard Henderson lop->args[1] = temp_arg(arg_ts->mem_base); 3295b83eabeaSRichard Henderson lop->args[2] = arg_ts->mem_offset; 32965a18407fSRichard Henderson 32975a18407fSRichard Henderson /* Loaded, but synced with memory. */ 3298b83eabeaSRichard Henderson arg_ts->state = TS_MEM; 32995a18407fSRichard Henderson } 33005a18407fSRichard Henderson } 33015a18407fSRichard Henderson } 33025a18407fSRichard Henderson 33035a18407fSRichard Henderson /* Perform input replacement, and mark inputs that became dead. 33045a18407fSRichard Henderson No action is required except keeping temp_state up to date 33055a18407fSRichard Henderson so that we reload when needed. */ 33065a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 3307b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 3308b83eabeaSRichard Henderson if (arg_ts) { 3309b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 3310b83eabeaSRichard Henderson if (dir_ts) { 3311b83eabeaSRichard Henderson op->args[i] = temp_arg(dir_ts); 33125a18407fSRichard Henderson changes = true; 33135a18407fSRichard Henderson if (IS_DEAD_ARG(i)) { 3314b83eabeaSRichard Henderson arg_ts->state = TS_DEAD; 33155a18407fSRichard Henderson } 33165a18407fSRichard Henderson } 33175a18407fSRichard Henderson } 33185a18407fSRichard Henderson } 33195a18407fSRichard Henderson 33205a18407fSRichard Henderson /* Liveness analysis should ensure that the following are 33215a18407fSRichard Henderson all correct, for call sites and basic block end points. */ 33225a18407fSRichard Henderson if (call_flags & TCG_CALL_NO_READ_GLOBALS) { 33235a18407fSRichard Henderson /* Nothing to do */ 33245a18407fSRichard Henderson } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) { 33255a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 33265a18407fSRichard Henderson /* Liveness should see that globals are synced back, 33275a18407fSRichard Henderson that is, either TS_DEAD or TS_MEM. */ 3328b83eabeaSRichard Henderson arg_ts = &s->temps[i]; 3329b83eabeaSRichard Henderson tcg_debug_assert(arg_ts->state_ptr == 0 3330b83eabeaSRichard Henderson || arg_ts->state != 0); 33315a18407fSRichard Henderson } 33325a18407fSRichard Henderson } else { 33335a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 33345a18407fSRichard Henderson /* Liveness should see that globals are saved back, 33355a18407fSRichard Henderson that is, TS_DEAD, waiting to be reloaded. */ 3336b83eabeaSRichard Henderson arg_ts = &s->temps[i]; 3337b83eabeaSRichard Henderson tcg_debug_assert(arg_ts->state_ptr == 0 3338b83eabeaSRichard Henderson || arg_ts->state == TS_DEAD); 33395a18407fSRichard Henderson } 33405a18407fSRichard Henderson } 33415a18407fSRichard Henderson 33425a18407fSRichard Henderson /* Outputs become available. */ 334361f15c48SRichard Henderson if (opc == INDEX_op_mov_i32 || opc == INDEX_op_mov_i64) { 334461f15c48SRichard Henderson arg_ts = arg_temp(op->args[0]); 334561f15c48SRichard Henderson dir_ts = arg_ts->state_ptr; 334661f15c48SRichard Henderson if (dir_ts) { 334761f15c48SRichard Henderson op->args[0] = temp_arg(dir_ts); 334861f15c48SRichard Henderson changes = true; 334961f15c48SRichard Henderson 335061f15c48SRichard Henderson /* The output is now live and modified. */ 335161f15c48SRichard Henderson arg_ts->state = 0; 335261f15c48SRichard Henderson 335361f15c48SRichard Henderson if (NEED_SYNC_ARG(0)) { 335461f15c48SRichard Henderson TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 335561f15c48SRichard Henderson ? INDEX_op_st_i32 335661f15c48SRichard Henderson : INDEX_op_st_i64); 335761f15c48SRichard Henderson TCGOp *sop = tcg_op_insert_after(s, op, sopc); 335861f15c48SRichard Henderson TCGTemp *out_ts = dir_ts; 335961f15c48SRichard Henderson 336061f15c48SRichard Henderson if (IS_DEAD_ARG(0)) { 336161f15c48SRichard Henderson out_ts = arg_temp(op->args[1]); 336261f15c48SRichard Henderson arg_ts->state = TS_DEAD; 336361f15c48SRichard Henderson tcg_op_remove(s, op); 336461f15c48SRichard Henderson } else { 336561f15c48SRichard Henderson arg_ts->state = TS_MEM; 336661f15c48SRichard Henderson } 336761f15c48SRichard Henderson 336861f15c48SRichard Henderson sop->args[0] = temp_arg(out_ts); 336961f15c48SRichard Henderson sop->args[1] = temp_arg(arg_ts->mem_base); 337061f15c48SRichard Henderson sop->args[2] = arg_ts->mem_offset; 337161f15c48SRichard Henderson } else { 337261f15c48SRichard Henderson tcg_debug_assert(!IS_DEAD_ARG(0)); 337361f15c48SRichard Henderson } 337461f15c48SRichard Henderson } 337561f15c48SRichard Henderson } else { 33765a18407fSRichard Henderson for (i = 0; i < nb_oargs; i++) { 3377b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 3378b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 3379b83eabeaSRichard Henderson if (!dir_ts) { 33805a18407fSRichard Henderson continue; 33815a18407fSRichard Henderson } 3382b83eabeaSRichard Henderson op->args[i] = temp_arg(dir_ts); 33835a18407fSRichard Henderson changes = true; 33845a18407fSRichard Henderson 33855a18407fSRichard Henderson /* The output is now live and modified. */ 3386b83eabeaSRichard Henderson arg_ts->state = 0; 33875a18407fSRichard Henderson 33885a18407fSRichard Henderson /* Sync outputs upon their last write. */ 33895a18407fSRichard Henderson if (NEED_SYNC_ARG(i)) { 3390b83eabeaSRichard Henderson TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 33915a18407fSRichard Henderson ? INDEX_op_st_i32 33925a18407fSRichard Henderson : INDEX_op_st_i64); 3393ac1043f6SEmilio G. Cota TCGOp *sop = tcg_op_insert_after(s, op, sopc); 33945a18407fSRichard Henderson 3395b83eabeaSRichard Henderson sop->args[0] = temp_arg(dir_ts); 3396b83eabeaSRichard Henderson sop->args[1] = temp_arg(arg_ts->mem_base); 3397b83eabeaSRichard Henderson sop->args[2] = arg_ts->mem_offset; 33985a18407fSRichard Henderson 3399b83eabeaSRichard Henderson arg_ts->state = TS_MEM; 34005a18407fSRichard Henderson } 34015a18407fSRichard Henderson /* Drop outputs that are dead. */ 34025a18407fSRichard Henderson if (IS_DEAD_ARG(i)) { 3403b83eabeaSRichard Henderson arg_ts->state = TS_DEAD; 34045a18407fSRichard Henderson } 34055a18407fSRichard Henderson } 34065a18407fSRichard Henderson } 340761f15c48SRichard Henderson } 34085a18407fSRichard Henderson 34095a18407fSRichard Henderson return changes; 34105a18407fSRichard Henderson } 34115a18407fSRichard Henderson 34128d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG 3413c896fe29Sbellard static void dump_regs(TCGContext *s) 3414c896fe29Sbellard { 3415c896fe29Sbellard TCGTemp *ts; 3416c896fe29Sbellard int i; 3417c896fe29Sbellard char buf[64]; 3418c896fe29Sbellard 3419c896fe29Sbellard for(i = 0; i < s->nb_temps; i++) { 3420c896fe29Sbellard ts = &s->temps[i]; 342143439139SRichard Henderson printf(" %10s: ", tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts)); 3422c896fe29Sbellard switch(ts->val_type) { 3423c896fe29Sbellard case TEMP_VAL_REG: 3424c896fe29Sbellard printf("%s", tcg_target_reg_names[ts->reg]); 3425c896fe29Sbellard break; 3426c896fe29Sbellard case TEMP_VAL_MEM: 3427b3a62939SRichard Henderson printf("%d(%s)", (int)ts->mem_offset, 3428b3a62939SRichard Henderson tcg_target_reg_names[ts->mem_base->reg]); 3429c896fe29Sbellard break; 3430c896fe29Sbellard case TEMP_VAL_CONST: 3431bdb38b95SRichard Henderson printf("$0x%" PRIx64, ts->val); 3432c896fe29Sbellard break; 3433c896fe29Sbellard case TEMP_VAL_DEAD: 3434c896fe29Sbellard printf("D"); 3435c896fe29Sbellard break; 3436c896fe29Sbellard default: 3437c896fe29Sbellard printf("???"); 3438c896fe29Sbellard break; 3439c896fe29Sbellard } 3440c896fe29Sbellard printf("\n"); 3441c896fe29Sbellard } 3442c896fe29Sbellard 3443c896fe29Sbellard for(i = 0; i < TCG_TARGET_NB_REGS; i++) { 3444f8b2f202SRichard Henderson if (s->reg_to_temp[i] != NULL) { 3445c896fe29Sbellard printf("%s: %s\n", 3446c896fe29Sbellard tcg_target_reg_names[i], 3447f8b2f202SRichard Henderson tcg_get_arg_str_ptr(s, buf, sizeof(buf), s->reg_to_temp[i])); 3448c896fe29Sbellard } 3449c896fe29Sbellard } 3450c896fe29Sbellard } 3451c896fe29Sbellard 3452c896fe29Sbellard static void check_regs(TCGContext *s) 3453c896fe29Sbellard { 3454869938aeSRichard Henderson int reg; 3455b6638662SRichard Henderson int k; 3456c896fe29Sbellard TCGTemp *ts; 3457c896fe29Sbellard char buf[64]; 3458c896fe29Sbellard 3459c896fe29Sbellard for (reg = 0; reg < TCG_TARGET_NB_REGS; reg++) { 3460f8b2f202SRichard Henderson ts = s->reg_to_temp[reg]; 3461f8b2f202SRichard Henderson if (ts != NULL) { 3462f8b2f202SRichard Henderson if (ts->val_type != TEMP_VAL_REG || ts->reg != reg) { 3463c896fe29Sbellard printf("Inconsistency for register %s:\n", 3464c896fe29Sbellard tcg_target_reg_names[reg]); 3465b03cce8eSbellard goto fail; 3466c896fe29Sbellard } 3467c896fe29Sbellard } 3468c896fe29Sbellard } 3469c896fe29Sbellard for (k = 0; k < s->nb_temps; k++) { 3470c896fe29Sbellard ts = &s->temps[k]; 3471ee17db83SRichard Henderson if (ts->val_type == TEMP_VAL_REG 3472ee17db83SRichard Henderson && ts->kind != TEMP_FIXED 3473f8b2f202SRichard Henderson && s->reg_to_temp[ts->reg] != ts) { 3474c896fe29Sbellard printf("Inconsistency for temp %s:\n", 3475f8b2f202SRichard Henderson tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts)); 3476b03cce8eSbellard fail: 3477c896fe29Sbellard printf("reg state:\n"); 3478c896fe29Sbellard dump_regs(s); 3479c896fe29Sbellard tcg_abort(); 3480c896fe29Sbellard } 3481c896fe29Sbellard } 3482c896fe29Sbellard } 3483c896fe29Sbellard #endif 3484c896fe29Sbellard 34852272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts) 3486c896fe29Sbellard { 34879b9c37c3SRichard Henderson #if !(defined(__sparc__) && TCG_TARGET_REG_BITS == 64) 34889b9c37c3SRichard Henderson /* Sparc64 stack is accessed with offset of 2047 */ 3489b591dc59SBlue Swirl s->current_frame_offset = (s->current_frame_offset + 3490b591dc59SBlue Swirl (tcg_target_long)sizeof(tcg_target_long) - 1) & 3491b591dc59SBlue Swirl ~(sizeof(tcg_target_long) - 1); 3492f44c9960SBlue Swirl #endif 3493b591dc59SBlue Swirl if (s->current_frame_offset + (tcg_target_long)sizeof(tcg_target_long) > 3494b591dc59SBlue Swirl s->frame_end) { 34955ff9d6a4Sbellard tcg_abort(); 3496b591dc59SBlue Swirl } 3497c896fe29Sbellard ts->mem_offset = s->current_frame_offset; 3498b3a62939SRichard Henderson ts->mem_base = s->frame_temp; 3499c896fe29Sbellard ts->mem_allocated = 1; 3500e2c6d1b4SRichard Henderson s->current_frame_offset += sizeof(tcg_target_long); 3501c896fe29Sbellard } 3502c896fe29Sbellard 3503b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet); 3504b3915dbbSRichard Henderson 350559d7c14eSRichard Henderson /* Mark a temporary as free or dead. If 'free_or_dead' is negative, 350659d7c14eSRichard Henderson mark it free; otherwise mark it dead. */ 350759d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead) 3508c896fe29Sbellard { 3509c0522136SRichard Henderson TCGTempVal new_type; 3510c0522136SRichard Henderson 3511c0522136SRichard Henderson switch (ts->kind) { 3512c0522136SRichard Henderson case TEMP_FIXED: 351359d7c14eSRichard Henderson return; 3514c0522136SRichard Henderson case TEMP_GLOBAL: 3515c0522136SRichard Henderson case TEMP_LOCAL: 3516c0522136SRichard Henderson new_type = TEMP_VAL_MEM; 3517c0522136SRichard Henderson break; 3518c0522136SRichard Henderson case TEMP_NORMAL: 3519c0522136SRichard Henderson new_type = free_or_dead < 0 ? TEMP_VAL_MEM : TEMP_VAL_DEAD; 3520c0522136SRichard Henderson break; 3521c0522136SRichard Henderson case TEMP_CONST: 3522c0522136SRichard Henderson new_type = TEMP_VAL_CONST; 3523c0522136SRichard Henderson break; 3524c0522136SRichard Henderson default: 3525c0522136SRichard Henderson g_assert_not_reached(); 352659d7c14eSRichard Henderson } 352759d7c14eSRichard Henderson if (ts->val_type == TEMP_VAL_REG) { 352859d7c14eSRichard Henderson s->reg_to_temp[ts->reg] = NULL; 352959d7c14eSRichard Henderson } 3530c0522136SRichard Henderson ts->val_type = new_type; 353159d7c14eSRichard Henderson } 3532c896fe29Sbellard 353359d7c14eSRichard Henderson /* Mark a temporary as dead. */ 353459d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts) 353559d7c14eSRichard Henderson { 353659d7c14eSRichard Henderson temp_free_or_dead(s, ts, 1); 353759d7c14eSRichard Henderson } 353859d7c14eSRichard Henderson 353959d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary 354059d7c14eSRichard Henderson registers needs to be allocated to store a constant. If 'free_or_dead' 354159d7c14eSRichard Henderson is non-zero, subsequently release the temporary; if it is positive, the 354259d7c14eSRichard Henderson temp is dead; if it is negative, the temp is free. */ 354398b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs, 354498b4e186SRichard Henderson TCGRegSet preferred_regs, int free_or_dead) 354559d7c14eSRichard Henderson { 3546c0522136SRichard Henderson if (!temp_readonly(ts) && !ts->mem_coherent) { 35477f6ceedfSAurelien Jarno if (!ts->mem_allocated) { 35482272e4a7SRichard Henderson temp_allocate_frame(s, ts); 354959d7c14eSRichard Henderson } 355059d7c14eSRichard Henderson switch (ts->val_type) { 355159d7c14eSRichard Henderson case TEMP_VAL_CONST: 355259d7c14eSRichard Henderson /* If we're going to free the temp immediately, then we won't 355359d7c14eSRichard Henderson require it later in a register, so attempt to store the 355459d7c14eSRichard Henderson constant to memory directly. */ 355559d7c14eSRichard Henderson if (free_or_dead 355659d7c14eSRichard Henderson && tcg_out_sti(s, ts->type, ts->val, 355759d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset)) { 355859d7c14eSRichard Henderson break; 355959d7c14eSRichard Henderson } 356059d7c14eSRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 356198b4e186SRichard Henderson allocated_regs, preferred_regs); 356259d7c14eSRichard Henderson /* fallthrough */ 356359d7c14eSRichard Henderson 356459d7c14eSRichard Henderson case TEMP_VAL_REG: 356559d7c14eSRichard Henderson tcg_out_st(s, ts->type, ts->reg, 356659d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset); 356759d7c14eSRichard Henderson break; 356859d7c14eSRichard Henderson 356959d7c14eSRichard Henderson case TEMP_VAL_MEM: 357059d7c14eSRichard Henderson break; 357159d7c14eSRichard Henderson 357259d7c14eSRichard Henderson case TEMP_VAL_DEAD: 357359d7c14eSRichard Henderson default: 357459d7c14eSRichard Henderson tcg_abort(); 3575c896fe29Sbellard } 35767f6ceedfSAurelien Jarno ts->mem_coherent = 1; 35777f6ceedfSAurelien Jarno } 357859d7c14eSRichard Henderson if (free_or_dead) { 357959d7c14eSRichard Henderson temp_free_or_dead(s, ts, free_or_dead); 358059d7c14eSRichard Henderson } 358159d7c14eSRichard Henderson } 35827f6ceedfSAurelien Jarno 35837f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */ 3584b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs) 35857f6ceedfSAurelien Jarno { 3586f8b2f202SRichard Henderson TCGTemp *ts = s->reg_to_temp[reg]; 3587f8b2f202SRichard Henderson if (ts != NULL) { 358898b4e186SRichard Henderson temp_sync(s, ts, allocated_regs, 0, -1); 3589c896fe29Sbellard } 3590c896fe29Sbellard } 3591c896fe29Sbellard 3592b016486eSRichard Henderson /** 3593b016486eSRichard Henderson * tcg_reg_alloc: 3594b016486eSRichard Henderson * @required_regs: Set of registers in which we must allocate. 3595b016486eSRichard Henderson * @allocated_regs: Set of registers which must be avoided. 3596b016486eSRichard Henderson * @preferred_regs: Set of registers we should prefer. 3597b016486eSRichard Henderson * @rev: True if we search the registers in "indirect" order. 3598b016486eSRichard Henderson * 3599b016486eSRichard Henderson * The allocated register must be in @required_regs & ~@allocated_regs, 3600b016486eSRichard Henderson * but if we can put it in @preferred_regs we may save a move later. 3601b016486eSRichard Henderson */ 3602b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs, 3603b016486eSRichard Henderson TCGRegSet allocated_regs, 3604b016486eSRichard Henderson TCGRegSet preferred_regs, bool rev) 3605c896fe29Sbellard { 3606b016486eSRichard Henderson int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order); 3607b016486eSRichard Henderson TCGRegSet reg_ct[2]; 360891478cefSRichard Henderson const int *order; 3609c896fe29Sbellard 3610b016486eSRichard Henderson reg_ct[1] = required_regs & ~allocated_regs; 3611b016486eSRichard Henderson tcg_debug_assert(reg_ct[1] != 0); 3612b016486eSRichard Henderson reg_ct[0] = reg_ct[1] & preferred_regs; 3613b016486eSRichard Henderson 3614b016486eSRichard Henderson /* Skip the preferred_regs option if it cannot be satisfied, 3615b016486eSRichard Henderson or if the preference made no difference. */ 3616b016486eSRichard Henderson f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1]; 3617b016486eSRichard Henderson 361891478cefSRichard Henderson order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order; 3619c896fe29Sbellard 3620b016486eSRichard Henderson /* Try free registers, preferences first. */ 3621b016486eSRichard Henderson for (j = f; j < 2; j++) { 3622b016486eSRichard Henderson TCGRegSet set = reg_ct[j]; 3623b016486eSRichard Henderson 3624b016486eSRichard Henderson if (tcg_regset_single(set)) { 3625b016486eSRichard Henderson /* One register in the set. */ 3626b016486eSRichard Henderson TCGReg reg = tcg_regset_first(set); 3627b016486eSRichard Henderson if (s->reg_to_temp[reg] == NULL) { 3628c896fe29Sbellard return reg; 3629c896fe29Sbellard } 3630b016486eSRichard Henderson } else { 363191478cefSRichard Henderson for (i = 0; i < n; i++) { 3632b016486eSRichard Henderson TCGReg reg = order[i]; 3633b016486eSRichard Henderson if (s->reg_to_temp[reg] == NULL && 3634b016486eSRichard Henderson tcg_regset_test_reg(set, reg)) { 3635b016486eSRichard Henderson return reg; 3636b016486eSRichard Henderson } 3637b016486eSRichard Henderson } 3638b016486eSRichard Henderson } 3639b016486eSRichard Henderson } 3640b016486eSRichard Henderson 3641b016486eSRichard Henderson /* We must spill something. */ 3642b016486eSRichard Henderson for (j = f; j < 2; j++) { 3643b016486eSRichard Henderson TCGRegSet set = reg_ct[j]; 3644b016486eSRichard Henderson 3645b016486eSRichard Henderson if (tcg_regset_single(set)) { 3646b016486eSRichard Henderson /* One register in the set. */ 3647b016486eSRichard Henderson TCGReg reg = tcg_regset_first(set); 3648b3915dbbSRichard Henderson tcg_reg_free(s, reg, allocated_regs); 3649c896fe29Sbellard return reg; 3650b016486eSRichard Henderson } else { 3651b016486eSRichard Henderson for (i = 0; i < n; i++) { 3652b016486eSRichard Henderson TCGReg reg = order[i]; 3653b016486eSRichard Henderson if (tcg_regset_test_reg(set, reg)) { 3654b016486eSRichard Henderson tcg_reg_free(s, reg, allocated_regs); 3655b016486eSRichard Henderson return reg; 3656b016486eSRichard Henderson } 3657b016486eSRichard Henderson } 3658c896fe29Sbellard } 3659c896fe29Sbellard } 3660c896fe29Sbellard 3661c896fe29Sbellard tcg_abort(); 3662c896fe29Sbellard } 3663c896fe29Sbellard 366440ae5c62SRichard Henderson /* Make sure the temporary is in a register. If needed, allocate the register 366540ae5c62SRichard Henderson from DESIRED while avoiding ALLOCATED. */ 366640ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs, 3667b722452aSRichard Henderson TCGRegSet allocated_regs, TCGRegSet preferred_regs) 366840ae5c62SRichard Henderson { 366940ae5c62SRichard Henderson TCGReg reg; 367040ae5c62SRichard Henderson 367140ae5c62SRichard Henderson switch (ts->val_type) { 367240ae5c62SRichard Henderson case TEMP_VAL_REG: 367340ae5c62SRichard Henderson return; 367440ae5c62SRichard Henderson case TEMP_VAL_CONST: 3675b016486eSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs, 3676b722452aSRichard Henderson preferred_regs, ts->indirect_base); 36770a6a8bc8SRichard Henderson if (ts->type <= TCG_TYPE_I64) { 367840ae5c62SRichard Henderson tcg_out_movi(s, ts->type, reg, ts->val); 36790a6a8bc8SRichard Henderson } else { 36804e186175SRichard Henderson uint64_t val = ts->val; 36814e186175SRichard Henderson MemOp vece = MO_64; 36824e186175SRichard Henderson 36834e186175SRichard Henderson /* 36844e186175SRichard Henderson * Find the minimal vector element that matches the constant. 36854e186175SRichard Henderson * The targets will, in general, have to do this search anyway, 36864e186175SRichard Henderson * do this generically. 36874e186175SRichard Henderson */ 36884e186175SRichard Henderson if (val == dup_const(MO_8, val)) { 36894e186175SRichard Henderson vece = MO_8; 36904e186175SRichard Henderson } else if (val == dup_const(MO_16, val)) { 36914e186175SRichard Henderson vece = MO_16; 36920b4286ddSRichard Henderson } else if (val == dup_const(MO_32, val)) { 36934e186175SRichard Henderson vece = MO_32; 36944e186175SRichard Henderson } 36954e186175SRichard Henderson 36964e186175SRichard Henderson tcg_out_dupi_vec(s, ts->type, vece, reg, ts->val); 36970a6a8bc8SRichard Henderson } 369840ae5c62SRichard Henderson ts->mem_coherent = 0; 369940ae5c62SRichard Henderson break; 370040ae5c62SRichard Henderson case TEMP_VAL_MEM: 3701b016486eSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs, 3702b722452aSRichard Henderson preferred_regs, ts->indirect_base); 370340ae5c62SRichard Henderson tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset); 370440ae5c62SRichard Henderson ts->mem_coherent = 1; 370540ae5c62SRichard Henderson break; 370640ae5c62SRichard Henderson case TEMP_VAL_DEAD: 370740ae5c62SRichard Henderson default: 370840ae5c62SRichard Henderson tcg_abort(); 370940ae5c62SRichard Henderson } 371040ae5c62SRichard Henderson ts->reg = reg; 371140ae5c62SRichard Henderson ts->val_type = TEMP_VAL_REG; 371240ae5c62SRichard Henderson s->reg_to_temp[reg] = ts; 371340ae5c62SRichard Henderson } 371440ae5c62SRichard Henderson 371559d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a 3716e8996ee0Sbellard temporary registers needs to be allocated to store a constant. */ 371759d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs) 37181ad80729SAurelien Jarno { 37192c0366f0SAurelien Jarno /* The liveness analysis already ensures that globals are back 3720eabb7b91SAurelien Jarno in memory. Keep an tcg_debug_assert for safety. */ 3721e01fa97dSRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || temp_readonly(ts)); 37221ad80729SAurelien Jarno } 37231ad80729SAurelien Jarno 37249814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be 3725641d5fbeSbellard modified be the following code. 'allocated_regs' is used in case a 3726641d5fbeSbellard temporary registers needs to be allocated to store a constant. */ 3727641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs) 3728641d5fbeSbellard { 3729ac3b8891SRichard Henderson int i, n; 3730641d5fbeSbellard 3731ac3b8891SRichard Henderson for (i = 0, n = s->nb_globals; i < n; i++) { 3732b13eb728SRichard Henderson temp_save(s, &s->temps[i], allocated_regs); 3733641d5fbeSbellard } 3734e5097dc8Sbellard } 3735e5097dc8Sbellard 37363d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be 37373d5c5f87SAurelien Jarno read by the following code. 'allocated_regs' is used in case a 37383d5c5f87SAurelien Jarno temporary registers needs to be allocated to store a constant. */ 37393d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs) 37403d5c5f87SAurelien Jarno { 3741ac3b8891SRichard Henderson int i, n; 37423d5c5f87SAurelien Jarno 3743ac3b8891SRichard Henderson for (i = 0, n = s->nb_globals; i < n; i++) { 374412b9b11aSRichard Henderson TCGTemp *ts = &s->temps[i]; 374512b9b11aSRichard Henderson tcg_debug_assert(ts->val_type != TEMP_VAL_REG 3746ee17db83SRichard Henderson || ts->kind == TEMP_FIXED 374712b9b11aSRichard Henderson || ts->mem_coherent); 37483d5c5f87SAurelien Jarno } 37493d5c5f87SAurelien Jarno } 37503d5c5f87SAurelien Jarno 3751e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and 3752e8996ee0Sbellard all globals are stored at their canonical location. */ 3753e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs) 3754e5097dc8Sbellard { 3755e5097dc8Sbellard int i; 3756e5097dc8Sbellard 3757c896fe29Sbellard for (i = s->nb_globals; i < s->nb_temps; i++) { 3758b13eb728SRichard Henderson TCGTemp *ts = &s->temps[i]; 3759c0522136SRichard Henderson 3760c0522136SRichard Henderson switch (ts->kind) { 3761c0522136SRichard Henderson case TEMP_LOCAL: 3762b13eb728SRichard Henderson temp_save(s, ts, allocated_regs); 3763c0522136SRichard Henderson break; 3764c0522136SRichard Henderson case TEMP_NORMAL: 37652c0366f0SAurelien Jarno /* The liveness analysis already ensures that temps are dead. 3766eabb7b91SAurelien Jarno Keep an tcg_debug_assert for safety. */ 3767eabb7b91SAurelien Jarno tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD); 3768c0522136SRichard Henderson break; 3769c0522136SRichard Henderson case TEMP_CONST: 3770c0522136SRichard Henderson /* Similarly, we should have freed any allocated register. */ 3771c0522136SRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_CONST); 3772c0522136SRichard Henderson break; 3773c0522136SRichard Henderson default: 3774c0522136SRichard Henderson g_assert_not_reached(); 3775c896fe29Sbellard } 3776641d5fbeSbellard } 3777e8996ee0Sbellard 3778e8996ee0Sbellard save_globals(s, allocated_regs); 3779c896fe29Sbellard } 3780c896fe29Sbellard 3781bab1671fSRichard Henderson /* 3782b4cb76e6SRichard Henderson * At a conditional branch, we assume all temporaries are dead and 3783b4cb76e6SRichard Henderson * all globals and local temps are synced to their location. 3784b4cb76e6SRichard Henderson */ 3785b4cb76e6SRichard Henderson static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs) 3786b4cb76e6SRichard Henderson { 3787b4cb76e6SRichard Henderson sync_globals(s, allocated_regs); 3788b4cb76e6SRichard Henderson 3789b4cb76e6SRichard Henderson for (int i = s->nb_globals; i < s->nb_temps; i++) { 3790b4cb76e6SRichard Henderson TCGTemp *ts = &s->temps[i]; 3791b4cb76e6SRichard Henderson /* 3792b4cb76e6SRichard Henderson * The liveness analysis already ensures that temps are dead. 3793b4cb76e6SRichard Henderson * Keep tcg_debug_asserts for safety. 3794b4cb76e6SRichard Henderson */ 3795c0522136SRichard Henderson switch (ts->kind) { 3796c0522136SRichard Henderson case TEMP_LOCAL: 3797b4cb76e6SRichard Henderson tcg_debug_assert(ts->val_type != TEMP_VAL_REG || ts->mem_coherent); 3798c0522136SRichard Henderson break; 3799c0522136SRichard Henderson case TEMP_NORMAL: 3800b4cb76e6SRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD); 3801c0522136SRichard Henderson break; 3802c0522136SRichard Henderson case TEMP_CONST: 3803c0522136SRichard Henderson break; 3804c0522136SRichard Henderson default: 3805c0522136SRichard Henderson g_assert_not_reached(); 3806b4cb76e6SRichard Henderson } 3807b4cb76e6SRichard Henderson } 3808b4cb76e6SRichard Henderson } 3809b4cb76e6SRichard Henderson 3810b4cb76e6SRichard Henderson /* 3811c58f4c97SRichard Henderson * Specialized code generation for INDEX_op_mov_* with a constant. 3812bab1671fSRichard Henderson */ 38130fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots, 3814ba87719cSRichard Henderson tcg_target_ulong val, TCGLifeData arg_life, 3815ba87719cSRichard Henderson TCGRegSet preferred_regs) 3816e8996ee0Sbellard { 3817d63e3b6eSRichard Henderson /* ENV should not be modified. */ 3818e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 381959d7c14eSRichard Henderson 382059d7c14eSRichard Henderson /* The movi is not explicitly generated here. */ 3821f8b2f202SRichard Henderson if (ots->val_type == TEMP_VAL_REG) { 3822f8b2f202SRichard Henderson s->reg_to_temp[ots->reg] = NULL; 3823f8b2f202SRichard Henderson } 3824e8996ee0Sbellard ots->val_type = TEMP_VAL_CONST; 3825e8996ee0Sbellard ots->val = val; 382659d7c14eSRichard Henderson ots->mem_coherent = 0; 3827ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) { 3828ba87719cSRichard Henderson temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0)); 382959d7c14eSRichard Henderson } else if (IS_DEAD_ARG(0)) { 3830f8bf00f1SRichard Henderson temp_dead(s, ots); 38314c4e1ab2SAurelien Jarno } 3832e8996ee0Sbellard } 3833e8996ee0Sbellard 3834bab1671fSRichard Henderson /* 3835bab1671fSRichard Henderson * Specialized code generation for INDEX_op_mov_*. 3836bab1671fSRichard Henderson */ 3837dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op) 3838c896fe29Sbellard { 3839dd186292SRichard Henderson const TCGLifeData arg_life = op->life; 384069e3706dSRichard Henderson TCGRegSet allocated_regs, preferred_regs; 3841c896fe29Sbellard TCGTemp *ts, *ots; 3842450445d5SRichard Henderson TCGType otype, itype; 3843c896fe29Sbellard 3844d21369f5SRichard Henderson allocated_regs = s->reserved_regs; 384569e3706dSRichard Henderson preferred_regs = op->output_pref[0]; 384643439139SRichard Henderson ots = arg_temp(op->args[0]); 384743439139SRichard Henderson ts = arg_temp(op->args[1]); 3848450445d5SRichard Henderson 3849d63e3b6eSRichard Henderson /* ENV should not be modified. */ 3850e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 3851d63e3b6eSRichard Henderson 3852450445d5SRichard Henderson /* Note that otype != itype for no-op truncation. */ 3853450445d5SRichard Henderson otype = ots->type; 3854450445d5SRichard Henderson itype = ts->type; 3855c896fe29Sbellard 38560fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_CONST) { 38570fe4fca4SPaolo Bonzini /* propagate constant or generate sti */ 38580fe4fca4SPaolo Bonzini tcg_target_ulong val = ts->val; 38590fe4fca4SPaolo Bonzini if (IS_DEAD_ARG(1)) { 38600fe4fca4SPaolo Bonzini temp_dead(s, ts); 38610fe4fca4SPaolo Bonzini } 386269e3706dSRichard Henderson tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs); 38630fe4fca4SPaolo Bonzini return; 38640fe4fca4SPaolo Bonzini } 38650fe4fca4SPaolo Bonzini 38660fe4fca4SPaolo Bonzini /* If the source value is in memory we're going to be forced 38670fe4fca4SPaolo Bonzini to have it in a register in order to perform the copy. Copy 38680fe4fca4SPaolo Bonzini the SOURCE value into its own register first, that way we 38690fe4fca4SPaolo Bonzini don't have to reload SOURCE the next time it is used. */ 38700fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_MEM) { 387169e3706dSRichard Henderson temp_load(s, ts, tcg_target_available_regs[itype], 387269e3706dSRichard Henderson allocated_regs, preferred_regs); 3873c29c1d7eSAurelien Jarno } 3874c29c1d7eSAurelien Jarno 38750fe4fca4SPaolo Bonzini tcg_debug_assert(ts->val_type == TEMP_VAL_REG); 3876d63e3b6eSRichard Henderson if (IS_DEAD_ARG(0)) { 3877c29c1d7eSAurelien Jarno /* mov to a non-saved dead register makes no sense (even with 3878c29c1d7eSAurelien Jarno liveness analysis disabled). */ 3879eabb7b91SAurelien Jarno tcg_debug_assert(NEED_SYNC_ARG(0)); 3880c29c1d7eSAurelien Jarno if (!ots->mem_allocated) { 38812272e4a7SRichard Henderson temp_allocate_frame(s, ots); 3882c29c1d7eSAurelien Jarno } 3883b3a62939SRichard Henderson tcg_out_st(s, otype, ts->reg, ots->mem_base->reg, ots->mem_offset); 3884c29c1d7eSAurelien Jarno if (IS_DEAD_ARG(1)) { 3885f8bf00f1SRichard Henderson temp_dead(s, ts); 3886c29c1d7eSAurelien Jarno } 3887f8bf00f1SRichard Henderson temp_dead(s, ots); 3888e8996ee0Sbellard } else { 3889ee17db83SRichard Henderson if (IS_DEAD_ARG(1) && ts->kind != TEMP_FIXED) { 3890c29c1d7eSAurelien Jarno /* the mov can be suppressed */ 3891c29c1d7eSAurelien Jarno if (ots->val_type == TEMP_VAL_REG) { 3892f8b2f202SRichard Henderson s->reg_to_temp[ots->reg] = NULL; 3893c896fe29Sbellard } 3894c29c1d7eSAurelien Jarno ots->reg = ts->reg; 3895f8bf00f1SRichard Henderson temp_dead(s, ts); 3896c29c1d7eSAurelien Jarno } else { 3897c29c1d7eSAurelien Jarno if (ots->val_type != TEMP_VAL_REG) { 3898c29c1d7eSAurelien Jarno /* When allocating a new register, make sure to not spill the 3899c29c1d7eSAurelien Jarno input one. */ 3900c29c1d7eSAurelien Jarno tcg_regset_set_reg(allocated_regs, ts->reg); 3901450445d5SRichard Henderson ots->reg = tcg_reg_alloc(s, tcg_target_available_regs[otype], 390269e3706dSRichard Henderson allocated_regs, preferred_regs, 3903b016486eSRichard Henderson ots->indirect_base); 3904c29c1d7eSAurelien Jarno } 390578113e83SRichard Henderson if (!tcg_out_mov(s, otype, ots->reg, ts->reg)) { 3906240c08d0SRichard Henderson /* 3907240c08d0SRichard Henderson * Cross register class move not supported. 3908240c08d0SRichard Henderson * Store the source register into the destination slot 3909240c08d0SRichard Henderson * and leave the destination temp as TEMP_VAL_MEM. 3910240c08d0SRichard Henderson */ 3911e01fa97dSRichard Henderson assert(!temp_readonly(ots)); 3912240c08d0SRichard Henderson if (!ts->mem_allocated) { 3913240c08d0SRichard Henderson temp_allocate_frame(s, ots); 3914240c08d0SRichard Henderson } 3915240c08d0SRichard Henderson tcg_out_st(s, ts->type, ts->reg, 3916240c08d0SRichard Henderson ots->mem_base->reg, ots->mem_offset); 3917240c08d0SRichard Henderson ots->mem_coherent = 1; 3918240c08d0SRichard Henderson temp_free_or_dead(s, ots, -1); 3919240c08d0SRichard Henderson return; 392078113e83SRichard Henderson } 3921c29c1d7eSAurelien Jarno } 3922c896fe29Sbellard ots->val_type = TEMP_VAL_REG; 3923c896fe29Sbellard ots->mem_coherent = 0; 3924f8b2f202SRichard Henderson s->reg_to_temp[ots->reg] = ots; 3925ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) { 392698b4e186SRichard Henderson temp_sync(s, ots, allocated_regs, 0, 0); 3927c29c1d7eSAurelien Jarno } 3928ec7a869dSAurelien Jarno } 3929c896fe29Sbellard } 3930c896fe29Sbellard 3931bab1671fSRichard Henderson /* 3932bab1671fSRichard Henderson * Specialized code generation for INDEX_op_dup_vec. 3933bab1671fSRichard Henderson */ 3934bab1671fSRichard Henderson static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op) 3935bab1671fSRichard Henderson { 3936bab1671fSRichard Henderson const TCGLifeData arg_life = op->life; 3937bab1671fSRichard Henderson TCGRegSet dup_out_regs, dup_in_regs; 3938bab1671fSRichard Henderson TCGTemp *its, *ots; 3939bab1671fSRichard Henderson TCGType itype, vtype; 3940d6ecb4a9SRichard Henderson intptr_t endian_fixup; 3941bab1671fSRichard Henderson unsigned vece; 3942bab1671fSRichard Henderson bool ok; 3943bab1671fSRichard Henderson 3944bab1671fSRichard Henderson ots = arg_temp(op->args[0]); 3945bab1671fSRichard Henderson its = arg_temp(op->args[1]); 3946bab1671fSRichard Henderson 3947bab1671fSRichard Henderson /* ENV should not be modified. */ 3948e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 3949bab1671fSRichard Henderson 3950bab1671fSRichard Henderson itype = its->type; 3951bab1671fSRichard Henderson vece = TCGOP_VECE(op); 3952bab1671fSRichard Henderson vtype = TCGOP_VECL(op) + TCG_TYPE_V64; 3953bab1671fSRichard Henderson 3954bab1671fSRichard Henderson if (its->val_type == TEMP_VAL_CONST) { 3955bab1671fSRichard Henderson /* Propagate constant via movi -> dupi. */ 3956bab1671fSRichard Henderson tcg_target_ulong val = its->val; 3957bab1671fSRichard Henderson if (IS_DEAD_ARG(1)) { 3958bab1671fSRichard Henderson temp_dead(s, its); 3959bab1671fSRichard Henderson } 3960bab1671fSRichard Henderson tcg_reg_alloc_do_movi(s, ots, val, arg_life, op->output_pref[0]); 3961bab1671fSRichard Henderson return; 3962bab1671fSRichard Henderson } 3963bab1671fSRichard Henderson 39649be0d080SRichard Henderson dup_out_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs; 39659be0d080SRichard Henderson dup_in_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[1].regs; 3966bab1671fSRichard Henderson 3967bab1671fSRichard Henderson /* Allocate the output register now. */ 3968bab1671fSRichard Henderson if (ots->val_type != TEMP_VAL_REG) { 3969bab1671fSRichard Henderson TCGRegSet allocated_regs = s->reserved_regs; 3970bab1671fSRichard Henderson 3971bab1671fSRichard Henderson if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) { 3972bab1671fSRichard Henderson /* Make sure to not spill the input register. */ 3973bab1671fSRichard Henderson tcg_regset_set_reg(allocated_regs, its->reg); 3974bab1671fSRichard Henderson } 3975bab1671fSRichard Henderson ots->reg = tcg_reg_alloc(s, dup_out_regs, allocated_regs, 3976bab1671fSRichard Henderson op->output_pref[0], ots->indirect_base); 3977bab1671fSRichard Henderson ots->val_type = TEMP_VAL_REG; 3978bab1671fSRichard Henderson ots->mem_coherent = 0; 3979bab1671fSRichard Henderson s->reg_to_temp[ots->reg] = ots; 3980bab1671fSRichard Henderson } 3981bab1671fSRichard Henderson 3982bab1671fSRichard Henderson switch (its->val_type) { 3983bab1671fSRichard Henderson case TEMP_VAL_REG: 3984bab1671fSRichard Henderson /* 3985bab1671fSRichard Henderson * The dup constriaints must be broad, covering all possible VECE. 3986bab1671fSRichard Henderson * However, tcg_op_dup_vec() gets to see the VECE and we allow it 3987bab1671fSRichard Henderson * to fail, indicating that extra moves are required for that case. 3988bab1671fSRichard Henderson */ 3989bab1671fSRichard Henderson if (tcg_regset_test_reg(dup_in_regs, its->reg)) { 3990bab1671fSRichard Henderson if (tcg_out_dup_vec(s, vtype, vece, ots->reg, its->reg)) { 3991bab1671fSRichard Henderson goto done; 3992bab1671fSRichard Henderson } 3993bab1671fSRichard Henderson /* Try again from memory or a vector input register. */ 3994bab1671fSRichard Henderson } 3995bab1671fSRichard Henderson if (!its->mem_coherent) { 3996bab1671fSRichard Henderson /* 3997bab1671fSRichard Henderson * The input register is not synced, and so an extra store 3998bab1671fSRichard Henderson * would be required to use memory. Attempt an integer-vector 3999bab1671fSRichard Henderson * register move first. We do not have a TCGRegSet for this. 4000bab1671fSRichard Henderson */ 4001bab1671fSRichard Henderson if (tcg_out_mov(s, itype, ots->reg, its->reg)) { 4002bab1671fSRichard Henderson break; 4003bab1671fSRichard Henderson } 4004bab1671fSRichard Henderson /* Sync the temp back to its slot and load from there. */ 4005bab1671fSRichard Henderson temp_sync(s, its, s->reserved_regs, 0, 0); 4006bab1671fSRichard Henderson } 4007bab1671fSRichard Henderson /* fall through */ 4008bab1671fSRichard Henderson 4009bab1671fSRichard Henderson case TEMP_VAL_MEM: 4010d6ecb4a9SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 4011d6ecb4a9SRichard Henderson endian_fixup = itype == TCG_TYPE_I32 ? 4 : 8; 4012d6ecb4a9SRichard Henderson endian_fixup -= 1 << vece; 4013d6ecb4a9SRichard Henderson #else 4014d6ecb4a9SRichard Henderson endian_fixup = 0; 4015d6ecb4a9SRichard Henderson #endif 4016d6ecb4a9SRichard Henderson if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg, 4017d6ecb4a9SRichard Henderson its->mem_offset + endian_fixup)) { 4018d6ecb4a9SRichard Henderson goto done; 4019d6ecb4a9SRichard Henderson } 4020bab1671fSRichard Henderson tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset); 4021bab1671fSRichard Henderson break; 4022bab1671fSRichard Henderson 4023bab1671fSRichard Henderson default: 4024bab1671fSRichard Henderson g_assert_not_reached(); 4025bab1671fSRichard Henderson } 4026bab1671fSRichard Henderson 4027bab1671fSRichard Henderson /* We now have a vector input register, so dup must succeed. */ 4028bab1671fSRichard Henderson ok = tcg_out_dup_vec(s, vtype, vece, ots->reg, ots->reg); 4029bab1671fSRichard Henderson tcg_debug_assert(ok); 4030bab1671fSRichard Henderson 4031bab1671fSRichard Henderson done: 4032bab1671fSRichard Henderson if (IS_DEAD_ARG(1)) { 4033bab1671fSRichard Henderson temp_dead(s, its); 4034bab1671fSRichard Henderson } 4035bab1671fSRichard Henderson if (NEED_SYNC_ARG(0)) { 4036bab1671fSRichard Henderson temp_sync(s, ots, s->reserved_regs, 0, 0); 4037bab1671fSRichard Henderson } 4038bab1671fSRichard Henderson if (IS_DEAD_ARG(0)) { 4039bab1671fSRichard Henderson temp_dead(s, ots); 4040bab1671fSRichard Henderson } 4041bab1671fSRichard Henderson } 4042bab1671fSRichard Henderson 4043dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) 4044c896fe29Sbellard { 4045dd186292SRichard Henderson const TCGLifeData arg_life = op->life; 4046dd186292SRichard Henderson const TCGOpDef * const def = &tcg_op_defs[op->opc]; 404782790a87SRichard Henderson TCGRegSet i_allocated_regs; 404882790a87SRichard Henderson TCGRegSet o_allocated_regs; 4049b6638662SRichard Henderson int i, k, nb_iargs, nb_oargs; 4050b6638662SRichard Henderson TCGReg reg; 4051c896fe29Sbellard TCGArg arg; 4052c896fe29Sbellard const TCGArgConstraint *arg_ct; 4053c896fe29Sbellard TCGTemp *ts; 4054c896fe29Sbellard TCGArg new_args[TCG_MAX_OP_ARGS]; 4055c896fe29Sbellard int const_args[TCG_MAX_OP_ARGS]; 4056c896fe29Sbellard 4057c896fe29Sbellard nb_oargs = def->nb_oargs; 4058c896fe29Sbellard nb_iargs = def->nb_iargs; 4059c896fe29Sbellard 4060c896fe29Sbellard /* copy constants */ 4061c896fe29Sbellard memcpy(new_args + nb_oargs + nb_iargs, 4062dd186292SRichard Henderson op->args + nb_oargs + nb_iargs, 4063c896fe29Sbellard sizeof(TCGArg) * def->nb_cargs); 4064c896fe29Sbellard 4065d21369f5SRichard Henderson i_allocated_regs = s->reserved_regs; 4066d21369f5SRichard Henderson o_allocated_regs = s->reserved_regs; 406782790a87SRichard Henderson 4068c896fe29Sbellard /* satisfy input constraints */ 4069c896fe29Sbellard for (k = 0; k < nb_iargs; k++) { 4070d62816f2SRichard Henderson TCGRegSet i_preferred_regs, o_preferred_regs; 4071d62816f2SRichard Henderson 407266792f90SRichard Henderson i = def->args_ct[nb_oargs + k].sort_index; 4073dd186292SRichard Henderson arg = op->args[i]; 4074c896fe29Sbellard arg_ct = &def->args_ct[i]; 407543439139SRichard Henderson ts = arg_temp(arg); 407640ae5c62SRichard Henderson 407740ae5c62SRichard Henderson if (ts->val_type == TEMP_VAL_CONST 407840ae5c62SRichard Henderson && tcg_target_const_match(ts->val, ts->type, arg_ct)) { 4079c896fe29Sbellard /* constant is OK for instruction */ 4080c896fe29Sbellard const_args[i] = 1; 4081c896fe29Sbellard new_args[i] = ts->val; 4082d62816f2SRichard Henderson continue; 4083c896fe29Sbellard } 408440ae5c62SRichard Henderson 4085d62816f2SRichard Henderson i_preferred_regs = o_preferred_regs = 0; 4086bc2b17e6SRichard Henderson if (arg_ct->ialias) { 4087d62816f2SRichard Henderson o_preferred_regs = op->output_pref[arg_ct->alias_index]; 4088c0522136SRichard Henderson 4089c0522136SRichard Henderson /* 4090c0522136SRichard Henderson * If the input is readonly, then it cannot also be an 4091c0522136SRichard Henderson * output and aliased to itself. If the input is not 4092c0522136SRichard Henderson * dead after the instruction, we must allocate a new 4093c0522136SRichard Henderson * register and move it. 4094c0522136SRichard Henderson */ 4095c0522136SRichard Henderson if (temp_readonly(ts) || !IS_DEAD_ARG(i)) { 4096c896fe29Sbellard goto allocate_in_reg; 4097c896fe29Sbellard } 4098d62816f2SRichard Henderson 4099c0522136SRichard Henderson /* 4100c0522136SRichard Henderson * Check if the current register has already been allocated 4101c0522136SRichard Henderson * for another input aliased to an output. 4102c0522136SRichard Henderson */ 4103d62816f2SRichard Henderson if (ts->val_type == TEMP_VAL_REG) { 4104d62816f2SRichard Henderson reg = ts->reg; 4105c0522136SRichard Henderson for (int k2 = 0; k2 < k; k2++) { 4106c0522136SRichard Henderson int i2 = def->args_ct[nb_oargs + k2].sort_index; 4107bc2b17e6SRichard Henderson if (def->args_ct[i2].ialias && reg == new_args[i2]) { 41087e1df267SAurelien Jarno goto allocate_in_reg; 41097e1df267SAurelien Jarno } 41107e1df267SAurelien Jarno } 41115ff9d6a4Sbellard } 4112d62816f2SRichard Henderson i_preferred_regs = o_preferred_regs; 4113866cb6cbSAurelien Jarno } 4114d62816f2SRichard Henderson 41159be0d080SRichard Henderson temp_load(s, ts, arg_ct->regs, i_allocated_regs, i_preferred_regs); 4116c896fe29Sbellard reg = ts->reg; 4117d62816f2SRichard Henderson 4118c0522136SRichard Henderson if (!tcg_regset_test_reg(arg_ct->regs, reg)) { 4119c896fe29Sbellard allocate_in_reg: 4120c0522136SRichard Henderson /* 4121c0522136SRichard Henderson * Allocate a new register matching the constraint 4122c0522136SRichard Henderson * and move the temporary register into it. 4123c0522136SRichard Henderson */ 4124d62816f2SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 4125d62816f2SRichard Henderson i_allocated_regs, 0); 41269be0d080SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->regs, i_allocated_regs, 4127d62816f2SRichard Henderson o_preferred_regs, ts->indirect_base); 412878113e83SRichard Henderson if (!tcg_out_mov(s, ts->type, reg, ts->reg)) { 4129240c08d0SRichard Henderson /* 4130240c08d0SRichard Henderson * Cross register class move not supported. Sync the 4131240c08d0SRichard Henderson * temp back to its slot and load from there. 4132240c08d0SRichard Henderson */ 4133240c08d0SRichard Henderson temp_sync(s, ts, i_allocated_regs, 0, 0); 4134240c08d0SRichard Henderson tcg_out_ld(s, ts->type, reg, 4135240c08d0SRichard Henderson ts->mem_base->reg, ts->mem_offset); 413678113e83SRichard Henderson } 4137c896fe29Sbellard } 4138c896fe29Sbellard new_args[i] = reg; 4139c896fe29Sbellard const_args[i] = 0; 414082790a87SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg); 4141c896fe29Sbellard } 4142c896fe29Sbellard 4143c896fe29Sbellard /* mark dead temporaries and free the associated registers */ 4144866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 4145866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) { 414643439139SRichard Henderson temp_dead(s, arg_temp(op->args[i])); 4147c896fe29Sbellard } 4148c896fe29Sbellard } 4149c896fe29Sbellard 4150b4cb76e6SRichard Henderson if (def->flags & TCG_OPF_COND_BRANCH) { 4151b4cb76e6SRichard Henderson tcg_reg_alloc_cbranch(s, i_allocated_regs); 4152b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 415382790a87SRichard Henderson tcg_reg_alloc_bb_end(s, i_allocated_regs); 4154a52ad07eSAurelien Jarno } else { 4155c896fe29Sbellard if (def->flags & TCG_OPF_CALL_CLOBBER) { 4156b03cce8eSbellard /* XXX: permit generic clobber register list ? */ 4157c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) { 4158c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { 415982790a87SRichard Henderson tcg_reg_free(s, i, i_allocated_regs); 4160c896fe29Sbellard } 4161c896fe29Sbellard } 41623d5c5f87SAurelien Jarno } 41633d5c5f87SAurelien Jarno if (def->flags & TCG_OPF_SIDE_EFFECTS) { 41643d5c5f87SAurelien Jarno /* sync globals if the op has side effects and might trigger 41653d5c5f87SAurelien Jarno an exception. */ 416682790a87SRichard Henderson sync_globals(s, i_allocated_regs); 4167c896fe29Sbellard } 4168c896fe29Sbellard 4169c896fe29Sbellard /* satisfy the output constraints */ 4170c896fe29Sbellard for(k = 0; k < nb_oargs; k++) { 417166792f90SRichard Henderson i = def->args_ct[k].sort_index; 4172dd186292SRichard Henderson arg = op->args[i]; 4173c896fe29Sbellard arg_ct = &def->args_ct[i]; 417443439139SRichard Henderson ts = arg_temp(arg); 4175d63e3b6eSRichard Henderson 4176d63e3b6eSRichard Henderson /* ENV should not be modified. */ 4177e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ts)); 4178d63e3b6eSRichard Henderson 4179bc2b17e6SRichard Henderson if (arg_ct->oalias && !const_args[arg_ct->alias_index]) { 41805ff9d6a4Sbellard reg = new_args[arg_ct->alias_index]; 4181bc2b17e6SRichard Henderson } else if (arg_ct->newreg) { 41829be0d080SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->regs, 418382790a87SRichard Henderson i_allocated_regs | o_allocated_regs, 418469e3706dSRichard Henderson op->output_pref[k], ts->indirect_base); 4185c896fe29Sbellard } else { 41869be0d080SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs, 418769e3706dSRichard Henderson op->output_pref[k], ts->indirect_base); 4188c896fe29Sbellard } 418982790a87SRichard Henderson tcg_regset_set_reg(o_allocated_regs, reg); 4190639368ddSAurelien Jarno if (ts->val_type == TEMP_VAL_REG) { 4191f8b2f202SRichard Henderson s->reg_to_temp[ts->reg] = NULL; 4192639368ddSAurelien Jarno } 4193c896fe29Sbellard ts->val_type = TEMP_VAL_REG; 4194c896fe29Sbellard ts->reg = reg; 4195d63e3b6eSRichard Henderson /* 4196d63e3b6eSRichard Henderson * Temp value is modified, so the value kept in memory is 4197d63e3b6eSRichard Henderson * potentially not the same. 4198d63e3b6eSRichard Henderson */ 4199c896fe29Sbellard ts->mem_coherent = 0; 4200f8b2f202SRichard Henderson s->reg_to_temp[reg] = ts; 4201c896fe29Sbellard new_args[i] = reg; 4202c896fe29Sbellard } 4203e8996ee0Sbellard } 4204c896fe29Sbellard 4205c896fe29Sbellard /* emit instruction */ 4206d2fd745fSRichard Henderson if (def->flags & TCG_OPF_VECTOR) { 4207d2fd745fSRichard Henderson tcg_out_vec_op(s, op->opc, TCGOP_VECL(op), TCGOP_VECE(op), 4208d2fd745fSRichard Henderson new_args, const_args); 4209d2fd745fSRichard Henderson } else { 4210dd186292SRichard Henderson tcg_out_op(s, op->opc, new_args, const_args); 4211d2fd745fSRichard Henderson } 4212c896fe29Sbellard 4213c896fe29Sbellard /* move the outputs in the correct register if needed */ 4214c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 421543439139SRichard Henderson ts = arg_temp(op->args[i]); 4216d63e3b6eSRichard Henderson 4217d63e3b6eSRichard Henderson /* ENV should not be modified. */ 4218e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ts)); 4219d63e3b6eSRichard Henderson 4220ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) { 422198b4e186SRichard Henderson temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i)); 422259d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) { 4223f8bf00f1SRichard Henderson temp_dead(s, ts); 4224ec7a869dSAurelien Jarno } 4225c896fe29Sbellard } 4226c896fe29Sbellard } 4227c896fe29Sbellard 4228efe86b21SRichard Henderson static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op) 4229efe86b21SRichard Henderson { 4230efe86b21SRichard Henderson const TCGLifeData arg_life = op->life; 4231efe86b21SRichard Henderson TCGTemp *ots, *itsl, *itsh; 4232efe86b21SRichard Henderson TCGType vtype = TCGOP_VECL(op) + TCG_TYPE_V64; 4233efe86b21SRichard Henderson 4234efe86b21SRichard Henderson /* This opcode is only valid for 32-bit hosts, for 64-bit elements. */ 4235efe86b21SRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 32); 4236efe86b21SRichard Henderson tcg_debug_assert(TCGOP_VECE(op) == MO_64); 4237efe86b21SRichard Henderson 4238efe86b21SRichard Henderson ots = arg_temp(op->args[0]); 4239efe86b21SRichard Henderson itsl = arg_temp(op->args[1]); 4240efe86b21SRichard Henderson itsh = arg_temp(op->args[2]); 4241efe86b21SRichard Henderson 4242efe86b21SRichard Henderson /* ENV should not be modified. */ 4243efe86b21SRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 4244efe86b21SRichard Henderson 4245efe86b21SRichard Henderson /* Allocate the output register now. */ 4246efe86b21SRichard Henderson if (ots->val_type != TEMP_VAL_REG) { 4247efe86b21SRichard Henderson TCGRegSet allocated_regs = s->reserved_regs; 4248efe86b21SRichard Henderson TCGRegSet dup_out_regs = 4249efe86b21SRichard Henderson tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs; 4250efe86b21SRichard Henderson 4251efe86b21SRichard Henderson /* Make sure to not spill the input registers. */ 4252efe86b21SRichard Henderson if (!IS_DEAD_ARG(1) && itsl->val_type == TEMP_VAL_REG) { 4253efe86b21SRichard Henderson tcg_regset_set_reg(allocated_regs, itsl->reg); 4254efe86b21SRichard Henderson } 4255efe86b21SRichard Henderson if (!IS_DEAD_ARG(2) && itsh->val_type == TEMP_VAL_REG) { 4256efe86b21SRichard Henderson tcg_regset_set_reg(allocated_regs, itsh->reg); 4257efe86b21SRichard Henderson } 4258efe86b21SRichard Henderson 4259efe86b21SRichard Henderson ots->reg = tcg_reg_alloc(s, dup_out_regs, allocated_regs, 4260efe86b21SRichard Henderson op->output_pref[0], ots->indirect_base); 4261efe86b21SRichard Henderson ots->val_type = TEMP_VAL_REG; 4262efe86b21SRichard Henderson ots->mem_coherent = 0; 4263efe86b21SRichard Henderson s->reg_to_temp[ots->reg] = ots; 4264efe86b21SRichard Henderson } 4265efe86b21SRichard Henderson 4266efe86b21SRichard Henderson /* Promote dup2 of immediates to dupi_vec. */ 4267efe86b21SRichard Henderson if (itsl->val_type == TEMP_VAL_CONST && itsh->val_type == TEMP_VAL_CONST) { 4268efe86b21SRichard Henderson uint64_t val = deposit64(itsl->val, 32, 32, itsh->val); 4269efe86b21SRichard Henderson MemOp vece = MO_64; 4270efe86b21SRichard Henderson 4271efe86b21SRichard Henderson if (val == dup_const(MO_8, val)) { 4272efe86b21SRichard Henderson vece = MO_8; 4273efe86b21SRichard Henderson } else if (val == dup_const(MO_16, val)) { 4274efe86b21SRichard Henderson vece = MO_16; 4275efe86b21SRichard Henderson } else if (val == dup_const(MO_32, val)) { 4276efe86b21SRichard Henderson vece = MO_32; 4277efe86b21SRichard Henderson } 4278efe86b21SRichard Henderson 4279efe86b21SRichard Henderson tcg_out_dupi_vec(s, vtype, vece, ots->reg, val); 4280efe86b21SRichard Henderson goto done; 4281efe86b21SRichard Henderson } 4282efe86b21SRichard Henderson 4283efe86b21SRichard Henderson /* If the two inputs form one 64-bit value, try dupm_vec. */ 4284efe86b21SRichard Henderson if (itsl + 1 == itsh && itsl->base_type == TCG_TYPE_I64) { 4285efe86b21SRichard Henderson if (!itsl->mem_coherent) { 4286efe86b21SRichard Henderson temp_sync(s, itsl, s->reserved_regs, 0, 0); 4287efe86b21SRichard Henderson } 4288efe86b21SRichard Henderson if (!itsh->mem_coherent) { 4289efe86b21SRichard Henderson temp_sync(s, itsh, s->reserved_regs, 0, 0); 4290efe86b21SRichard Henderson } 4291efe86b21SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 4292efe86b21SRichard Henderson TCGTemp *its = itsh; 4293efe86b21SRichard Henderson #else 4294efe86b21SRichard Henderson TCGTemp *its = itsl; 4295efe86b21SRichard Henderson #endif 4296efe86b21SRichard Henderson if (tcg_out_dupm_vec(s, vtype, MO_64, ots->reg, 4297efe86b21SRichard Henderson its->mem_base->reg, its->mem_offset)) { 4298efe86b21SRichard Henderson goto done; 4299efe86b21SRichard Henderson } 4300efe86b21SRichard Henderson } 4301efe86b21SRichard Henderson 4302efe86b21SRichard Henderson /* Fall back to generic expansion. */ 4303efe86b21SRichard Henderson return false; 4304efe86b21SRichard Henderson 4305efe86b21SRichard Henderson done: 4306efe86b21SRichard Henderson if (IS_DEAD_ARG(1)) { 4307efe86b21SRichard Henderson temp_dead(s, itsl); 4308efe86b21SRichard Henderson } 4309efe86b21SRichard Henderson if (IS_DEAD_ARG(2)) { 4310efe86b21SRichard Henderson temp_dead(s, itsh); 4311efe86b21SRichard Henderson } 4312efe86b21SRichard Henderson if (NEED_SYNC_ARG(0)) { 4313efe86b21SRichard Henderson temp_sync(s, ots, s->reserved_regs, 0, IS_DEAD_ARG(0)); 4314efe86b21SRichard Henderson } else if (IS_DEAD_ARG(0)) { 4315efe86b21SRichard Henderson temp_dead(s, ots); 4316efe86b21SRichard Henderson } 4317efe86b21SRichard Henderson return true; 4318efe86b21SRichard Henderson } 4319efe86b21SRichard Henderson 4320b03cce8eSbellard #ifdef TCG_TARGET_STACK_GROWSUP 4321b03cce8eSbellard #define STACK_DIR(x) (-(x)) 4322b03cce8eSbellard #else 4323b03cce8eSbellard #define STACK_DIR(x) (x) 4324b03cce8eSbellard #endif 4325b03cce8eSbellard 4326dd186292SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op) 4327c896fe29Sbellard { 4328cd9090aaSRichard Henderson const int nb_oargs = TCGOP_CALLO(op); 4329cd9090aaSRichard Henderson const int nb_iargs = TCGOP_CALLI(op); 4330dd186292SRichard Henderson const TCGLifeData arg_life = op->life; 4331b6638662SRichard Henderson int flags, nb_regs, i; 4332b6638662SRichard Henderson TCGReg reg; 4333cf066674SRichard Henderson TCGArg arg; 4334c896fe29Sbellard TCGTemp *ts; 4335d3452f1fSRichard Henderson intptr_t stack_offset; 4336d3452f1fSRichard Henderson size_t call_stack_size; 4337cf066674SRichard Henderson tcg_insn_unit *func_addr; 4338cf066674SRichard Henderson int allocate_args; 4339c896fe29Sbellard TCGRegSet allocated_regs; 4340c896fe29Sbellard 4341dd186292SRichard Henderson func_addr = (tcg_insn_unit *)(intptr_t)op->args[nb_oargs + nb_iargs]; 4342dd186292SRichard Henderson flags = op->args[nb_oargs + nb_iargs + 1]; 4343c896fe29Sbellard 43446e17d0c5SStefan Weil nb_regs = ARRAY_SIZE(tcg_target_call_iarg_regs); 4345c45cb8bbSRichard Henderson if (nb_regs > nb_iargs) { 4346c45cb8bbSRichard Henderson nb_regs = nb_iargs; 4347cf066674SRichard Henderson } 4348c896fe29Sbellard 4349c896fe29Sbellard /* assign stack slots first */ 4350c45cb8bbSRichard Henderson call_stack_size = (nb_iargs - nb_regs) * sizeof(tcg_target_long); 4351c896fe29Sbellard call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) & 4352c896fe29Sbellard ~(TCG_TARGET_STACK_ALIGN - 1); 4353b03cce8eSbellard allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE); 4354b03cce8eSbellard if (allocate_args) { 4355345649c0SBlue Swirl /* XXX: if more than TCG_STATIC_CALL_ARGS_SIZE is needed, 4356345649c0SBlue Swirl preallocate call stack */ 4357345649c0SBlue Swirl tcg_abort(); 4358b03cce8eSbellard } 435939cf05d3Sbellard 436039cf05d3Sbellard stack_offset = TCG_TARGET_CALL_STACK_OFFSET; 4361c45cb8bbSRichard Henderson for (i = nb_regs; i < nb_iargs; i++) { 4362dd186292SRichard Henderson arg = op->args[nb_oargs + i]; 436339cf05d3Sbellard #ifdef TCG_TARGET_STACK_GROWSUP 436439cf05d3Sbellard stack_offset -= sizeof(tcg_target_long); 436539cf05d3Sbellard #endif 436639cf05d3Sbellard if (arg != TCG_CALL_DUMMY_ARG) { 436743439139SRichard Henderson ts = arg_temp(arg); 436840ae5c62SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 4369b722452aSRichard Henderson s->reserved_regs, 0); 4370e4d5434cSblueswir1 tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset); 437139cf05d3Sbellard } 437239cf05d3Sbellard #ifndef TCG_TARGET_STACK_GROWSUP 437339cf05d3Sbellard stack_offset += sizeof(tcg_target_long); 437439cf05d3Sbellard #endif 4375c896fe29Sbellard } 4376c896fe29Sbellard 4377c896fe29Sbellard /* assign input registers */ 4378d21369f5SRichard Henderson allocated_regs = s->reserved_regs; 4379c896fe29Sbellard for (i = 0; i < nb_regs; i++) { 4380dd186292SRichard Henderson arg = op->args[nb_oargs + i]; 438139cf05d3Sbellard if (arg != TCG_CALL_DUMMY_ARG) { 438243439139SRichard Henderson ts = arg_temp(arg); 4383c896fe29Sbellard reg = tcg_target_call_iarg_regs[i]; 438440ae5c62SRichard Henderson 4385c896fe29Sbellard if (ts->val_type == TEMP_VAL_REG) { 4386c896fe29Sbellard if (ts->reg != reg) { 43874250da10SRichard Henderson tcg_reg_free(s, reg, allocated_regs); 438878113e83SRichard Henderson if (!tcg_out_mov(s, ts->type, reg, ts->reg)) { 4389240c08d0SRichard Henderson /* 4390240c08d0SRichard Henderson * Cross register class move not supported. Sync the 4391240c08d0SRichard Henderson * temp back to its slot and load from there. 4392240c08d0SRichard Henderson */ 4393240c08d0SRichard Henderson temp_sync(s, ts, allocated_regs, 0, 0); 4394240c08d0SRichard Henderson tcg_out_ld(s, ts->type, reg, 4395240c08d0SRichard Henderson ts->mem_base->reg, ts->mem_offset); 439678113e83SRichard Henderson } 4397c896fe29Sbellard } 4398c896fe29Sbellard } else { 4399ccb1bb66SRichard Henderson TCGRegSet arg_set = 0; 440040ae5c62SRichard Henderson 44014250da10SRichard Henderson tcg_reg_free(s, reg, allocated_regs); 440240ae5c62SRichard Henderson tcg_regset_set_reg(arg_set, reg); 4403b722452aSRichard Henderson temp_load(s, ts, arg_set, allocated_regs, 0); 4404c896fe29Sbellard } 440540ae5c62SRichard Henderson 4406c896fe29Sbellard tcg_regset_set_reg(allocated_regs, reg); 4407c896fe29Sbellard } 440839cf05d3Sbellard } 4409c896fe29Sbellard 4410c896fe29Sbellard /* mark dead temporaries and free the associated registers */ 4411866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 4412866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) { 441343439139SRichard Henderson temp_dead(s, arg_temp(op->args[i])); 4414c896fe29Sbellard } 4415c896fe29Sbellard } 4416c896fe29Sbellard 4417c896fe29Sbellard /* clobber call registers */ 4418c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) { 4419c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { 4420b3915dbbSRichard Henderson tcg_reg_free(s, i, allocated_regs); 4421c896fe29Sbellard } 4422c896fe29Sbellard } 4423c896fe29Sbellard 442478505279SAurelien Jarno /* Save globals if they might be written by the helper, sync them if 442578505279SAurelien Jarno they might be read. */ 442678505279SAurelien Jarno if (flags & TCG_CALL_NO_READ_GLOBALS) { 442778505279SAurelien Jarno /* Nothing to do */ 442878505279SAurelien Jarno } else if (flags & TCG_CALL_NO_WRITE_GLOBALS) { 442978505279SAurelien Jarno sync_globals(s, allocated_regs); 443078505279SAurelien Jarno } else { 4431e8996ee0Sbellard save_globals(s, allocated_regs); 4432b9c18f56Saurel32 } 4433c896fe29Sbellard 4434cf066674SRichard Henderson tcg_out_call(s, func_addr); 4435c896fe29Sbellard 4436c896fe29Sbellard /* assign output registers and emit moves if needed */ 4437c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 4438dd186292SRichard Henderson arg = op->args[i]; 443943439139SRichard Henderson ts = arg_temp(arg); 4440d63e3b6eSRichard Henderson 4441d63e3b6eSRichard Henderson /* ENV should not be modified. */ 4442e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ts)); 4443d63e3b6eSRichard Henderson 4444c896fe29Sbellard reg = tcg_target_call_oarg_regs[i]; 4445eabb7b91SAurelien Jarno tcg_debug_assert(s->reg_to_temp[reg] == NULL); 4446639368ddSAurelien Jarno if (ts->val_type == TEMP_VAL_REG) { 4447f8b2f202SRichard Henderson s->reg_to_temp[ts->reg] = NULL; 4448639368ddSAurelien Jarno } 4449c896fe29Sbellard ts->val_type = TEMP_VAL_REG; 4450c896fe29Sbellard ts->reg = reg; 4451c896fe29Sbellard ts->mem_coherent = 0; 4452f8b2f202SRichard Henderson s->reg_to_temp[reg] = ts; 4453ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) { 445498b4e186SRichard Henderson temp_sync(s, ts, allocated_regs, 0, IS_DEAD_ARG(i)); 445559d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) { 4456f8bf00f1SRichard Henderson temp_dead(s, ts); 4457c896fe29Sbellard } 4458c896fe29Sbellard } 44598c11ad25SAurelien Jarno } 4460c896fe29Sbellard 4461c896fe29Sbellard #ifdef CONFIG_PROFILER 4462c896fe29Sbellard 4463c3fac113SEmilio G. Cota /* avoid copy/paste errors */ 4464c3fac113SEmilio G. Cota #define PROF_ADD(to, from, field) \ 4465c3fac113SEmilio G. Cota do { \ 4466d73415a3SStefan Hajnoczi (to)->field += qatomic_read(&((from)->field)); \ 4467c3fac113SEmilio G. Cota } while (0) 4468c896fe29Sbellard 4469c3fac113SEmilio G. Cota #define PROF_MAX(to, from, field) \ 4470c3fac113SEmilio G. Cota do { \ 4471d73415a3SStefan Hajnoczi typeof((from)->field) val__ = qatomic_read(&((from)->field)); \ 4472c3fac113SEmilio G. Cota if (val__ > (to)->field) { \ 4473c3fac113SEmilio G. Cota (to)->field = val__; \ 4474c3fac113SEmilio G. Cota } \ 4475c3fac113SEmilio G. Cota } while (0) 4476c3fac113SEmilio G. Cota 4477c3fac113SEmilio G. Cota /* Pass in a zero'ed @prof */ 4478c3fac113SEmilio G. Cota static inline 4479c3fac113SEmilio G. Cota void tcg_profile_snapshot(TCGProfile *prof, bool counters, bool table) 4480c896fe29Sbellard { 4481d73415a3SStefan Hajnoczi unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs); 4482c3fac113SEmilio G. Cota unsigned int i; 4483c3fac113SEmilio G. Cota 44843468b59eSEmilio G. Cota for (i = 0; i < n_ctxs; i++) { 4485d73415a3SStefan Hajnoczi TCGContext *s = qatomic_read(&tcg_ctxs[i]); 44863468b59eSEmilio G. Cota const TCGProfile *orig = &s->prof; 4487c3fac113SEmilio G. Cota 4488c3fac113SEmilio G. Cota if (counters) { 448972fd2efbSEmilio G. Cota PROF_ADD(prof, orig, cpu_exec_time); 4490c3fac113SEmilio G. Cota PROF_ADD(prof, orig, tb_count1); 4491c3fac113SEmilio G. Cota PROF_ADD(prof, orig, tb_count); 4492c3fac113SEmilio G. Cota PROF_ADD(prof, orig, op_count); 4493c3fac113SEmilio G. Cota PROF_MAX(prof, orig, op_count_max); 4494c3fac113SEmilio G. Cota PROF_ADD(prof, orig, temp_count); 4495c3fac113SEmilio G. Cota PROF_MAX(prof, orig, temp_count_max); 4496c3fac113SEmilio G. Cota PROF_ADD(prof, orig, del_op_count); 4497c3fac113SEmilio G. Cota PROF_ADD(prof, orig, code_in_len); 4498c3fac113SEmilio G. Cota PROF_ADD(prof, orig, code_out_len); 4499c3fac113SEmilio G. Cota PROF_ADD(prof, orig, search_out_len); 4500c3fac113SEmilio G. Cota PROF_ADD(prof, orig, interm_time); 4501c3fac113SEmilio G. Cota PROF_ADD(prof, orig, code_time); 4502c3fac113SEmilio G. Cota PROF_ADD(prof, orig, la_time); 4503c3fac113SEmilio G. Cota PROF_ADD(prof, orig, opt_time); 4504c3fac113SEmilio G. Cota PROF_ADD(prof, orig, restore_count); 4505c3fac113SEmilio G. Cota PROF_ADD(prof, orig, restore_time); 4506c3fac113SEmilio G. Cota } 4507c3fac113SEmilio G. Cota if (table) { 4508c896fe29Sbellard int i; 4509d70724ceSzhanghailiang 451015fc7daaSRichard Henderson for (i = 0; i < NB_OPS; i++) { 4511c3fac113SEmilio G. Cota PROF_ADD(prof, orig, table_op_count[i]); 4512c3fac113SEmilio G. Cota } 4513c3fac113SEmilio G. Cota } 4514c3fac113SEmilio G. Cota } 4515c3fac113SEmilio G. Cota } 4516c3fac113SEmilio G. Cota 4517c3fac113SEmilio G. Cota #undef PROF_ADD 4518c3fac113SEmilio G. Cota #undef PROF_MAX 4519c3fac113SEmilio G. Cota 4520c3fac113SEmilio G. Cota static void tcg_profile_snapshot_counters(TCGProfile *prof) 4521c3fac113SEmilio G. Cota { 4522c3fac113SEmilio G. Cota tcg_profile_snapshot(prof, true, false); 4523c3fac113SEmilio G. Cota } 4524c3fac113SEmilio G. Cota 4525c3fac113SEmilio G. Cota static void tcg_profile_snapshot_table(TCGProfile *prof) 4526c3fac113SEmilio G. Cota { 4527c3fac113SEmilio G. Cota tcg_profile_snapshot(prof, false, true); 4528c3fac113SEmilio G. Cota } 4529c3fac113SEmilio G. Cota 4530d4c51a0aSMarkus Armbruster void tcg_dump_op_count(void) 4531c3fac113SEmilio G. Cota { 4532c3fac113SEmilio G. Cota TCGProfile prof = {}; 4533c3fac113SEmilio G. Cota int i; 4534c3fac113SEmilio G. Cota 4535c3fac113SEmilio G. Cota tcg_profile_snapshot_table(&prof); 4536c3fac113SEmilio G. Cota for (i = 0; i < NB_OPS; i++) { 4537d4c51a0aSMarkus Armbruster qemu_printf("%s %" PRId64 "\n", tcg_op_defs[i].name, 4538c3fac113SEmilio G. Cota prof.table_op_count[i]); 4539c896fe29Sbellard } 4540c896fe29Sbellard } 454172fd2efbSEmilio G. Cota 454272fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void) 454372fd2efbSEmilio G. Cota { 4544d73415a3SStefan Hajnoczi unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs); 454572fd2efbSEmilio G. Cota unsigned int i; 454672fd2efbSEmilio G. Cota int64_t ret = 0; 454772fd2efbSEmilio G. Cota 454872fd2efbSEmilio G. Cota for (i = 0; i < n_ctxs; i++) { 4549d73415a3SStefan Hajnoczi const TCGContext *s = qatomic_read(&tcg_ctxs[i]); 455072fd2efbSEmilio G. Cota const TCGProfile *prof = &s->prof; 455172fd2efbSEmilio G. Cota 4552d73415a3SStefan Hajnoczi ret += qatomic_read(&prof->cpu_exec_time); 455372fd2efbSEmilio G. Cota } 455472fd2efbSEmilio G. Cota return ret; 455572fd2efbSEmilio G. Cota } 4556246ae24dSMax Filippov #else 4557d4c51a0aSMarkus Armbruster void tcg_dump_op_count(void) 4558246ae24dSMax Filippov { 4559d4c51a0aSMarkus Armbruster qemu_printf("[TCG profiler not compiled]\n"); 4560246ae24dSMax Filippov } 456172fd2efbSEmilio G. Cota 456272fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void) 456372fd2efbSEmilio G. Cota { 456472fd2efbSEmilio G. Cota error_report("%s: TCG profiler not compiled", __func__); 456572fd2efbSEmilio G. Cota exit(EXIT_FAILURE); 456672fd2efbSEmilio G. Cota } 4567c896fe29Sbellard #endif 4568c896fe29Sbellard 4569c896fe29Sbellard 45705bd2ec3dSAlex Bennée int tcg_gen_code(TCGContext *s, TranslationBlock *tb) 4571c896fe29Sbellard { 4572c3fac113SEmilio G. Cota #ifdef CONFIG_PROFILER 4573c3fac113SEmilio G. Cota TCGProfile *prof = &s->prof; 4574c3fac113SEmilio G. Cota #endif 457515fa08f8SRichard Henderson int i, num_insns; 457615fa08f8SRichard Henderson TCGOp *op; 4577c896fe29Sbellard 457804fe6400SRichard Henderson #ifdef CONFIG_PROFILER 457904fe6400SRichard Henderson { 4580c1f543b7SEmilio G. Cota int n = 0; 458104fe6400SRichard Henderson 458215fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 458315fa08f8SRichard Henderson n++; 458415fa08f8SRichard Henderson } 4585d73415a3SStefan Hajnoczi qatomic_set(&prof->op_count, prof->op_count + n); 4586c3fac113SEmilio G. Cota if (n > prof->op_count_max) { 4587d73415a3SStefan Hajnoczi qatomic_set(&prof->op_count_max, n); 458804fe6400SRichard Henderson } 458904fe6400SRichard Henderson 459004fe6400SRichard Henderson n = s->nb_temps; 4591d73415a3SStefan Hajnoczi qatomic_set(&prof->temp_count, prof->temp_count + n); 4592c3fac113SEmilio G. Cota if (n > prof->temp_count_max) { 4593d73415a3SStefan Hajnoczi qatomic_set(&prof->temp_count_max, n); 459404fe6400SRichard Henderson } 459504fe6400SRichard Henderson } 459604fe6400SRichard Henderson #endif 459704fe6400SRichard Henderson 4598c896fe29Sbellard #ifdef DEBUG_DISAS 4599d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP) 4600d977e1c2SAlex Bennée && qemu_log_in_addr_range(tb->pc))) { 4601fc59d2d8SRobert Foley FILE *logfile = qemu_log_lock(); 460293fcfe39Saliguori qemu_log("OP:\n"); 46031894f69aSRichard Henderson tcg_dump_ops(s, false); 460493fcfe39Saliguori qemu_log("\n"); 4605fc59d2d8SRobert Foley qemu_log_unlock(logfile); 4606c896fe29Sbellard } 4607c896fe29Sbellard #endif 4608c896fe29Sbellard 4609bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG 4610bef16ab4SRichard Henderson /* Ensure all labels referenced have been emitted. */ 4611bef16ab4SRichard Henderson { 4612bef16ab4SRichard Henderson TCGLabel *l; 4613bef16ab4SRichard Henderson bool error = false; 4614bef16ab4SRichard Henderson 4615bef16ab4SRichard Henderson QSIMPLEQ_FOREACH(l, &s->labels, next) { 4616bef16ab4SRichard Henderson if (unlikely(!l->present) && l->refs) { 4617bef16ab4SRichard Henderson qemu_log_mask(CPU_LOG_TB_OP, 4618bef16ab4SRichard Henderson "$L%d referenced but not present.\n", l->id); 4619bef16ab4SRichard Henderson error = true; 4620bef16ab4SRichard Henderson } 4621bef16ab4SRichard Henderson } 4622bef16ab4SRichard Henderson assert(!error); 4623bef16ab4SRichard Henderson } 4624bef16ab4SRichard Henderson #endif 4625bef16ab4SRichard Henderson 4626c5cc28ffSAurelien Jarno #ifdef CONFIG_PROFILER 4627d73415a3SStefan Hajnoczi qatomic_set(&prof->opt_time, prof->opt_time - profile_getclock()); 4628c5cc28ffSAurelien Jarno #endif 4629c5cc28ffSAurelien Jarno 46308f2e8c07SKirill Batuzov #ifdef USE_TCG_OPTIMIZATIONS 4631c45cb8bbSRichard Henderson tcg_optimize(s); 46328f2e8c07SKirill Batuzov #endif 46338f2e8c07SKirill Batuzov 4634a23a9ec6Sbellard #ifdef CONFIG_PROFILER 4635d73415a3SStefan Hajnoczi qatomic_set(&prof->opt_time, prof->opt_time + profile_getclock()); 4636d73415a3SStefan Hajnoczi qatomic_set(&prof->la_time, prof->la_time - profile_getclock()); 4637a23a9ec6Sbellard #endif 4638c5cc28ffSAurelien Jarno 4639b4fc67c7SRichard Henderson reachable_code_pass(s); 4640b83eabeaSRichard Henderson liveness_pass_1(s); 46415a18407fSRichard Henderson 46425a18407fSRichard Henderson if (s->nb_indirects > 0) { 46435a18407fSRichard Henderson #ifdef DEBUG_DISAS 46445a18407fSRichard Henderson if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND) 46455a18407fSRichard Henderson && qemu_log_in_addr_range(tb->pc))) { 4646fc59d2d8SRobert Foley FILE *logfile = qemu_log_lock(); 46475a18407fSRichard Henderson qemu_log("OP before indirect lowering:\n"); 46481894f69aSRichard Henderson tcg_dump_ops(s, false); 46495a18407fSRichard Henderson qemu_log("\n"); 4650fc59d2d8SRobert Foley qemu_log_unlock(logfile); 46515a18407fSRichard Henderson } 46525a18407fSRichard Henderson #endif 46535a18407fSRichard Henderson /* Replace indirect temps with direct temps. */ 4654b83eabeaSRichard Henderson if (liveness_pass_2(s)) { 46555a18407fSRichard Henderson /* If changes were made, re-run liveness. */ 4656b83eabeaSRichard Henderson liveness_pass_1(s); 46575a18407fSRichard Henderson } 46585a18407fSRichard Henderson } 4659c5cc28ffSAurelien Jarno 4660a23a9ec6Sbellard #ifdef CONFIG_PROFILER 4661d73415a3SStefan Hajnoczi qatomic_set(&prof->la_time, prof->la_time + profile_getclock()); 4662a23a9ec6Sbellard #endif 4663c896fe29Sbellard 4664c896fe29Sbellard #ifdef DEBUG_DISAS 4665d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT) 4666d977e1c2SAlex Bennée && qemu_log_in_addr_range(tb->pc))) { 4667fc59d2d8SRobert Foley FILE *logfile = qemu_log_lock(); 4668c5cc28ffSAurelien Jarno qemu_log("OP after optimization and liveness analysis:\n"); 46691894f69aSRichard Henderson tcg_dump_ops(s, true); 467093fcfe39Saliguori qemu_log("\n"); 4671fc59d2d8SRobert Foley qemu_log_unlock(logfile); 4672c896fe29Sbellard } 4673c896fe29Sbellard #endif 4674c896fe29Sbellard 4675c896fe29Sbellard tcg_reg_alloc_start(s); 4676c896fe29Sbellard 4677db0c51a3SRichard Henderson /* 4678db0c51a3SRichard Henderson * Reset the buffer pointers when restarting after overflow. 4679db0c51a3SRichard Henderson * TODO: Move this into translate-all.c with the rest of the 4680db0c51a3SRichard Henderson * buffer management. Having only this done here is confusing. 4681db0c51a3SRichard Henderson */ 4682db0c51a3SRichard Henderson s->code_buf = tcg_splitwx_to_rw(tb->tc.ptr); 4683db0c51a3SRichard Henderson s->code_ptr = s->code_buf; 4684c896fe29Sbellard 4685659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS 46866001f772SLaurent Vivier QSIMPLEQ_INIT(&s->ldst_labels); 4687659ef5cbSRichard Henderson #endif 468857a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 468957a26946SRichard Henderson s->pool_labels = NULL; 469057a26946SRichard Henderson #endif 46919ecefc84SRichard Henderson 4692fca8a500SRichard Henderson num_insns = -1; 469315fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 4694c45cb8bbSRichard Henderson TCGOpcode opc = op->opc; 4695b3db8758Sblueswir1 4696c896fe29Sbellard #ifdef CONFIG_PROFILER 4697d73415a3SStefan Hajnoczi qatomic_set(&prof->table_op_count[opc], prof->table_op_count[opc] + 1); 4698c896fe29Sbellard #endif 4699c45cb8bbSRichard Henderson 4700c896fe29Sbellard switch (opc) { 4701c896fe29Sbellard case INDEX_op_mov_i32: 4702c896fe29Sbellard case INDEX_op_mov_i64: 4703d2fd745fSRichard Henderson case INDEX_op_mov_vec: 4704dd186292SRichard Henderson tcg_reg_alloc_mov(s, op); 4705c896fe29Sbellard break; 4706bab1671fSRichard Henderson case INDEX_op_dup_vec: 4707bab1671fSRichard Henderson tcg_reg_alloc_dup(s, op); 4708bab1671fSRichard Henderson break; 4709765b842aSRichard Henderson case INDEX_op_insn_start: 4710fca8a500SRichard Henderson if (num_insns >= 0) { 47119f754620SRichard Henderson size_t off = tcg_current_code_size(s); 47129f754620SRichard Henderson s->gen_insn_end_off[num_insns] = off; 47139f754620SRichard Henderson /* Assert that we do not overflow our stored offset. */ 47149f754620SRichard Henderson assert(s->gen_insn_end_off[num_insns] == off); 4715fca8a500SRichard Henderson } 4716fca8a500SRichard Henderson num_insns++; 4717bad729e2SRichard Henderson for (i = 0; i < TARGET_INSN_START_WORDS; ++i) { 4718bad729e2SRichard Henderson target_ulong a; 4719bad729e2SRichard Henderson #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS 4720efee3746SRichard Henderson a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]); 4721bad729e2SRichard Henderson #else 4722efee3746SRichard Henderson a = op->args[i]; 4723bad729e2SRichard Henderson #endif 4724fca8a500SRichard Henderson s->gen_insn_data[num_insns][i] = a; 4725bad729e2SRichard Henderson } 4726c896fe29Sbellard break; 47275ff9d6a4Sbellard case INDEX_op_discard: 472843439139SRichard Henderson temp_dead(s, arg_temp(op->args[0])); 47295ff9d6a4Sbellard break; 4730c896fe29Sbellard case INDEX_op_set_label: 4731e8996ee0Sbellard tcg_reg_alloc_bb_end(s, s->reserved_regs); 473292ab8e7dSRichard Henderson tcg_out_label(s, arg_label(op->args[0])); 4733c896fe29Sbellard break; 4734c896fe29Sbellard case INDEX_op_call: 4735dd186292SRichard Henderson tcg_reg_alloc_call(s, op); 4736c45cb8bbSRichard Henderson break; 4737efe86b21SRichard Henderson case INDEX_op_dup2_vec: 4738efe86b21SRichard Henderson if (tcg_reg_alloc_dup2(s, op)) { 4739efe86b21SRichard Henderson break; 4740efe86b21SRichard Henderson } 4741efe86b21SRichard Henderson /* fall through */ 4742c896fe29Sbellard default: 474325c4d9ccSRichard Henderson /* Sanity check that we've not introduced any unhandled opcodes. */ 4744be0f34b5SRichard Henderson tcg_debug_assert(tcg_op_supported(opc)); 4745c896fe29Sbellard /* Note: in order to speed up the code, it would be much 4746c896fe29Sbellard faster to have specialized register allocator functions for 4747c896fe29Sbellard some common argument patterns */ 4748dd186292SRichard Henderson tcg_reg_alloc_op(s, op); 4749c896fe29Sbellard break; 4750c896fe29Sbellard } 47518d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG 4752c896fe29Sbellard check_regs(s); 4753c896fe29Sbellard #endif 4754b125f9dcSRichard Henderson /* Test for (pending) buffer overflow. The assumption is that any 4755b125f9dcSRichard Henderson one operation beginning below the high water mark cannot overrun 4756b125f9dcSRichard Henderson the buffer completely. Thus we can test for overflow after 4757b125f9dcSRichard Henderson generating code without having to check during generation. */ 4758644da9b3SJohn Clarke if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) { 4759b125f9dcSRichard Henderson return -1; 4760b125f9dcSRichard Henderson } 47616e6c4efeSRichard Henderson /* Test for TB overflow, as seen by gen_insn_end_off. */ 47626e6c4efeSRichard Henderson if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) { 47636e6c4efeSRichard Henderson return -2; 47646e6c4efeSRichard Henderson } 4765c896fe29Sbellard } 4766fca8a500SRichard Henderson tcg_debug_assert(num_insns >= 0); 4767fca8a500SRichard Henderson s->gen_insn_end_off[num_insns] = tcg_current_code_size(s); 4768c45cb8bbSRichard Henderson 4769b76f0d8cSYeongkyoon Lee /* Generate TB finalization at the end of block */ 4770659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS 4771aeee05f5SRichard Henderson i = tcg_out_ldst_finalize(s); 4772aeee05f5SRichard Henderson if (i < 0) { 4773aeee05f5SRichard Henderson return i; 477423dceda6SRichard Henderson } 4775659ef5cbSRichard Henderson #endif 477657a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 47771768987bSRichard Henderson i = tcg_out_pool_finalize(s); 47781768987bSRichard Henderson if (i < 0) { 47791768987bSRichard Henderson return i; 478057a26946SRichard Henderson } 478157a26946SRichard Henderson #endif 47827ecd02a0SRichard Henderson if (!tcg_resolve_relocs(s)) { 47837ecd02a0SRichard Henderson return -2; 47847ecd02a0SRichard Henderson } 4785c896fe29Sbellard 4786df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 4787c896fe29Sbellard /* flush instruction cache */ 4788db0c51a3SRichard Henderson flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf), 4789db0c51a3SRichard Henderson (uintptr_t)s->code_buf, 47901da8de39SRichard Henderson tcg_ptr_byte_diff(s->code_ptr, s->code_buf)); 4791df5d2b16SRichard Henderson #endif 47922aeabc08SStefan Weil 47931813e175SRichard Henderson return tcg_current_code_size(s); 4794c896fe29Sbellard } 4795c896fe29Sbellard 4796a23a9ec6Sbellard #ifdef CONFIG_PROFILER 47973de2faa9SMarkus Armbruster void tcg_dump_info(void) 4798a23a9ec6Sbellard { 4799c3fac113SEmilio G. Cota TCGProfile prof = {}; 4800c3fac113SEmilio G. Cota const TCGProfile *s; 4801c3fac113SEmilio G. Cota int64_t tb_count; 4802c3fac113SEmilio G. Cota int64_t tb_div_count; 4803c3fac113SEmilio G. Cota int64_t tot; 4804c3fac113SEmilio G. Cota 4805c3fac113SEmilio G. Cota tcg_profile_snapshot_counters(&prof); 4806c3fac113SEmilio G. Cota s = &prof; 4807c3fac113SEmilio G. Cota tb_count = s->tb_count; 4808c3fac113SEmilio G. Cota tb_div_count = tb_count ? tb_count : 1; 4809c3fac113SEmilio G. Cota tot = s->interm_time + s->code_time; 4810a23a9ec6Sbellard 48113de2faa9SMarkus Armbruster qemu_printf("JIT cycles %" PRId64 " (%0.3f s at 2.4 GHz)\n", 4812a23a9ec6Sbellard tot, tot / 2.4e9); 48133de2faa9SMarkus Armbruster qemu_printf("translated TBs %" PRId64 " (aborted=%" PRId64 48143de2faa9SMarkus Armbruster " %0.1f%%)\n", 4815fca8a500SRichard Henderson tb_count, s->tb_count1 - tb_count, 4816fca8a500SRichard Henderson (double)(s->tb_count1 - s->tb_count) 4817fca8a500SRichard Henderson / (s->tb_count1 ? s->tb_count1 : 1) * 100.0); 48183de2faa9SMarkus Armbruster qemu_printf("avg ops/TB %0.1f max=%d\n", 4819fca8a500SRichard Henderson (double)s->op_count / tb_div_count, s->op_count_max); 48203de2faa9SMarkus Armbruster qemu_printf("deleted ops/TB %0.2f\n", 4821fca8a500SRichard Henderson (double)s->del_op_count / tb_div_count); 48223de2faa9SMarkus Armbruster qemu_printf("avg temps/TB %0.2f max=%d\n", 4823fca8a500SRichard Henderson (double)s->temp_count / tb_div_count, s->temp_count_max); 48243de2faa9SMarkus Armbruster qemu_printf("avg host code/TB %0.1f\n", 4825fca8a500SRichard Henderson (double)s->code_out_len / tb_div_count); 48263de2faa9SMarkus Armbruster qemu_printf("avg search data/TB %0.1f\n", 4827fca8a500SRichard Henderson (double)s->search_out_len / tb_div_count); 4828a23a9ec6Sbellard 48293de2faa9SMarkus Armbruster qemu_printf("cycles/op %0.1f\n", 4830a23a9ec6Sbellard s->op_count ? (double)tot / s->op_count : 0); 48313de2faa9SMarkus Armbruster qemu_printf("cycles/in byte %0.1f\n", 4832a23a9ec6Sbellard s->code_in_len ? (double)tot / s->code_in_len : 0); 48333de2faa9SMarkus Armbruster qemu_printf("cycles/out byte %0.1f\n", 4834a23a9ec6Sbellard s->code_out_len ? (double)tot / s->code_out_len : 0); 48353de2faa9SMarkus Armbruster qemu_printf("cycles/search byte %0.1f\n", 4836fca8a500SRichard Henderson s->search_out_len ? (double)tot / s->search_out_len : 0); 4837fca8a500SRichard Henderson if (tot == 0) { 4838a23a9ec6Sbellard tot = 1; 4839fca8a500SRichard Henderson } 48403de2faa9SMarkus Armbruster qemu_printf(" gen_interm time %0.1f%%\n", 4841a23a9ec6Sbellard (double)s->interm_time / tot * 100.0); 48423de2faa9SMarkus Armbruster qemu_printf(" gen_code time %0.1f%%\n", 4843a23a9ec6Sbellard (double)s->code_time / tot * 100.0); 48443de2faa9SMarkus Armbruster qemu_printf("optim./code time %0.1f%%\n", 4845c5cc28ffSAurelien Jarno (double)s->opt_time / (s->code_time ? s->code_time : 1) 4846c5cc28ffSAurelien Jarno * 100.0); 48473de2faa9SMarkus Armbruster qemu_printf("liveness/code time %0.1f%%\n", 4848a23a9ec6Sbellard (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0); 48493de2faa9SMarkus Armbruster qemu_printf("cpu_restore count %" PRId64 "\n", 4850a23a9ec6Sbellard s->restore_count); 48513de2faa9SMarkus Armbruster qemu_printf(" avg cycles %0.1f\n", 4852a23a9ec6Sbellard s->restore_count ? (double)s->restore_time / s->restore_count : 0); 4853a23a9ec6Sbellard } 4854a23a9ec6Sbellard #else 48553de2faa9SMarkus Armbruster void tcg_dump_info(void) 4856a23a9ec6Sbellard { 48573de2faa9SMarkus Armbruster qemu_printf("[TCG profiler not compiled]\n"); 4858a23a9ec6Sbellard } 4859a23a9ec6Sbellard #endif 4860813da627SRichard Henderson 4861813da627SRichard Henderson #ifdef ELF_HOST_MACHINE 48625872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things: 48635872bbf2SRichard Henderson 48645872bbf2SRichard Henderson (1) Define ELF_HOST_MACHINE to indicate both what value to 48655872bbf2SRichard Henderson put into the ELF image and to indicate support for the feature. 48665872bbf2SRichard Henderson 48675872bbf2SRichard Henderson (2) Define tcg_register_jit. This should create a buffer containing 48685872bbf2SRichard Henderson the contents of a .debug_frame section that describes the post- 48695872bbf2SRichard Henderson prologue unwind info for the tcg machine. 48705872bbf2SRichard Henderson 48715872bbf2SRichard Henderson (3) Call tcg_register_jit_int, with the constructed .debug_frame. 48725872bbf2SRichard Henderson */ 4873813da627SRichard Henderson 4874813da627SRichard Henderson /* Begin GDB interface. THE FOLLOWING MUST MATCH GDB DOCS. */ 4875813da627SRichard Henderson typedef enum { 4876813da627SRichard Henderson JIT_NOACTION = 0, 4877813da627SRichard Henderson JIT_REGISTER_FN, 4878813da627SRichard Henderson JIT_UNREGISTER_FN 4879813da627SRichard Henderson } jit_actions_t; 4880813da627SRichard Henderson 4881813da627SRichard Henderson struct jit_code_entry { 4882813da627SRichard Henderson struct jit_code_entry *next_entry; 4883813da627SRichard Henderson struct jit_code_entry *prev_entry; 4884813da627SRichard Henderson const void *symfile_addr; 4885813da627SRichard Henderson uint64_t symfile_size; 4886813da627SRichard Henderson }; 4887813da627SRichard Henderson 4888813da627SRichard Henderson struct jit_descriptor { 4889813da627SRichard Henderson uint32_t version; 4890813da627SRichard Henderson uint32_t action_flag; 4891813da627SRichard Henderson struct jit_code_entry *relevant_entry; 4892813da627SRichard Henderson struct jit_code_entry *first_entry; 4893813da627SRichard Henderson }; 4894813da627SRichard Henderson 4895813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline)); 4896813da627SRichard Henderson void __jit_debug_register_code(void) 4897813da627SRichard Henderson { 4898813da627SRichard Henderson asm(""); 4899813da627SRichard Henderson } 4900813da627SRichard Henderson 4901813da627SRichard Henderson /* Must statically initialize the version, because GDB may check 4902813da627SRichard Henderson the version before we can set it. */ 4903813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 }; 4904813da627SRichard Henderson 4905813da627SRichard Henderson /* End GDB interface. */ 4906813da627SRichard Henderson 4907813da627SRichard Henderson static int find_string(const char *strtab, const char *str) 4908813da627SRichard Henderson { 4909813da627SRichard Henderson const char *p = strtab + 1; 4910813da627SRichard Henderson 4911813da627SRichard Henderson while (1) { 4912813da627SRichard Henderson if (strcmp(p, str) == 0) { 4913813da627SRichard Henderson return p - strtab; 4914813da627SRichard Henderson } 4915813da627SRichard Henderson p += strlen(p) + 1; 4916813da627SRichard Henderson } 4917813da627SRichard Henderson } 4918813da627SRichard Henderson 4919755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf_ptr, size_t buf_size, 49202c90784aSRichard Henderson const void *debug_frame, 49212c90784aSRichard Henderson size_t debug_frame_size) 4922813da627SRichard Henderson { 49235872bbf2SRichard Henderson struct __attribute__((packed)) DebugInfo { 49245872bbf2SRichard Henderson uint32_t len; 49255872bbf2SRichard Henderson uint16_t version; 49265872bbf2SRichard Henderson uint32_t abbrev; 49275872bbf2SRichard Henderson uint8_t ptr_size; 49285872bbf2SRichard Henderson uint8_t cu_die; 49295872bbf2SRichard Henderson uint16_t cu_lang; 49305872bbf2SRichard Henderson uintptr_t cu_low_pc; 49315872bbf2SRichard Henderson uintptr_t cu_high_pc; 49325872bbf2SRichard Henderson uint8_t fn_die; 49335872bbf2SRichard Henderson char fn_name[16]; 49345872bbf2SRichard Henderson uintptr_t fn_low_pc; 49355872bbf2SRichard Henderson uintptr_t fn_high_pc; 49365872bbf2SRichard Henderson uint8_t cu_eoc; 49375872bbf2SRichard Henderson }; 4938813da627SRichard Henderson 4939813da627SRichard Henderson struct ElfImage { 4940813da627SRichard Henderson ElfW(Ehdr) ehdr; 4941813da627SRichard Henderson ElfW(Phdr) phdr; 49425872bbf2SRichard Henderson ElfW(Shdr) shdr[7]; 49435872bbf2SRichard Henderson ElfW(Sym) sym[2]; 49445872bbf2SRichard Henderson struct DebugInfo di; 49455872bbf2SRichard Henderson uint8_t da[24]; 49465872bbf2SRichard Henderson char str[80]; 49475872bbf2SRichard Henderson }; 49485872bbf2SRichard Henderson 49495872bbf2SRichard Henderson struct ElfImage *img; 49505872bbf2SRichard Henderson 49515872bbf2SRichard Henderson static const struct ElfImage img_template = { 49525872bbf2SRichard Henderson .ehdr = { 49535872bbf2SRichard Henderson .e_ident[EI_MAG0] = ELFMAG0, 49545872bbf2SRichard Henderson .e_ident[EI_MAG1] = ELFMAG1, 49555872bbf2SRichard Henderson .e_ident[EI_MAG2] = ELFMAG2, 49565872bbf2SRichard Henderson .e_ident[EI_MAG3] = ELFMAG3, 49575872bbf2SRichard Henderson .e_ident[EI_CLASS] = ELF_CLASS, 49585872bbf2SRichard Henderson .e_ident[EI_DATA] = ELF_DATA, 49595872bbf2SRichard Henderson .e_ident[EI_VERSION] = EV_CURRENT, 49605872bbf2SRichard Henderson .e_type = ET_EXEC, 49615872bbf2SRichard Henderson .e_machine = ELF_HOST_MACHINE, 49625872bbf2SRichard Henderson .e_version = EV_CURRENT, 49635872bbf2SRichard Henderson .e_phoff = offsetof(struct ElfImage, phdr), 49645872bbf2SRichard Henderson .e_shoff = offsetof(struct ElfImage, shdr), 49655872bbf2SRichard Henderson .e_ehsize = sizeof(ElfW(Shdr)), 49665872bbf2SRichard Henderson .e_phentsize = sizeof(ElfW(Phdr)), 49675872bbf2SRichard Henderson .e_phnum = 1, 49685872bbf2SRichard Henderson .e_shentsize = sizeof(ElfW(Shdr)), 49695872bbf2SRichard Henderson .e_shnum = ARRAY_SIZE(img->shdr), 49705872bbf2SRichard Henderson .e_shstrndx = ARRAY_SIZE(img->shdr) - 1, 4971abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS 4972abbb3eaeSRichard Henderson .e_flags = ELF_HOST_FLAGS, 4973abbb3eaeSRichard Henderson #endif 4974abbb3eaeSRichard Henderson #ifdef ELF_OSABI 4975abbb3eaeSRichard Henderson .e_ident[EI_OSABI] = ELF_OSABI, 4976abbb3eaeSRichard Henderson #endif 49775872bbf2SRichard Henderson }, 49785872bbf2SRichard Henderson .phdr = { 49795872bbf2SRichard Henderson .p_type = PT_LOAD, 49805872bbf2SRichard Henderson .p_flags = PF_X, 49815872bbf2SRichard Henderson }, 49825872bbf2SRichard Henderson .shdr = { 49835872bbf2SRichard Henderson [0] = { .sh_type = SHT_NULL }, 49845872bbf2SRichard Henderson /* Trick: The contents of code_gen_buffer are not present in 49855872bbf2SRichard Henderson this fake ELF file; that got allocated elsewhere. Therefore 49865872bbf2SRichard Henderson we mark .text as SHT_NOBITS (similar to .bss) so that readers 49875872bbf2SRichard Henderson will not look for contents. We can record any address. */ 49885872bbf2SRichard Henderson [1] = { /* .text */ 49895872bbf2SRichard Henderson .sh_type = SHT_NOBITS, 49905872bbf2SRichard Henderson .sh_flags = SHF_EXECINSTR | SHF_ALLOC, 49915872bbf2SRichard Henderson }, 49925872bbf2SRichard Henderson [2] = { /* .debug_info */ 49935872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 49945872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, di), 49955872bbf2SRichard Henderson .sh_size = sizeof(struct DebugInfo), 49965872bbf2SRichard Henderson }, 49975872bbf2SRichard Henderson [3] = { /* .debug_abbrev */ 49985872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 49995872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, da), 50005872bbf2SRichard Henderson .sh_size = sizeof(img->da), 50015872bbf2SRichard Henderson }, 50025872bbf2SRichard Henderson [4] = { /* .debug_frame */ 50035872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 50045872bbf2SRichard Henderson .sh_offset = sizeof(struct ElfImage), 50055872bbf2SRichard Henderson }, 50065872bbf2SRichard Henderson [5] = { /* .symtab */ 50075872bbf2SRichard Henderson .sh_type = SHT_SYMTAB, 50085872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, sym), 50095872bbf2SRichard Henderson .sh_size = sizeof(img->sym), 50105872bbf2SRichard Henderson .sh_info = 1, 50115872bbf2SRichard Henderson .sh_link = ARRAY_SIZE(img->shdr) - 1, 50125872bbf2SRichard Henderson .sh_entsize = sizeof(ElfW(Sym)), 50135872bbf2SRichard Henderson }, 50145872bbf2SRichard Henderson [6] = { /* .strtab */ 50155872bbf2SRichard Henderson .sh_type = SHT_STRTAB, 50165872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, str), 50175872bbf2SRichard Henderson .sh_size = sizeof(img->str), 50185872bbf2SRichard Henderson } 50195872bbf2SRichard Henderson }, 50205872bbf2SRichard Henderson .sym = { 50215872bbf2SRichard Henderson [1] = { /* code_gen_buffer */ 50225872bbf2SRichard Henderson .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC), 50235872bbf2SRichard Henderson .st_shndx = 1, 50245872bbf2SRichard Henderson } 50255872bbf2SRichard Henderson }, 50265872bbf2SRichard Henderson .di = { 50275872bbf2SRichard Henderson .len = sizeof(struct DebugInfo) - 4, 50285872bbf2SRichard Henderson .version = 2, 50295872bbf2SRichard Henderson .ptr_size = sizeof(void *), 50305872bbf2SRichard Henderson .cu_die = 1, 50315872bbf2SRichard Henderson .cu_lang = 0x8001, /* DW_LANG_Mips_Assembler */ 50325872bbf2SRichard Henderson .fn_die = 2, 50335872bbf2SRichard Henderson .fn_name = "code_gen_buffer" 50345872bbf2SRichard Henderson }, 50355872bbf2SRichard Henderson .da = { 50365872bbf2SRichard Henderson 1, /* abbrev number (the cu) */ 50375872bbf2SRichard Henderson 0x11, 1, /* DW_TAG_compile_unit, has children */ 50385872bbf2SRichard Henderson 0x13, 0x5, /* DW_AT_language, DW_FORM_data2 */ 50395872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */ 50405872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */ 50415872bbf2SRichard Henderson 0, 0, /* end of abbrev */ 50425872bbf2SRichard Henderson 2, /* abbrev number (the fn) */ 50435872bbf2SRichard Henderson 0x2e, 0, /* DW_TAG_subprogram, no children */ 50445872bbf2SRichard Henderson 0x3, 0x8, /* DW_AT_name, DW_FORM_string */ 50455872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */ 50465872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */ 50475872bbf2SRichard Henderson 0, 0, /* end of abbrev */ 50485872bbf2SRichard Henderson 0 /* no more abbrev */ 50495872bbf2SRichard Henderson }, 50505872bbf2SRichard Henderson .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0" 50515872bbf2SRichard Henderson ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer", 5052813da627SRichard Henderson }; 5053813da627SRichard Henderson 5054813da627SRichard Henderson /* We only need a single jit entry; statically allocate it. */ 5055813da627SRichard Henderson static struct jit_code_entry one_entry; 5056813da627SRichard Henderson 50575872bbf2SRichard Henderson uintptr_t buf = (uintptr_t)buf_ptr; 5058813da627SRichard Henderson size_t img_size = sizeof(struct ElfImage) + debug_frame_size; 50592c90784aSRichard Henderson DebugFrameHeader *dfh; 5060813da627SRichard Henderson 50615872bbf2SRichard Henderson img = g_malloc(img_size); 50625872bbf2SRichard Henderson *img = img_template; 5063813da627SRichard Henderson 50645872bbf2SRichard Henderson img->phdr.p_vaddr = buf; 50655872bbf2SRichard Henderson img->phdr.p_paddr = buf; 50665872bbf2SRichard Henderson img->phdr.p_memsz = buf_size; 5067813da627SRichard Henderson 50685872bbf2SRichard Henderson img->shdr[1].sh_name = find_string(img->str, ".text"); 50695872bbf2SRichard Henderson img->shdr[1].sh_addr = buf; 50705872bbf2SRichard Henderson img->shdr[1].sh_size = buf_size; 5071813da627SRichard Henderson 50725872bbf2SRichard Henderson img->shdr[2].sh_name = find_string(img->str, ".debug_info"); 50735872bbf2SRichard Henderson img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev"); 50745872bbf2SRichard Henderson 50755872bbf2SRichard Henderson img->shdr[4].sh_name = find_string(img->str, ".debug_frame"); 50765872bbf2SRichard Henderson img->shdr[4].sh_size = debug_frame_size; 50775872bbf2SRichard Henderson 50785872bbf2SRichard Henderson img->shdr[5].sh_name = find_string(img->str, ".symtab"); 50795872bbf2SRichard Henderson img->shdr[6].sh_name = find_string(img->str, ".strtab"); 50805872bbf2SRichard Henderson 50815872bbf2SRichard Henderson img->sym[1].st_name = find_string(img->str, "code_gen_buffer"); 50825872bbf2SRichard Henderson img->sym[1].st_value = buf; 50835872bbf2SRichard Henderson img->sym[1].st_size = buf_size; 50845872bbf2SRichard Henderson 50855872bbf2SRichard Henderson img->di.cu_low_pc = buf; 508645aba097SRichard Henderson img->di.cu_high_pc = buf + buf_size; 50875872bbf2SRichard Henderson img->di.fn_low_pc = buf; 508845aba097SRichard Henderson img->di.fn_high_pc = buf + buf_size; 5089813da627SRichard Henderson 50902c90784aSRichard Henderson dfh = (DebugFrameHeader *)(img + 1); 50912c90784aSRichard Henderson memcpy(dfh, debug_frame, debug_frame_size); 50922c90784aSRichard Henderson dfh->fde.func_start = buf; 50932c90784aSRichard Henderson dfh->fde.func_len = buf_size; 50942c90784aSRichard Henderson 5095813da627SRichard Henderson #ifdef DEBUG_JIT 5096813da627SRichard Henderson /* Enable this block to be able to debug the ELF image file creation. 5097813da627SRichard Henderson One can use readelf, objdump, or other inspection utilities. */ 5098813da627SRichard Henderson { 5099813da627SRichard Henderson FILE *f = fopen("/tmp/qemu.jit", "w+b"); 5100813da627SRichard Henderson if (f) { 51015872bbf2SRichard Henderson if (fwrite(img, img_size, 1, f) != img_size) { 5102813da627SRichard Henderson /* Avoid stupid unused return value warning for fwrite. */ 5103813da627SRichard Henderson } 5104813da627SRichard Henderson fclose(f); 5105813da627SRichard Henderson } 5106813da627SRichard Henderson } 5107813da627SRichard Henderson #endif 5108813da627SRichard Henderson 5109813da627SRichard Henderson one_entry.symfile_addr = img; 5110813da627SRichard Henderson one_entry.symfile_size = img_size; 5111813da627SRichard Henderson 5112813da627SRichard Henderson __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; 5113813da627SRichard Henderson __jit_debug_descriptor.relevant_entry = &one_entry; 5114813da627SRichard Henderson __jit_debug_descriptor.first_entry = &one_entry; 5115813da627SRichard Henderson __jit_debug_register_code(); 5116813da627SRichard Henderson } 5117813da627SRichard Henderson #else 51185872bbf2SRichard Henderson /* No support for the feature. Provide the entry point expected by exec.c, 51195872bbf2SRichard Henderson and implement the internal function we declared earlier. */ 5120813da627SRichard Henderson 5121755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size, 51222c90784aSRichard Henderson const void *debug_frame, 51232c90784aSRichard Henderson size_t debug_frame_size) 5124813da627SRichard Henderson { 5125813da627SRichard Henderson } 5126813da627SRichard Henderson 5127755bf9e5SRichard Henderson void tcg_register_jit(const void *buf, size_t buf_size) 5128813da627SRichard Henderson { 5129813da627SRichard Henderson } 5130813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */ 5131db432672SRichard Henderson 5132db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec 5133db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...) 5134db432672SRichard Henderson { 5135db432672SRichard Henderson g_assert_not_reached(); 5136db432672SRichard Henderson } 5137db432672SRichard Henderson #endif 5138