1c896fe29Sbellard /* 2c896fe29Sbellard * Tiny Code Generator for QEMU 3c896fe29Sbellard * 4c896fe29Sbellard * Copyright (c) 2008 Fabrice Bellard 5c896fe29Sbellard * 6c896fe29Sbellard * Permission is hereby granted, free of charge, to any person obtaining a copy 7c896fe29Sbellard * of this software and associated documentation files (the "Software"), to deal 8c896fe29Sbellard * in the Software without restriction, including without limitation the rights 9c896fe29Sbellard * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10c896fe29Sbellard * copies of the Software, and to permit persons to whom the Software is 11c896fe29Sbellard * furnished to do so, subject to the following conditions: 12c896fe29Sbellard * 13c896fe29Sbellard * The above copyright notice and this permission notice shall be included in 14c896fe29Sbellard * all copies or substantial portions of the Software. 15c896fe29Sbellard * 16c896fe29Sbellard * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17c896fe29Sbellard * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18c896fe29Sbellard * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19c896fe29Sbellard * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20c896fe29Sbellard * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21c896fe29Sbellard * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22c896fe29Sbellard * THE SOFTWARE. 23c896fe29Sbellard */ 24c896fe29Sbellard 25c896fe29Sbellard /* define it to use liveness analysis (better code) */ 268f2e8c07SKirill Batuzov #define USE_TCG_OPTIMIZATIONS 27c896fe29Sbellard 28757e725bSPeter Maydell #include "qemu/osdep.h" 29cca82982Saurel32 30813da627SRichard Henderson /* Define to jump the ELF file used to communicate with GDB. */ 31813da627SRichard Henderson #undef DEBUG_JIT 32813da627SRichard Henderson 3372fd2efbSEmilio G. Cota #include "qemu/error-report.h" 34f348b6d1SVeronia Bahaa #include "qemu/cutils.h" 351de7afc9SPaolo Bonzini #include "qemu/host-utils.h" 36d4c51a0aSMarkus Armbruster #include "qemu/qemu-print.h" 37084cfca1SRichard Henderson #include "qemu/cacheflush.h" 38ad768e6fSPeter Maydell #include "qemu/cacheinfo.h" 39c896fe29Sbellard 40c5d3c498SStefan Weil /* Note: the long term plan is to reduce the dependencies on the QEMU 41c896fe29Sbellard CPU definitions. Currently they are used for qemu_ld/st 42c896fe29Sbellard instructions */ 43c896fe29Sbellard #define NO_CPU_IO_DEFS 44c896fe29Sbellard 4563c91552SPaolo Bonzini #include "exec/exec-all.h" 46dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h" 47813da627SRichard Henderson 48edee2579SRichard Henderson #if UINTPTR_MAX == UINT32_MAX 49813da627SRichard Henderson # define ELF_CLASS ELFCLASS32 50edee2579SRichard Henderson #else 51edee2579SRichard Henderson # define ELF_CLASS ELFCLASS64 52813da627SRichard Henderson #endif 53e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN 54813da627SRichard Henderson # define ELF_DATA ELFDATA2MSB 55813da627SRichard Henderson #else 56813da627SRichard Henderson # define ELF_DATA ELFDATA2LSB 57813da627SRichard Henderson #endif 58813da627SRichard Henderson 59c896fe29Sbellard #include "elf.h" 60508127e2SPaolo Bonzini #include "exec/log.h" 61d2ba8026SRichard Henderson #include "tcg/tcg-ldst.h" 625ff7258cSRichard Henderson #include "tcg-internal.h" 635584e2dbSIlya Leoshkevich #include "accel/tcg/perf.h" 64c896fe29Sbellard 65139c1837SPaolo Bonzini /* Forward declarations for functions declared in tcg-target.c.inc and 66ce151109SPeter Maydell used here. */ 67e4d58b41SRichard Henderson static void tcg_target_init(TCGContext *s); 68e4d58b41SRichard Henderson static void tcg_target_qemu_prologue(TCGContext *s); 696ac17786SRichard Henderson static bool patch_reloc(tcg_insn_unit *code_ptr, int type, 702ba7fae2SRichard Henderson intptr_t value, intptr_t addend); 71c896fe29Sbellard 72497a22ebSRichard Henderson /* The CIE and FDE header definitions will be common to all hosts. */ 73497a22ebSRichard Henderson typedef struct { 74497a22ebSRichard Henderson uint32_t len __attribute__((aligned((sizeof(void *))))); 75497a22ebSRichard Henderson uint32_t id; 76497a22ebSRichard Henderson uint8_t version; 77497a22ebSRichard Henderson char augmentation[1]; 78497a22ebSRichard Henderson uint8_t code_align; 79497a22ebSRichard Henderson uint8_t data_align; 80497a22ebSRichard Henderson uint8_t return_column; 81497a22ebSRichard Henderson } DebugFrameCIE; 82497a22ebSRichard Henderson 83497a22ebSRichard Henderson typedef struct QEMU_PACKED { 84497a22ebSRichard Henderson uint32_t len __attribute__((aligned((sizeof(void *))))); 85497a22ebSRichard Henderson uint32_t cie_offset; 86edee2579SRichard Henderson uintptr_t func_start; 87edee2579SRichard Henderson uintptr_t func_len; 88497a22ebSRichard Henderson } DebugFrameFDEHeader; 89497a22ebSRichard Henderson 902c90784aSRichard Henderson typedef struct QEMU_PACKED { 912c90784aSRichard Henderson DebugFrameCIE cie; 922c90784aSRichard Henderson DebugFrameFDEHeader fde; 932c90784aSRichard Henderson } DebugFrameHeader; 942c90784aSRichard Henderson 95755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size, 962c90784aSRichard Henderson const void *debug_frame, 972c90784aSRichard Henderson size_t debug_frame_size) 98813da627SRichard Henderson __attribute__((unused)); 99813da627SRichard Henderson 100139c1837SPaolo Bonzini /* Forward declarations for functions declared and used in tcg-target.c.inc. */ 1012a534affSRichard Henderson static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1, 102a05b5b9bSRichard Henderson intptr_t arg2); 10378113e83SRichard Henderson static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg); 104c0ad3001SStefan Weil static void tcg_out_movi(TCGContext *s, TCGType type, 1052a534affSRichard Henderson TCGReg ret, tcg_target_long arg); 106313bdea8SRichard Henderson static void tcg_out_addi_ptr(TCGContext *s, TCGReg, TCGReg, tcg_target_long); 107b55a8d9dSRichard Henderson static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg); 108cf7d6b8eSRichard Henderson static void tcg_out_goto_tb(TCGContext *s, int which); 1095e8892dbSMiroslav Rezanina static void tcg_out_op(TCGContext *s, TCGOpcode opc, 1105e8892dbSMiroslav Rezanina const TCGArg args[TCG_MAX_OP_ARGS], 1115e8892dbSMiroslav Rezanina const int const_args[TCG_MAX_OP_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); 1195e8892dbSMiroslav Rezanina static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, 1205e8892dbSMiroslav Rezanina unsigned vecl, unsigned vece, 1215e8892dbSMiroslav Rezanina const TCGArg args[TCG_MAX_OP_ARGS], 1225e8892dbSMiroslav Rezanina const int const_args[TCG_MAX_OP_ARGS]); 123d2fd745fSRichard Henderson #else 124e7632cfaSRichard Henderson static inline bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece, 125e7632cfaSRichard Henderson TCGReg dst, TCGReg src) 126e7632cfaSRichard Henderson { 127e7632cfaSRichard Henderson g_assert_not_reached(); 128e7632cfaSRichard Henderson } 129d6ecb4a9SRichard Henderson static inline bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece, 130d6ecb4a9SRichard Henderson TCGReg dst, TCGReg base, intptr_t offset) 131d6ecb4a9SRichard Henderson { 132d6ecb4a9SRichard Henderson g_assert_not_reached(); 133d6ecb4a9SRichard Henderson } 1344e186175SRichard Henderson static inline void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece, 1354e186175SRichard Henderson TCGReg dst, int64_t arg) 136e7632cfaSRichard Henderson { 137e7632cfaSRichard Henderson g_assert_not_reached(); 138e7632cfaSRichard Henderson } 1395e8892dbSMiroslav Rezanina static inline void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, 1405e8892dbSMiroslav Rezanina unsigned vecl, unsigned vece, 1415e8892dbSMiroslav Rezanina const TCGArg args[TCG_MAX_OP_ARGS], 1425e8892dbSMiroslav Rezanina const int const_args[TCG_MAX_OP_ARGS]) 143d2fd745fSRichard Henderson { 144d2fd745fSRichard Henderson g_assert_not_reached(); 145d2fd745fSRichard Henderson } 146d2fd745fSRichard Henderson #endif 1472a534affSRichard Henderson static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1, 148a05b5b9bSRichard Henderson intptr_t arg2); 14959d7c14eSRichard Henderson static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val, 15059d7c14eSRichard Henderson TCGReg base, intptr_t ofs); 1517b7d8b2dSRichard Henderson static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target, 152cee44b03SRichard Henderson const TCGHelperInfo *info); 1535e3d0c19SRichard Henderson static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot); 154a4fbbd77SRichard Henderson static bool tcg_target_const_match(int64_t val, TCGType type, int ct); 155659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS 156aeee05f5SRichard Henderson static int tcg_out_ldst_finalize(TCGContext *s); 157659ef5cbSRichard Henderson #endif 158c896fe29Sbellard 15942eb6dfcSRichard Henderson TCGContext tcg_init_ctx; 16042eb6dfcSRichard Henderson __thread TCGContext *tcg_ctx; 16142eb6dfcSRichard Henderson 1625ff7258cSRichard Henderson TCGContext **tcg_ctxs; 1630e2d61cfSRichard Henderson unsigned int tcg_cur_ctxs; 1640e2d61cfSRichard Henderson unsigned int tcg_max_ctxs; 1651c2adb95SRichard Henderson TCGv_env cpu_env = 0; 166c8bc1168SRichard Henderson const void *tcg_code_gen_epilogue; 167db0c51a3SRichard Henderson uintptr_t tcg_splitwx_diff; 168df2cce29SEmilio G. Cota 169b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 170b91ccb31SRichard Henderson tcg_prologue_fn *tcg_qemu_tb_exec; 171b91ccb31SRichard Henderson #endif 172b91ccb31SRichard Henderson 173d2fd745fSRichard Henderson static TCGRegSet tcg_target_available_regs[TCG_TYPE_COUNT]; 174b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs; 175c896fe29Sbellard 1761813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1 1774196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v) 178c896fe29Sbellard { 179c896fe29Sbellard *s->code_ptr++ = v; 180c896fe29Sbellard } 181c896fe29Sbellard 1824196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p, 1834196dca6SPeter Maydell uint8_t v) 1845c53bb81SPeter Maydell { 1851813e175SRichard Henderson *p = v; 1865c53bb81SPeter Maydell } 1871813e175SRichard Henderson #endif 1885c53bb81SPeter Maydell 1891813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2 1904196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v) 191c896fe29Sbellard { 1921813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 2) { 1931813e175SRichard Henderson *s->code_ptr++ = v; 1941813e175SRichard Henderson } else { 1951813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 1964387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 1971813e175SRichard Henderson s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE); 1981813e175SRichard Henderson } 199c896fe29Sbellard } 200c896fe29Sbellard 2014196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p, 2024196dca6SPeter Maydell uint16_t v) 2035c53bb81SPeter Maydell { 2041813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 2) { 2051813e175SRichard Henderson *p = v; 2061813e175SRichard Henderson } else { 2075c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 2085c53bb81SPeter Maydell } 2091813e175SRichard Henderson } 2101813e175SRichard Henderson #endif 2115c53bb81SPeter Maydell 2121813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4 2134196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v) 214c896fe29Sbellard { 2151813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 4) { 2161813e175SRichard Henderson *s->code_ptr++ = v; 2171813e175SRichard Henderson } else { 2181813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 2194387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 2201813e175SRichard Henderson s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE); 2211813e175SRichard Henderson } 222c896fe29Sbellard } 223c896fe29Sbellard 2244196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p, 2254196dca6SPeter Maydell uint32_t v) 2265c53bb81SPeter Maydell { 2271813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 4) { 2281813e175SRichard Henderson *p = v; 2291813e175SRichard Henderson } else { 2305c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 2315c53bb81SPeter Maydell } 2321813e175SRichard Henderson } 2331813e175SRichard Henderson #endif 2345c53bb81SPeter Maydell 2351813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 8 2364196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v) 237ac26eb69SRichard Henderson { 2381813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 8) { 2391813e175SRichard Henderson *s->code_ptr++ = v; 2401813e175SRichard Henderson } else { 2411813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 2424387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 2431813e175SRichard Henderson s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE); 2441813e175SRichard Henderson } 245ac26eb69SRichard Henderson } 246ac26eb69SRichard Henderson 2474196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p, 2484196dca6SPeter Maydell uint64_t v) 2495c53bb81SPeter Maydell { 2501813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 8) { 2511813e175SRichard Henderson *p = v; 2521813e175SRichard Henderson } else { 2535c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 2545c53bb81SPeter Maydell } 2551813e175SRichard Henderson } 2561813e175SRichard Henderson #endif 2575c53bb81SPeter Maydell 258c896fe29Sbellard /* label relocation processing */ 259c896fe29Sbellard 2601813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type, 261bec16311SRichard Henderson TCGLabel *l, intptr_t addend) 262c896fe29Sbellard { 2637ecd02a0SRichard Henderson TCGRelocation *r = tcg_malloc(sizeof(TCGRelocation)); 264c896fe29Sbellard 265c896fe29Sbellard r->type = type; 266c896fe29Sbellard r->ptr = code_ptr; 267c896fe29Sbellard r->addend = addend; 2687ecd02a0SRichard Henderson QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next); 269c896fe29Sbellard } 270c896fe29Sbellard 27192ab8e7dSRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l) 272c896fe29Sbellard { 273eabb7b91SAurelien Jarno tcg_debug_assert(!l->has_value); 274c896fe29Sbellard l->has_value = 1; 27592ab8e7dSRichard Henderson l->u.value_ptr = tcg_splitwx_to_rx(s->code_ptr); 276c896fe29Sbellard } 277c896fe29Sbellard 27842a268c2SRichard Henderson TCGLabel *gen_new_label(void) 279c896fe29Sbellard { 280b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 28151e3972cSRichard Henderson TCGLabel *l = tcg_malloc(sizeof(TCGLabel)); 282c896fe29Sbellard 2837ecd02a0SRichard Henderson memset(l, 0, sizeof(TCGLabel)); 2847ecd02a0SRichard Henderson l->id = s->nb_labels++; 2857ecd02a0SRichard Henderson QSIMPLEQ_INIT(&l->relocs); 2867ecd02a0SRichard Henderson 287bef16ab4SRichard Henderson QSIMPLEQ_INSERT_TAIL(&s->labels, l, next); 28842a268c2SRichard Henderson 28942a268c2SRichard Henderson return l; 290c896fe29Sbellard } 291c896fe29Sbellard 2927ecd02a0SRichard Henderson static bool tcg_resolve_relocs(TCGContext *s) 2937ecd02a0SRichard Henderson { 2947ecd02a0SRichard Henderson TCGLabel *l; 2957ecd02a0SRichard Henderson 2967ecd02a0SRichard Henderson QSIMPLEQ_FOREACH(l, &s->labels, next) { 2977ecd02a0SRichard Henderson TCGRelocation *r; 2987ecd02a0SRichard Henderson uintptr_t value = l->u.value; 2997ecd02a0SRichard Henderson 3007ecd02a0SRichard Henderson QSIMPLEQ_FOREACH(r, &l->relocs, next) { 3017ecd02a0SRichard Henderson if (!patch_reloc(r->ptr, r->type, value, r->addend)) { 3027ecd02a0SRichard Henderson return false; 3037ecd02a0SRichard Henderson } 3047ecd02a0SRichard Henderson } 3057ecd02a0SRichard Henderson } 3067ecd02a0SRichard Henderson return true; 3077ecd02a0SRichard Henderson } 3087ecd02a0SRichard Henderson 3099f754620SRichard Henderson static void set_jmp_reset_offset(TCGContext *s, int which) 3109f754620SRichard Henderson { 311f14bed3fSRichard Henderson /* 312f14bed3fSRichard Henderson * We will check for overflow at the end of the opcode loop in 313f14bed3fSRichard Henderson * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX. 314f14bed3fSRichard Henderson */ 315b7e4afbdSRichard Henderson s->gen_tb->jmp_reset_offset[which] = tcg_current_code_size(s); 3169f754620SRichard Henderson } 3179f754620SRichard Henderson 318b52a2c03SRichard Henderson static void G_GNUC_UNUSED set_jmp_insn_offset(TCGContext *s, int which) 319b52a2c03SRichard Henderson { 320b52a2c03SRichard Henderson /* 321b52a2c03SRichard Henderson * We will check for overflow at the end of the opcode loop in 322b52a2c03SRichard Henderson * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX. 323b52a2c03SRichard Henderson */ 3249da6079bSRichard Henderson s->gen_tb->jmp_insn_offset[which] = tcg_current_code_size(s); 325b52a2c03SRichard Henderson } 326b52a2c03SRichard Henderson 327becc452aSRichard Henderson static uintptr_t G_GNUC_UNUSED get_jmp_target_addr(TCGContext *s, int which) 328becc452aSRichard Henderson { 329becc452aSRichard Henderson /* 330becc452aSRichard Henderson * Return the read-execute version of the pointer, for the benefit 331becc452aSRichard Henderson * of any pc-relative addressing mode. 332becc452aSRichard Henderson */ 3339da6079bSRichard Henderson return (uintptr_t)tcg_splitwx_to_rx(&s->gen_tb->jmp_target_addr[which]); 334becc452aSRichard Henderson } 335becc452aSRichard Henderson 336db6b7d0cSRichard Henderson /* Signal overflow, starting over with fewer guest insns. */ 3378905770bSMarc-André Lureau static G_NORETURN 3388905770bSMarc-André Lureau void tcg_raise_tb_overflow(TCGContext *s) 339db6b7d0cSRichard Henderson { 340db6b7d0cSRichard Henderson siglongjmp(s->jmp_trans, -2); 341db6b7d0cSRichard Henderson } 342db6b7d0cSRichard Henderson 3434c22e840SRichard Henderson #define C_PFX1(P, A) P##A 3444c22e840SRichard Henderson #define C_PFX2(P, A, B) P##A##_##B 3454c22e840SRichard Henderson #define C_PFX3(P, A, B, C) P##A##_##B##_##C 3464c22e840SRichard Henderson #define C_PFX4(P, A, B, C, D) P##A##_##B##_##C##_##D 3474c22e840SRichard Henderson #define C_PFX5(P, A, B, C, D, E) P##A##_##B##_##C##_##D##_##E 3484c22e840SRichard Henderson #define C_PFX6(P, A, B, C, D, E, F) P##A##_##B##_##C##_##D##_##E##_##F 3494c22e840SRichard Henderson 3504c22e840SRichard Henderson /* Define an enumeration for the various combinations. */ 3514c22e840SRichard Henderson 3524c22e840SRichard Henderson #define C_O0_I1(I1) C_PFX1(c_o0_i1_, I1), 3534c22e840SRichard Henderson #define C_O0_I2(I1, I2) C_PFX2(c_o0_i2_, I1, I2), 3544c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3) C_PFX3(c_o0_i3_, I1, I2, I3), 3554c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4) C_PFX4(c_o0_i4_, I1, I2, I3, I4), 3564c22e840SRichard Henderson 3574c22e840SRichard Henderson #define C_O1_I1(O1, I1) C_PFX2(c_o1_i1_, O1, I1), 3584c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2) C_PFX3(c_o1_i2_, O1, I1, I2), 3594c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3) C_PFX4(c_o1_i3_, O1, I1, I2, I3), 3604c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4) C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4), 3614c22e840SRichard Henderson 3624c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2) C_PFX3(c_n1_i2_, O1, I1, I2), 3634c22e840SRichard Henderson 3644c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1) C_PFX3(c_o2_i1_, O1, O2, I1), 3654c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2) C_PFX4(c_o2_i2_, O1, O2, I1, I2), 3664c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3) C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3), 3674c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4), 3684c22e840SRichard Henderson 3694c22e840SRichard Henderson typedef enum { 3704c22e840SRichard Henderson #include "tcg-target-con-set.h" 3714c22e840SRichard Henderson } TCGConstraintSetIndex; 3724c22e840SRichard Henderson 3734c22e840SRichard Henderson static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode); 3744c22e840SRichard Henderson 3754c22e840SRichard Henderson #undef C_O0_I1 3764c22e840SRichard Henderson #undef C_O0_I2 3774c22e840SRichard Henderson #undef C_O0_I3 3784c22e840SRichard Henderson #undef C_O0_I4 3794c22e840SRichard Henderson #undef C_O1_I1 3804c22e840SRichard Henderson #undef C_O1_I2 3814c22e840SRichard Henderson #undef C_O1_I3 3824c22e840SRichard Henderson #undef C_O1_I4 3834c22e840SRichard Henderson #undef C_N1_I2 3844c22e840SRichard Henderson #undef C_O2_I1 3854c22e840SRichard Henderson #undef C_O2_I2 3864c22e840SRichard Henderson #undef C_O2_I3 3874c22e840SRichard Henderson #undef C_O2_I4 3884c22e840SRichard Henderson 3894c22e840SRichard Henderson /* Put all of the constraint sets into an array, indexed by the enum. */ 3904c22e840SRichard Henderson 3914c22e840SRichard Henderson #define C_O0_I1(I1) { .args_ct_str = { #I1 } }, 3924c22e840SRichard Henderson #define C_O0_I2(I1, I2) { .args_ct_str = { #I1, #I2 } }, 3934c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3) { .args_ct_str = { #I1, #I2, #I3 } }, 3944c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4) { .args_ct_str = { #I1, #I2, #I3, #I4 } }, 3954c22e840SRichard Henderson 3964c22e840SRichard Henderson #define C_O1_I1(O1, I1) { .args_ct_str = { #O1, #I1 } }, 3974c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2) { .args_ct_str = { #O1, #I1, #I2 } }, 3984c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3) { .args_ct_str = { #O1, #I1, #I2, #I3 } }, 3994c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4) { .args_ct_str = { #O1, #I1, #I2, #I3, #I4 } }, 4004c22e840SRichard Henderson 4014c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2) { .args_ct_str = { "&" #O1, #I1, #I2 } }, 4024c22e840SRichard Henderson 4034c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1) { .args_ct_str = { #O1, #O2, #I1 } }, 4044c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2) { .args_ct_str = { #O1, #O2, #I1, #I2 } }, 4054c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3) { .args_ct_str = { #O1, #O2, #I1, #I2, #I3 } }, 4064c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) { .args_ct_str = { #O1, #O2, #I1, #I2, #I3, #I4 } }, 4074c22e840SRichard Henderson 4084c22e840SRichard Henderson static const TCGTargetOpDef constraint_sets[] = { 4094c22e840SRichard Henderson #include "tcg-target-con-set.h" 4104c22e840SRichard Henderson }; 4114c22e840SRichard Henderson 4124c22e840SRichard Henderson 4134c22e840SRichard Henderson #undef C_O0_I1 4144c22e840SRichard Henderson #undef C_O0_I2 4154c22e840SRichard Henderson #undef C_O0_I3 4164c22e840SRichard Henderson #undef C_O0_I4 4174c22e840SRichard Henderson #undef C_O1_I1 4184c22e840SRichard Henderson #undef C_O1_I2 4194c22e840SRichard Henderson #undef C_O1_I3 4204c22e840SRichard Henderson #undef C_O1_I4 4214c22e840SRichard Henderson #undef C_N1_I2 4224c22e840SRichard Henderson #undef C_O2_I1 4234c22e840SRichard Henderson #undef C_O2_I2 4244c22e840SRichard Henderson #undef C_O2_I3 4254c22e840SRichard Henderson #undef C_O2_I4 4264c22e840SRichard Henderson 4274c22e840SRichard Henderson /* Expand the enumerator to be returned from tcg_target_op_def(). */ 4284c22e840SRichard Henderson 4294c22e840SRichard Henderson #define C_O0_I1(I1) C_PFX1(c_o0_i1_, I1) 4304c22e840SRichard Henderson #define C_O0_I2(I1, I2) C_PFX2(c_o0_i2_, I1, I2) 4314c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3) C_PFX3(c_o0_i3_, I1, I2, I3) 4324c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4) C_PFX4(c_o0_i4_, I1, I2, I3, I4) 4334c22e840SRichard Henderson 4344c22e840SRichard Henderson #define C_O1_I1(O1, I1) C_PFX2(c_o1_i1_, O1, I1) 4354c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2) C_PFX3(c_o1_i2_, O1, I1, I2) 4364c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3) C_PFX4(c_o1_i3_, O1, I1, I2, I3) 4374c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4) C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4) 4384c22e840SRichard Henderson 4394c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2) C_PFX3(c_n1_i2_, O1, I1, I2) 4404c22e840SRichard Henderson 4414c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1) C_PFX3(c_o2_i1_, O1, O2, I1) 4424c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2) C_PFX4(c_o2_i2_, O1, O2, I1, I2) 4434c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3) C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3) 4444c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4) 4454c22e840SRichard Henderson 446139c1837SPaolo Bonzini #include "tcg-target.c.inc" 447c896fe29Sbellard 44838b47b19SEmilio G. Cota static void alloc_tcg_plugin_context(TCGContext *s) 44938b47b19SEmilio G. Cota { 45038b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN 45138b47b19SEmilio G. Cota s->plugin_tb = g_new0(struct qemu_plugin_tb, 1); 45238b47b19SEmilio G. Cota s->plugin_tb->insns = 45338b47b19SEmilio G. Cota g_ptr_array_new_with_free_func(qemu_plugin_insn_cleanup_fn); 45438b47b19SEmilio G. Cota #endif 45538b47b19SEmilio G. Cota } 45638b47b19SEmilio G. Cota 457e8feb96fSEmilio G. Cota /* 4583468b59eSEmilio G. Cota * All TCG threads except the parent (i.e. the one that called tcg_context_init 4593468b59eSEmilio G. Cota * and registered the target's TCG globals) must register with this function 4603468b59eSEmilio G. Cota * before initiating translation. 4613468b59eSEmilio G. Cota * 4623468b59eSEmilio G. Cota * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation 4633468b59eSEmilio G. Cota * of tcg_region_init() for the reasoning behind this. 4643468b59eSEmilio G. Cota * 4653468b59eSEmilio G. Cota * In softmmu each caller registers its context in tcg_ctxs[]. Note that in 4663468b59eSEmilio G. Cota * softmmu tcg_ctxs[] does not track tcg_ctx_init, since the initial context 4673468b59eSEmilio G. Cota * is not used anymore for translation once this function is called. 4683468b59eSEmilio G. Cota * 4693468b59eSEmilio G. Cota * Not tracking tcg_init_ctx in tcg_ctxs[] in softmmu keeps code that iterates 4703468b59eSEmilio G. Cota * over the array (e.g. tcg_code_size() the same for both softmmu and user-mode. 4713468b59eSEmilio G. Cota */ 4723468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY 4733468b59eSEmilio G. Cota void tcg_register_thread(void) 4743468b59eSEmilio G. Cota { 4753468b59eSEmilio G. Cota tcg_ctx = &tcg_init_ctx; 4763468b59eSEmilio G. Cota } 4773468b59eSEmilio G. Cota #else 4783468b59eSEmilio G. Cota void tcg_register_thread(void) 4793468b59eSEmilio G. Cota { 4803468b59eSEmilio G. Cota TCGContext *s = g_malloc(sizeof(*s)); 4813468b59eSEmilio G. Cota unsigned int i, n; 4823468b59eSEmilio G. Cota 4833468b59eSEmilio G. Cota *s = tcg_init_ctx; 4843468b59eSEmilio G. Cota 4853468b59eSEmilio G. Cota /* Relink mem_base. */ 4863468b59eSEmilio G. Cota for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) { 4873468b59eSEmilio G. Cota if (tcg_init_ctx.temps[i].mem_base) { 4883468b59eSEmilio G. Cota ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps; 4893468b59eSEmilio G. Cota tcg_debug_assert(b >= 0 && b < n); 4903468b59eSEmilio G. Cota s->temps[i].mem_base = &s->temps[b]; 4913468b59eSEmilio G. Cota } 4923468b59eSEmilio G. Cota } 4933468b59eSEmilio G. Cota 4943468b59eSEmilio G. Cota /* Claim an entry in tcg_ctxs */ 4950e2d61cfSRichard Henderson n = qatomic_fetch_inc(&tcg_cur_ctxs); 4960e2d61cfSRichard Henderson g_assert(n < tcg_max_ctxs); 497d73415a3SStefan Hajnoczi qatomic_set(&tcg_ctxs[n], s); 4983468b59eSEmilio G. Cota 49938b47b19SEmilio G. Cota if (n > 0) { 50038b47b19SEmilio G. Cota alloc_tcg_plugin_context(s); 501bf042e8eSRichard Henderson tcg_region_initial_alloc(s); 50238b47b19SEmilio G. Cota } 50338b47b19SEmilio G. Cota 5043468b59eSEmilio G. Cota tcg_ctx = s; 5053468b59eSEmilio G. Cota } 5063468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */ 5073468b59eSEmilio G. Cota 508c896fe29Sbellard /* pool based memory allocation */ 509c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size) 510c896fe29Sbellard { 511c896fe29Sbellard TCGPool *p; 512c896fe29Sbellard int pool_size; 513c896fe29Sbellard 514c896fe29Sbellard if (size > TCG_POOL_CHUNK_SIZE) { 515c896fe29Sbellard /* big malloc: insert a new pool (XXX: could optimize) */ 5167267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + size); 517c896fe29Sbellard p->size = size; 5184055299eSKirill Batuzov p->next = s->pool_first_large; 5194055299eSKirill Batuzov s->pool_first_large = p; 5204055299eSKirill Batuzov return p->data; 521c896fe29Sbellard } else { 522c896fe29Sbellard p = s->pool_current; 523c896fe29Sbellard if (!p) { 524c896fe29Sbellard p = s->pool_first; 525c896fe29Sbellard if (!p) 526c896fe29Sbellard goto new_pool; 527c896fe29Sbellard } else { 528c896fe29Sbellard if (!p->next) { 529c896fe29Sbellard new_pool: 530c896fe29Sbellard pool_size = TCG_POOL_CHUNK_SIZE; 5317267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + pool_size); 532c896fe29Sbellard p->size = pool_size; 533c896fe29Sbellard p->next = NULL; 534a813e36fSRichard Henderson if (s->pool_current) { 535c896fe29Sbellard s->pool_current->next = p; 536a813e36fSRichard Henderson } else { 537c896fe29Sbellard s->pool_first = p; 538a813e36fSRichard Henderson } 539c896fe29Sbellard } else { 540c896fe29Sbellard p = p->next; 541c896fe29Sbellard } 542c896fe29Sbellard } 543c896fe29Sbellard } 544c896fe29Sbellard s->pool_current = p; 545c896fe29Sbellard s->pool_cur = p->data + size; 546c896fe29Sbellard s->pool_end = p->data + p->size; 547c896fe29Sbellard return p->data; 548c896fe29Sbellard } 549c896fe29Sbellard 550c896fe29Sbellard void tcg_pool_reset(TCGContext *s) 551c896fe29Sbellard { 5524055299eSKirill Batuzov TCGPool *p, *t; 5534055299eSKirill Batuzov for (p = s->pool_first_large; p; p = t) { 5544055299eSKirill Batuzov t = p->next; 5554055299eSKirill Batuzov g_free(p); 5564055299eSKirill Batuzov } 5574055299eSKirill Batuzov s->pool_first_large = NULL; 558c896fe29Sbellard s->pool_cur = s->pool_end = NULL; 559c896fe29Sbellard s->pool_current = NULL; 560c896fe29Sbellard } 561c896fe29Sbellard 5622ef6175aSRichard Henderson #include "exec/helper-proto.h" 5632ef6175aSRichard Henderson 56439004a71SRichard Henderson static TCGHelperInfo all_helpers[] = { 5652ef6175aSRichard Henderson #include "exec/helper-tcg.h" 566100b5e01SRichard Henderson }; 567619205fdSEmilio G. Cota static GHashTable *helper_table; 568100b5e01SRichard Henderson 56922f15579SRichard Henderson #ifdef CONFIG_TCG_INTERPRETER 570c6ef8c7bSPhilippe Mathieu-Daudé static ffi_type *typecode_to_ffi(int argmask) 571c6ef8c7bSPhilippe Mathieu-Daudé { 572e9709e17SRichard Henderson /* 573e9709e17SRichard Henderson * libffi does not support __int128_t, so we have forced Int128 574e9709e17SRichard Henderson * to use the structure definition instead of the builtin type. 575e9709e17SRichard Henderson */ 576e9709e17SRichard Henderson static ffi_type *ffi_type_i128_elements[3] = { 577e9709e17SRichard Henderson &ffi_type_uint64, 578e9709e17SRichard Henderson &ffi_type_uint64, 579e9709e17SRichard Henderson NULL 580e9709e17SRichard Henderson }; 581e9709e17SRichard Henderson static ffi_type ffi_type_i128 = { 582e9709e17SRichard Henderson .size = 16, 583e9709e17SRichard Henderson .alignment = __alignof__(Int128), 584e9709e17SRichard Henderson .type = FFI_TYPE_STRUCT, 585e9709e17SRichard Henderson .elements = ffi_type_i128_elements, 586e9709e17SRichard Henderson }; 587e9709e17SRichard Henderson 588c6ef8c7bSPhilippe Mathieu-Daudé switch (argmask) { 589c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_void: 590c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_void; 591c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_i32: 592c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_uint32; 593c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_s32: 594c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_sint32; 595c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_i64: 596c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_uint64; 597c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_s64: 598c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_sint64; 599c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_ptr: 600c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_pointer; 601e9709e17SRichard Henderson case dh_typecode_i128: 602e9709e17SRichard Henderson return &ffi_type_i128; 603c6ef8c7bSPhilippe Mathieu-Daudé } 604c6ef8c7bSPhilippe Mathieu-Daudé g_assert_not_reached(); 605c6ef8c7bSPhilippe Mathieu-Daudé } 6060c22e176SPhilippe Mathieu-Daudé 6070c22e176SPhilippe Mathieu-Daudé static void init_ffi_layouts(void) 6080c22e176SPhilippe Mathieu-Daudé { 6090c22e176SPhilippe Mathieu-Daudé /* g_direct_hash/equal for direct comparisons on uint32_t. */ 610f9c4bb80SRichard Henderson GHashTable *ffi_table = g_hash_table_new(NULL, NULL); 611f9c4bb80SRichard Henderson 6120c22e176SPhilippe Mathieu-Daudé for (int i = 0; i < ARRAY_SIZE(all_helpers); ++i) { 613f9c4bb80SRichard Henderson TCGHelperInfo *info = &all_helpers[i]; 614f9c4bb80SRichard Henderson unsigned typemask = info->typemask; 6150c22e176SPhilippe Mathieu-Daudé gpointer hash = (gpointer)(uintptr_t)typemask; 6160c22e176SPhilippe Mathieu-Daudé struct { 6170c22e176SPhilippe Mathieu-Daudé ffi_cif cif; 6180c22e176SPhilippe Mathieu-Daudé ffi_type *args[]; 6190c22e176SPhilippe Mathieu-Daudé } *ca; 6200c22e176SPhilippe Mathieu-Daudé ffi_status status; 6210c22e176SPhilippe Mathieu-Daudé int nargs; 622f9c4bb80SRichard Henderson ffi_cif *cif; 6230c22e176SPhilippe Mathieu-Daudé 624f9c4bb80SRichard Henderson cif = g_hash_table_lookup(ffi_table, hash); 625f9c4bb80SRichard Henderson if (cif) { 626f9c4bb80SRichard Henderson info->cif = cif; 6270c22e176SPhilippe Mathieu-Daudé continue; 6280c22e176SPhilippe Mathieu-Daudé } 6290c22e176SPhilippe Mathieu-Daudé 6300c22e176SPhilippe Mathieu-Daudé /* Ignoring the return type, find the last non-zero field. */ 6310c22e176SPhilippe Mathieu-Daudé nargs = 32 - clz32(typemask >> 3); 6320c22e176SPhilippe Mathieu-Daudé nargs = DIV_ROUND_UP(nargs, 3); 633e9709e17SRichard Henderson assert(nargs <= MAX_CALL_IARGS); 6340c22e176SPhilippe Mathieu-Daudé 6350c22e176SPhilippe Mathieu-Daudé ca = g_malloc0(sizeof(*ca) + nargs * sizeof(ffi_type *)); 6360c22e176SPhilippe Mathieu-Daudé ca->cif.rtype = typecode_to_ffi(typemask & 7); 6370c22e176SPhilippe Mathieu-Daudé ca->cif.nargs = nargs; 6380c22e176SPhilippe Mathieu-Daudé 6390c22e176SPhilippe Mathieu-Daudé if (nargs != 0) { 6400c22e176SPhilippe Mathieu-Daudé ca->cif.arg_types = ca->args; 6410c22e176SPhilippe Mathieu-Daudé for (int j = 0; j < nargs; ++j) { 6420c22e176SPhilippe Mathieu-Daudé int typecode = extract32(typemask, (j + 1) * 3, 3); 6430c22e176SPhilippe Mathieu-Daudé ca->args[j] = typecode_to_ffi(typecode); 6440c22e176SPhilippe Mathieu-Daudé } 6450c22e176SPhilippe Mathieu-Daudé } 6460c22e176SPhilippe Mathieu-Daudé 6470c22e176SPhilippe Mathieu-Daudé status = ffi_prep_cif(&ca->cif, FFI_DEFAULT_ABI, nargs, 6480c22e176SPhilippe Mathieu-Daudé ca->cif.rtype, ca->cif.arg_types); 6490c22e176SPhilippe Mathieu-Daudé assert(status == FFI_OK); 6500c22e176SPhilippe Mathieu-Daudé 651f9c4bb80SRichard Henderson cif = &ca->cif; 652f9c4bb80SRichard Henderson info->cif = cif; 653f9c4bb80SRichard Henderson g_hash_table_insert(ffi_table, hash, (gpointer)cif); 6540c22e176SPhilippe Mathieu-Daudé } 655f9c4bb80SRichard Henderson 656f9c4bb80SRichard Henderson g_hash_table_destroy(ffi_table); 6570c22e176SPhilippe Mathieu-Daudé } 6580c22e176SPhilippe Mathieu-Daudé #endif /* CONFIG_TCG_INTERPRETER */ 65922f15579SRichard Henderson 66039004a71SRichard Henderson typedef struct TCGCumulativeArgs { 66139004a71SRichard Henderson int arg_idx; /* tcg_gen_callN args[] */ 66239004a71SRichard Henderson int info_in_idx; /* TCGHelperInfo in[] */ 66339004a71SRichard Henderson int arg_slot; /* regs+stack slot */ 66439004a71SRichard Henderson int ref_slot; /* stack slots for references */ 66539004a71SRichard Henderson } TCGCumulativeArgs; 66639004a71SRichard Henderson 66739004a71SRichard Henderson static void layout_arg_even(TCGCumulativeArgs *cum) 66839004a71SRichard Henderson { 66939004a71SRichard Henderson cum->arg_slot += cum->arg_slot & 1; 67039004a71SRichard Henderson } 67139004a71SRichard Henderson 67239004a71SRichard Henderson static void layout_arg_1(TCGCumulativeArgs *cum, TCGHelperInfo *info, 67339004a71SRichard Henderson TCGCallArgumentKind kind) 67439004a71SRichard Henderson { 67539004a71SRichard Henderson TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx]; 67639004a71SRichard Henderson 67739004a71SRichard Henderson *loc = (TCGCallArgumentLoc){ 67839004a71SRichard Henderson .kind = kind, 67939004a71SRichard Henderson .arg_idx = cum->arg_idx, 68039004a71SRichard Henderson .arg_slot = cum->arg_slot, 68139004a71SRichard Henderson }; 68239004a71SRichard Henderson cum->info_in_idx++; 68339004a71SRichard Henderson cum->arg_slot++; 68439004a71SRichard Henderson } 68539004a71SRichard Henderson 68639004a71SRichard Henderson static void layout_arg_normal_n(TCGCumulativeArgs *cum, 68739004a71SRichard Henderson TCGHelperInfo *info, int n) 68839004a71SRichard Henderson { 68939004a71SRichard Henderson TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx]; 69039004a71SRichard Henderson 69139004a71SRichard Henderson for (int i = 0; i < n; ++i) { 69239004a71SRichard Henderson /* Layout all using the same arg_idx, adjusting the subindex. */ 69339004a71SRichard Henderson loc[i] = (TCGCallArgumentLoc){ 69439004a71SRichard Henderson .kind = TCG_CALL_ARG_NORMAL, 69539004a71SRichard Henderson .arg_idx = cum->arg_idx, 69639004a71SRichard Henderson .tmp_subindex = i, 69739004a71SRichard Henderson .arg_slot = cum->arg_slot + i, 69839004a71SRichard Henderson }; 69939004a71SRichard Henderson } 70039004a71SRichard Henderson cum->info_in_idx += n; 70139004a71SRichard Henderson cum->arg_slot += n; 70239004a71SRichard Henderson } 70339004a71SRichard Henderson 704313bdea8SRichard Henderson static void layout_arg_by_ref(TCGCumulativeArgs *cum, TCGHelperInfo *info) 705313bdea8SRichard Henderson { 706313bdea8SRichard Henderson TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx]; 707313bdea8SRichard Henderson int n = 128 / TCG_TARGET_REG_BITS; 708313bdea8SRichard Henderson 709313bdea8SRichard Henderson /* The first subindex carries the pointer. */ 710313bdea8SRichard Henderson layout_arg_1(cum, info, TCG_CALL_ARG_BY_REF); 711313bdea8SRichard Henderson 712313bdea8SRichard Henderson /* 713313bdea8SRichard Henderson * The callee is allowed to clobber memory associated with 714313bdea8SRichard Henderson * structure pass by-reference. Therefore we must make copies. 715313bdea8SRichard Henderson * Allocate space from "ref_slot", which will be adjusted to 716313bdea8SRichard Henderson * follow the parameters on the stack. 717313bdea8SRichard Henderson */ 718313bdea8SRichard Henderson loc[0].ref_slot = cum->ref_slot; 719313bdea8SRichard Henderson 720313bdea8SRichard Henderson /* 721313bdea8SRichard Henderson * Subsequent words also go into the reference slot, but 722313bdea8SRichard Henderson * do not accumulate into the regular arguments. 723313bdea8SRichard Henderson */ 724313bdea8SRichard Henderson for (int i = 1; i < n; ++i) { 725313bdea8SRichard Henderson loc[i] = (TCGCallArgumentLoc){ 726313bdea8SRichard Henderson .kind = TCG_CALL_ARG_BY_REF_N, 727313bdea8SRichard Henderson .arg_idx = cum->arg_idx, 728313bdea8SRichard Henderson .tmp_subindex = i, 729313bdea8SRichard Henderson .ref_slot = cum->ref_slot + i, 730313bdea8SRichard Henderson }; 731313bdea8SRichard Henderson } 732313bdea8SRichard Henderson cum->info_in_idx += n; 733313bdea8SRichard Henderson cum->ref_slot += n; 734313bdea8SRichard Henderson } 735313bdea8SRichard Henderson 73639004a71SRichard Henderson static void init_call_layout(TCGHelperInfo *info) 73739004a71SRichard Henderson { 73839004a71SRichard Henderson int max_reg_slots = ARRAY_SIZE(tcg_target_call_iarg_regs); 73939004a71SRichard Henderson int max_stk_slots = TCG_STATIC_CALL_ARGS_SIZE / sizeof(tcg_target_long); 74039004a71SRichard Henderson unsigned typemask = info->typemask; 74139004a71SRichard Henderson unsigned typecode; 74239004a71SRichard Henderson TCGCumulativeArgs cum = { }; 74339004a71SRichard Henderson 74439004a71SRichard Henderson /* 74539004a71SRichard Henderson * Parse and place any function return value. 74639004a71SRichard Henderson */ 74739004a71SRichard Henderson typecode = typemask & 7; 74839004a71SRichard Henderson switch (typecode) { 74939004a71SRichard Henderson case dh_typecode_void: 75039004a71SRichard Henderson info->nr_out = 0; 75139004a71SRichard Henderson break; 75239004a71SRichard Henderson case dh_typecode_i32: 75339004a71SRichard Henderson case dh_typecode_s32: 75439004a71SRichard Henderson case dh_typecode_ptr: 75539004a71SRichard Henderson info->nr_out = 1; 75639004a71SRichard Henderson info->out_kind = TCG_CALL_RET_NORMAL; 75739004a71SRichard Henderson break; 75839004a71SRichard Henderson case dh_typecode_i64: 75939004a71SRichard Henderson case dh_typecode_s64: 76039004a71SRichard Henderson info->nr_out = 64 / TCG_TARGET_REG_BITS; 76139004a71SRichard Henderson info->out_kind = TCG_CALL_RET_NORMAL; 7625e3d0c19SRichard Henderson /* Query the last register now to trigger any assert early. */ 7635e3d0c19SRichard Henderson tcg_target_call_oarg_reg(info->out_kind, info->nr_out - 1); 764466d3759SRichard Henderson break; 765466d3759SRichard Henderson case dh_typecode_i128: 766466d3759SRichard Henderson info->nr_out = 128 / TCG_TARGET_REG_BITS; 7675427a9a7SRichard Henderson info->out_kind = TCG_TARGET_CALL_RET_I128; 7685427a9a7SRichard Henderson switch (TCG_TARGET_CALL_RET_I128) { 769466d3759SRichard Henderson case TCG_CALL_RET_NORMAL: 7705e3d0c19SRichard Henderson /* Query the last register now to trigger any assert early. */ 7715e3d0c19SRichard Henderson tcg_target_call_oarg_reg(info->out_kind, info->nr_out - 1); 772466d3759SRichard Henderson break; 773c6556aa0SRichard Henderson case TCG_CALL_RET_BY_VEC: 774c6556aa0SRichard Henderson /* Query the single register now to trigger any assert early. */ 775c6556aa0SRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0); 776c6556aa0SRichard Henderson break; 777313bdea8SRichard Henderson case TCG_CALL_RET_BY_REF: 778313bdea8SRichard Henderson /* 779313bdea8SRichard Henderson * Allocate the first argument to the output. 780313bdea8SRichard Henderson * We don't need to store this anywhere, just make it 781313bdea8SRichard Henderson * unavailable for use in the input loop below. 782313bdea8SRichard Henderson */ 783313bdea8SRichard Henderson cum.arg_slot = 1; 784313bdea8SRichard Henderson break; 785466d3759SRichard Henderson default: 786466d3759SRichard Henderson qemu_build_not_reached(); 787466d3759SRichard Henderson } 78839004a71SRichard Henderson break; 78939004a71SRichard Henderson default: 79039004a71SRichard Henderson g_assert_not_reached(); 79139004a71SRichard Henderson } 79239004a71SRichard Henderson 79339004a71SRichard Henderson /* 79439004a71SRichard Henderson * Parse and place function arguments. 79539004a71SRichard Henderson */ 79639004a71SRichard Henderson for (typemask >>= 3; typemask; typemask >>= 3, cum.arg_idx++) { 79739004a71SRichard Henderson TCGCallArgumentKind kind; 79839004a71SRichard Henderson TCGType type; 79939004a71SRichard Henderson 80039004a71SRichard Henderson typecode = typemask & 7; 80139004a71SRichard Henderson switch (typecode) { 80239004a71SRichard Henderson case dh_typecode_i32: 80339004a71SRichard Henderson case dh_typecode_s32: 80439004a71SRichard Henderson type = TCG_TYPE_I32; 80539004a71SRichard Henderson break; 80639004a71SRichard Henderson case dh_typecode_i64: 80739004a71SRichard Henderson case dh_typecode_s64: 80839004a71SRichard Henderson type = TCG_TYPE_I64; 80939004a71SRichard Henderson break; 81039004a71SRichard Henderson case dh_typecode_ptr: 81139004a71SRichard Henderson type = TCG_TYPE_PTR; 81239004a71SRichard Henderson break; 813466d3759SRichard Henderson case dh_typecode_i128: 814466d3759SRichard Henderson type = TCG_TYPE_I128; 815466d3759SRichard Henderson break; 81639004a71SRichard Henderson default: 81739004a71SRichard Henderson g_assert_not_reached(); 81839004a71SRichard Henderson } 81939004a71SRichard Henderson 82039004a71SRichard Henderson switch (type) { 82139004a71SRichard Henderson case TCG_TYPE_I32: 82239004a71SRichard Henderson switch (TCG_TARGET_CALL_ARG_I32) { 82339004a71SRichard Henderson case TCG_CALL_ARG_EVEN: 82439004a71SRichard Henderson layout_arg_even(&cum); 82539004a71SRichard Henderson /* fall through */ 82639004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 82739004a71SRichard Henderson layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL); 82839004a71SRichard Henderson break; 82939004a71SRichard Henderson case TCG_CALL_ARG_EXTEND: 83039004a71SRichard Henderson kind = TCG_CALL_ARG_EXTEND_U + (typecode & 1); 83139004a71SRichard Henderson layout_arg_1(&cum, info, kind); 83239004a71SRichard Henderson break; 83339004a71SRichard Henderson default: 83439004a71SRichard Henderson qemu_build_not_reached(); 83539004a71SRichard Henderson } 83639004a71SRichard Henderson break; 83739004a71SRichard Henderson 83839004a71SRichard Henderson case TCG_TYPE_I64: 83939004a71SRichard Henderson switch (TCG_TARGET_CALL_ARG_I64) { 84039004a71SRichard Henderson case TCG_CALL_ARG_EVEN: 84139004a71SRichard Henderson layout_arg_even(&cum); 84239004a71SRichard Henderson /* fall through */ 84339004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 84439004a71SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 84539004a71SRichard Henderson layout_arg_normal_n(&cum, info, 2); 84639004a71SRichard Henderson } else { 84739004a71SRichard Henderson layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL); 84839004a71SRichard Henderson } 84939004a71SRichard Henderson break; 85039004a71SRichard Henderson default: 85139004a71SRichard Henderson qemu_build_not_reached(); 85239004a71SRichard Henderson } 85339004a71SRichard Henderson break; 85439004a71SRichard Henderson 855466d3759SRichard Henderson case TCG_TYPE_I128: 8565427a9a7SRichard Henderson switch (TCG_TARGET_CALL_ARG_I128) { 857466d3759SRichard Henderson case TCG_CALL_ARG_EVEN: 858466d3759SRichard Henderson layout_arg_even(&cum); 859466d3759SRichard Henderson /* fall through */ 860466d3759SRichard Henderson case TCG_CALL_ARG_NORMAL: 861466d3759SRichard Henderson layout_arg_normal_n(&cum, info, 128 / TCG_TARGET_REG_BITS); 862466d3759SRichard Henderson break; 863313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF: 864313bdea8SRichard Henderson layout_arg_by_ref(&cum, info); 865313bdea8SRichard Henderson break; 866466d3759SRichard Henderson default: 867466d3759SRichard Henderson qemu_build_not_reached(); 868466d3759SRichard Henderson } 869466d3759SRichard Henderson break; 870466d3759SRichard Henderson 87139004a71SRichard Henderson default: 87239004a71SRichard Henderson g_assert_not_reached(); 87339004a71SRichard Henderson } 87439004a71SRichard Henderson } 87539004a71SRichard Henderson info->nr_in = cum.info_in_idx; 87639004a71SRichard Henderson 87739004a71SRichard Henderson /* Validate that we didn't overrun the input array. */ 87839004a71SRichard Henderson assert(cum.info_in_idx <= ARRAY_SIZE(info->in)); 87939004a71SRichard Henderson /* Validate the backend has enough argument space. */ 88039004a71SRichard Henderson assert(cum.arg_slot <= max_reg_slots + max_stk_slots); 881313bdea8SRichard Henderson 882313bdea8SRichard Henderson /* 883313bdea8SRichard Henderson * Relocate the "ref_slot" area to the end of the parameters. 884313bdea8SRichard Henderson * Minimizing this stack offset helps code size for x86, 885313bdea8SRichard Henderson * which has a signed 8-bit offset encoding. 886313bdea8SRichard Henderson */ 887313bdea8SRichard Henderson if (cum.ref_slot != 0) { 888313bdea8SRichard Henderson int ref_base = 0; 889313bdea8SRichard Henderson 890313bdea8SRichard Henderson if (cum.arg_slot > max_reg_slots) { 891313bdea8SRichard Henderson int align = __alignof(Int128) / sizeof(tcg_target_long); 892313bdea8SRichard Henderson 893313bdea8SRichard Henderson ref_base = cum.arg_slot - max_reg_slots; 894313bdea8SRichard Henderson if (align > 1) { 895313bdea8SRichard Henderson ref_base = ROUND_UP(ref_base, align); 896313bdea8SRichard Henderson } 897313bdea8SRichard Henderson } 898313bdea8SRichard Henderson assert(ref_base + cum.ref_slot <= max_stk_slots); 899313bdea8SRichard Henderson 900313bdea8SRichard Henderson if (ref_base != 0) { 901313bdea8SRichard Henderson for (int i = cum.info_in_idx - 1; i >= 0; --i) { 902313bdea8SRichard Henderson TCGCallArgumentLoc *loc = &info->in[i]; 903313bdea8SRichard Henderson switch (loc->kind) { 904313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF: 905313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF_N: 906313bdea8SRichard Henderson loc->ref_slot += ref_base; 907313bdea8SRichard Henderson break; 908313bdea8SRichard Henderson default: 909313bdea8SRichard Henderson break; 910313bdea8SRichard Henderson } 911313bdea8SRichard Henderson } 912313bdea8SRichard Henderson } 913313bdea8SRichard Henderson } 91439004a71SRichard Henderson } 91539004a71SRichard Henderson 91691478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)]; 917f69d277eSRichard Henderson static void process_op_defs(TCGContext *s); 9181c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type, 9191c2adb95SRichard Henderson TCGReg reg, const char *name); 92091478cefSRichard Henderson 92143b972b7SRichard Henderson static void tcg_context_init(unsigned max_cpus) 922c896fe29Sbellard { 923a76aabd3SRichard Henderson TCGContext *s = &tcg_init_ctx; 924100b5e01SRichard Henderson int op, total_args, n, i; 925c896fe29Sbellard TCGOpDef *def; 926c896fe29Sbellard TCGArgConstraint *args_ct; 9271c2adb95SRichard Henderson TCGTemp *ts; 928c896fe29Sbellard 929c896fe29Sbellard memset(s, 0, sizeof(*s)); 930c896fe29Sbellard s->nb_globals = 0; 931c896fe29Sbellard 932c896fe29Sbellard /* Count total number of arguments and allocate the corresponding 933c896fe29Sbellard space */ 934c896fe29Sbellard total_args = 0; 935c896fe29Sbellard for(op = 0; op < NB_OPS; op++) { 936c896fe29Sbellard def = &tcg_op_defs[op]; 937c896fe29Sbellard n = def->nb_iargs + def->nb_oargs; 938c896fe29Sbellard total_args += n; 939c896fe29Sbellard } 940c896fe29Sbellard 941bc2b17e6SRichard Henderson args_ct = g_new0(TCGArgConstraint, total_args); 942c896fe29Sbellard 943c896fe29Sbellard for(op = 0; op < NB_OPS; op++) { 944c896fe29Sbellard def = &tcg_op_defs[op]; 945c896fe29Sbellard def->args_ct = args_ct; 946c896fe29Sbellard n = def->nb_iargs + def->nb_oargs; 947c896fe29Sbellard args_ct += n; 948c896fe29Sbellard } 949c896fe29Sbellard 9505cd8f621SRichard Henderson /* Register helpers. */ 95184fd9dd3SRichard Henderson /* Use g_direct_hash/equal for direct pointer comparisons on func. */ 952619205fdSEmilio G. Cota helper_table = g_hash_table_new(NULL, NULL); 95384fd9dd3SRichard Henderson 954100b5e01SRichard Henderson for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) { 95539004a71SRichard Henderson init_call_layout(&all_helpers[i]); 95684fd9dd3SRichard Henderson g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func, 95772866e82SRichard Henderson (gpointer)&all_helpers[i]); 958100b5e01SRichard Henderson } 9595cd8f621SRichard Henderson 96022f15579SRichard Henderson #ifdef CONFIG_TCG_INTERPRETER 9610c22e176SPhilippe Mathieu-Daudé init_ffi_layouts(); 96222f15579SRichard Henderson #endif 96322f15579SRichard Henderson 964c896fe29Sbellard tcg_target_init(s); 965f69d277eSRichard Henderson process_op_defs(s); 96691478cefSRichard Henderson 96791478cefSRichard Henderson /* Reverse the order of the saved registers, assuming they're all at 96891478cefSRichard Henderson the start of tcg_target_reg_alloc_order. */ 96991478cefSRichard Henderson for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) { 97091478cefSRichard Henderson int r = tcg_target_reg_alloc_order[n]; 97191478cefSRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) { 97291478cefSRichard Henderson break; 97391478cefSRichard Henderson } 97491478cefSRichard Henderson } 97591478cefSRichard Henderson for (i = 0; i < n; ++i) { 97691478cefSRichard Henderson indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i]; 97791478cefSRichard Henderson } 97891478cefSRichard Henderson for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) { 97991478cefSRichard Henderson indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i]; 98091478cefSRichard Henderson } 981b1311c4aSEmilio G. Cota 98238b47b19SEmilio G. Cota alloc_tcg_plugin_context(s); 98338b47b19SEmilio G. Cota 984b1311c4aSEmilio G. Cota tcg_ctx = s; 9853468b59eSEmilio G. Cota /* 9863468b59eSEmilio G. Cota * In user-mode we simply share the init context among threads, since we 9873468b59eSEmilio G. Cota * use a single region. See the documentation tcg_region_init() for the 9883468b59eSEmilio G. Cota * reasoning behind this. 9893468b59eSEmilio G. Cota * In softmmu we will have at most max_cpus TCG threads. 9903468b59eSEmilio G. Cota */ 9913468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY 992df2cce29SEmilio G. Cota tcg_ctxs = &tcg_ctx; 9930e2d61cfSRichard Henderson tcg_cur_ctxs = 1; 9940e2d61cfSRichard Henderson tcg_max_ctxs = 1; 9953468b59eSEmilio G. Cota #else 9960e2d61cfSRichard Henderson tcg_max_ctxs = max_cpus; 9970e2d61cfSRichard Henderson tcg_ctxs = g_new0(TCGContext *, max_cpus); 9983468b59eSEmilio G. Cota #endif 9991c2adb95SRichard Henderson 10001c2adb95SRichard Henderson tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0)); 10011c2adb95SRichard Henderson ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env"); 10021c2adb95SRichard Henderson cpu_env = temp_tcgv_ptr(ts); 10039002ec79SRichard Henderson } 1004b03cce8eSbellard 100543b972b7SRichard Henderson void tcg_init(size_t tb_size, int splitwx, unsigned max_cpus) 1006a76aabd3SRichard Henderson { 100743b972b7SRichard Henderson tcg_context_init(max_cpus); 100843b972b7SRichard Henderson tcg_region_init(tb_size, splitwx, max_cpus); 1009a76aabd3SRichard Henderson } 1010a76aabd3SRichard Henderson 10116e3b2bfdSEmilio G. Cota /* 10126e3b2bfdSEmilio G. Cota * Allocate TBs right before their corresponding translated code, making 10136e3b2bfdSEmilio G. Cota * sure that TBs and code are on different cache lines. 10146e3b2bfdSEmilio G. Cota */ 10156e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s) 10166e3b2bfdSEmilio G. Cota { 10176e3b2bfdSEmilio G. Cota uintptr_t align = qemu_icache_linesize; 10186e3b2bfdSEmilio G. Cota TranslationBlock *tb; 10196e3b2bfdSEmilio G. Cota void *next; 10206e3b2bfdSEmilio G. Cota 1021e8feb96fSEmilio G. Cota retry: 10226e3b2bfdSEmilio G. Cota tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align); 10236e3b2bfdSEmilio G. Cota next = (void *)ROUND_UP((uintptr_t)(tb + 1), align); 10246e3b2bfdSEmilio G. Cota 10256e3b2bfdSEmilio G. Cota if (unlikely(next > s->code_gen_highwater)) { 1026e8feb96fSEmilio G. Cota if (tcg_region_alloc(s)) { 10276e3b2bfdSEmilio G. Cota return NULL; 10286e3b2bfdSEmilio G. Cota } 1029e8feb96fSEmilio G. Cota goto retry; 1030e8feb96fSEmilio G. Cota } 1031d73415a3SStefan Hajnoczi qatomic_set(&s->code_gen_ptr, next); 103257a26946SRichard Henderson s->data_gen_ptr = NULL; 10336e3b2bfdSEmilio G. Cota return tb; 10346e3b2bfdSEmilio G. Cota } 10356e3b2bfdSEmilio G. Cota 10369002ec79SRichard Henderson void tcg_prologue_init(TCGContext *s) 10379002ec79SRichard Henderson { 1038b0a0794aSRichard Henderson size_t prologue_size; 10398163b749SRichard Henderson 1040b0a0794aSRichard Henderson s->code_ptr = s->code_gen_ptr; 1041b0a0794aSRichard Henderson s->code_buf = s->code_gen_ptr; 10425b38ee31SRichard Henderson s->data_gen_ptr = NULL; 1043b91ccb31SRichard Henderson 1044b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 1045b0a0794aSRichard Henderson tcg_qemu_tb_exec = (tcg_prologue_fn *)tcg_splitwx_to_rx(s->code_ptr); 1046b91ccb31SRichard Henderson #endif 10478163b749SRichard Henderson 10485b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 10495b38ee31SRichard Henderson s->pool_labels = NULL; 10505b38ee31SRichard Henderson #endif 10515b38ee31SRichard Henderson 1052653b87ebSRoman Bolshakov qemu_thread_jit_write(); 10538163b749SRichard Henderson /* Generate the prologue. */ 1054b03cce8eSbellard tcg_target_qemu_prologue(s); 10555b38ee31SRichard Henderson 10565b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 10575b38ee31SRichard Henderson /* Allow the prologue to put e.g. guest_base into a pool entry. */ 10585b38ee31SRichard Henderson { 10591768987bSRichard Henderson int result = tcg_out_pool_finalize(s); 10601768987bSRichard Henderson tcg_debug_assert(result == 0); 10615b38ee31SRichard Henderson } 10625b38ee31SRichard Henderson #endif 10635b38ee31SRichard Henderson 1064b0a0794aSRichard Henderson prologue_size = tcg_current_code_size(s); 10655584e2dbSIlya Leoshkevich perf_report_prologue(s->code_gen_ptr, prologue_size); 1066b0a0794aSRichard Henderson 1067df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 1068b0a0794aSRichard Henderson flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf), 1069b0a0794aSRichard Henderson (uintptr_t)s->code_buf, prologue_size); 1070df5d2b16SRichard Henderson #endif 10718163b749SRichard Henderson 1072d6b64b2bSRichard Henderson #ifdef DEBUG_DISAS 1073d6b64b2bSRichard Henderson if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) { 1074c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock(); 107578b54858SRichard Henderson if (logfile) { 107678b54858SRichard Henderson fprintf(logfile, "PROLOGUE: [size=%zu]\n", prologue_size); 10775b38ee31SRichard Henderson if (s->data_gen_ptr) { 1078b0a0794aSRichard Henderson size_t code_size = s->data_gen_ptr - s->code_gen_ptr; 10795b38ee31SRichard Henderson size_t data_size = prologue_size - code_size; 10805b38ee31SRichard Henderson size_t i; 10815b38ee31SRichard Henderson 108278b54858SRichard Henderson disas(logfile, s->code_gen_ptr, code_size); 10835b38ee31SRichard Henderson 10845b38ee31SRichard Henderson for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) { 10855b38ee31SRichard Henderson if (sizeof(tcg_target_ulong) == 8) { 108678b54858SRichard Henderson fprintf(logfile, 108778b54858SRichard Henderson "0x%08" PRIxPTR ": .quad 0x%016" PRIx64 "\n", 10885b38ee31SRichard Henderson (uintptr_t)s->data_gen_ptr + i, 10895b38ee31SRichard Henderson *(uint64_t *)(s->data_gen_ptr + i)); 10905b38ee31SRichard Henderson } else { 109178b54858SRichard Henderson fprintf(logfile, 109278b54858SRichard Henderson "0x%08" PRIxPTR ": .long 0x%08x\n", 10935b38ee31SRichard Henderson (uintptr_t)s->data_gen_ptr + i, 10945b38ee31SRichard Henderson *(uint32_t *)(s->data_gen_ptr + i)); 10955b38ee31SRichard Henderson } 10965b38ee31SRichard Henderson } 10975b38ee31SRichard Henderson } else { 109878b54858SRichard Henderson disas(logfile, s->code_gen_ptr, prologue_size); 10995b38ee31SRichard Henderson } 110078b54858SRichard Henderson fprintf(logfile, "\n"); 1101fc59d2d8SRobert Foley qemu_log_unlock(logfile); 1102d6b64b2bSRichard Henderson } 110378b54858SRichard Henderson } 1104d6b64b2bSRichard Henderson #endif 1105cedbcb01SEmilio G. Cota 11066eea0434SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 11076eea0434SRichard Henderson /* 11086eea0434SRichard Henderson * Assert that goto_ptr is implemented completely, setting an epilogue. 11096eea0434SRichard Henderson * For tci, we use NULL as the signal to return from the interpreter, 11106eea0434SRichard Henderson * so skip this check. 11116eea0434SRichard Henderson */ 11128b5c2b62SRichard Henderson tcg_debug_assert(tcg_code_gen_epilogue != NULL); 11136eea0434SRichard Henderson #endif 1114d1c74ab3SRichard Henderson 1115d1c74ab3SRichard Henderson tcg_region_prologue_set(s); 1116c896fe29Sbellard } 1117c896fe29Sbellard 1118c896fe29Sbellard void tcg_func_start(TCGContext *s) 1119c896fe29Sbellard { 1120c896fe29Sbellard tcg_pool_reset(s); 1121c896fe29Sbellard s->nb_temps = s->nb_globals; 11220ec9eabcSRichard Henderson 11230ec9eabcSRichard Henderson /* No temps have been previously allocated for size or locality. */ 11240ec9eabcSRichard Henderson memset(s->free_temps, 0, sizeof(s->free_temps)); 11250ec9eabcSRichard Henderson 1126c0522136SRichard Henderson /* No constant temps have been previously allocated. */ 1127c0522136SRichard Henderson for (int i = 0; i < TCG_TYPE_COUNT; ++i) { 1128c0522136SRichard Henderson if (s->const_table[i]) { 1129c0522136SRichard Henderson g_hash_table_remove_all(s->const_table[i]); 1130c0522136SRichard Henderson } 1131c0522136SRichard Henderson } 1132c0522136SRichard Henderson 1133abebf925SRichard Henderson s->nb_ops = 0; 1134c896fe29Sbellard s->nb_labels = 0; 1135c896fe29Sbellard s->current_frame_offset = s->frame_start; 1136c896fe29Sbellard 11370a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG 11380a209d4bSRichard Henderson s->goto_tb_issue_mask = 0; 11390a209d4bSRichard Henderson #endif 11400a209d4bSRichard Henderson 114115fa08f8SRichard Henderson QTAILQ_INIT(&s->ops); 114215fa08f8SRichard Henderson QTAILQ_INIT(&s->free_ops); 1143bef16ab4SRichard Henderson QSIMPLEQ_INIT(&s->labels); 1144c896fe29Sbellard } 1145c896fe29Sbellard 1146ae30e866SRichard Henderson static TCGTemp *tcg_temp_alloc(TCGContext *s) 11477ca4b752SRichard Henderson { 11487ca4b752SRichard Henderson int n = s->nb_temps++; 1149ae30e866SRichard Henderson 1150ae30e866SRichard Henderson if (n >= TCG_MAX_TEMPS) { 1151db6b7d0cSRichard Henderson tcg_raise_tb_overflow(s); 1152ae30e866SRichard Henderson } 11537ca4b752SRichard Henderson return memset(&s->temps[n], 0, sizeof(TCGTemp)); 11547ca4b752SRichard Henderson } 11557ca4b752SRichard Henderson 1156ae30e866SRichard Henderson static TCGTemp *tcg_global_alloc(TCGContext *s) 11577ca4b752SRichard Henderson { 1158fa477d25SRichard Henderson TCGTemp *ts; 1159fa477d25SRichard Henderson 11607ca4b752SRichard Henderson tcg_debug_assert(s->nb_globals == s->nb_temps); 1161ae30e866SRichard Henderson tcg_debug_assert(s->nb_globals < TCG_MAX_TEMPS); 11627ca4b752SRichard Henderson s->nb_globals++; 1163fa477d25SRichard Henderson ts = tcg_temp_alloc(s); 1164ee17db83SRichard Henderson ts->kind = TEMP_GLOBAL; 1165fa477d25SRichard Henderson 1166fa477d25SRichard Henderson return ts; 1167c896fe29Sbellard } 1168c896fe29Sbellard 1169085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type, 1170b6638662SRichard Henderson TCGReg reg, const char *name) 1171c896fe29Sbellard { 1172c896fe29Sbellard TCGTemp *ts; 1173c896fe29Sbellard 1174b3a62939SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type != TCG_TYPE_I32) { 1175c896fe29Sbellard tcg_abort(); 1176b3a62939SRichard Henderson } 11777ca4b752SRichard Henderson 11787ca4b752SRichard Henderson ts = tcg_global_alloc(s); 1179c896fe29Sbellard ts->base_type = type; 1180c896fe29Sbellard ts->type = type; 1181ee17db83SRichard Henderson ts->kind = TEMP_FIXED; 1182c896fe29Sbellard ts->reg = reg; 1183c896fe29Sbellard ts->name = name; 1184c896fe29Sbellard tcg_regset_set_reg(s->reserved_regs, reg); 11857ca4b752SRichard Henderson 1186085272b3SRichard Henderson return ts; 1187a7812ae4Spbrook } 1188a7812ae4Spbrook 1189b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size) 1190a7812ae4Spbrook { 1191b3a62939SRichard Henderson s->frame_start = start; 1192b3a62939SRichard Henderson s->frame_end = start + size; 1193085272b3SRichard Henderson s->frame_temp 1194085272b3SRichard Henderson = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame"); 1195b3a62939SRichard Henderson } 1196a7812ae4Spbrook 1197085272b3SRichard Henderson TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base, 1198e1ccc054SRichard Henderson intptr_t offset, const char *name) 1199c896fe29Sbellard { 1200b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1201dc41aa7dSRichard Henderson TCGTemp *base_ts = tcgv_ptr_temp(base); 12027ca4b752SRichard Henderson TCGTemp *ts = tcg_global_alloc(s); 1203aef85402SRichard Henderson int indirect_reg = 0; 1204c896fe29Sbellard 1205c0522136SRichard Henderson switch (base_ts->kind) { 1206c0522136SRichard Henderson case TEMP_FIXED: 1207c0522136SRichard Henderson break; 1208c0522136SRichard Henderson case TEMP_GLOBAL: 12095a18407fSRichard Henderson /* We do not support double-indirect registers. */ 12105a18407fSRichard Henderson tcg_debug_assert(!base_ts->indirect_reg); 1211b3915dbbSRichard Henderson base_ts->indirect_base = 1; 12125a18407fSRichard Henderson s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64 12135a18407fSRichard Henderson ? 2 : 1); 12145a18407fSRichard Henderson indirect_reg = 1; 1215c0522136SRichard Henderson break; 1216c0522136SRichard Henderson default: 1217c0522136SRichard Henderson g_assert_not_reached(); 1218b3915dbbSRichard Henderson } 1219b3915dbbSRichard Henderson 12207ca4b752SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { 12217ca4b752SRichard Henderson TCGTemp *ts2 = tcg_global_alloc(s); 1222c896fe29Sbellard char buf[64]; 12237ca4b752SRichard Henderson 12247ca4b752SRichard Henderson ts->base_type = TCG_TYPE_I64; 1225c896fe29Sbellard ts->type = TCG_TYPE_I32; 1226b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg; 1227c896fe29Sbellard ts->mem_allocated = 1; 1228b3a62939SRichard Henderson ts->mem_base = base_ts; 1229aef85402SRichard Henderson ts->mem_offset = offset; 1230c896fe29Sbellard pstrcpy(buf, sizeof(buf), name); 1231c896fe29Sbellard pstrcat(buf, sizeof(buf), "_0"); 1232c896fe29Sbellard ts->name = strdup(buf); 1233c896fe29Sbellard 12347ca4b752SRichard Henderson tcg_debug_assert(ts2 == ts + 1); 12357ca4b752SRichard Henderson ts2->base_type = TCG_TYPE_I64; 12367ca4b752SRichard Henderson ts2->type = TCG_TYPE_I32; 1237b3915dbbSRichard Henderson ts2->indirect_reg = indirect_reg; 12387ca4b752SRichard Henderson ts2->mem_allocated = 1; 12397ca4b752SRichard Henderson ts2->mem_base = base_ts; 1240aef85402SRichard Henderson ts2->mem_offset = offset + 4; 1241fac87bd2SRichard Henderson ts2->temp_subindex = 1; 1242c896fe29Sbellard pstrcpy(buf, sizeof(buf), name); 1243c896fe29Sbellard pstrcat(buf, sizeof(buf), "_1"); 1244120c1084SRichard Henderson ts2->name = strdup(buf); 12457ca4b752SRichard Henderson } else { 1246c896fe29Sbellard ts->base_type = type; 1247c896fe29Sbellard ts->type = type; 1248b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg; 1249c896fe29Sbellard ts->mem_allocated = 1; 1250b3a62939SRichard Henderson ts->mem_base = base_ts; 1251c896fe29Sbellard ts->mem_offset = offset; 1252c896fe29Sbellard ts->name = name; 1253c896fe29Sbellard } 1254085272b3SRichard Henderson return ts; 1255c896fe29Sbellard } 1256c896fe29Sbellard 12575bfa8034SRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, bool temp_local) 1258c896fe29Sbellard { 1259b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1260f57c6915SRichard Henderson TCGTempKind kind = temp_local ? TEMP_TB : TEMP_NORMAL; 1261c896fe29Sbellard TCGTemp *ts; 1262641d5fbeSbellard int idx, k; 1263c896fe29Sbellard 12640ec9eabcSRichard Henderson k = type + (temp_local ? TCG_TYPE_COUNT : 0); 12650ec9eabcSRichard Henderson idx = find_first_bit(s->free_temps[k].l, TCG_MAX_TEMPS); 12660ec9eabcSRichard Henderson if (idx < TCG_MAX_TEMPS) { 12670ec9eabcSRichard Henderson /* There is already an available temp with the right type. */ 12680ec9eabcSRichard Henderson clear_bit(idx, s->free_temps[k].l); 12690ec9eabcSRichard Henderson 1270e8996ee0Sbellard ts = &s->temps[idx]; 1271e8996ee0Sbellard ts->temp_allocated = 1; 12727ca4b752SRichard Henderson tcg_debug_assert(ts->base_type == type); 1273ee17db83SRichard Henderson tcg_debug_assert(ts->kind == kind); 1274e8996ee0Sbellard } else { 127543eef72fSRichard Henderson int i, n; 127643eef72fSRichard Henderson 127743eef72fSRichard Henderson switch (type) { 127843eef72fSRichard Henderson case TCG_TYPE_I32: 127943eef72fSRichard Henderson case TCG_TYPE_V64: 128043eef72fSRichard Henderson case TCG_TYPE_V128: 128143eef72fSRichard Henderson case TCG_TYPE_V256: 128243eef72fSRichard Henderson n = 1; 128343eef72fSRichard Henderson break; 128443eef72fSRichard Henderson case TCG_TYPE_I64: 128543eef72fSRichard Henderson n = 64 / TCG_TARGET_REG_BITS; 128643eef72fSRichard Henderson break; 128743eef72fSRichard Henderson case TCG_TYPE_I128: 128843eef72fSRichard Henderson n = 128 / TCG_TARGET_REG_BITS; 128943eef72fSRichard Henderson break; 129043eef72fSRichard Henderson default: 129143eef72fSRichard Henderson g_assert_not_reached(); 129243eef72fSRichard Henderson } 129343eef72fSRichard Henderson 12947ca4b752SRichard Henderson ts = tcg_temp_alloc(s); 129543eef72fSRichard Henderson ts->base_type = type; 129643eef72fSRichard Henderson ts->temp_allocated = 1; 129743eef72fSRichard Henderson ts->kind = kind; 129843eef72fSRichard Henderson 129943eef72fSRichard Henderson if (n == 1) { 130043eef72fSRichard Henderson ts->type = type; 130143eef72fSRichard Henderson } else { 130243eef72fSRichard Henderson ts->type = TCG_TYPE_REG; 130343eef72fSRichard Henderson 130443eef72fSRichard Henderson for (i = 1; i < n; ++i) { 13057ca4b752SRichard Henderson TCGTemp *ts2 = tcg_temp_alloc(s); 13067ca4b752SRichard Henderson 130743eef72fSRichard Henderson tcg_debug_assert(ts2 == ts + i); 130843eef72fSRichard Henderson ts2->base_type = type; 130943eef72fSRichard Henderson ts2->type = TCG_TYPE_REG; 13107ca4b752SRichard Henderson ts2->temp_allocated = 1; 131143eef72fSRichard Henderson ts2->temp_subindex = i; 1312ee17db83SRichard Henderson ts2->kind = kind; 131343eef72fSRichard Henderson } 1314c896fe29Sbellard } 1315e8996ee0Sbellard } 131627bfd83cSPeter Maydell 131727bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG) 131827bfd83cSPeter Maydell s->temps_in_use++; 131927bfd83cSPeter Maydell #endif 1320085272b3SRichard Henderson return ts; 1321c896fe29Sbellard } 1322c896fe29Sbellard 1323d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type) 1324d2fd745fSRichard Henderson { 1325d2fd745fSRichard Henderson TCGTemp *t; 1326d2fd745fSRichard Henderson 1327d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG 1328d2fd745fSRichard Henderson switch (type) { 1329d2fd745fSRichard Henderson case TCG_TYPE_V64: 1330d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v64); 1331d2fd745fSRichard Henderson break; 1332d2fd745fSRichard Henderson case TCG_TYPE_V128: 1333d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v128); 1334d2fd745fSRichard Henderson break; 1335d2fd745fSRichard Henderson case TCG_TYPE_V256: 1336d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v256); 1337d2fd745fSRichard Henderson break; 1338d2fd745fSRichard Henderson default: 1339d2fd745fSRichard Henderson g_assert_not_reached(); 1340d2fd745fSRichard Henderson } 1341d2fd745fSRichard Henderson #endif 1342d2fd745fSRichard Henderson 1343d2fd745fSRichard Henderson t = tcg_temp_new_internal(type, 0); 1344d2fd745fSRichard Henderson return temp_tcgv_vec(t); 1345d2fd745fSRichard Henderson } 1346d2fd745fSRichard Henderson 1347d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp. */ 1348d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match) 1349d2fd745fSRichard Henderson { 1350d2fd745fSRichard Henderson TCGTemp *t = tcgv_vec_temp(match); 1351d2fd745fSRichard Henderson 1352d2fd745fSRichard Henderson tcg_debug_assert(t->temp_allocated != 0); 1353d2fd745fSRichard Henderson 1354d2fd745fSRichard Henderson t = tcg_temp_new_internal(t->base_type, 0); 1355d2fd745fSRichard Henderson return temp_tcgv_vec(t); 1356d2fd745fSRichard Henderson } 1357d2fd745fSRichard Henderson 13585bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts) 1359c896fe29Sbellard { 1360b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1361085272b3SRichard Henderson int k, idx; 1362c896fe29Sbellard 1363c7482438SRichard Henderson switch (ts->kind) { 1364c7482438SRichard Henderson case TEMP_CONST: 1365c7482438SRichard Henderson /* 1366c7482438SRichard Henderson * In order to simplify users of tcg_constant_*, 1367c7482438SRichard Henderson * silently ignore free. 1368c7482438SRichard Henderson */ 1369c0522136SRichard Henderson return; 1370c7482438SRichard Henderson case TEMP_NORMAL: 1371f57c6915SRichard Henderson case TEMP_TB: 1372c7482438SRichard Henderson break; 1373c7482438SRichard Henderson default: 1374c7482438SRichard Henderson g_assert_not_reached(); 1375c0522136SRichard Henderson } 1376c0522136SRichard Henderson 1377eabb7b91SAurelien Jarno tcg_debug_assert(ts->temp_allocated != 0); 1378e8996ee0Sbellard ts->temp_allocated = 0; 13790ec9eabcSRichard Henderson 13800ef3d704SRichard Henderson #if defined(CONFIG_DEBUG_TCG) 13810ef3d704SRichard Henderson assert(s->temps_in_use > 0); 13820ef3d704SRichard Henderson s->temps_in_use--; 13830ef3d704SRichard Henderson #endif 13840ef3d704SRichard Henderson 1385085272b3SRichard Henderson idx = temp_idx(ts); 1386ee17db83SRichard Henderson k = ts->base_type + (ts->kind == TEMP_NORMAL ? 0 : TCG_TYPE_COUNT); 13870ec9eabcSRichard Henderson set_bit(idx, s->free_temps[k].l); 1388e8996ee0Sbellard } 1389e8996ee0Sbellard 1390c0522136SRichard Henderson TCGTemp *tcg_constant_internal(TCGType type, int64_t val) 1391c0522136SRichard Henderson { 1392c0522136SRichard Henderson TCGContext *s = tcg_ctx; 1393c0522136SRichard Henderson GHashTable *h = s->const_table[type]; 1394c0522136SRichard Henderson TCGTemp *ts; 1395c0522136SRichard Henderson 1396c0522136SRichard Henderson if (h == NULL) { 1397c0522136SRichard Henderson h = g_hash_table_new(g_int64_hash, g_int64_equal); 1398c0522136SRichard Henderson s->const_table[type] = h; 1399c0522136SRichard Henderson } 1400c0522136SRichard Henderson 1401c0522136SRichard Henderson ts = g_hash_table_lookup(h, &val); 1402c0522136SRichard Henderson if (ts == NULL) { 1403aef85402SRichard Henderson int64_t *val_ptr; 1404aef85402SRichard Henderson 1405c0522136SRichard Henderson ts = tcg_temp_alloc(s); 1406c0522136SRichard Henderson 1407c0522136SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { 1408c0522136SRichard Henderson TCGTemp *ts2 = tcg_temp_alloc(s); 1409c0522136SRichard Henderson 1410aef85402SRichard Henderson tcg_debug_assert(ts2 == ts + 1); 1411aef85402SRichard Henderson 1412c0522136SRichard Henderson ts->base_type = TCG_TYPE_I64; 1413c0522136SRichard Henderson ts->type = TCG_TYPE_I32; 1414c0522136SRichard Henderson ts->kind = TEMP_CONST; 1415c0522136SRichard Henderson ts->temp_allocated = 1; 1416c0522136SRichard Henderson 1417c0522136SRichard Henderson ts2->base_type = TCG_TYPE_I64; 1418c0522136SRichard Henderson ts2->type = TCG_TYPE_I32; 1419c0522136SRichard Henderson ts2->kind = TEMP_CONST; 1420c0522136SRichard Henderson ts2->temp_allocated = 1; 1421fac87bd2SRichard Henderson ts2->temp_subindex = 1; 1422aef85402SRichard Henderson 1423aef85402SRichard Henderson /* 1424aef85402SRichard Henderson * Retain the full value of the 64-bit constant in the low 1425aef85402SRichard Henderson * part, so that the hash table works. Actual uses will 1426aef85402SRichard Henderson * truncate the value to the low part. 1427aef85402SRichard Henderson */ 1428aef85402SRichard Henderson ts[HOST_BIG_ENDIAN].val = val; 1429aef85402SRichard Henderson ts[!HOST_BIG_ENDIAN].val = val >> 32; 1430aef85402SRichard Henderson val_ptr = &ts[HOST_BIG_ENDIAN].val; 1431c0522136SRichard Henderson } else { 1432c0522136SRichard Henderson ts->base_type = type; 1433c0522136SRichard Henderson ts->type = type; 1434c0522136SRichard Henderson ts->kind = TEMP_CONST; 1435c0522136SRichard Henderson ts->temp_allocated = 1; 1436c0522136SRichard Henderson ts->val = val; 1437aef85402SRichard Henderson val_ptr = &ts->val; 1438c0522136SRichard Henderson } 1439aef85402SRichard Henderson g_hash_table_insert(h, val_ptr, ts); 1440c0522136SRichard Henderson } 1441c0522136SRichard Henderson 1442c0522136SRichard Henderson return ts; 1443c0522136SRichard Henderson } 1444c0522136SRichard Henderson 1445c0522136SRichard Henderson TCGv_vec tcg_constant_vec(TCGType type, unsigned vece, int64_t val) 1446c0522136SRichard Henderson { 1447c0522136SRichard Henderson val = dup_const(vece, val); 1448c0522136SRichard Henderson return temp_tcgv_vec(tcg_constant_internal(type, val)); 1449c0522136SRichard Henderson } 1450c0522136SRichard Henderson 145188d4005bSRichard Henderson TCGv_vec tcg_constant_vec_matching(TCGv_vec match, unsigned vece, int64_t val) 145288d4005bSRichard Henderson { 145388d4005bSRichard Henderson TCGTemp *t = tcgv_vec_temp(match); 145488d4005bSRichard Henderson 145588d4005bSRichard Henderson tcg_debug_assert(t->temp_allocated != 0); 145688d4005bSRichard Henderson return tcg_constant_vec(t->base_type, vece, val); 145788d4005bSRichard Henderson } 145888d4005bSRichard Henderson 1459a7812ae4Spbrook TCGv_i32 tcg_const_i32(int32_t val) 1460a7812ae4Spbrook { 1461a7812ae4Spbrook TCGv_i32 t0; 1462a7812ae4Spbrook t0 = tcg_temp_new_i32(); 1463e8996ee0Sbellard tcg_gen_movi_i32(t0, val); 1464e8996ee0Sbellard return t0; 1465c896fe29Sbellard } 1466c896fe29Sbellard 1467a7812ae4Spbrook TCGv_i64 tcg_const_i64(int64_t val) 1468c896fe29Sbellard { 1469a7812ae4Spbrook TCGv_i64 t0; 1470a7812ae4Spbrook t0 = tcg_temp_new_i64(); 1471e8996ee0Sbellard tcg_gen_movi_i64(t0, val); 1472e8996ee0Sbellard return t0; 1473c896fe29Sbellard } 1474c896fe29Sbellard 1475a7812ae4Spbrook TCGv_i32 tcg_const_local_i32(int32_t val) 1476bdffd4a9Saurel32 { 1477a7812ae4Spbrook TCGv_i32 t0; 1478a7812ae4Spbrook t0 = tcg_temp_local_new_i32(); 1479bdffd4a9Saurel32 tcg_gen_movi_i32(t0, val); 1480bdffd4a9Saurel32 return t0; 1481bdffd4a9Saurel32 } 1482bdffd4a9Saurel32 1483a7812ae4Spbrook TCGv_i64 tcg_const_local_i64(int64_t val) 1484bdffd4a9Saurel32 { 1485a7812ae4Spbrook TCGv_i64 t0; 1486a7812ae4Spbrook t0 = tcg_temp_local_new_i64(); 1487bdffd4a9Saurel32 tcg_gen_movi_i64(t0, val); 1488bdffd4a9Saurel32 return t0; 1489bdffd4a9Saurel32 } 1490bdffd4a9Saurel32 149127bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG) 149227bfd83cSPeter Maydell void tcg_clear_temp_count(void) 149327bfd83cSPeter Maydell { 1494b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 149527bfd83cSPeter Maydell s->temps_in_use = 0; 149627bfd83cSPeter Maydell } 149727bfd83cSPeter Maydell 149827bfd83cSPeter Maydell int tcg_check_temp_count(void) 149927bfd83cSPeter Maydell { 1500b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 150127bfd83cSPeter Maydell if (s->temps_in_use) { 150227bfd83cSPeter Maydell /* Clear the count so that we don't give another 150327bfd83cSPeter Maydell * warning immediately next time around. 150427bfd83cSPeter Maydell */ 150527bfd83cSPeter Maydell s->temps_in_use = 0; 150627bfd83cSPeter Maydell return 1; 150727bfd83cSPeter Maydell } 150827bfd83cSPeter Maydell return 0; 150927bfd83cSPeter Maydell } 151027bfd83cSPeter Maydell #endif 151127bfd83cSPeter Maydell 1512be0f34b5SRichard Henderson /* Return true if OP may appear in the opcode stream. 1513be0f34b5SRichard Henderson Test the runtime variable that controls each opcode. */ 1514be0f34b5SRichard Henderson bool tcg_op_supported(TCGOpcode op) 1515be0f34b5SRichard Henderson { 1516d2fd745fSRichard Henderson const bool have_vec 1517d2fd745fSRichard Henderson = TCG_TARGET_HAS_v64 | TCG_TARGET_HAS_v128 | TCG_TARGET_HAS_v256; 1518d2fd745fSRichard Henderson 1519be0f34b5SRichard Henderson switch (op) { 1520be0f34b5SRichard Henderson case INDEX_op_discard: 1521be0f34b5SRichard Henderson case INDEX_op_set_label: 1522be0f34b5SRichard Henderson case INDEX_op_call: 1523be0f34b5SRichard Henderson case INDEX_op_br: 1524be0f34b5SRichard Henderson case INDEX_op_mb: 1525be0f34b5SRichard Henderson case INDEX_op_insn_start: 1526be0f34b5SRichard Henderson case INDEX_op_exit_tb: 1527be0f34b5SRichard Henderson case INDEX_op_goto_tb: 1528f4e01e30SRichard Henderson case INDEX_op_goto_ptr: 1529be0f34b5SRichard Henderson case INDEX_op_qemu_ld_i32: 1530be0f34b5SRichard Henderson case INDEX_op_qemu_st_i32: 1531be0f34b5SRichard Henderson case INDEX_op_qemu_ld_i64: 1532be0f34b5SRichard Henderson case INDEX_op_qemu_st_i64: 1533be0f34b5SRichard Henderson return true; 1534be0f34b5SRichard Henderson 153507ce0b05SRichard Henderson case INDEX_op_qemu_st8_i32: 153607ce0b05SRichard Henderson return TCG_TARGET_HAS_qemu_st8_i32; 153707ce0b05SRichard Henderson 1538be0f34b5SRichard Henderson case INDEX_op_mov_i32: 1539be0f34b5SRichard Henderson case INDEX_op_setcond_i32: 1540be0f34b5SRichard Henderson case INDEX_op_brcond_i32: 1541be0f34b5SRichard Henderson case INDEX_op_ld8u_i32: 1542be0f34b5SRichard Henderson case INDEX_op_ld8s_i32: 1543be0f34b5SRichard Henderson case INDEX_op_ld16u_i32: 1544be0f34b5SRichard Henderson case INDEX_op_ld16s_i32: 1545be0f34b5SRichard Henderson case INDEX_op_ld_i32: 1546be0f34b5SRichard Henderson case INDEX_op_st8_i32: 1547be0f34b5SRichard Henderson case INDEX_op_st16_i32: 1548be0f34b5SRichard Henderson case INDEX_op_st_i32: 1549be0f34b5SRichard Henderson case INDEX_op_add_i32: 1550be0f34b5SRichard Henderson case INDEX_op_sub_i32: 1551be0f34b5SRichard Henderson case INDEX_op_mul_i32: 1552be0f34b5SRichard Henderson case INDEX_op_and_i32: 1553be0f34b5SRichard Henderson case INDEX_op_or_i32: 1554be0f34b5SRichard Henderson case INDEX_op_xor_i32: 1555be0f34b5SRichard Henderson case INDEX_op_shl_i32: 1556be0f34b5SRichard Henderson case INDEX_op_shr_i32: 1557be0f34b5SRichard Henderson case INDEX_op_sar_i32: 1558be0f34b5SRichard Henderson return true; 1559be0f34b5SRichard Henderson 1560be0f34b5SRichard Henderson case INDEX_op_movcond_i32: 1561be0f34b5SRichard Henderson return TCG_TARGET_HAS_movcond_i32; 1562be0f34b5SRichard Henderson case INDEX_op_div_i32: 1563be0f34b5SRichard Henderson case INDEX_op_divu_i32: 1564be0f34b5SRichard Henderson return TCG_TARGET_HAS_div_i32; 1565be0f34b5SRichard Henderson case INDEX_op_rem_i32: 1566be0f34b5SRichard Henderson case INDEX_op_remu_i32: 1567be0f34b5SRichard Henderson return TCG_TARGET_HAS_rem_i32; 1568be0f34b5SRichard Henderson case INDEX_op_div2_i32: 1569be0f34b5SRichard Henderson case INDEX_op_divu2_i32: 1570be0f34b5SRichard Henderson return TCG_TARGET_HAS_div2_i32; 1571be0f34b5SRichard Henderson case INDEX_op_rotl_i32: 1572be0f34b5SRichard Henderson case INDEX_op_rotr_i32: 1573be0f34b5SRichard Henderson return TCG_TARGET_HAS_rot_i32; 1574be0f34b5SRichard Henderson case INDEX_op_deposit_i32: 1575be0f34b5SRichard Henderson return TCG_TARGET_HAS_deposit_i32; 1576be0f34b5SRichard Henderson case INDEX_op_extract_i32: 1577be0f34b5SRichard Henderson return TCG_TARGET_HAS_extract_i32; 1578be0f34b5SRichard Henderson case INDEX_op_sextract_i32: 1579be0f34b5SRichard Henderson return TCG_TARGET_HAS_sextract_i32; 1580fce1296fSRichard Henderson case INDEX_op_extract2_i32: 1581fce1296fSRichard Henderson return TCG_TARGET_HAS_extract2_i32; 1582be0f34b5SRichard Henderson case INDEX_op_add2_i32: 1583be0f34b5SRichard Henderson return TCG_TARGET_HAS_add2_i32; 1584be0f34b5SRichard Henderson case INDEX_op_sub2_i32: 1585be0f34b5SRichard Henderson return TCG_TARGET_HAS_sub2_i32; 1586be0f34b5SRichard Henderson case INDEX_op_mulu2_i32: 1587be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulu2_i32; 1588be0f34b5SRichard Henderson case INDEX_op_muls2_i32: 1589be0f34b5SRichard Henderson return TCG_TARGET_HAS_muls2_i32; 1590be0f34b5SRichard Henderson case INDEX_op_muluh_i32: 1591be0f34b5SRichard Henderson return TCG_TARGET_HAS_muluh_i32; 1592be0f34b5SRichard Henderson case INDEX_op_mulsh_i32: 1593be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulsh_i32; 1594be0f34b5SRichard Henderson case INDEX_op_ext8s_i32: 1595be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8s_i32; 1596be0f34b5SRichard Henderson case INDEX_op_ext16s_i32: 1597be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16s_i32; 1598be0f34b5SRichard Henderson case INDEX_op_ext8u_i32: 1599be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8u_i32; 1600be0f34b5SRichard Henderson case INDEX_op_ext16u_i32: 1601be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16u_i32; 1602be0f34b5SRichard Henderson case INDEX_op_bswap16_i32: 1603be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap16_i32; 1604be0f34b5SRichard Henderson case INDEX_op_bswap32_i32: 1605be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap32_i32; 1606be0f34b5SRichard Henderson case INDEX_op_not_i32: 1607be0f34b5SRichard Henderson return TCG_TARGET_HAS_not_i32; 1608be0f34b5SRichard Henderson case INDEX_op_neg_i32: 1609be0f34b5SRichard Henderson return TCG_TARGET_HAS_neg_i32; 1610be0f34b5SRichard Henderson case INDEX_op_andc_i32: 1611be0f34b5SRichard Henderson return TCG_TARGET_HAS_andc_i32; 1612be0f34b5SRichard Henderson case INDEX_op_orc_i32: 1613be0f34b5SRichard Henderson return TCG_TARGET_HAS_orc_i32; 1614be0f34b5SRichard Henderson case INDEX_op_eqv_i32: 1615be0f34b5SRichard Henderson return TCG_TARGET_HAS_eqv_i32; 1616be0f34b5SRichard Henderson case INDEX_op_nand_i32: 1617be0f34b5SRichard Henderson return TCG_TARGET_HAS_nand_i32; 1618be0f34b5SRichard Henderson case INDEX_op_nor_i32: 1619be0f34b5SRichard Henderson return TCG_TARGET_HAS_nor_i32; 1620be0f34b5SRichard Henderson case INDEX_op_clz_i32: 1621be0f34b5SRichard Henderson return TCG_TARGET_HAS_clz_i32; 1622be0f34b5SRichard Henderson case INDEX_op_ctz_i32: 1623be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctz_i32; 1624be0f34b5SRichard Henderson case INDEX_op_ctpop_i32: 1625be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctpop_i32; 1626be0f34b5SRichard Henderson 1627be0f34b5SRichard Henderson case INDEX_op_brcond2_i32: 1628be0f34b5SRichard Henderson case INDEX_op_setcond2_i32: 1629be0f34b5SRichard Henderson return TCG_TARGET_REG_BITS == 32; 1630be0f34b5SRichard Henderson 1631be0f34b5SRichard Henderson case INDEX_op_mov_i64: 1632be0f34b5SRichard Henderson case INDEX_op_setcond_i64: 1633be0f34b5SRichard Henderson case INDEX_op_brcond_i64: 1634be0f34b5SRichard Henderson case INDEX_op_ld8u_i64: 1635be0f34b5SRichard Henderson case INDEX_op_ld8s_i64: 1636be0f34b5SRichard Henderson case INDEX_op_ld16u_i64: 1637be0f34b5SRichard Henderson case INDEX_op_ld16s_i64: 1638be0f34b5SRichard Henderson case INDEX_op_ld32u_i64: 1639be0f34b5SRichard Henderson case INDEX_op_ld32s_i64: 1640be0f34b5SRichard Henderson case INDEX_op_ld_i64: 1641be0f34b5SRichard Henderson case INDEX_op_st8_i64: 1642be0f34b5SRichard Henderson case INDEX_op_st16_i64: 1643be0f34b5SRichard Henderson case INDEX_op_st32_i64: 1644be0f34b5SRichard Henderson case INDEX_op_st_i64: 1645be0f34b5SRichard Henderson case INDEX_op_add_i64: 1646be0f34b5SRichard Henderson case INDEX_op_sub_i64: 1647be0f34b5SRichard Henderson case INDEX_op_mul_i64: 1648be0f34b5SRichard Henderson case INDEX_op_and_i64: 1649be0f34b5SRichard Henderson case INDEX_op_or_i64: 1650be0f34b5SRichard Henderson case INDEX_op_xor_i64: 1651be0f34b5SRichard Henderson case INDEX_op_shl_i64: 1652be0f34b5SRichard Henderson case INDEX_op_shr_i64: 1653be0f34b5SRichard Henderson case INDEX_op_sar_i64: 1654be0f34b5SRichard Henderson case INDEX_op_ext_i32_i64: 1655be0f34b5SRichard Henderson case INDEX_op_extu_i32_i64: 1656be0f34b5SRichard Henderson return TCG_TARGET_REG_BITS == 64; 1657be0f34b5SRichard Henderson 1658be0f34b5SRichard Henderson case INDEX_op_movcond_i64: 1659be0f34b5SRichard Henderson return TCG_TARGET_HAS_movcond_i64; 1660be0f34b5SRichard Henderson case INDEX_op_div_i64: 1661be0f34b5SRichard Henderson case INDEX_op_divu_i64: 1662be0f34b5SRichard Henderson return TCG_TARGET_HAS_div_i64; 1663be0f34b5SRichard Henderson case INDEX_op_rem_i64: 1664be0f34b5SRichard Henderson case INDEX_op_remu_i64: 1665be0f34b5SRichard Henderson return TCG_TARGET_HAS_rem_i64; 1666be0f34b5SRichard Henderson case INDEX_op_div2_i64: 1667be0f34b5SRichard Henderson case INDEX_op_divu2_i64: 1668be0f34b5SRichard Henderson return TCG_TARGET_HAS_div2_i64; 1669be0f34b5SRichard Henderson case INDEX_op_rotl_i64: 1670be0f34b5SRichard Henderson case INDEX_op_rotr_i64: 1671be0f34b5SRichard Henderson return TCG_TARGET_HAS_rot_i64; 1672be0f34b5SRichard Henderson case INDEX_op_deposit_i64: 1673be0f34b5SRichard Henderson return TCG_TARGET_HAS_deposit_i64; 1674be0f34b5SRichard Henderson case INDEX_op_extract_i64: 1675be0f34b5SRichard Henderson return TCG_TARGET_HAS_extract_i64; 1676be0f34b5SRichard Henderson case INDEX_op_sextract_i64: 1677be0f34b5SRichard Henderson return TCG_TARGET_HAS_sextract_i64; 1678fce1296fSRichard Henderson case INDEX_op_extract2_i64: 1679fce1296fSRichard Henderson return TCG_TARGET_HAS_extract2_i64; 1680be0f34b5SRichard Henderson case INDEX_op_extrl_i64_i32: 1681be0f34b5SRichard Henderson return TCG_TARGET_HAS_extrl_i64_i32; 1682be0f34b5SRichard Henderson case INDEX_op_extrh_i64_i32: 1683be0f34b5SRichard Henderson return TCG_TARGET_HAS_extrh_i64_i32; 1684be0f34b5SRichard Henderson case INDEX_op_ext8s_i64: 1685be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8s_i64; 1686be0f34b5SRichard Henderson case INDEX_op_ext16s_i64: 1687be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16s_i64; 1688be0f34b5SRichard Henderson case INDEX_op_ext32s_i64: 1689be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext32s_i64; 1690be0f34b5SRichard Henderson case INDEX_op_ext8u_i64: 1691be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8u_i64; 1692be0f34b5SRichard Henderson case INDEX_op_ext16u_i64: 1693be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16u_i64; 1694be0f34b5SRichard Henderson case INDEX_op_ext32u_i64: 1695be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext32u_i64; 1696be0f34b5SRichard Henderson case INDEX_op_bswap16_i64: 1697be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap16_i64; 1698be0f34b5SRichard Henderson case INDEX_op_bswap32_i64: 1699be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap32_i64; 1700be0f34b5SRichard Henderson case INDEX_op_bswap64_i64: 1701be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap64_i64; 1702be0f34b5SRichard Henderson case INDEX_op_not_i64: 1703be0f34b5SRichard Henderson return TCG_TARGET_HAS_not_i64; 1704be0f34b5SRichard Henderson case INDEX_op_neg_i64: 1705be0f34b5SRichard Henderson return TCG_TARGET_HAS_neg_i64; 1706be0f34b5SRichard Henderson case INDEX_op_andc_i64: 1707be0f34b5SRichard Henderson return TCG_TARGET_HAS_andc_i64; 1708be0f34b5SRichard Henderson case INDEX_op_orc_i64: 1709be0f34b5SRichard Henderson return TCG_TARGET_HAS_orc_i64; 1710be0f34b5SRichard Henderson case INDEX_op_eqv_i64: 1711be0f34b5SRichard Henderson return TCG_TARGET_HAS_eqv_i64; 1712be0f34b5SRichard Henderson case INDEX_op_nand_i64: 1713be0f34b5SRichard Henderson return TCG_TARGET_HAS_nand_i64; 1714be0f34b5SRichard Henderson case INDEX_op_nor_i64: 1715be0f34b5SRichard Henderson return TCG_TARGET_HAS_nor_i64; 1716be0f34b5SRichard Henderson case INDEX_op_clz_i64: 1717be0f34b5SRichard Henderson return TCG_TARGET_HAS_clz_i64; 1718be0f34b5SRichard Henderson case INDEX_op_ctz_i64: 1719be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctz_i64; 1720be0f34b5SRichard Henderson case INDEX_op_ctpop_i64: 1721be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctpop_i64; 1722be0f34b5SRichard Henderson case INDEX_op_add2_i64: 1723be0f34b5SRichard Henderson return TCG_TARGET_HAS_add2_i64; 1724be0f34b5SRichard Henderson case INDEX_op_sub2_i64: 1725be0f34b5SRichard Henderson return TCG_TARGET_HAS_sub2_i64; 1726be0f34b5SRichard Henderson case INDEX_op_mulu2_i64: 1727be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulu2_i64; 1728be0f34b5SRichard Henderson case INDEX_op_muls2_i64: 1729be0f34b5SRichard Henderson return TCG_TARGET_HAS_muls2_i64; 1730be0f34b5SRichard Henderson case INDEX_op_muluh_i64: 1731be0f34b5SRichard Henderson return TCG_TARGET_HAS_muluh_i64; 1732be0f34b5SRichard Henderson case INDEX_op_mulsh_i64: 1733be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulsh_i64; 1734be0f34b5SRichard Henderson 1735d2fd745fSRichard Henderson case INDEX_op_mov_vec: 1736d2fd745fSRichard Henderson case INDEX_op_dup_vec: 173737ee55a0SRichard Henderson case INDEX_op_dupm_vec: 1738d2fd745fSRichard Henderson case INDEX_op_ld_vec: 1739d2fd745fSRichard Henderson case INDEX_op_st_vec: 1740d2fd745fSRichard Henderson case INDEX_op_add_vec: 1741d2fd745fSRichard Henderson case INDEX_op_sub_vec: 1742d2fd745fSRichard Henderson case INDEX_op_and_vec: 1743d2fd745fSRichard Henderson case INDEX_op_or_vec: 1744d2fd745fSRichard Henderson case INDEX_op_xor_vec: 1745212be173SRichard Henderson case INDEX_op_cmp_vec: 1746d2fd745fSRichard Henderson return have_vec; 1747d2fd745fSRichard Henderson case INDEX_op_dup2_vec: 1748d2fd745fSRichard Henderson return have_vec && TCG_TARGET_REG_BITS == 32; 1749d2fd745fSRichard Henderson case INDEX_op_not_vec: 1750d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_not_vec; 1751d2fd745fSRichard Henderson case INDEX_op_neg_vec: 1752d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_neg_vec; 1753bcefc902SRichard Henderson case INDEX_op_abs_vec: 1754bcefc902SRichard Henderson return have_vec && TCG_TARGET_HAS_abs_vec; 1755d2fd745fSRichard Henderson case INDEX_op_andc_vec: 1756d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_andc_vec; 1757d2fd745fSRichard Henderson case INDEX_op_orc_vec: 1758d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_orc_vec; 1759ed523473SRichard Henderson case INDEX_op_nand_vec: 1760ed523473SRichard Henderson return have_vec && TCG_TARGET_HAS_nand_vec; 1761ed523473SRichard Henderson case INDEX_op_nor_vec: 1762ed523473SRichard Henderson return have_vec && TCG_TARGET_HAS_nor_vec; 1763ed523473SRichard Henderson case INDEX_op_eqv_vec: 1764ed523473SRichard Henderson return have_vec && TCG_TARGET_HAS_eqv_vec; 17653774030aSRichard Henderson case INDEX_op_mul_vec: 17663774030aSRichard Henderson return have_vec && TCG_TARGET_HAS_mul_vec; 1767d0ec9796SRichard Henderson case INDEX_op_shli_vec: 1768d0ec9796SRichard Henderson case INDEX_op_shri_vec: 1769d0ec9796SRichard Henderson case INDEX_op_sari_vec: 1770d0ec9796SRichard Henderson return have_vec && TCG_TARGET_HAS_shi_vec; 1771d0ec9796SRichard Henderson case INDEX_op_shls_vec: 1772d0ec9796SRichard Henderson case INDEX_op_shrs_vec: 1773d0ec9796SRichard Henderson case INDEX_op_sars_vec: 1774d0ec9796SRichard Henderson return have_vec && TCG_TARGET_HAS_shs_vec; 1775d0ec9796SRichard Henderson case INDEX_op_shlv_vec: 1776d0ec9796SRichard Henderson case INDEX_op_shrv_vec: 1777d0ec9796SRichard Henderson case INDEX_op_sarv_vec: 1778d0ec9796SRichard Henderson return have_vec && TCG_TARGET_HAS_shv_vec; 1779b0f7e744SRichard Henderson case INDEX_op_rotli_vec: 1780b0f7e744SRichard Henderson return have_vec && TCG_TARGET_HAS_roti_vec; 178123850a74SRichard Henderson case INDEX_op_rotls_vec: 178223850a74SRichard Henderson return have_vec && TCG_TARGET_HAS_rots_vec; 17835d0ceda9SRichard Henderson case INDEX_op_rotlv_vec: 17845d0ceda9SRichard Henderson case INDEX_op_rotrv_vec: 17855d0ceda9SRichard Henderson return have_vec && TCG_TARGET_HAS_rotv_vec; 17868afaf050SRichard Henderson case INDEX_op_ssadd_vec: 17878afaf050SRichard Henderson case INDEX_op_usadd_vec: 17888afaf050SRichard Henderson case INDEX_op_sssub_vec: 17898afaf050SRichard Henderson case INDEX_op_ussub_vec: 17908afaf050SRichard Henderson return have_vec && TCG_TARGET_HAS_sat_vec; 1791dd0a0fcdSRichard Henderson case INDEX_op_smin_vec: 1792dd0a0fcdSRichard Henderson case INDEX_op_umin_vec: 1793dd0a0fcdSRichard Henderson case INDEX_op_smax_vec: 1794dd0a0fcdSRichard Henderson case INDEX_op_umax_vec: 1795dd0a0fcdSRichard Henderson return have_vec && TCG_TARGET_HAS_minmax_vec; 179638dc1294SRichard Henderson case INDEX_op_bitsel_vec: 179738dc1294SRichard Henderson return have_vec && TCG_TARGET_HAS_bitsel_vec; 1798f75da298SRichard Henderson case INDEX_op_cmpsel_vec: 1799f75da298SRichard Henderson return have_vec && TCG_TARGET_HAS_cmpsel_vec; 1800d2fd745fSRichard Henderson 1801db432672SRichard Henderson default: 1802db432672SRichard Henderson tcg_debug_assert(op > INDEX_op_last_generic && op < NB_OPS); 1803db432672SRichard Henderson return true; 1804be0f34b5SRichard Henderson } 1805be0f34b5SRichard Henderson } 1806be0f34b5SRichard Henderson 180739004a71SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs); 180839004a71SRichard Henderson 1809ae8b75dcSRichard Henderson void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args) 1810c896fe29Sbellard { 18113e92aa34SRichard Henderson const TCGHelperInfo *info; 181239004a71SRichard Henderson TCGv_i64 extend_free[MAX_CALL_IARGS]; 181339004a71SRichard Henderson int n_extend = 0; 181475e8b9b7SRichard Henderson TCGOp *op; 181539004a71SRichard Henderson int i, n, pi = 0, total_args; 1816afb49896SRichard Henderson 1817619205fdSEmilio G. Cota info = g_hash_table_lookup(helper_table, (gpointer)func); 181839004a71SRichard Henderson total_args = info->nr_out + info->nr_in + 2; 181939004a71SRichard Henderson op = tcg_op_alloc(INDEX_op_call, total_args); 18202bece2c8SRichard Henderson 182138b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN 182217083f6fSEmilio Cota /* Flag helpers that may affect guest state */ 182317083f6fSEmilio Cota if (tcg_ctx->plugin_insn && 182417083f6fSEmilio Cota !(info->flags & TCG_CALL_PLUGIN) && 182517083f6fSEmilio Cota !(info->flags & TCG_CALL_NO_SIDE_EFFECTS)) { 182638b47b19SEmilio G. Cota tcg_ctx->plugin_insn->calls_helpers = true; 182738b47b19SEmilio G. Cota } 182838b47b19SEmilio G. Cota #endif 182938b47b19SEmilio G. Cota 183039004a71SRichard Henderson TCGOP_CALLO(op) = n = info->nr_out; 183139004a71SRichard Henderson switch (n) { 183239004a71SRichard Henderson case 0: 183339004a71SRichard Henderson tcg_debug_assert(ret == NULL); 183439004a71SRichard Henderson break; 183539004a71SRichard Henderson case 1: 183639004a71SRichard Henderson tcg_debug_assert(ret != NULL); 183739004a71SRichard Henderson op->args[pi++] = temp_arg(ret); 183839004a71SRichard Henderson break; 183939004a71SRichard Henderson case 2: 1840466d3759SRichard Henderson case 4: 184139004a71SRichard Henderson tcg_debug_assert(ret != NULL); 1842466d3759SRichard Henderson tcg_debug_assert(ret->base_type == ret->type + ctz32(n)); 184339004a71SRichard Henderson tcg_debug_assert(ret->temp_subindex == 0); 1844466d3759SRichard Henderson for (i = 0; i < n; ++i) { 1845466d3759SRichard Henderson op->args[pi++] = temp_arg(ret + i); 1846466d3759SRichard Henderson } 184739004a71SRichard Henderson break; 184839004a71SRichard Henderson default: 184939004a71SRichard Henderson g_assert_not_reached(); 185039004a71SRichard Henderson } 18517319d83aSRichard Henderson 185239004a71SRichard Henderson TCGOP_CALLI(op) = n = info->nr_in; 185339004a71SRichard Henderson for (i = 0; i < n; i++) { 185439004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i]; 185539004a71SRichard Henderson TCGTemp *ts = args[loc->arg_idx] + loc->tmp_subindex; 185639004a71SRichard Henderson 185739004a71SRichard Henderson switch (loc->kind) { 185839004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 1859313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF: 1860313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF_N: 186139004a71SRichard Henderson op->args[pi++] = temp_arg(ts); 186239004a71SRichard Henderson break; 186339004a71SRichard Henderson 186439004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 186539004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 186639004a71SRichard Henderson { 18672bece2c8SRichard Henderson TCGv_i64 temp = tcg_temp_new_i64(); 186839004a71SRichard Henderson TCGv_i32 orig = temp_tcgv_i32(ts); 186939004a71SRichard Henderson 187039004a71SRichard Henderson if (loc->kind == TCG_CALL_ARG_EXTEND_S) { 187118cf3d07SRichard Henderson tcg_gen_ext_i32_i64(temp, orig); 18722bece2c8SRichard Henderson } else { 187318cf3d07SRichard Henderson tcg_gen_extu_i32_i64(temp, orig); 18742bece2c8SRichard Henderson } 187539004a71SRichard Henderson op->args[pi++] = tcgv_i64_arg(temp); 187639004a71SRichard Henderson extend_free[n_extend++] = temp; 18772bece2c8SRichard Henderson } 187839004a71SRichard Henderson break; 18792bece2c8SRichard Henderson 1880e2a9dd6bSRichard Henderson default: 1881e2a9dd6bSRichard Henderson g_assert_not_reached(); 1882e2a9dd6bSRichard Henderson } 1883c896fe29Sbellard } 188475e8b9b7SRichard Henderson op->args[pi++] = (uintptr_t)func; 18853e92aa34SRichard Henderson op->args[pi++] = (uintptr_t)info; 188639004a71SRichard Henderson tcg_debug_assert(pi == total_args); 1887a7812ae4Spbrook 188839004a71SRichard Henderson QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link); 18892bece2c8SRichard Henderson 189039004a71SRichard Henderson tcg_debug_assert(n_extend < ARRAY_SIZE(extend_free)); 189139004a71SRichard Henderson for (i = 0; i < n_extend; ++i) { 189239004a71SRichard Henderson tcg_temp_free_i64(extend_free[i]); 1893eb8b0224SRichard Henderson } 1894a7812ae4Spbrook } 1895c896fe29Sbellard 18968fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s) 1897c896fe29Sbellard { 1898ac3b8891SRichard Henderson int i, n; 1899ac3b8891SRichard Henderson 1900ee17db83SRichard Henderson for (i = 0, n = s->nb_temps; i < n; i++) { 1901ee17db83SRichard Henderson TCGTemp *ts = &s->temps[i]; 1902ee17db83SRichard Henderson TCGTempVal val = TEMP_VAL_MEM; 1903ee17db83SRichard Henderson 1904ee17db83SRichard Henderson switch (ts->kind) { 1905c0522136SRichard Henderson case TEMP_CONST: 1906c0522136SRichard Henderson val = TEMP_VAL_CONST; 1907c0522136SRichard Henderson break; 1908ee17db83SRichard Henderson case TEMP_FIXED: 1909ee17db83SRichard Henderson val = TEMP_VAL_REG; 1910ee17db83SRichard Henderson break; 1911ee17db83SRichard Henderson case TEMP_GLOBAL: 1912ee17db83SRichard Henderson break; 1913ee17db83SRichard Henderson case TEMP_NORMAL: 1914c7482438SRichard Henderson case TEMP_EBB: 1915ee17db83SRichard Henderson val = TEMP_VAL_DEAD; 1916ee17db83SRichard Henderson /* fall through */ 1917f57c6915SRichard Henderson case TEMP_TB: 1918e8996ee0Sbellard ts->mem_allocated = 0; 1919ee17db83SRichard Henderson break; 1920ee17db83SRichard Henderson default: 1921ee17db83SRichard Henderson g_assert_not_reached(); 1922ee17db83SRichard Henderson } 1923ee17db83SRichard Henderson ts->val_type = val; 1924e8996ee0Sbellard } 1925f8b2f202SRichard Henderson 1926f8b2f202SRichard Henderson memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp)); 1927c896fe29Sbellard } 1928c896fe29Sbellard 1929f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size, 1930f8b2f202SRichard Henderson TCGTemp *ts) 1931c896fe29Sbellard { 19321807f4c4SRichard Henderson int idx = temp_idx(ts); 1933ac56dd48Spbrook 1934ee17db83SRichard Henderson switch (ts->kind) { 1935ee17db83SRichard Henderson case TEMP_FIXED: 1936ee17db83SRichard Henderson case TEMP_GLOBAL: 1937ac56dd48Spbrook pstrcpy(buf, buf_size, ts->name); 1938ee17db83SRichard Henderson break; 1939f57c6915SRichard Henderson case TEMP_TB: 1940641d5fbeSbellard snprintf(buf, buf_size, "loc%d", idx - s->nb_globals); 1941ee17db83SRichard Henderson break; 1942c7482438SRichard Henderson case TEMP_EBB: 1943c7482438SRichard Henderson snprintf(buf, buf_size, "ebb%d", idx - s->nb_globals); 1944c7482438SRichard Henderson break; 1945ee17db83SRichard Henderson case TEMP_NORMAL: 1946ac56dd48Spbrook snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals); 1947ee17db83SRichard Henderson break; 1948c0522136SRichard Henderson case TEMP_CONST: 1949c0522136SRichard Henderson switch (ts->type) { 1950c0522136SRichard Henderson case TCG_TYPE_I32: 1951c0522136SRichard Henderson snprintf(buf, buf_size, "$0x%x", (int32_t)ts->val); 1952c0522136SRichard Henderson break; 1953c0522136SRichard Henderson #if TCG_TARGET_REG_BITS > 32 1954c0522136SRichard Henderson case TCG_TYPE_I64: 1955c0522136SRichard Henderson snprintf(buf, buf_size, "$0x%" PRIx64, ts->val); 1956c0522136SRichard Henderson break; 1957c0522136SRichard Henderson #endif 1958c0522136SRichard Henderson case TCG_TYPE_V64: 1959c0522136SRichard Henderson case TCG_TYPE_V128: 1960c0522136SRichard Henderson case TCG_TYPE_V256: 1961c0522136SRichard Henderson snprintf(buf, buf_size, "v%d$0x%" PRIx64, 1962c0522136SRichard Henderson 64 << (ts->type - TCG_TYPE_V64), ts->val); 1963c0522136SRichard Henderson break; 1964c0522136SRichard Henderson default: 1965c0522136SRichard Henderson g_assert_not_reached(); 1966c0522136SRichard Henderson } 1967c0522136SRichard Henderson break; 1968c896fe29Sbellard } 1969c896fe29Sbellard return buf; 1970c896fe29Sbellard } 1971c896fe29Sbellard 197243439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf, 197343439139SRichard Henderson int buf_size, TCGArg arg) 1974f8b2f202SRichard Henderson { 197543439139SRichard Henderson return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg)); 1976f8b2f202SRichard Henderson } 1977f8b2f202SRichard Henderson 1978f48f3edeSblueswir1 static const char * const cond_name[] = 1979f48f3edeSblueswir1 { 19800aed257fSRichard Henderson [TCG_COND_NEVER] = "never", 19810aed257fSRichard Henderson [TCG_COND_ALWAYS] = "always", 1982f48f3edeSblueswir1 [TCG_COND_EQ] = "eq", 1983f48f3edeSblueswir1 [TCG_COND_NE] = "ne", 1984f48f3edeSblueswir1 [TCG_COND_LT] = "lt", 1985f48f3edeSblueswir1 [TCG_COND_GE] = "ge", 1986f48f3edeSblueswir1 [TCG_COND_LE] = "le", 1987f48f3edeSblueswir1 [TCG_COND_GT] = "gt", 1988f48f3edeSblueswir1 [TCG_COND_LTU] = "ltu", 1989f48f3edeSblueswir1 [TCG_COND_GEU] = "geu", 1990f48f3edeSblueswir1 [TCG_COND_LEU] = "leu", 1991f48f3edeSblueswir1 [TCG_COND_GTU] = "gtu" 1992f48f3edeSblueswir1 }; 1993f48f3edeSblueswir1 1994f713d6adSRichard Henderson static const char * const ldst_name[] = 1995f713d6adSRichard Henderson { 1996f713d6adSRichard Henderson [MO_UB] = "ub", 1997f713d6adSRichard Henderson [MO_SB] = "sb", 1998f713d6adSRichard Henderson [MO_LEUW] = "leuw", 1999f713d6adSRichard Henderson [MO_LESW] = "lesw", 2000f713d6adSRichard Henderson [MO_LEUL] = "leul", 2001f713d6adSRichard Henderson [MO_LESL] = "lesl", 2002fc313c64SFrédéric Pétrot [MO_LEUQ] = "leq", 2003f713d6adSRichard Henderson [MO_BEUW] = "beuw", 2004f713d6adSRichard Henderson [MO_BESW] = "besw", 2005f713d6adSRichard Henderson [MO_BEUL] = "beul", 2006f713d6adSRichard Henderson [MO_BESL] = "besl", 2007fc313c64SFrédéric Pétrot [MO_BEUQ] = "beq", 2008f713d6adSRichard Henderson }; 2009f713d6adSRichard Henderson 20101f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = { 201152bf9771Stony.nguyen@bt.com #ifdef TARGET_ALIGNED_ONLY 20121f00b27fSSergey Sorokin [MO_UNALN >> MO_ASHIFT] = "un+", 20131f00b27fSSergey Sorokin [MO_ALIGN >> MO_ASHIFT] = "", 20141f00b27fSSergey Sorokin #else 20151f00b27fSSergey Sorokin [MO_UNALN >> MO_ASHIFT] = "", 20161f00b27fSSergey Sorokin [MO_ALIGN >> MO_ASHIFT] = "al+", 20171f00b27fSSergey Sorokin #endif 20181f00b27fSSergey Sorokin [MO_ALIGN_2 >> MO_ASHIFT] = "al2+", 20191f00b27fSSergey Sorokin [MO_ALIGN_4 >> MO_ASHIFT] = "al4+", 20201f00b27fSSergey Sorokin [MO_ALIGN_8 >> MO_ASHIFT] = "al8+", 20211f00b27fSSergey Sorokin [MO_ALIGN_16 >> MO_ASHIFT] = "al16+", 20221f00b27fSSergey Sorokin [MO_ALIGN_32 >> MO_ASHIFT] = "al32+", 20231f00b27fSSergey Sorokin [MO_ALIGN_64 >> MO_ASHIFT] = "al64+", 20241f00b27fSSergey Sorokin }; 20251f00b27fSSergey Sorokin 2026587195bdSRichard Henderson static const char bswap_flag_name[][6] = { 2027587195bdSRichard Henderson [TCG_BSWAP_IZ] = "iz", 2028587195bdSRichard Henderson [TCG_BSWAP_OZ] = "oz", 2029587195bdSRichard Henderson [TCG_BSWAP_OS] = "os", 2030587195bdSRichard Henderson [TCG_BSWAP_IZ | TCG_BSWAP_OZ] = "iz,oz", 2031587195bdSRichard Henderson [TCG_BSWAP_IZ | TCG_BSWAP_OS] = "iz,os", 2032587195bdSRichard Henderson }; 2033587195bdSRichard Henderson 2034b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d) 2035b016486eSRichard Henderson { 2036b016486eSRichard Henderson return (d & (d - 1)) == 0; 2037b016486eSRichard Henderson } 2038b016486eSRichard Henderson 2039b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d) 2040b016486eSRichard Henderson { 2041b016486eSRichard Henderson if (TCG_TARGET_NB_REGS <= 32) { 2042b016486eSRichard Henderson return ctz32(d); 2043b016486eSRichard Henderson } else { 2044b016486eSRichard Henderson return ctz64(d); 2045b016486eSRichard Henderson } 2046b016486eSRichard Henderson } 2047b016486eSRichard Henderson 2048b7a83ff8SRichard Henderson /* Return only the number of characters output -- no error return. */ 2049b7a83ff8SRichard Henderson #define ne_fprintf(...) \ 2050b7a83ff8SRichard Henderson ({ int ret_ = fprintf(__VA_ARGS__); ret_ >= 0 ? ret_ : 0; }) 2051b7a83ff8SRichard Henderson 2052b7a83ff8SRichard Henderson static void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs) 2053c896fe29Sbellard { 2054c896fe29Sbellard char buf[128]; 2055c45cb8bbSRichard Henderson TCGOp *op; 2056c896fe29Sbellard 205715fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 2058c45cb8bbSRichard Henderson int i, k, nb_oargs, nb_iargs, nb_cargs; 2059c45cb8bbSRichard Henderson const TCGOpDef *def; 2060c45cb8bbSRichard Henderson TCGOpcode c; 2061bdfb460eSRichard Henderson int col = 0; 2062c45cb8bbSRichard Henderson 2063c45cb8bbSRichard Henderson c = op->opc; 2064c896fe29Sbellard def = &tcg_op_defs[c]; 2065c45cb8bbSRichard Henderson 2066765b842aSRichard Henderson if (c == INDEX_op_insn_start) { 2067b016486eSRichard Henderson nb_oargs = 0; 2068b7a83ff8SRichard Henderson col += ne_fprintf(f, "\n ----"); 20699aef40edSRichard Henderson 20709aef40edSRichard Henderson for (i = 0; i < TARGET_INSN_START_WORDS; ++i) { 20719aef40edSRichard Henderson target_ulong a; 20727e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS 2073efee3746SRichard Henderson a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]); 20747e4597d7Sbellard #else 2075efee3746SRichard Henderson a = op->args[i]; 20767e4597d7Sbellard #endif 2077b7a83ff8SRichard Henderson col += ne_fprintf(f, " " TARGET_FMT_lx, a); 2078eeacee4dSBlue Swirl } 20797e4597d7Sbellard } else if (c == INDEX_op_call) { 20803e92aa34SRichard Henderson const TCGHelperInfo *info = tcg_call_info(op); 2081fa52e660SRichard Henderson void *func = tcg_call_func(op); 20823e92aa34SRichard Henderson 2083c896fe29Sbellard /* variable number of arguments */ 2084cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 2085cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 2086c896fe29Sbellard nb_cargs = def->nb_cargs; 2087b03cce8eSbellard 2088b7a83ff8SRichard Henderson col += ne_fprintf(f, " %s ", def->name); 20893e92aa34SRichard Henderson 20903e92aa34SRichard Henderson /* 20913e92aa34SRichard Henderson * Print the function name from TCGHelperInfo, if available. 20923e92aa34SRichard Henderson * Note that plugins have a template function for the info, 20933e92aa34SRichard Henderson * but the actual function pointer comes from the plugin. 20943e92aa34SRichard Henderson */ 20953e92aa34SRichard Henderson if (func == info->func) { 2096b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s", info->name); 20973e92aa34SRichard Henderson } else { 2098b7a83ff8SRichard Henderson col += ne_fprintf(f, "plugin(%p)", func); 20993e92aa34SRichard Henderson } 21003e92aa34SRichard Henderson 2101b7a83ff8SRichard Henderson col += ne_fprintf(f, ",$0x%x,$%d", info->flags, nb_oargs); 2102b03cce8eSbellard for (i = 0; i < nb_oargs; i++) { 2103b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", tcg_get_arg_str(s, buf, sizeof(buf), 2104efee3746SRichard Henderson op->args[i])); 2105b03cce8eSbellard } 2106cf066674SRichard Henderson for (i = 0; i < nb_iargs; i++) { 2107efee3746SRichard Henderson TCGArg arg = op->args[nb_oargs + i]; 210839004a71SRichard Henderson const char *t = tcg_get_arg_str(s, buf, sizeof(buf), arg); 2109b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", t); 2110e8996ee0Sbellard } 2111b03cce8eSbellard } else { 2112b7a83ff8SRichard Henderson col += ne_fprintf(f, " %s ", def->name); 2113c45cb8bbSRichard Henderson 2114c896fe29Sbellard nb_oargs = def->nb_oargs; 2115c896fe29Sbellard nb_iargs = def->nb_iargs; 2116c896fe29Sbellard nb_cargs = def->nb_cargs; 2117c896fe29Sbellard 2118d2fd745fSRichard Henderson if (def->flags & TCG_OPF_VECTOR) { 2119b7a83ff8SRichard Henderson col += ne_fprintf(f, "v%d,e%d,", 64 << TCGOP_VECL(op), 2120d2fd745fSRichard Henderson 8 << TCGOP_VECE(op)); 2121d2fd745fSRichard Henderson } 2122d2fd745fSRichard Henderson 2123c896fe29Sbellard k = 0; 2124c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 2125b7a83ff8SRichard Henderson const char *sep = k ? "," : ""; 2126b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s%s", sep, 2127b7a83ff8SRichard Henderson tcg_get_arg_str(s, buf, sizeof(buf), 2128efee3746SRichard Henderson op->args[k++])); 2129c896fe29Sbellard } 2130c896fe29Sbellard for (i = 0; i < nb_iargs; i++) { 2131b7a83ff8SRichard Henderson const char *sep = k ? "," : ""; 2132b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s%s", sep, 2133b7a83ff8SRichard Henderson tcg_get_arg_str(s, buf, sizeof(buf), 2134efee3746SRichard Henderson op->args[k++])); 2135c896fe29Sbellard } 2136be210acbSRichard Henderson switch (c) { 2137be210acbSRichard Henderson case INDEX_op_brcond_i32: 2138ffc5ea09SRichard Henderson case INDEX_op_setcond_i32: 2139ffc5ea09SRichard Henderson case INDEX_op_movcond_i32: 2140be210acbSRichard Henderson case INDEX_op_brcond2_i32: 2141be210acbSRichard Henderson case INDEX_op_setcond2_i32: 2142ffc5ea09SRichard Henderson case INDEX_op_brcond_i64: 2143be210acbSRichard Henderson case INDEX_op_setcond_i64: 2144ffc5ea09SRichard Henderson case INDEX_op_movcond_i64: 2145212be173SRichard Henderson case INDEX_op_cmp_vec: 2146f75da298SRichard Henderson case INDEX_op_cmpsel_vec: 2147efee3746SRichard Henderson if (op->args[k] < ARRAY_SIZE(cond_name) 2148efee3746SRichard Henderson && cond_name[op->args[k]]) { 2149b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", cond_name[op->args[k++]]); 2150eeacee4dSBlue Swirl } else { 2151b7a83ff8SRichard Henderson col += ne_fprintf(f, ",$0x%" TCG_PRIlx, op->args[k++]); 2152eeacee4dSBlue Swirl } 2153f48f3edeSblueswir1 i = 1; 2154be210acbSRichard Henderson break; 2155f713d6adSRichard Henderson case INDEX_op_qemu_ld_i32: 2156f713d6adSRichard Henderson case INDEX_op_qemu_st_i32: 215707ce0b05SRichard Henderson case INDEX_op_qemu_st8_i32: 2158f713d6adSRichard Henderson case INDEX_op_qemu_ld_i64: 2159f713d6adSRichard Henderson case INDEX_op_qemu_st_i64: 216059227d5dSRichard Henderson { 21619002ffcbSRichard Henderson MemOpIdx oi = op->args[k++]; 216214776ab5STony Nguyen MemOp op = get_memop(oi); 216359227d5dSRichard Henderson unsigned ix = get_mmuidx(oi); 216459227d5dSRichard Henderson 216559c4b7e8SRichard Henderson if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) { 2166b7a83ff8SRichard Henderson col += ne_fprintf(f, ",$0x%x,%u", op, ix); 216759c4b7e8SRichard Henderson } else { 21681f00b27fSSergey Sorokin const char *s_al, *s_op; 21691f00b27fSSergey Sorokin s_al = alignment_name[(op & MO_AMASK) >> MO_ASHIFT]; 217059c4b7e8SRichard Henderson s_op = ldst_name[op & (MO_BSWAP | MO_SSIZE)]; 2171b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s%s,%u", s_al, s_op, ix); 2172f713d6adSRichard Henderson } 2173f713d6adSRichard Henderson i = 1; 217459227d5dSRichard Henderson } 2175f713d6adSRichard Henderson break; 2176587195bdSRichard Henderson case INDEX_op_bswap16_i32: 2177587195bdSRichard Henderson case INDEX_op_bswap16_i64: 2178587195bdSRichard Henderson case INDEX_op_bswap32_i32: 2179587195bdSRichard Henderson case INDEX_op_bswap32_i64: 2180587195bdSRichard Henderson case INDEX_op_bswap64_i64: 2181587195bdSRichard Henderson { 2182587195bdSRichard Henderson TCGArg flags = op->args[k]; 2183587195bdSRichard Henderson const char *name = NULL; 2184587195bdSRichard Henderson 2185587195bdSRichard Henderson if (flags < ARRAY_SIZE(bswap_flag_name)) { 2186587195bdSRichard Henderson name = bswap_flag_name[flags]; 2187587195bdSRichard Henderson } 2188587195bdSRichard Henderson if (name) { 2189b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", name); 2190587195bdSRichard Henderson } else { 2191b7a83ff8SRichard Henderson col += ne_fprintf(f, ",$0x%" TCG_PRIlx, flags); 2192587195bdSRichard Henderson } 2193587195bdSRichard Henderson i = k = 1; 2194587195bdSRichard Henderson } 2195587195bdSRichard Henderson break; 2196be210acbSRichard Henderson default: 2197f48f3edeSblueswir1 i = 0; 2198be210acbSRichard Henderson break; 2199be210acbSRichard Henderson } 220051e3972cSRichard Henderson switch (c) { 220151e3972cSRichard Henderson case INDEX_op_set_label: 220251e3972cSRichard Henderson case INDEX_op_br: 220351e3972cSRichard Henderson case INDEX_op_brcond_i32: 220451e3972cSRichard Henderson case INDEX_op_brcond_i64: 220551e3972cSRichard Henderson case INDEX_op_brcond2_i32: 2206b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s$L%d", k ? "," : "", 2207efee3746SRichard Henderson arg_label(op->args[k])->id); 220851e3972cSRichard Henderson i++, k++; 220951e3972cSRichard Henderson break; 221051e3972cSRichard Henderson default: 221151e3972cSRichard Henderson break; 2212eeacee4dSBlue Swirl } 221351e3972cSRichard Henderson for (; i < nb_cargs; i++, k++) { 2214b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s$0x%" TCG_PRIlx, k ? "," : "", 2215b7a83ff8SRichard Henderson op->args[k]); 2216bdfb460eSRichard Henderson } 2217bdfb460eSRichard Henderson } 2218bdfb460eSRichard Henderson 22191894f69aSRichard Henderson if (have_prefs || op->life) { 22201894f69aSRichard Henderson for (; col < 40; ++col) { 2221b7a83ff8SRichard Henderson putc(' ', f); 2222bdfb460eSRichard Henderson } 22231894f69aSRichard Henderson } 22241894f69aSRichard Henderson 22251894f69aSRichard Henderson if (op->life) { 22261894f69aSRichard Henderson unsigned life = op->life; 2227bdfb460eSRichard Henderson 2228bdfb460eSRichard Henderson if (life & (SYNC_ARG * 3)) { 2229b7a83ff8SRichard Henderson ne_fprintf(f, " sync:"); 2230bdfb460eSRichard Henderson for (i = 0; i < 2; ++i) { 2231bdfb460eSRichard Henderson if (life & (SYNC_ARG << i)) { 2232b7a83ff8SRichard Henderson ne_fprintf(f, " %d", i); 2233bdfb460eSRichard Henderson } 2234bdfb460eSRichard Henderson } 2235bdfb460eSRichard Henderson } 2236bdfb460eSRichard Henderson life /= DEAD_ARG; 2237bdfb460eSRichard Henderson if (life) { 2238b7a83ff8SRichard Henderson ne_fprintf(f, " dead:"); 2239bdfb460eSRichard Henderson for (i = 0; life; ++i, life >>= 1) { 2240bdfb460eSRichard Henderson if (life & 1) { 2241b7a83ff8SRichard Henderson ne_fprintf(f, " %d", i); 2242bdfb460eSRichard Henderson } 2243bdfb460eSRichard Henderson } 2244c896fe29Sbellard } 2245b03cce8eSbellard } 22461894f69aSRichard Henderson 22471894f69aSRichard Henderson if (have_prefs) { 22481894f69aSRichard Henderson for (i = 0; i < nb_oargs; ++i) { 224931fd884bSRichard Henderson TCGRegSet set = output_pref(op, i); 22501894f69aSRichard Henderson 22511894f69aSRichard Henderson if (i == 0) { 2252b7a83ff8SRichard Henderson ne_fprintf(f, " pref="); 22531894f69aSRichard Henderson } else { 2254b7a83ff8SRichard Henderson ne_fprintf(f, ","); 22551894f69aSRichard Henderson } 22561894f69aSRichard Henderson if (set == 0) { 2257b7a83ff8SRichard Henderson ne_fprintf(f, "none"); 22581894f69aSRichard Henderson } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) { 2259b7a83ff8SRichard Henderson ne_fprintf(f, "all"); 22601894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG 22611894f69aSRichard Henderson } else if (tcg_regset_single(set)) { 22621894f69aSRichard Henderson TCGReg reg = tcg_regset_first(set); 2263b7a83ff8SRichard Henderson ne_fprintf(f, "%s", tcg_target_reg_names[reg]); 22641894f69aSRichard Henderson #endif 22651894f69aSRichard Henderson } else if (TCG_TARGET_NB_REGS <= 32) { 2266b7a83ff8SRichard Henderson ne_fprintf(f, "0x%x", (uint32_t)set); 22671894f69aSRichard Henderson } else { 2268b7a83ff8SRichard Henderson ne_fprintf(f, "0x%" PRIx64, (uint64_t)set); 22691894f69aSRichard Henderson } 22701894f69aSRichard Henderson } 22711894f69aSRichard Henderson } 22721894f69aSRichard Henderson 2273b7a83ff8SRichard Henderson putc('\n', f); 2274c896fe29Sbellard } 2275c896fe29Sbellard } 2276c896fe29Sbellard 2277c896fe29Sbellard /* we give more priority to constraints with less registers */ 2278c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k) 2279c896fe29Sbellard { 228074a11790SRichard Henderson const TCGArgConstraint *arg_ct = &def->args_ct[k]; 228129f5e925SRichard Henderson int n = ctpop64(arg_ct->regs); 2282c896fe29Sbellard 228329f5e925SRichard Henderson /* 228429f5e925SRichard Henderson * Sort constraints of a single register first, which includes output 228529f5e925SRichard Henderson * aliases (which must exactly match the input already allocated). 228629f5e925SRichard Henderson */ 228729f5e925SRichard Henderson if (n == 1 || arg_ct->oalias) { 228829f5e925SRichard Henderson return INT_MAX; 2289c896fe29Sbellard } 229029f5e925SRichard Henderson 229129f5e925SRichard Henderson /* 229229f5e925SRichard Henderson * Sort register pairs next, first then second immediately after. 229329f5e925SRichard Henderson * Arbitrarily sort multiple pairs by the index of the first reg; 229429f5e925SRichard Henderson * there shouldn't be many pairs. 229529f5e925SRichard Henderson */ 229629f5e925SRichard Henderson switch (arg_ct->pair) { 229729f5e925SRichard Henderson case 1: 229829f5e925SRichard Henderson case 3: 229929f5e925SRichard Henderson return (k + 1) * 2; 230029f5e925SRichard Henderson case 2: 230129f5e925SRichard Henderson return (arg_ct->pair_index + 1) * 2 - 1; 230229f5e925SRichard Henderson } 230329f5e925SRichard Henderson 230429f5e925SRichard Henderson /* Finally, sort by decreasing register count. */ 230529f5e925SRichard Henderson assert(n > 1); 230629f5e925SRichard Henderson return -n; 2307c896fe29Sbellard } 2308c896fe29Sbellard 2309c896fe29Sbellard /* sort from highest priority to lowest */ 2310c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n) 2311c896fe29Sbellard { 231266792f90SRichard Henderson int i, j; 231366792f90SRichard Henderson TCGArgConstraint *a = def->args_ct; 2314c896fe29Sbellard 231566792f90SRichard Henderson for (i = 0; i < n; i++) { 231666792f90SRichard Henderson a[start + i].sort_index = start + i; 231766792f90SRichard Henderson } 231866792f90SRichard Henderson if (n <= 1) { 2319c896fe29Sbellard return; 232066792f90SRichard Henderson } 2321c896fe29Sbellard for (i = 0; i < n - 1; i++) { 2322c896fe29Sbellard for (j = i + 1; j < n; j++) { 232366792f90SRichard Henderson int p1 = get_constraint_priority(def, a[start + i].sort_index); 232466792f90SRichard Henderson int p2 = get_constraint_priority(def, a[start + j].sort_index); 2325c896fe29Sbellard if (p1 < p2) { 232666792f90SRichard Henderson int tmp = a[start + i].sort_index; 232766792f90SRichard Henderson a[start + i].sort_index = a[start + j].sort_index; 232866792f90SRichard Henderson a[start + j].sort_index = tmp; 2329c896fe29Sbellard } 2330c896fe29Sbellard } 2331c896fe29Sbellard } 2332c896fe29Sbellard } 2333c896fe29Sbellard 2334f69d277eSRichard Henderson static void process_op_defs(TCGContext *s) 2335c896fe29Sbellard { 2336a9751609SRichard Henderson TCGOpcode op; 2337c896fe29Sbellard 2338f69d277eSRichard Henderson for (op = 0; op < NB_OPS; op++) { 2339f69d277eSRichard Henderson TCGOpDef *def = &tcg_op_defs[op]; 2340f69d277eSRichard Henderson const TCGTargetOpDef *tdefs; 234129f5e925SRichard Henderson bool saw_alias_pair = false; 234229f5e925SRichard Henderson int i, o, i2, o2, nb_args; 2343f69d277eSRichard Henderson 2344f69d277eSRichard Henderson if (def->flags & TCG_OPF_NOT_PRESENT) { 2345f69d277eSRichard Henderson continue; 2346f69d277eSRichard Henderson } 2347f69d277eSRichard Henderson 2348c896fe29Sbellard nb_args = def->nb_iargs + def->nb_oargs; 2349f69d277eSRichard Henderson if (nb_args == 0) { 2350f69d277eSRichard Henderson continue; 2351f69d277eSRichard Henderson } 2352f69d277eSRichard Henderson 23534c22e840SRichard Henderson /* 23544c22e840SRichard Henderson * Macro magic should make it impossible, but double-check that 23554c22e840SRichard Henderson * the array index is in range. Since the signness of an enum 23564c22e840SRichard Henderson * is implementation defined, force the result to unsigned. 23574c22e840SRichard Henderson */ 23584c22e840SRichard Henderson unsigned con_set = tcg_target_op_def(op); 23594c22e840SRichard Henderson tcg_debug_assert(con_set < ARRAY_SIZE(constraint_sets)); 23604c22e840SRichard Henderson tdefs = &constraint_sets[con_set]; 2361f69d277eSRichard Henderson 2362c896fe29Sbellard for (i = 0; i < nb_args; i++) { 2363f69d277eSRichard Henderson const char *ct_str = tdefs->args_ct_str[i]; 23648940ea0dSPhilippe Mathieu-Daudé bool input_p = i >= def->nb_oargs; 23658940ea0dSPhilippe Mathieu-Daudé 2366f69d277eSRichard Henderson /* Incomplete TCGTargetOpDef entry. */ 2367eabb7b91SAurelien Jarno tcg_debug_assert(ct_str != NULL); 2368f69d277eSRichard Henderson 236917280ff4SRichard Henderson switch (*ct_str) { 237017280ff4SRichard Henderson case '0' ... '9': 23718940ea0dSPhilippe Mathieu-Daudé o = *ct_str - '0'; 23728940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(input_p); 23738940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(o < def->nb_oargs); 23748940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(def->args_ct[o].regs != 0); 23758940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(!def->args_ct[o].oalias); 23768940ea0dSPhilippe Mathieu-Daudé def->args_ct[i] = def->args_ct[o]; 2377bc2b17e6SRichard Henderson /* The output sets oalias. */ 23788940ea0dSPhilippe Mathieu-Daudé def->args_ct[o].oalias = 1; 23798940ea0dSPhilippe Mathieu-Daudé def->args_ct[o].alias_index = i; 2380bc2b17e6SRichard Henderson /* The input sets ialias. */ 23818940ea0dSPhilippe Mathieu-Daudé def->args_ct[i].ialias = 1; 23828940ea0dSPhilippe Mathieu-Daudé def->args_ct[i].alias_index = o; 238329f5e925SRichard Henderson if (def->args_ct[i].pair) { 238429f5e925SRichard Henderson saw_alias_pair = true; 238529f5e925SRichard Henderson } 23868940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(ct_str[1] == '\0'); 23878940ea0dSPhilippe Mathieu-Daudé continue; 23888940ea0dSPhilippe Mathieu-Daudé 238982790a87SRichard Henderson case '&': 23908940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(!input_p); 2391bc2b17e6SRichard Henderson def->args_ct[i].newreg = true; 239282790a87SRichard Henderson ct_str++; 239382790a87SRichard Henderson break; 239429f5e925SRichard Henderson 239529f5e925SRichard Henderson case 'p': /* plus */ 239629f5e925SRichard Henderson /* Allocate to the register after the previous. */ 239729f5e925SRichard Henderson tcg_debug_assert(i > (input_p ? def->nb_oargs : 0)); 239829f5e925SRichard Henderson o = i - 1; 239929f5e925SRichard Henderson tcg_debug_assert(!def->args_ct[o].pair); 240029f5e925SRichard Henderson tcg_debug_assert(!def->args_ct[o].ct); 240129f5e925SRichard Henderson def->args_ct[i] = (TCGArgConstraint){ 240229f5e925SRichard Henderson .pair = 2, 240329f5e925SRichard Henderson .pair_index = o, 240429f5e925SRichard Henderson .regs = def->args_ct[o].regs << 1, 240529f5e925SRichard Henderson }; 240629f5e925SRichard Henderson def->args_ct[o].pair = 1; 240729f5e925SRichard Henderson def->args_ct[o].pair_index = i; 240829f5e925SRichard Henderson tcg_debug_assert(ct_str[1] == '\0'); 240929f5e925SRichard Henderson continue; 241029f5e925SRichard Henderson 241129f5e925SRichard Henderson case 'm': /* minus */ 241229f5e925SRichard Henderson /* Allocate to the register before the previous. */ 241329f5e925SRichard Henderson tcg_debug_assert(i > (input_p ? def->nb_oargs : 0)); 241429f5e925SRichard Henderson o = i - 1; 241529f5e925SRichard Henderson tcg_debug_assert(!def->args_ct[o].pair); 241629f5e925SRichard Henderson tcg_debug_assert(!def->args_ct[o].ct); 241729f5e925SRichard Henderson def->args_ct[i] = (TCGArgConstraint){ 241829f5e925SRichard Henderson .pair = 1, 241929f5e925SRichard Henderson .pair_index = o, 242029f5e925SRichard Henderson .regs = def->args_ct[o].regs >> 1, 242129f5e925SRichard Henderson }; 242229f5e925SRichard Henderson def->args_ct[o].pair = 2; 242329f5e925SRichard Henderson def->args_ct[o].pair_index = i; 242429f5e925SRichard Henderson tcg_debug_assert(ct_str[1] == '\0'); 242529f5e925SRichard Henderson continue; 24268940ea0dSPhilippe Mathieu-Daudé } 24278940ea0dSPhilippe Mathieu-Daudé 24288940ea0dSPhilippe Mathieu-Daudé do { 24298940ea0dSPhilippe Mathieu-Daudé switch (*ct_str) { 2430c896fe29Sbellard case 'i': 2431c896fe29Sbellard def->args_ct[i].ct |= TCG_CT_CONST; 2432c896fe29Sbellard break; 2433358b4923SRichard Henderson 2434358b4923SRichard Henderson /* Include all of the target-specific constraints. */ 2435358b4923SRichard Henderson 2436358b4923SRichard Henderson #undef CONST 2437358b4923SRichard Henderson #define CONST(CASE, MASK) \ 24388940ea0dSPhilippe Mathieu-Daudé case CASE: def->args_ct[i].ct |= MASK; break; 2439358b4923SRichard Henderson #define REGS(CASE, MASK) \ 24408940ea0dSPhilippe Mathieu-Daudé case CASE: def->args_ct[i].regs |= MASK; break; 2441358b4923SRichard Henderson 2442358b4923SRichard Henderson #include "tcg-target-con-str.h" 2443358b4923SRichard Henderson 2444358b4923SRichard Henderson #undef REGS 2445358b4923SRichard Henderson #undef CONST 2446c896fe29Sbellard default: 24478940ea0dSPhilippe Mathieu-Daudé case '0' ... '9': 24488940ea0dSPhilippe Mathieu-Daudé case '&': 244929f5e925SRichard Henderson case 'p': 245029f5e925SRichard Henderson case 'm': 2451358b4923SRichard Henderson /* Typo in TCGTargetOpDef constraint. */ 2452358b4923SRichard Henderson g_assert_not_reached(); 2453358b4923SRichard Henderson } 24548940ea0dSPhilippe Mathieu-Daudé } while (*++ct_str != '\0'); 2455c896fe29Sbellard } 2456c896fe29Sbellard 2457c68aaa18SStefan Weil /* TCGTargetOpDef entry with too much information? */ 2458eabb7b91SAurelien Jarno tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL); 2459c68aaa18SStefan Weil 246029f5e925SRichard Henderson /* 246129f5e925SRichard Henderson * Fix up output pairs that are aliased with inputs. 246229f5e925SRichard Henderson * When we created the alias, we copied pair from the output. 246329f5e925SRichard Henderson * There are three cases: 246429f5e925SRichard Henderson * (1a) Pairs of inputs alias pairs of outputs. 246529f5e925SRichard Henderson * (1b) One input aliases the first of a pair of outputs. 246629f5e925SRichard Henderson * (2) One input aliases the second of a pair of outputs. 246729f5e925SRichard Henderson * 246829f5e925SRichard Henderson * Case 1a is handled by making sure that the pair_index'es are 246929f5e925SRichard Henderson * properly updated so that they appear the same as a pair of inputs. 247029f5e925SRichard Henderson * 247129f5e925SRichard Henderson * Case 1b is handled by setting the pair_index of the input to 247229f5e925SRichard Henderson * itself, simply so it doesn't point to an unrelated argument. 247329f5e925SRichard Henderson * Since we don't encounter the "second" during the input allocation 247429f5e925SRichard Henderson * phase, nothing happens with the second half of the input pair. 247529f5e925SRichard Henderson * 247629f5e925SRichard Henderson * Case 2 is handled by setting the second input to pair=3, the 247729f5e925SRichard Henderson * first output to pair=3, and the pair_index'es to match. 247829f5e925SRichard Henderson */ 247929f5e925SRichard Henderson if (saw_alias_pair) { 248029f5e925SRichard Henderson for (i = def->nb_oargs; i < nb_args; i++) { 248129f5e925SRichard Henderson /* 248229f5e925SRichard Henderson * Since [0-9pm] must be alone in the constraint string, 248329f5e925SRichard Henderson * the only way they can both be set is if the pair comes 248429f5e925SRichard Henderson * from the output alias. 248529f5e925SRichard Henderson */ 248629f5e925SRichard Henderson if (!def->args_ct[i].ialias) { 248729f5e925SRichard Henderson continue; 248829f5e925SRichard Henderson } 248929f5e925SRichard Henderson switch (def->args_ct[i].pair) { 249029f5e925SRichard Henderson case 0: 249129f5e925SRichard Henderson break; 249229f5e925SRichard Henderson case 1: 249329f5e925SRichard Henderson o = def->args_ct[i].alias_index; 249429f5e925SRichard Henderson o2 = def->args_ct[o].pair_index; 249529f5e925SRichard Henderson tcg_debug_assert(def->args_ct[o].pair == 1); 249629f5e925SRichard Henderson tcg_debug_assert(def->args_ct[o2].pair == 2); 249729f5e925SRichard Henderson if (def->args_ct[o2].oalias) { 249829f5e925SRichard Henderson /* Case 1a */ 249929f5e925SRichard Henderson i2 = def->args_ct[o2].alias_index; 250029f5e925SRichard Henderson tcg_debug_assert(def->args_ct[i2].pair == 2); 250129f5e925SRichard Henderson def->args_ct[i2].pair_index = i; 250229f5e925SRichard Henderson def->args_ct[i].pair_index = i2; 250329f5e925SRichard Henderson } else { 250429f5e925SRichard Henderson /* Case 1b */ 250529f5e925SRichard Henderson def->args_ct[i].pair_index = i; 250629f5e925SRichard Henderson } 250729f5e925SRichard Henderson break; 250829f5e925SRichard Henderson case 2: 250929f5e925SRichard Henderson o = def->args_ct[i].alias_index; 251029f5e925SRichard Henderson o2 = def->args_ct[o].pair_index; 251129f5e925SRichard Henderson tcg_debug_assert(def->args_ct[o].pair == 2); 251229f5e925SRichard Henderson tcg_debug_assert(def->args_ct[o2].pair == 1); 251329f5e925SRichard Henderson if (def->args_ct[o2].oalias) { 251429f5e925SRichard Henderson /* Case 1a */ 251529f5e925SRichard Henderson i2 = def->args_ct[o2].alias_index; 251629f5e925SRichard Henderson tcg_debug_assert(def->args_ct[i2].pair == 1); 251729f5e925SRichard Henderson def->args_ct[i2].pair_index = i; 251829f5e925SRichard Henderson def->args_ct[i].pair_index = i2; 251929f5e925SRichard Henderson } else { 252029f5e925SRichard Henderson /* Case 2 */ 252129f5e925SRichard Henderson def->args_ct[i].pair = 3; 252229f5e925SRichard Henderson def->args_ct[o2].pair = 3; 252329f5e925SRichard Henderson def->args_ct[i].pair_index = o2; 252429f5e925SRichard Henderson def->args_ct[o2].pair_index = i; 252529f5e925SRichard Henderson } 252629f5e925SRichard Henderson break; 252729f5e925SRichard Henderson default: 252829f5e925SRichard Henderson g_assert_not_reached(); 252929f5e925SRichard Henderson } 253029f5e925SRichard Henderson } 253129f5e925SRichard Henderson } 253229f5e925SRichard Henderson 2533c896fe29Sbellard /* sort the constraints (XXX: this is just an heuristic) */ 2534c896fe29Sbellard sort_constraints(def, 0, def->nb_oargs); 2535c896fe29Sbellard sort_constraints(def, def->nb_oargs, def->nb_iargs); 2536c896fe29Sbellard } 2537c896fe29Sbellard } 2538c896fe29Sbellard 25390c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op) 25400c627cdcSRichard Henderson { 2541d88a117eSRichard Henderson TCGLabel *label; 2542d88a117eSRichard Henderson 2543d88a117eSRichard Henderson switch (op->opc) { 2544d88a117eSRichard Henderson case INDEX_op_br: 2545d88a117eSRichard Henderson label = arg_label(op->args[0]); 2546d88a117eSRichard Henderson label->refs--; 2547d88a117eSRichard Henderson break; 2548d88a117eSRichard Henderson case INDEX_op_brcond_i32: 2549d88a117eSRichard Henderson case INDEX_op_brcond_i64: 2550d88a117eSRichard Henderson label = arg_label(op->args[3]); 2551d88a117eSRichard Henderson label->refs--; 2552d88a117eSRichard Henderson break; 2553d88a117eSRichard Henderson case INDEX_op_brcond2_i32: 2554d88a117eSRichard Henderson label = arg_label(op->args[5]); 2555d88a117eSRichard Henderson label->refs--; 2556d88a117eSRichard Henderson break; 2557d88a117eSRichard Henderson default: 2558d88a117eSRichard Henderson break; 2559d88a117eSRichard Henderson } 2560d88a117eSRichard Henderson 256115fa08f8SRichard Henderson QTAILQ_REMOVE(&s->ops, op, link); 256215fa08f8SRichard Henderson QTAILQ_INSERT_TAIL(&s->free_ops, op, link); 2563abebf925SRichard Henderson s->nb_ops--; 25640c627cdcSRichard Henderson 25650c627cdcSRichard Henderson #ifdef CONFIG_PROFILER 2566d73415a3SStefan Hajnoczi qatomic_set(&s->prof.del_op_count, s->prof.del_op_count + 1); 25670c627cdcSRichard Henderson #endif 25680c627cdcSRichard Henderson } 25690c627cdcSRichard Henderson 2570a80cdd31SRichard Henderson void tcg_remove_ops_after(TCGOp *op) 2571a80cdd31SRichard Henderson { 2572a80cdd31SRichard Henderson TCGContext *s = tcg_ctx; 2573a80cdd31SRichard Henderson 2574a80cdd31SRichard Henderson while (true) { 2575a80cdd31SRichard Henderson TCGOp *last = tcg_last_op(); 2576a80cdd31SRichard Henderson if (last == op) { 2577a80cdd31SRichard Henderson return; 2578a80cdd31SRichard Henderson } 2579a80cdd31SRichard Henderson tcg_op_remove(s, last); 2580a80cdd31SRichard Henderson } 2581a80cdd31SRichard Henderson } 2582a80cdd31SRichard Henderson 2583d4478943SPhilippe Mathieu-Daudé static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs) 258415fa08f8SRichard Henderson { 258515fa08f8SRichard Henderson TCGContext *s = tcg_ctx; 2586cb10bc63SRichard Henderson TCGOp *op = NULL; 258715fa08f8SRichard Henderson 2588cb10bc63SRichard Henderson if (unlikely(!QTAILQ_EMPTY(&s->free_ops))) { 2589cb10bc63SRichard Henderson QTAILQ_FOREACH(op, &s->free_ops, link) { 2590cb10bc63SRichard Henderson if (nargs <= op->nargs) { 259115fa08f8SRichard Henderson QTAILQ_REMOVE(&s->free_ops, op, link); 2592cb10bc63SRichard Henderson nargs = op->nargs; 2593cb10bc63SRichard Henderson goto found; 259415fa08f8SRichard Henderson } 2595cb10bc63SRichard Henderson } 2596cb10bc63SRichard Henderson } 2597cb10bc63SRichard Henderson 2598cb10bc63SRichard Henderson /* Most opcodes have 3 or 4 operands: reduce fragmentation. */ 2599cb10bc63SRichard Henderson nargs = MAX(4, nargs); 2600cb10bc63SRichard Henderson op = tcg_malloc(sizeof(TCGOp) + sizeof(TCGArg) * nargs); 2601cb10bc63SRichard Henderson 2602cb10bc63SRichard Henderson found: 260315fa08f8SRichard Henderson memset(op, 0, offsetof(TCGOp, link)); 260415fa08f8SRichard Henderson op->opc = opc; 2605cb10bc63SRichard Henderson op->nargs = nargs; 260615fa08f8SRichard Henderson 2607cb10bc63SRichard Henderson /* Check for bitfield overflow. */ 2608cb10bc63SRichard Henderson tcg_debug_assert(op->nargs == nargs); 2609cb10bc63SRichard Henderson 2610cb10bc63SRichard Henderson s->nb_ops++; 261115fa08f8SRichard Henderson return op; 261215fa08f8SRichard Henderson } 261315fa08f8SRichard Henderson 2614d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_emit_op(TCGOpcode opc, unsigned nargs) 261515fa08f8SRichard Henderson { 2616d4478943SPhilippe Mathieu-Daudé TCGOp *op = tcg_op_alloc(opc, nargs); 261715fa08f8SRichard Henderson QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link); 261815fa08f8SRichard Henderson return op; 261915fa08f8SRichard Henderson } 262015fa08f8SRichard Henderson 2621d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op, 2622d4478943SPhilippe Mathieu-Daudé TCGOpcode opc, unsigned nargs) 26235a18407fSRichard Henderson { 2624d4478943SPhilippe Mathieu-Daudé TCGOp *new_op = tcg_op_alloc(opc, nargs); 262515fa08f8SRichard Henderson QTAILQ_INSERT_BEFORE(old_op, new_op, link); 26265a18407fSRichard Henderson return new_op; 26275a18407fSRichard Henderson } 26285a18407fSRichard Henderson 2629d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, 2630d4478943SPhilippe Mathieu-Daudé TCGOpcode opc, unsigned nargs) 26315a18407fSRichard Henderson { 2632d4478943SPhilippe Mathieu-Daudé TCGOp *new_op = tcg_op_alloc(opc, nargs); 263315fa08f8SRichard Henderson QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link); 26345a18407fSRichard Henderson return new_op; 26355a18407fSRichard Henderson } 26365a18407fSRichard Henderson 2637b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code. */ 26389bbee4c0SRichard Henderson static void __attribute__((noinline)) 26399bbee4c0SRichard Henderson reachable_code_pass(TCGContext *s) 2640b4fc67c7SRichard Henderson { 26414d89d0bbSRichard Henderson TCGOp *op, *op_next, *op_prev; 2642b4fc67c7SRichard Henderson bool dead = false; 2643b4fc67c7SRichard Henderson 2644b4fc67c7SRichard Henderson QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) { 2645b4fc67c7SRichard Henderson bool remove = dead; 2646b4fc67c7SRichard Henderson TCGLabel *label; 2647b4fc67c7SRichard Henderson 2648b4fc67c7SRichard Henderson switch (op->opc) { 2649b4fc67c7SRichard Henderson case INDEX_op_set_label: 2650b4fc67c7SRichard Henderson label = arg_label(op->args[0]); 26514d89d0bbSRichard Henderson 26524d89d0bbSRichard Henderson /* 26534d89d0bbSRichard Henderson * Optimization can fold conditional branches to unconditional. 26544d89d0bbSRichard Henderson * If we find a label which is preceded by an unconditional 26554d89d0bbSRichard Henderson * branch to next, remove the branch. We couldn't do this when 26564d89d0bbSRichard Henderson * processing the branch because any dead code between the branch 26574d89d0bbSRichard Henderson * and label had not yet been removed. 26584d89d0bbSRichard Henderson */ 26594d89d0bbSRichard Henderson op_prev = QTAILQ_PREV(op, link); 26604d89d0bbSRichard Henderson if (op_prev->opc == INDEX_op_br && 26614d89d0bbSRichard Henderson label == arg_label(op_prev->args[0])) { 26624d89d0bbSRichard Henderson tcg_op_remove(s, op_prev); 26634d89d0bbSRichard Henderson /* Fall through means insns become live again. */ 26644d89d0bbSRichard Henderson dead = false; 26654d89d0bbSRichard Henderson } 26664d89d0bbSRichard Henderson 2667b4fc67c7SRichard Henderson if (label->refs == 0) { 2668b4fc67c7SRichard Henderson /* 2669b4fc67c7SRichard Henderson * While there is an occasional backward branch, virtually 2670b4fc67c7SRichard Henderson * all branches generated by the translators are forward. 2671b4fc67c7SRichard Henderson * Which means that generally we will have already removed 2672b4fc67c7SRichard Henderson * all references to the label that will be, and there is 2673b4fc67c7SRichard Henderson * little to be gained by iterating. 2674b4fc67c7SRichard Henderson */ 2675b4fc67c7SRichard Henderson remove = true; 2676b4fc67c7SRichard Henderson } else { 2677b4fc67c7SRichard Henderson /* Once we see a label, insns become live again. */ 2678b4fc67c7SRichard Henderson dead = false; 2679b4fc67c7SRichard Henderson remove = false; 2680b4fc67c7SRichard Henderson } 2681b4fc67c7SRichard Henderson break; 2682b4fc67c7SRichard Henderson 2683b4fc67c7SRichard Henderson case INDEX_op_br: 2684b4fc67c7SRichard Henderson case INDEX_op_exit_tb: 2685b4fc67c7SRichard Henderson case INDEX_op_goto_ptr: 2686b4fc67c7SRichard Henderson /* Unconditional branches; everything following is dead. */ 2687b4fc67c7SRichard Henderson dead = true; 2688b4fc67c7SRichard Henderson break; 2689b4fc67c7SRichard Henderson 2690b4fc67c7SRichard Henderson case INDEX_op_call: 2691b4fc67c7SRichard Henderson /* Notice noreturn helper calls, raising exceptions. */ 269290163900SRichard Henderson if (tcg_call_flags(op) & TCG_CALL_NO_RETURN) { 2693b4fc67c7SRichard Henderson dead = true; 2694b4fc67c7SRichard Henderson } 2695b4fc67c7SRichard Henderson break; 2696b4fc67c7SRichard Henderson 2697b4fc67c7SRichard Henderson case INDEX_op_insn_start: 2698b4fc67c7SRichard Henderson /* Never remove -- we need to keep these for unwind. */ 2699b4fc67c7SRichard Henderson remove = false; 2700b4fc67c7SRichard Henderson break; 2701b4fc67c7SRichard Henderson 2702b4fc67c7SRichard Henderson default: 2703b4fc67c7SRichard Henderson break; 2704b4fc67c7SRichard Henderson } 2705b4fc67c7SRichard Henderson 2706b4fc67c7SRichard Henderson if (remove) { 2707b4fc67c7SRichard Henderson tcg_op_remove(s, op); 2708b4fc67c7SRichard Henderson } 2709b4fc67c7SRichard Henderson } 2710b4fc67c7SRichard Henderson } 2711b4fc67c7SRichard Henderson 2712c70fbf0aSRichard Henderson #define TS_DEAD 1 2713c70fbf0aSRichard Henderson #define TS_MEM 2 2714c70fbf0aSRichard Henderson 27155a18407fSRichard Henderson #define IS_DEAD_ARG(n) (arg_life & (DEAD_ARG << (n))) 27165a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n))) 27175a18407fSRichard Henderson 271825f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp. */ 271925f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts) 272025f49c5fSRichard Henderson { 272125f49c5fSRichard Henderson return ts->state_ptr; 272225f49c5fSRichard Henderson } 272325f49c5fSRichard Henderson 272425f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the 272525f49c5fSRichard Henderson * maximal regset for its type. 272625f49c5fSRichard Henderson */ 272725f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts) 272825f49c5fSRichard Henderson { 272925f49c5fSRichard Henderson *la_temp_pref(ts) 273025f49c5fSRichard Henderson = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]); 273125f49c5fSRichard Henderson } 273225f49c5fSRichard Henderson 27339c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals 27349c43b68dSAurelien Jarno should be in memory. */ 27352616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt) 2736c896fe29Sbellard { 2737b83eabeaSRichard Henderson int i; 2738b83eabeaSRichard Henderson 2739b83eabeaSRichard Henderson for (i = 0; i < ng; ++i) { 2740b83eabeaSRichard Henderson s->temps[i].state = TS_DEAD | TS_MEM; 274125f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 2742b83eabeaSRichard Henderson } 2743b83eabeaSRichard Henderson for (i = ng; i < nt; ++i) { 2744b83eabeaSRichard Henderson s->temps[i].state = TS_DEAD; 274525f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 2746b83eabeaSRichard Henderson } 2747c896fe29Sbellard } 2748c896fe29Sbellard 27499c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals 27509c43b68dSAurelien Jarno and local temps should be in memory. */ 27512616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt) 2752641d5fbeSbellard { 2753b83eabeaSRichard Henderson int i; 2754641d5fbeSbellard 2755ee17db83SRichard Henderson for (i = 0; i < nt; ++i) { 2756ee17db83SRichard Henderson TCGTemp *ts = &s->temps[i]; 2757ee17db83SRichard Henderson int state; 2758ee17db83SRichard Henderson 2759ee17db83SRichard Henderson switch (ts->kind) { 2760ee17db83SRichard Henderson case TEMP_FIXED: 2761ee17db83SRichard Henderson case TEMP_GLOBAL: 2762f57c6915SRichard Henderson case TEMP_TB: 2763ee17db83SRichard Henderson state = TS_DEAD | TS_MEM; 2764ee17db83SRichard Henderson break; 2765ee17db83SRichard Henderson case TEMP_NORMAL: 2766c7482438SRichard Henderson case TEMP_EBB: 2767c0522136SRichard Henderson case TEMP_CONST: 2768ee17db83SRichard Henderson state = TS_DEAD; 2769ee17db83SRichard Henderson break; 2770ee17db83SRichard Henderson default: 2771ee17db83SRichard Henderson g_assert_not_reached(); 2772c70fbf0aSRichard Henderson } 2773ee17db83SRichard Henderson ts->state = state; 2774ee17db83SRichard Henderson la_reset_pref(ts); 2775641d5fbeSbellard } 2776641d5fbeSbellard } 2777641d5fbeSbellard 2778f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory. */ 2779f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng) 2780f65a061cSRichard Henderson { 2781f65a061cSRichard Henderson int i; 2782f65a061cSRichard Henderson 2783f65a061cSRichard Henderson for (i = 0; i < ng; ++i) { 278425f49c5fSRichard Henderson int state = s->temps[i].state; 278525f49c5fSRichard Henderson s->temps[i].state = state | TS_MEM; 278625f49c5fSRichard Henderson if (state == TS_DEAD) { 278725f49c5fSRichard Henderson /* If the global was previously dead, reset prefs. */ 278825f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 278925f49c5fSRichard Henderson } 2790f65a061cSRichard Henderson } 2791f65a061cSRichard Henderson } 2792f65a061cSRichard Henderson 2793b4cb76e6SRichard Henderson /* 2794c7482438SRichard Henderson * liveness analysis: conditional branch: all temps are dead unless 2795c7482438SRichard Henderson * explicitly live-across-conditional-branch, globals and local temps 2796c7482438SRichard Henderson * should be synced. 2797b4cb76e6SRichard Henderson */ 2798b4cb76e6SRichard Henderson static void la_bb_sync(TCGContext *s, int ng, int nt) 2799b4cb76e6SRichard Henderson { 2800b4cb76e6SRichard Henderson la_global_sync(s, ng); 2801b4cb76e6SRichard Henderson 2802b4cb76e6SRichard Henderson for (int i = ng; i < nt; ++i) { 2803c0522136SRichard Henderson TCGTemp *ts = &s->temps[i]; 2804c0522136SRichard Henderson int state; 2805c0522136SRichard Henderson 2806c0522136SRichard Henderson switch (ts->kind) { 2807f57c6915SRichard Henderson case TEMP_TB: 2808c0522136SRichard Henderson state = ts->state; 2809c0522136SRichard Henderson ts->state = state | TS_MEM; 2810b4cb76e6SRichard Henderson if (state != TS_DEAD) { 2811b4cb76e6SRichard Henderson continue; 2812b4cb76e6SRichard Henderson } 2813c0522136SRichard Henderson break; 2814c0522136SRichard Henderson case TEMP_NORMAL: 2815b4cb76e6SRichard Henderson s->temps[i].state = TS_DEAD; 2816c0522136SRichard Henderson break; 2817c7482438SRichard Henderson case TEMP_EBB: 2818c0522136SRichard Henderson case TEMP_CONST: 2819c0522136SRichard Henderson continue; 2820c0522136SRichard Henderson default: 2821c0522136SRichard Henderson g_assert_not_reached(); 2822b4cb76e6SRichard Henderson } 2823b4cb76e6SRichard Henderson la_reset_pref(&s->temps[i]); 2824b4cb76e6SRichard Henderson } 2825b4cb76e6SRichard Henderson } 2826b4cb76e6SRichard Henderson 2827f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill. */ 2828f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng) 2829f65a061cSRichard Henderson { 2830f65a061cSRichard Henderson int i; 2831f65a061cSRichard Henderson 2832f65a061cSRichard Henderson for (i = 0; i < ng; i++) { 2833f65a061cSRichard Henderson s->temps[i].state = TS_DEAD | TS_MEM; 283425f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 283525f49c5fSRichard Henderson } 283625f49c5fSRichard Henderson } 283725f49c5fSRichard Henderson 283825f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls. */ 283925f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt) 284025f49c5fSRichard Henderson { 284125f49c5fSRichard Henderson TCGRegSet mask = ~tcg_target_call_clobber_regs; 284225f49c5fSRichard Henderson int i; 284325f49c5fSRichard Henderson 284425f49c5fSRichard Henderson for (i = 0; i < nt; i++) { 284525f49c5fSRichard Henderson TCGTemp *ts = &s->temps[i]; 284625f49c5fSRichard Henderson if (!(ts->state & TS_DEAD)) { 284725f49c5fSRichard Henderson TCGRegSet *pset = la_temp_pref(ts); 284825f49c5fSRichard Henderson TCGRegSet set = *pset; 284925f49c5fSRichard Henderson 285025f49c5fSRichard Henderson set &= mask; 285125f49c5fSRichard Henderson /* If the combination is not possible, restart. */ 285225f49c5fSRichard Henderson if (set == 0) { 285325f49c5fSRichard Henderson set = tcg_target_available_regs[ts->type] & mask; 285425f49c5fSRichard Henderson } 285525f49c5fSRichard Henderson *pset = set; 285625f49c5fSRichard Henderson } 2857f65a061cSRichard Henderson } 2858f65a061cSRichard Henderson } 2859f65a061cSRichard Henderson 2860*874b8574SRichard Henderson /* 2861*874b8574SRichard Henderson * Liveness analysis: Verify the lifetime of TEMP_TB, and reduce 2862*874b8574SRichard Henderson * to TEMP_EBB, if possible. 2863*874b8574SRichard Henderson */ 2864*874b8574SRichard Henderson static void __attribute__((noinline)) 2865*874b8574SRichard Henderson liveness_pass_0(TCGContext *s) 2866*874b8574SRichard Henderson { 2867*874b8574SRichard Henderson void * const multiple_ebb = (void *)(uintptr_t)-1; 2868*874b8574SRichard Henderson int nb_temps = s->nb_temps; 2869*874b8574SRichard Henderson TCGOp *op, *ebb; 2870*874b8574SRichard Henderson 2871*874b8574SRichard Henderson for (int i = s->nb_globals; i < nb_temps; ++i) { 2872*874b8574SRichard Henderson s->temps[i].state_ptr = NULL; 2873*874b8574SRichard Henderson } 2874*874b8574SRichard Henderson 2875*874b8574SRichard Henderson /* 2876*874b8574SRichard Henderson * Represent each EBB by the op at which it begins. In the case of 2877*874b8574SRichard Henderson * the first EBB, this is the first op, otherwise it is a label. 2878*874b8574SRichard Henderson * Collect the uses of each TEMP_TB: NULL for unused, EBB for use 2879*874b8574SRichard Henderson * within a single EBB, else MULTIPLE_EBB. 2880*874b8574SRichard Henderson */ 2881*874b8574SRichard Henderson ebb = QTAILQ_FIRST(&s->ops); 2882*874b8574SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 2883*874b8574SRichard Henderson const TCGOpDef *def; 2884*874b8574SRichard Henderson int nb_oargs, nb_iargs; 2885*874b8574SRichard Henderson 2886*874b8574SRichard Henderson switch (op->opc) { 2887*874b8574SRichard Henderson case INDEX_op_set_label: 2888*874b8574SRichard Henderson ebb = op; 2889*874b8574SRichard Henderson continue; 2890*874b8574SRichard Henderson case INDEX_op_discard: 2891*874b8574SRichard Henderson continue; 2892*874b8574SRichard Henderson case INDEX_op_call: 2893*874b8574SRichard Henderson nb_oargs = TCGOP_CALLO(op); 2894*874b8574SRichard Henderson nb_iargs = TCGOP_CALLI(op); 2895*874b8574SRichard Henderson break; 2896*874b8574SRichard Henderson default: 2897*874b8574SRichard Henderson def = &tcg_op_defs[op->opc]; 2898*874b8574SRichard Henderson nb_oargs = def->nb_oargs; 2899*874b8574SRichard Henderson nb_iargs = def->nb_iargs; 2900*874b8574SRichard Henderson break; 2901*874b8574SRichard Henderson } 2902*874b8574SRichard Henderson 2903*874b8574SRichard Henderson for (int i = 0; i < nb_oargs + nb_iargs; ++i) { 2904*874b8574SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]); 2905*874b8574SRichard Henderson 2906*874b8574SRichard Henderson if (ts->kind != TEMP_TB) { 2907*874b8574SRichard Henderson continue; 2908*874b8574SRichard Henderson } 2909*874b8574SRichard Henderson if (ts->state_ptr == NULL) { 2910*874b8574SRichard Henderson ts->state_ptr = ebb; 2911*874b8574SRichard Henderson } else if (ts->state_ptr != ebb) { 2912*874b8574SRichard Henderson ts->state_ptr = multiple_ebb; 2913*874b8574SRichard Henderson } 2914*874b8574SRichard Henderson } 2915*874b8574SRichard Henderson } 2916*874b8574SRichard Henderson 2917*874b8574SRichard Henderson /* 2918*874b8574SRichard Henderson * For TEMP_TB that turned out not to be used beyond one EBB, 2919*874b8574SRichard Henderson * reduce the liveness to TEMP_EBB. 2920*874b8574SRichard Henderson */ 2921*874b8574SRichard Henderson for (int i = s->nb_globals; i < nb_temps; ++i) { 2922*874b8574SRichard Henderson TCGTemp *ts = &s->temps[i]; 2923*874b8574SRichard Henderson if (ts->kind == TEMP_TB && ts->state_ptr != multiple_ebb) { 2924*874b8574SRichard Henderson ts->kind = TEMP_EBB; 2925*874b8574SRichard Henderson } 2926*874b8574SRichard Henderson } 2927*874b8574SRichard Henderson } 2928*874b8574SRichard Henderson 2929a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a 2930c896fe29Sbellard given input arguments is dead. Instructions updating dead 2931c896fe29Sbellard temporaries are removed. */ 29329bbee4c0SRichard Henderson static void __attribute__((noinline)) 29339bbee4c0SRichard Henderson liveness_pass_1(TCGContext *s) 2934c896fe29Sbellard { 2935c70fbf0aSRichard Henderson int nb_globals = s->nb_globals; 29362616c808SRichard Henderson int nb_temps = s->nb_temps; 293715fa08f8SRichard Henderson TCGOp *op, *op_prev; 293825f49c5fSRichard Henderson TCGRegSet *prefs; 293925f49c5fSRichard Henderson int i; 294025f49c5fSRichard Henderson 294125f49c5fSRichard Henderson prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps); 294225f49c5fSRichard Henderson for (i = 0; i < nb_temps; ++i) { 294325f49c5fSRichard Henderson s->temps[i].state_ptr = prefs + i; 294425f49c5fSRichard Henderson } 2945c896fe29Sbellard 2946ae36a246SRichard Henderson /* ??? Should be redundant with the exit_tb that ends the TB. */ 29472616c808SRichard Henderson la_func_end(s, nb_globals, nb_temps); 2948c896fe29Sbellard 2949eae3eb3eSPaolo Bonzini QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) { 295025f49c5fSRichard Henderson int nb_iargs, nb_oargs; 2951c45cb8bbSRichard Henderson TCGOpcode opc_new, opc_new2; 2952c45cb8bbSRichard Henderson bool have_opc_new2; 2953a1b3c48dSRichard Henderson TCGLifeData arg_life = 0; 295425f49c5fSRichard Henderson TCGTemp *ts; 2955c45cb8bbSRichard Henderson TCGOpcode opc = op->opc; 2956c45cb8bbSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 2957c45cb8bbSRichard Henderson 2958c45cb8bbSRichard Henderson switch (opc) { 2959c896fe29Sbellard case INDEX_op_call: 2960c6e113f5Sbellard { 296139004a71SRichard Henderson const TCGHelperInfo *info = tcg_call_info(op); 296239004a71SRichard Henderson int call_flags = tcg_call_flags(op); 2963c6e113f5Sbellard 2964cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 2965cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 2966c6e113f5Sbellard 2967c45cb8bbSRichard Henderson /* pure functions can be removed if their result is unused */ 296878505279SAurelien Jarno if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) { 2969c6e113f5Sbellard for (i = 0; i < nb_oargs; i++) { 297025f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 297125f49c5fSRichard Henderson if (ts->state != TS_DEAD) { 2972c6e113f5Sbellard goto do_not_remove_call; 2973c6e113f5Sbellard } 29749c43b68dSAurelien Jarno } 2975c45cb8bbSRichard Henderson goto do_remove; 2976152c35aaSRichard Henderson } 2977c6e113f5Sbellard do_not_remove_call: 2978c896fe29Sbellard 297925f49c5fSRichard Henderson /* Output args are dead. */ 2980c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 298125f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 298225f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 2983a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 29846b64b624SAurelien Jarno } 298525f49c5fSRichard Henderson if (ts->state & TS_MEM) { 2986a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i; 29879c43b68dSAurelien Jarno } 298825f49c5fSRichard Henderson ts->state = TS_DEAD; 298925f49c5fSRichard Henderson la_reset_pref(ts); 2990c896fe29Sbellard } 2991c896fe29Sbellard 299231fd884bSRichard Henderson /* Not used -- it will be tcg_target_call_oarg_reg(). */ 299331fd884bSRichard Henderson memset(op->output_pref, 0, sizeof(op->output_pref)); 299431fd884bSRichard Henderson 299578505279SAurelien Jarno if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS | 299678505279SAurelien Jarno TCG_CALL_NO_READ_GLOBALS))) { 2997f65a061cSRichard Henderson la_global_kill(s, nb_globals); 2998c70fbf0aSRichard Henderson } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) { 2999f65a061cSRichard Henderson la_global_sync(s, nb_globals); 3000b9c18f56Saurel32 } 3001c896fe29Sbellard 300225f49c5fSRichard Henderson /* Record arguments that die in this helper. */ 3003866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 300425f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 300539004a71SRichard Henderson if (ts->state & TS_DEAD) { 3006a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 3007c896fe29Sbellard } 3008c896fe29Sbellard } 300925f49c5fSRichard Henderson 301025f49c5fSRichard Henderson /* For all live registers, remove call-clobbered prefs. */ 301125f49c5fSRichard Henderson la_cross_call(s, nb_temps); 301225f49c5fSRichard Henderson 301339004a71SRichard Henderson /* 301439004a71SRichard Henderson * Input arguments are live for preceding opcodes. 301539004a71SRichard Henderson * 301639004a71SRichard Henderson * For those arguments that die, and will be allocated in 301739004a71SRichard Henderson * registers, clear the register set for that arg, to be 301839004a71SRichard Henderson * filled in below. For args that will be on the stack, 301939004a71SRichard Henderson * reset to any available reg. Process arguments in reverse 302039004a71SRichard Henderson * order so that if a temp is used more than once, the stack 302139004a71SRichard Henderson * reset to max happens before the register reset to 0. 302225f49c5fSRichard Henderson */ 302339004a71SRichard Henderson for (i = nb_iargs - 1; i >= 0; i--) { 302439004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i]; 302539004a71SRichard Henderson ts = arg_temp(op->args[nb_oargs + i]); 302639004a71SRichard Henderson 302739004a71SRichard Henderson if (ts->state & TS_DEAD) { 302839004a71SRichard Henderson switch (loc->kind) { 302939004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 303039004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 303139004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 303239004a71SRichard Henderson if (REG_P(loc)) { 303339004a71SRichard Henderson *la_temp_pref(ts) = 0; 303439004a71SRichard Henderson break; 303539004a71SRichard Henderson } 303639004a71SRichard Henderson /* fall through */ 303739004a71SRichard Henderson default: 303839004a71SRichard Henderson *la_temp_pref(ts) = 303939004a71SRichard Henderson tcg_target_available_regs[ts->type]; 304039004a71SRichard Henderson break; 304139004a71SRichard Henderson } 304225f49c5fSRichard Henderson ts->state &= ~TS_DEAD; 304325f49c5fSRichard Henderson } 304425f49c5fSRichard Henderson } 304525f49c5fSRichard Henderson 304639004a71SRichard Henderson /* 304739004a71SRichard Henderson * For each input argument, add its input register to prefs. 304839004a71SRichard Henderson * If a temp is used once, this produces a single set bit; 304939004a71SRichard Henderson * if a temp is used multiple times, this produces a set. 305039004a71SRichard Henderson */ 305139004a71SRichard Henderson for (i = 0; i < nb_iargs; i++) { 305239004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i]; 305339004a71SRichard Henderson ts = arg_temp(op->args[nb_oargs + i]); 305439004a71SRichard Henderson 305539004a71SRichard Henderson switch (loc->kind) { 305639004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 305739004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 305839004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 305939004a71SRichard Henderson if (REG_P(loc)) { 306025f49c5fSRichard Henderson tcg_regset_set_reg(*la_temp_pref(ts), 306139004a71SRichard Henderson tcg_target_call_iarg_regs[loc->arg_slot]); 306239004a71SRichard Henderson } 306339004a71SRichard Henderson break; 306439004a71SRichard Henderson default: 306539004a71SRichard Henderson break; 3066c70fbf0aSRichard Henderson } 3067c19f47bfSAurelien Jarno } 3068c6e113f5Sbellard } 3069c896fe29Sbellard break; 3070765b842aSRichard Henderson case INDEX_op_insn_start: 3071c896fe29Sbellard break; 30725ff9d6a4Sbellard case INDEX_op_discard: 30735ff9d6a4Sbellard /* mark the temporary as dead */ 307425f49c5fSRichard Henderson ts = arg_temp(op->args[0]); 307525f49c5fSRichard Henderson ts->state = TS_DEAD; 307625f49c5fSRichard Henderson la_reset_pref(ts); 30775ff9d6a4Sbellard break; 30781305c451SRichard Henderson 30791305c451SRichard Henderson case INDEX_op_add2_i32: 3080c45cb8bbSRichard Henderson opc_new = INDEX_op_add_i32; 3081f1fae40cSRichard Henderson goto do_addsub2; 30821305c451SRichard Henderson case INDEX_op_sub2_i32: 3083c45cb8bbSRichard Henderson opc_new = INDEX_op_sub_i32; 3084f1fae40cSRichard Henderson goto do_addsub2; 3085f1fae40cSRichard Henderson case INDEX_op_add2_i64: 3086c45cb8bbSRichard Henderson opc_new = INDEX_op_add_i64; 3087f1fae40cSRichard Henderson goto do_addsub2; 3088f1fae40cSRichard Henderson case INDEX_op_sub2_i64: 3089c45cb8bbSRichard Henderson opc_new = INDEX_op_sub_i64; 3090f1fae40cSRichard Henderson do_addsub2: 30911305c451SRichard Henderson nb_iargs = 4; 30921305c451SRichard Henderson nb_oargs = 2; 30931305c451SRichard Henderson /* Test if the high part of the operation is dead, but not 30941305c451SRichard Henderson the low part. The result can be optimized to a simple 30951305c451SRichard Henderson add or sub. This happens often for x86_64 guest when the 30961305c451SRichard Henderson cpu mode is set to 32 bit. */ 3097b83eabeaSRichard Henderson if (arg_temp(op->args[1])->state == TS_DEAD) { 3098b83eabeaSRichard Henderson if (arg_temp(op->args[0])->state == TS_DEAD) { 30991305c451SRichard Henderson goto do_remove; 31001305c451SRichard Henderson } 3101c45cb8bbSRichard Henderson /* Replace the opcode and adjust the args in place, 3102c45cb8bbSRichard Henderson leaving 3 unused args at the end. */ 3103c45cb8bbSRichard Henderson op->opc = opc = opc_new; 3104efee3746SRichard Henderson op->args[1] = op->args[2]; 3105efee3746SRichard Henderson op->args[2] = op->args[4]; 31061305c451SRichard Henderson /* Fall through and mark the single-word operation live. */ 31071305c451SRichard Henderson nb_iargs = 2; 31081305c451SRichard Henderson nb_oargs = 1; 31091305c451SRichard Henderson } 31101305c451SRichard Henderson goto do_not_remove; 31111305c451SRichard Henderson 31121414968aSRichard Henderson case INDEX_op_mulu2_i32: 3113c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i32; 3114c45cb8bbSRichard Henderson opc_new2 = INDEX_op_muluh_i32; 3115c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_muluh_i32; 311603271524SRichard Henderson goto do_mul2; 3117f1fae40cSRichard Henderson case INDEX_op_muls2_i32: 3118c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i32; 3119c45cb8bbSRichard Henderson opc_new2 = INDEX_op_mulsh_i32; 3120c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_mulsh_i32; 3121f1fae40cSRichard Henderson goto do_mul2; 3122f1fae40cSRichard Henderson case INDEX_op_mulu2_i64: 3123c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i64; 3124c45cb8bbSRichard Henderson opc_new2 = INDEX_op_muluh_i64; 3125c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_muluh_i64; 312603271524SRichard Henderson goto do_mul2; 3127f1fae40cSRichard Henderson case INDEX_op_muls2_i64: 3128c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i64; 3129c45cb8bbSRichard Henderson opc_new2 = INDEX_op_mulsh_i64; 3130c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_mulsh_i64; 313103271524SRichard Henderson goto do_mul2; 3132f1fae40cSRichard Henderson do_mul2: 31331414968aSRichard Henderson nb_iargs = 2; 31341414968aSRichard Henderson nb_oargs = 2; 3135b83eabeaSRichard Henderson if (arg_temp(op->args[1])->state == TS_DEAD) { 3136b83eabeaSRichard Henderson if (arg_temp(op->args[0])->state == TS_DEAD) { 313703271524SRichard Henderson /* Both parts of the operation are dead. */ 31381414968aSRichard Henderson goto do_remove; 31391414968aSRichard Henderson } 314003271524SRichard Henderson /* The high part of the operation is dead; generate the low. */ 3141c45cb8bbSRichard Henderson op->opc = opc = opc_new; 3142efee3746SRichard Henderson op->args[1] = op->args[2]; 3143efee3746SRichard Henderson op->args[2] = op->args[3]; 3144b83eabeaSRichard Henderson } else if (arg_temp(op->args[0])->state == TS_DEAD && have_opc_new2) { 314503271524SRichard Henderson /* The low part of the operation is dead; generate the high. */ 3146c45cb8bbSRichard Henderson op->opc = opc = opc_new2; 3147efee3746SRichard Henderson op->args[0] = op->args[1]; 3148efee3746SRichard Henderson op->args[1] = op->args[2]; 3149efee3746SRichard Henderson op->args[2] = op->args[3]; 315003271524SRichard Henderson } else { 315103271524SRichard Henderson goto do_not_remove; 315203271524SRichard Henderson } 315303271524SRichard Henderson /* Mark the single-word operation live. */ 31541414968aSRichard Henderson nb_oargs = 1; 31551414968aSRichard Henderson goto do_not_remove; 31561414968aSRichard Henderson 3157c896fe29Sbellard default: 31581305c451SRichard Henderson /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */ 3159c896fe29Sbellard nb_iargs = def->nb_iargs; 3160c896fe29Sbellard nb_oargs = def->nb_oargs; 3161c896fe29Sbellard 3162c896fe29Sbellard /* Test if the operation can be removed because all 31635ff9d6a4Sbellard its outputs are dead. We assume that nb_oargs == 0 31645ff9d6a4Sbellard implies side effects */ 31655ff9d6a4Sbellard if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) { 3166c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 3167b83eabeaSRichard Henderson if (arg_temp(op->args[i])->state != TS_DEAD) { 3168c896fe29Sbellard goto do_not_remove; 3169c896fe29Sbellard } 31709c43b68dSAurelien Jarno } 3171152c35aaSRichard Henderson goto do_remove; 3172152c35aaSRichard Henderson } 3173152c35aaSRichard Henderson goto do_not_remove; 3174152c35aaSRichard Henderson 31751305c451SRichard Henderson do_remove: 31760c627cdcSRichard Henderson tcg_op_remove(s, op); 3177152c35aaSRichard Henderson break; 3178152c35aaSRichard Henderson 3179c896fe29Sbellard do_not_remove: 3180c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 318125f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 318225f49c5fSRichard Henderson 318325f49c5fSRichard Henderson /* Remember the preference of the uses that followed. */ 318431fd884bSRichard Henderson if (i < ARRAY_SIZE(op->output_pref)) { 318525f49c5fSRichard Henderson op->output_pref[i] = *la_temp_pref(ts); 318631fd884bSRichard Henderson } 318725f49c5fSRichard Henderson 318825f49c5fSRichard Henderson /* Output args are dead. */ 318925f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 3190a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 31916b64b624SAurelien Jarno } 319225f49c5fSRichard Henderson if (ts->state & TS_MEM) { 3193a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i; 31949c43b68dSAurelien Jarno } 319525f49c5fSRichard Henderson ts->state = TS_DEAD; 319625f49c5fSRichard Henderson la_reset_pref(ts); 3197c896fe29Sbellard } 3198c896fe29Sbellard 319925f49c5fSRichard Henderson /* If end of basic block, update. */ 3200ae36a246SRichard Henderson if (def->flags & TCG_OPF_BB_EXIT) { 3201ae36a246SRichard Henderson la_func_end(s, nb_globals, nb_temps); 3202b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_COND_BRANCH) { 3203b4cb76e6SRichard Henderson la_bb_sync(s, nb_globals, nb_temps); 3204ae36a246SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 32052616c808SRichard Henderson la_bb_end(s, nb_globals, nb_temps); 32063d5c5f87SAurelien Jarno } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { 3207f65a061cSRichard Henderson la_global_sync(s, nb_globals); 320825f49c5fSRichard Henderson if (def->flags & TCG_OPF_CALL_CLOBBER) { 320925f49c5fSRichard Henderson la_cross_call(s, nb_temps); 321025f49c5fSRichard Henderson } 3211c896fe29Sbellard } 3212c896fe29Sbellard 321325f49c5fSRichard Henderson /* Record arguments that die in this opcode. */ 3214866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 321525f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 321625f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 3217a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 3218c896fe29Sbellard } 3219c19f47bfSAurelien Jarno } 322025f49c5fSRichard Henderson 322125f49c5fSRichard Henderson /* Input arguments are live for preceding opcodes. */ 3222c19f47bfSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 322325f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 322425f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 322525f49c5fSRichard Henderson /* For operands that were dead, initially allow 322625f49c5fSRichard Henderson all regs for the type. */ 322725f49c5fSRichard Henderson *la_temp_pref(ts) = tcg_target_available_regs[ts->type]; 322825f49c5fSRichard Henderson ts->state &= ~TS_DEAD; 322925f49c5fSRichard Henderson } 323025f49c5fSRichard Henderson } 323125f49c5fSRichard Henderson 323225f49c5fSRichard Henderson /* Incorporate constraints for this operand. */ 323325f49c5fSRichard Henderson switch (opc) { 323425f49c5fSRichard Henderson case INDEX_op_mov_i32: 323525f49c5fSRichard Henderson case INDEX_op_mov_i64: 323625f49c5fSRichard Henderson /* Note that these are TCG_OPF_NOT_PRESENT and do not 323725f49c5fSRichard Henderson have proper constraints. That said, special case 323825f49c5fSRichard Henderson moves to propagate preferences backward. */ 323925f49c5fSRichard Henderson if (IS_DEAD_ARG(1)) { 324025f49c5fSRichard Henderson *la_temp_pref(arg_temp(op->args[0])) 324125f49c5fSRichard Henderson = *la_temp_pref(arg_temp(op->args[1])); 324225f49c5fSRichard Henderson } 324325f49c5fSRichard Henderson break; 324425f49c5fSRichard Henderson 324525f49c5fSRichard Henderson default: 324625f49c5fSRichard Henderson for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 324725f49c5fSRichard Henderson const TCGArgConstraint *ct = &def->args_ct[i]; 324825f49c5fSRichard Henderson TCGRegSet set, *pset; 324925f49c5fSRichard Henderson 325025f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 325125f49c5fSRichard Henderson pset = la_temp_pref(ts); 325225f49c5fSRichard Henderson set = *pset; 325325f49c5fSRichard Henderson 32549be0d080SRichard Henderson set &= ct->regs; 3255bc2b17e6SRichard Henderson if (ct->ialias) { 325631fd884bSRichard Henderson set &= output_pref(op, ct->alias_index); 325725f49c5fSRichard Henderson } 325825f49c5fSRichard Henderson /* If the combination is not possible, restart. */ 325925f49c5fSRichard Henderson if (set == 0) { 32609be0d080SRichard Henderson set = ct->regs; 326125f49c5fSRichard Henderson } 326225f49c5fSRichard Henderson *pset = set; 326325f49c5fSRichard Henderson } 326425f49c5fSRichard Henderson break; 3265c896fe29Sbellard } 3266c896fe29Sbellard break; 3267c896fe29Sbellard } 3268bee158cbSRichard Henderson op->life = arg_life; 3269c896fe29Sbellard } 32701ff0a2c5SEvgeny Voevodin } 3271c896fe29Sbellard 32725a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries. */ 32739bbee4c0SRichard Henderson static bool __attribute__((noinline)) 32749bbee4c0SRichard Henderson liveness_pass_2(TCGContext *s) 32755a18407fSRichard Henderson { 32765a18407fSRichard Henderson int nb_globals = s->nb_globals; 327715fa08f8SRichard Henderson int nb_temps, i; 32785a18407fSRichard Henderson bool changes = false; 327915fa08f8SRichard Henderson TCGOp *op, *op_next; 32805a18407fSRichard Henderson 32815a18407fSRichard Henderson /* Create a temporary for each indirect global. */ 32825a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 32835a18407fSRichard Henderson TCGTemp *its = &s->temps[i]; 32845a18407fSRichard Henderson if (its->indirect_reg) { 32855a18407fSRichard Henderson TCGTemp *dts = tcg_temp_alloc(s); 32865a18407fSRichard Henderson dts->type = its->type; 32875a18407fSRichard Henderson dts->base_type = its->base_type; 3288e1e64652SRichard Henderson dts->temp_subindex = its->temp_subindex; 3289c7482438SRichard Henderson dts->kind = TEMP_EBB; 3290b83eabeaSRichard Henderson its->state_ptr = dts; 3291b83eabeaSRichard Henderson } else { 3292b83eabeaSRichard Henderson its->state_ptr = NULL; 32935a18407fSRichard Henderson } 3294b83eabeaSRichard Henderson /* All globals begin dead. */ 3295b83eabeaSRichard Henderson its->state = TS_DEAD; 32965a18407fSRichard Henderson } 3297b83eabeaSRichard Henderson for (nb_temps = s->nb_temps; i < nb_temps; ++i) { 3298b83eabeaSRichard Henderson TCGTemp *its = &s->temps[i]; 3299b83eabeaSRichard Henderson its->state_ptr = NULL; 3300b83eabeaSRichard Henderson its->state = TS_DEAD; 3301b83eabeaSRichard Henderson } 33025a18407fSRichard Henderson 330315fa08f8SRichard Henderson QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) { 33045a18407fSRichard Henderson TCGOpcode opc = op->opc; 33055a18407fSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 33065a18407fSRichard Henderson TCGLifeData arg_life = op->life; 33075a18407fSRichard Henderson int nb_iargs, nb_oargs, call_flags; 3308b83eabeaSRichard Henderson TCGTemp *arg_ts, *dir_ts; 33095a18407fSRichard Henderson 33105a18407fSRichard Henderson if (opc == INDEX_op_call) { 3311cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 3312cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 331390163900SRichard Henderson call_flags = tcg_call_flags(op); 33145a18407fSRichard Henderson } else { 33155a18407fSRichard Henderson nb_iargs = def->nb_iargs; 33165a18407fSRichard Henderson nb_oargs = def->nb_oargs; 33175a18407fSRichard Henderson 33185a18407fSRichard Henderson /* Set flags similar to how calls require. */ 3319b4cb76e6SRichard Henderson if (def->flags & TCG_OPF_COND_BRANCH) { 3320b4cb76e6SRichard Henderson /* Like reading globals: sync_globals */ 3321b4cb76e6SRichard Henderson call_flags = TCG_CALL_NO_WRITE_GLOBALS; 3322b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 33235a18407fSRichard Henderson /* Like writing globals: save_globals */ 33245a18407fSRichard Henderson call_flags = 0; 33255a18407fSRichard Henderson } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { 33265a18407fSRichard Henderson /* Like reading globals: sync_globals */ 33275a18407fSRichard Henderson call_flags = TCG_CALL_NO_WRITE_GLOBALS; 33285a18407fSRichard Henderson } else { 33295a18407fSRichard Henderson /* No effect on globals. */ 33305a18407fSRichard Henderson call_flags = (TCG_CALL_NO_READ_GLOBALS | 33315a18407fSRichard Henderson TCG_CALL_NO_WRITE_GLOBALS); 33325a18407fSRichard Henderson } 33335a18407fSRichard Henderson } 33345a18407fSRichard Henderson 33355a18407fSRichard Henderson /* Make sure that input arguments are available. */ 33365a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 3337b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 3338b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 3339b83eabeaSRichard Henderson if (dir_ts && arg_ts->state == TS_DEAD) { 3340b83eabeaSRichard Henderson TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32 33415a18407fSRichard Henderson ? INDEX_op_ld_i32 33425a18407fSRichard Henderson : INDEX_op_ld_i64); 3343d4478943SPhilippe Mathieu-Daudé TCGOp *lop = tcg_op_insert_before(s, op, lopc, 3); 33445a18407fSRichard Henderson 3345b83eabeaSRichard Henderson lop->args[0] = temp_arg(dir_ts); 3346b83eabeaSRichard Henderson lop->args[1] = temp_arg(arg_ts->mem_base); 3347b83eabeaSRichard Henderson lop->args[2] = arg_ts->mem_offset; 33485a18407fSRichard Henderson 33495a18407fSRichard Henderson /* Loaded, but synced with memory. */ 3350b83eabeaSRichard Henderson arg_ts->state = TS_MEM; 33515a18407fSRichard Henderson } 33525a18407fSRichard Henderson } 33535a18407fSRichard Henderson 33545a18407fSRichard Henderson /* Perform input replacement, and mark inputs that became dead. 33555a18407fSRichard Henderson No action is required except keeping temp_state up to date 33565a18407fSRichard Henderson so that we reload when needed. */ 33575a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 3358b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 3359b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 3360b83eabeaSRichard Henderson if (dir_ts) { 3361b83eabeaSRichard Henderson op->args[i] = temp_arg(dir_ts); 33625a18407fSRichard Henderson changes = true; 33635a18407fSRichard Henderson if (IS_DEAD_ARG(i)) { 3364b83eabeaSRichard Henderson arg_ts->state = TS_DEAD; 33655a18407fSRichard Henderson } 33665a18407fSRichard Henderson } 33675a18407fSRichard Henderson } 33685a18407fSRichard Henderson 33695a18407fSRichard Henderson /* Liveness analysis should ensure that the following are 33705a18407fSRichard Henderson all correct, for call sites and basic block end points. */ 33715a18407fSRichard Henderson if (call_flags & TCG_CALL_NO_READ_GLOBALS) { 33725a18407fSRichard Henderson /* Nothing to do */ 33735a18407fSRichard Henderson } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) { 33745a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 33755a18407fSRichard Henderson /* Liveness should see that globals are synced back, 33765a18407fSRichard Henderson that is, either TS_DEAD or TS_MEM. */ 3377b83eabeaSRichard Henderson arg_ts = &s->temps[i]; 3378b83eabeaSRichard Henderson tcg_debug_assert(arg_ts->state_ptr == 0 3379b83eabeaSRichard Henderson || arg_ts->state != 0); 33805a18407fSRichard Henderson } 33815a18407fSRichard Henderson } else { 33825a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 33835a18407fSRichard Henderson /* Liveness should see that globals are saved back, 33845a18407fSRichard Henderson that is, TS_DEAD, waiting to be reloaded. */ 3385b83eabeaSRichard Henderson arg_ts = &s->temps[i]; 3386b83eabeaSRichard Henderson tcg_debug_assert(arg_ts->state_ptr == 0 3387b83eabeaSRichard Henderson || arg_ts->state == TS_DEAD); 33885a18407fSRichard Henderson } 33895a18407fSRichard Henderson } 33905a18407fSRichard Henderson 33915a18407fSRichard Henderson /* Outputs become available. */ 339261f15c48SRichard Henderson if (opc == INDEX_op_mov_i32 || opc == INDEX_op_mov_i64) { 339361f15c48SRichard Henderson arg_ts = arg_temp(op->args[0]); 339461f15c48SRichard Henderson dir_ts = arg_ts->state_ptr; 339561f15c48SRichard Henderson if (dir_ts) { 339661f15c48SRichard Henderson op->args[0] = temp_arg(dir_ts); 339761f15c48SRichard Henderson changes = true; 339861f15c48SRichard Henderson 339961f15c48SRichard Henderson /* The output is now live and modified. */ 340061f15c48SRichard Henderson arg_ts->state = 0; 340161f15c48SRichard Henderson 340261f15c48SRichard Henderson if (NEED_SYNC_ARG(0)) { 340361f15c48SRichard Henderson TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 340461f15c48SRichard Henderson ? INDEX_op_st_i32 340561f15c48SRichard Henderson : INDEX_op_st_i64); 3406d4478943SPhilippe Mathieu-Daudé TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3); 340761f15c48SRichard Henderson TCGTemp *out_ts = dir_ts; 340861f15c48SRichard Henderson 340961f15c48SRichard Henderson if (IS_DEAD_ARG(0)) { 341061f15c48SRichard Henderson out_ts = arg_temp(op->args[1]); 341161f15c48SRichard Henderson arg_ts->state = TS_DEAD; 341261f15c48SRichard Henderson tcg_op_remove(s, op); 341361f15c48SRichard Henderson } else { 341461f15c48SRichard Henderson arg_ts->state = TS_MEM; 341561f15c48SRichard Henderson } 341661f15c48SRichard Henderson 341761f15c48SRichard Henderson sop->args[0] = temp_arg(out_ts); 341861f15c48SRichard Henderson sop->args[1] = temp_arg(arg_ts->mem_base); 341961f15c48SRichard Henderson sop->args[2] = arg_ts->mem_offset; 342061f15c48SRichard Henderson } else { 342161f15c48SRichard Henderson tcg_debug_assert(!IS_DEAD_ARG(0)); 342261f15c48SRichard Henderson } 342361f15c48SRichard Henderson } 342461f15c48SRichard Henderson } else { 34255a18407fSRichard Henderson for (i = 0; i < nb_oargs; i++) { 3426b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 3427b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 3428b83eabeaSRichard Henderson if (!dir_ts) { 34295a18407fSRichard Henderson continue; 34305a18407fSRichard Henderson } 3431b83eabeaSRichard Henderson op->args[i] = temp_arg(dir_ts); 34325a18407fSRichard Henderson changes = true; 34335a18407fSRichard Henderson 34345a18407fSRichard Henderson /* The output is now live and modified. */ 3435b83eabeaSRichard Henderson arg_ts->state = 0; 34365a18407fSRichard Henderson 34375a18407fSRichard Henderson /* Sync outputs upon their last write. */ 34385a18407fSRichard Henderson if (NEED_SYNC_ARG(i)) { 3439b83eabeaSRichard Henderson TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 34405a18407fSRichard Henderson ? INDEX_op_st_i32 34415a18407fSRichard Henderson : INDEX_op_st_i64); 3442d4478943SPhilippe Mathieu-Daudé TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3); 34435a18407fSRichard Henderson 3444b83eabeaSRichard Henderson sop->args[0] = temp_arg(dir_ts); 3445b83eabeaSRichard Henderson sop->args[1] = temp_arg(arg_ts->mem_base); 3446b83eabeaSRichard Henderson sop->args[2] = arg_ts->mem_offset; 34475a18407fSRichard Henderson 3448b83eabeaSRichard Henderson arg_ts->state = TS_MEM; 34495a18407fSRichard Henderson } 34505a18407fSRichard Henderson /* Drop outputs that are dead. */ 34515a18407fSRichard Henderson if (IS_DEAD_ARG(i)) { 3452b83eabeaSRichard Henderson arg_ts->state = TS_DEAD; 34535a18407fSRichard Henderson } 34545a18407fSRichard Henderson } 34555a18407fSRichard Henderson } 345661f15c48SRichard Henderson } 34575a18407fSRichard Henderson 34585a18407fSRichard Henderson return changes; 34595a18407fSRichard Henderson } 34605a18407fSRichard Henderson 34612272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts) 3462c896fe29Sbellard { 346331c96417SRichard Henderson intptr_t off; 3464273eb50cSRichard Henderson int size, align; 3465c1c09194SRichard Henderson 3466273eb50cSRichard Henderson /* When allocating an object, look at the full type. */ 3467273eb50cSRichard Henderson size = tcg_type_size(ts->base_type); 3468273eb50cSRichard Henderson switch (ts->base_type) { 3469c1c09194SRichard Henderson case TCG_TYPE_I32: 347031c96417SRichard Henderson align = 4; 3471c1c09194SRichard Henderson break; 3472c1c09194SRichard Henderson case TCG_TYPE_I64: 3473c1c09194SRichard Henderson case TCG_TYPE_V64: 347431c96417SRichard Henderson align = 8; 3475c1c09194SRichard Henderson break; 347643eef72fSRichard Henderson case TCG_TYPE_I128: 3477c1c09194SRichard Henderson case TCG_TYPE_V128: 3478c1c09194SRichard Henderson case TCG_TYPE_V256: 347943eef72fSRichard Henderson /* 348043eef72fSRichard Henderson * Note that we do not require aligned storage for V256, 348143eef72fSRichard Henderson * and that we provide alignment for I128 to match V128, 348243eef72fSRichard Henderson * even if that's above what the host ABI requires. 348343eef72fSRichard Henderson */ 348431c96417SRichard Henderson align = 16; 3485c1c09194SRichard Henderson break; 3486c1c09194SRichard Henderson default: 3487c1c09194SRichard Henderson g_assert_not_reached(); 3488b591dc59SBlue Swirl } 3489c1c09194SRichard Henderson 3490b9537d59SRichard Henderson /* 3491b9537d59SRichard Henderson * Assume the stack is sufficiently aligned. 3492b9537d59SRichard Henderson * This affects e.g. ARM NEON, where we have 8 byte stack alignment 3493b9537d59SRichard Henderson * and do not require 16 byte vector alignment. This seems slightly 3494b9537d59SRichard Henderson * easier than fully parameterizing the above switch statement. 3495b9537d59SRichard Henderson */ 3496b9537d59SRichard Henderson align = MIN(TCG_TARGET_STACK_ALIGN, align); 3497c1c09194SRichard Henderson off = ROUND_UP(s->current_frame_offset, align); 3498732d5897SRichard Henderson 3499732d5897SRichard Henderson /* If we've exhausted the stack frame, restart with a smaller TB. */ 3500732d5897SRichard Henderson if (off + size > s->frame_end) { 3501732d5897SRichard Henderson tcg_raise_tb_overflow(s); 3502732d5897SRichard Henderson } 3503c1c09194SRichard Henderson s->current_frame_offset = off + size; 35049defd1bdSRichard Henderson #if defined(__sparc__) 3505273eb50cSRichard Henderson off += TCG_TARGET_STACK_BIAS; 35069defd1bdSRichard Henderson #endif 3507273eb50cSRichard Henderson 3508273eb50cSRichard Henderson /* If the object was subdivided, assign memory to all the parts. */ 3509273eb50cSRichard Henderson if (ts->base_type != ts->type) { 3510273eb50cSRichard Henderson int part_size = tcg_type_size(ts->type); 3511273eb50cSRichard Henderson int part_count = size / part_size; 3512273eb50cSRichard Henderson 3513273eb50cSRichard Henderson /* 3514273eb50cSRichard Henderson * Each part is allocated sequentially in tcg_temp_new_internal. 3515273eb50cSRichard Henderson * Jump back to the first part by subtracting the current index. 3516273eb50cSRichard Henderson */ 3517273eb50cSRichard Henderson ts -= ts->temp_subindex; 3518273eb50cSRichard Henderson for (int i = 0; i < part_count; ++i) { 3519273eb50cSRichard Henderson ts[i].mem_offset = off + i * part_size; 3520273eb50cSRichard Henderson ts[i].mem_base = s->frame_temp; 3521273eb50cSRichard Henderson ts[i].mem_allocated = 1; 3522273eb50cSRichard Henderson } 3523273eb50cSRichard Henderson } else { 3524273eb50cSRichard Henderson ts->mem_offset = off; 3525b3a62939SRichard Henderson ts->mem_base = s->frame_temp; 3526c896fe29Sbellard ts->mem_allocated = 1; 3527c896fe29Sbellard } 3528273eb50cSRichard Henderson } 3529c896fe29Sbellard 3530098859f1SRichard Henderson /* Assign @reg to @ts, and update reg_to_temp[]. */ 3531098859f1SRichard Henderson static void set_temp_val_reg(TCGContext *s, TCGTemp *ts, TCGReg reg) 3532098859f1SRichard Henderson { 3533098859f1SRichard Henderson if (ts->val_type == TEMP_VAL_REG) { 3534098859f1SRichard Henderson TCGReg old = ts->reg; 3535098859f1SRichard Henderson tcg_debug_assert(s->reg_to_temp[old] == ts); 3536098859f1SRichard Henderson if (old == reg) { 3537098859f1SRichard Henderson return; 3538098859f1SRichard Henderson } 3539098859f1SRichard Henderson s->reg_to_temp[old] = NULL; 3540098859f1SRichard Henderson } 3541098859f1SRichard Henderson tcg_debug_assert(s->reg_to_temp[reg] == NULL); 3542098859f1SRichard Henderson s->reg_to_temp[reg] = ts; 3543098859f1SRichard Henderson ts->val_type = TEMP_VAL_REG; 3544098859f1SRichard Henderson ts->reg = reg; 3545098859f1SRichard Henderson } 3546098859f1SRichard Henderson 3547098859f1SRichard Henderson /* Assign a non-register value type to @ts, and update reg_to_temp[]. */ 3548098859f1SRichard Henderson static void set_temp_val_nonreg(TCGContext *s, TCGTemp *ts, TCGTempVal type) 3549098859f1SRichard Henderson { 3550098859f1SRichard Henderson tcg_debug_assert(type != TEMP_VAL_REG); 3551098859f1SRichard Henderson if (ts->val_type == TEMP_VAL_REG) { 3552098859f1SRichard Henderson TCGReg reg = ts->reg; 3553098859f1SRichard Henderson tcg_debug_assert(s->reg_to_temp[reg] == ts); 3554098859f1SRichard Henderson s->reg_to_temp[reg] = NULL; 3555098859f1SRichard Henderson } 3556098859f1SRichard Henderson ts->val_type = type; 3557098859f1SRichard Henderson } 3558098859f1SRichard Henderson 3559b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet); 3560b3915dbbSRichard Henderson 356159d7c14eSRichard Henderson /* Mark a temporary as free or dead. If 'free_or_dead' is negative, 356259d7c14eSRichard Henderson mark it free; otherwise mark it dead. */ 356359d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead) 3564c896fe29Sbellard { 3565c0522136SRichard Henderson TCGTempVal new_type; 3566c0522136SRichard Henderson 3567c0522136SRichard Henderson switch (ts->kind) { 3568c0522136SRichard Henderson case TEMP_FIXED: 356959d7c14eSRichard Henderson return; 3570c0522136SRichard Henderson case TEMP_GLOBAL: 3571f57c6915SRichard Henderson case TEMP_TB: 3572c0522136SRichard Henderson new_type = TEMP_VAL_MEM; 3573c0522136SRichard Henderson break; 3574c0522136SRichard Henderson case TEMP_NORMAL: 3575c7482438SRichard Henderson case TEMP_EBB: 3576c0522136SRichard Henderson new_type = free_or_dead < 0 ? TEMP_VAL_MEM : TEMP_VAL_DEAD; 3577c0522136SRichard Henderson break; 3578c0522136SRichard Henderson case TEMP_CONST: 3579c0522136SRichard Henderson new_type = TEMP_VAL_CONST; 3580c0522136SRichard Henderson break; 3581c0522136SRichard Henderson default: 3582c0522136SRichard Henderson g_assert_not_reached(); 358359d7c14eSRichard Henderson } 3584098859f1SRichard Henderson set_temp_val_nonreg(s, ts, new_type); 358559d7c14eSRichard Henderson } 3586c896fe29Sbellard 358759d7c14eSRichard Henderson /* Mark a temporary as dead. */ 358859d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts) 358959d7c14eSRichard Henderson { 359059d7c14eSRichard Henderson temp_free_or_dead(s, ts, 1); 359159d7c14eSRichard Henderson } 359259d7c14eSRichard Henderson 359359d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary 359459d7c14eSRichard Henderson registers needs to be allocated to store a constant. If 'free_or_dead' 359559d7c14eSRichard Henderson is non-zero, subsequently release the temporary; if it is positive, the 359659d7c14eSRichard Henderson temp is dead; if it is negative, the temp is free. */ 359798b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs, 359898b4e186SRichard Henderson TCGRegSet preferred_regs, int free_or_dead) 359959d7c14eSRichard Henderson { 3600c0522136SRichard Henderson if (!temp_readonly(ts) && !ts->mem_coherent) { 36017f6ceedfSAurelien Jarno if (!ts->mem_allocated) { 36022272e4a7SRichard Henderson temp_allocate_frame(s, ts); 360359d7c14eSRichard Henderson } 360459d7c14eSRichard Henderson switch (ts->val_type) { 360559d7c14eSRichard Henderson case TEMP_VAL_CONST: 360659d7c14eSRichard Henderson /* If we're going to free the temp immediately, then we won't 360759d7c14eSRichard Henderson require it later in a register, so attempt to store the 360859d7c14eSRichard Henderson constant to memory directly. */ 360959d7c14eSRichard Henderson if (free_or_dead 361059d7c14eSRichard Henderson && tcg_out_sti(s, ts->type, ts->val, 361159d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset)) { 361259d7c14eSRichard Henderson break; 361359d7c14eSRichard Henderson } 361459d7c14eSRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 361598b4e186SRichard Henderson allocated_regs, preferred_regs); 361659d7c14eSRichard Henderson /* fallthrough */ 361759d7c14eSRichard Henderson 361859d7c14eSRichard Henderson case TEMP_VAL_REG: 361959d7c14eSRichard Henderson tcg_out_st(s, ts->type, ts->reg, 362059d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset); 362159d7c14eSRichard Henderson break; 362259d7c14eSRichard Henderson 362359d7c14eSRichard Henderson case TEMP_VAL_MEM: 362459d7c14eSRichard Henderson break; 362559d7c14eSRichard Henderson 362659d7c14eSRichard Henderson case TEMP_VAL_DEAD: 362759d7c14eSRichard Henderson default: 362859d7c14eSRichard Henderson tcg_abort(); 3629c896fe29Sbellard } 36307f6ceedfSAurelien Jarno ts->mem_coherent = 1; 36317f6ceedfSAurelien Jarno } 363259d7c14eSRichard Henderson if (free_or_dead) { 363359d7c14eSRichard Henderson temp_free_or_dead(s, ts, free_or_dead); 363459d7c14eSRichard Henderson } 363559d7c14eSRichard Henderson } 36367f6ceedfSAurelien Jarno 36377f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */ 3638b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs) 36397f6ceedfSAurelien Jarno { 3640f8b2f202SRichard Henderson TCGTemp *ts = s->reg_to_temp[reg]; 3641f8b2f202SRichard Henderson if (ts != NULL) { 364298b4e186SRichard Henderson temp_sync(s, ts, allocated_regs, 0, -1); 3643c896fe29Sbellard } 3644c896fe29Sbellard } 3645c896fe29Sbellard 3646b016486eSRichard Henderson /** 3647b016486eSRichard Henderson * tcg_reg_alloc: 3648b016486eSRichard Henderson * @required_regs: Set of registers in which we must allocate. 3649b016486eSRichard Henderson * @allocated_regs: Set of registers which must be avoided. 3650b016486eSRichard Henderson * @preferred_regs: Set of registers we should prefer. 3651b016486eSRichard Henderson * @rev: True if we search the registers in "indirect" order. 3652b016486eSRichard Henderson * 3653b016486eSRichard Henderson * The allocated register must be in @required_regs & ~@allocated_regs, 3654b016486eSRichard Henderson * but if we can put it in @preferred_regs we may save a move later. 3655b016486eSRichard Henderson */ 3656b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs, 3657b016486eSRichard Henderson TCGRegSet allocated_regs, 3658b016486eSRichard Henderson TCGRegSet preferred_regs, bool rev) 3659c896fe29Sbellard { 3660b016486eSRichard Henderson int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order); 3661b016486eSRichard Henderson TCGRegSet reg_ct[2]; 366291478cefSRichard Henderson const int *order; 3663c896fe29Sbellard 3664b016486eSRichard Henderson reg_ct[1] = required_regs & ~allocated_regs; 3665b016486eSRichard Henderson tcg_debug_assert(reg_ct[1] != 0); 3666b016486eSRichard Henderson reg_ct[0] = reg_ct[1] & preferred_regs; 3667b016486eSRichard Henderson 3668b016486eSRichard Henderson /* Skip the preferred_regs option if it cannot be satisfied, 3669b016486eSRichard Henderson or if the preference made no difference. */ 3670b016486eSRichard Henderson f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1]; 3671b016486eSRichard Henderson 367291478cefSRichard Henderson order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order; 3673c896fe29Sbellard 3674b016486eSRichard Henderson /* Try free registers, preferences first. */ 3675b016486eSRichard Henderson for (j = f; j < 2; j++) { 3676b016486eSRichard Henderson TCGRegSet set = reg_ct[j]; 3677b016486eSRichard Henderson 3678b016486eSRichard Henderson if (tcg_regset_single(set)) { 3679b016486eSRichard Henderson /* One register in the set. */ 3680b016486eSRichard Henderson TCGReg reg = tcg_regset_first(set); 3681b016486eSRichard Henderson if (s->reg_to_temp[reg] == NULL) { 3682c896fe29Sbellard return reg; 3683c896fe29Sbellard } 3684b016486eSRichard Henderson } else { 368591478cefSRichard Henderson for (i = 0; i < n; i++) { 3686b016486eSRichard Henderson TCGReg reg = order[i]; 3687b016486eSRichard Henderson if (s->reg_to_temp[reg] == NULL && 3688b016486eSRichard Henderson tcg_regset_test_reg(set, reg)) { 3689b016486eSRichard Henderson return reg; 3690b016486eSRichard Henderson } 3691b016486eSRichard Henderson } 3692b016486eSRichard Henderson } 3693b016486eSRichard Henderson } 3694b016486eSRichard Henderson 3695b016486eSRichard Henderson /* We must spill something. */ 3696b016486eSRichard Henderson for (j = f; j < 2; j++) { 3697b016486eSRichard Henderson TCGRegSet set = reg_ct[j]; 3698b016486eSRichard Henderson 3699b016486eSRichard Henderson if (tcg_regset_single(set)) { 3700b016486eSRichard Henderson /* One register in the set. */ 3701b016486eSRichard Henderson TCGReg reg = tcg_regset_first(set); 3702b3915dbbSRichard Henderson tcg_reg_free(s, reg, allocated_regs); 3703c896fe29Sbellard return reg; 3704b016486eSRichard Henderson } else { 3705b016486eSRichard Henderson for (i = 0; i < n; i++) { 3706b016486eSRichard Henderson TCGReg reg = order[i]; 3707b016486eSRichard Henderson if (tcg_regset_test_reg(set, reg)) { 3708b016486eSRichard Henderson tcg_reg_free(s, reg, allocated_regs); 3709b016486eSRichard Henderson return reg; 3710b016486eSRichard Henderson } 3711b016486eSRichard Henderson } 3712c896fe29Sbellard } 3713c896fe29Sbellard } 3714c896fe29Sbellard 3715c896fe29Sbellard tcg_abort(); 3716c896fe29Sbellard } 3717c896fe29Sbellard 371829f5e925SRichard Henderson static TCGReg tcg_reg_alloc_pair(TCGContext *s, TCGRegSet required_regs, 371929f5e925SRichard Henderson TCGRegSet allocated_regs, 372029f5e925SRichard Henderson TCGRegSet preferred_regs, bool rev) 372129f5e925SRichard Henderson { 372229f5e925SRichard Henderson int i, j, k, fmin, n = ARRAY_SIZE(tcg_target_reg_alloc_order); 372329f5e925SRichard Henderson TCGRegSet reg_ct[2]; 372429f5e925SRichard Henderson const int *order; 372529f5e925SRichard Henderson 372629f5e925SRichard Henderson /* Ensure that if I is not in allocated_regs, I+1 is not either. */ 372729f5e925SRichard Henderson reg_ct[1] = required_regs & ~(allocated_regs | (allocated_regs >> 1)); 372829f5e925SRichard Henderson tcg_debug_assert(reg_ct[1] != 0); 372929f5e925SRichard Henderson reg_ct[0] = reg_ct[1] & preferred_regs; 373029f5e925SRichard Henderson 373129f5e925SRichard Henderson order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order; 373229f5e925SRichard Henderson 373329f5e925SRichard Henderson /* 373429f5e925SRichard Henderson * Skip the preferred_regs option if it cannot be satisfied, 373529f5e925SRichard Henderson * or if the preference made no difference. 373629f5e925SRichard Henderson */ 373729f5e925SRichard Henderson k = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1]; 373829f5e925SRichard Henderson 373929f5e925SRichard Henderson /* 374029f5e925SRichard Henderson * Minimize the number of flushes by looking for 2 free registers first, 374129f5e925SRichard Henderson * then a single flush, then two flushes. 374229f5e925SRichard Henderson */ 374329f5e925SRichard Henderson for (fmin = 2; fmin >= 0; fmin--) { 374429f5e925SRichard Henderson for (j = k; j < 2; j++) { 374529f5e925SRichard Henderson TCGRegSet set = reg_ct[j]; 374629f5e925SRichard Henderson 374729f5e925SRichard Henderson for (i = 0; i < n; i++) { 374829f5e925SRichard Henderson TCGReg reg = order[i]; 374929f5e925SRichard Henderson 375029f5e925SRichard Henderson if (tcg_regset_test_reg(set, reg)) { 375129f5e925SRichard Henderson int f = !s->reg_to_temp[reg] + !s->reg_to_temp[reg + 1]; 375229f5e925SRichard Henderson if (f >= fmin) { 375329f5e925SRichard Henderson tcg_reg_free(s, reg, allocated_regs); 375429f5e925SRichard Henderson tcg_reg_free(s, reg + 1, allocated_regs); 375529f5e925SRichard Henderson return reg; 375629f5e925SRichard Henderson } 375729f5e925SRichard Henderson } 375829f5e925SRichard Henderson } 375929f5e925SRichard Henderson } 376029f5e925SRichard Henderson } 376129f5e925SRichard Henderson tcg_abort(); 376229f5e925SRichard Henderson } 376329f5e925SRichard Henderson 376440ae5c62SRichard Henderson /* Make sure the temporary is in a register. If needed, allocate the register 376540ae5c62SRichard Henderson from DESIRED while avoiding ALLOCATED. */ 376640ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs, 3767b722452aSRichard Henderson TCGRegSet allocated_regs, TCGRegSet preferred_regs) 376840ae5c62SRichard Henderson { 376940ae5c62SRichard Henderson TCGReg reg; 377040ae5c62SRichard Henderson 377140ae5c62SRichard Henderson switch (ts->val_type) { 377240ae5c62SRichard Henderson case TEMP_VAL_REG: 377340ae5c62SRichard Henderson return; 377440ae5c62SRichard Henderson case TEMP_VAL_CONST: 3775b016486eSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs, 3776b722452aSRichard Henderson preferred_regs, ts->indirect_base); 37770a6a8bc8SRichard Henderson if (ts->type <= TCG_TYPE_I64) { 377840ae5c62SRichard Henderson tcg_out_movi(s, ts->type, reg, ts->val); 37790a6a8bc8SRichard Henderson } else { 37804e186175SRichard Henderson uint64_t val = ts->val; 37814e186175SRichard Henderson MemOp vece = MO_64; 37824e186175SRichard Henderson 37834e186175SRichard Henderson /* 37844e186175SRichard Henderson * Find the minimal vector element that matches the constant. 37854e186175SRichard Henderson * The targets will, in general, have to do this search anyway, 37864e186175SRichard Henderson * do this generically. 37874e186175SRichard Henderson */ 37884e186175SRichard Henderson if (val == dup_const(MO_8, val)) { 37894e186175SRichard Henderson vece = MO_8; 37904e186175SRichard Henderson } else if (val == dup_const(MO_16, val)) { 37914e186175SRichard Henderson vece = MO_16; 37920b4286ddSRichard Henderson } else if (val == dup_const(MO_32, val)) { 37934e186175SRichard Henderson vece = MO_32; 37944e186175SRichard Henderson } 37954e186175SRichard Henderson 37964e186175SRichard Henderson tcg_out_dupi_vec(s, ts->type, vece, reg, ts->val); 37970a6a8bc8SRichard Henderson } 379840ae5c62SRichard Henderson ts->mem_coherent = 0; 379940ae5c62SRichard Henderson break; 380040ae5c62SRichard Henderson case TEMP_VAL_MEM: 3801b016486eSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs, 3802b722452aSRichard Henderson preferred_regs, ts->indirect_base); 380340ae5c62SRichard Henderson tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset); 380440ae5c62SRichard Henderson ts->mem_coherent = 1; 380540ae5c62SRichard Henderson break; 380640ae5c62SRichard Henderson case TEMP_VAL_DEAD: 380740ae5c62SRichard Henderson default: 380840ae5c62SRichard Henderson tcg_abort(); 380940ae5c62SRichard Henderson } 3810098859f1SRichard Henderson set_temp_val_reg(s, ts, reg); 381140ae5c62SRichard Henderson } 381240ae5c62SRichard Henderson 381359d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a 3814e8996ee0Sbellard temporary registers needs to be allocated to store a constant. */ 381559d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs) 38161ad80729SAurelien Jarno { 38172c0366f0SAurelien Jarno /* The liveness analysis already ensures that globals are back 3818eabb7b91SAurelien Jarno in memory. Keep an tcg_debug_assert for safety. */ 3819e01fa97dSRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || temp_readonly(ts)); 38201ad80729SAurelien Jarno } 38211ad80729SAurelien Jarno 38229814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be 3823641d5fbeSbellard modified be the following code. 'allocated_regs' is used in case a 3824641d5fbeSbellard temporary registers needs to be allocated to store a constant. */ 3825641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs) 3826641d5fbeSbellard { 3827ac3b8891SRichard Henderson int i, n; 3828641d5fbeSbellard 3829ac3b8891SRichard Henderson for (i = 0, n = s->nb_globals; i < n; i++) { 3830b13eb728SRichard Henderson temp_save(s, &s->temps[i], allocated_regs); 3831641d5fbeSbellard } 3832e5097dc8Sbellard } 3833e5097dc8Sbellard 38343d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be 38353d5c5f87SAurelien Jarno read by the following code. 'allocated_regs' is used in case a 38363d5c5f87SAurelien Jarno temporary registers needs to be allocated to store a constant. */ 38373d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs) 38383d5c5f87SAurelien Jarno { 3839ac3b8891SRichard Henderson int i, n; 38403d5c5f87SAurelien Jarno 3841ac3b8891SRichard Henderson for (i = 0, n = s->nb_globals; i < n; i++) { 384212b9b11aSRichard Henderson TCGTemp *ts = &s->temps[i]; 384312b9b11aSRichard Henderson tcg_debug_assert(ts->val_type != TEMP_VAL_REG 3844ee17db83SRichard Henderson || ts->kind == TEMP_FIXED 384512b9b11aSRichard Henderson || ts->mem_coherent); 38463d5c5f87SAurelien Jarno } 38473d5c5f87SAurelien Jarno } 38483d5c5f87SAurelien Jarno 3849e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and 3850e8996ee0Sbellard all globals are stored at their canonical location. */ 3851e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs) 3852e5097dc8Sbellard { 3853e5097dc8Sbellard int i; 3854e5097dc8Sbellard 3855c896fe29Sbellard for (i = s->nb_globals; i < s->nb_temps; i++) { 3856b13eb728SRichard Henderson TCGTemp *ts = &s->temps[i]; 3857c0522136SRichard Henderson 3858c0522136SRichard Henderson switch (ts->kind) { 3859f57c6915SRichard Henderson case TEMP_TB: 3860b13eb728SRichard Henderson temp_save(s, ts, allocated_regs); 3861c0522136SRichard Henderson break; 3862c0522136SRichard Henderson case TEMP_NORMAL: 3863c7482438SRichard Henderson case TEMP_EBB: 38642c0366f0SAurelien Jarno /* The liveness analysis already ensures that temps are dead. 3865eabb7b91SAurelien Jarno Keep an tcg_debug_assert for safety. */ 3866eabb7b91SAurelien Jarno tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD); 3867c0522136SRichard Henderson break; 3868c0522136SRichard Henderson case TEMP_CONST: 3869c0522136SRichard Henderson /* Similarly, we should have freed any allocated register. */ 3870c0522136SRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_CONST); 3871c0522136SRichard Henderson break; 3872c0522136SRichard Henderson default: 3873c0522136SRichard Henderson g_assert_not_reached(); 3874c896fe29Sbellard } 3875641d5fbeSbellard } 3876e8996ee0Sbellard 3877e8996ee0Sbellard save_globals(s, allocated_regs); 3878c896fe29Sbellard } 3879c896fe29Sbellard 3880bab1671fSRichard Henderson /* 3881c7482438SRichard Henderson * At a conditional branch, we assume all temporaries are dead unless 3882c7482438SRichard Henderson * explicitly live-across-conditional-branch; all globals and local 3883c7482438SRichard Henderson * temps are synced to their location. 3884b4cb76e6SRichard Henderson */ 3885b4cb76e6SRichard Henderson static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs) 3886b4cb76e6SRichard Henderson { 3887b4cb76e6SRichard Henderson sync_globals(s, allocated_regs); 3888b4cb76e6SRichard Henderson 3889b4cb76e6SRichard Henderson for (int i = s->nb_globals; i < s->nb_temps; i++) { 3890b4cb76e6SRichard Henderson TCGTemp *ts = &s->temps[i]; 3891b4cb76e6SRichard Henderson /* 3892b4cb76e6SRichard Henderson * The liveness analysis already ensures that temps are dead. 3893b4cb76e6SRichard Henderson * Keep tcg_debug_asserts for safety. 3894b4cb76e6SRichard Henderson */ 3895c0522136SRichard Henderson switch (ts->kind) { 3896f57c6915SRichard Henderson case TEMP_TB: 3897b4cb76e6SRichard Henderson tcg_debug_assert(ts->val_type != TEMP_VAL_REG || ts->mem_coherent); 3898c0522136SRichard Henderson break; 3899c0522136SRichard Henderson case TEMP_NORMAL: 3900b4cb76e6SRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD); 3901c0522136SRichard Henderson break; 3902c7482438SRichard Henderson case TEMP_EBB: 3903c0522136SRichard Henderson case TEMP_CONST: 3904c0522136SRichard Henderson break; 3905c0522136SRichard Henderson default: 3906c0522136SRichard Henderson g_assert_not_reached(); 3907b4cb76e6SRichard Henderson } 3908b4cb76e6SRichard Henderson } 3909b4cb76e6SRichard Henderson } 3910b4cb76e6SRichard Henderson 3911b4cb76e6SRichard Henderson /* 3912c58f4c97SRichard Henderson * Specialized code generation for INDEX_op_mov_* with a constant. 3913bab1671fSRichard Henderson */ 39140fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots, 3915ba87719cSRichard Henderson tcg_target_ulong val, TCGLifeData arg_life, 3916ba87719cSRichard Henderson TCGRegSet preferred_regs) 3917e8996ee0Sbellard { 3918d63e3b6eSRichard Henderson /* ENV should not be modified. */ 3919e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 392059d7c14eSRichard Henderson 392159d7c14eSRichard Henderson /* The movi is not explicitly generated here. */ 3922098859f1SRichard Henderson set_temp_val_nonreg(s, ots, TEMP_VAL_CONST); 3923e8996ee0Sbellard ots->val = val; 392459d7c14eSRichard Henderson ots->mem_coherent = 0; 3925ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) { 3926ba87719cSRichard Henderson temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0)); 392759d7c14eSRichard Henderson } else if (IS_DEAD_ARG(0)) { 3928f8bf00f1SRichard Henderson temp_dead(s, ots); 39294c4e1ab2SAurelien Jarno } 3930e8996ee0Sbellard } 3931e8996ee0Sbellard 3932bab1671fSRichard Henderson /* 3933bab1671fSRichard Henderson * Specialized code generation for INDEX_op_mov_*. 3934bab1671fSRichard Henderson */ 3935dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op) 3936c896fe29Sbellard { 3937dd186292SRichard Henderson const TCGLifeData arg_life = op->life; 393869e3706dSRichard Henderson TCGRegSet allocated_regs, preferred_regs; 3939c896fe29Sbellard TCGTemp *ts, *ots; 3940450445d5SRichard Henderson TCGType otype, itype; 3941098859f1SRichard Henderson TCGReg oreg, ireg; 3942c896fe29Sbellard 3943d21369f5SRichard Henderson allocated_regs = s->reserved_regs; 394431fd884bSRichard Henderson preferred_regs = output_pref(op, 0); 394543439139SRichard Henderson ots = arg_temp(op->args[0]); 394643439139SRichard Henderson ts = arg_temp(op->args[1]); 3947450445d5SRichard Henderson 3948d63e3b6eSRichard Henderson /* ENV should not be modified. */ 3949e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 3950d63e3b6eSRichard Henderson 3951450445d5SRichard Henderson /* Note that otype != itype for no-op truncation. */ 3952450445d5SRichard Henderson otype = ots->type; 3953450445d5SRichard Henderson itype = ts->type; 3954c896fe29Sbellard 39550fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_CONST) { 39560fe4fca4SPaolo Bonzini /* propagate constant or generate sti */ 39570fe4fca4SPaolo Bonzini tcg_target_ulong val = ts->val; 39580fe4fca4SPaolo Bonzini if (IS_DEAD_ARG(1)) { 39590fe4fca4SPaolo Bonzini temp_dead(s, ts); 39600fe4fca4SPaolo Bonzini } 396169e3706dSRichard Henderson tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs); 39620fe4fca4SPaolo Bonzini return; 39630fe4fca4SPaolo Bonzini } 39640fe4fca4SPaolo Bonzini 39650fe4fca4SPaolo Bonzini /* If the source value is in memory we're going to be forced 39660fe4fca4SPaolo Bonzini to have it in a register in order to perform the copy. Copy 39670fe4fca4SPaolo Bonzini the SOURCE value into its own register first, that way we 39680fe4fca4SPaolo Bonzini don't have to reload SOURCE the next time it is used. */ 39690fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_MEM) { 397069e3706dSRichard Henderson temp_load(s, ts, tcg_target_available_regs[itype], 397169e3706dSRichard Henderson allocated_regs, preferred_regs); 3972c29c1d7eSAurelien Jarno } 39730fe4fca4SPaolo Bonzini tcg_debug_assert(ts->val_type == TEMP_VAL_REG); 3974098859f1SRichard Henderson ireg = ts->reg; 3975098859f1SRichard Henderson 3976d63e3b6eSRichard Henderson if (IS_DEAD_ARG(0)) { 3977c29c1d7eSAurelien Jarno /* mov to a non-saved dead register makes no sense (even with 3978c29c1d7eSAurelien Jarno liveness analysis disabled). */ 3979eabb7b91SAurelien Jarno tcg_debug_assert(NEED_SYNC_ARG(0)); 3980c29c1d7eSAurelien Jarno if (!ots->mem_allocated) { 39812272e4a7SRichard Henderson temp_allocate_frame(s, ots); 3982c29c1d7eSAurelien Jarno } 3983098859f1SRichard Henderson tcg_out_st(s, otype, ireg, ots->mem_base->reg, ots->mem_offset); 3984c29c1d7eSAurelien Jarno if (IS_DEAD_ARG(1)) { 3985f8bf00f1SRichard Henderson temp_dead(s, ts); 3986c29c1d7eSAurelien Jarno } 3987f8bf00f1SRichard Henderson temp_dead(s, ots); 3988098859f1SRichard Henderson return; 3989098859f1SRichard Henderson } 3990098859f1SRichard Henderson 3991ee17db83SRichard Henderson if (IS_DEAD_ARG(1) && ts->kind != TEMP_FIXED) { 3992098859f1SRichard Henderson /* 3993098859f1SRichard Henderson * The mov can be suppressed. Kill input first, so that it 3994098859f1SRichard Henderson * is unlinked from reg_to_temp, then set the output to the 3995098859f1SRichard Henderson * reg that we saved from the input. 3996098859f1SRichard Henderson */ 3997f8bf00f1SRichard Henderson temp_dead(s, ts); 3998098859f1SRichard Henderson oreg = ireg; 3999c29c1d7eSAurelien Jarno } else { 4000098859f1SRichard Henderson if (ots->val_type == TEMP_VAL_REG) { 4001098859f1SRichard Henderson oreg = ots->reg; 4002098859f1SRichard Henderson } else { 4003098859f1SRichard Henderson /* Make sure to not spill the input register during allocation. */ 4004098859f1SRichard Henderson oreg = tcg_reg_alloc(s, tcg_target_available_regs[otype], 4005098859f1SRichard Henderson allocated_regs | ((TCGRegSet)1 << ireg), 4006098859f1SRichard Henderson preferred_regs, ots->indirect_base); 4007c29c1d7eSAurelien Jarno } 4008098859f1SRichard Henderson if (!tcg_out_mov(s, otype, oreg, ireg)) { 4009240c08d0SRichard Henderson /* 4010240c08d0SRichard Henderson * Cross register class move not supported. 4011240c08d0SRichard Henderson * Store the source register into the destination slot 4012240c08d0SRichard Henderson * and leave the destination temp as TEMP_VAL_MEM. 4013240c08d0SRichard Henderson */ 4014e01fa97dSRichard Henderson assert(!temp_readonly(ots)); 4015240c08d0SRichard Henderson if (!ts->mem_allocated) { 4016240c08d0SRichard Henderson temp_allocate_frame(s, ots); 4017240c08d0SRichard Henderson } 4018098859f1SRichard Henderson tcg_out_st(s, ts->type, ireg, ots->mem_base->reg, ots->mem_offset); 4019098859f1SRichard Henderson set_temp_val_nonreg(s, ts, TEMP_VAL_MEM); 4020240c08d0SRichard Henderson ots->mem_coherent = 1; 4021240c08d0SRichard Henderson return; 402278113e83SRichard Henderson } 4023c29c1d7eSAurelien Jarno } 4024098859f1SRichard Henderson set_temp_val_reg(s, ots, oreg); 4025c896fe29Sbellard ots->mem_coherent = 0; 4026098859f1SRichard Henderson 4027ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) { 402898b4e186SRichard Henderson temp_sync(s, ots, allocated_regs, 0, 0); 4029c29c1d7eSAurelien Jarno } 4030ec7a869dSAurelien Jarno } 4031c896fe29Sbellard 4032bab1671fSRichard Henderson /* 4033bab1671fSRichard Henderson * Specialized code generation for INDEX_op_dup_vec. 4034bab1671fSRichard Henderson */ 4035bab1671fSRichard Henderson static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op) 4036bab1671fSRichard Henderson { 4037bab1671fSRichard Henderson const TCGLifeData arg_life = op->life; 4038bab1671fSRichard Henderson TCGRegSet dup_out_regs, dup_in_regs; 4039bab1671fSRichard Henderson TCGTemp *its, *ots; 4040bab1671fSRichard Henderson TCGType itype, vtype; 4041bab1671fSRichard Henderson unsigned vece; 404231c96417SRichard Henderson int lowpart_ofs; 4043bab1671fSRichard Henderson bool ok; 4044bab1671fSRichard Henderson 4045bab1671fSRichard Henderson ots = arg_temp(op->args[0]); 4046bab1671fSRichard Henderson its = arg_temp(op->args[1]); 4047bab1671fSRichard Henderson 4048bab1671fSRichard Henderson /* ENV should not be modified. */ 4049e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 4050bab1671fSRichard Henderson 4051bab1671fSRichard Henderson itype = its->type; 4052bab1671fSRichard Henderson vece = TCGOP_VECE(op); 4053bab1671fSRichard Henderson vtype = TCGOP_VECL(op) + TCG_TYPE_V64; 4054bab1671fSRichard Henderson 4055bab1671fSRichard Henderson if (its->val_type == TEMP_VAL_CONST) { 4056bab1671fSRichard Henderson /* Propagate constant via movi -> dupi. */ 4057bab1671fSRichard Henderson tcg_target_ulong val = its->val; 4058bab1671fSRichard Henderson if (IS_DEAD_ARG(1)) { 4059bab1671fSRichard Henderson temp_dead(s, its); 4060bab1671fSRichard Henderson } 406131fd884bSRichard Henderson tcg_reg_alloc_do_movi(s, ots, val, arg_life, output_pref(op, 0)); 4062bab1671fSRichard Henderson return; 4063bab1671fSRichard Henderson } 4064bab1671fSRichard Henderson 40659be0d080SRichard Henderson dup_out_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs; 40669be0d080SRichard Henderson dup_in_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[1].regs; 4067bab1671fSRichard Henderson 4068bab1671fSRichard Henderson /* Allocate the output register now. */ 4069bab1671fSRichard Henderson if (ots->val_type != TEMP_VAL_REG) { 4070bab1671fSRichard Henderson TCGRegSet allocated_regs = s->reserved_regs; 4071098859f1SRichard Henderson TCGReg oreg; 4072bab1671fSRichard Henderson 4073bab1671fSRichard Henderson if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) { 4074bab1671fSRichard Henderson /* Make sure to not spill the input register. */ 4075bab1671fSRichard Henderson tcg_regset_set_reg(allocated_regs, its->reg); 4076bab1671fSRichard Henderson } 4077098859f1SRichard Henderson oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs, 407831fd884bSRichard Henderson output_pref(op, 0), ots->indirect_base); 4079098859f1SRichard Henderson set_temp_val_reg(s, ots, oreg); 4080bab1671fSRichard Henderson } 4081bab1671fSRichard Henderson 4082bab1671fSRichard Henderson switch (its->val_type) { 4083bab1671fSRichard Henderson case TEMP_VAL_REG: 4084bab1671fSRichard Henderson /* 4085bab1671fSRichard Henderson * The dup constriaints must be broad, covering all possible VECE. 4086bab1671fSRichard Henderson * However, tcg_op_dup_vec() gets to see the VECE and we allow it 4087bab1671fSRichard Henderson * to fail, indicating that extra moves are required for that case. 4088bab1671fSRichard Henderson */ 4089bab1671fSRichard Henderson if (tcg_regset_test_reg(dup_in_regs, its->reg)) { 4090bab1671fSRichard Henderson if (tcg_out_dup_vec(s, vtype, vece, ots->reg, its->reg)) { 4091bab1671fSRichard Henderson goto done; 4092bab1671fSRichard Henderson } 4093bab1671fSRichard Henderson /* Try again from memory or a vector input register. */ 4094bab1671fSRichard Henderson } 4095bab1671fSRichard Henderson if (!its->mem_coherent) { 4096bab1671fSRichard Henderson /* 4097bab1671fSRichard Henderson * The input register is not synced, and so an extra store 4098bab1671fSRichard Henderson * would be required to use memory. Attempt an integer-vector 4099bab1671fSRichard Henderson * register move first. We do not have a TCGRegSet for this. 4100bab1671fSRichard Henderson */ 4101bab1671fSRichard Henderson if (tcg_out_mov(s, itype, ots->reg, its->reg)) { 4102bab1671fSRichard Henderson break; 4103bab1671fSRichard Henderson } 4104bab1671fSRichard Henderson /* Sync the temp back to its slot and load from there. */ 4105bab1671fSRichard Henderson temp_sync(s, its, s->reserved_regs, 0, 0); 4106bab1671fSRichard Henderson } 4107bab1671fSRichard Henderson /* fall through */ 4108bab1671fSRichard Henderson 4109bab1671fSRichard Henderson case TEMP_VAL_MEM: 411031c96417SRichard Henderson lowpart_ofs = 0; 411131c96417SRichard Henderson if (HOST_BIG_ENDIAN) { 411231c96417SRichard Henderson lowpart_ofs = tcg_type_size(itype) - (1 << vece); 411331c96417SRichard Henderson } 4114d6ecb4a9SRichard Henderson if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg, 411531c96417SRichard Henderson its->mem_offset + lowpart_ofs)) { 4116d6ecb4a9SRichard Henderson goto done; 4117d6ecb4a9SRichard Henderson } 4118098859f1SRichard Henderson /* Load the input into the destination vector register. */ 4119bab1671fSRichard Henderson tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset); 4120bab1671fSRichard Henderson break; 4121bab1671fSRichard Henderson 4122bab1671fSRichard Henderson default: 4123bab1671fSRichard Henderson g_assert_not_reached(); 4124bab1671fSRichard Henderson } 4125bab1671fSRichard Henderson 4126bab1671fSRichard Henderson /* We now have a vector input register, so dup must succeed. */ 4127bab1671fSRichard Henderson ok = tcg_out_dup_vec(s, vtype, vece, ots->reg, ots->reg); 4128bab1671fSRichard Henderson tcg_debug_assert(ok); 4129bab1671fSRichard Henderson 4130bab1671fSRichard Henderson done: 413136f5539cSRichard Henderson ots->mem_coherent = 0; 4132bab1671fSRichard Henderson if (IS_DEAD_ARG(1)) { 4133bab1671fSRichard Henderson temp_dead(s, its); 4134bab1671fSRichard Henderson } 4135bab1671fSRichard Henderson if (NEED_SYNC_ARG(0)) { 4136bab1671fSRichard Henderson temp_sync(s, ots, s->reserved_regs, 0, 0); 4137bab1671fSRichard Henderson } 4138bab1671fSRichard Henderson if (IS_DEAD_ARG(0)) { 4139bab1671fSRichard Henderson temp_dead(s, ots); 4140bab1671fSRichard Henderson } 4141bab1671fSRichard Henderson } 4142bab1671fSRichard Henderson 4143dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) 4144c896fe29Sbellard { 4145dd186292SRichard Henderson const TCGLifeData arg_life = op->life; 4146dd186292SRichard Henderson const TCGOpDef * const def = &tcg_op_defs[op->opc]; 414782790a87SRichard Henderson TCGRegSet i_allocated_regs; 414882790a87SRichard Henderson TCGRegSet o_allocated_regs; 4149b6638662SRichard Henderson int i, k, nb_iargs, nb_oargs; 4150b6638662SRichard Henderson TCGReg reg; 4151c896fe29Sbellard TCGArg arg; 4152c896fe29Sbellard const TCGArgConstraint *arg_ct; 4153c896fe29Sbellard TCGTemp *ts; 4154c896fe29Sbellard TCGArg new_args[TCG_MAX_OP_ARGS]; 4155c896fe29Sbellard int const_args[TCG_MAX_OP_ARGS]; 4156c896fe29Sbellard 4157c896fe29Sbellard nb_oargs = def->nb_oargs; 4158c896fe29Sbellard nb_iargs = def->nb_iargs; 4159c896fe29Sbellard 4160c896fe29Sbellard /* copy constants */ 4161c896fe29Sbellard memcpy(new_args + nb_oargs + nb_iargs, 4162dd186292SRichard Henderson op->args + nb_oargs + nb_iargs, 4163c896fe29Sbellard sizeof(TCGArg) * def->nb_cargs); 4164c896fe29Sbellard 4165d21369f5SRichard Henderson i_allocated_regs = s->reserved_regs; 4166d21369f5SRichard Henderson o_allocated_regs = s->reserved_regs; 416782790a87SRichard Henderson 4168c896fe29Sbellard /* satisfy input constraints */ 4169c896fe29Sbellard for (k = 0; k < nb_iargs; k++) { 417029f5e925SRichard Henderson TCGRegSet i_preferred_regs, i_required_regs; 417129f5e925SRichard Henderson bool allocate_new_reg, copyto_new_reg; 417229f5e925SRichard Henderson TCGTemp *ts2; 417329f5e925SRichard Henderson int i1, i2; 4174d62816f2SRichard Henderson 417566792f90SRichard Henderson i = def->args_ct[nb_oargs + k].sort_index; 4176dd186292SRichard Henderson arg = op->args[i]; 4177c896fe29Sbellard arg_ct = &def->args_ct[i]; 417843439139SRichard Henderson ts = arg_temp(arg); 417940ae5c62SRichard Henderson 418040ae5c62SRichard Henderson if (ts->val_type == TEMP_VAL_CONST 4181a4fbbd77SRichard Henderson && tcg_target_const_match(ts->val, ts->type, arg_ct->ct)) { 4182c896fe29Sbellard /* constant is OK for instruction */ 4183c896fe29Sbellard const_args[i] = 1; 4184c896fe29Sbellard new_args[i] = ts->val; 4185d62816f2SRichard Henderson continue; 4186c896fe29Sbellard } 418740ae5c62SRichard Henderson 41881c1824dcSRichard Henderson reg = ts->reg; 41891c1824dcSRichard Henderson i_preferred_regs = 0; 419029f5e925SRichard Henderson i_required_regs = arg_ct->regs; 41911c1824dcSRichard Henderson allocate_new_reg = false; 419229f5e925SRichard Henderson copyto_new_reg = false; 41931c1824dcSRichard Henderson 419429f5e925SRichard Henderson switch (arg_ct->pair) { 419529f5e925SRichard Henderson case 0: /* not paired */ 4196bc2b17e6SRichard Henderson if (arg_ct->ialias) { 419731fd884bSRichard Henderson i_preferred_regs = output_pref(op, arg_ct->alias_index); 4198c0522136SRichard Henderson 4199c0522136SRichard Henderson /* 4200c0522136SRichard Henderson * If the input is readonly, then it cannot also be an 4201c0522136SRichard Henderson * output and aliased to itself. If the input is not 4202c0522136SRichard Henderson * dead after the instruction, we must allocate a new 4203c0522136SRichard Henderson * register and move it. 4204c0522136SRichard Henderson */ 4205c0522136SRichard Henderson if (temp_readonly(ts) || !IS_DEAD_ARG(i)) { 42061c1824dcSRichard Henderson allocate_new_reg = true; 42071c1824dcSRichard Henderson } else if (ts->val_type == TEMP_VAL_REG) { 4208c0522136SRichard Henderson /* 42091c1824dcSRichard Henderson * Check if the current register has already been 42101c1824dcSRichard Henderson * allocated for another input. 4211c0522136SRichard Henderson */ 421229f5e925SRichard Henderson allocate_new_reg = 421329f5e925SRichard Henderson tcg_regset_test_reg(i_allocated_regs, reg); 42147e1df267SAurelien Jarno } 42157e1df267SAurelien Jarno } 42161c1824dcSRichard Henderson if (!allocate_new_reg) { 421729f5e925SRichard Henderson temp_load(s, ts, i_required_regs, i_allocated_regs, 421829f5e925SRichard Henderson i_preferred_regs); 4219c896fe29Sbellard reg = ts->reg; 422029f5e925SRichard Henderson allocate_new_reg = !tcg_regset_test_reg(i_required_regs, reg); 42211c1824dcSRichard Henderson } 42221c1824dcSRichard Henderson if (allocate_new_reg) { 4223c0522136SRichard Henderson /* 4224c0522136SRichard Henderson * Allocate a new register matching the constraint 4225c0522136SRichard Henderson * and move the temporary register into it. 4226c0522136SRichard Henderson */ 4227d62816f2SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 4228d62816f2SRichard Henderson i_allocated_regs, 0); 422929f5e925SRichard Henderson reg = tcg_reg_alloc(s, i_required_regs, i_allocated_regs, 42301c1824dcSRichard Henderson i_preferred_regs, ts->indirect_base); 423129f5e925SRichard Henderson copyto_new_reg = true; 423229f5e925SRichard Henderson } 423329f5e925SRichard Henderson break; 423429f5e925SRichard Henderson 423529f5e925SRichard Henderson case 1: 423629f5e925SRichard Henderson /* First of an input pair; if i1 == i2, the second is an output. */ 423729f5e925SRichard Henderson i1 = i; 423829f5e925SRichard Henderson i2 = arg_ct->pair_index; 423929f5e925SRichard Henderson ts2 = i1 != i2 ? arg_temp(op->args[i2]) : NULL; 424029f5e925SRichard Henderson 424129f5e925SRichard Henderson /* 424229f5e925SRichard Henderson * It is easier to default to allocating a new pair 424329f5e925SRichard Henderson * and to identify a few cases where it's not required. 424429f5e925SRichard Henderson */ 424529f5e925SRichard Henderson if (arg_ct->ialias) { 424631fd884bSRichard Henderson i_preferred_regs = output_pref(op, arg_ct->alias_index); 424729f5e925SRichard Henderson if (IS_DEAD_ARG(i1) && 424829f5e925SRichard Henderson IS_DEAD_ARG(i2) && 424929f5e925SRichard Henderson !temp_readonly(ts) && 425029f5e925SRichard Henderson ts->val_type == TEMP_VAL_REG && 425129f5e925SRichard Henderson ts->reg < TCG_TARGET_NB_REGS - 1 && 425229f5e925SRichard Henderson tcg_regset_test_reg(i_required_regs, reg) && 425329f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg) && 425429f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg + 1) && 425529f5e925SRichard Henderson (ts2 425629f5e925SRichard Henderson ? ts2->val_type == TEMP_VAL_REG && 425729f5e925SRichard Henderson ts2->reg == reg + 1 && 425829f5e925SRichard Henderson !temp_readonly(ts2) 425929f5e925SRichard Henderson : s->reg_to_temp[reg + 1] == NULL)) { 426029f5e925SRichard Henderson break; 426129f5e925SRichard Henderson } 426229f5e925SRichard Henderson } else { 426329f5e925SRichard Henderson /* Without aliasing, the pair must also be an input. */ 426429f5e925SRichard Henderson tcg_debug_assert(ts2); 426529f5e925SRichard Henderson if (ts->val_type == TEMP_VAL_REG && 426629f5e925SRichard Henderson ts2->val_type == TEMP_VAL_REG && 426729f5e925SRichard Henderson ts2->reg == reg + 1 && 426829f5e925SRichard Henderson tcg_regset_test_reg(i_required_regs, reg)) { 426929f5e925SRichard Henderson break; 427029f5e925SRichard Henderson } 427129f5e925SRichard Henderson } 427229f5e925SRichard Henderson reg = tcg_reg_alloc_pair(s, i_required_regs, i_allocated_regs, 427329f5e925SRichard Henderson 0, ts->indirect_base); 427429f5e925SRichard Henderson goto do_pair; 427529f5e925SRichard Henderson 427629f5e925SRichard Henderson case 2: /* pair second */ 427729f5e925SRichard Henderson reg = new_args[arg_ct->pair_index] + 1; 427829f5e925SRichard Henderson goto do_pair; 427929f5e925SRichard Henderson 428029f5e925SRichard Henderson case 3: /* ialias with second output, no first input */ 428129f5e925SRichard Henderson tcg_debug_assert(arg_ct->ialias); 428231fd884bSRichard Henderson i_preferred_regs = output_pref(op, arg_ct->alias_index); 428329f5e925SRichard Henderson 428429f5e925SRichard Henderson if (IS_DEAD_ARG(i) && 428529f5e925SRichard Henderson !temp_readonly(ts) && 428629f5e925SRichard Henderson ts->val_type == TEMP_VAL_REG && 428729f5e925SRichard Henderson reg > 0 && 428829f5e925SRichard Henderson s->reg_to_temp[reg - 1] == NULL && 428929f5e925SRichard Henderson tcg_regset_test_reg(i_required_regs, reg) && 429029f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg) && 429129f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg - 1)) { 429229f5e925SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg - 1); 429329f5e925SRichard Henderson break; 429429f5e925SRichard Henderson } 429529f5e925SRichard Henderson reg = tcg_reg_alloc_pair(s, i_required_regs >> 1, 429629f5e925SRichard Henderson i_allocated_regs, 0, 429729f5e925SRichard Henderson ts->indirect_base); 429829f5e925SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg); 429929f5e925SRichard Henderson reg += 1; 430029f5e925SRichard Henderson goto do_pair; 430129f5e925SRichard Henderson 430229f5e925SRichard Henderson do_pair: 430329f5e925SRichard Henderson /* 430429f5e925SRichard Henderson * If an aliased input is not dead after the instruction, 430529f5e925SRichard Henderson * we must allocate a new register and move it. 430629f5e925SRichard Henderson */ 430729f5e925SRichard Henderson if (arg_ct->ialias && (!IS_DEAD_ARG(i) || temp_readonly(ts))) { 430829f5e925SRichard Henderson TCGRegSet t_allocated_regs = i_allocated_regs; 430929f5e925SRichard Henderson 431029f5e925SRichard Henderson /* 431129f5e925SRichard Henderson * Because of the alias, and the continued life, make sure 431229f5e925SRichard Henderson * that the temp is somewhere *other* than the reg pair, 431329f5e925SRichard Henderson * and we get a copy in reg. 431429f5e925SRichard Henderson */ 431529f5e925SRichard Henderson tcg_regset_set_reg(t_allocated_regs, reg); 431629f5e925SRichard Henderson tcg_regset_set_reg(t_allocated_regs, reg + 1); 431729f5e925SRichard Henderson if (ts->val_type == TEMP_VAL_REG && ts->reg == reg) { 431829f5e925SRichard Henderson /* If ts was already in reg, copy it somewhere else. */ 431929f5e925SRichard Henderson TCGReg nr; 432029f5e925SRichard Henderson bool ok; 432129f5e925SRichard Henderson 432229f5e925SRichard Henderson tcg_debug_assert(ts->kind != TEMP_FIXED); 432329f5e925SRichard Henderson nr = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], 432429f5e925SRichard Henderson t_allocated_regs, 0, ts->indirect_base); 432529f5e925SRichard Henderson ok = tcg_out_mov(s, ts->type, nr, reg); 432629f5e925SRichard Henderson tcg_debug_assert(ok); 432729f5e925SRichard Henderson 432829f5e925SRichard Henderson set_temp_val_reg(s, ts, nr); 432929f5e925SRichard Henderson } else { 433029f5e925SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 433129f5e925SRichard Henderson t_allocated_regs, 0); 433229f5e925SRichard Henderson copyto_new_reg = true; 433329f5e925SRichard Henderson } 433429f5e925SRichard Henderson } else { 433529f5e925SRichard Henderson /* Preferably allocate to reg, otherwise copy. */ 433629f5e925SRichard Henderson i_required_regs = (TCGRegSet)1 << reg; 433729f5e925SRichard Henderson temp_load(s, ts, i_required_regs, i_allocated_regs, 433829f5e925SRichard Henderson i_preferred_regs); 433929f5e925SRichard Henderson copyto_new_reg = ts->reg != reg; 434029f5e925SRichard Henderson } 434129f5e925SRichard Henderson break; 434229f5e925SRichard Henderson 434329f5e925SRichard Henderson default: 434429f5e925SRichard Henderson g_assert_not_reached(); 434529f5e925SRichard Henderson } 434629f5e925SRichard Henderson 434729f5e925SRichard Henderson if (copyto_new_reg) { 434878113e83SRichard Henderson if (!tcg_out_mov(s, ts->type, reg, ts->reg)) { 4349240c08d0SRichard Henderson /* 4350240c08d0SRichard Henderson * Cross register class move not supported. Sync the 4351240c08d0SRichard Henderson * temp back to its slot and load from there. 4352240c08d0SRichard Henderson */ 4353240c08d0SRichard Henderson temp_sync(s, ts, i_allocated_regs, 0, 0); 4354240c08d0SRichard Henderson tcg_out_ld(s, ts->type, reg, 4355240c08d0SRichard Henderson ts->mem_base->reg, ts->mem_offset); 435678113e83SRichard Henderson } 4357c896fe29Sbellard } 4358c896fe29Sbellard new_args[i] = reg; 4359c896fe29Sbellard const_args[i] = 0; 436082790a87SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg); 4361c896fe29Sbellard } 4362c896fe29Sbellard 4363c896fe29Sbellard /* mark dead temporaries and free the associated registers */ 4364866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 4365866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) { 436643439139SRichard Henderson temp_dead(s, arg_temp(op->args[i])); 4367c896fe29Sbellard } 4368c896fe29Sbellard } 4369c896fe29Sbellard 4370b4cb76e6SRichard Henderson if (def->flags & TCG_OPF_COND_BRANCH) { 4371b4cb76e6SRichard Henderson tcg_reg_alloc_cbranch(s, i_allocated_regs); 4372b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 437382790a87SRichard Henderson tcg_reg_alloc_bb_end(s, i_allocated_regs); 4374a52ad07eSAurelien Jarno } else { 4375c896fe29Sbellard if (def->flags & TCG_OPF_CALL_CLOBBER) { 4376b03cce8eSbellard /* XXX: permit generic clobber register list ? */ 4377c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) { 4378c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { 437982790a87SRichard Henderson tcg_reg_free(s, i, i_allocated_regs); 4380c896fe29Sbellard } 4381c896fe29Sbellard } 43823d5c5f87SAurelien Jarno } 43833d5c5f87SAurelien Jarno if (def->flags & TCG_OPF_SIDE_EFFECTS) { 43843d5c5f87SAurelien Jarno /* sync globals if the op has side effects and might trigger 43853d5c5f87SAurelien Jarno an exception. */ 438682790a87SRichard Henderson sync_globals(s, i_allocated_regs); 4387c896fe29Sbellard } 4388c896fe29Sbellard 4389c896fe29Sbellard /* satisfy the output constraints */ 4390c896fe29Sbellard for(k = 0; k < nb_oargs; k++) { 439166792f90SRichard Henderson i = def->args_ct[k].sort_index; 4392dd186292SRichard Henderson arg = op->args[i]; 4393c896fe29Sbellard arg_ct = &def->args_ct[i]; 439443439139SRichard Henderson ts = arg_temp(arg); 4395d63e3b6eSRichard Henderson 4396d63e3b6eSRichard Henderson /* ENV should not be modified. */ 4397e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ts)); 4398d63e3b6eSRichard Henderson 439929f5e925SRichard Henderson switch (arg_ct->pair) { 440029f5e925SRichard Henderson case 0: /* not paired */ 4401bc2b17e6SRichard Henderson if (arg_ct->oalias && !const_args[arg_ct->alias_index]) { 44025ff9d6a4Sbellard reg = new_args[arg_ct->alias_index]; 4403bc2b17e6SRichard Henderson } else if (arg_ct->newreg) { 44049be0d080SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->regs, 440582790a87SRichard Henderson i_allocated_regs | o_allocated_regs, 440631fd884bSRichard Henderson output_pref(op, k), ts->indirect_base); 4407c896fe29Sbellard } else { 44089be0d080SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs, 440931fd884bSRichard Henderson output_pref(op, k), ts->indirect_base); 4410c896fe29Sbellard } 441129f5e925SRichard Henderson break; 441229f5e925SRichard Henderson 441329f5e925SRichard Henderson case 1: /* first of pair */ 441429f5e925SRichard Henderson tcg_debug_assert(!arg_ct->newreg); 441529f5e925SRichard Henderson if (arg_ct->oalias) { 441629f5e925SRichard Henderson reg = new_args[arg_ct->alias_index]; 441729f5e925SRichard Henderson break; 441829f5e925SRichard Henderson } 441929f5e925SRichard Henderson reg = tcg_reg_alloc_pair(s, arg_ct->regs, o_allocated_regs, 442031fd884bSRichard Henderson output_pref(op, k), ts->indirect_base); 442129f5e925SRichard Henderson break; 442229f5e925SRichard Henderson 442329f5e925SRichard Henderson case 2: /* second of pair */ 442429f5e925SRichard Henderson tcg_debug_assert(!arg_ct->newreg); 442529f5e925SRichard Henderson if (arg_ct->oalias) { 442629f5e925SRichard Henderson reg = new_args[arg_ct->alias_index]; 442729f5e925SRichard Henderson } else { 442829f5e925SRichard Henderson reg = new_args[arg_ct->pair_index] + 1; 442929f5e925SRichard Henderson } 443029f5e925SRichard Henderson break; 443129f5e925SRichard Henderson 443229f5e925SRichard Henderson case 3: /* first of pair, aliasing with a second input */ 443329f5e925SRichard Henderson tcg_debug_assert(!arg_ct->newreg); 443429f5e925SRichard Henderson reg = new_args[arg_ct->pair_index] - 1; 443529f5e925SRichard Henderson break; 443629f5e925SRichard Henderson 443729f5e925SRichard Henderson default: 443829f5e925SRichard Henderson g_assert_not_reached(); 443929f5e925SRichard Henderson } 444082790a87SRichard Henderson tcg_regset_set_reg(o_allocated_regs, reg); 4441098859f1SRichard Henderson set_temp_val_reg(s, ts, reg); 4442c896fe29Sbellard ts->mem_coherent = 0; 4443c896fe29Sbellard new_args[i] = reg; 4444c896fe29Sbellard } 4445e8996ee0Sbellard } 4446c896fe29Sbellard 4447c896fe29Sbellard /* emit instruction */ 4448d2fd745fSRichard Henderson if (def->flags & TCG_OPF_VECTOR) { 4449d2fd745fSRichard Henderson tcg_out_vec_op(s, op->opc, TCGOP_VECL(op), TCGOP_VECE(op), 4450d2fd745fSRichard Henderson new_args, const_args); 4451d2fd745fSRichard Henderson } else { 4452dd186292SRichard Henderson tcg_out_op(s, op->opc, new_args, const_args); 4453d2fd745fSRichard Henderson } 4454c896fe29Sbellard 4455c896fe29Sbellard /* move the outputs in the correct register if needed */ 4456c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 445743439139SRichard Henderson ts = arg_temp(op->args[i]); 4458d63e3b6eSRichard Henderson 4459d63e3b6eSRichard Henderson /* ENV should not be modified. */ 4460e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ts)); 4461d63e3b6eSRichard Henderson 4462ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) { 446398b4e186SRichard Henderson temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i)); 446459d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) { 4465f8bf00f1SRichard Henderson temp_dead(s, ts); 4466ec7a869dSAurelien Jarno } 4467c896fe29Sbellard } 4468c896fe29Sbellard } 4469c896fe29Sbellard 4470efe86b21SRichard Henderson static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op) 4471efe86b21SRichard Henderson { 4472efe86b21SRichard Henderson const TCGLifeData arg_life = op->life; 4473efe86b21SRichard Henderson TCGTemp *ots, *itsl, *itsh; 4474efe86b21SRichard Henderson TCGType vtype = TCGOP_VECL(op) + TCG_TYPE_V64; 4475efe86b21SRichard Henderson 4476efe86b21SRichard Henderson /* This opcode is only valid for 32-bit hosts, for 64-bit elements. */ 4477efe86b21SRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 32); 4478efe86b21SRichard Henderson tcg_debug_assert(TCGOP_VECE(op) == MO_64); 4479efe86b21SRichard Henderson 4480efe86b21SRichard Henderson ots = arg_temp(op->args[0]); 4481efe86b21SRichard Henderson itsl = arg_temp(op->args[1]); 4482efe86b21SRichard Henderson itsh = arg_temp(op->args[2]); 4483efe86b21SRichard Henderson 4484efe86b21SRichard Henderson /* ENV should not be modified. */ 4485efe86b21SRichard Henderson tcg_debug_assert(!temp_readonly(ots)); 4486efe86b21SRichard Henderson 4487efe86b21SRichard Henderson /* Allocate the output register now. */ 4488efe86b21SRichard Henderson if (ots->val_type != TEMP_VAL_REG) { 4489efe86b21SRichard Henderson TCGRegSet allocated_regs = s->reserved_regs; 4490efe86b21SRichard Henderson TCGRegSet dup_out_regs = 4491efe86b21SRichard Henderson tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs; 4492098859f1SRichard Henderson TCGReg oreg; 4493efe86b21SRichard Henderson 4494efe86b21SRichard Henderson /* Make sure to not spill the input registers. */ 4495efe86b21SRichard Henderson if (!IS_DEAD_ARG(1) && itsl->val_type == TEMP_VAL_REG) { 4496efe86b21SRichard Henderson tcg_regset_set_reg(allocated_regs, itsl->reg); 4497efe86b21SRichard Henderson } 4498efe86b21SRichard Henderson if (!IS_DEAD_ARG(2) && itsh->val_type == TEMP_VAL_REG) { 4499efe86b21SRichard Henderson tcg_regset_set_reg(allocated_regs, itsh->reg); 4500efe86b21SRichard Henderson } 4501efe86b21SRichard Henderson 4502098859f1SRichard Henderson oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs, 450331fd884bSRichard Henderson output_pref(op, 0), ots->indirect_base); 4504098859f1SRichard Henderson set_temp_val_reg(s, ots, oreg); 4505efe86b21SRichard Henderson } 4506efe86b21SRichard Henderson 4507efe86b21SRichard Henderson /* Promote dup2 of immediates to dupi_vec. */ 4508efe86b21SRichard Henderson if (itsl->val_type == TEMP_VAL_CONST && itsh->val_type == TEMP_VAL_CONST) { 4509efe86b21SRichard Henderson uint64_t val = deposit64(itsl->val, 32, 32, itsh->val); 4510efe86b21SRichard Henderson MemOp vece = MO_64; 4511efe86b21SRichard Henderson 4512efe86b21SRichard Henderson if (val == dup_const(MO_8, val)) { 4513efe86b21SRichard Henderson vece = MO_8; 4514efe86b21SRichard Henderson } else if (val == dup_const(MO_16, val)) { 4515efe86b21SRichard Henderson vece = MO_16; 4516efe86b21SRichard Henderson } else if (val == dup_const(MO_32, val)) { 4517efe86b21SRichard Henderson vece = MO_32; 4518efe86b21SRichard Henderson } 4519efe86b21SRichard Henderson 4520efe86b21SRichard Henderson tcg_out_dupi_vec(s, vtype, vece, ots->reg, val); 4521efe86b21SRichard Henderson goto done; 4522efe86b21SRichard Henderson } 4523efe86b21SRichard Henderson 4524efe86b21SRichard Henderson /* If the two inputs form one 64-bit value, try dupm_vec. */ 4525aef85402SRichard Henderson if (itsl->temp_subindex == HOST_BIG_ENDIAN && 4526aef85402SRichard Henderson itsh->temp_subindex == !HOST_BIG_ENDIAN && 4527aef85402SRichard Henderson itsl == itsh + (HOST_BIG_ENDIAN ? 1 : -1)) { 4528aef85402SRichard Henderson TCGTemp *its = itsl - HOST_BIG_ENDIAN; 4529aef85402SRichard Henderson 4530aef85402SRichard Henderson temp_sync(s, its + 0, s->reserved_regs, 0, 0); 4531aef85402SRichard Henderson temp_sync(s, its + 1, s->reserved_regs, 0, 0); 4532aef85402SRichard Henderson 4533efe86b21SRichard Henderson if (tcg_out_dupm_vec(s, vtype, MO_64, ots->reg, 4534efe86b21SRichard Henderson its->mem_base->reg, its->mem_offset)) { 4535efe86b21SRichard Henderson goto done; 4536efe86b21SRichard Henderson } 4537efe86b21SRichard Henderson } 4538efe86b21SRichard Henderson 4539efe86b21SRichard Henderson /* Fall back to generic expansion. */ 4540efe86b21SRichard Henderson return false; 4541efe86b21SRichard Henderson 4542efe86b21SRichard Henderson done: 454336f5539cSRichard Henderson ots->mem_coherent = 0; 4544efe86b21SRichard Henderson if (IS_DEAD_ARG(1)) { 4545efe86b21SRichard Henderson temp_dead(s, itsl); 4546efe86b21SRichard Henderson } 4547efe86b21SRichard Henderson if (IS_DEAD_ARG(2)) { 4548efe86b21SRichard Henderson temp_dead(s, itsh); 4549efe86b21SRichard Henderson } 4550efe86b21SRichard Henderson if (NEED_SYNC_ARG(0)) { 4551efe86b21SRichard Henderson temp_sync(s, ots, s->reserved_regs, 0, IS_DEAD_ARG(0)); 4552efe86b21SRichard Henderson } else if (IS_DEAD_ARG(0)) { 4553efe86b21SRichard Henderson temp_dead(s, ots); 4554efe86b21SRichard Henderson } 4555efe86b21SRichard Henderson return true; 4556efe86b21SRichard Henderson } 4557efe86b21SRichard Henderson 455839004a71SRichard Henderson static void load_arg_reg(TCGContext *s, TCGReg reg, TCGTemp *ts, 455939004a71SRichard Henderson TCGRegSet allocated_regs) 4560c896fe29Sbellard { 4561c896fe29Sbellard if (ts->val_type == TEMP_VAL_REG) { 4562c896fe29Sbellard if (ts->reg != reg) { 45634250da10SRichard Henderson tcg_reg_free(s, reg, allocated_regs); 456478113e83SRichard Henderson if (!tcg_out_mov(s, ts->type, reg, ts->reg)) { 4565240c08d0SRichard Henderson /* 4566240c08d0SRichard Henderson * Cross register class move not supported. Sync the 4567240c08d0SRichard Henderson * temp back to its slot and load from there. 4568240c08d0SRichard Henderson */ 4569240c08d0SRichard Henderson temp_sync(s, ts, allocated_regs, 0, 0); 4570240c08d0SRichard Henderson tcg_out_ld(s, ts->type, reg, 4571240c08d0SRichard Henderson ts->mem_base->reg, ts->mem_offset); 457278113e83SRichard Henderson } 4573c896fe29Sbellard } 4574c896fe29Sbellard } else { 4575ccb1bb66SRichard Henderson TCGRegSet arg_set = 0; 457640ae5c62SRichard Henderson 45774250da10SRichard Henderson tcg_reg_free(s, reg, allocated_regs); 457840ae5c62SRichard Henderson tcg_regset_set_reg(arg_set, reg); 4579b722452aSRichard Henderson temp_load(s, ts, arg_set, allocated_regs, 0); 4580c896fe29Sbellard } 458139004a71SRichard Henderson } 458240ae5c62SRichard Henderson 458339004a71SRichard Henderson static void load_arg_stk(TCGContext *s, int stk_slot, TCGTemp *ts, 458439004a71SRichard Henderson TCGRegSet allocated_regs) 458539004a71SRichard Henderson { 458639004a71SRichard Henderson /* 458739004a71SRichard Henderson * When the destination is on the stack, load up the temp and store. 458839004a71SRichard Henderson * If there are many call-saved registers, the temp might live to 458939004a71SRichard Henderson * see another use; otherwise it'll be discarded. 459039004a71SRichard Henderson */ 459139004a71SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], allocated_regs, 0); 459239004a71SRichard Henderson tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, 459339004a71SRichard Henderson TCG_TARGET_CALL_STACK_OFFSET + 459439004a71SRichard Henderson stk_slot * sizeof(tcg_target_long)); 459539004a71SRichard Henderson } 459639004a71SRichard Henderson 459739004a71SRichard Henderson static void load_arg_normal(TCGContext *s, const TCGCallArgumentLoc *l, 459839004a71SRichard Henderson TCGTemp *ts, TCGRegSet *allocated_regs) 459939004a71SRichard Henderson { 460039004a71SRichard Henderson if (REG_P(l)) { 460139004a71SRichard Henderson TCGReg reg = tcg_target_call_iarg_regs[l->arg_slot]; 460239004a71SRichard Henderson load_arg_reg(s, reg, ts, *allocated_regs); 460339004a71SRichard Henderson tcg_regset_set_reg(*allocated_regs, reg); 460439004a71SRichard Henderson } else { 460539004a71SRichard Henderson load_arg_stk(s, l->arg_slot - ARRAY_SIZE(tcg_target_call_iarg_regs), 460639004a71SRichard Henderson ts, *allocated_regs); 4607c896fe29Sbellard } 460839cf05d3Sbellard } 4609c896fe29Sbellard 4610313bdea8SRichard Henderson static void load_arg_ref(TCGContext *s, int arg_slot, TCGReg ref_base, 4611313bdea8SRichard Henderson intptr_t ref_off, TCGRegSet *allocated_regs) 4612313bdea8SRichard Henderson { 4613313bdea8SRichard Henderson TCGReg reg; 4614313bdea8SRichard Henderson int stk_slot = arg_slot - ARRAY_SIZE(tcg_target_call_iarg_regs); 4615313bdea8SRichard Henderson 4616313bdea8SRichard Henderson if (stk_slot < 0) { 4617313bdea8SRichard Henderson reg = tcg_target_call_iarg_regs[arg_slot]; 4618313bdea8SRichard Henderson tcg_reg_free(s, reg, *allocated_regs); 4619313bdea8SRichard Henderson tcg_out_addi_ptr(s, reg, ref_base, ref_off); 4620313bdea8SRichard Henderson tcg_regset_set_reg(*allocated_regs, reg); 4621313bdea8SRichard Henderson } else { 4622313bdea8SRichard Henderson reg = tcg_reg_alloc(s, tcg_target_available_regs[TCG_TYPE_PTR], 4623313bdea8SRichard Henderson *allocated_regs, 0, false); 4624313bdea8SRichard Henderson tcg_out_addi_ptr(s, reg, ref_base, ref_off); 4625313bdea8SRichard Henderson tcg_out_st(s, TCG_TYPE_PTR, reg, TCG_REG_CALL_STACK, 4626313bdea8SRichard Henderson TCG_TARGET_CALL_STACK_OFFSET 4627313bdea8SRichard Henderson + stk_slot * sizeof(tcg_target_long)); 4628313bdea8SRichard Henderson } 4629313bdea8SRichard Henderson } 4630313bdea8SRichard Henderson 463139004a71SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op) 463239004a71SRichard Henderson { 463339004a71SRichard Henderson const int nb_oargs = TCGOP_CALLO(op); 463439004a71SRichard Henderson const int nb_iargs = TCGOP_CALLI(op); 463539004a71SRichard Henderson const TCGLifeData arg_life = op->life; 463639004a71SRichard Henderson const TCGHelperInfo *info = tcg_call_info(op); 463739004a71SRichard Henderson TCGRegSet allocated_regs = s->reserved_regs; 463839004a71SRichard Henderson int i; 463939004a71SRichard Henderson 464039004a71SRichard Henderson /* 464139004a71SRichard Henderson * Move inputs into place in reverse order, 464239004a71SRichard Henderson * so that we place stacked arguments first. 464339004a71SRichard Henderson */ 464439004a71SRichard Henderson for (i = nb_iargs - 1; i >= 0; --i) { 464539004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i]; 464639004a71SRichard Henderson TCGTemp *ts = arg_temp(op->args[nb_oargs + i]); 464739004a71SRichard Henderson 464839004a71SRichard Henderson switch (loc->kind) { 464939004a71SRichard Henderson case TCG_CALL_ARG_NORMAL: 465039004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U: 465139004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S: 465239004a71SRichard Henderson load_arg_normal(s, loc, ts, &allocated_regs); 465339004a71SRichard Henderson break; 4654313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF: 4655313bdea8SRichard Henderson load_arg_stk(s, loc->ref_slot, ts, allocated_regs); 4656313bdea8SRichard Henderson load_arg_ref(s, loc->arg_slot, TCG_REG_CALL_STACK, 4657313bdea8SRichard Henderson TCG_TARGET_CALL_STACK_OFFSET 4658313bdea8SRichard Henderson + loc->ref_slot * sizeof(tcg_target_long), 4659313bdea8SRichard Henderson &allocated_regs); 4660313bdea8SRichard Henderson break; 4661313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF_N: 4662313bdea8SRichard Henderson load_arg_stk(s, loc->ref_slot, ts, allocated_regs); 4663313bdea8SRichard Henderson break; 466439004a71SRichard Henderson default: 466539004a71SRichard Henderson g_assert_not_reached(); 466639004a71SRichard Henderson } 466739004a71SRichard Henderson } 466839004a71SRichard Henderson 466939004a71SRichard Henderson /* Mark dead temporaries and free the associated registers. */ 4670866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 4671866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) { 467243439139SRichard Henderson temp_dead(s, arg_temp(op->args[i])); 4673c896fe29Sbellard } 4674c896fe29Sbellard } 4675c896fe29Sbellard 467639004a71SRichard Henderson /* Clobber call registers. */ 4677c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) { 4678c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { 4679b3915dbbSRichard Henderson tcg_reg_free(s, i, allocated_regs); 4680c896fe29Sbellard } 4681c896fe29Sbellard } 4682c896fe29Sbellard 468339004a71SRichard Henderson /* 468439004a71SRichard Henderson * Save globals if they might be written by the helper, 468539004a71SRichard Henderson * sync them if they might be read. 468639004a71SRichard Henderson */ 468739004a71SRichard Henderson if (info->flags & TCG_CALL_NO_READ_GLOBALS) { 468878505279SAurelien Jarno /* Nothing to do */ 468939004a71SRichard Henderson } else if (info->flags & TCG_CALL_NO_WRITE_GLOBALS) { 469078505279SAurelien Jarno sync_globals(s, allocated_regs); 469178505279SAurelien Jarno } else { 4692e8996ee0Sbellard save_globals(s, allocated_regs); 4693b9c18f56Saurel32 } 4694c896fe29Sbellard 4695313bdea8SRichard Henderson /* 4696313bdea8SRichard Henderson * If the ABI passes a pointer to the returned struct as the first 4697313bdea8SRichard Henderson * argument, load that now. Pass a pointer to the output home slot. 4698313bdea8SRichard Henderson */ 4699313bdea8SRichard Henderson if (info->out_kind == TCG_CALL_RET_BY_REF) { 4700313bdea8SRichard Henderson TCGTemp *ts = arg_temp(op->args[0]); 4701313bdea8SRichard Henderson 4702313bdea8SRichard Henderson if (!ts->mem_allocated) { 4703313bdea8SRichard Henderson temp_allocate_frame(s, ts); 4704313bdea8SRichard Henderson } 4705313bdea8SRichard Henderson load_arg_ref(s, 0, ts->mem_base->reg, ts->mem_offset, &allocated_regs); 4706313bdea8SRichard Henderson } 4707313bdea8SRichard Henderson 4708cee44b03SRichard Henderson tcg_out_call(s, tcg_call_func(op), info); 4709c896fe29Sbellard 471039004a71SRichard Henderson /* Assign output registers and emit moves if needed. */ 471139004a71SRichard Henderson switch (info->out_kind) { 471239004a71SRichard Henderson case TCG_CALL_RET_NORMAL: 4713c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 471439004a71SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]); 47155e3d0c19SRichard Henderson TCGReg reg = tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, i); 4716d63e3b6eSRichard Henderson 4717d63e3b6eSRichard Henderson /* ENV should not be modified. */ 4718e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ts)); 4719d63e3b6eSRichard Henderson 4720098859f1SRichard Henderson set_temp_val_reg(s, ts, reg); 4721c896fe29Sbellard ts->mem_coherent = 0; 472239004a71SRichard Henderson } 472339004a71SRichard Henderson break; 4724313bdea8SRichard Henderson 4725c6556aa0SRichard Henderson case TCG_CALL_RET_BY_VEC: 4726c6556aa0SRichard Henderson { 4727c6556aa0SRichard Henderson TCGTemp *ts = arg_temp(op->args[0]); 4728c6556aa0SRichard Henderson 4729c6556aa0SRichard Henderson tcg_debug_assert(ts->base_type == TCG_TYPE_I128); 4730c6556aa0SRichard Henderson tcg_debug_assert(ts->temp_subindex == 0); 4731c6556aa0SRichard Henderson if (!ts->mem_allocated) { 4732c6556aa0SRichard Henderson temp_allocate_frame(s, ts); 4733c6556aa0SRichard Henderson } 4734c6556aa0SRichard Henderson tcg_out_st(s, TCG_TYPE_V128, 4735c6556aa0SRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0), 4736c6556aa0SRichard Henderson ts->mem_base->reg, ts->mem_offset); 4737c6556aa0SRichard Henderson } 4738c6556aa0SRichard Henderson /* fall through to mark all parts in memory */ 4739c6556aa0SRichard Henderson 4740313bdea8SRichard Henderson case TCG_CALL_RET_BY_REF: 4741313bdea8SRichard Henderson /* The callee has performed a write through the reference. */ 4742313bdea8SRichard Henderson for (i = 0; i < nb_oargs; i++) { 4743313bdea8SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]); 4744313bdea8SRichard Henderson ts->val_type = TEMP_VAL_MEM; 4745313bdea8SRichard Henderson } 4746313bdea8SRichard Henderson break; 4747313bdea8SRichard Henderson 474839004a71SRichard Henderson default: 474939004a71SRichard Henderson g_assert_not_reached(); 475039004a71SRichard Henderson } 475139004a71SRichard Henderson 475239004a71SRichard Henderson /* Flush or discard output registers as needed. */ 475339004a71SRichard Henderson for (i = 0; i < nb_oargs; i++) { 475439004a71SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]); 4755ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) { 475639004a71SRichard Henderson temp_sync(s, ts, s->reserved_regs, 0, IS_DEAD_ARG(i)); 475759d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) { 4758f8bf00f1SRichard Henderson temp_dead(s, ts); 4759c896fe29Sbellard } 4760c896fe29Sbellard } 47618c11ad25SAurelien Jarno } 4762c896fe29Sbellard 4763c896fe29Sbellard #ifdef CONFIG_PROFILER 4764c896fe29Sbellard 4765c3fac113SEmilio G. Cota /* avoid copy/paste errors */ 4766c3fac113SEmilio G. Cota #define PROF_ADD(to, from, field) \ 4767c3fac113SEmilio G. Cota do { \ 4768d73415a3SStefan Hajnoczi (to)->field += qatomic_read(&((from)->field)); \ 4769c3fac113SEmilio G. Cota } while (0) 4770c896fe29Sbellard 4771c3fac113SEmilio G. Cota #define PROF_MAX(to, from, field) \ 4772c3fac113SEmilio G. Cota do { \ 4773d73415a3SStefan Hajnoczi typeof((from)->field) val__ = qatomic_read(&((from)->field)); \ 4774c3fac113SEmilio G. Cota if (val__ > (to)->field) { \ 4775c3fac113SEmilio G. Cota (to)->field = val__; \ 4776c3fac113SEmilio G. Cota } \ 4777c3fac113SEmilio G. Cota } while (0) 4778c3fac113SEmilio G. Cota 4779c3fac113SEmilio G. Cota /* Pass in a zero'ed @prof */ 4780c3fac113SEmilio G. Cota static inline 4781c3fac113SEmilio G. Cota void tcg_profile_snapshot(TCGProfile *prof, bool counters, bool table) 4782c896fe29Sbellard { 47830e2d61cfSRichard Henderson unsigned int n_ctxs = qatomic_read(&tcg_cur_ctxs); 4784c3fac113SEmilio G. Cota unsigned int i; 4785c3fac113SEmilio G. Cota 47863468b59eSEmilio G. Cota for (i = 0; i < n_ctxs; i++) { 4787d73415a3SStefan Hajnoczi TCGContext *s = qatomic_read(&tcg_ctxs[i]); 47883468b59eSEmilio G. Cota const TCGProfile *orig = &s->prof; 4789c3fac113SEmilio G. Cota 4790c3fac113SEmilio G. Cota if (counters) { 479172fd2efbSEmilio G. Cota PROF_ADD(prof, orig, cpu_exec_time); 4792c3fac113SEmilio G. Cota PROF_ADD(prof, orig, tb_count1); 4793c3fac113SEmilio G. Cota PROF_ADD(prof, orig, tb_count); 4794c3fac113SEmilio G. Cota PROF_ADD(prof, orig, op_count); 4795c3fac113SEmilio G. Cota PROF_MAX(prof, orig, op_count_max); 4796c3fac113SEmilio G. Cota PROF_ADD(prof, orig, temp_count); 4797c3fac113SEmilio G. Cota PROF_MAX(prof, orig, temp_count_max); 4798c3fac113SEmilio G. Cota PROF_ADD(prof, orig, del_op_count); 4799c3fac113SEmilio G. Cota PROF_ADD(prof, orig, code_in_len); 4800c3fac113SEmilio G. Cota PROF_ADD(prof, orig, code_out_len); 4801c3fac113SEmilio G. Cota PROF_ADD(prof, orig, search_out_len); 4802c3fac113SEmilio G. Cota PROF_ADD(prof, orig, interm_time); 4803c3fac113SEmilio G. Cota PROF_ADD(prof, orig, code_time); 4804c3fac113SEmilio G. Cota PROF_ADD(prof, orig, la_time); 4805c3fac113SEmilio G. Cota PROF_ADD(prof, orig, opt_time); 4806c3fac113SEmilio G. Cota PROF_ADD(prof, orig, restore_count); 4807c3fac113SEmilio G. Cota PROF_ADD(prof, orig, restore_time); 4808c3fac113SEmilio G. Cota } 4809c3fac113SEmilio G. Cota if (table) { 4810c896fe29Sbellard int i; 4811d70724ceSzhanghailiang 481215fc7daaSRichard Henderson for (i = 0; i < NB_OPS; i++) { 4813c3fac113SEmilio G. Cota PROF_ADD(prof, orig, table_op_count[i]); 4814c3fac113SEmilio G. Cota } 4815c3fac113SEmilio G. Cota } 4816c3fac113SEmilio G. Cota } 4817c3fac113SEmilio G. Cota } 4818c3fac113SEmilio G. Cota 4819c3fac113SEmilio G. Cota #undef PROF_ADD 4820c3fac113SEmilio G. Cota #undef PROF_MAX 4821c3fac113SEmilio G. Cota 4822c3fac113SEmilio G. Cota static void tcg_profile_snapshot_counters(TCGProfile *prof) 4823c3fac113SEmilio G. Cota { 4824c3fac113SEmilio G. Cota tcg_profile_snapshot(prof, true, false); 4825c3fac113SEmilio G. Cota } 4826c3fac113SEmilio G. Cota 4827c3fac113SEmilio G. Cota static void tcg_profile_snapshot_table(TCGProfile *prof) 4828c3fac113SEmilio G. Cota { 4829c3fac113SEmilio G. Cota tcg_profile_snapshot(prof, false, true); 4830c3fac113SEmilio G. Cota } 4831c3fac113SEmilio G. Cota 4832b6a7f3e0SDaniel P. Berrangé void tcg_dump_op_count(GString *buf) 4833c3fac113SEmilio G. Cota { 4834c3fac113SEmilio G. Cota TCGProfile prof = {}; 4835c3fac113SEmilio G. Cota int i; 4836c3fac113SEmilio G. Cota 4837c3fac113SEmilio G. Cota tcg_profile_snapshot_table(&prof); 4838c3fac113SEmilio G. Cota for (i = 0; i < NB_OPS; i++) { 4839b6a7f3e0SDaniel P. Berrangé g_string_append_printf(buf, "%s %" PRId64 "\n", tcg_op_defs[i].name, 4840c3fac113SEmilio G. Cota prof.table_op_count[i]); 4841c896fe29Sbellard } 4842c896fe29Sbellard } 484372fd2efbSEmilio G. Cota 484472fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void) 484572fd2efbSEmilio G. Cota { 48460e2d61cfSRichard Henderson unsigned int n_ctxs = qatomic_read(&tcg_cur_ctxs); 484772fd2efbSEmilio G. Cota unsigned int i; 484872fd2efbSEmilio G. Cota int64_t ret = 0; 484972fd2efbSEmilio G. Cota 485072fd2efbSEmilio G. Cota for (i = 0; i < n_ctxs; i++) { 4851d73415a3SStefan Hajnoczi const TCGContext *s = qatomic_read(&tcg_ctxs[i]); 485272fd2efbSEmilio G. Cota const TCGProfile *prof = &s->prof; 485372fd2efbSEmilio G. Cota 4854d73415a3SStefan Hajnoczi ret += qatomic_read(&prof->cpu_exec_time); 485572fd2efbSEmilio G. Cota } 485672fd2efbSEmilio G. Cota return ret; 485772fd2efbSEmilio G. Cota } 4858246ae24dSMax Filippov #else 4859b6a7f3e0SDaniel P. Berrangé void tcg_dump_op_count(GString *buf) 4860246ae24dSMax Filippov { 4861b6a7f3e0SDaniel P. Berrangé g_string_append_printf(buf, "[TCG profiler not compiled]\n"); 4862246ae24dSMax Filippov } 486372fd2efbSEmilio G. Cota 486472fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void) 486572fd2efbSEmilio G. Cota { 486672fd2efbSEmilio G. Cota error_report("%s: TCG profiler not compiled", __func__); 486772fd2efbSEmilio G. Cota exit(EXIT_FAILURE); 486872fd2efbSEmilio G. Cota } 4869c896fe29Sbellard #endif 4870c896fe29Sbellard 4871c896fe29Sbellard 4872fbf59aadSRichard Henderson int tcg_gen_code(TCGContext *s, TranslationBlock *tb, target_ulong pc_start) 4873c896fe29Sbellard { 4874c3fac113SEmilio G. Cota #ifdef CONFIG_PROFILER 4875c3fac113SEmilio G. Cota TCGProfile *prof = &s->prof; 4876c3fac113SEmilio G. Cota #endif 487715fa08f8SRichard Henderson int i, num_insns; 487815fa08f8SRichard Henderson TCGOp *op; 4879c896fe29Sbellard 488004fe6400SRichard Henderson #ifdef CONFIG_PROFILER 488104fe6400SRichard Henderson { 4882c1f543b7SEmilio G. Cota int n = 0; 488304fe6400SRichard Henderson 488415fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 488515fa08f8SRichard Henderson n++; 488615fa08f8SRichard Henderson } 4887d73415a3SStefan Hajnoczi qatomic_set(&prof->op_count, prof->op_count + n); 4888c3fac113SEmilio G. Cota if (n > prof->op_count_max) { 4889d73415a3SStefan Hajnoczi qatomic_set(&prof->op_count_max, n); 489004fe6400SRichard Henderson } 489104fe6400SRichard Henderson 489204fe6400SRichard Henderson n = s->nb_temps; 4893d73415a3SStefan Hajnoczi qatomic_set(&prof->temp_count, prof->temp_count + n); 4894c3fac113SEmilio G. Cota if (n > prof->temp_count_max) { 4895d73415a3SStefan Hajnoczi qatomic_set(&prof->temp_count_max, n); 489604fe6400SRichard Henderson } 489704fe6400SRichard Henderson } 489804fe6400SRichard Henderson #endif 489904fe6400SRichard Henderson 4900c896fe29Sbellard #ifdef DEBUG_DISAS 4901d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP) 4902fbf59aadSRichard Henderson && qemu_log_in_addr_range(pc_start))) { 4903c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock(); 490478b54858SRichard Henderson if (logfile) { 490578b54858SRichard Henderson fprintf(logfile, "OP:\n"); 4906b7a83ff8SRichard Henderson tcg_dump_ops(s, logfile, false); 490778b54858SRichard Henderson fprintf(logfile, "\n"); 4908fc59d2d8SRobert Foley qemu_log_unlock(logfile); 4909c896fe29Sbellard } 491078b54858SRichard Henderson } 4911c896fe29Sbellard #endif 4912c896fe29Sbellard 4913bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG 4914bef16ab4SRichard Henderson /* Ensure all labels referenced have been emitted. */ 4915bef16ab4SRichard Henderson { 4916bef16ab4SRichard Henderson TCGLabel *l; 4917bef16ab4SRichard Henderson bool error = false; 4918bef16ab4SRichard Henderson 4919bef16ab4SRichard Henderson QSIMPLEQ_FOREACH(l, &s->labels, next) { 4920bef16ab4SRichard Henderson if (unlikely(!l->present) && l->refs) { 4921bef16ab4SRichard Henderson qemu_log_mask(CPU_LOG_TB_OP, 4922bef16ab4SRichard Henderson "$L%d referenced but not present.\n", l->id); 4923bef16ab4SRichard Henderson error = true; 4924bef16ab4SRichard Henderson } 4925bef16ab4SRichard Henderson } 4926bef16ab4SRichard Henderson assert(!error); 4927bef16ab4SRichard Henderson } 4928bef16ab4SRichard Henderson #endif 4929bef16ab4SRichard Henderson 4930c5cc28ffSAurelien Jarno #ifdef CONFIG_PROFILER 4931d73415a3SStefan Hajnoczi qatomic_set(&prof->opt_time, prof->opt_time - profile_getclock()); 4932c5cc28ffSAurelien Jarno #endif 4933c5cc28ffSAurelien Jarno 49348f2e8c07SKirill Batuzov #ifdef USE_TCG_OPTIMIZATIONS 4935c45cb8bbSRichard Henderson tcg_optimize(s); 49368f2e8c07SKirill Batuzov #endif 49378f2e8c07SKirill Batuzov 4938a23a9ec6Sbellard #ifdef CONFIG_PROFILER 4939d73415a3SStefan Hajnoczi qatomic_set(&prof->opt_time, prof->opt_time + profile_getclock()); 4940d73415a3SStefan Hajnoczi qatomic_set(&prof->la_time, prof->la_time - profile_getclock()); 4941a23a9ec6Sbellard #endif 4942c5cc28ffSAurelien Jarno 4943b4fc67c7SRichard Henderson reachable_code_pass(s); 4944*874b8574SRichard Henderson liveness_pass_0(s); 4945b83eabeaSRichard Henderson liveness_pass_1(s); 49465a18407fSRichard Henderson 49475a18407fSRichard Henderson if (s->nb_indirects > 0) { 49485a18407fSRichard Henderson #ifdef DEBUG_DISAS 49495a18407fSRichard Henderson if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND) 4950fbf59aadSRichard Henderson && qemu_log_in_addr_range(pc_start))) { 4951c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock(); 495278b54858SRichard Henderson if (logfile) { 495378b54858SRichard Henderson fprintf(logfile, "OP before indirect lowering:\n"); 4954b7a83ff8SRichard Henderson tcg_dump_ops(s, logfile, false); 495578b54858SRichard Henderson fprintf(logfile, "\n"); 4956fc59d2d8SRobert Foley qemu_log_unlock(logfile); 49575a18407fSRichard Henderson } 495878b54858SRichard Henderson } 49595a18407fSRichard Henderson #endif 49605a18407fSRichard Henderson /* Replace indirect temps with direct temps. */ 4961b83eabeaSRichard Henderson if (liveness_pass_2(s)) { 49625a18407fSRichard Henderson /* If changes were made, re-run liveness. */ 4963b83eabeaSRichard Henderson liveness_pass_1(s); 49645a18407fSRichard Henderson } 49655a18407fSRichard Henderson } 4966c5cc28ffSAurelien Jarno 4967a23a9ec6Sbellard #ifdef CONFIG_PROFILER 4968d73415a3SStefan Hajnoczi qatomic_set(&prof->la_time, prof->la_time + profile_getclock()); 4969a23a9ec6Sbellard #endif 4970c896fe29Sbellard 4971c896fe29Sbellard #ifdef DEBUG_DISAS 4972d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT) 4973fbf59aadSRichard Henderson && qemu_log_in_addr_range(pc_start))) { 4974c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock(); 497578b54858SRichard Henderson if (logfile) { 497678b54858SRichard Henderson fprintf(logfile, "OP after optimization and liveness analysis:\n"); 4977b7a83ff8SRichard Henderson tcg_dump_ops(s, logfile, true); 497878b54858SRichard Henderson fprintf(logfile, "\n"); 4979fc59d2d8SRobert Foley qemu_log_unlock(logfile); 4980c896fe29Sbellard } 498178b54858SRichard Henderson } 4982c896fe29Sbellard #endif 4983c896fe29Sbellard 498435abb009SRichard Henderson /* Initialize goto_tb jump offsets. */ 49853a50f424SRichard Henderson tb->jmp_reset_offset[0] = TB_JMP_OFFSET_INVALID; 49863a50f424SRichard Henderson tb->jmp_reset_offset[1] = TB_JMP_OFFSET_INVALID; 49879da6079bSRichard Henderson tb->jmp_insn_offset[0] = TB_JMP_OFFSET_INVALID; 49889da6079bSRichard Henderson tb->jmp_insn_offset[1] = TB_JMP_OFFSET_INVALID; 498935abb009SRichard Henderson 4990c896fe29Sbellard tcg_reg_alloc_start(s); 4991c896fe29Sbellard 4992db0c51a3SRichard Henderson /* 4993db0c51a3SRichard Henderson * Reset the buffer pointers when restarting after overflow. 4994db0c51a3SRichard Henderson * TODO: Move this into translate-all.c with the rest of the 4995db0c51a3SRichard Henderson * buffer management. Having only this done here is confusing. 4996db0c51a3SRichard Henderson */ 4997db0c51a3SRichard Henderson s->code_buf = tcg_splitwx_to_rw(tb->tc.ptr); 4998db0c51a3SRichard Henderson s->code_ptr = s->code_buf; 4999c896fe29Sbellard 5000659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS 50016001f772SLaurent Vivier QSIMPLEQ_INIT(&s->ldst_labels); 5002659ef5cbSRichard Henderson #endif 500357a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 500457a26946SRichard Henderson s->pool_labels = NULL; 500557a26946SRichard Henderson #endif 50069ecefc84SRichard Henderson 5007fca8a500SRichard Henderson num_insns = -1; 500815fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 5009c45cb8bbSRichard Henderson TCGOpcode opc = op->opc; 5010b3db8758Sblueswir1 5011c896fe29Sbellard #ifdef CONFIG_PROFILER 5012d73415a3SStefan Hajnoczi qatomic_set(&prof->table_op_count[opc], prof->table_op_count[opc] + 1); 5013c896fe29Sbellard #endif 5014c45cb8bbSRichard Henderson 5015c896fe29Sbellard switch (opc) { 5016c896fe29Sbellard case INDEX_op_mov_i32: 5017c896fe29Sbellard case INDEX_op_mov_i64: 5018d2fd745fSRichard Henderson case INDEX_op_mov_vec: 5019dd186292SRichard Henderson tcg_reg_alloc_mov(s, op); 5020c896fe29Sbellard break; 5021bab1671fSRichard Henderson case INDEX_op_dup_vec: 5022bab1671fSRichard Henderson tcg_reg_alloc_dup(s, op); 5023bab1671fSRichard Henderson break; 5024765b842aSRichard Henderson case INDEX_op_insn_start: 5025fca8a500SRichard Henderson if (num_insns >= 0) { 50269f754620SRichard Henderson size_t off = tcg_current_code_size(s); 50279f754620SRichard Henderson s->gen_insn_end_off[num_insns] = off; 50289f754620SRichard Henderson /* Assert that we do not overflow our stored offset. */ 50299f754620SRichard Henderson assert(s->gen_insn_end_off[num_insns] == off); 5030fca8a500SRichard Henderson } 5031fca8a500SRichard Henderson num_insns++; 5032bad729e2SRichard Henderson for (i = 0; i < TARGET_INSN_START_WORDS; ++i) { 5033bad729e2SRichard Henderson target_ulong a; 5034bad729e2SRichard Henderson #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS 5035efee3746SRichard Henderson a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]); 5036bad729e2SRichard Henderson #else 5037efee3746SRichard Henderson a = op->args[i]; 5038bad729e2SRichard Henderson #endif 5039fca8a500SRichard Henderson s->gen_insn_data[num_insns][i] = a; 5040bad729e2SRichard Henderson } 5041c896fe29Sbellard break; 50425ff9d6a4Sbellard case INDEX_op_discard: 504343439139SRichard Henderson temp_dead(s, arg_temp(op->args[0])); 50445ff9d6a4Sbellard break; 5045c896fe29Sbellard case INDEX_op_set_label: 5046e8996ee0Sbellard tcg_reg_alloc_bb_end(s, s->reserved_regs); 504792ab8e7dSRichard Henderson tcg_out_label(s, arg_label(op->args[0])); 5048c896fe29Sbellard break; 5049c896fe29Sbellard case INDEX_op_call: 5050dd186292SRichard Henderson tcg_reg_alloc_call(s, op); 5051c45cb8bbSRichard Henderson break; 5052b55a8d9dSRichard Henderson case INDEX_op_exit_tb: 5053b55a8d9dSRichard Henderson tcg_out_exit_tb(s, op->args[0]); 5054b55a8d9dSRichard Henderson break; 5055cf7d6b8eSRichard Henderson case INDEX_op_goto_tb: 5056cf7d6b8eSRichard Henderson tcg_out_goto_tb(s, op->args[0]); 5057cf7d6b8eSRichard Henderson break; 5058efe86b21SRichard Henderson case INDEX_op_dup2_vec: 5059efe86b21SRichard Henderson if (tcg_reg_alloc_dup2(s, op)) { 5060efe86b21SRichard Henderson break; 5061efe86b21SRichard Henderson } 5062efe86b21SRichard Henderson /* fall through */ 5063c896fe29Sbellard default: 506425c4d9ccSRichard Henderson /* Sanity check that we've not introduced any unhandled opcodes. */ 5065be0f34b5SRichard Henderson tcg_debug_assert(tcg_op_supported(opc)); 5066c896fe29Sbellard /* Note: in order to speed up the code, it would be much 5067c896fe29Sbellard faster to have specialized register allocator functions for 5068c896fe29Sbellard some common argument patterns */ 5069dd186292SRichard Henderson tcg_reg_alloc_op(s, op); 5070c896fe29Sbellard break; 5071c896fe29Sbellard } 5072b125f9dcSRichard Henderson /* Test for (pending) buffer overflow. The assumption is that any 5073b125f9dcSRichard Henderson one operation beginning below the high water mark cannot overrun 5074b125f9dcSRichard Henderson the buffer completely. Thus we can test for overflow after 5075b125f9dcSRichard Henderson generating code without having to check during generation. */ 5076644da9b3SJohn Clarke if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) { 5077b125f9dcSRichard Henderson return -1; 5078b125f9dcSRichard Henderson } 50796e6c4efeSRichard Henderson /* Test for TB overflow, as seen by gen_insn_end_off. */ 50806e6c4efeSRichard Henderson if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) { 50816e6c4efeSRichard Henderson return -2; 50826e6c4efeSRichard Henderson } 5083c896fe29Sbellard } 5084fca8a500SRichard Henderson tcg_debug_assert(num_insns >= 0); 5085fca8a500SRichard Henderson s->gen_insn_end_off[num_insns] = tcg_current_code_size(s); 5086c45cb8bbSRichard Henderson 5087b76f0d8cSYeongkyoon Lee /* Generate TB finalization at the end of block */ 5088659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS 5089aeee05f5SRichard Henderson i = tcg_out_ldst_finalize(s); 5090aeee05f5SRichard Henderson if (i < 0) { 5091aeee05f5SRichard Henderson return i; 509223dceda6SRichard Henderson } 5093659ef5cbSRichard Henderson #endif 509457a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 50951768987bSRichard Henderson i = tcg_out_pool_finalize(s); 50961768987bSRichard Henderson if (i < 0) { 50971768987bSRichard Henderson return i; 509857a26946SRichard Henderson } 509957a26946SRichard Henderson #endif 51007ecd02a0SRichard Henderson if (!tcg_resolve_relocs(s)) { 51017ecd02a0SRichard Henderson return -2; 51027ecd02a0SRichard Henderson } 5103c896fe29Sbellard 5104df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER 5105c896fe29Sbellard /* flush instruction cache */ 5106db0c51a3SRichard Henderson flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf), 5107db0c51a3SRichard Henderson (uintptr_t)s->code_buf, 51081da8de39SRichard Henderson tcg_ptr_byte_diff(s->code_ptr, s->code_buf)); 5109df5d2b16SRichard Henderson #endif 51102aeabc08SStefan Weil 51111813e175SRichard Henderson return tcg_current_code_size(s); 5112c896fe29Sbellard } 5113c896fe29Sbellard 5114a23a9ec6Sbellard #ifdef CONFIG_PROFILER 51153a841ab5SDaniel P. Berrangé void tcg_dump_info(GString *buf) 5116a23a9ec6Sbellard { 5117c3fac113SEmilio G. Cota TCGProfile prof = {}; 5118c3fac113SEmilio G. Cota const TCGProfile *s; 5119c3fac113SEmilio G. Cota int64_t tb_count; 5120c3fac113SEmilio G. Cota int64_t tb_div_count; 5121c3fac113SEmilio G. Cota int64_t tot; 5122c3fac113SEmilio G. Cota 5123c3fac113SEmilio G. Cota tcg_profile_snapshot_counters(&prof); 5124c3fac113SEmilio G. Cota s = &prof; 5125c3fac113SEmilio G. Cota tb_count = s->tb_count; 5126c3fac113SEmilio G. Cota tb_div_count = tb_count ? tb_count : 1; 5127c3fac113SEmilio G. Cota tot = s->interm_time + s->code_time; 5128a23a9ec6Sbellard 51293a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "JIT cycles %" PRId64 51303a841ab5SDaniel P. Berrangé " (%0.3f s at 2.4 GHz)\n", 5131a23a9ec6Sbellard tot, tot / 2.4e9); 51323a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "translated TBs %" PRId64 51333a841ab5SDaniel P. Berrangé " (aborted=%" PRId64 " %0.1f%%)\n", 5134fca8a500SRichard Henderson tb_count, s->tb_count1 - tb_count, 5135fca8a500SRichard Henderson (double)(s->tb_count1 - s->tb_count) 5136fca8a500SRichard Henderson / (s->tb_count1 ? s->tb_count1 : 1) * 100.0); 51373a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "avg ops/TB %0.1f max=%d\n", 5138fca8a500SRichard Henderson (double)s->op_count / tb_div_count, s->op_count_max); 51393a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "deleted ops/TB %0.2f\n", 5140fca8a500SRichard Henderson (double)s->del_op_count / tb_div_count); 51413a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "avg temps/TB %0.2f max=%d\n", 51423a841ab5SDaniel P. Berrangé (double)s->temp_count / tb_div_count, 51433a841ab5SDaniel P. Berrangé s->temp_count_max); 51443a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "avg host code/TB %0.1f\n", 5145fca8a500SRichard Henderson (double)s->code_out_len / tb_div_count); 51463a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "avg search data/TB %0.1f\n", 5147fca8a500SRichard Henderson (double)s->search_out_len / tb_div_count); 5148a23a9ec6Sbellard 51493a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "cycles/op %0.1f\n", 5150a23a9ec6Sbellard s->op_count ? (double)tot / s->op_count : 0); 51513a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "cycles/in byte %0.1f\n", 5152a23a9ec6Sbellard s->code_in_len ? (double)tot / s->code_in_len : 0); 51533a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "cycles/out byte %0.1f\n", 5154a23a9ec6Sbellard s->code_out_len ? (double)tot / s->code_out_len : 0); 51553a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "cycles/search byte %0.1f\n", 51563a841ab5SDaniel P. Berrangé s->search_out_len ? 51573a841ab5SDaniel P. Berrangé (double)tot / s->search_out_len : 0); 5158fca8a500SRichard Henderson if (tot == 0) { 5159a23a9ec6Sbellard tot = 1; 5160fca8a500SRichard Henderson } 51613a841ab5SDaniel P. Berrangé g_string_append_printf(buf, " gen_interm time %0.1f%%\n", 5162a23a9ec6Sbellard (double)s->interm_time / tot * 100.0); 51633a841ab5SDaniel P. Berrangé g_string_append_printf(buf, " gen_code time %0.1f%%\n", 5164a23a9ec6Sbellard (double)s->code_time / tot * 100.0); 51653a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "optim./code time %0.1f%%\n", 51663a841ab5SDaniel P. Berrangé (double)s->opt_time / (s->code_time ? 51673a841ab5SDaniel P. Berrangé s->code_time : 1) 5168c5cc28ffSAurelien Jarno * 100.0); 51693a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "liveness/code time %0.1f%%\n", 51703a841ab5SDaniel P. Berrangé (double)s->la_time / (s->code_time ? 51713a841ab5SDaniel P. Berrangé s->code_time : 1) * 100.0); 51723a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "cpu_restore count %" PRId64 "\n", 5173a23a9ec6Sbellard s->restore_count); 51743a841ab5SDaniel P. Berrangé g_string_append_printf(buf, " avg cycles %0.1f\n", 51753a841ab5SDaniel P. Berrangé s->restore_count ? 51763a841ab5SDaniel P. Berrangé (double)s->restore_time / s->restore_count : 0); 5177a23a9ec6Sbellard } 5178a23a9ec6Sbellard #else 51793a841ab5SDaniel P. Berrangé void tcg_dump_info(GString *buf) 5180a23a9ec6Sbellard { 51813a841ab5SDaniel P. Berrangé g_string_append_printf(buf, "[TCG profiler not compiled]\n"); 5182a23a9ec6Sbellard } 5183a23a9ec6Sbellard #endif 5184813da627SRichard Henderson 5185813da627SRichard Henderson #ifdef ELF_HOST_MACHINE 51865872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things: 51875872bbf2SRichard Henderson 51885872bbf2SRichard Henderson (1) Define ELF_HOST_MACHINE to indicate both what value to 51895872bbf2SRichard Henderson put into the ELF image and to indicate support for the feature. 51905872bbf2SRichard Henderson 51915872bbf2SRichard Henderson (2) Define tcg_register_jit. This should create a buffer containing 51925872bbf2SRichard Henderson the contents of a .debug_frame section that describes the post- 51935872bbf2SRichard Henderson prologue unwind info for the tcg machine. 51945872bbf2SRichard Henderson 51955872bbf2SRichard Henderson (3) Call tcg_register_jit_int, with the constructed .debug_frame. 51965872bbf2SRichard Henderson */ 5197813da627SRichard Henderson 5198813da627SRichard Henderson /* Begin GDB interface. THE FOLLOWING MUST MATCH GDB DOCS. */ 5199813da627SRichard Henderson typedef enum { 5200813da627SRichard Henderson JIT_NOACTION = 0, 5201813da627SRichard Henderson JIT_REGISTER_FN, 5202813da627SRichard Henderson JIT_UNREGISTER_FN 5203813da627SRichard Henderson } jit_actions_t; 5204813da627SRichard Henderson 5205813da627SRichard Henderson struct jit_code_entry { 5206813da627SRichard Henderson struct jit_code_entry *next_entry; 5207813da627SRichard Henderson struct jit_code_entry *prev_entry; 5208813da627SRichard Henderson const void *symfile_addr; 5209813da627SRichard Henderson uint64_t symfile_size; 5210813da627SRichard Henderson }; 5211813da627SRichard Henderson 5212813da627SRichard Henderson struct jit_descriptor { 5213813da627SRichard Henderson uint32_t version; 5214813da627SRichard Henderson uint32_t action_flag; 5215813da627SRichard Henderson struct jit_code_entry *relevant_entry; 5216813da627SRichard Henderson struct jit_code_entry *first_entry; 5217813da627SRichard Henderson }; 5218813da627SRichard Henderson 5219813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline)); 5220813da627SRichard Henderson void __jit_debug_register_code(void) 5221813da627SRichard Henderson { 5222813da627SRichard Henderson asm(""); 5223813da627SRichard Henderson } 5224813da627SRichard Henderson 5225813da627SRichard Henderson /* Must statically initialize the version, because GDB may check 5226813da627SRichard Henderson the version before we can set it. */ 5227813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 }; 5228813da627SRichard Henderson 5229813da627SRichard Henderson /* End GDB interface. */ 5230813da627SRichard Henderson 5231813da627SRichard Henderson static int find_string(const char *strtab, const char *str) 5232813da627SRichard Henderson { 5233813da627SRichard Henderson const char *p = strtab + 1; 5234813da627SRichard Henderson 5235813da627SRichard Henderson while (1) { 5236813da627SRichard Henderson if (strcmp(p, str) == 0) { 5237813da627SRichard Henderson return p - strtab; 5238813da627SRichard Henderson } 5239813da627SRichard Henderson p += strlen(p) + 1; 5240813da627SRichard Henderson } 5241813da627SRichard Henderson } 5242813da627SRichard Henderson 5243755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf_ptr, size_t buf_size, 52442c90784aSRichard Henderson const void *debug_frame, 52452c90784aSRichard Henderson size_t debug_frame_size) 5246813da627SRichard Henderson { 52475872bbf2SRichard Henderson struct __attribute__((packed)) DebugInfo { 52485872bbf2SRichard Henderson uint32_t len; 52495872bbf2SRichard Henderson uint16_t version; 52505872bbf2SRichard Henderson uint32_t abbrev; 52515872bbf2SRichard Henderson uint8_t ptr_size; 52525872bbf2SRichard Henderson uint8_t cu_die; 52535872bbf2SRichard Henderson uint16_t cu_lang; 52545872bbf2SRichard Henderson uintptr_t cu_low_pc; 52555872bbf2SRichard Henderson uintptr_t cu_high_pc; 52565872bbf2SRichard Henderson uint8_t fn_die; 52575872bbf2SRichard Henderson char fn_name[16]; 52585872bbf2SRichard Henderson uintptr_t fn_low_pc; 52595872bbf2SRichard Henderson uintptr_t fn_high_pc; 52605872bbf2SRichard Henderson uint8_t cu_eoc; 52615872bbf2SRichard Henderson }; 5262813da627SRichard Henderson 5263813da627SRichard Henderson struct ElfImage { 5264813da627SRichard Henderson ElfW(Ehdr) ehdr; 5265813da627SRichard Henderson ElfW(Phdr) phdr; 52665872bbf2SRichard Henderson ElfW(Shdr) shdr[7]; 52675872bbf2SRichard Henderson ElfW(Sym) sym[2]; 52685872bbf2SRichard Henderson struct DebugInfo di; 52695872bbf2SRichard Henderson uint8_t da[24]; 52705872bbf2SRichard Henderson char str[80]; 52715872bbf2SRichard Henderson }; 52725872bbf2SRichard Henderson 52735872bbf2SRichard Henderson struct ElfImage *img; 52745872bbf2SRichard Henderson 52755872bbf2SRichard Henderson static const struct ElfImage img_template = { 52765872bbf2SRichard Henderson .ehdr = { 52775872bbf2SRichard Henderson .e_ident[EI_MAG0] = ELFMAG0, 52785872bbf2SRichard Henderson .e_ident[EI_MAG1] = ELFMAG1, 52795872bbf2SRichard Henderson .e_ident[EI_MAG2] = ELFMAG2, 52805872bbf2SRichard Henderson .e_ident[EI_MAG3] = ELFMAG3, 52815872bbf2SRichard Henderson .e_ident[EI_CLASS] = ELF_CLASS, 52825872bbf2SRichard Henderson .e_ident[EI_DATA] = ELF_DATA, 52835872bbf2SRichard Henderson .e_ident[EI_VERSION] = EV_CURRENT, 52845872bbf2SRichard Henderson .e_type = ET_EXEC, 52855872bbf2SRichard Henderson .e_machine = ELF_HOST_MACHINE, 52865872bbf2SRichard Henderson .e_version = EV_CURRENT, 52875872bbf2SRichard Henderson .e_phoff = offsetof(struct ElfImage, phdr), 52885872bbf2SRichard Henderson .e_shoff = offsetof(struct ElfImage, shdr), 52895872bbf2SRichard Henderson .e_ehsize = sizeof(ElfW(Shdr)), 52905872bbf2SRichard Henderson .e_phentsize = sizeof(ElfW(Phdr)), 52915872bbf2SRichard Henderson .e_phnum = 1, 52925872bbf2SRichard Henderson .e_shentsize = sizeof(ElfW(Shdr)), 52935872bbf2SRichard Henderson .e_shnum = ARRAY_SIZE(img->shdr), 52945872bbf2SRichard Henderson .e_shstrndx = ARRAY_SIZE(img->shdr) - 1, 5295abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS 5296abbb3eaeSRichard Henderson .e_flags = ELF_HOST_FLAGS, 5297abbb3eaeSRichard Henderson #endif 5298abbb3eaeSRichard Henderson #ifdef ELF_OSABI 5299abbb3eaeSRichard Henderson .e_ident[EI_OSABI] = ELF_OSABI, 5300abbb3eaeSRichard Henderson #endif 53015872bbf2SRichard Henderson }, 53025872bbf2SRichard Henderson .phdr = { 53035872bbf2SRichard Henderson .p_type = PT_LOAD, 53045872bbf2SRichard Henderson .p_flags = PF_X, 53055872bbf2SRichard Henderson }, 53065872bbf2SRichard Henderson .shdr = { 53075872bbf2SRichard Henderson [0] = { .sh_type = SHT_NULL }, 53085872bbf2SRichard Henderson /* Trick: The contents of code_gen_buffer are not present in 53095872bbf2SRichard Henderson this fake ELF file; that got allocated elsewhere. Therefore 53105872bbf2SRichard Henderson we mark .text as SHT_NOBITS (similar to .bss) so that readers 53115872bbf2SRichard Henderson will not look for contents. We can record any address. */ 53125872bbf2SRichard Henderson [1] = { /* .text */ 53135872bbf2SRichard Henderson .sh_type = SHT_NOBITS, 53145872bbf2SRichard Henderson .sh_flags = SHF_EXECINSTR | SHF_ALLOC, 53155872bbf2SRichard Henderson }, 53165872bbf2SRichard Henderson [2] = { /* .debug_info */ 53175872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 53185872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, di), 53195872bbf2SRichard Henderson .sh_size = sizeof(struct DebugInfo), 53205872bbf2SRichard Henderson }, 53215872bbf2SRichard Henderson [3] = { /* .debug_abbrev */ 53225872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 53235872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, da), 53245872bbf2SRichard Henderson .sh_size = sizeof(img->da), 53255872bbf2SRichard Henderson }, 53265872bbf2SRichard Henderson [4] = { /* .debug_frame */ 53275872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 53285872bbf2SRichard Henderson .sh_offset = sizeof(struct ElfImage), 53295872bbf2SRichard Henderson }, 53305872bbf2SRichard Henderson [5] = { /* .symtab */ 53315872bbf2SRichard Henderson .sh_type = SHT_SYMTAB, 53325872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, sym), 53335872bbf2SRichard Henderson .sh_size = sizeof(img->sym), 53345872bbf2SRichard Henderson .sh_info = 1, 53355872bbf2SRichard Henderson .sh_link = ARRAY_SIZE(img->shdr) - 1, 53365872bbf2SRichard Henderson .sh_entsize = sizeof(ElfW(Sym)), 53375872bbf2SRichard Henderson }, 53385872bbf2SRichard Henderson [6] = { /* .strtab */ 53395872bbf2SRichard Henderson .sh_type = SHT_STRTAB, 53405872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, str), 53415872bbf2SRichard Henderson .sh_size = sizeof(img->str), 53425872bbf2SRichard Henderson } 53435872bbf2SRichard Henderson }, 53445872bbf2SRichard Henderson .sym = { 53455872bbf2SRichard Henderson [1] = { /* code_gen_buffer */ 53465872bbf2SRichard Henderson .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC), 53475872bbf2SRichard Henderson .st_shndx = 1, 53485872bbf2SRichard Henderson } 53495872bbf2SRichard Henderson }, 53505872bbf2SRichard Henderson .di = { 53515872bbf2SRichard Henderson .len = sizeof(struct DebugInfo) - 4, 53525872bbf2SRichard Henderson .version = 2, 53535872bbf2SRichard Henderson .ptr_size = sizeof(void *), 53545872bbf2SRichard Henderson .cu_die = 1, 53555872bbf2SRichard Henderson .cu_lang = 0x8001, /* DW_LANG_Mips_Assembler */ 53565872bbf2SRichard Henderson .fn_die = 2, 53575872bbf2SRichard Henderson .fn_name = "code_gen_buffer" 53585872bbf2SRichard Henderson }, 53595872bbf2SRichard Henderson .da = { 53605872bbf2SRichard Henderson 1, /* abbrev number (the cu) */ 53615872bbf2SRichard Henderson 0x11, 1, /* DW_TAG_compile_unit, has children */ 53625872bbf2SRichard Henderson 0x13, 0x5, /* DW_AT_language, DW_FORM_data2 */ 53635872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */ 53645872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */ 53655872bbf2SRichard Henderson 0, 0, /* end of abbrev */ 53665872bbf2SRichard Henderson 2, /* abbrev number (the fn) */ 53675872bbf2SRichard Henderson 0x2e, 0, /* DW_TAG_subprogram, no children */ 53685872bbf2SRichard Henderson 0x3, 0x8, /* DW_AT_name, DW_FORM_string */ 53695872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */ 53705872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */ 53715872bbf2SRichard Henderson 0, 0, /* end of abbrev */ 53725872bbf2SRichard Henderson 0 /* no more abbrev */ 53735872bbf2SRichard Henderson }, 53745872bbf2SRichard Henderson .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0" 53755872bbf2SRichard Henderson ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer", 5376813da627SRichard Henderson }; 5377813da627SRichard Henderson 5378813da627SRichard Henderson /* We only need a single jit entry; statically allocate it. */ 5379813da627SRichard Henderson static struct jit_code_entry one_entry; 5380813da627SRichard Henderson 53815872bbf2SRichard Henderson uintptr_t buf = (uintptr_t)buf_ptr; 5382813da627SRichard Henderson size_t img_size = sizeof(struct ElfImage) + debug_frame_size; 53832c90784aSRichard Henderson DebugFrameHeader *dfh; 5384813da627SRichard Henderson 53855872bbf2SRichard Henderson img = g_malloc(img_size); 53865872bbf2SRichard Henderson *img = img_template; 5387813da627SRichard Henderson 53885872bbf2SRichard Henderson img->phdr.p_vaddr = buf; 53895872bbf2SRichard Henderson img->phdr.p_paddr = buf; 53905872bbf2SRichard Henderson img->phdr.p_memsz = buf_size; 5391813da627SRichard Henderson 53925872bbf2SRichard Henderson img->shdr[1].sh_name = find_string(img->str, ".text"); 53935872bbf2SRichard Henderson img->shdr[1].sh_addr = buf; 53945872bbf2SRichard Henderson img->shdr[1].sh_size = buf_size; 5395813da627SRichard Henderson 53965872bbf2SRichard Henderson img->shdr[2].sh_name = find_string(img->str, ".debug_info"); 53975872bbf2SRichard Henderson img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev"); 53985872bbf2SRichard Henderson 53995872bbf2SRichard Henderson img->shdr[4].sh_name = find_string(img->str, ".debug_frame"); 54005872bbf2SRichard Henderson img->shdr[4].sh_size = debug_frame_size; 54015872bbf2SRichard Henderson 54025872bbf2SRichard Henderson img->shdr[5].sh_name = find_string(img->str, ".symtab"); 54035872bbf2SRichard Henderson img->shdr[6].sh_name = find_string(img->str, ".strtab"); 54045872bbf2SRichard Henderson 54055872bbf2SRichard Henderson img->sym[1].st_name = find_string(img->str, "code_gen_buffer"); 54065872bbf2SRichard Henderson img->sym[1].st_value = buf; 54075872bbf2SRichard Henderson img->sym[1].st_size = buf_size; 54085872bbf2SRichard Henderson 54095872bbf2SRichard Henderson img->di.cu_low_pc = buf; 541045aba097SRichard Henderson img->di.cu_high_pc = buf + buf_size; 54115872bbf2SRichard Henderson img->di.fn_low_pc = buf; 541245aba097SRichard Henderson img->di.fn_high_pc = buf + buf_size; 5413813da627SRichard Henderson 54142c90784aSRichard Henderson dfh = (DebugFrameHeader *)(img + 1); 54152c90784aSRichard Henderson memcpy(dfh, debug_frame, debug_frame_size); 54162c90784aSRichard Henderson dfh->fde.func_start = buf; 54172c90784aSRichard Henderson dfh->fde.func_len = buf_size; 54182c90784aSRichard Henderson 5419813da627SRichard Henderson #ifdef DEBUG_JIT 5420813da627SRichard Henderson /* Enable this block to be able to debug the ELF image file creation. 5421813da627SRichard Henderson One can use readelf, objdump, or other inspection utilities. */ 5422813da627SRichard Henderson { 5423eb6b2edfSBin Meng g_autofree char *jit = g_strdup_printf("%s/qemu.jit", g_get_tmp_dir()); 5424eb6b2edfSBin Meng FILE *f = fopen(jit, "w+b"); 5425813da627SRichard Henderson if (f) { 54265872bbf2SRichard Henderson if (fwrite(img, img_size, 1, f) != img_size) { 5427813da627SRichard Henderson /* Avoid stupid unused return value warning for fwrite. */ 5428813da627SRichard Henderson } 5429813da627SRichard Henderson fclose(f); 5430813da627SRichard Henderson } 5431813da627SRichard Henderson } 5432813da627SRichard Henderson #endif 5433813da627SRichard Henderson 5434813da627SRichard Henderson one_entry.symfile_addr = img; 5435813da627SRichard Henderson one_entry.symfile_size = img_size; 5436813da627SRichard Henderson 5437813da627SRichard Henderson __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; 5438813da627SRichard Henderson __jit_debug_descriptor.relevant_entry = &one_entry; 5439813da627SRichard Henderson __jit_debug_descriptor.first_entry = &one_entry; 5440813da627SRichard Henderson __jit_debug_register_code(); 5441813da627SRichard Henderson } 5442813da627SRichard Henderson #else 54435872bbf2SRichard Henderson /* No support for the feature. Provide the entry point expected by exec.c, 54445872bbf2SRichard Henderson and implement the internal function we declared earlier. */ 5445813da627SRichard Henderson 5446755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size, 54472c90784aSRichard Henderson const void *debug_frame, 54482c90784aSRichard Henderson size_t debug_frame_size) 5449813da627SRichard Henderson { 5450813da627SRichard Henderson } 5451813da627SRichard Henderson 5452755bf9e5SRichard Henderson void tcg_register_jit(const void *buf, size_t buf_size) 5453813da627SRichard Henderson { 5454813da627SRichard Henderson } 5455813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */ 5456db432672SRichard Henderson 5457db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec 5458db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...) 5459db432672SRichard Henderson { 5460db432672SRichard Henderson g_assert_not_reached(); 5461db432672SRichard Henderson } 5462db432672SRichard Henderson #endif 5463