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
25757e725bSPeter Maydell #include "qemu/osdep.h"
26cca82982Saurel32
27813da627SRichard Henderson /* Define to jump the ELF file used to communicate with GDB. */
28813da627SRichard Henderson #undef DEBUG_JIT
29813da627SRichard Henderson
3072fd2efbSEmilio G. Cota #include "qemu/error-report.h"
31f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
321de7afc9SPaolo Bonzini #include "qemu/host-utils.h"
33d4c51a0aSMarkus Armbruster #include "qemu/qemu-print.h"
34084cfca1SRichard Henderson #include "qemu/cacheflush.h"
35ad768e6fSPeter Maydell #include "qemu/cacheinfo.h"
36533206f0SRichard W.M. Jones #include "qemu/timer.h"
37*11efde54SRichard Henderson #include "exec/target_page.h"
38cac9b0fdSRichard Henderson #include "exec/translation-block.h"
39d0a9bb5eSRichard Henderson #include "exec/tlb-common.h"
40d7ec12f8SRichard Henderson #include "tcg/startup.h"
41ad3d0e4dSRichard Henderson #include "tcg/tcg-op-common.h"
42813da627SRichard Henderson
43edee2579SRichard Henderson #if UINTPTR_MAX == UINT32_MAX
44813da627SRichard Henderson # define ELF_CLASS ELFCLASS32
45edee2579SRichard Henderson #else
46edee2579SRichard Henderson # define ELF_CLASS ELFCLASS64
47813da627SRichard Henderson #endif
48e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN
49813da627SRichard Henderson # define ELF_DATA ELFDATA2MSB
50813da627SRichard Henderson #else
51813da627SRichard Henderson # define ELF_DATA ELFDATA2LSB
52813da627SRichard Henderson #endif
53813da627SRichard Henderson
54c896fe29Sbellard #include "elf.h"
55508127e2SPaolo Bonzini #include "exec/log.h"
56d2ba8026SRichard Henderson #include "tcg/tcg-ldst.h"
5747f7313dSRichard Henderson #include "tcg/tcg-temp-internal.h"
585ff7258cSRichard Henderson #include "tcg-internal.h"
59327b75a4SIlya Leoshkevich #include "tcg/perf.h"
6093280b67SRichard Henderson #include "tcg-has.h"
617d478306SRichard Henderson #ifdef CONFIG_USER_ONLY
62d3cbde74SPhilippe Mathieu-Daudé #include "user/guest-base.h"
637d478306SRichard Henderson #endif
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);
71a417ef83SRichard Henderson static void tcg_out_nop_fill(tcg_insn_unit *p, int count);
72a417ef83SRichard Henderson
73a417ef83SRichard Henderson typedef struct TCGLabelQemuLdst TCGLabelQemuLdst;
74a417ef83SRichard Henderson static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l);
75a417ef83SRichard Henderson static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l);
76c896fe29Sbellard
77497a22ebSRichard Henderson /* The CIE and FDE header definitions will be common to all hosts. */
78497a22ebSRichard Henderson typedef struct {
79497a22ebSRichard Henderson uint32_t len __attribute__((aligned((sizeof(void *)))));
80497a22ebSRichard Henderson uint32_t id;
81497a22ebSRichard Henderson uint8_t version;
82497a22ebSRichard Henderson char augmentation[1];
83497a22ebSRichard Henderson uint8_t code_align;
84497a22ebSRichard Henderson uint8_t data_align;
85497a22ebSRichard Henderson uint8_t return_column;
86497a22ebSRichard Henderson } DebugFrameCIE;
87497a22ebSRichard Henderson
88497a22ebSRichard Henderson typedef struct QEMU_PACKED {
89497a22ebSRichard Henderson uint32_t len __attribute__((aligned((sizeof(void *)))));
90497a22ebSRichard Henderson uint32_t cie_offset;
91edee2579SRichard Henderson uintptr_t func_start;
92edee2579SRichard Henderson uintptr_t func_len;
93497a22ebSRichard Henderson } DebugFrameFDEHeader;
94497a22ebSRichard Henderson
952c90784aSRichard Henderson typedef struct QEMU_PACKED {
962c90784aSRichard Henderson DebugFrameCIE cie;
972c90784aSRichard Henderson DebugFrameFDEHeader fde;
982c90784aSRichard Henderson } DebugFrameHeader;
992c90784aSRichard Henderson
100a417ef83SRichard Henderson struct TCGLabelQemuLdst {
1012528f771SRichard Henderson bool is_ld; /* qemu_ld: true, qemu_st: false */
1022528f771SRichard Henderson MemOpIdx oi;
1032528f771SRichard Henderson TCGType type; /* result type of a load */
1040cd38379SRichard Henderson TCGReg addr_reg; /* reg index for guest virtual addr */
1052528f771SRichard Henderson TCGReg datalo_reg; /* reg index for low word to be loaded or stored */
1062528f771SRichard Henderson TCGReg datahi_reg; /* reg index for high word to be loaded or stored */
1072528f771SRichard Henderson const tcg_insn_unit *raddr; /* addr of the next IR of qemu_ld/st IR */
1082528f771SRichard Henderson tcg_insn_unit *label_ptr[2]; /* label pointers to be updated */
1092528f771SRichard Henderson QSIMPLEQ_ENTRY(TCGLabelQemuLdst) next;
110a417ef83SRichard Henderson };
1112528f771SRichard Henderson
112755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size,
1132c90784aSRichard Henderson const void *debug_frame,
1142c90784aSRichard Henderson size_t debug_frame_size)
115813da627SRichard Henderson __attribute__((unused));
116813da627SRichard Henderson
117139c1837SPaolo Bonzini /* Forward declarations for functions declared and used in tcg-target.c.inc. */
1189358fbbfSRichard Henderson static void tcg_out_tb_start(TCGContext *s);
1192a534affSRichard Henderson static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
120a05b5b9bSRichard Henderson intptr_t arg2);
12178113e83SRichard Henderson static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
122c0ad3001SStefan Weil static void tcg_out_movi(TCGContext *s, TCGType type,
1232a534affSRichard Henderson TCGReg ret, tcg_target_long arg);
124678155b2SRichard Henderson static void tcg_out_ext8s(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
125753e42eaSRichard Henderson static void tcg_out_ext16s(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
126d0e66c89SRichard Henderson static void tcg_out_ext8u(TCGContext *s, TCGReg ret, TCGReg arg);
127379afdffSRichard Henderson static void tcg_out_ext16u(TCGContext *s, TCGReg ret, TCGReg arg);
12852bf3398SRichard Henderson static void tcg_out_ext32s(TCGContext *s, TCGReg ret, TCGReg arg);
1299ecf5f61SRichard Henderson static void tcg_out_ext32u(TCGContext *s, TCGReg ret, TCGReg arg);
1309c6aa274SRichard Henderson static void tcg_out_exts_i32_i64(TCGContext *s, TCGReg ret, TCGReg arg);
131b9bfe000SRichard Henderson static void tcg_out_extu_i32_i64(TCGContext *s, TCGReg ret, TCGReg arg);
132b8b94ac6SRichard Henderson static void tcg_out_extrl_i64_i32(TCGContext *s, TCGReg ret, TCGReg arg);
133313bdea8SRichard Henderson static void tcg_out_addi_ptr(TCGContext *s, TCGReg, TCGReg, tcg_target_long);
134129f1f9eSRichard Henderson static bool tcg_out_xchg(TCGContext *s, TCGType type, TCGReg r1, TCGReg r2);
135b55a8d9dSRichard Henderson static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg);
136cf7d6b8eSRichard Henderson static void tcg_out_goto_tb(TCGContext *s, int which);
137fee03fddSRichard Henderson static void tcg_out_goto_ptr(TCGContext *s, TCGReg dest);
138e038696cSRichard Henderson static void tcg_out_mb(TCGContext *s, unsigned bar);
1393752a5a5SRichard Henderson static void tcg_out_br(TCGContext *s, TCGLabel *l);
140ee603152SRichard Henderson static void tcg_out_set_carry(TCGContext *s);
141ee603152SRichard Henderson static void tcg_out_set_borrow(TCGContext *s);
142d2fd745fSRichard Henderson #if TCG_TARGET_MAYBE_vec
143e7632cfaSRichard Henderson static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
144e7632cfaSRichard Henderson TCGReg dst, TCGReg src);
145d6ecb4a9SRichard Henderson static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
146d6ecb4a9SRichard Henderson TCGReg dst, TCGReg base, intptr_t offset);
1474e186175SRichard Henderson static void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece,
1484e186175SRichard Henderson TCGReg dst, int64_t arg);
1495e8892dbSMiroslav Rezanina static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
1505e8892dbSMiroslav Rezanina unsigned vecl, unsigned vece,
1515e8892dbSMiroslav Rezanina const TCGArg args[TCG_MAX_OP_ARGS],
1525e8892dbSMiroslav Rezanina const int const_args[TCG_MAX_OP_ARGS]);
153d2fd745fSRichard Henderson #else
tcg_out_dup_vec(TCGContext * s,TCGType type,unsigned vece,TCGReg dst,TCGReg src)154e7632cfaSRichard Henderson static inline bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
155e7632cfaSRichard Henderson TCGReg dst, TCGReg src)
156e7632cfaSRichard Henderson {
157e7632cfaSRichard Henderson g_assert_not_reached();
158e7632cfaSRichard Henderson }
tcg_out_dupm_vec(TCGContext * s,TCGType type,unsigned vece,TCGReg dst,TCGReg base,intptr_t offset)159d6ecb4a9SRichard Henderson static inline bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
160d6ecb4a9SRichard Henderson TCGReg dst, TCGReg base, intptr_t offset)
161d6ecb4a9SRichard Henderson {
162d6ecb4a9SRichard Henderson g_assert_not_reached();
163d6ecb4a9SRichard Henderson }
tcg_out_dupi_vec(TCGContext * s,TCGType type,unsigned vece,TCGReg dst,int64_t arg)1644e186175SRichard Henderson static inline void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece,
1654e186175SRichard Henderson TCGReg dst, int64_t arg)
166e7632cfaSRichard Henderson {
167e7632cfaSRichard Henderson g_assert_not_reached();
168e7632cfaSRichard Henderson }
tcg_out_vec_op(TCGContext * s,TCGOpcode opc,unsigned vecl,unsigned vece,const TCGArg args[TCG_MAX_OP_ARGS],const int const_args[TCG_MAX_OP_ARGS])1695e8892dbSMiroslav Rezanina static inline void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
1705e8892dbSMiroslav Rezanina unsigned vecl, unsigned vece,
1715e8892dbSMiroslav Rezanina const TCGArg args[TCG_MAX_OP_ARGS],
1725e8892dbSMiroslav Rezanina const int const_args[TCG_MAX_OP_ARGS])
173d2fd745fSRichard Henderson {
174d2fd745fSRichard Henderson g_assert_not_reached();
175d2fd745fSRichard Henderson }
tcg_can_emit_vec_op(TCGOpcode o,TCGType t,unsigned ve)1767d3e705aSRichard Henderson int tcg_can_emit_vec_op(TCGOpcode o, TCGType t, unsigned ve)
1777d3e705aSRichard Henderson {
1787d3e705aSRichard Henderson return 0;
1797d3e705aSRichard Henderson }
180d2fd745fSRichard Henderson #endif
1812a534affSRichard Henderson static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
182a05b5b9bSRichard Henderson intptr_t arg2);
18359d7c14eSRichard Henderson static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
18459d7c14eSRichard Henderson TCGReg base, intptr_t ofs);
1857b7d8b2dSRichard Henderson static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target,
186cee44b03SRichard Henderson const TCGHelperInfo *info);
1875e3d0c19SRichard Henderson static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot);
18821e9a8aeSRichard Henderson static bool tcg_target_const_match(int64_t val, int ct,
18921e9a8aeSRichard Henderson TCGType type, TCGCond cond, int vece);
190c896fe29Sbellard
19123088ca0SRichard Henderson #ifndef CONFIG_USER_ONLY
19223088ca0SRichard Henderson #define guest_base ({ qemu_build_not_reached(); (uintptr_t)0; })
19323088ca0SRichard Henderson #endif
19423088ca0SRichard Henderson
1958429a1caSRichard Henderson typedef struct TCGLdstHelperParam {
1968429a1caSRichard Henderson TCGReg (*ra_gen)(TCGContext *s, const TCGLabelQemuLdst *l, int arg_reg);
1978429a1caSRichard Henderson unsigned ntmp;
1988429a1caSRichard Henderson int tmp[3];
1998429a1caSRichard Henderson } TCGLdstHelperParam;
2008429a1caSRichard Henderson
2018429a1caSRichard Henderson static void tcg_out_ld_helper_args(TCGContext *s, const TCGLabelQemuLdst *l,
2028429a1caSRichard Henderson const TCGLdstHelperParam *p)
2038429a1caSRichard Henderson __attribute__((unused));
2048429a1caSRichard Henderson static void tcg_out_ld_helper_ret(TCGContext *s, const TCGLabelQemuLdst *l,
2058429a1caSRichard Henderson bool load_sign, const TCGLdstHelperParam *p)
2068429a1caSRichard Henderson __attribute__((unused));
2078429a1caSRichard Henderson static void tcg_out_st_helper_args(TCGContext *s, const TCGLabelQemuLdst *l,
2088429a1caSRichard Henderson const TCGLdstHelperParam *p)
2098429a1caSRichard Henderson __attribute__((unused));
2108429a1caSRichard Henderson
211de95016dSRichard Henderson static void * const qemu_ld_helpers[MO_SSIZE + 1] __attribute__((unused)) = {
2120cadc1edSRichard Henderson [MO_UB] = helper_ldub_mmu,
2130cadc1edSRichard Henderson [MO_SB] = helper_ldsb_mmu,
2140cadc1edSRichard Henderson [MO_UW] = helper_lduw_mmu,
2150cadc1edSRichard Henderson [MO_SW] = helper_ldsw_mmu,
2160cadc1edSRichard Henderson [MO_UL] = helper_ldul_mmu,
2170cadc1edSRichard Henderson [MO_UQ] = helper_ldq_mmu,
2180cadc1edSRichard Henderson #if TCG_TARGET_REG_BITS == 64
2190cadc1edSRichard Henderson [MO_SL] = helper_ldsl_mmu,
220ebebea53SRichard Henderson [MO_128] = helper_ld16_mmu,
2210cadc1edSRichard Henderson #endif
2220cadc1edSRichard Henderson };
2230cadc1edSRichard Henderson
224de95016dSRichard Henderson static void * const qemu_st_helpers[MO_SIZE + 1] __attribute__((unused)) = {
2250cadc1edSRichard Henderson [MO_8] = helper_stb_mmu,
2260cadc1edSRichard Henderson [MO_16] = helper_stw_mmu,
2270cadc1edSRichard Henderson [MO_32] = helper_stl_mmu,
2280cadc1edSRichard Henderson [MO_64] = helper_stq_mmu,
229ebebea53SRichard Henderson #if TCG_TARGET_REG_BITS == 64
230ebebea53SRichard Henderson [MO_128] = helper_st16_mmu,
231ebebea53SRichard Henderson #endif
2320cadc1edSRichard Henderson };
2330cadc1edSRichard Henderson
234e63b8a29SRichard Henderson typedef struct {
235e63b8a29SRichard Henderson MemOp atom; /* lg2 bits of atomicity required */
236e63b8a29SRichard Henderson MemOp align; /* lg2 bits of alignment to use */
237e63b8a29SRichard Henderson } TCGAtomAlign;
238e63b8a29SRichard Henderson
239e63b8a29SRichard Henderson static TCGAtomAlign atom_and_align_for_opc(TCGContext *s, MemOp opc,
240e63b8a29SRichard Henderson MemOp host_atom, bool allow_two_ops)
241e63b8a29SRichard Henderson __attribute__((unused));
242e63b8a29SRichard Henderson
243397cabaaSRichard Henderson #ifdef CONFIG_USER_ONLY
244397cabaaSRichard Henderson bool tcg_use_softmmu;
245397cabaaSRichard Henderson #endif
246397cabaaSRichard Henderson
24742eb6dfcSRichard Henderson TCGContext tcg_init_ctx;
24842eb6dfcSRichard Henderson __thread TCGContext *tcg_ctx;
24942eb6dfcSRichard Henderson
2505ff7258cSRichard Henderson TCGContext **tcg_ctxs;
2510e2d61cfSRichard Henderson unsigned int tcg_cur_ctxs;
2520e2d61cfSRichard Henderson unsigned int tcg_max_ctxs;
253ad75a51eSRichard Henderson TCGv_env tcg_env;
254c8bc1168SRichard Henderson const void *tcg_code_gen_epilogue;
255db0c51a3SRichard Henderson uintptr_t tcg_splitwx_diff;
256df2cce29SEmilio G. Cota
257b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
258b91ccb31SRichard Henderson tcg_prologue_fn *tcg_qemu_tb_exec;
259b91ccb31SRichard Henderson #endif
260b91ccb31SRichard Henderson
261d2fd745fSRichard Henderson static TCGRegSet tcg_target_available_regs[TCG_TYPE_COUNT];
262b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs;
263c896fe29Sbellard
2641813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1
tcg_out8(TCGContext * s,uint8_t v)2654196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v)
266c896fe29Sbellard {
267c896fe29Sbellard *s->code_ptr++ = v;
268c896fe29Sbellard }
269c896fe29Sbellard
tcg_patch8(tcg_insn_unit * p,uint8_t v)2704196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p,
2714196dca6SPeter Maydell uint8_t v)
2725c53bb81SPeter Maydell {
2731813e175SRichard Henderson *p = v;
2745c53bb81SPeter Maydell }
2751813e175SRichard Henderson #endif
2765c53bb81SPeter Maydell
2771813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2
tcg_out16(TCGContext * s,uint16_t v)2784196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v)
279c896fe29Sbellard {
2801813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
2811813e175SRichard Henderson *s->code_ptr++ = v;
2821813e175SRichard Henderson } else {
2831813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr;
2844387345aSPeter Maydell memcpy(p, &v, sizeof(v));
2851813e175SRichard Henderson s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE);
2861813e175SRichard Henderson }
287c896fe29Sbellard }
288c896fe29Sbellard
tcg_patch16(tcg_insn_unit * p,uint16_t v)2894196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p,
2904196dca6SPeter Maydell uint16_t v)
2915c53bb81SPeter Maydell {
2921813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
2931813e175SRichard Henderson *p = v;
2941813e175SRichard Henderson } else {
2955c53bb81SPeter Maydell memcpy(p, &v, sizeof(v));
2965c53bb81SPeter Maydell }
2971813e175SRichard Henderson }
2981813e175SRichard Henderson #endif
2995c53bb81SPeter Maydell
3001813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4
tcg_out32(TCGContext * s,uint32_t v)3014196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v)
302c896fe29Sbellard {
3031813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
3041813e175SRichard Henderson *s->code_ptr++ = v;
3051813e175SRichard Henderson } else {
3061813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr;
3074387345aSPeter Maydell memcpy(p, &v, sizeof(v));
3081813e175SRichard Henderson s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE);
3091813e175SRichard Henderson }
310c896fe29Sbellard }
311c896fe29Sbellard
tcg_patch32(tcg_insn_unit * p,uint32_t v)3124196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p,
3134196dca6SPeter Maydell uint32_t v)
3145c53bb81SPeter Maydell {
3151813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
3161813e175SRichard Henderson *p = v;
3171813e175SRichard Henderson } else {
3185c53bb81SPeter Maydell memcpy(p, &v, sizeof(v));
3195c53bb81SPeter Maydell }
3201813e175SRichard Henderson }
3211813e175SRichard Henderson #endif
3225c53bb81SPeter Maydell
3231813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 8
tcg_out64(TCGContext * s,uint64_t v)3244196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v)
325ac26eb69SRichard Henderson {
3261813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
3271813e175SRichard Henderson *s->code_ptr++ = v;
3281813e175SRichard Henderson } else {
3291813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr;
3304387345aSPeter Maydell memcpy(p, &v, sizeof(v));
3311813e175SRichard Henderson s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE);
3321813e175SRichard Henderson }
333ac26eb69SRichard Henderson }
334ac26eb69SRichard Henderson
tcg_patch64(tcg_insn_unit * p,uint64_t v)3354196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p,
3364196dca6SPeter Maydell uint64_t v)
3375c53bb81SPeter Maydell {
3381813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
3391813e175SRichard Henderson *p = v;
3401813e175SRichard Henderson } else {
3415c53bb81SPeter Maydell memcpy(p, &v, sizeof(v));
3425c53bb81SPeter Maydell }
3431813e175SRichard Henderson }
3441813e175SRichard Henderson #endif
3455c53bb81SPeter Maydell
346c896fe29Sbellard /* label relocation processing */
347c896fe29Sbellard
tcg_out_reloc(TCGContext * s,tcg_insn_unit * code_ptr,int type,TCGLabel * l,intptr_t addend)3481813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
349bec16311SRichard Henderson TCGLabel *l, intptr_t addend)
350c896fe29Sbellard {
3517ecd02a0SRichard Henderson TCGRelocation *r = tcg_malloc(sizeof(TCGRelocation));
352c896fe29Sbellard
353c896fe29Sbellard r->type = type;
354c896fe29Sbellard r->ptr = code_ptr;
355c896fe29Sbellard r->addend = addend;
3567ecd02a0SRichard Henderson QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next);
357c896fe29Sbellard }
358c896fe29Sbellard
tcg_out_label(TCGContext * s,TCGLabel * l)35992ab8e7dSRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l)
360c896fe29Sbellard {
361eabb7b91SAurelien Jarno tcg_debug_assert(!l->has_value);
362c896fe29Sbellard l->has_value = 1;
36392ab8e7dSRichard Henderson l->u.value_ptr = tcg_splitwx_to_rx(s->code_ptr);
364c896fe29Sbellard }
365c896fe29Sbellard
gen_new_label(void)36642a268c2SRichard Henderson TCGLabel *gen_new_label(void)
367c896fe29Sbellard {
368b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx;
36951e3972cSRichard Henderson TCGLabel *l = tcg_malloc(sizeof(TCGLabel));
370c896fe29Sbellard
3717ecd02a0SRichard Henderson memset(l, 0, sizeof(TCGLabel));
3727ecd02a0SRichard Henderson l->id = s->nb_labels++;
373f85b1fc4SRichard Henderson QSIMPLEQ_INIT(&l->branches);
3747ecd02a0SRichard Henderson QSIMPLEQ_INIT(&l->relocs);
3757ecd02a0SRichard Henderson
376bef16ab4SRichard Henderson QSIMPLEQ_INSERT_TAIL(&s->labels, l, next);
37742a268c2SRichard Henderson
37842a268c2SRichard Henderson return l;
379c896fe29Sbellard }
380c896fe29Sbellard
tcg_resolve_relocs(TCGContext * s)3817ecd02a0SRichard Henderson static bool tcg_resolve_relocs(TCGContext *s)
3827ecd02a0SRichard Henderson {
3837ecd02a0SRichard Henderson TCGLabel *l;
3847ecd02a0SRichard Henderson
3857ecd02a0SRichard Henderson QSIMPLEQ_FOREACH(l, &s->labels, next) {
3867ecd02a0SRichard Henderson TCGRelocation *r;
3877ecd02a0SRichard Henderson uintptr_t value = l->u.value;
3887ecd02a0SRichard Henderson
3897ecd02a0SRichard Henderson QSIMPLEQ_FOREACH(r, &l->relocs, next) {
3907ecd02a0SRichard Henderson if (!patch_reloc(r->ptr, r->type, value, r->addend)) {
3917ecd02a0SRichard Henderson return false;
3927ecd02a0SRichard Henderson }
3937ecd02a0SRichard Henderson }
3947ecd02a0SRichard Henderson }
3957ecd02a0SRichard Henderson return true;
3967ecd02a0SRichard Henderson }
3977ecd02a0SRichard Henderson
set_jmp_reset_offset(TCGContext * s,int which)3989f754620SRichard Henderson static void set_jmp_reset_offset(TCGContext *s, int which)
3999f754620SRichard Henderson {
400f14bed3fSRichard Henderson /*
401f14bed3fSRichard Henderson * We will check for overflow at the end of the opcode loop in
402f14bed3fSRichard Henderson * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX.
403f14bed3fSRichard Henderson */
404b7e4afbdSRichard Henderson s->gen_tb->jmp_reset_offset[which] = tcg_current_code_size(s);
4059f754620SRichard Henderson }
4069f754620SRichard Henderson
set_jmp_insn_offset(TCGContext * s,int which)407b52a2c03SRichard Henderson static void G_GNUC_UNUSED set_jmp_insn_offset(TCGContext *s, int which)
408b52a2c03SRichard Henderson {
409b52a2c03SRichard Henderson /*
410b52a2c03SRichard Henderson * We will check for overflow at the end of the opcode loop in
411b52a2c03SRichard Henderson * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX.
412b52a2c03SRichard Henderson */
4139da6079bSRichard Henderson s->gen_tb->jmp_insn_offset[which] = tcg_current_code_size(s);
414b52a2c03SRichard Henderson }
415b52a2c03SRichard Henderson
get_jmp_target_addr(TCGContext * s,int which)416becc452aSRichard Henderson static uintptr_t G_GNUC_UNUSED get_jmp_target_addr(TCGContext *s, int which)
417becc452aSRichard Henderson {
418becc452aSRichard Henderson /*
419becc452aSRichard Henderson * Return the read-execute version of the pointer, for the benefit
420becc452aSRichard Henderson * of any pc-relative addressing mode.
421becc452aSRichard Henderson */
4229da6079bSRichard Henderson return (uintptr_t)tcg_splitwx_to_rx(&s->gen_tb->jmp_target_addr[which]);
423becc452aSRichard Henderson }
424becc452aSRichard Henderson
425397cabaaSRichard Henderson static int __attribute__((unused))
tlb_mask_table_ofs(TCGContext * s,int which)426397cabaaSRichard Henderson tlb_mask_table_ofs(TCGContext *s, int which)
427d0a9bb5eSRichard Henderson {
4287857ee11SRichard Henderson return (offsetof(CPUNegativeOffsetState, tlb.f[which]) -
4297857ee11SRichard Henderson sizeof(CPUNegativeOffsetState));
430d0a9bb5eSRichard Henderson }
431d0a9bb5eSRichard Henderson
432db6b7d0cSRichard Henderson /* Signal overflow, starting over with fewer guest insns. */
4338905770bSMarc-André Lureau static G_NORETURN
tcg_raise_tb_overflow(TCGContext * s)4348905770bSMarc-André Lureau void tcg_raise_tb_overflow(TCGContext *s)
435db6b7d0cSRichard Henderson {
436db6b7d0cSRichard Henderson siglongjmp(s->jmp_trans, -2);
437db6b7d0cSRichard Henderson }
438db6b7d0cSRichard Henderson
4398429a1caSRichard Henderson /*
4408429a1caSRichard Henderson * Used by tcg_out_movext{1,2} to hold the arguments for tcg_out_movext.
4418429a1caSRichard Henderson * By the time we arrive at tcg_out_movext1, @dst is always a TCGReg.
4428429a1caSRichard Henderson *
4438429a1caSRichard Henderson * However, tcg_out_helper_load_slots reuses this field to hold an
4448429a1caSRichard Henderson * argument slot number (which may designate a argument register or an
4458429a1caSRichard Henderson * argument stack slot), converting to TCGReg once all arguments that
4468429a1caSRichard Henderson * are destined for the stack are processed.
4478429a1caSRichard Henderson */
448129f1f9eSRichard Henderson typedef struct TCGMovExtend {
4498429a1caSRichard Henderson unsigned dst;
450129f1f9eSRichard Henderson TCGReg src;
451129f1f9eSRichard Henderson TCGType dst_type;
452129f1f9eSRichard Henderson TCGType src_type;
453129f1f9eSRichard Henderson MemOp src_ext;
454129f1f9eSRichard Henderson } TCGMovExtend;
455129f1f9eSRichard Henderson
456b3dfd5fcSRichard Henderson /**
457b3dfd5fcSRichard Henderson * tcg_out_movext -- move and extend
458b3dfd5fcSRichard Henderson * @s: tcg context
459b3dfd5fcSRichard Henderson * @dst_type: integral type for destination
460b3dfd5fcSRichard Henderson * @dst: destination register
461b3dfd5fcSRichard Henderson * @src_type: integral type for source
462b3dfd5fcSRichard Henderson * @src_ext: extension to apply to source
463b3dfd5fcSRichard Henderson * @src: source register
464b3dfd5fcSRichard Henderson *
465b3dfd5fcSRichard Henderson * Move or extend @src into @dst, depending on @src_ext and the types.
466b3dfd5fcSRichard Henderson */
tcg_out_movext(TCGContext * s,TCGType dst_type,TCGReg dst,TCGType src_type,MemOp src_ext,TCGReg src)467129f1f9eSRichard Henderson static void tcg_out_movext(TCGContext *s, TCGType dst_type, TCGReg dst,
468b3dfd5fcSRichard Henderson TCGType src_type, MemOp src_ext, TCGReg src)
469b3dfd5fcSRichard Henderson {
470b3dfd5fcSRichard Henderson switch (src_ext) {
471b3dfd5fcSRichard Henderson case MO_UB:
472b3dfd5fcSRichard Henderson tcg_out_ext8u(s, dst, src);
473b3dfd5fcSRichard Henderson break;
474b3dfd5fcSRichard Henderson case MO_SB:
475b3dfd5fcSRichard Henderson tcg_out_ext8s(s, dst_type, dst, src);
476b3dfd5fcSRichard Henderson break;
477b3dfd5fcSRichard Henderson case MO_UW:
478b3dfd5fcSRichard Henderson tcg_out_ext16u(s, dst, src);
479b3dfd5fcSRichard Henderson break;
480b3dfd5fcSRichard Henderson case MO_SW:
481b3dfd5fcSRichard Henderson tcg_out_ext16s(s, dst_type, dst, src);
482b3dfd5fcSRichard Henderson break;
483b3dfd5fcSRichard Henderson case MO_UL:
484b3dfd5fcSRichard Henderson case MO_SL:
485b3dfd5fcSRichard Henderson if (dst_type == TCG_TYPE_I32) {
486b3dfd5fcSRichard Henderson if (src_type == TCG_TYPE_I32) {
487b3dfd5fcSRichard Henderson tcg_out_mov(s, TCG_TYPE_I32, dst, src);
488b3dfd5fcSRichard Henderson } else {
489b3dfd5fcSRichard Henderson tcg_out_extrl_i64_i32(s, dst, src);
490b3dfd5fcSRichard Henderson }
491b3dfd5fcSRichard Henderson } else if (src_type == TCG_TYPE_I32) {
492b3dfd5fcSRichard Henderson if (src_ext & MO_SIGN) {
493b3dfd5fcSRichard Henderson tcg_out_exts_i32_i64(s, dst, src);
494b3dfd5fcSRichard Henderson } else {
495b3dfd5fcSRichard Henderson tcg_out_extu_i32_i64(s, dst, src);
496b3dfd5fcSRichard Henderson }
497b3dfd5fcSRichard Henderson } else {
498b3dfd5fcSRichard Henderson if (src_ext & MO_SIGN) {
499b3dfd5fcSRichard Henderson tcg_out_ext32s(s, dst, src);
500b3dfd5fcSRichard Henderson } else {
501b3dfd5fcSRichard Henderson tcg_out_ext32u(s, dst, src);
502b3dfd5fcSRichard Henderson }
503b3dfd5fcSRichard Henderson }
504b3dfd5fcSRichard Henderson break;
505b3dfd5fcSRichard Henderson case MO_UQ:
506b3dfd5fcSRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 64);
507b3dfd5fcSRichard Henderson if (dst_type == TCG_TYPE_I32) {
508b3dfd5fcSRichard Henderson tcg_out_extrl_i64_i32(s, dst, src);
509b3dfd5fcSRichard Henderson } else {
510b3dfd5fcSRichard Henderson tcg_out_mov(s, TCG_TYPE_I64, dst, src);
511b3dfd5fcSRichard Henderson }
512b3dfd5fcSRichard Henderson break;
513b3dfd5fcSRichard Henderson default:
514b3dfd5fcSRichard Henderson g_assert_not_reached();
515b3dfd5fcSRichard Henderson }
516b3dfd5fcSRichard Henderson }
517b3dfd5fcSRichard Henderson
518129f1f9eSRichard Henderson /* Minor variations on a theme, using a structure. */
tcg_out_movext1_new_src(TCGContext * s,const TCGMovExtend * i,TCGReg src)519129f1f9eSRichard Henderson static void tcg_out_movext1_new_src(TCGContext *s, const TCGMovExtend *i,
520129f1f9eSRichard Henderson TCGReg src)
521129f1f9eSRichard Henderson {
522129f1f9eSRichard Henderson tcg_out_movext(s, i->dst_type, i->dst, i->src_type, i->src_ext, src);
523129f1f9eSRichard Henderson }
524129f1f9eSRichard Henderson
tcg_out_movext1(TCGContext * s,const TCGMovExtend * i)525129f1f9eSRichard Henderson static void tcg_out_movext1(TCGContext *s, const TCGMovExtend *i)
526129f1f9eSRichard Henderson {
527129f1f9eSRichard Henderson tcg_out_movext1_new_src(s, i, i->src);
528129f1f9eSRichard Henderson }
529129f1f9eSRichard Henderson
530129f1f9eSRichard Henderson /**
531129f1f9eSRichard Henderson * tcg_out_movext2 -- move and extend two pair
532129f1f9eSRichard Henderson * @s: tcg context
533129f1f9eSRichard Henderson * @i1: first move description
534129f1f9eSRichard Henderson * @i2: second move description
535129f1f9eSRichard Henderson * @scratch: temporary register, or -1 for none
536129f1f9eSRichard Henderson *
537129f1f9eSRichard Henderson * As tcg_out_movext, for both @i1 and @i2, caring for overlap
538129f1f9eSRichard Henderson * between the sources and destinations.
539129f1f9eSRichard Henderson */
540129f1f9eSRichard Henderson
tcg_out_movext2(TCGContext * s,const TCGMovExtend * i1,const TCGMovExtend * i2,int scratch)5418429a1caSRichard Henderson static void tcg_out_movext2(TCGContext *s, const TCGMovExtend *i1,
542129f1f9eSRichard Henderson const TCGMovExtend *i2, int scratch)
543129f1f9eSRichard Henderson {
544129f1f9eSRichard Henderson TCGReg src1 = i1->src;
545129f1f9eSRichard Henderson TCGReg src2 = i2->src;
546129f1f9eSRichard Henderson
547129f1f9eSRichard Henderson if (i1->dst != src2) {
548129f1f9eSRichard Henderson tcg_out_movext1(s, i1);
549129f1f9eSRichard Henderson tcg_out_movext1(s, i2);
550129f1f9eSRichard Henderson return;
551129f1f9eSRichard Henderson }
552129f1f9eSRichard Henderson if (i2->dst == src1) {
553129f1f9eSRichard Henderson TCGType src1_type = i1->src_type;
554129f1f9eSRichard Henderson TCGType src2_type = i2->src_type;
555129f1f9eSRichard Henderson
556129f1f9eSRichard Henderson if (tcg_out_xchg(s, MAX(src1_type, src2_type), src1, src2)) {
557129f1f9eSRichard Henderson /* The data is now in the correct registers, now extend. */
558129f1f9eSRichard Henderson src1 = i2->src;
559129f1f9eSRichard Henderson src2 = i1->src;
560129f1f9eSRichard Henderson } else {
561129f1f9eSRichard Henderson tcg_debug_assert(scratch >= 0);
562129f1f9eSRichard Henderson tcg_out_mov(s, src1_type, scratch, src1);
563129f1f9eSRichard Henderson src1 = scratch;
564129f1f9eSRichard Henderson }
565129f1f9eSRichard Henderson }
566129f1f9eSRichard Henderson tcg_out_movext1_new_src(s, i2, src2);
567129f1f9eSRichard Henderson tcg_out_movext1_new_src(s, i1, src1);
568129f1f9eSRichard Henderson }
569129f1f9eSRichard Henderson
5702462e30eSRichard Henderson /**
5712462e30eSRichard Henderson * tcg_out_movext3 -- move and extend three pair
5722462e30eSRichard Henderson * @s: tcg context
5732462e30eSRichard Henderson * @i1: first move description
5742462e30eSRichard Henderson * @i2: second move description
5752462e30eSRichard Henderson * @i3: third move description
5762462e30eSRichard Henderson * @scratch: temporary register, or -1 for none
5772462e30eSRichard Henderson *
5782462e30eSRichard Henderson * As tcg_out_movext, for all of @i1, @i2 and @i3, caring for overlap
5792462e30eSRichard Henderson * between the sources and destinations.
5802462e30eSRichard Henderson */
5812462e30eSRichard Henderson
tcg_out_movext3(TCGContext * s,const TCGMovExtend * i1,const TCGMovExtend * i2,const TCGMovExtend * i3,int scratch)5822462e30eSRichard Henderson static void tcg_out_movext3(TCGContext *s, const TCGMovExtend *i1,
5832462e30eSRichard Henderson const TCGMovExtend *i2, const TCGMovExtend *i3,
5842462e30eSRichard Henderson int scratch)
5852462e30eSRichard Henderson {
5862462e30eSRichard Henderson TCGReg src1 = i1->src;
5872462e30eSRichard Henderson TCGReg src2 = i2->src;
5882462e30eSRichard Henderson TCGReg src3 = i3->src;
5892462e30eSRichard Henderson
5902462e30eSRichard Henderson if (i1->dst != src2 && i1->dst != src3) {
5912462e30eSRichard Henderson tcg_out_movext1(s, i1);
5922462e30eSRichard Henderson tcg_out_movext2(s, i2, i3, scratch);
5932462e30eSRichard Henderson return;
5942462e30eSRichard Henderson }
5952462e30eSRichard Henderson if (i2->dst != src1 && i2->dst != src3) {
5962462e30eSRichard Henderson tcg_out_movext1(s, i2);
5972462e30eSRichard Henderson tcg_out_movext2(s, i1, i3, scratch);
5982462e30eSRichard Henderson return;
5992462e30eSRichard Henderson }
6002462e30eSRichard Henderson if (i3->dst != src1 && i3->dst != src2) {
6012462e30eSRichard Henderson tcg_out_movext1(s, i3);
6022462e30eSRichard Henderson tcg_out_movext2(s, i1, i2, scratch);
6032462e30eSRichard Henderson return;
6042462e30eSRichard Henderson }
6052462e30eSRichard Henderson
6062462e30eSRichard Henderson /*
6072462e30eSRichard Henderson * There is a cycle. Since there are only 3 nodes, the cycle is
6082462e30eSRichard Henderson * either "clockwise" or "anti-clockwise", and can be solved with
6092462e30eSRichard Henderson * a single scratch or two xchg.
6102462e30eSRichard Henderson */
6112462e30eSRichard Henderson if (i1->dst == src2 && i2->dst == src3 && i3->dst == src1) {
6122462e30eSRichard Henderson /* "Clockwise" */
6132462e30eSRichard Henderson if (tcg_out_xchg(s, MAX(i1->src_type, i2->src_type), src1, src2)) {
6142462e30eSRichard Henderson tcg_out_xchg(s, MAX(i2->src_type, i3->src_type), src2, src3);
6152462e30eSRichard Henderson /* The data is now in the correct registers, now extend. */
6162462e30eSRichard Henderson tcg_out_movext1_new_src(s, i1, i1->dst);
6172462e30eSRichard Henderson tcg_out_movext1_new_src(s, i2, i2->dst);
6182462e30eSRichard Henderson tcg_out_movext1_new_src(s, i3, i3->dst);
6192462e30eSRichard Henderson } else {
6202462e30eSRichard Henderson tcg_debug_assert(scratch >= 0);
6212462e30eSRichard Henderson tcg_out_mov(s, i1->src_type, scratch, src1);
6222462e30eSRichard Henderson tcg_out_movext1(s, i3);
6232462e30eSRichard Henderson tcg_out_movext1(s, i2);
6242462e30eSRichard Henderson tcg_out_movext1_new_src(s, i1, scratch);
6252462e30eSRichard Henderson }
6262462e30eSRichard Henderson } else if (i1->dst == src3 && i2->dst == src1 && i3->dst == src2) {
6272462e30eSRichard Henderson /* "Anti-clockwise" */
6282462e30eSRichard Henderson if (tcg_out_xchg(s, MAX(i2->src_type, i3->src_type), src2, src3)) {
6292462e30eSRichard Henderson tcg_out_xchg(s, MAX(i1->src_type, i2->src_type), src1, src2);
6302462e30eSRichard Henderson /* The data is now in the correct registers, now extend. */
6312462e30eSRichard Henderson tcg_out_movext1_new_src(s, i1, i1->dst);
6322462e30eSRichard Henderson tcg_out_movext1_new_src(s, i2, i2->dst);
6332462e30eSRichard Henderson tcg_out_movext1_new_src(s, i3, i3->dst);
6342462e30eSRichard Henderson } else {
6352462e30eSRichard Henderson tcg_debug_assert(scratch >= 0);
6362462e30eSRichard Henderson tcg_out_mov(s, i1->src_type, scratch, src1);
6372462e30eSRichard Henderson tcg_out_movext1(s, i2);
6382462e30eSRichard Henderson tcg_out_movext1(s, i3);
6392462e30eSRichard Henderson tcg_out_movext1_new_src(s, i1, scratch);
6402462e30eSRichard Henderson }
6412462e30eSRichard Henderson } else {
6422462e30eSRichard Henderson g_assert_not_reached();
6432462e30eSRichard Henderson }
6442462e30eSRichard Henderson }
6452462e30eSRichard Henderson
646a417ef83SRichard Henderson /*
647a417ef83SRichard Henderson * Allocate a new TCGLabelQemuLdst entry.
648a417ef83SRichard Henderson */
649a417ef83SRichard Henderson
650a417ef83SRichard Henderson __attribute__((unused))
new_ldst_label(TCGContext * s)651a417ef83SRichard Henderson static TCGLabelQemuLdst *new_ldst_label(TCGContext *s)
652a417ef83SRichard Henderson {
653a417ef83SRichard Henderson TCGLabelQemuLdst *l = tcg_malloc(sizeof(*l));
654a417ef83SRichard Henderson
655a417ef83SRichard Henderson memset(l, 0, sizeof(*l));
656a417ef83SRichard Henderson QSIMPLEQ_INSERT_TAIL(&s->ldst_labels, l, next);
657a417ef83SRichard Henderson
658a417ef83SRichard Henderson return l;
659a417ef83SRichard Henderson }
660a417ef83SRichard Henderson
661a417ef83SRichard Henderson /*
662a417ef83SRichard Henderson * Allocate new constant pool entries.
663a417ef83SRichard Henderson */
664a417ef83SRichard Henderson
665a417ef83SRichard Henderson typedef struct TCGLabelPoolData {
666a417ef83SRichard Henderson struct TCGLabelPoolData *next;
667a417ef83SRichard Henderson tcg_insn_unit *label;
668a417ef83SRichard Henderson intptr_t addend;
669a417ef83SRichard Henderson int rtype;
670a417ef83SRichard Henderson unsigned nlong;
671a417ef83SRichard Henderson tcg_target_ulong data[];
672a417ef83SRichard Henderson } TCGLabelPoolData;
673a417ef83SRichard Henderson
new_pool_alloc(TCGContext * s,int nlong,int rtype,tcg_insn_unit * label,intptr_t addend)674a417ef83SRichard Henderson static TCGLabelPoolData *new_pool_alloc(TCGContext *s, int nlong, int rtype,
675a417ef83SRichard Henderson tcg_insn_unit *label, intptr_t addend)
676a417ef83SRichard Henderson {
677a417ef83SRichard Henderson TCGLabelPoolData *n = tcg_malloc(sizeof(TCGLabelPoolData)
678a417ef83SRichard Henderson + sizeof(tcg_target_ulong) * nlong);
679a417ef83SRichard Henderson
680a417ef83SRichard Henderson n->label = label;
681a417ef83SRichard Henderson n->addend = addend;
682a417ef83SRichard Henderson n->rtype = rtype;
683a417ef83SRichard Henderson n->nlong = nlong;
684a417ef83SRichard Henderson return n;
685a417ef83SRichard Henderson }
686a417ef83SRichard Henderson
new_pool_insert(TCGContext * s,TCGLabelPoolData * n)687a417ef83SRichard Henderson static void new_pool_insert(TCGContext *s, TCGLabelPoolData *n)
688a417ef83SRichard Henderson {
689a417ef83SRichard Henderson TCGLabelPoolData *i, **pp;
690a417ef83SRichard Henderson int nlong = n->nlong;
691a417ef83SRichard Henderson
692a417ef83SRichard Henderson /* Insertion sort on the pool. */
693a417ef83SRichard Henderson for (pp = &s->pool_labels; (i = *pp) != NULL; pp = &i->next) {
694a417ef83SRichard Henderson if (nlong > i->nlong) {
695a417ef83SRichard Henderson break;
696a417ef83SRichard Henderson }
697a417ef83SRichard Henderson if (nlong < i->nlong) {
698a417ef83SRichard Henderson continue;
699a417ef83SRichard Henderson }
700a417ef83SRichard Henderson if (memcmp(n->data, i->data, sizeof(tcg_target_ulong) * nlong) >= 0) {
701a417ef83SRichard Henderson break;
702a417ef83SRichard Henderson }
703a417ef83SRichard Henderson }
704a417ef83SRichard Henderson n->next = *pp;
705a417ef83SRichard Henderson *pp = n;
706a417ef83SRichard Henderson }
707a417ef83SRichard Henderson
708a417ef83SRichard Henderson /* The "usual" for generic integer code. */
709a417ef83SRichard Henderson __attribute__((unused))
new_pool_label(TCGContext * s,tcg_target_ulong d,int rtype,tcg_insn_unit * label,intptr_t addend)710a417ef83SRichard Henderson static void new_pool_label(TCGContext *s, tcg_target_ulong d, int rtype,
711a417ef83SRichard Henderson tcg_insn_unit *label, intptr_t addend)
712a417ef83SRichard Henderson {
713a417ef83SRichard Henderson TCGLabelPoolData *n = new_pool_alloc(s, 1, rtype, label, addend);
714a417ef83SRichard Henderson n->data[0] = d;
715a417ef83SRichard Henderson new_pool_insert(s, n);
716a417ef83SRichard Henderson }
717a417ef83SRichard Henderson
718a417ef83SRichard Henderson /* For v64 or v128, depending on the host. */
719a417ef83SRichard Henderson __attribute__((unused))
new_pool_l2(TCGContext * s,int rtype,tcg_insn_unit * label,intptr_t addend,tcg_target_ulong d0,tcg_target_ulong d1)720a417ef83SRichard Henderson static void new_pool_l2(TCGContext *s, int rtype, tcg_insn_unit *label,
721a417ef83SRichard Henderson intptr_t addend, tcg_target_ulong d0,
722a417ef83SRichard Henderson tcg_target_ulong d1)
723a417ef83SRichard Henderson {
724a417ef83SRichard Henderson TCGLabelPoolData *n = new_pool_alloc(s, 2, rtype, label, addend);
725a417ef83SRichard Henderson n->data[0] = d0;
726a417ef83SRichard Henderson n->data[1] = d1;
727a417ef83SRichard Henderson new_pool_insert(s, n);
728a417ef83SRichard Henderson }
729a417ef83SRichard Henderson
730a417ef83SRichard Henderson /* For v128 or v256, depending on the host. */
731a417ef83SRichard Henderson __attribute__((unused))
new_pool_l4(TCGContext * s,int rtype,tcg_insn_unit * label,intptr_t addend,tcg_target_ulong d0,tcg_target_ulong d1,tcg_target_ulong d2,tcg_target_ulong d3)732a417ef83SRichard Henderson static void new_pool_l4(TCGContext *s, int rtype, tcg_insn_unit *label,
733a417ef83SRichard Henderson intptr_t addend, tcg_target_ulong d0,
734a417ef83SRichard Henderson tcg_target_ulong d1, tcg_target_ulong d2,
735a417ef83SRichard Henderson tcg_target_ulong d3)
736a417ef83SRichard Henderson {
737a417ef83SRichard Henderson TCGLabelPoolData *n = new_pool_alloc(s, 4, rtype, label, addend);
738a417ef83SRichard Henderson n->data[0] = d0;
739a417ef83SRichard Henderson n->data[1] = d1;
740a417ef83SRichard Henderson n->data[2] = d2;
741a417ef83SRichard Henderson n->data[3] = d3;
742a417ef83SRichard Henderson new_pool_insert(s, n);
743a417ef83SRichard Henderson }
744a417ef83SRichard Henderson
745a417ef83SRichard Henderson /* For v256, for 32-bit host. */
746a417ef83SRichard Henderson __attribute__((unused))
new_pool_l8(TCGContext * s,int rtype,tcg_insn_unit * label,intptr_t addend,tcg_target_ulong d0,tcg_target_ulong d1,tcg_target_ulong d2,tcg_target_ulong d3,tcg_target_ulong d4,tcg_target_ulong d5,tcg_target_ulong d6,tcg_target_ulong d7)747a417ef83SRichard Henderson static void new_pool_l8(TCGContext *s, int rtype, tcg_insn_unit *label,
748a417ef83SRichard Henderson intptr_t addend, tcg_target_ulong d0,
749a417ef83SRichard Henderson tcg_target_ulong d1, tcg_target_ulong d2,
750a417ef83SRichard Henderson tcg_target_ulong d3, tcg_target_ulong d4,
751a417ef83SRichard Henderson tcg_target_ulong d5, tcg_target_ulong d6,
752a417ef83SRichard Henderson tcg_target_ulong d7)
753a417ef83SRichard Henderson {
754a417ef83SRichard Henderson TCGLabelPoolData *n = new_pool_alloc(s, 8, rtype, label, addend);
755a417ef83SRichard Henderson n->data[0] = d0;
756a417ef83SRichard Henderson n->data[1] = d1;
757a417ef83SRichard Henderson n->data[2] = d2;
758a417ef83SRichard Henderson n->data[3] = d3;
759a417ef83SRichard Henderson n->data[4] = d4;
760a417ef83SRichard Henderson n->data[5] = d5;
761a417ef83SRichard Henderson n->data[6] = d6;
762a417ef83SRichard Henderson n->data[7] = d7;
763a417ef83SRichard Henderson new_pool_insert(s, n);
764a417ef83SRichard Henderson }
765a417ef83SRichard Henderson
766a417ef83SRichard Henderson /*
767a417ef83SRichard Henderson * Generate TB finalization at the end of block
768a417ef83SRichard Henderson */
769a417ef83SRichard Henderson
tcg_out_ldst_finalize(TCGContext * s)770a417ef83SRichard Henderson static int tcg_out_ldst_finalize(TCGContext *s)
771a417ef83SRichard Henderson {
772a417ef83SRichard Henderson TCGLabelQemuLdst *lb;
773a417ef83SRichard Henderson
774a417ef83SRichard Henderson /* qemu_ld/st slow paths */
775a417ef83SRichard Henderson QSIMPLEQ_FOREACH(lb, &s->ldst_labels, next) {
776a417ef83SRichard Henderson if (lb->is_ld
777a417ef83SRichard Henderson ? !tcg_out_qemu_ld_slow_path(s, lb)
778a417ef83SRichard Henderson : !tcg_out_qemu_st_slow_path(s, lb)) {
779a417ef83SRichard Henderson return -2;
780a417ef83SRichard Henderson }
781a417ef83SRichard Henderson
782a417ef83SRichard Henderson /*
783a417ef83SRichard Henderson * Test for (pending) buffer overflow. The assumption is that any
784a417ef83SRichard Henderson * one operation beginning below the high water mark cannot overrun
785a417ef83SRichard Henderson * the buffer completely. Thus we can test for overflow after
786a417ef83SRichard Henderson * generating code without having to check during generation.
787a417ef83SRichard Henderson */
788a417ef83SRichard Henderson if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) {
789a417ef83SRichard Henderson return -1;
790a417ef83SRichard Henderson }
791a417ef83SRichard Henderson }
792a417ef83SRichard Henderson return 0;
793a417ef83SRichard Henderson }
794a417ef83SRichard Henderson
tcg_out_pool_finalize(TCGContext * s)795a417ef83SRichard Henderson static int tcg_out_pool_finalize(TCGContext *s)
796a417ef83SRichard Henderson {
797a417ef83SRichard Henderson TCGLabelPoolData *p = s->pool_labels;
798a417ef83SRichard Henderson TCGLabelPoolData *l = NULL;
799a417ef83SRichard Henderson void *a;
800a417ef83SRichard Henderson
801a417ef83SRichard Henderson if (p == NULL) {
802a417ef83SRichard Henderson return 0;
803a417ef83SRichard Henderson }
804a417ef83SRichard Henderson
805a417ef83SRichard Henderson /*
806a417ef83SRichard Henderson * ??? Round up to qemu_icache_linesize, but then do not round
807a417ef83SRichard Henderson * again when allocating the next TranslationBlock structure.
808a417ef83SRichard Henderson */
809a417ef83SRichard Henderson a = (void *)ROUND_UP((uintptr_t)s->code_ptr,
810a417ef83SRichard Henderson sizeof(tcg_target_ulong) * p->nlong);
811a417ef83SRichard Henderson tcg_out_nop_fill(s->code_ptr, (tcg_insn_unit *)a - s->code_ptr);
812a417ef83SRichard Henderson s->data_gen_ptr = a;
813a417ef83SRichard Henderson
814a417ef83SRichard Henderson for (; p != NULL; p = p->next) {
815a417ef83SRichard Henderson size_t size = sizeof(tcg_target_ulong) * p->nlong;
816a417ef83SRichard Henderson uintptr_t value;
817a417ef83SRichard Henderson
818a417ef83SRichard Henderson if (!l || l->nlong != p->nlong || memcmp(l->data, p->data, size)) {
819a417ef83SRichard Henderson if (unlikely(a > s->code_gen_highwater)) {
820a417ef83SRichard Henderson return -1;
821a417ef83SRichard Henderson }
822a417ef83SRichard Henderson memcpy(a, p->data, size);
823a417ef83SRichard Henderson a += size;
824a417ef83SRichard Henderson l = p;
825a417ef83SRichard Henderson }
826a417ef83SRichard Henderson
827a417ef83SRichard Henderson value = (uintptr_t)tcg_splitwx_to_rx(a) - size;
828a417ef83SRichard Henderson if (!patch_reloc(p->label, p->rtype, value, p->addend)) {
829a417ef83SRichard Henderson return -2;
830a417ef83SRichard Henderson }
831a417ef83SRichard Henderson }
832a417ef83SRichard Henderson
833a417ef83SRichard Henderson s->code_ptr = a;
834a417ef83SRichard Henderson return 0;
835a417ef83SRichard Henderson }
836a417ef83SRichard Henderson
8374c22e840SRichard Henderson #define C_PFX1(P, A) P##A
8384c22e840SRichard Henderson #define C_PFX2(P, A, B) P##A##_##B
8394c22e840SRichard Henderson #define C_PFX3(P, A, B, C) P##A##_##B##_##C
8404c22e840SRichard Henderson #define C_PFX4(P, A, B, C, D) P##A##_##B##_##C##_##D
8414c22e840SRichard Henderson #define C_PFX5(P, A, B, C, D, E) P##A##_##B##_##C##_##D##_##E
8424c22e840SRichard Henderson #define C_PFX6(P, A, B, C, D, E, F) P##A##_##B##_##C##_##D##_##E##_##F
8434c22e840SRichard Henderson
8444c22e840SRichard Henderson /* Define an enumeration for the various combinations. */
8454c22e840SRichard Henderson
8464c22e840SRichard Henderson #define C_O0_I1(I1) C_PFX1(c_o0_i1_, I1),
8474c22e840SRichard Henderson #define C_O0_I2(I1, I2) C_PFX2(c_o0_i2_, I1, I2),
8484c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3) C_PFX3(c_o0_i3_, I1, I2, I3),
8494c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4) C_PFX4(c_o0_i4_, I1, I2, I3, I4),
8504c22e840SRichard Henderson
8514c22e840SRichard Henderson #define C_O1_I1(O1, I1) C_PFX2(c_o1_i1_, O1, I1),
8524c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2) C_PFX3(c_o1_i2_, O1, I1, I2),
8534c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3) C_PFX4(c_o1_i3_, O1, I1, I2, I3),
8544c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4) C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4),
8554c22e840SRichard Henderson
8564c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2) C_PFX3(c_n1_i2_, O1, I1, I2),
857ca5bed07SRichard Henderson #define C_N1O1_I1(O1, O2, I1) C_PFX3(c_n1o1_i1_, O1, O2, I1),
858fa645b48SRichard Henderson #define C_N2_I1(O1, O2, I1) C_PFX3(c_n2_i1_, O1, O2, I1),
8594c22e840SRichard Henderson
8604c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1) C_PFX3(c_o2_i1_, O1, O2, I1),
8614c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2) C_PFX4(c_o2_i2_, O1, O2, I1, I2),
8624c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3) C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3),
8634c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4),
86422d2e535SIlya Leoshkevich #define C_N1_O1_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_n1_o1_i4_, O1, O2, I1, I2, I3, I4),
8654c22e840SRichard Henderson
8664c22e840SRichard Henderson typedef enum {
8675500bd9eSRichard Henderson C_Dynamic = -2,
868da43e5e6SRichard Henderson C_NotImplemented = -1,
8694c22e840SRichard Henderson #include "tcg-target-con-set.h"
8704c22e840SRichard Henderson } TCGConstraintSetIndex;
8714c22e840SRichard Henderson
8726323b363SRichard Henderson static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode, TCGType, unsigned);
8734c22e840SRichard Henderson
8744c22e840SRichard Henderson #undef C_O0_I1
8754c22e840SRichard Henderson #undef C_O0_I2
8764c22e840SRichard Henderson #undef C_O0_I3
8774c22e840SRichard Henderson #undef C_O0_I4
8784c22e840SRichard Henderson #undef C_O1_I1
8794c22e840SRichard Henderson #undef C_O1_I2
8804c22e840SRichard Henderson #undef C_O1_I3
8814c22e840SRichard Henderson #undef C_O1_I4
8824c22e840SRichard Henderson #undef C_N1_I2
883ca5bed07SRichard Henderson #undef C_N1O1_I1
884fa645b48SRichard Henderson #undef C_N2_I1
8854c22e840SRichard Henderson #undef C_O2_I1
8864c22e840SRichard Henderson #undef C_O2_I2
8874c22e840SRichard Henderson #undef C_O2_I3
8884c22e840SRichard Henderson #undef C_O2_I4
88922d2e535SIlya Leoshkevich #undef C_N1_O1_I4
8904c22e840SRichard Henderson
8914c22e840SRichard Henderson /* Put all of the constraint sets into an array, indexed by the enum. */
8924c22e840SRichard Henderson
8933e80824eSRichard Henderson typedef struct TCGConstraintSet {
8943e80824eSRichard Henderson uint8_t nb_oargs, nb_iargs;
8953e80824eSRichard Henderson const char *args_ct_str[TCG_MAX_OP_ARGS];
8963e80824eSRichard Henderson } TCGConstraintSet;
8974c22e840SRichard Henderson
8983e80824eSRichard Henderson #define C_O0_I1(I1) { 0, 1, { #I1 } },
8993e80824eSRichard Henderson #define C_O0_I2(I1, I2) { 0, 2, { #I1, #I2 } },
9003e80824eSRichard Henderson #define C_O0_I3(I1, I2, I3) { 0, 3, { #I1, #I2, #I3 } },
9013e80824eSRichard Henderson #define C_O0_I4(I1, I2, I3, I4) { 0, 4, { #I1, #I2, #I3, #I4 } },
9024c22e840SRichard Henderson
9033e80824eSRichard Henderson #define C_O1_I1(O1, I1) { 1, 1, { #O1, #I1 } },
9043e80824eSRichard Henderson #define C_O1_I2(O1, I1, I2) { 1, 2, { #O1, #I1, #I2 } },
9053e80824eSRichard Henderson #define C_O1_I3(O1, I1, I2, I3) { 1, 3, { #O1, #I1, #I2, #I3 } },
9063e80824eSRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4) { 1, 4, { #O1, #I1, #I2, #I3, #I4 } },
9074c22e840SRichard Henderson
9083e80824eSRichard Henderson #define C_N1_I2(O1, I1, I2) { 1, 2, { "&" #O1, #I1, #I2 } },
9093e80824eSRichard Henderson #define C_N1O1_I1(O1, O2, I1) { 2, 1, { "&" #O1, #O2, #I1 } },
9103e80824eSRichard Henderson #define C_N2_I1(O1, O2, I1) { 2, 1, { "&" #O1, "&" #O2, #I1 } },
9114c22e840SRichard Henderson
9123e80824eSRichard Henderson #define C_O2_I1(O1, O2, I1) { 2, 1, { #O1, #O2, #I1 } },
9133e80824eSRichard Henderson #define C_O2_I2(O1, O2, I1, I2) { 2, 2, { #O1, #O2, #I1, #I2 } },
9143e80824eSRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3) { 2, 3, { #O1, #O2, #I1, #I2, #I3 } },
9153e80824eSRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) { 2, 4, { #O1, #O2, #I1, #I2, #I3, #I4 } },
9163e80824eSRichard Henderson #define C_N1_O1_I4(O1, O2, I1, I2, I3, I4) { 2, 4, { "&" #O1, #O2, #I1, #I2, #I3, #I4 } },
9173e80824eSRichard Henderson
9183e80824eSRichard Henderson static const TCGConstraintSet constraint_sets[] = {
9194c22e840SRichard Henderson #include "tcg-target-con-set.h"
9204c22e840SRichard Henderson };
9214c22e840SRichard Henderson
9224c22e840SRichard Henderson #undef C_O0_I1
9234c22e840SRichard Henderson #undef C_O0_I2
9244c22e840SRichard Henderson #undef C_O0_I3
9254c22e840SRichard Henderson #undef C_O0_I4
9264c22e840SRichard Henderson #undef C_O1_I1
9274c22e840SRichard Henderson #undef C_O1_I2
9284c22e840SRichard Henderson #undef C_O1_I3
9294c22e840SRichard Henderson #undef C_O1_I4
9304c22e840SRichard Henderson #undef C_N1_I2
931ca5bed07SRichard Henderson #undef C_N1O1_I1
932fa645b48SRichard Henderson #undef C_N2_I1
9334c22e840SRichard Henderson #undef C_O2_I1
9344c22e840SRichard Henderson #undef C_O2_I2
9354c22e840SRichard Henderson #undef C_O2_I3
9364c22e840SRichard Henderson #undef C_O2_I4
93722d2e535SIlya Leoshkevich #undef C_N1_O1_I4
9384c22e840SRichard Henderson
9394c22e840SRichard Henderson /* Expand the enumerator to be returned from tcg_target_op_def(). */
9404c22e840SRichard Henderson
9414c22e840SRichard Henderson #define C_O0_I1(I1) C_PFX1(c_o0_i1_, I1)
9424c22e840SRichard Henderson #define C_O0_I2(I1, I2) C_PFX2(c_o0_i2_, I1, I2)
9434c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3) C_PFX3(c_o0_i3_, I1, I2, I3)
9444c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4) C_PFX4(c_o0_i4_, I1, I2, I3, I4)
9454c22e840SRichard Henderson
9464c22e840SRichard Henderson #define C_O1_I1(O1, I1) C_PFX2(c_o1_i1_, O1, I1)
9474c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2) C_PFX3(c_o1_i2_, O1, I1, I2)
9484c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3) C_PFX4(c_o1_i3_, O1, I1, I2, I3)
9494c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4) C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4)
9504c22e840SRichard Henderson
9514c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2) C_PFX3(c_n1_i2_, O1, I1, I2)
952ca5bed07SRichard Henderson #define C_N1O1_I1(O1, O2, I1) C_PFX3(c_n1o1_i1_, O1, O2, I1)
953fa645b48SRichard Henderson #define C_N2_I1(O1, O2, I1) C_PFX3(c_n2_i1_, O1, O2, I1)
9544c22e840SRichard Henderson
9554c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1) C_PFX3(c_o2_i1_, O1, O2, I1)
9564c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2) C_PFX4(c_o2_i2_, O1, O2, I1, I2)
9574c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3) C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3)
9584c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4)
95922d2e535SIlya Leoshkevich #define C_N1_O1_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_n1_o1_i4_, O1, O2, I1, I2, I3, I4)
9604c22e840SRichard Henderson
9615500bd9eSRichard Henderson /*
9625500bd9eSRichard Henderson * TCGOutOp is the base class for a set of structures that describe how
9635500bd9eSRichard Henderson * to generate code for a given TCGOpcode.
9645500bd9eSRichard Henderson *
9655500bd9eSRichard Henderson * @static_constraint:
9665500bd9eSRichard Henderson * C_NotImplemented: The TCGOpcode is not supported by the backend.
9675500bd9eSRichard Henderson * C_Dynamic: Use @dynamic_constraint to select a constraint set
9685500bd9eSRichard Henderson * based on any of @type, @flags, or host isa.
9695500bd9eSRichard Henderson * Otherwise: The register allocation constrains for the TCGOpcode.
9705500bd9eSRichard Henderson *
9715500bd9eSRichard Henderson * Subclasses of TCGOutOp will define a set of output routines that may
9725500bd9eSRichard Henderson * be used. Such routines will often be selected by the set of registers
9735500bd9eSRichard Henderson * and constants that come out of register allocation. The set of
9745500bd9eSRichard Henderson * routines that are provided will guide the set of constraints that are
9755500bd9eSRichard Henderson * legal. In particular, assume that tcg_optimize() has done its job in
9765500bd9eSRichard Henderson * swapping commutative operands and folding operations for which all
9775500bd9eSRichard Henderson * operands are constant.
9785500bd9eSRichard Henderson */
9795500bd9eSRichard Henderson typedef struct TCGOutOp {
9805500bd9eSRichard Henderson TCGConstraintSetIndex static_constraint;
9815500bd9eSRichard Henderson TCGConstraintSetIndex (*dynamic_constraint)(TCGType type, unsigned flags);
9825500bd9eSRichard Henderson } TCGOutOp;
9835500bd9eSRichard Henderson
984ee603152SRichard Henderson typedef struct TCGOutOpAddSubCarry {
985ee603152SRichard Henderson TCGOutOp base;
986ee603152SRichard Henderson void (*out_rrr)(TCGContext *s, TCGType type,
987ee603152SRichard Henderson TCGReg a0, TCGReg a1, TCGReg a2);
988ee603152SRichard Henderson void (*out_rri)(TCGContext *s, TCGType type,
989ee603152SRichard Henderson TCGReg a0, TCGReg a1, tcg_target_long a2);
990ee603152SRichard Henderson void (*out_rir)(TCGContext *s, TCGType type,
991ee603152SRichard Henderson TCGReg a0, tcg_target_long a1, TCGReg a2);
992ee603152SRichard Henderson void (*out_rii)(TCGContext *s, TCGType type,
993ee603152SRichard Henderson TCGReg a0, tcg_target_long a1, tcg_target_long a2);
994ee603152SRichard Henderson } TCGOutOpAddSubCarry;
995ee603152SRichard Henderson
996662cdbcfSRichard Henderson typedef struct TCGOutOpBinary {
997662cdbcfSRichard Henderson TCGOutOp base;
998662cdbcfSRichard Henderson void (*out_rrr)(TCGContext *s, TCGType type,
999662cdbcfSRichard Henderson TCGReg a0, TCGReg a1, TCGReg a2);
1000662cdbcfSRichard Henderson void (*out_rri)(TCGContext *s, TCGType type,
1001662cdbcfSRichard Henderson TCGReg a0, TCGReg a1, tcg_target_long a2);
1002662cdbcfSRichard Henderson } TCGOutOpBinary;
1003662cdbcfSRichard Henderson
100499ac4706SRichard Henderson typedef struct TCGOutOpBrcond {
100599ac4706SRichard Henderson TCGOutOp base;
100699ac4706SRichard Henderson void (*out_rr)(TCGContext *s, TCGType type, TCGCond cond,
100799ac4706SRichard Henderson TCGReg a1, TCGReg a2, TCGLabel *label);
100899ac4706SRichard Henderson void (*out_ri)(TCGContext *s, TCGType type, TCGCond cond,
100999ac4706SRichard Henderson TCGReg a1, tcg_target_long a2, TCGLabel *label);
101099ac4706SRichard Henderson } TCGOutOpBrcond;
101199ac4706SRichard Henderson
1012f408df58SRichard Henderson typedef struct TCGOutOpBrcond2 {
1013f408df58SRichard Henderson TCGOutOp base;
1014f408df58SRichard Henderson void (*out)(TCGContext *s, TCGCond cond, TCGReg al, TCGReg ah,
1015f408df58SRichard Henderson TCGArg bl, bool const_bl,
1016f408df58SRichard Henderson TCGArg bh, bool const_bh, TCGLabel *l);
1017f408df58SRichard Henderson } TCGOutOpBrcond2;
1018f408df58SRichard Henderson
10195fa8e138SRichard Henderson typedef struct TCGOutOpBswap {
10205fa8e138SRichard Henderson TCGOutOp base;
10215fa8e138SRichard Henderson void (*out_rr)(TCGContext *s, TCGType type,
10225fa8e138SRichard Henderson TCGReg a0, TCGReg a1, unsigned flags);
10235fa8e138SRichard Henderson } TCGOutOpBswap;
10245fa8e138SRichard Henderson
1025cf4905c0SRichard Henderson typedef struct TCGOutOpDeposit {
1026cf4905c0SRichard Henderson TCGOutOp base;
1027cf4905c0SRichard Henderson void (*out_rrr)(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
1028cf4905c0SRichard Henderson TCGReg a2, unsigned ofs, unsigned len);
1029cf4905c0SRichard Henderson void (*out_rri)(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
1030cf4905c0SRichard Henderson tcg_target_long a2, unsigned ofs, unsigned len);
1031cf4905c0SRichard Henderson void (*out_rzr)(TCGContext *s, TCGType type, TCGReg a0,
1032cf4905c0SRichard Henderson TCGReg a2, unsigned ofs, unsigned len);
1033cf4905c0SRichard Henderson } TCGOutOpDeposit;
1034cf4905c0SRichard Henderson
1035d6cad9c9SRichard Henderson typedef struct TCGOutOpDivRem {
1036d6cad9c9SRichard Henderson TCGOutOp base;
1037d6cad9c9SRichard Henderson void (*out_rr01r)(TCGContext *s, TCGType type,
1038d6cad9c9SRichard Henderson TCGReg a0, TCGReg a1, TCGReg a4);
1039d6cad9c9SRichard Henderson } TCGOutOpDivRem;
1040d6cad9c9SRichard Henderson
10415a4d034fSRichard Henderson typedef struct TCGOutOpExtract {
10425a4d034fSRichard Henderson TCGOutOp base;
10435a4d034fSRichard Henderson void (*out_rr)(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
10445a4d034fSRichard Henderson unsigned ofs, unsigned len);
10455a4d034fSRichard Henderson } TCGOutOpExtract;
10465a4d034fSRichard Henderson
1047c8f9f700SRichard Henderson typedef struct TCGOutOpExtract2 {
1048c8f9f700SRichard Henderson TCGOutOp base;
1049c8f9f700SRichard Henderson void (*out_rrr)(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
1050c8f9f700SRichard Henderson TCGReg a2, unsigned shr);
1051c8f9f700SRichard Henderson } TCGOutOpExtract2;
1052c8f9f700SRichard Henderson
10530de5c9d1SRichard Henderson typedef struct TCGOutOpLoad {
10540de5c9d1SRichard Henderson TCGOutOp base;
10550de5c9d1SRichard Henderson void (*out)(TCGContext *s, TCGType type, TCGReg dest,
10560de5c9d1SRichard Henderson TCGReg base, intptr_t offset);
10570de5c9d1SRichard Henderson } TCGOutOpLoad;
10580de5c9d1SRichard Henderson
10591f406e46SRichard Henderson typedef struct TCGOutOpMovcond {
10601f406e46SRichard Henderson TCGOutOp base;
10611f406e46SRichard Henderson void (*out)(TCGContext *s, TCGType type, TCGCond cond,
10621f406e46SRichard Henderson TCGReg ret, TCGReg c1, TCGArg c2, bool const_c2,
10631f406e46SRichard Henderson TCGArg vt, bool const_vt, TCGArg vf, bool consf_vf);
10641f406e46SRichard Henderson } TCGOutOpMovcond;
10651f406e46SRichard Henderson
10665641afdfSRichard Henderson typedef struct TCGOutOpMul2 {
10675641afdfSRichard Henderson TCGOutOp base;
10685641afdfSRichard Henderson void (*out_rrrr)(TCGContext *s, TCGType type,
10695641afdfSRichard Henderson TCGReg a0, TCGReg a1, TCGReg a2, TCGReg a3);
10705641afdfSRichard Henderson } TCGOutOpMul2;
10715641afdfSRichard Henderson
10723bedb9d3SRichard Henderson typedef struct TCGOutOpQemuLdSt {
10733bedb9d3SRichard Henderson TCGOutOp base;
10743bedb9d3SRichard Henderson void (*out)(TCGContext *s, TCGType type, TCGReg dest,
10753bedb9d3SRichard Henderson TCGReg addr, MemOpIdx oi);
10763bedb9d3SRichard Henderson } TCGOutOpQemuLdSt;
10773bedb9d3SRichard Henderson
10783bedb9d3SRichard Henderson typedef struct TCGOutOpQemuLdSt2 {
10793bedb9d3SRichard Henderson TCGOutOp base;
10803bedb9d3SRichard Henderson void (*out)(TCGContext *s, TCGType type, TCGReg dlo, TCGReg dhi,
10813bedb9d3SRichard Henderson TCGReg addr, MemOpIdx oi);
10823bedb9d3SRichard Henderson } TCGOutOpQemuLdSt2;
10833bedb9d3SRichard Henderson
1084e126a91cSRichard Henderson typedef struct TCGOutOpUnary {
1085e126a91cSRichard Henderson TCGOutOp base;
1086e126a91cSRichard Henderson void (*out_rr)(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1);
1087e126a91cSRichard Henderson } TCGOutOpUnary;
1088e126a91cSRichard Henderson
10895a7b38c8SRichard Henderson typedef struct TCGOutOpSetcond {
10905a7b38c8SRichard Henderson TCGOutOp base;
10915a7b38c8SRichard Henderson void (*out_rrr)(TCGContext *s, TCGType type, TCGCond cond,
10925a7b38c8SRichard Henderson TCGReg ret, TCGReg a1, TCGReg a2);
10935a7b38c8SRichard Henderson void (*out_rri)(TCGContext *s, TCGType type, TCGCond cond,
10945a7b38c8SRichard Henderson TCGReg ret, TCGReg a1, tcg_target_long a2);
10955a7b38c8SRichard Henderson } TCGOutOpSetcond;
10965a7b38c8SRichard Henderson
1097e579c717SRichard Henderson typedef struct TCGOutOpSetcond2 {
1098e579c717SRichard Henderson TCGOutOp base;
1099e579c717SRichard Henderson void (*out)(TCGContext *s, TCGCond cond, TCGReg ret, TCGReg al, TCGReg ah,
1100e579c717SRichard Henderson TCGArg bl, bool const_bl, TCGArg bh, bool const_bh);
1101e579c717SRichard Henderson } TCGOutOpSetcond2;
1102e579c717SRichard Henderson
11034a686aa9SRichard Henderson typedef struct TCGOutOpStore {
11044a686aa9SRichard Henderson TCGOutOp base;
11054a686aa9SRichard Henderson void (*out_r)(TCGContext *s, TCGType type, TCGReg data,
11064a686aa9SRichard Henderson TCGReg base, intptr_t offset);
11074a686aa9SRichard Henderson void (*out_i)(TCGContext *s, TCGType type, tcg_target_long data,
11084a686aa9SRichard Henderson TCGReg base, intptr_t offset);
11094a686aa9SRichard Henderson } TCGOutOpStore;
11104a686aa9SRichard Henderson
11113f057e24SRichard Henderson typedef struct TCGOutOpSubtract {
11123f057e24SRichard Henderson TCGOutOp base;
11133f057e24SRichard Henderson void (*out_rrr)(TCGContext *s, TCGType type,
11143f057e24SRichard Henderson TCGReg a0, TCGReg a1, TCGReg a2);
11153f057e24SRichard Henderson void (*out_rir)(TCGContext *s, TCGType type,
11163f057e24SRichard Henderson TCGReg a0, tcg_target_long a1, TCGReg a2);
11173f057e24SRichard Henderson } TCGOutOpSubtract;
11183f057e24SRichard Henderson
1119139c1837SPaolo Bonzini #include "tcg-target.c.inc"
1120c896fe29Sbellard
11217857ee11SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
11227857ee11SRichard Henderson /* Validate CPUTLBDescFast placement. */
11237857ee11SRichard Henderson QEMU_BUILD_BUG_ON((int)(offsetof(CPUNegativeOffsetState, tlb.f[0]) -
11247857ee11SRichard Henderson sizeof(CPUNegativeOffsetState))
11257857ee11SRichard Henderson < MIN_TLB_MASK_TABLE_OFS);
11267857ee11SRichard Henderson #endif
11277857ee11SRichard Henderson
1128b7b7347fSRichard Henderson #if TCG_TARGET_REG_BITS == 64
1129b7b7347fSRichard Henderson /*
1130b7b7347fSRichard Henderson * We require these functions for slow-path function calls.
1131b7b7347fSRichard Henderson * Adapt them generically for opcode output.
1132b7b7347fSRichard Henderson */
1133b7b7347fSRichard Henderson
tgen_exts_i32_i64(TCGContext * s,TCGType t,TCGReg a0,TCGReg a1)1134b7b7347fSRichard Henderson static void tgen_exts_i32_i64(TCGContext *s, TCGType t, TCGReg a0, TCGReg a1)
1135b7b7347fSRichard Henderson {
1136b7b7347fSRichard Henderson tcg_out_exts_i32_i64(s, a0, a1);
1137b7b7347fSRichard Henderson }
1138b7b7347fSRichard Henderson
1139b7b7347fSRichard Henderson static const TCGOutOpUnary outop_exts_i32_i64 = {
1140b7b7347fSRichard Henderson .base.static_constraint = C_O1_I1(r, r),
1141b7b7347fSRichard Henderson .out_rr = tgen_exts_i32_i64,
1142b7b7347fSRichard Henderson };
1143c1ad25deSRichard Henderson
tgen_extu_i32_i64(TCGContext * s,TCGType t,TCGReg a0,TCGReg a1)1144c1ad25deSRichard Henderson static void tgen_extu_i32_i64(TCGContext *s, TCGType t, TCGReg a0, TCGReg a1)
1145c1ad25deSRichard Henderson {
1146c1ad25deSRichard Henderson tcg_out_extu_i32_i64(s, a0, a1);
1147c1ad25deSRichard Henderson }
1148c1ad25deSRichard Henderson
1149c1ad25deSRichard Henderson static const TCGOutOpUnary outop_extu_i32_i64 = {
1150c1ad25deSRichard Henderson .base.static_constraint = C_O1_I1(r, r),
1151c1ad25deSRichard Henderson .out_rr = tgen_extu_i32_i64,
1152c1ad25deSRichard Henderson };
11531e6fec9dSRichard Henderson
tgen_extrl_i64_i32(TCGContext * s,TCGType t,TCGReg a0,TCGReg a1)11541e6fec9dSRichard Henderson static void tgen_extrl_i64_i32(TCGContext *s, TCGType t, TCGReg a0, TCGReg a1)
11551e6fec9dSRichard Henderson {
11561e6fec9dSRichard Henderson tcg_out_extrl_i64_i32(s, a0, a1);
11571e6fec9dSRichard Henderson }
11581e6fec9dSRichard Henderson
11591e6fec9dSRichard Henderson static const TCGOutOpUnary outop_extrl_i64_i32 = {
11601e6fec9dSRichard Henderson .base.static_constraint = C_O1_I1(r, r),
11611e6fec9dSRichard Henderson .out_rr = TCG_TARGET_HAS_extr_i64_i32 ? tgen_extrl_i64_i32 : NULL,
11621e6fec9dSRichard Henderson };
1163b7b7347fSRichard Henderson #endif
1164b7b7347fSRichard Henderson
1165fee03fddSRichard Henderson static const TCGOutOp outop_goto_ptr = {
1166fee03fddSRichard Henderson .static_constraint = C_O0_I1(r),
1167fee03fddSRichard Henderson };
1168fee03fddSRichard Henderson
11690de5c9d1SRichard Henderson static const TCGOutOpLoad outop_ld = {
11700de5c9d1SRichard Henderson .base.static_constraint = C_O1_I1(r, r),
11710de5c9d1SRichard Henderson .out = tcg_out_ld,
11720de5c9d1SRichard Henderson };
11730de5c9d1SRichard Henderson
1174662cdbcfSRichard Henderson /*
1175662cdbcfSRichard Henderson * Register V as the TCGOutOp for O.
1176662cdbcfSRichard Henderson * This verifies that V is of type T, otherwise give a nice compiler error.
1177662cdbcfSRichard Henderson * This prevents trivial mistakes within each arch/tcg-target.c.inc.
1178662cdbcfSRichard Henderson */
1179662cdbcfSRichard Henderson #define OUTOP(O, T, V) [O] = _Generic(V, T: &V.base)
1180662cdbcfSRichard Henderson
11815500bd9eSRichard Henderson /* Register allocation descriptions for every TCGOpcode. */
11825500bd9eSRichard Henderson static const TCGOutOp * const all_outop[NB_OPS] = {
118379602f63SRichard Henderson OUTOP(INDEX_op_add, TCGOutOpBinary, outop_add),
1184ee603152SRichard Henderson OUTOP(INDEX_op_addci, TCGOutOpAddSubCarry, outop_addci),
1185ee603152SRichard Henderson OUTOP(INDEX_op_addcio, TCGOutOpBinary, outop_addcio),
1186ee603152SRichard Henderson OUTOP(INDEX_op_addco, TCGOutOpBinary, outop_addco),
1187ee603152SRichard Henderson /* addc1o is implemented with set_carry + addcio */
1188ee603152SRichard Henderson OUTOP(INDEX_op_addc1o, TCGOutOpBinary, outop_addcio),
1189c3b920b3SRichard Henderson OUTOP(INDEX_op_and, TCGOutOpBinary, outop_and),
119046f96bffSRichard Henderson OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc),
1191b6d69fceSRichard Henderson OUTOP(INDEX_op_brcond, TCGOutOpBrcond, outop_brcond),
11920dd07ee1SRichard Henderson OUTOP(INDEX_op_bswap16, TCGOutOpBswap, outop_bswap16),
11937498d882SRichard Henderson OUTOP(INDEX_op_bswap32, TCGOutOpBswap, outop_bswap32),
11945a5bb0a5SRichard Henderson OUTOP(INDEX_op_clz, TCGOutOpBinary, outop_clz),
119597218ae9SRichard Henderson OUTOP(INDEX_op_ctpop, TCGOutOpUnary, outop_ctpop),
1196c96447d8SRichard Henderson OUTOP(INDEX_op_ctz, TCGOutOpBinary, outop_ctz),
11974d137ff8SRichard Henderson OUTOP(INDEX_op_deposit, TCGOutOpDeposit, outop_deposit),
1198b2c514f9SRichard Henderson OUTOP(INDEX_op_divs, TCGOutOpBinary, outop_divs),
1199961b80aeSRichard Henderson OUTOP(INDEX_op_divu, TCGOutOpBinary, outop_divu),
1200ee1805b9SRichard Henderson OUTOP(INDEX_op_divs2, TCGOutOpDivRem, outop_divs2),
12018109598bSRichard Henderson OUTOP(INDEX_op_divu2, TCGOutOpDivRem, outop_divu2),
12025c0968a7SRichard Henderson OUTOP(INDEX_op_eqv, TCGOutOpBinary, outop_eqv),
120307d5d502SRichard Henderson OUTOP(INDEX_op_extract, TCGOutOpExtract, outop_extract),
120461d6a876SRichard Henderson OUTOP(INDEX_op_extract2, TCGOutOpExtract2, outop_extract2),
1205e996804dSRichard Henderson OUTOP(INDEX_op_ld8u, TCGOutOpLoad, outop_ld8u),
1206e996804dSRichard Henderson OUTOP(INDEX_op_ld8s, TCGOutOpLoad, outop_ld8s),
1207e996804dSRichard Henderson OUTOP(INDEX_op_ld16u, TCGOutOpLoad, outop_ld16u),
1208e996804dSRichard Henderson OUTOP(INDEX_op_ld16s, TCGOutOpLoad, outop_ld16s),
1209e996804dSRichard Henderson OUTOP(INDEX_op_ld, TCGOutOpLoad, outop_ld),
1210ea46c4bcSRichard Henderson OUTOP(INDEX_op_movcond, TCGOutOpMovcond, outop_movcond),
1211d2c3ecadSRichard Henderson OUTOP(INDEX_op_mul, TCGOutOpBinary, outop_mul),
1212bfe96480SRichard Henderson OUTOP(INDEX_op_muls2, TCGOutOpMul2, outop_muls2),
1213c742824dSRichard Henderson OUTOP(INDEX_op_mulsh, TCGOutOpBinary, outop_mulsh),
1214d776198cSRichard Henderson OUTOP(INDEX_op_mulu2, TCGOutOpMul2, outop_mulu2),
1215aa28c9efSRichard Henderson OUTOP(INDEX_op_muluh, TCGOutOpBinary, outop_muluh),
121659379a45SRichard Henderson OUTOP(INDEX_op_nand, TCGOutOpBinary, outop_nand),
121769713587SRichard Henderson OUTOP(INDEX_op_neg, TCGOutOpUnary, outop_neg),
1218a363e1e1SRichard Henderson OUTOP(INDEX_op_negsetcond, TCGOutOpSetcond, outop_negsetcond),
12193a8c4e9eSRichard Henderson OUTOP(INDEX_op_nor, TCGOutOpBinary, outop_nor),
12205c62d377SRichard Henderson OUTOP(INDEX_op_not, TCGOutOpUnary, outop_not),
122149bd7514SRichard Henderson OUTOP(INDEX_op_or, TCGOutOpBinary, outop_or),
12226aba25ebSRichard Henderson OUTOP(INDEX_op_orc, TCGOutOpBinary, outop_orc),
12233bedb9d3SRichard Henderson OUTOP(INDEX_op_qemu_ld, TCGOutOpQemuLdSt, outop_qemu_ld),
12243bedb9d3SRichard Henderson OUTOP(INDEX_op_qemu_ld2, TCGOutOpQemuLdSt2, outop_qemu_ld2),
122586fe5c25SRichard Henderson OUTOP(INDEX_op_qemu_st, TCGOutOpQemuLdSt, outop_qemu_st),
122686fe5c25SRichard Henderson OUTOP(INDEX_op_qemu_st2, TCGOutOpQemuLdSt2, outop_qemu_st2),
12279a6bc184SRichard Henderson OUTOP(INDEX_op_rems, TCGOutOpBinary, outop_rems),
1228cd9acd20SRichard Henderson OUTOP(INDEX_op_remu, TCGOutOpBinary, outop_remu),
1229005a87e1SRichard Henderson OUTOP(INDEX_op_rotl, TCGOutOpBinary, outop_rotl),
1230005a87e1SRichard Henderson OUTOP(INDEX_op_rotr, TCGOutOpBinary, outop_rotr),
12313949f365SRichard Henderson OUTOP(INDEX_op_sar, TCGOutOpBinary, outop_sar),
1232a363e1e1SRichard Henderson OUTOP(INDEX_op_setcond, TCGOutOpSetcond, outop_setcond),
1233fa361eefSRichard Henderson OUTOP(INDEX_op_sextract, TCGOutOpExtract, outop_sextract),
12346ca59451SRichard Henderson OUTOP(INDEX_op_shl, TCGOutOpBinary, outop_shl),
123574dbd36fSRichard Henderson OUTOP(INDEX_op_shr, TCGOutOpBinary, outop_shr),
1236a28f151dSRichard Henderson OUTOP(INDEX_op_st, TCGOutOpStore, outop_st),
1237a28f151dSRichard Henderson OUTOP(INDEX_op_st8, TCGOutOpStore, outop_st8),
1238a28f151dSRichard Henderson OUTOP(INDEX_op_st16, TCGOutOpStore, outop_st16),
123960f34f55SRichard Henderson OUTOP(INDEX_op_sub, TCGOutOpSubtract, outop_sub),
1240ee603152SRichard Henderson OUTOP(INDEX_op_subbi, TCGOutOpAddSubCarry, outop_subbi),
1241ee603152SRichard Henderson OUTOP(INDEX_op_subbio, TCGOutOpAddSubCarry, outop_subbio),
1242ee603152SRichard Henderson OUTOP(INDEX_op_subbo, TCGOutOpAddSubCarry, outop_subbo),
1243ee603152SRichard Henderson /* subb1o is implemented with set_borrow + subbio */
1244ee603152SRichard Henderson OUTOP(INDEX_op_subb1o, TCGOutOpAddSubCarry, outop_subbio),
1245fffd3dc9SRichard Henderson OUTOP(INDEX_op_xor, TCGOutOpBinary, outop_xor),
1246f408df58SRichard Henderson
1247fee03fddSRichard Henderson [INDEX_op_goto_ptr] = &outop_goto_ptr,
1248fee03fddSRichard Henderson
1249f408df58SRichard Henderson #if TCG_TARGET_REG_BITS == 32
1250f408df58SRichard Henderson OUTOP(INDEX_op_brcond2_i32, TCGOutOpBrcond2, outop_brcond2),
1251e579c717SRichard Henderson OUTOP(INDEX_op_setcond2_i32, TCGOutOpSetcond2, outop_setcond2),
1252613b571cSRichard Henderson #else
12533ad5d4ccSRichard Henderson OUTOP(INDEX_op_bswap64, TCGOutOpUnary, outop_bswap64),
1254b7b7347fSRichard Henderson OUTOP(INDEX_op_ext_i32_i64, TCGOutOpUnary, outop_exts_i32_i64),
1255c1ad25deSRichard Henderson OUTOP(INDEX_op_extu_i32_i64, TCGOutOpUnary, outop_extu_i32_i64),
12561e6fec9dSRichard Henderson OUTOP(INDEX_op_extrl_i64_i32, TCGOutOpUnary, outop_extrl_i64_i32),
1257b3b13976SRichard Henderson OUTOP(INDEX_op_extrh_i64_i32, TCGOutOpUnary, outop_extrh_i64_i32),
1258e996804dSRichard Henderson OUTOP(INDEX_op_ld32u, TCGOutOpLoad, outop_ld32u),
1259e996804dSRichard Henderson OUTOP(INDEX_op_ld32s, TCGOutOpLoad, outop_ld32s),
1260a28f151dSRichard Henderson OUTOP(INDEX_op_st32, TCGOutOpStore, outop_st),
1261f408df58SRichard Henderson #endif
12625500bd9eSRichard Henderson };
12635500bd9eSRichard Henderson
1264662cdbcfSRichard Henderson #undef OUTOP
1265662cdbcfSRichard Henderson
1266e8feb96fSEmilio G. Cota /*
12673468b59eSEmilio G. Cota * All TCG threads except the parent (i.e. the one that called tcg_context_init
12683468b59eSEmilio G. Cota * and registered the target's TCG globals) must register with this function
12693468b59eSEmilio G. Cota * before initiating translation.
12703468b59eSEmilio G. Cota *
12713468b59eSEmilio G. Cota * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation
12723468b59eSEmilio G. Cota * of tcg_region_init() for the reasoning behind this.
12733468b59eSEmilio G. Cota *
12747893e42dSPhilippe Mathieu-Daudé * In system-mode each caller registers its context in tcg_ctxs[]. Note that in
12757893e42dSPhilippe Mathieu-Daudé * system-mode tcg_ctxs[] does not track tcg_ctx_init, since the initial context
12763468b59eSEmilio G. Cota * is not used anymore for translation once this function is called.
12773468b59eSEmilio G. Cota *
12787893e42dSPhilippe Mathieu-Daudé * Not tracking tcg_init_ctx in tcg_ctxs[] in system-mode keeps code that
12797893e42dSPhilippe Mathieu-Daudé * iterates over the array (e.g. tcg_code_size() the same for both system/user
12807893e42dSPhilippe Mathieu-Daudé * modes.
12813468b59eSEmilio G. Cota */
12823468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
tcg_register_thread(void)12833468b59eSEmilio G. Cota void tcg_register_thread(void)
12843468b59eSEmilio G. Cota {
12853468b59eSEmilio G. Cota tcg_ctx = &tcg_init_ctx;
12863468b59eSEmilio G. Cota }
12873468b59eSEmilio G. Cota #else
tcg_register_thread(void)12883468b59eSEmilio G. Cota void tcg_register_thread(void)
12893468b59eSEmilio G. Cota {
12903468b59eSEmilio G. Cota TCGContext *s = g_malloc(sizeof(*s));
12913468b59eSEmilio G. Cota unsigned int i, n;
12923468b59eSEmilio G. Cota
12933468b59eSEmilio G. Cota *s = tcg_init_ctx;
12943468b59eSEmilio G. Cota
12953468b59eSEmilio G. Cota /* Relink mem_base. */
12963468b59eSEmilio G. Cota for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) {
12973468b59eSEmilio G. Cota if (tcg_init_ctx.temps[i].mem_base) {
12983468b59eSEmilio G. Cota ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps;
12993468b59eSEmilio G. Cota tcg_debug_assert(b >= 0 && b < n);
13003468b59eSEmilio G. Cota s->temps[i].mem_base = &s->temps[b];
13013468b59eSEmilio G. Cota }
13023468b59eSEmilio G. Cota }
13033468b59eSEmilio G. Cota
13043468b59eSEmilio G. Cota /* Claim an entry in tcg_ctxs */
13050e2d61cfSRichard Henderson n = qatomic_fetch_inc(&tcg_cur_ctxs);
13060e2d61cfSRichard Henderson g_assert(n < tcg_max_ctxs);
1307d73415a3SStefan Hajnoczi qatomic_set(&tcg_ctxs[n], s);
13083468b59eSEmilio G. Cota
130938b47b19SEmilio G. Cota if (n > 0) {
1310bf042e8eSRichard Henderson tcg_region_initial_alloc(s);
131138b47b19SEmilio G. Cota }
131238b47b19SEmilio G. Cota
13133468b59eSEmilio G. Cota tcg_ctx = s;
13143468b59eSEmilio G. Cota }
13153468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */
13163468b59eSEmilio G. Cota
1317c896fe29Sbellard /* pool based memory allocation */
tcg_malloc_internal(TCGContext * s,int size)1318c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size)
1319c896fe29Sbellard {
1320c896fe29Sbellard TCGPool *p;
1321c896fe29Sbellard int pool_size;
1322c896fe29Sbellard
1323c896fe29Sbellard if (size > TCG_POOL_CHUNK_SIZE) {
1324c896fe29Sbellard /* big malloc: insert a new pool (XXX: could optimize) */
13257267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + size);
1326c896fe29Sbellard p->size = size;
13274055299eSKirill Batuzov p->next = s->pool_first_large;
13284055299eSKirill Batuzov s->pool_first_large = p;
13294055299eSKirill Batuzov return p->data;
1330c896fe29Sbellard } else {
1331c896fe29Sbellard p = s->pool_current;
1332c896fe29Sbellard if (!p) {
1333c896fe29Sbellard p = s->pool_first;
1334c896fe29Sbellard if (!p)
1335c896fe29Sbellard goto new_pool;
1336c896fe29Sbellard } else {
1337c896fe29Sbellard if (!p->next) {
1338c896fe29Sbellard new_pool:
1339c896fe29Sbellard pool_size = TCG_POOL_CHUNK_SIZE;
13407267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + pool_size);
1341c896fe29Sbellard p->size = pool_size;
1342c896fe29Sbellard p->next = NULL;
1343a813e36fSRichard Henderson if (s->pool_current) {
1344c896fe29Sbellard s->pool_current->next = p;
1345a813e36fSRichard Henderson } else {
1346c896fe29Sbellard s->pool_first = p;
1347a813e36fSRichard Henderson }
1348c896fe29Sbellard } else {
1349c896fe29Sbellard p = p->next;
1350c896fe29Sbellard }
1351c896fe29Sbellard }
1352c896fe29Sbellard }
1353c896fe29Sbellard s->pool_current = p;
1354c896fe29Sbellard s->pool_cur = p->data + size;
1355c896fe29Sbellard s->pool_end = p->data + p->size;
1356c896fe29Sbellard return p->data;
1357c896fe29Sbellard }
1358c896fe29Sbellard
tcg_pool_reset(TCGContext * s)1359c896fe29Sbellard void tcg_pool_reset(TCGContext *s)
1360c896fe29Sbellard {
13614055299eSKirill Batuzov TCGPool *p, *t;
13624055299eSKirill Batuzov for (p = s->pool_first_large; p; p = t) {
13634055299eSKirill Batuzov t = p->next;
13644055299eSKirill Batuzov g_free(p);
13654055299eSKirill Batuzov }
13664055299eSKirill Batuzov s->pool_first_large = NULL;
1367c896fe29Sbellard s->pool_cur = s->pool_end = NULL;
1368c896fe29Sbellard s->pool_current = NULL;
1369c896fe29Sbellard }
1370c896fe29Sbellard
13718429a1caSRichard Henderson /*
13728429a1caSRichard Henderson * Create TCGHelperInfo structures for "tcg/tcg-ldst.h" functions,
13738429a1caSRichard Henderson * akin to what "exec/helper-tcg.h" does with DEF_HELPER_FLAGS_N.
13748429a1caSRichard Henderson * We only use these for layout in tcg_out_ld_helper_ret and
13758429a1caSRichard Henderson * tcg_out_st_helper_args, and share them between several of
13768429a1caSRichard Henderson * the helpers, with the end result that it's easier to build manually.
13778429a1caSRichard Henderson */
13788429a1caSRichard Henderson
13798429a1caSRichard Henderson #if TCG_TARGET_REG_BITS == 32
13808429a1caSRichard Henderson # define dh_typecode_ttl dh_typecode_i32
13818429a1caSRichard Henderson #else
13828429a1caSRichard Henderson # define dh_typecode_ttl dh_typecode_i64
13838429a1caSRichard Henderson #endif
13848429a1caSRichard Henderson
13858429a1caSRichard Henderson static TCGHelperInfo info_helper_ld32_mmu = {
13868429a1caSRichard Henderson .flags = TCG_CALL_NO_WG,
13878429a1caSRichard Henderson .typemask = dh_typemask(ttl, 0) /* return tcg_target_ulong */
13888429a1caSRichard Henderson | dh_typemask(env, 1)
138924e46e6cSRichard Henderson | dh_typemask(i64, 2) /* uint64_t addr */
13908429a1caSRichard Henderson | dh_typemask(i32, 3) /* unsigned oi */
13918429a1caSRichard Henderson | dh_typemask(ptr, 4) /* uintptr_t ra */
13928429a1caSRichard Henderson };
13938429a1caSRichard Henderson
13948429a1caSRichard Henderson static TCGHelperInfo info_helper_ld64_mmu = {
13958429a1caSRichard Henderson .flags = TCG_CALL_NO_WG,
13968429a1caSRichard Henderson .typemask = dh_typemask(i64, 0) /* return uint64_t */
13978429a1caSRichard Henderson | dh_typemask(env, 1)
139824e46e6cSRichard Henderson | dh_typemask(i64, 2) /* uint64_t addr */
13998429a1caSRichard Henderson | dh_typemask(i32, 3) /* unsigned oi */
14008429a1caSRichard Henderson | dh_typemask(ptr, 4) /* uintptr_t ra */
14018429a1caSRichard Henderson };
14028429a1caSRichard Henderson
1403ebebea53SRichard Henderson static TCGHelperInfo info_helper_ld128_mmu = {
1404ebebea53SRichard Henderson .flags = TCG_CALL_NO_WG,
1405ebebea53SRichard Henderson .typemask = dh_typemask(i128, 0) /* return Int128 */
1406ebebea53SRichard Henderson | dh_typemask(env, 1)
140724e46e6cSRichard Henderson | dh_typemask(i64, 2) /* uint64_t addr */
1408ebebea53SRichard Henderson | dh_typemask(i32, 3) /* unsigned oi */
1409ebebea53SRichard Henderson | dh_typemask(ptr, 4) /* uintptr_t ra */
1410ebebea53SRichard Henderson };
1411ebebea53SRichard Henderson
14128429a1caSRichard Henderson static TCGHelperInfo info_helper_st32_mmu = {
14138429a1caSRichard Henderson .flags = TCG_CALL_NO_WG,
14148429a1caSRichard Henderson .typemask = dh_typemask(void, 0)
14158429a1caSRichard Henderson | dh_typemask(env, 1)
141624e46e6cSRichard Henderson | dh_typemask(i64, 2) /* uint64_t addr */
14178429a1caSRichard Henderson | dh_typemask(i32, 3) /* uint32_t data */
14188429a1caSRichard Henderson | dh_typemask(i32, 4) /* unsigned oi */
14198429a1caSRichard Henderson | dh_typemask(ptr, 5) /* uintptr_t ra */
14208429a1caSRichard Henderson };
14218429a1caSRichard Henderson
14228429a1caSRichard Henderson static TCGHelperInfo info_helper_st64_mmu = {
14238429a1caSRichard Henderson .flags = TCG_CALL_NO_WG,
14248429a1caSRichard Henderson .typemask = dh_typemask(void, 0)
14258429a1caSRichard Henderson | dh_typemask(env, 1)
142624e46e6cSRichard Henderson | dh_typemask(i64, 2) /* uint64_t addr */
14278429a1caSRichard Henderson | dh_typemask(i64, 3) /* uint64_t data */
14288429a1caSRichard Henderson | dh_typemask(i32, 4) /* unsigned oi */
14298429a1caSRichard Henderson | dh_typemask(ptr, 5) /* uintptr_t ra */
14308429a1caSRichard Henderson };
14318429a1caSRichard Henderson
1432ebebea53SRichard Henderson static TCGHelperInfo info_helper_st128_mmu = {
1433ebebea53SRichard Henderson .flags = TCG_CALL_NO_WG,
1434ebebea53SRichard Henderson .typemask = dh_typemask(void, 0)
1435ebebea53SRichard Henderson | dh_typemask(env, 1)
143624e46e6cSRichard Henderson | dh_typemask(i64, 2) /* uint64_t addr */
1437ebebea53SRichard Henderson | dh_typemask(i128, 3) /* Int128 data */
1438ebebea53SRichard Henderson | dh_typemask(i32, 4) /* unsigned oi */
1439ebebea53SRichard Henderson | dh_typemask(ptr, 5) /* uintptr_t ra */
1440ebebea53SRichard Henderson };
1441ebebea53SRichard Henderson
144222f15579SRichard Henderson #ifdef CONFIG_TCG_INTERPRETER
typecode_to_ffi(int argmask)1443c6ef8c7bSPhilippe Mathieu-Daudé static ffi_type *typecode_to_ffi(int argmask)
1444c6ef8c7bSPhilippe Mathieu-Daudé {
1445e9709e17SRichard Henderson /*
1446e9709e17SRichard Henderson * libffi does not support __int128_t, so we have forced Int128
1447e9709e17SRichard Henderson * to use the structure definition instead of the builtin type.
1448e9709e17SRichard Henderson */
1449e9709e17SRichard Henderson static ffi_type *ffi_type_i128_elements[3] = {
1450e9709e17SRichard Henderson &ffi_type_uint64,
1451e9709e17SRichard Henderson &ffi_type_uint64,
1452e9709e17SRichard Henderson NULL
1453e9709e17SRichard Henderson };
1454e9709e17SRichard Henderson static ffi_type ffi_type_i128 = {
1455e9709e17SRichard Henderson .size = 16,
1456e9709e17SRichard Henderson .alignment = __alignof__(Int128),
1457e9709e17SRichard Henderson .type = FFI_TYPE_STRUCT,
1458e9709e17SRichard Henderson .elements = ffi_type_i128_elements,
1459e9709e17SRichard Henderson };
1460e9709e17SRichard Henderson
1461c6ef8c7bSPhilippe Mathieu-Daudé switch (argmask) {
1462c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_void:
1463c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_void;
1464c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_i32:
1465c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_uint32;
1466c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_s32:
1467c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_sint32;
1468c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_i64:
1469c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_uint64;
1470c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_s64:
1471c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_sint64;
1472c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_ptr:
1473c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_pointer;
1474e9709e17SRichard Henderson case dh_typecode_i128:
1475e9709e17SRichard Henderson return &ffi_type_i128;
1476c6ef8c7bSPhilippe Mathieu-Daudé }
1477c6ef8c7bSPhilippe Mathieu-Daudé g_assert_not_reached();
1478c6ef8c7bSPhilippe Mathieu-Daudé }
14790c22e176SPhilippe Mathieu-Daudé
init_ffi_layout(TCGHelperInfo * info)1480d53106c9SRichard Henderson static ffi_cif *init_ffi_layout(TCGHelperInfo *info)
14810c22e176SPhilippe Mathieu-Daudé {
1482f9c4bb80SRichard Henderson unsigned typemask = info->typemask;
14830c22e176SPhilippe Mathieu-Daudé struct {
14840c22e176SPhilippe Mathieu-Daudé ffi_cif cif;
14850c22e176SPhilippe Mathieu-Daudé ffi_type *args[];
14860c22e176SPhilippe Mathieu-Daudé } *ca;
14870c22e176SPhilippe Mathieu-Daudé ffi_status status;
14880c22e176SPhilippe Mathieu-Daudé int nargs;
14890c22e176SPhilippe Mathieu-Daudé
14900c22e176SPhilippe Mathieu-Daudé /* Ignoring the return type, find the last non-zero field. */
14910c22e176SPhilippe Mathieu-Daudé nargs = 32 - clz32(typemask >> 3);
14920c22e176SPhilippe Mathieu-Daudé nargs = DIV_ROUND_UP(nargs, 3);
1493e9709e17SRichard Henderson assert(nargs <= MAX_CALL_IARGS);
14940c22e176SPhilippe Mathieu-Daudé
14950c22e176SPhilippe Mathieu-Daudé ca = g_malloc0(sizeof(*ca) + nargs * sizeof(ffi_type *));
14960c22e176SPhilippe Mathieu-Daudé ca->cif.rtype = typecode_to_ffi(typemask & 7);
14970c22e176SPhilippe Mathieu-Daudé ca->cif.nargs = nargs;
14980c22e176SPhilippe Mathieu-Daudé
14990c22e176SPhilippe Mathieu-Daudé if (nargs != 0) {
15000c22e176SPhilippe Mathieu-Daudé ca->cif.arg_types = ca->args;
15010c22e176SPhilippe Mathieu-Daudé for (int j = 0; j < nargs; ++j) {
15020c22e176SPhilippe Mathieu-Daudé int typecode = extract32(typemask, (j + 1) * 3, 3);
15030c22e176SPhilippe Mathieu-Daudé ca->args[j] = typecode_to_ffi(typecode);
15040c22e176SPhilippe Mathieu-Daudé }
15050c22e176SPhilippe Mathieu-Daudé }
15060c22e176SPhilippe Mathieu-Daudé
15070c22e176SPhilippe Mathieu-Daudé status = ffi_prep_cif(&ca->cif, FFI_DEFAULT_ABI, nargs,
15080c22e176SPhilippe Mathieu-Daudé ca->cif.rtype, ca->cif.arg_types);
15090c22e176SPhilippe Mathieu-Daudé assert(status == FFI_OK);
15100c22e176SPhilippe Mathieu-Daudé
1511d53106c9SRichard Henderson return &ca->cif;
15120c22e176SPhilippe Mathieu-Daudé }
1513f9c4bb80SRichard Henderson
1514d53106c9SRichard Henderson #define HELPER_INFO_INIT(I) (&(I)->cif)
1515d53106c9SRichard Henderson #define HELPER_INFO_INIT_VAL(I) init_ffi_layout(I)
1516d53106c9SRichard Henderson #else
1517d53106c9SRichard Henderson #define HELPER_INFO_INIT(I) (&(I)->init)
1518d53106c9SRichard Henderson #define HELPER_INFO_INIT_VAL(I) 1
15190c22e176SPhilippe Mathieu-Daudé #endif /* CONFIG_TCG_INTERPRETER */
152022f15579SRichard Henderson
arg_slot_reg_p(unsigned arg_slot)1521338b61e9SRichard Henderson static inline bool arg_slot_reg_p(unsigned arg_slot)
1522338b61e9SRichard Henderson {
1523338b61e9SRichard Henderson /*
1524338b61e9SRichard Henderson * Split the sizeof away from the comparison to avoid Werror from
1525338b61e9SRichard Henderson * "unsigned < 0 is always false", when iarg_regs is empty.
1526338b61e9SRichard Henderson */
1527338b61e9SRichard Henderson unsigned nreg = ARRAY_SIZE(tcg_target_call_iarg_regs);
1528338b61e9SRichard Henderson return arg_slot < nreg;
1529338b61e9SRichard Henderson }
1530338b61e9SRichard Henderson
arg_slot_stk_ofs(unsigned arg_slot)1531d78e4a4fSRichard Henderson static inline int arg_slot_stk_ofs(unsigned arg_slot)
1532d78e4a4fSRichard Henderson {
1533d78e4a4fSRichard Henderson unsigned max = TCG_STATIC_CALL_ARGS_SIZE / sizeof(tcg_target_long);
1534d78e4a4fSRichard Henderson unsigned stk_slot = arg_slot - ARRAY_SIZE(tcg_target_call_iarg_regs);
1535d78e4a4fSRichard Henderson
1536d78e4a4fSRichard Henderson tcg_debug_assert(stk_slot < max);
1537d78e4a4fSRichard Henderson return TCG_TARGET_CALL_STACK_OFFSET + stk_slot * sizeof(tcg_target_long);
1538d78e4a4fSRichard Henderson }
1539d78e4a4fSRichard Henderson
154039004a71SRichard Henderson typedef struct TCGCumulativeArgs {
154139004a71SRichard Henderson int arg_idx; /* tcg_gen_callN args[] */
154239004a71SRichard Henderson int info_in_idx; /* TCGHelperInfo in[] */
154339004a71SRichard Henderson int arg_slot; /* regs+stack slot */
154439004a71SRichard Henderson int ref_slot; /* stack slots for references */
154539004a71SRichard Henderson } TCGCumulativeArgs;
154639004a71SRichard Henderson
layout_arg_even(TCGCumulativeArgs * cum)154739004a71SRichard Henderson static void layout_arg_even(TCGCumulativeArgs *cum)
154839004a71SRichard Henderson {
154939004a71SRichard Henderson cum->arg_slot += cum->arg_slot & 1;
155039004a71SRichard Henderson }
155139004a71SRichard Henderson
layout_arg_1(TCGCumulativeArgs * cum,TCGHelperInfo * info,TCGCallArgumentKind kind)155239004a71SRichard Henderson static void layout_arg_1(TCGCumulativeArgs *cum, TCGHelperInfo *info,
155339004a71SRichard Henderson TCGCallArgumentKind kind)
155439004a71SRichard Henderson {
155539004a71SRichard Henderson TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx];
155639004a71SRichard Henderson
155739004a71SRichard Henderson *loc = (TCGCallArgumentLoc){
155839004a71SRichard Henderson .kind = kind,
155939004a71SRichard Henderson .arg_idx = cum->arg_idx,
156039004a71SRichard Henderson .arg_slot = cum->arg_slot,
156139004a71SRichard Henderson };
156239004a71SRichard Henderson cum->info_in_idx++;
156339004a71SRichard Henderson cum->arg_slot++;
156439004a71SRichard Henderson }
156539004a71SRichard Henderson
layout_arg_normal_n(TCGCumulativeArgs * cum,TCGHelperInfo * info,int n)156639004a71SRichard Henderson static void layout_arg_normal_n(TCGCumulativeArgs *cum,
156739004a71SRichard Henderson TCGHelperInfo *info, int n)
156839004a71SRichard Henderson {
156939004a71SRichard Henderson TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx];
157039004a71SRichard Henderson
157139004a71SRichard Henderson for (int i = 0; i < n; ++i) {
157239004a71SRichard Henderson /* Layout all using the same arg_idx, adjusting the subindex. */
157339004a71SRichard Henderson loc[i] = (TCGCallArgumentLoc){
157439004a71SRichard Henderson .kind = TCG_CALL_ARG_NORMAL,
157539004a71SRichard Henderson .arg_idx = cum->arg_idx,
157639004a71SRichard Henderson .tmp_subindex = i,
157739004a71SRichard Henderson .arg_slot = cum->arg_slot + i,
157839004a71SRichard Henderson };
157939004a71SRichard Henderson }
158039004a71SRichard Henderson cum->info_in_idx += n;
158139004a71SRichard Henderson cum->arg_slot += n;
158239004a71SRichard Henderson }
158339004a71SRichard Henderson
layout_arg_by_ref(TCGCumulativeArgs * cum,TCGHelperInfo * info)1584313bdea8SRichard Henderson static void layout_arg_by_ref(TCGCumulativeArgs *cum, TCGHelperInfo *info)
1585313bdea8SRichard Henderson {
1586313bdea8SRichard Henderson TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx];
1587313bdea8SRichard Henderson int n = 128 / TCG_TARGET_REG_BITS;
1588313bdea8SRichard Henderson
1589313bdea8SRichard Henderson /* The first subindex carries the pointer. */
1590313bdea8SRichard Henderson layout_arg_1(cum, info, TCG_CALL_ARG_BY_REF);
1591313bdea8SRichard Henderson
1592313bdea8SRichard Henderson /*
1593313bdea8SRichard Henderson * The callee is allowed to clobber memory associated with
1594313bdea8SRichard Henderson * structure pass by-reference. Therefore we must make copies.
1595313bdea8SRichard Henderson * Allocate space from "ref_slot", which will be adjusted to
1596313bdea8SRichard Henderson * follow the parameters on the stack.
1597313bdea8SRichard Henderson */
1598313bdea8SRichard Henderson loc[0].ref_slot = cum->ref_slot;
1599313bdea8SRichard Henderson
1600313bdea8SRichard Henderson /*
1601313bdea8SRichard Henderson * Subsequent words also go into the reference slot, but
1602313bdea8SRichard Henderson * do not accumulate into the regular arguments.
1603313bdea8SRichard Henderson */
1604313bdea8SRichard Henderson for (int i = 1; i < n; ++i) {
1605313bdea8SRichard Henderson loc[i] = (TCGCallArgumentLoc){
1606313bdea8SRichard Henderson .kind = TCG_CALL_ARG_BY_REF_N,
1607313bdea8SRichard Henderson .arg_idx = cum->arg_idx,
1608313bdea8SRichard Henderson .tmp_subindex = i,
1609313bdea8SRichard Henderson .ref_slot = cum->ref_slot + i,
1610313bdea8SRichard Henderson };
1611313bdea8SRichard Henderson }
1612e18ed26cSRichard Henderson cum->info_in_idx += n - 1; /* i=0 accounted for in layout_arg_1 */
1613313bdea8SRichard Henderson cum->ref_slot += n;
1614313bdea8SRichard Henderson }
1615313bdea8SRichard Henderson
init_call_layout(TCGHelperInfo * info)161639004a71SRichard Henderson static void init_call_layout(TCGHelperInfo *info)
161739004a71SRichard Henderson {
161839004a71SRichard Henderson int max_reg_slots = ARRAY_SIZE(tcg_target_call_iarg_regs);
161939004a71SRichard Henderson int max_stk_slots = TCG_STATIC_CALL_ARGS_SIZE / sizeof(tcg_target_long);
162039004a71SRichard Henderson unsigned typemask = info->typemask;
162139004a71SRichard Henderson unsigned typecode;
162239004a71SRichard Henderson TCGCumulativeArgs cum = { };
162339004a71SRichard Henderson
162439004a71SRichard Henderson /*
162539004a71SRichard Henderson * Parse and place any function return value.
162639004a71SRichard Henderson */
162739004a71SRichard Henderson typecode = typemask & 7;
162839004a71SRichard Henderson switch (typecode) {
162939004a71SRichard Henderson case dh_typecode_void:
163039004a71SRichard Henderson info->nr_out = 0;
163139004a71SRichard Henderson break;
163239004a71SRichard Henderson case dh_typecode_i32:
163339004a71SRichard Henderson case dh_typecode_s32:
163439004a71SRichard Henderson case dh_typecode_ptr:
163539004a71SRichard Henderson info->nr_out = 1;
163639004a71SRichard Henderson info->out_kind = TCG_CALL_RET_NORMAL;
163739004a71SRichard Henderson break;
163839004a71SRichard Henderson case dh_typecode_i64:
163939004a71SRichard Henderson case dh_typecode_s64:
164039004a71SRichard Henderson info->nr_out = 64 / TCG_TARGET_REG_BITS;
164139004a71SRichard Henderson info->out_kind = TCG_CALL_RET_NORMAL;
16425e3d0c19SRichard Henderson /* Query the last register now to trigger any assert early. */
16435e3d0c19SRichard Henderson tcg_target_call_oarg_reg(info->out_kind, info->nr_out - 1);
1644466d3759SRichard Henderson break;
1645466d3759SRichard Henderson case dh_typecode_i128:
1646466d3759SRichard Henderson info->nr_out = 128 / TCG_TARGET_REG_BITS;
16475427a9a7SRichard Henderson info->out_kind = TCG_TARGET_CALL_RET_I128;
16485427a9a7SRichard Henderson switch (TCG_TARGET_CALL_RET_I128) {
1649466d3759SRichard Henderson case TCG_CALL_RET_NORMAL:
16505e3d0c19SRichard Henderson /* Query the last register now to trigger any assert early. */
16515e3d0c19SRichard Henderson tcg_target_call_oarg_reg(info->out_kind, info->nr_out - 1);
1652466d3759SRichard Henderson break;
1653c6556aa0SRichard Henderson case TCG_CALL_RET_BY_VEC:
1654c6556aa0SRichard Henderson /* Query the single register now to trigger any assert early. */
1655c6556aa0SRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0);
1656c6556aa0SRichard Henderson break;
1657313bdea8SRichard Henderson case TCG_CALL_RET_BY_REF:
1658313bdea8SRichard Henderson /*
1659313bdea8SRichard Henderson * Allocate the first argument to the output.
1660313bdea8SRichard Henderson * We don't need to store this anywhere, just make it
1661313bdea8SRichard Henderson * unavailable for use in the input loop below.
1662313bdea8SRichard Henderson */
1663313bdea8SRichard Henderson cum.arg_slot = 1;
1664313bdea8SRichard Henderson break;
1665466d3759SRichard Henderson default:
1666466d3759SRichard Henderson qemu_build_not_reached();
1667466d3759SRichard Henderson }
166839004a71SRichard Henderson break;
166939004a71SRichard Henderson default:
167039004a71SRichard Henderson g_assert_not_reached();
167139004a71SRichard Henderson }
167239004a71SRichard Henderson
167339004a71SRichard Henderson /*
167439004a71SRichard Henderson * Parse and place function arguments.
167539004a71SRichard Henderson */
167639004a71SRichard Henderson for (typemask >>= 3; typemask; typemask >>= 3, cum.arg_idx++) {
167739004a71SRichard Henderson TCGCallArgumentKind kind;
167839004a71SRichard Henderson TCGType type;
167939004a71SRichard Henderson
168039004a71SRichard Henderson typecode = typemask & 7;
168139004a71SRichard Henderson switch (typecode) {
168239004a71SRichard Henderson case dh_typecode_i32:
168339004a71SRichard Henderson case dh_typecode_s32:
168439004a71SRichard Henderson type = TCG_TYPE_I32;
168539004a71SRichard Henderson break;
168639004a71SRichard Henderson case dh_typecode_i64:
168739004a71SRichard Henderson case dh_typecode_s64:
168839004a71SRichard Henderson type = TCG_TYPE_I64;
168939004a71SRichard Henderson break;
169039004a71SRichard Henderson case dh_typecode_ptr:
169139004a71SRichard Henderson type = TCG_TYPE_PTR;
169239004a71SRichard Henderson break;
1693466d3759SRichard Henderson case dh_typecode_i128:
1694466d3759SRichard Henderson type = TCG_TYPE_I128;
1695466d3759SRichard Henderson break;
169639004a71SRichard Henderson default:
169739004a71SRichard Henderson g_assert_not_reached();
169839004a71SRichard Henderson }
169939004a71SRichard Henderson
170039004a71SRichard Henderson switch (type) {
170139004a71SRichard Henderson case TCG_TYPE_I32:
170239004a71SRichard Henderson switch (TCG_TARGET_CALL_ARG_I32) {
170339004a71SRichard Henderson case TCG_CALL_ARG_EVEN:
170439004a71SRichard Henderson layout_arg_even(&cum);
170539004a71SRichard Henderson /* fall through */
170639004a71SRichard Henderson case TCG_CALL_ARG_NORMAL:
170739004a71SRichard Henderson layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL);
170839004a71SRichard Henderson break;
170939004a71SRichard Henderson case TCG_CALL_ARG_EXTEND:
171039004a71SRichard Henderson kind = TCG_CALL_ARG_EXTEND_U + (typecode & 1);
171139004a71SRichard Henderson layout_arg_1(&cum, info, kind);
171239004a71SRichard Henderson break;
171339004a71SRichard Henderson default:
171439004a71SRichard Henderson qemu_build_not_reached();
171539004a71SRichard Henderson }
171639004a71SRichard Henderson break;
171739004a71SRichard Henderson
171839004a71SRichard Henderson case TCG_TYPE_I64:
171939004a71SRichard Henderson switch (TCG_TARGET_CALL_ARG_I64) {
172039004a71SRichard Henderson case TCG_CALL_ARG_EVEN:
172139004a71SRichard Henderson layout_arg_even(&cum);
172239004a71SRichard Henderson /* fall through */
172339004a71SRichard Henderson case TCG_CALL_ARG_NORMAL:
172439004a71SRichard Henderson if (TCG_TARGET_REG_BITS == 32) {
172539004a71SRichard Henderson layout_arg_normal_n(&cum, info, 2);
172639004a71SRichard Henderson } else {
172739004a71SRichard Henderson layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL);
172839004a71SRichard Henderson }
172939004a71SRichard Henderson break;
173039004a71SRichard Henderson default:
173139004a71SRichard Henderson qemu_build_not_reached();
173239004a71SRichard Henderson }
173339004a71SRichard Henderson break;
173439004a71SRichard Henderson
1735466d3759SRichard Henderson case TCG_TYPE_I128:
17365427a9a7SRichard Henderson switch (TCG_TARGET_CALL_ARG_I128) {
1737466d3759SRichard Henderson case TCG_CALL_ARG_EVEN:
1738466d3759SRichard Henderson layout_arg_even(&cum);
1739466d3759SRichard Henderson /* fall through */
1740466d3759SRichard Henderson case TCG_CALL_ARG_NORMAL:
1741466d3759SRichard Henderson layout_arg_normal_n(&cum, info, 128 / TCG_TARGET_REG_BITS);
1742466d3759SRichard Henderson break;
1743313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF:
1744313bdea8SRichard Henderson layout_arg_by_ref(&cum, info);
1745313bdea8SRichard Henderson break;
1746466d3759SRichard Henderson default:
1747466d3759SRichard Henderson qemu_build_not_reached();
1748466d3759SRichard Henderson }
1749466d3759SRichard Henderson break;
1750466d3759SRichard Henderson
175139004a71SRichard Henderson default:
175239004a71SRichard Henderson g_assert_not_reached();
175339004a71SRichard Henderson }
175439004a71SRichard Henderson }
175539004a71SRichard Henderson info->nr_in = cum.info_in_idx;
175639004a71SRichard Henderson
175739004a71SRichard Henderson /* Validate that we didn't overrun the input array. */
175839004a71SRichard Henderson assert(cum.info_in_idx <= ARRAY_SIZE(info->in));
175939004a71SRichard Henderson /* Validate the backend has enough argument space. */
176039004a71SRichard Henderson assert(cum.arg_slot <= max_reg_slots + max_stk_slots);
1761313bdea8SRichard Henderson
1762313bdea8SRichard Henderson /*
1763313bdea8SRichard Henderson * Relocate the "ref_slot" area to the end of the parameters.
1764313bdea8SRichard Henderson * Minimizing this stack offset helps code size for x86,
1765313bdea8SRichard Henderson * which has a signed 8-bit offset encoding.
1766313bdea8SRichard Henderson */
1767313bdea8SRichard Henderson if (cum.ref_slot != 0) {
1768313bdea8SRichard Henderson int ref_base = 0;
1769313bdea8SRichard Henderson
1770313bdea8SRichard Henderson if (cum.arg_slot > max_reg_slots) {
1771313bdea8SRichard Henderson int align = __alignof(Int128) / sizeof(tcg_target_long);
1772313bdea8SRichard Henderson
1773313bdea8SRichard Henderson ref_base = cum.arg_slot - max_reg_slots;
1774313bdea8SRichard Henderson if (align > 1) {
1775313bdea8SRichard Henderson ref_base = ROUND_UP(ref_base, align);
1776313bdea8SRichard Henderson }
1777313bdea8SRichard Henderson }
1778313bdea8SRichard Henderson assert(ref_base + cum.ref_slot <= max_stk_slots);
1779d78e4a4fSRichard Henderson ref_base += max_reg_slots;
1780313bdea8SRichard Henderson
1781313bdea8SRichard Henderson if (ref_base != 0) {
1782313bdea8SRichard Henderson for (int i = cum.info_in_idx - 1; i >= 0; --i) {
1783313bdea8SRichard Henderson TCGCallArgumentLoc *loc = &info->in[i];
1784313bdea8SRichard Henderson switch (loc->kind) {
1785313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF:
1786313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF_N:
1787313bdea8SRichard Henderson loc->ref_slot += ref_base;
1788313bdea8SRichard Henderson break;
1789313bdea8SRichard Henderson default:
1790313bdea8SRichard Henderson break;
1791313bdea8SRichard Henderson }
1792313bdea8SRichard Henderson }
1793313bdea8SRichard Henderson }
1794313bdea8SRichard Henderson }
179539004a71SRichard Henderson }
179639004a71SRichard Henderson
179791478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)];
1798501fb3daSRichard Henderson static void process_constraint_sets(void);
17991c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
18001c2adb95SRichard Henderson TCGReg reg, const char *name);
180191478cefSRichard Henderson
tcg_context_init(unsigned max_threads)1802a9d107faSRichard Henderson static void tcg_context_init(unsigned max_threads)
1803c896fe29Sbellard {
1804a76aabd3SRichard Henderson TCGContext *s = &tcg_init_ctx;
18053e80824eSRichard Henderson int n, i;
18061c2adb95SRichard Henderson TCGTemp *ts;
1807c896fe29Sbellard
1808c896fe29Sbellard memset(s, 0, sizeof(*s));
1809c896fe29Sbellard s->nb_globals = 0;
1810c896fe29Sbellard
18118429a1caSRichard Henderson init_call_layout(&info_helper_ld32_mmu);
18128429a1caSRichard Henderson init_call_layout(&info_helper_ld64_mmu);
1813ebebea53SRichard Henderson init_call_layout(&info_helper_ld128_mmu);
18148429a1caSRichard Henderson init_call_layout(&info_helper_st32_mmu);
18158429a1caSRichard Henderson init_call_layout(&info_helper_st64_mmu);
1816ebebea53SRichard Henderson init_call_layout(&info_helper_st128_mmu);
18178429a1caSRichard Henderson
1818c896fe29Sbellard tcg_target_init(s);
1819501fb3daSRichard Henderson process_constraint_sets();
182091478cefSRichard Henderson
182191478cefSRichard Henderson /* Reverse the order of the saved registers, assuming they're all at
182291478cefSRichard Henderson the start of tcg_target_reg_alloc_order. */
182391478cefSRichard Henderson for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) {
182491478cefSRichard Henderson int r = tcg_target_reg_alloc_order[n];
182591478cefSRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) {
182691478cefSRichard Henderson break;
182791478cefSRichard Henderson }
182891478cefSRichard Henderson }
182991478cefSRichard Henderson for (i = 0; i < n; ++i) {
183091478cefSRichard Henderson indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i];
183191478cefSRichard Henderson }
183291478cefSRichard Henderson for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) {
183391478cefSRichard Henderson indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i];
183491478cefSRichard Henderson }
1835b1311c4aSEmilio G. Cota
1836b1311c4aSEmilio G. Cota tcg_ctx = s;
18373468b59eSEmilio G. Cota /*
18383468b59eSEmilio G. Cota * In user-mode we simply share the init context among threads, since we
18393468b59eSEmilio G. Cota * use a single region. See the documentation tcg_region_init() for the
18403468b59eSEmilio G. Cota * reasoning behind this.
1841a9d107faSRichard Henderson * In system-mode we will have at most max_threads TCG threads.
18423468b59eSEmilio G. Cota */
18433468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
1844df2cce29SEmilio G. Cota tcg_ctxs = &tcg_ctx;
18450e2d61cfSRichard Henderson tcg_cur_ctxs = 1;
18460e2d61cfSRichard Henderson tcg_max_ctxs = 1;
18473468b59eSEmilio G. Cota #else
1848a9d107faSRichard Henderson tcg_max_ctxs = max_threads;
1849a9d107faSRichard Henderson tcg_ctxs = g_new0(TCGContext *, max_threads);
18503468b59eSEmilio G. Cota #endif
18511c2adb95SRichard Henderson
18521c2adb95SRichard Henderson tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0));
18531c2adb95SRichard Henderson ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env");
1854ad75a51eSRichard Henderson tcg_env = temp_tcgv_ptr(ts);
18559002ec79SRichard Henderson }
1856b03cce8eSbellard
tcg_init(size_t tb_size,int splitwx,unsigned max_threads)1857a9d107faSRichard Henderson void tcg_init(size_t tb_size, int splitwx, unsigned max_threads)
1858a76aabd3SRichard Henderson {
1859a9d107faSRichard Henderson tcg_context_init(max_threads);
1860a9d107faSRichard Henderson tcg_region_init(tb_size, splitwx, max_threads);
1861a76aabd3SRichard Henderson }
1862a76aabd3SRichard Henderson
18636e3b2bfdSEmilio G. Cota /*
18646e3b2bfdSEmilio G. Cota * Allocate TBs right before their corresponding translated code, making
18656e3b2bfdSEmilio G. Cota * sure that TBs and code are on different cache lines.
18666e3b2bfdSEmilio G. Cota */
tcg_tb_alloc(TCGContext * s)18676e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s)
18686e3b2bfdSEmilio G. Cota {
18696e3b2bfdSEmilio G. Cota uintptr_t align = qemu_icache_linesize;
18706e3b2bfdSEmilio G. Cota TranslationBlock *tb;
18716e3b2bfdSEmilio G. Cota void *next;
18726e3b2bfdSEmilio G. Cota
1873e8feb96fSEmilio G. Cota retry:
18746e3b2bfdSEmilio G. Cota tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align);
18756e3b2bfdSEmilio G. Cota next = (void *)ROUND_UP((uintptr_t)(tb + 1), align);
18766e3b2bfdSEmilio G. Cota
18776e3b2bfdSEmilio G. Cota if (unlikely(next > s->code_gen_highwater)) {
1878e8feb96fSEmilio G. Cota if (tcg_region_alloc(s)) {
18796e3b2bfdSEmilio G. Cota return NULL;
18806e3b2bfdSEmilio G. Cota }
1881e8feb96fSEmilio G. Cota goto retry;
1882e8feb96fSEmilio G. Cota }
1883d73415a3SStefan Hajnoczi qatomic_set(&s->code_gen_ptr, next);
18846e3b2bfdSEmilio G. Cota return tb;
18856e3b2bfdSEmilio G. Cota }
18866e3b2bfdSEmilio G. Cota
tcg_prologue_init(void)1887935f75aeSRichard Henderson void tcg_prologue_init(void)
18889002ec79SRichard Henderson {
1889935f75aeSRichard Henderson TCGContext *s = tcg_ctx;
1890b0a0794aSRichard Henderson size_t prologue_size;
18918163b749SRichard Henderson
1892b0a0794aSRichard Henderson s->code_ptr = s->code_gen_ptr;
1893b0a0794aSRichard Henderson s->code_buf = s->code_gen_ptr;
18945b38ee31SRichard Henderson s->data_gen_ptr = NULL;
1895b91ccb31SRichard Henderson
1896b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
1897b0a0794aSRichard Henderson tcg_qemu_tb_exec = (tcg_prologue_fn *)tcg_splitwx_to_rx(s->code_ptr);
1898b91ccb31SRichard Henderson #endif
18998163b749SRichard Henderson
19005b38ee31SRichard Henderson s->pool_labels = NULL;
19015b38ee31SRichard Henderson
1902653b87ebSRoman Bolshakov qemu_thread_jit_write();
19038163b749SRichard Henderson /* Generate the prologue. */
1904b03cce8eSbellard tcg_target_qemu_prologue(s);
19055b38ee31SRichard Henderson
19065b38ee31SRichard Henderson /* Allow the prologue to put e.g. guest_base into a pool entry. */
19075b38ee31SRichard Henderson {
19081768987bSRichard Henderson int result = tcg_out_pool_finalize(s);
19091768987bSRichard Henderson tcg_debug_assert(result == 0);
19105b38ee31SRichard Henderson }
19115b38ee31SRichard Henderson
1912b0a0794aSRichard Henderson prologue_size = tcg_current_code_size(s);
19135584e2dbSIlya Leoshkevich perf_report_prologue(s->code_gen_ptr, prologue_size);
1914b0a0794aSRichard Henderson
1915df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
1916b0a0794aSRichard Henderson flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf),
1917b0a0794aSRichard Henderson (uintptr_t)s->code_buf, prologue_size);
1918df5d2b16SRichard Henderson #endif
19198163b749SRichard Henderson
1920d6b64b2bSRichard Henderson if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) {
1921c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock();
192278b54858SRichard Henderson if (logfile) {
192378b54858SRichard Henderson fprintf(logfile, "PROLOGUE: [size=%zu]\n", prologue_size);
19245b38ee31SRichard Henderson if (s->data_gen_ptr) {
1925b0a0794aSRichard Henderson size_t code_size = s->data_gen_ptr - s->code_gen_ptr;
19265b38ee31SRichard Henderson size_t data_size = prologue_size - code_size;
19275b38ee31SRichard Henderson size_t i;
19285b38ee31SRichard Henderson
192978b54858SRichard Henderson disas(logfile, s->code_gen_ptr, code_size);
19305b38ee31SRichard Henderson
19315b38ee31SRichard Henderson for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) {
19325b38ee31SRichard Henderson if (sizeof(tcg_target_ulong) == 8) {
193378b54858SRichard Henderson fprintf(logfile,
193478b54858SRichard Henderson "0x%08" PRIxPTR ": .quad 0x%016" PRIx64 "\n",
19355b38ee31SRichard Henderson (uintptr_t)s->data_gen_ptr + i,
19365b38ee31SRichard Henderson *(uint64_t *)(s->data_gen_ptr + i));
19375b38ee31SRichard Henderson } else {
193878b54858SRichard Henderson fprintf(logfile,
193978b54858SRichard Henderson "0x%08" PRIxPTR ": .long 0x%08x\n",
19405b38ee31SRichard Henderson (uintptr_t)s->data_gen_ptr + i,
19415b38ee31SRichard Henderson *(uint32_t *)(s->data_gen_ptr + i));
19425b38ee31SRichard Henderson }
19435b38ee31SRichard Henderson }
19445b38ee31SRichard Henderson } else {
194578b54858SRichard Henderson disas(logfile, s->code_gen_ptr, prologue_size);
19465b38ee31SRichard Henderson }
194778b54858SRichard Henderson fprintf(logfile, "\n");
1948fc59d2d8SRobert Foley qemu_log_unlock(logfile);
1949d6b64b2bSRichard Henderson }
195078b54858SRichard Henderson }
1951cedbcb01SEmilio G. Cota
19526eea0434SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
19536eea0434SRichard Henderson /*
19546eea0434SRichard Henderson * Assert that goto_ptr is implemented completely, setting an epilogue.
19556eea0434SRichard Henderson * For tci, we use NULL as the signal to return from the interpreter,
19566eea0434SRichard Henderson * so skip this check.
19576eea0434SRichard Henderson */
19588b5c2b62SRichard Henderson tcg_debug_assert(tcg_code_gen_epilogue != NULL);
19596eea0434SRichard Henderson #endif
1960d1c74ab3SRichard Henderson
1961d1c74ab3SRichard Henderson tcg_region_prologue_set(s);
1962c896fe29Sbellard }
1963c896fe29Sbellard
tcg_func_start(TCGContext * s)1964c896fe29Sbellard void tcg_func_start(TCGContext *s)
1965c896fe29Sbellard {
1966c896fe29Sbellard tcg_pool_reset(s);
1967c896fe29Sbellard s->nb_temps = s->nb_globals;
19680ec9eabcSRichard Henderson
19690ec9eabcSRichard Henderson /* No temps have been previously allocated for size or locality. */
197004e006abSRichard Henderson tcg_temp_ebb_reset_freed(s);
19710ec9eabcSRichard Henderson
1972c0522136SRichard Henderson /* No constant temps have been previously allocated. */
1973c0522136SRichard Henderson for (int i = 0; i < TCG_TYPE_COUNT; ++i) {
1974c0522136SRichard Henderson if (s->const_table[i]) {
1975c0522136SRichard Henderson g_hash_table_remove_all(s->const_table[i]);
1976c0522136SRichard Henderson }
1977c0522136SRichard Henderson }
1978c0522136SRichard Henderson
1979abebf925SRichard Henderson s->nb_ops = 0;
1980c896fe29Sbellard s->nb_labels = 0;
1981c896fe29Sbellard s->current_frame_offset = s->frame_start;
1982c896fe29Sbellard
19830a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG
19840a209d4bSRichard Henderson s->goto_tb_issue_mask = 0;
19850a209d4bSRichard Henderson #endif
19860a209d4bSRichard Henderson
198715fa08f8SRichard Henderson QTAILQ_INIT(&s->ops);
198815fa08f8SRichard Henderson QTAILQ_INIT(&s->free_ops);
198907843f75SRichard Henderson s->emit_before_op = NULL;
1990bef16ab4SRichard Henderson QSIMPLEQ_INIT(&s->labels);
19914baf3978SRichard Henderson
1992a0ecb8e4SRichard Henderson tcg_debug_assert(s->addr_type <= TCG_TYPE_REG);
1993c896fe29Sbellard }
1994c896fe29Sbellard
tcg_temp_alloc(TCGContext * s)1995ae30e866SRichard Henderson static TCGTemp *tcg_temp_alloc(TCGContext *s)
19967ca4b752SRichard Henderson {
19977ca4b752SRichard Henderson int n = s->nb_temps++;
1998ae30e866SRichard Henderson
1999ae30e866SRichard Henderson if (n >= TCG_MAX_TEMPS) {
2000db6b7d0cSRichard Henderson tcg_raise_tb_overflow(s);
2001ae30e866SRichard Henderson }
20027ca4b752SRichard Henderson return memset(&s->temps[n], 0, sizeof(TCGTemp));
20037ca4b752SRichard Henderson }
20047ca4b752SRichard Henderson
tcg_global_alloc(TCGContext * s)2005ae30e866SRichard Henderson static TCGTemp *tcg_global_alloc(TCGContext *s)
20067ca4b752SRichard Henderson {
2007fa477d25SRichard Henderson TCGTemp *ts;
2008fa477d25SRichard Henderson
20097ca4b752SRichard Henderson tcg_debug_assert(s->nb_globals == s->nb_temps);
2010ae30e866SRichard Henderson tcg_debug_assert(s->nb_globals < TCG_MAX_TEMPS);
20117ca4b752SRichard Henderson s->nb_globals++;
2012fa477d25SRichard Henderson ts = tcg_temp_alloc(s);
2013ee17db83SRichard Henderson ts->kind = TEMP_GLOBAL;
2014fa477d25SRichard Henderson
2015fa477d25SRichard Henderson return ts;
2016c896fe29Sbellard }
2017c896fe29Sbellard
tcg_global_reg_new_internal(TCGContext * s,TCGType type,TCGReg reg,const char * name)2018085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
2019b6638662SRichard Henderson TCGReg reg, const char *name)
2020c896fe29Sbellard {
2021c896fe29Sbellard TCGTemp *ts;
2022c896fe29Sbellard
20231a057554SRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 64 || type == TCG_TYPE_I32);
20247ca4b752SRichard Henderson
20257ca4b752SRichard Henderson ts = tcg_global_alloc(s);
2026c896fe29Sbellard ts->base_type = type;
2027c896fe29Sbellard ts->type = type;
2028ee17db83SRichard Henderson ts->kind = TEMP_FIXED;
2029c896fe29Sbellard ts->reg = reg;
2030c896fe29Sbellard ts->name = name;
2031c896fe29Sbellard tcg_regset_set_reg(s->reserved_regs, reg);
20327ca4b752SRichard Henderson
2033085272b3SRichard Henderson return ts;
2034a7812ae4Spbrook }
2035a7812ae4Spbrook
tcg_set_frame(TCGContext * s,TCGReg reg,intptr_t start,intptr_t size)2036b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size)
2037a7812ae4Spbrook {
2038b3a62939SRichard Henderson s->frame_start = start;
2039b3a62939SRichard Henderson s->frame_end = start + size;
2040085272b3SRichard Henderson s->frame_temp
2041085272b3SRichard Henderson = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame");
2042b3a62939SRichard Henderson }
2043a7812ae4Spbrook
tcg_global_mem_new_internal(TCGv_ptr base,intptr_t offset,const char * name,TCGType type)20444643f3e0SRichard Henderson static TCGTemp *tcg_global_mem_new_internal(TCGv_ptr base, intptr_t offset,
20454643f3e0SRichard Henderson const char *name, TCGType type)
2046c896fe29Sbellard {
2047b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx;
2048dc41aa7dSRichard Henderson TCGTemp *base_ts = tcgv_ptr_temp(base);
20497ca4b752SRichard Henderson TCGTemp *ts = tcg_global_alloc(s);
2050aef85402SRichard Henderson int indirect_reg = 0;
2051c896fe29Sbellard
2052c0522136SRichard Henderson switch (base_ts->kind) {
2053c0522136SRichard Henderson case TEMP_FIXED:
2054c0522136SRichard Henderson break;
2055c0522136SRichard Henderson case TEMP_GLOBAL:
20565a18407fSRichard Henderson /* We do not support double-indirect registers. */
20575a18407fSRichard Henderson tcg_debug_assert(!base_ts->indirect_reg);
2058b3915dbbSRichard Henderson base_ts->indirect_base = 1;
20595a18407fSRichard Henderson s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64
20605a18407fSRichard Henderson ? 2 : 1);
20615a18407fSRichard Henderson indirect_reg = 1;
2062c0522136SRichard Henderson break;
2063c0522136SRichard Henderson default:
2064c0522136SRichard Henderson g_assert_not_reached();
2065b3915dbbSRichard Henderson }
2066b3915dbbSRichard Henderson
20677ca4b752SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
20687ca4b752SRichard Henderson TCGTemp *ts2 = tcg_global_alloc(s);
2069c896fe29Sbellard char buf[64];
20707ca4b752SRichard Henderson
20717ca4b752SRichard Henderson ts->base_type = TCG_TYPE_I64;
2072c896fe29Sbellard ts->type = TCG_TYPE_I32;
2073b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg;
2074c896fe29Sbellard ts->mem_allocated = 1;
2075b3a62939SRichard Henderson ts->mem_base = base_ts;
2076aef85402SRichard Henderson ts->mem_offset = offset;
2077c896fe29Sbellard pstrcpy(buf, sizeof(buf), name);
2078c896fe29Sbellard pstrcat(buf, sizeof(buf), "_0");
2079c896fe29Sbellard ts->name = strdup(buf);
2080c896fe29Sbellard
20817ca4b752SRichard Henderson tcg_debug_assert(ts2 == ts + 1);
20827ca4b752SRichard Henderson ts2->base_type = TCG_TYPE_I64;
20837ca4b752SRichard Henderson ts2->type = TCG_TYPE_I32;
2084b3915dbbSRichard Henderson ts2->indirect_reg = indirect_reg;
20857ca4b752SRichard Henderson ts2->mem_allocated = 1;
20867ca4b752SRichard Henderson ts2->mem_base = base_ts;
2087aef85402SRichard Henderson ts2->mem_offset = offset + 4;
2088fac87bd2SRichard Henderson ts2->temp_subindex = 1;
2089c896fe29Sbellard pstrcpy(buf, sizeof(buf), name);
2090c896fe29Sbellard pstrcat(buf, sizeof(buf), "_1");
2091120c1084SRichard Henderson ts2->name = strdup(buf);
20927ca4b752SRichard Henderson } else {
2093c896fe29Sbellard ts->base_type = type;
2094c896fe29Sbellard ts->type = type;
2095b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg;
2096c896fe29Sbellard ts->mem_allocated = 1;
2097b3a62939SRichard Henderson ts->mem_base = base_ts;
2098c896fe29Sbellard ts->mem_offset = offset;
2099c896fe29Sbellard ts->name = name;
2100c896fe29Sbellard }
2101085272b3SRichard Henderson return ts;
2102c896fe29Sbellard }
2103c896fe29Sbellard
tcg_global_mem_new_i32(TCGv_ptr reg,intptr_t off,const char * name)21044643f3e0SRichard Henderson TCGv_i32 tcg_global_mem_new_i32(TCGv_ptr reg, intptr_t off, const char *name)
21054643f3e0SRichard Henderson {
21064643f3e0SRichard Henderson TCGTemp *ts = tcg_global_mem_new_internal(reg, off, name, TCG_TYPE_I32);
21074643f3e0SRichard Henderson return temp_tcgv_i32(ts);
21084643f3e0SRichard Henderson }
21094643f3e0SRichard Henderson
tcg_global_mem_new_i64(TCGv_ptr reg,intptr_t off,const char * name)21104643f3e0SRichard Henderson TCGv_i64 tcg_global_mem_new_i64(TCGv_ptr reg, intptr_t off, const char *name)
21114643f3e0SRichard Henderson {
21124643f3e0SRichard Henderson TCGTemp *ts = tcg_global_mem_new_internal(reg, off, name, TCG_TYPE_I64);
21134643f3e0SRichard Henderson return temp_tcgv_i64(ts);
21144643f3e0SRichard Henderson }
21154643f3e0SRichard Henderson
tcg_global_mem_new_ptr(TCGv_ptr reg,intptr_t off,const char * name)21164643f3e0SRichard Henderson TCGv_ptr tcg_global_mem_new_ptr(TCGv_ptr reg, intptr_t off, const char *name)
21174643f3e0SRichard Henderson {
21184643f3e0SRichard Henderson TCGTemp *ts = tcg_global_mem_new_internal(reg, off, name, TCG_TYPE_PTR);
21194643f3e0SRichard Henderson return temp_tcgv_ptr(ts);
21204643f3e0SRichard Henderson }
21214643f3e0SRichard Henderson
tcg_temp_new_internal(TCGType type,TCGTempKind kind)2122fb04ab7dSRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, TCGTempKind kind)
2123c896fe29Sbellard {
2124b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx;
2125c896fe29Sbellard TCGTemp *ts;
2126e1c08b00SRichard Henderson int n;
2127c896fe29Sbellard
2128e1c08b00SRichard Henderson if (kind == TEMP_EBB) {
2129e1c08b00SRichard Henderson int idx = find_first_bit(s->free_temps[type].l, TCG_MAX_TEMPS);
2130e1c08b00SRichard Henderson
21310ec9eabcSRichard Henderson if (idx < TCG_MAX_TEMPS) {
21320ec9eabcSRichard Henderson /* There is already an available temp with the right type. */
2133e1c08b00SRichard Henderson clear_bit(idx, s->free_temps[type].l);
21340ec9eabcSRichard Henderson
2135e8996ee0Sbellard ts = &s->temps[idx];
2136e8996ee0Sbellard ts->temp_allocated = 1;
21377ca4b752SRichard Henderson tcg_debug_assert(ts->base_type == type);
2138ee17db83SRichard Henderson tcg_debug_assert(ts->kind == kind);
21392f2e911dSRichard Henderson return ts;
2140e1c08b00SRichard Henderson }
2141e8996ee0Sbellard } else {
2142e1c08b00SRichard Henderson tcg_debug_assert(kind == TEMP_TB);
2143e1c08b00SRichard Henderson }
214443eef72fSRichard Henderson
214543eef72fSRichard Henderson switch (type) {
214643eef72fSRichard Henderson case TCG_TYPE_I32:
214743eef72fSRichard Henderson case TCG_TYPE_V64:
214843eef72fSRichard Henderson case TCG_TYPE_V128:
214943eef72fSRichard Henderson case TCG_TYPE_V256:
215043eef72fSRichard Henderson n = 1;
215143eef72fSRichard Henderson break;
215243eef72fSRichard Henderson case TCG_TYPE_I64:
215343eef72fSRichard Henderson n = 64 / TCG_TARGET_REG_BITS;
215443eef72fSRichard Henderson break;
215543eef72fSRichard Henderson case TCG_TYPE_I128:
215643eef72fSRichard Henderson n = 128 / TCG_TARGET_REG_BITS;
215743eef72fSRichard Henderson break;
215843eef72fSRichard Henderson default:
215943eef72fSRichard Henderson g_assert_not_reached();
216043eef72fSRichard Henderson }
216143eef72fSRichard Henderson
21627ca4b752SRichard Henderson ts = tcg_temp_alloc(s);
216343eef72fSRichard Henderson ts->base_type = type;
216443eef72fSRichard Henderson ts->temp_allocated = 1;
216543eef72fSRichard Henderson ts->kind = kind;
216643eef72fSRichard Henderson
216743eef72fSRichard Henderson if (n == 1) {
216843eef72fSRichard Henderson ts->type = type;
216943eef72fSRichard Henderson } else {
217043eef72fSRichard Henderson ts->type = TCG_TYPE_REG;
217143eef72fSRichard Henderson
2172e1c08b00SRichard Henderson for (int i = 1; i < n; ++i) {
21737ca4b752SRichard Henderson TCGTemp *ts2 = tcg_temp_alloc(s);
21747ca4b752SRichard Henderson
217543eef72fSRichard Henderson tcg_debug_assert(ts2 == ts + i);
217643eef72fSRichard Henderson ts2->base_type = type;
217743eef72fSRichard Henderson ts2->type = TCG_TYPE_REG;
21787ca4b752SRichard Henderson ts2->temp_allocated = 1;
217943eef72fSRichard Henderson ts2->temp_subindex = i;
2180ee17db83SRichard Henderson ts2->kind = kind;
218143eef72fSRichard Henderson }
2182c896fe29Sbellard }
2183085272b3SRichard Henderson return ts;
2184c896fe29Sbellard }
2185c896fe29Sbellard
tcg_temp_new_i32(void)21864643f3e0SRichard Henderson TCGv_i32 tcg_temp_new_i32(void)
21874643f3e0SRichard Henderson {
21884643f3e0SRichard Henderson return temp_tcgv_i32(tcg_temp_new_internal(TCG_TYPE_I32, TEMP_TB));
21894643f3e0SRichard Henderson }
21904643f3e0SRichard Henderson
tcg_temp_ebb_new_i32(void)21914643f3e0SRichard Henderson TCGv_i32 tcg_temp_ebb_new_i32(void)
21924643f3e0SRichard Henderson {
21934643f3e0SRichard Henderson return temp_tcgv_i32(tcg_temp_new_internal(TCG_TYPE_I32, TEMP_EBB));
21944643f3e0SRichard Henderson }
21954643f3e0SRichard Henderson
tcg_temp_new_i64(void)21964643f3e0SRichard Henderson TCGv_i64 tcg_temp_new_i64(void)
21974643f3e0SRichard Henderson {
21984643f3e0SRichard Henderson return temp_tcgv_i64(tcg_temp_new_internal(TCG_TYPE_I64, TEMP_TB));
21994643f3e0SRichard Henderson }
22004643f3e0SRichard Henderson
tcg_temp_ebb_new_i64(void)22014643f3e0SRichard Henderson TCGv_i64 tcg_temp_ebb_new_i64(void)
22024643f3e0SRichard Henderson {
22034643f3e0SRichard Henderson return temp_tcgv_i64(tcg_temp_new_internal(TCG_TYPE_I64, TEMP_EBB));
22044643f3e0SRichard Henderson }
22054643f3e0SRichard Henderson
tcg_temp_new_ptr(void)22064643f3e0SRichard Henderson TCGv_ptr tcg_temp_new_ptr(void)
22074643f3e0SRichard Henderson {
22084643f3e0SRichard Henderson return temp_tcgv_ptr(tcg_temp_new_internal(TCG_TYPE_PTR, TEMP_TB));
22094643f3e0SRichard Henderson }
22104643f3e0SRichard Henderson
tcg_temp_ebb_new_ptr(void)22114643f3e0SRichard Henderson TCGv_ptr tcg_temp_ebb_new_ptr(void)
22124643f3e0SRichard Henderson {
22134643f3e0SRichard Henderson return temp_tcgv_ptr(tcg_temp_new_internal(TCG_TYPE_PTR, TEMP_EBB));
22144643f3e0SRichard Henderson }
22154643f3e0SRichard Henderson
tcg_temp_new_i128(void)22164643f3e0SRichard Henderson TCGv_i128 tcg_temp_new_i128(void)
22174643f3e0SRichard Henderson {
22184643f3e0SRichard Henderson return temp_tcgv_i128(tcg_temp_new_internal(TCG_TYPE_I128, TEMP_TB));
22194643f3e0SRichard Henderson }
22204643f3e0SRichard Henderson
tcg_temp_ebb_new_i128(void)22214643f3e0SRichard Henderson TCGv_i128 tcg_temp_ebb_new_i128(void)
22224643f3e0SRichard Henderson {
22234643f3e0SRichard Henderson return temp_tcgv_i128(tcg_temp_new_internal(TCG_TYPE_I128, TEMP_EBB));
22244643f3e0SRichard Henderson }
22254643f3e0SRichard Henderson
tcg_temp_new_vec(TCGType type)2226d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type)
2227d2fd745fSRichard Henderson {
2228d2fd745fSRichard Henderson TCGTemp *t;
2229d2fd745fSRichard Henderson
2230d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG
2231d2fd745fSRichard Henderson switch (type) {
2232d2fd745fSRichard Henderson case TCG_TYPE_V64:
2233d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v64);
2234d2fd745fSRichard Henderson break;
2235d2fd745fSRichard Henderson case TCG_TYPE_V128:
2236d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v128);
2237d2fd745fSRichard Henderson break;
2238d2fd745fSRichard Henderson case TCG_TYPE_V256:
2239d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v256);
2240d2fd745fSRichard Henderson break;
2241d2fd745fSRichard Henderson default:
2242d2fd745fSRichard Henderson g_assert_not_reached();
2243d2fd745fSRichard Henderson }
2244d2fd745fSRichard Henderson #endif
2245d2fd745fSRichard Henderson
2246bbf989bfSRichard Henderson t = tcg_temp_new_internal(type, TEMP_EBB);
2247d2fd745fSRichard Henderson return temp_tcgv_vec(t);
2248d2fd745fSRichard Henderson }
2249d2fd745fSRichard Henderson
2250d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp. */
tcg_temp_new_vec_matching(TCGv_vec match)2251d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match)
2252d2fd745fSRichard Henderson {
2253d2fd745fSRichard Henderson TCGTemp *t = tcgv_vec_temp(match);
2254d2fd745fSRichard Henderson
2255d2fd745fSRichard Henderson tcg_debug_assert(t->temp_allocated != 0);
2256d2fd745fSRichard Henderson
2257bbf989bfSRichard Henderson t = tcg_temp_new_internal(t->base_type, TEMP_EBB);
2258d2fd745fSRichard Henderson return temp_tcgv_vec(t);
2259d2fd745fSRichard Henderson }
2260d2fd745fSRichard Henderson
tcg_temp_free_internal(TCGTemp * ts)22615bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts)
2262c896fe29Sbellard {
2263b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx;
2264c896fe29Sbellard
2265c7482438SRichard Henderson switch (ts->kind) {
2266c7482438SRichard Henderson case TEMP_CONST:
2267f57c6915SRichard Henderson case TEMP_TB:
22682f2e911dSRichard Henderson /* Silently ignore free. */
2269c7482438SRichard Henderson break;
22702f2e911dSRichard Henderson case TEMP_EBB:
2271eabb7b91SAurelien Jarno tcg_debug_assert(ts->temp_allocated != 0);
2272e8996ee0Sbellard ts->temp_allocated = 0;
22732f2e911dSRichard Henderson set_bit(temp_idx(ts), s->free_temps[ts->base_type].l);
22742f2e911dSRichard Henderson break;
22752f2e911dSRichard Henderson default:
22762f2e911dSRichard Henderson /* It never made sense to free TEMP_FIXED or TEMP_GLOBAL. */
22772f2e911dSRichard Henderson g_assert_not_reached();
2278e1c08b00SRichard Henderson }
2279e8996ee0Sbellard }
2280e8996ee0Sbellard
tcg_temp_free_i32(TCGv_i32 arg)228158b79713SRichard Henderson void tcg_temp_free_i32(TCGv_i32 arg)
228258b79713SRichard Henderson {
228358b79713SRichard Henderson tcg_temp_free_internal(tcgv_i32_temp(arg));
228458b79713SRichard Henderson }
228558b79713SRichard Henderson
tcg_temp_free_i64(TCGv_i64 arg)228658b79713SRichard Henderson void tcg_temp_free_i64(TCGv_i64 arg)
228758b79713SRichard Henderson {
228858b79713SRichard Henderson tcg_temp_free_internal(tcgv_i64_temp(arg));
228958b79713SRichard Henderson }
229058b79713SRichard Henderson
tcg_temp_free_i128(TCGv_i128 arg)229158b79713SRichard Henderson void tcg_temp_free_i128(TCGv_i128 arg)
229258b79713SRichard Henderson {
229358b79713SRichard Henderson tcg_temp_free_internal(tcgv_i128_temp(arg));
229458b79713SRichard Henderson }
229558b79713SRichard Henderson
tcg_temp_free_ptr(TCGv_ptr arg)229658b79713SRichard Henderson void tcg_temp_free_ptr(TCGv_ptr arg)
229758b79713SRichard Henderson {
229858b79713SRichard Henderson tcg_temp_free_internal(tcgv_ptr_temp(arg));
229958b79713SRichard Henderson }
230058b79713SRichard Henderson
tcg_temp_free_vec(TCGv_vec arg)230158b79713SRichard Henderson void tcg_temp_free_vec(TCGv_vec arg)
230258b79713SRichard Henderson {
230358b79713SRichard Henderson tcg_temp_free_internal(tcgv_vec_temp(arg));
230458b79713SRichard Henderson }
230558b79713SRichard Henderson
tcg_constant_internal(TCGType type,int64_t val)2306c0522136SRichard Henderson TCGTemp *tcg_constant_internal(TCGType type, int64_t val)
2307c0522136SRichard Henderson {
2308c0522136SRichard Henderson TCGContext *s = tcg_ctx;
2309c0522136SRichard Henderson GHashTable *h = s->const_table[type];
2310c0522136SRichard Henderson TCGTemp *ts;
2311c0522136SRichard Henderson
2312c0522136SRichard Henderson if (h == NULL) {
2313c0522136SRichard Henderson h = g_hash_table_new(g_int64_hash, g_int64_equal);
2314c0522136SRichard Henderson s->const_table[type] = h;
2315c0522136SRichard Henderson }
2316c0522136SRichard Henderson
2317c0522136SRichard Henderson ts = g_hash_table_lookup(h, &val);
2318c0522136SRichard Henderson if (ts == NULL) {
2319aef85402SRichard Henderson int64_t *val_ptr;
2320aef85402SRichard Henderson
2321c0522136SRichard Henderson ts = tcg_temp_alloc(s);
2322c0522136SRichard Henderson
2323c0522136SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
2324c0522136SRichard Henderson TCGTemp *ts2 = tcg_temp_alloc(s);
2325c0522136SRichard Henderson
2326aef85402SRichard Henderson tcg_debug_assert(ts2 == ts + 1);
2327aef85402SRichard Henderson
2328c0522136SRichard Henderson ts->base_type = TCG_TYPE_I64;
2329c0522136SRichard Henderson ts->type = TCG_TYPE_I32;
2330c0522136SRichard Henderson ts->kind = TEMP_CONST;
2331c0522136SRichard Henderson ts->temp_allocated = 1;
2332c0522136SRichard Henderson
2333c0522136SRichard Henderson ts2->base_type = TCG_TYPE_I64;
2334c0522136SRichard Henderson ts2->type = TCG_TYPE_I32;
2335c0522136SRichard Henderson ts2->kind = TEMP_CONST;
2336c0522136SRichard Henderson ts2->temp_allocated = 1;
2337fac87bd2SRichard Henderson ts2->temp_subindex = 1;
2338aef85402SRichard Henderson
2339aef85402SRichard Henderson /*
2340aef85402SRichard Henderson * Retain the full value of the 64-bit constant in the low
2341aef85402SRichard Henderson * part, so that the hash table works. Actual uses will
2342aef85402SRichard Henderson * truncate the value to the low part.
2343aef85402SRichard Henderson */
2344aef85402SRichard Henderson ts[HOST_BIG_ENDIAN].val = val;
2345aef85402SRichard Henderson ts[!HOST_BIG_ENDIAN].val = val >> 32;
2346aef85402SRichard Henderson val_ptr = &ts[HOST_BIG_ENDIAN].val;
2347c0522136SRichard Henderson } else {
2348c0522136SRichard Henderson ts->base_type = type;
2349c0522136SRichard Henderson ts->type = type;
2350c0522136SRichard Henderson ts->kind = TEMP_CONST;
2351c0522136SRichard Henderson ts->temp_allocated = 1;
2352c0522136SRichard Henderson ts->val = val;
2353aef85402SRichard Henderson val_ptr = &ts->val;
2354c0522136SRichard Henderson }
2355aef85402SRichard Henderson g_hash_table_insert(h, val_ptr, ts);
2356c0522136SRichard Henderson }
2357c0522136SRichard Henderson
2358c0522136SRichard Henderson return ts;
2359c0522136SRichard Henderson }
2360c0522136SRichard Henderson
tcg_constant_i32(int32_t val)236116edaee7SRichard Henderson TCGv_i32 tcg_constant_i32(int32_t val)
236216edaee7SRichard Henderson {
236316edaee7SRichard Henderson return temp_tcgv_i32(tcg_constant_internal(TCG_TYPE_I32, val));
236416edaee7SRichard Henderson }
236516edaee7SRichard Henderson
tcg_constant_i64(int64_t val)236616edaee7SRichard Henderson TCGv_i64 tcg_constant_i64(int64_t val)
236716edaee7SRichard Henderson {
236816edaee7SRichard Henderson return temp_tcgv_i64(tcg_constant_internal(TCG_TYPE_I64, val));
236916edaee7SRichard Henderson }
237016edaee7SRichard Henderson
tcg_constant_vaddr(uintptr_t val)237121a75f79SPierrick Bouvier TCGv_vaddr tcg_constant_vaddr(uintptr_t val)
237221a75f79SPierrick Bouvier {
237321a75f79SPierrick Bouvier return temp_tcgv_vaddr(tcg_constant_internal(TCG_TYPE_PTR, val));
237421a75f79SPierrick Bouvier }
237521a75f79SPierrick Bouvier
tcg_constant_ptr_int(intptr_t val)237616edaee7SRichard Henderson TCGv_ptr tcg_constant_ptr_int(intptr_t val)
237716edaee7SRichard Henderson {
237816edaee7SRichard Henderson return temp_tcgv_ptr(tcg_constant_internal(TCG_TYPE_PTR, val));
237916edaee7SRichard Henderson }
238016edaee7SRichard Henderson
tcg_constant_vec(TCGType type,unsigned vece,int64_t val)2381c0522136SRichard Henderson TCGv_vec tcg_constant_vec(TCGType type, unsigned vece, int64_t val)
2382c0522136SRichard Henderson {
2383c0522136SRichard Henderson val = dup_const(vece, val);
2384c0522136SRichard Henderson return temp_tcgv_vec(tcg_constant_internal(type, val));
2385c0522136SRichard Henderson }
2386c0522136SRichard Henderson
tcg_constant_vec_matching(TCGv_vec match,unsigned vece,int64_t val)238788d4005bSRichard Henderson TCGv_vec tcg_constant_vec_matching(TCGv_vec match, unsigned vece, int64_t val)
238888d4005bSRichard Henderson {
238988d4005bSRichard Henderson TCGTemp *t = tcgv_vec_temp(match);
239088d4005bSRichard Henderson
239188d4005bSRichard Henderson tcg_debug_assert(t->temp_allocated != 0);
239288d4005bSRichard Henderson return tcg_constant_vec(t->base_type, vece, val);
239388d4005bSRichard Henderson }
239488d4005bSRichard Henderson
2395177f648fSRichard Henderson #ifdef CONFIG_DEBUG_TCG
temp_idx(TCGTemp * ts)2396177f648fSRichard Henderson size_t temp_idx(TCGTemp *ts)
2397177f648fSRichard Henderson {
2398177f648fSRichard Henderson ptrdiff_t n = ts - tcg_ctx->temps;
2399177f648fSRichard Henderson assert(n >= 0 && n < tcg_ctx->nb_temps);
2400177f648fSRichard Henderson return n;
2401177f648fSRichard Henderson }
2402177f648fSRichard Henderson
tcgv_i32_temp(TCGv_i32 v)2403177f648fSRichard Henderson TCGTemp *tcgv_i32_temp(TCGv_i32 v)
2404177f648fSRichard Henderson {
2405177f648fSRichard Henderson uintptr_t o = (uintptr_t)v - offsetof(TCGContext, temps);
2406177f648fSRichard Henderson
2407177f648fSRichard Henderson assert(o < sizeof(TCGTemp) * tcg_ctx->nb_temps);
2408177f648fSRichard Henderson assert(o % sizeof(TCGTemp) == 0);
2409177f648fSRichard Henderson
2410177f648fSRichard Henderson return (void *)tcg_ctx + (uintptr_t)v;
2411177f648fSRichard Henderson }
2412177f648fSRichard Henderson #endif /* CONFIG_DEBUG_TCG */
2413177f648fSRichard Henderson
2414771a5925SRichard Henderson /*
2415771a5925SRichard Henderson * Return true if OP may appear in the opcode stream with TYPE.
2416771a5925SRichard Henderson * Test the runtime variable that controls each opcode.
2417771a5925SRichard Henderson */
tcg_op_supported(TCGOpcode op,TCGType type,unsigned flags)2418771a5925SRichard Henderson bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags)
2419be0f34b5SRichard Henderson {
2420f44824ccSRichard Henderson bool has_type;
2421f44824ccSRichard Henderson
2422f44824ccSRichard Henderson switch (type) {
2423f44824ccSRichard Henderson case TCG_TYPE_I32:
2424f44824ccSRichard Henderson has_type = true;
2425f44824ccSRichard Henderson break;
2426f44824ccSRichard Henderson case TCG_TYPE_I64:
2427f44824ccSRichard Henderson has_type = TCG_TARGET_REG_BITS == 64;
2428f44824ccSRichard Henderson break;
2429f44824ccSRichard Henderson case TCG_TYPE_V64:
2430f44824ccSRichard Henderson has_type = TCG_TARGET_HAS_v64;
2431f44824ccSRichard Henderson break;
2432f44824ccSRichard Henderson case TCG_TYPE_V128:
2433f44824ccSRichard Henderson has_type = TCG_TARGET_HAS_v128;
2434f44824ccSRichard Henderson break;
2435f44824ccSRichard Henderson case TCG_TYPE_V256:
2436f44824ccSRichard Henderson has_type = TCG_TARGET_HAS_v256;
2437f44824ccSRichard Henderson break;
2438f44824ccSRichard Henderson default:
2439f44824ccSRichard Henderson has_type = false;
2440f44824ccSRichard Henderson break;
2441f44824ccSRichard Henderson }
2442d2fd745fSRichard Henderson
2443be0f34b5SRichard Henderson switch (op) {
2444be0f34b5SRichard Henderson case INDEX_op_discard:
2445be0f34b5SRichard Henderson case INDEX_op_set_label:
2446be0f34b5SRichard Henderson case INDEX_op_call:
2447be0f34b5SRichard Henderson case INDEX_op_br:
2448be0f34b5SRichard Henderson case INDEX_op_mb:
2449be0f34b5SRichard Henderson case INDEX_op_insn_start:
2450be0f34b5SRichard Henderson case INDEX_op_exit_tb:
2451be0f34b5SRichard Henderson case INDEX_op_goto_tb:
2452f4e01e30SRichard Henderson case INDEX_op_goto_ptr:
2453be0f34b5SRichard Henderson return true;
2454be0f34b5SRichard Henderson
2455aae2456aSRichard Henderson case INDEX_op_qemu_ld:
2456aae2456aSRichard Henderson case INDEX_op_qemu_st:
2457aae2456aSRichard Henderson tcg_debug_assert(type <= TCG_TYPE_REG);
2458aae2456aSRichard Henderson return true;
2459aae2456aSRichard Henderson
2460aae2456aSRichard Henderson case INDEX_op_qemu_ld2:
2461aae2456aSRichard Henderson case INDEX_op_qemu_st2:
2462aae2456aSRichard Henderson if (TCG_TARGET_REG_BITS == 32) {
2463aae2456aSRichard Henderson tcg_debug_assert(type == TCG_TYPE_I64);
2464aae2456aSRichard Henderson return true;
2465aae2456aSRichard Henderson }
2466aae2456aSRichard Henderson tcg_debug_assert(type == TCG_TYPE_I128);
24673bedb9d3SRichard Henderson goto do_lookup;
246812fde9bcSRichard Henderson
246979602f63SRichard Henderson case INDEX_op_add:
2470c3b920b3SRichard Henderson case INDEX_op_and:
2471b6d69fceSRichard Henderson case INDEX_op_brcond:
24724d137ff8SRichard Henderson case INDEX_op_deposit:
247307d5d502SRichard Henderson case INDEX_op_extract:
2474e996804dSRichard Henderson case INDEX_op_ld8u:
2475e996804dSRichard Henderson case INDEX_op_ld8s:
2476e996804dSRichard Henderson case INDEX_op_ld16u:
2477e996804dSRichard Henderson case INDEX_op_ld16s:
2478e996804dSRichard Henderson case INDEX_op_ld:
2479b5701261SRichard Henderson case INDEX_op_mov:
2480ea46c4bcSRichard Henderson case INDEX_op_movcond:
2481a363e1e1SRichard Henderson case INDEX_op_negsetcond:
248249bd7514SRichard Henderson case INDEX_op_or:
2483a363e1e1SRichard Henderson case INDEX_op_setcond:
2484fa361eefSRichard Henderson case INDEX_op_sextract:
2485a28f151dSRichard Henderson case INDEX_op_st8:
2486a28f151dSRichard Henderson case INDEX_op_st16:
2487a28f151dSRichard Henderson case INDEX_op_st:
2488fffd3dc9SRichard Henderson case INDEX_op_xor:
2489b5701261SRichard Henderson return has_type;
2490b5701261SRichard Henderson
2491be0f34b5SRichard Henderson case INDEX_op_brcond2_i32:
2492be0f34b5SRichard Henderson case INDEX_op_setcond2_i32:
2493be0f34b5SRichard Henderson return TCG_TARGET_REG_BITS == 32;
2494be0f34b5SRichard Henderson
2495e996804dSRichard Henderson case INDEX_op_ld32u:
2496e996804dSRichard Henderson case INDEX_op_ld32s:
2497a28f151dSRichard Henderson case INDEX_op_st32:
2498be0f34b5SRichard Henderson case INDEX_op_ext_i32_i64:
2499be0f34b5SRichard Henderson case INDEX_op_extu_i32_i64:
25001e6fec9dSRichard Henderson case INDEX_op_extrl_i64_i32:
2501b3b13976SRichard Henderson case INDEX_op_extrh_i64_i32:
2502be0f34b5SRichard Henderson return TCG_TARGET_REG_BITS == 64;
2503be0f34b5SRichard Henderson
2504d2fd745fSRichard Henderson case INDEX_op_mov_vec:
2505d2fd745fSRichard Henderson case INDEX_op_dup_vec:
250637ee55a0SRichard Henderson case INDEX_op_dupm_vec:
2507d2fd745fSRichard Henderson case INDEX_op_ld_vec:
2508d2fd745fSRichard Henderson case INDEX_op_st_vec:
2509d2fd745fSRichard Henderson case INDEX_op_add_vec:
2510d2fd745fSRichard Henderson case INDEX_op_sub_vec:
2511d2fd745fSRichard Henderson case INDEX_op_and_vec:
2512d2fd745fSRichard Henderson case INDEX_op_or_vec:
2513d2fd745fSRichard Henderson case INDEX_op_xor_vec:
2514212be173SRichard Henderson case INDEX_op_cmp_vec:
2515f44824ccSRichard Henderson return has_type;
2516d2fd745fSRichard Henderson case INDEX_op_dup2_vec:
2517f44824ccSRichard Henderson return has_type && TCG_TARGET_REG_BITS == 32;
2518d2fd745fSRichard Henderson case INDEX_op_not_vec:
2519f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_not_vec;
2520d2fd745fSRichard Henderson case INDEX_op_neg_vec:
2521f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_neg_vec;
2522bcefc902SRichard Henderson case INDEX_op_abs_vec:
2523f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_abs_vec;
2524d2fd745fSRichard Henderson case INDEX_op_andc_vec:
2525f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_andc_vec;
2526d2fd745fSRichard Henderson case INDEX_op_orc_vec:
2527f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_orc_vec;
2528ed523473SRichard Henderson case INDEX_op_nand_vec:
2529f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_nand_vec;
2530ed523473SRichard Henderson case INDEX_op_nor_vec:
2531f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_nor_vec;
2532ed523473SRichard Henderson case INDEX_op_eqv_vec:
2533f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_eqv_vec;
25343774030aSRichard Henderson case INDEX_op_mul_vec:
2535f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_mul_vec;
2536d0ec9796SRichard Henderson case INDEX_op_shli_vec:
2537d0ec9796SRichard Henderson case INDEX_op_shri_vec:
2538d0ec9796SRichard Henderson case INDEX_op_sari_vec:
2539f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_shi_vec;
2540d0ec9796SRichard Henderson case INDEX_op_shls_vec:
2541d0ec9796SRichard Henderson case INDEX_op_shrs_vec:
2542d0ec9796SRichard Henderson case INDEX_op_sars_vec:
2543f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_shs_vec;
2544d0ec9796SRichard Henderson case INDEX_op_shlv_vec:
2545d0ec9796SRichard Henderson case INDEX_op_shrv_vec:
2546d0ec9796SRichard Henderson case INDEX_op_sarv_vec:
2547f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_shv_vec;
2548b0f7e744SRichard Henderson case INDEX_op_rotli_vec:
2549f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_roti_vec;
255023850a74SRichard Henderson case INDEX_op_rotls_vec:
2551f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_rots_vec;
25525d0ceda9SRichard Henderson case INDEX_op_rotlv_vec:
25535d0ceda9SRichard Henderson case INDEX_op_rotrv_vec:
2554f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_rotv_vec;
25558afaf050SRichard Henderson case INDEX_op_ssadd_vec:
25568afaf050SRichard Henderson case INDEX_op_usadd_vec:
25578afaf050SRichard Henderson case INDEX_op_sssub_vec:
25588afaf050SRichard Henderson case INDEX_op_ussub_vec:
2559f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_sat_vec;
2560dd0a0fcdSRichard Henderson case INDEX_op_smin_vec:
2561dd0a0fcdSRichard Henderson case INDEX_op_umin_vec:
2562dd0a0fcdSRichard Henderson case INDEX_op_smax_vec:
2563dd0a0fcdSRichard Henderson case INDEX_op_umax_vec:
2564f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_minmax_vec;
256538dc1294SRichard Henderson case INDEX_op_bitsel_vec:
2566f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_bitsel_vec;
2567f75da298SRichard Henderson case INDEX_op_cmpsel_vec:
2568f44824ccSRichard Henderson return has_type && TCG_TARGET_HAS_cmpsel_vec;
2569d2fd745fSRichard Henderson
2570db432672SRichard Henderson default:
25715500bd9eSRichard Henderson if (op < INDEX_op_last_generic) {
25725500bd9eSRichard Henderson const TCGOutOp *outop;
25735500bd9eSRichard Henderson TCGConstraintSetIndex con_set;
25745500bd9eSRichard Henderson
25755500bd9eSRichard Henderson if (!has_type) {
25765500bd9eSRichard Henderson return false;
25775500bd9eSRichard Henderson }
25785500bd9eSRichard Henderson
25793bedb9d3SRichard Henderson do_lookup:
25805500bd9eSRichard Henderson outop = all_outop[op];
25815500bd9eSRichard Henderson tcg_debug_assert(outop != NULL);
25825500bd9eSRichard Henderson
25835500bd9eSRichard Henderson con_set = outop->static_constraint;
25845500bd9eSRichard Henderson if (con_set == C_Dynamic) {
25855500bd9eSRichard Henderson con_set = outop->dynamic_constraint(type, flags);
25865500bd9eSRichard Henderson }
25875500bd9eSRichard Henderson if (con_set >= 0) {
2588db432672SRichard Henderson return true;
2589be0f34b5SRichard Henderson }
25905500bd9eSRichard Henderson tcg_debug_assert(con_set == C_NotImplemented);
25915500bd9eSRichard Henderson return false;
25925500bd9eSRichard Henderson }
25935500bd9eSRichard Henderson tcg_debug_assert(op < NB_OPS);
25945500bd9eSRichard Henderson return true;
25955500bd9eSRichard Henderson
25965500bd9eSRichard Henderson case INDEX_op_last_generic:
25975500bd9eSRichard Henderson g_assert_not_reached();
25985500bd9eSRichard Henderson }
2599be0f34b5SRichard Henderson }
2600be0f34b5SRichard Henderson
tcg_op_deposit_valid(TCGType type,unsigned ofs,unsigned len)26010e4c6424SRichard Henderson bool tcg_op_deposit_valid(TCGType type, unsigned ofs, unsigned len)
26020e4c6424SRichard Henderson {
26036482e9d2SRichard Henderson unsigned width;
26046482e9d2SRichard Henderson
26056482e9d2SRichard Henderson tcg_debug_assert(type == TCG_TYPE_I32 || type == TCG_TYPE_I64);
26066482e9d2SRichard Henderson width = (type == TCG_TYPE_I32 ? 32 : 64);
26076482e9d2SRichard Henderson
26086482e9d2SRichard Henderson tcg_debug_assert(ofs < width);
26090e4c6424SRichard Henderson tcg_debug_assert(len > 0);
26106482e9d2SRichard Henderson tcg_debug_assert(len <= width - ofs);
26116482e9d2SRichard Henderson
26126482e9d2SRichard Henderson return TCG_TARGET_deposit_valid(type, ofs, len);
26130e4c6424SRichard Henderson }
26140e4c6424SRichard Henderson
261539004a71SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs);
261639004a71SRichard Henderson
tcg_gen_callN(void * func,TCGHelperInfo * info,TCGTemp * ret,TCGTemp ** args)261783a0ad26SRichard Henderson static void tcg_gen_callN(void *func, TCGHelperInfo *info,
261883a0ad26SRichard Henderson TCGTemp *ret, TCGTemp **args)
2619c896fe29Sbellard {
262039004a71SRichard Henderson TCGv_i64 extend_free[MAX_CALL_IARGS];
262139004a71SRichard Henderson int n_extend = 0;
262275e8b9b7SRichard Henderson TCGOp *op;
262339004a71SRichard Henderson int i, n, pi = 0, total_args;
2624afb49896SRichard Henderson
2625d53106c9SRichard Henderson if (unlikely(g_once_init_enter(HELPER_INFO_INIT(info)))) {
2626d53106c9SRichard Henderson init_call_layout(info);
2627d53106c9SRichard Henderson g_once_init_leave(HELPER_INFO_INIT(info), HELPER_INFO_INIT_VAL(info));
2628d53106c9SRichard Henderson }
2629d53106c9SRichard Henderson
263039004a71SRichard Henderson total_args = info->nr_out + info->nr_in + 2;
263139004a71SRichard Henderson op = tcg_op_alloc(INDEX_op_call, total_args);
26322bece2c8SRichard Henderson
263338b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN
263417083f6fSEmilio Cota /* Flag helpers that may affect guest state */
2635b0748975SRichard Henderson if (tcg_ctx->plugin_insn && !(info->flags & TCG_CALL_NO_SIDE_EFFECTS)) {
263638b47b19SEmilio G. Cota tcg_ctx->plugin_insn->calls_helpers = true;
263738b47b19SEmilio G. Cota }
263838b47b19SEmilio G. Cota #endif
263938b47b19SEmilio G. Cota
264039004a71SRichard Henderson TCGOP_CALLO(op) = n = info->nr_out;
264139004a71SRichard Henderson switch (n) {
264239004a71SRichard Henderson case 0:
264339004a71SRichard Henderson tcg_debug_assert(ret == NULL);
264439004a71SRichard Henderson break;
264539004a71SRichard Henderson case 1:
264639004a71SRichard Henderson tcg_debug_assert(ret != NULL);
264739004a71SRichard Henderson op->args[pi++] = temp_arg(ret);
264839004a71SRichard Henderson break;
264939004a71SRichard Henderson case 2:
2650466d3759SRichard Henderson case 4:
265139004a71SRichard Henderson tcg_debug_assert(ret != NULL);
2652466d3759SRichard Henderson tcg_debug_assert(ret->base_type == ret->type + ctz32(n));
265339004a71SRichard Henderson tcg_debug_assert(ret->temp_subindex == 0);
2654466d3759SRichard Henderson for (i = 0; i < n; ++i) {
2655466d3759SRichard Henderson op->args[pi++] = temp_arg(ret + i);
2656466d3759SRichard Henderson }
265739004a71SRichard Henderson break;
265839004a71SRichard Henderson default:
265939004a71SRichard Henderson g_assert_not_reached();
266039004a71SRichard Henderson }
26617319d83aSRichard Henderson
266239004a71SRichard Henderson TCGOP_CALLI(op) = n = info->nr_in;
266339004a71SRichard Henderson for (i = 0; i < n; i++) {
266439004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i];
266539004a71SRichard Henderson TCGTemp *ts = args[loc->arg_idx] + loc->tmp_subindex;
266639004a71SRichard Henderson
266739004a71SRichard Henderson switch (loc->kind) {
266839004a71SRichard Henderson case TCG_CALL_ARG_NORMAL:
2669313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF:
2670313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF_N:
267139004a71SRichard Henderson op->args[pi++] = temp_arg(ts);
267239004a71SRichard Henderson break;
267339004a71SRichard Henderson
267439004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U:
267539004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S:
267639004a71SRichard Henderson {
26775dd48602SRichard Henderson TCGv_i64 temp = tcg_temp_ebb_new_i64();
267839004a71SRichard Henderson TCGv_i32 orig = temp_tcgv_i32(ts);
267939004a71SRichard Henderson
268039004a71SRichard Henderson if (loc->kind == TCG_CALL_ARG_EXTEND_S) {
268118cf3d07SRichard Henderson tcg_gen_ext_i32_i64(temp, orig);
26822bece2c8SRichard Henderson } else {
268318cf3d07SRichard Henderson tcg_gen_extu_i32_i64(temp, orig);
26842bece2c8SRichard Henderson }
268539004a71SRichard Henderson op->args[pi++] = tcgv_i64_arg(temp);
268639004a71SRichard Henderson extend_free[n_extend++] = temp;
26872bece2c8SRichard Henderson }
268839004a71SRichard Henderson break;
26892bece2c8SRichard Henderson
2690e2a9dd6bSRichard Henderson default:
2691e2a9dd6bSRichard Henderson g_assert_not_reached();
2692e2a9dd6bSRichard Henderson }
2693c896fe29Sbellard }
269483a0ad26SRichard Henderson op->args[pi++] = (uintptr_t)func;
26953e92aa34SRichard Henderson op->args[pi++] = (uintptr_t)info;
269639004a71SRichard Henderson tcg_debug_assert(pi == total_args);
2697a7812ae4Spbrook
269807843f75SRichard Henderson if (tcg_ctx->emit_before_op) {
269907843f75SRichard Henderson QTAILQ_INSERT_BEFORE(tcg_ctx->emit_before_op, op, link);
270007843f75SRichard Henderson } else {
270139004a71SRichard Henderson QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
270207843f75SRichard Henderson }
27032bece2c8SRichard Henderson
270439004a71SRichard Henderson tcg_debug_assert(n_extend < ARRAY_SIZE(extend_free));
270539004a71SRichard Henderson for (i = 0; i < n_extend; ++i) {
270639004a71SRichard Henderson tcg_temp_free_i64(extend_free[i]);
2707eb8b0224SRichard Henderson }
2708a7812ae4Spbrook }
2709c896fe29Sbellard
tcg_gen_call0(void * func,TCGHelperInfo * info,TCGTemp * ret)271083a0ad26SRichard Henderson void tcg_gen_call0(void *func, TCGHelperInfo *info, TCGTemp *ret)
2711a3a692b8SRichard Henderson {
271283a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, NULL);
2713a3a692b8SRichard Henderson }
2714a3a692b8SRichard Henderson
tcg_gen_call1(void * func,TCGHelperInfo * info,TCGTemp * ret,TCGTemp * t1)271583a0ad26SRichard Henderson void tcg_gen_call1(void *func, TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1)
2716a3a692b8SRichard Henderson {
271783a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, &t1);
2718a3a692b8SRichard Henderson }
2719a3a692b8SRichard Henderson
tcg_gen_call2(void * func,TCGHelperInfo * info,TCGTemp * ret,TCGTemp * t1,TCGTemp * t2)272083a0ad26SRichard Henderson void tcg_gen_call2(void *func, TCGHelperInfo *info, TCGTemp *ret,
272183a0ad26SRichard Henderson TCGTemp *t1, TCGTemp *t2)
2722a3a692b8SRichard Henderson {
2723a3a692b8SRichard Henderson TCGTemp *args[2] = { t1, t2 };
272483a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, args);
2725a3a692b8SRichard Henderson }
2726a3a692b8SRichard Henderson
tcg_gen_call3(void * func,TCGHelperInfo * info,TCGTemp * ret,TCGTemp * t1,TCGTemp * t2,TCGTemp * t3)272783a0ad26SRichard Henderson void tcg_gen_call3(void *func, TCGHelperInfo *info, TCGTemp *ret,
272883a0ad26SRichard Henderson TCGTemp *t1, TCGTemp *t2, TCGTemp *t3)
2729a3a692b8SRichard Henderson {
2730a3a692b8SRichard Henderson TCGTemp *args[3] = { t1, t2, t3 };
273183a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, args);
2732a3a692b8SRichard Henderson }
2733a3a692b8SRichard Henderson
tcg_gen_call4(void * func,TCGHelperInfo * info,TCGTemp * ret,TCGTemp * t1,TCGTemp * t2,TCGTemp * t3,TCGTemp * t4)273483a0ad26SRichard Henderson void tcg_gen_call4(void *func, TCGHelperInfo *info, TCGTemp *ret,
273583a0ad26SRichard Henderson TCGTemp *t1, TCGTemp *t2, TCGTemp *t3, TCGTemp *t4)
2736a3a692b8SRichard Henderson {
2737a3a692b8SRichard Henderson TCGTemp *args[4] = { t1, t2, t3, t4 };
273883a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, args);
2739a3a692b8SRichard Henderson }
2740a3a692b8SRichard Henderson
tcg_gen_call5(void * func,TCGHelperInfo * info,TCGTemp * ret,TCGTemp * t1,TCGTemp * t2,TCGTemp * t3,TCGTemp * t4,TCGTemp * t5)274183a0ad26SRichard Henderson void tcg_gen_call5(void *func, TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1,
2742a3a692b8SRichard Henderson TCGTemp *t2, TCGTemp *t3, TCGTemp *t4, TCGTemp *t5)
2743a3a692b8SRichard Henderson {
2744a3a692b8SRichard Henderson TCGTemp *args[5] = { t1, t2, t3, t4, t5 };
274583a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, args);
2746a3a692b8SRichard Henderson }
2747a3a692b8SRichard Henderson
tcg_gen_call6(void * func,TCGHelperInfo * info,TCGTemp * ret,TCGTemp * t1,TCGTemp * t2,TCGTemp * t3,TCGTemp * t4,TCGTemp * t5,TCGTemp * t6)274883a0ad26SRichard Henderson void tcg_gen_call6(void *func, TCGHelperInfo *info, TCGTemp *ret,
274983a0ad26SRichard Henderson TCGTemp *t1, TCGTemp *t2, TCGTemp *t3,
275083a0ad26SRichard Henderson TCGTemp *t4, TCGTemp *t5, TCGTemp *t6)
2751a3a692b8SRichard Henderson {
2752a3a692b8SRichard Henderson TCGTemp *args[6] = { t1, t2, t3, t4, t5, t6 };
275383a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, args);
2754a3a692b8SRichard Henderson }
2755a3a692b8SRichard Henderson
tcg_gen_call7(void * func,TCGHelperInfo * info,TCGTemp * ret,TCGTemp * t1,TCGTemp * t2,TCGTemp * t3,TCGTemp * t4,TCGTemp * t5,TCGTemp * t6,TCGTemp * t7)275683a0ad26SRichard Henderson void tcg_gen_call7(void *func, TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1,
2757a3a692b8SRichard Henderson TCGTemp *t2, TCGTemp *t3, TCGTemp *t4,
2758a3a692b8SRichard Henderson TCGTemp *t5, TCGTemp *t6, TCGTemp *t7)
2759a3a692b8SRichard Henderson {
2760a3a692b8SRichard Henderson TCGTemp *args[7] = { t1, t2, t3, t4, t5, t6, t7 };
276183a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, args);
2762a3a692b8SRichard Henderson }
2763a3a692b8SRichard Henderson
tcg_reg_alloc_start(TCGContext * s)27648fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s)
2765c896fe29Sbellard {
2766ac3b8891SRichard Henderson int i, n;
2767ac3b8891SRichard Henderson
2768ee17db83SRichard Henderson for (i = 0, n = s->nb_temps; i < n; i++) {
2769ee17db83SRichard Henderson TCGTemp *ts = &s->temps[i];
2770ee17db83SRichard Henderson TCGTempVal val = TEMP_VAL_MEM;
2771ee17db83SRichard Henderson
2772ee17db83SRichard Henderson switch (ts->kind) {
2773c0522136SRichard Henderson case TEMP_CONST:
2774c0522136SRichard Henderson val = TEMP_VAL_CONST;
2775c0522136SRichard Henderson break;
2776ee17db83SRichard Henderson case TEMP_FIXED:
2777ee17db83SRichard Henderson val = TEMP_VAL_REG;
2778ee17db83SRichard Henderson break;
2779ee17db83SRichard Henderson case TEMP_GLOBAL:
2780ee17db83SRichard Henderson break;
2781c7482438SRichard Henderson case TEMP_EBB:
2782ee17db83SRichard Henderson val = TEMP_VAL_DEAD;
2783ee17db83SRichard Henderson /* fall through */
2784f57c6915SRichard Henderson case TEMP_TB:
2785e8996ee0Sbellard ts->mem_allocated = 0;
2786ee17db83SRichard Henderson break;
2787ee17db83SRichard Henderson default:
2788ee17db83SRichard Henderson g_assert_not_reached();
2789ee17db83SRichard Henderson }
2790ee17db83SRichard Henderson ts->val_type = val;
2791e8996ee0Sbellard }
2792f8b2f202SRichard Henderson
2793f8b2f202SRichard Henderson memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp));
2794c896fe29Sbellard }
2795c896fe29Sbellard
tcg_get_arg_str_ptr(TCGContext * s,char * buf,int buf_size,TCGTemp * ts)2796f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size,
2797f8b2f202SRichard Henderson TCGTemp *ts)
2798c896fe29Sbellard {
27991807f4c4SRichard Henderson int idx = temp_idx(ts);
2800ac56dd48Spbrook
2801ee17db83SRichard Henderson switch (ts->kind) {
2802ee17db83SRichard Henderson case TEMP_FIXED:
2803ee17db83SRichard Henderson case TEMP_GLOBAL:
2804ac56dd48Spbrook pstrcpy(buf, buf_size, ts->name);
2805ee17db83SRichard Henderson break;
2806f57c6915SRichard Henderson case TEMP_TB:
2807641d5fbeSbellard snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
2808ee17db83SRichard Henderson break;
2809c7482438SRichard Henderson case TEMP_EBB:
2810ac56dd48Spbrook snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
2811ee17db83SRichard Henderson break;
2812c0522136SRichard Henderson case TEMP_CONST:
2813c0522136SRichard Henderson switch (ts->type) {
2814c0522136SRichard Henderson case TCG_TYPE_I32:
2815c0522136SRichard Henderson snprintf(buf, buf_size, "$0x%x", (int32_t)ts->val);
2816c0522136SRichard Henderson break;
2817c0522136SRichard Henderson #if TCG_TARGET_REG_BITS > 32
2818c0522136SRichard Henderson case TCG_TYPE_I64:
2819c0522136SRichard Henderson snprintf(buf, buf_size, "$0x%" PRIx64, ts->val);
2820c0522136SRichard Henderson break;
2821c0522136SRichard Henderson #endif
2822c0522136SRichard Henderson case TCG_TYPE_V64:
2823c0522136SRichard Henderson case TCG_TYPE_V128:
2824c0522136SRichard Henderson case TCG_TYPE_V256:
2825c0522136SRichard Henderson snprintf(buf, buf_size, "v%d$0x%" PRIx64,
2826c0522136SRichard Henderson 64 << (ts->type - TCG_TYPE_V64), ts->val);
2827c0522136SRichard Henderson break;
2828c0522136SRichard Henderson default:
2829c0522136SRichard Henderson g_assert_not_reached();
2830c0522136SRichard Henderson }
2831c0522136SRichard Henderson break;
2832c896fe29Sbellard }
2833c896fe29Sbellard return buf;
2834c896fe29Sbellard }
2835c896fe29Sbellard
tcg_get_arg_str(TCGContext * s,char * buf,int buf_size,TCGArg arg)283643439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf,
283743439139SRichard Henderson int buf_size, TCGArg arg)
2838f8b2f202SRichard Henderson {
283943439139SRichard Henderson return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg));
2840f8b2f202SRichard Henderson }
2841f8b2f202SRichard Henderson
2842f48f3edeSblueswir1 static const char * const cond_name[] =
2843f48f3edeSblueswir1 {
28440aed257fSRichard Henderson [TCG_COND_NEVER] = "never",
28450aed257fSRichard Henderson [TCG_COND_ALWAYS] = "always",
2846f48f3edeSblueswir1 [TCG_COND_EQ] = "eq",
2847f48f3edeSblueswir1 [TCG_COND_NE] = "ne",
2848f48f3edeSblueswir1 [TCG_COND_LT] = "lt",
2849f48f3edeSblueswir1 [TCG_COND_GE] = "ge",
2850f48f3edeSblueswir1 [TCG_COND_LE] = "le",
2851f48f3edeSblueswir1 [TCG_COND_GT] = "gt",
2852f48f3edeSblueswir1 [TCG_COND_LTU] = "ltu",
2853f48f3edeSblueswir1 [TCG_COND_GEU] = "geu",
2854f48f3edeSblueswir1 [TCG_COND_LEU] = "leu",
2855d48097d0SRichard Henderson [TCG_COND_GTU] = "gtu",
2856d48097d0SRichard Henderson [TCG_COND_TSTEQ] = "tsteq",
2857d48097d0SRichard Henderson [TCG_COND_TSTNE] = "tstne",
2858f48f3edeSblueswir1 };
2859f48f3edeSblueswir1
286012fde9bcSRichard Henderson static const char * const ldst_name[(MO_BSWAP | MO_SSIZE) + 1] =
2861f713d6adSRichard Henderson {
2862f713d6adSRichard Henderson [MO_UB] = "ub",
2863f713d6adSRichard Henderson [MO_SB] = "sb",
2864f713d6adSRichard Henderson [MO_LEUW] = "leuw",
2865f713d6adSRichard Henderson [MO_LESW] = "lesw",
2866f713d6adSRichard Henderson [MO_LEUL] = "leul",
2867f713d6adSRichard Henderson [MO_LESL] = "lesl",
2868fc313c64SFrédéric Pétrot [MO_LEUQ] = "leq",
2869f713d6adSRichard Henderson [MO_BEUW] = "beuw",
2870f713d6adSRichard Henderson [MO_BESW] = "besw",
2871f713d6adSRichard Henderson [MO_BEUL] = "beul",
2872f713d6adSRichard Henderson [MO_BESL] = "besl",
2873fc313c64SFrédéric Pétrot [MO_BEUQ] = "beq",
287412fde9bcSRichard Henderson [MO_128 + MO_BE] = "beo",
287512fde9bcSRichard Henderson [MO_128 + MO_LE] = "leo",
2876f713d6adSRichard Henderson };
2877f713d6adSRichard Henderson
28781f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = {
28791f00b27fSSergey Sorokin [MO_UNALN >> MO_ASHIFT] = "un+",
28801f00b27fSSergey Sorokin [MO_ALIGN >> MO_ASHIFT] = "al+",
28811f00b27fSSergey Sorokin [MO_ALIGN_2 >> MO_ASHIFT] = "al2+",
28821f00b27fSSergey Sorokin [MO_ALIGN_4 >> MO_ASHIFT] = "al4+",
28831f00b27fSSergey Sorokin [MO_ALIGN_8 >> MO_ASHIFT] = "al8+",
28841f00b27fSSergey Sorokin [MO_ALIGN_16 >> MO_ASHIFT] = "al16+",
28851f00b27fSSergey Sorokin [MO_ALIGN_32 >> MO_ASHIFT] = "al32+",
28861f00b27fSSergey Sorokin [MO_ALIGN_64 >> MO_ASHIFT] = "al64+",
28871f00b27fSSergey Sorokin };
28881f00b27fSSergey Sorokin
288937031fefSRichard Henderson static const char * const atom_name[(MO_ATOM_MASK >> MO_ATOM_SHIFT) + 1] = {
289037031fefSRichard Henderson [MO_ATOM_IFALIGN >> MO_ATOM_SHIFT] = "",
289137031fefSRichard Henderson [MO_ATOM_IFALIGN_PAIR >> MO_ATOM_SHIFT] = "pair+",
289237031fefSRichard Henderson [MO_ATOM_WITHIN16 >> MO_ATOM_SHIFT] = "w16+",
289337031fefSRichard Henderson [MO_ATOM_WITHIN16_PAIR >> MO_ATOM_SHIFT] = "w16p+",
289437031fefSRichard Henderson [MO_ATOM_SUBALIGN >> MO_ATOM_SHIFT] = "sub+",
289537031fefSRichard Henderson [MO_ATOM_NONE >> MO_ATOM_SHIFT] = "noat+",
289637031fefSRichard Henderson };
289737031fefSRichard Henderson
2898587195bdSRichard Henderson static const char bswap_flag_name[][6] = {
2899587195bdSRichard Henderson [TCG_BSWAP_IZ] = "iz",
2900587195bdSRichard Henderson [TCG_BSWAP_OZ] = "oz",
2901587195bdSRichard Henderson [TCG_BSWAP_OS] = "os",
2902587195bdSRichard Henderson [TCG_BSWAP_IZ | TCG_BSWAP_OZ] = "iz,oz",
2903587195bdSRichard Henderson [TCG_BSWAP_IZ | TCG_BSWAP_OS] = "iz,os",
2904587195bdSRichard Henderson };
2905587195bdSRichard Henderson
2906b384c734SRichard Henderson #ifdef CONFIG_PLUGIN
2907b384c734SRichard Henderson static const char * const plugin_from_name[] = {
2908b384c734SRichard Henderson "from-tb",
2909b384c734SRichard Henderson "from-insn",
2910b384c734SRichard Henderson "after-insn",
2911b384c734SRichard Henderson "after-tb",
2912b384c734SRichard Henderson };
2913b384c734SRichard Henderson #endif
2914b384c734SRichard Henderson
tcg_regset_single(TCGRegSet d)2915b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d)
2916b016486eSRichard Henderson {
2917b016486eSRichard Henderson return (d & (d - 1)) == 0;
2918b016486eSRichard Henderson }
2919b016486eSRichard Henderson
tcg_regset_first(TCGRegSet d)2920b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d)
2921b016486eSRichard Henderson {
2922b016486eSRichard Henderson if (TCG_TARGET_NB_REGS <= 32) {
2923b016486eSRichard Henderson return ctz32(d);
2924b016486eSRichard Henderson } else {
2925b016486eSRichard Henderson return ctz64(d);
2926b016486eSRichard Henderson }
2927b016486eSRichard Henderson }
2928b016486eSRichard Henderson
2929b7a83ff8SRichard Henderson /* Return only the number of characters output -- no error return. */
2930b7a83ff8SRichard Henderson #define ne_fprintf(...) \
2931b7a83ff8SRichard Henderson ({ int ret_ = fprintf(__VA_ARGS__); ret_ >= 0 ? ret_ : 0; })
2932b7a83ff8SRichard Henderson
tcg_dump_ops(TCGContext * s,FILE * f,bool have_prefs)2933b384c734SRichard Henderson void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs)
2934c896fe29Sbellard {
2935c896fe29Sbellard char buf[128];
2936c45cb8bbSRichard Henderson TCGOp *op;
2937c896fe29Sbellard
293815fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) {
2939c45cb8bbSRichard Henderson int i, k, nb_oargs, nb_iargs, nb_cargs;
2940c45cb8bbSRichard Henderson const TCGOpDef *def;
2941c45cb8bbSRichard Henderson TCGOpcode c;
2942bdfb460eSRichard Henderson int col = 0;
2943c45cb8bbSRichard Henderson
2944c45cb8bbSRichard Henderson c = op->opc;
2945c896fe29Sbellard def = &tcg_op_defs[c];
2946c45cb8bbSRichard Henderson
2947765b842aSRichard Henderson if (c == INDEX_op_insn_start) {
2948b016486eSRichard Henderson nb_oargs = 0;
2949b7a83ff8SRichard Henderson col += ne_fprintf(f, "\n ----");
29509aef40edSRichard Henderson
2951e1d8fabcSRichard Henderson for (i = 0, k = INSN_START_WORDS; i < k; ++i) {
2952c9ad8d27SRichard Henderson col += ne_fprintf(f, " %016" PRIx64,
2953c9ad8d27SRichard Henderson tcg_get_insn_start_param(op, i));
2954eeacee4dSBlue Swirl }
29557e4597d7Sbellard } else if (c == INDEX_op_call) {
29563e92aa34SRichard Henderson const TCGHelperInfo *info = tcg_call_info(op);
2957fa52e660SRichard Henderson void *func = tcg_call_func(op);
29583e92aa34SRichard Henderson
2959c896fe29Sbellard /* variable number of arguments */
2960cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op);
2961cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op);
2962c896fe29Sbellard nb_cargs = def->nb_cargs;
2963b03cce8eSbellard
2964b7a83ff8SRichard Henderson col += ne_fprintf(f, " %s ", def->name);
29653e92aa34SRichard Henderson
29663e92aa34SRichard Henderson /*
29673e92aa34SRichard Henderson * Print the function name from TCGHelperInfo, if available.
29683e92aa34SRichard Henderson * Note that plugins have a template function for the info,
29693e92aa34SRichard Henderson * but the actual function pointer comes from the plugin.
29703e92aa34SRichard Henderson */
29713e92aa34SRichard Henderson if (func == info->func) {
2972b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s", info->name);
29733e92aa34SRichard Henderson } else {
2974b7a83ff8SRichard Henderson col += ne_fprintf(f, "plugin(%p)", func);
29753e92aa34SRichard Henderson }
29763e92aa34SRichard Henderson
2977b7a83ff8SRichard Henderson col += ne_fprintf(f, ",$0x%x,$%d", info->flags, nb_oargs);
2978b03cce8eSbellard for (i = 0; i < nb_oargs; i++) {
2979b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", tcg_get_arg_str(s, buf, sizeof(buf),
2980efee3746SRichard Henderson op->args[i]));
2981b03cce8eSbellard }
2982cf066674SRichard Henderson for (i = 0; i < nb_iargs; i++) {
2983efee3746SRichard Henderson TCGArg arg = op->args[nb_oargs + i];
298439004a71SRichard Henderson const char *t = tcg_get_arg_str(s, buf, sizeof(buf), arg);
2985b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", t);
2986e8996ee0Sbellard }
2987b03cce8eSbellard } else {
2988b5701261SRichard Henderson if (def->flags & TCG_OPF_INT) {
2989b5701261SRichard Henderson col += ne_fprintf(f, " %s_i%d ",
2990b5701261SRichard Henderson def->name,
2991b5701261SRichard Henderson 8 * tcg_type_size(TCGOP_TYPE(op)));
2992b5701261SRichard Henderson } else if (def->flags & TCG_OPF_VECTOR) {
2993b5701261SRichard Henderson col += ne_fprintf(f, "%s v%d,e%d,",
2994b5701261SRichard Henderson def->name,
2995b5701261SRichard Henderson 8 * tcg_type_size(TCGOP_TYPE(op)),
2996b5701261SRichard Henderson 8 << TCGOP_VECE(op));
2997b5701261SRichard Henderson } else {
2998b7a83ff8SRichard Henderson col += ne_fprintf(f, " %s ", def->name);
2999b5701261SRichard Henderson }
3000c45cb8bbSRichard Henderson
3001c896fe29Sbellard nb_oargs = def->nb_oargs;
3002c896fe29Sbellard nb_iargs = def->nb_iargs;
3003c896fe29Sbellard nb_cargs = def->nb_cargs;
3004c896fe29Sbellard
3005c896fe29Sbellard k = 0;
3006c896fe29Sbellard for (i = 0; i < nb_oargs; i++) {
3007b7a83ff8SRichard Henderson const char *sep = k ? "," : "";
3008b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s%s", sep,
3009b7a83ff8SRichard Henderson tcg_get_arg_str(s, buf, sizeof(buf),
3010efee3746SRichard Henderson op->args[k++]));
3011c896fe29Sbellard }
3012c896fe29Sbellard for (i = 0; i < nb_iargs; i++) {
3013b7a83ff8SRichard Henderson const char *sep = k ? "," : "";
3014b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s%s", sep,
3015b7a83ff8SRichard Henderson tcg_get_arg_str(s, buf, sizeof(buf),
3016efee3746SRichard Henderson op->args[k++]));
3017c896fe29Sbellard }
3018be210acbSRichard Henderson switch (c) {
3019b6d69fceSRichard Henderson case INDEX_op_brcond:
3020a363e1e1SRichard Henderson case INDEX_op_setcond:
3021a363e1e1SRichard Henderson case INDEX_op_negsetcond:
3022ea46c4bcSRichard Henderson case INDEX_op_movcond:
3023be210acbSRichard Henderson case INDEX_op_brcond2_i32:
3024be210acbSRichard Henderson case INDEX_op_setcond2_i32:
3025212be173SRichard Henderson case INDEX_op_cmp_vec:
3026f75da298SRichard Henderson case INDEX_op_cmpsel_vec:
3027efee3746SRichard Henderson if (op->args[k] < ARRAY_SIZE(cond_name)
3028efee3746SRichard Henderson && cond_name[op->args[k]]) {
3029b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", cond_name[op->args[k++]]);
3030eeacee4dSBlue Swirl } else {
3031b7a83ff8SRichard Henderson col += ne_fprintf(f, ",$0x%" TCG_PRIlx, op->args[k++]);
3032eeacee4dSBlue Swirl }
3033f48f3edeSblueswir1 i = 1;
3034be210acbSRichard Henderson break;
3035aae2456aSRichard Henderson case INDEX_op_qemu_ld:
3036aae2456aSRichard Henderson case INDEX_op_qemu_st:
3037aae2456aSRichard Henderson case INDEX_op_qemu_ld2:
3038aae2456aSRichard Henderson case INDEX_op_qemu_st2:
303959227d5dSRichard Henderson {
304037031fefSRichard Henderson const char *s_al, *s_op, *s_at;
30419002ffcbSRichard Henderson MemOpIdx oi = op->args[k++];
30429a239c6eSPhilippe Mathieu-Daudé MemOp mop = get_memop(oi);
304359227d5dSRichard Henderson unsigned ix = get_mmuidx(oi);
304459227d5dSRichard Henderson
30459a239c6eSPhilippe Mathieu-Daudé s_al = alignment_name[(mop & MO_AMASK) >> MO_ASHIFT];
30469a239c6eSPhilippe Mathieu-Daudé s_op = ldst_name[mop & (MO_BSWAP | MO_SSIZE)];
30479a239c6eSPhilippe Mathieu-Daudé s_at = atom_name[(mop & MO_ATOM_MASK) >> MO_ATOM_SHIFT];
30489a239c6eSPhilippe Mathieu-Daudé mop &= ~(MO_AMASK | MO_BSWAP | MO_SSIZE | MO_ATOM_MASK);
304937031fefSRichard Henderson
305037031fefSRichard Henderson /* If all fields are accounted for, print symbolically. */
30519a239c6eSPhilippe Mathieu-Daudé if (!mop && s_al && s_op && s_at) {
305237031fefSRichard Henderson col += ne_fprintf(f, ",%s%s%s,%u",
305337031fefSRichard Henderson s_at, s_al, s_op, ix);
305437031fefSRichard Henderson } else {
30559a239c6eSPhilippe Mathieu-Daudé mop = get_memop(oi);
30569a239c6eSPhilippe Mathieu-Daudé col += ne_fprintf(f, ",$0x%x,%u", mop, ix);
3057f713d6adSRichard Henderson }
3058f713d6adSRichard Henderson i = 1;
305959227d5dSRichard Henderson }
3060f713d6adSRichard Henderson break;
30610dd07ee1SRichard Henderson case INDEX_op_bswap16:
30627498d882SRichard Henderson case INDEX_op_bswap32:
30633ad5d4ccSRichard Henderson case INDEX_op_bswap64:
3064587195bdSRichard Henderson {
3065587195bdSRichard Henderson TCGArg flags = op->args[k];
3066587195bdSRichard Henderson const char *name = NULL;
3067587195bdSRichard Henderson
3068587195bdSRichard Henderson if (flags < ARRAY_SIZE(bswap_flag_name)) {
3069587195bdSRichard Henderson name = bswap_flag_name[flags];
3070587195bdSRichard Henderson }
3071587195bdSRichard Henderson if (name) {
3072b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", name);
3073587195bdSRichard Henderson } else {
3074b7a83ff8SRichard Henderson col += ne_fprintf(f, ",$0x%" TCG_PRIlx, flags);
3075587195bdSRichard Henderson }
3076587195bdSRichard Henderson i = k = 1;
3077587195bdSRichard Henderson }
3078587195bdSRichard Henderson break;
3079b384c734SRichard Henderson #ifdef CONFIG_PLUGIN
3080b384c734SRichard Henderson case INDEX_op_plugin_cb:
3081b384c734SRichard Henderson {
3082b384c734SRichard Henderson TCGArg from = op->args[k++];
3083b384c734SRichard Henderson const char *name = NULL;
3084b384c734SRichard Henderson
3085b384c734SRichard Henderson if (from < ARRAY_SIZE(plugin_from_name)) {
3086b384c734SRichard Henderson name = plugin_from_name[from];
3087b384c734SRichard Henderson }
3088b384c734SRichard Henderson if (name) {
3089b384c734SRichard Henderson col += ne_fprintf(f, "%s", name);
3090b384c734SRichard Henderson } else {
3091b384c734SRichard Henderson col += ne_fprintf(f, "$0x%" TCG_PRIlx, from);
3092b384c734SRichard Henderson }
3093b384c734SRichard Henderson i = 1;
3094b384c734SRichard Henderson }
3095b384c734SRichard Henderson break;
3096b384c734SRichard Henderson #endif
3097be210acbSRichard Henderson default:
3098f48f3edeSblueswir1 i = 0;
3099be210acbSRichard Henderson break;
3100be210acbSRichard Henderson }
310151e3972cSRichard Henderson switch (c) {
310251e3972cSRichard Henderson case INDEX_op_set_label:
310351e3972cSRichard Henderson case INDEX_op_br:
3104b6d69fceSRichard Henderson case INDEX_op_brcond:
310551e3972cSRichard Henderson case INDEX_op_brcond2_i32:
3106b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s$L%d", k ? "," : "",
3107efee3746SRichard Henderson arg_label(op->args[k])->id);
310851e3972cSRichard Henderson i++, k++;
310951e3972cSRichard Henderson break;
31103470867bSRichard Henderson case INDEX_op_mb:
31113470867bSRichard Henderson {
31123470867bSRichard Henderson TCGBar membar = op->args[k];
31133470867bSRichard Henderson const char *b_op, *m_op;
31143470867bSRichard Henderson
31153470867bSRichard Henderson switch (membar & TCG_BAR_SC) {
31163470867bSRichard Henderson case 0:
31173470867bSRichard Henderson b_op = "none";
31183470867bSRichard Henderson break;
31193470867bSRichard Henderson case TCG_BAR_LDAQ:
31203470867bSRichard Henderson b_op = "acq";
31213470867bSRichard Henderson break;
31223470867bSRichard Henderson case TCG_BAR_STRL:
31233470867bSRichard Henderson b_op = "rel";
31243470867bSRichard Henderson break;
31253470867bSRichard Henderson case TCG_BAR_SC:
31263470867bSRichard Henderson b_op = "seq";
31273470867bSRichard Henderson break;
31283470867bSRichard Henderson default:
31293470867bSRichard Henderson g_assert_not_reached();
31303470867bSRichard Henderson }
31313470867bSRichard Henderson
31323470867bSRichard Henderson switch (membar & TCG_MO_ALL) {
31333470867bSRichard Henderson case 0:
31343470867bSRichard Henderson m_op = "none";
31353470867bSRichard Henderson break;
31363470867bSRichard Henderson case TCG_MO_LD_LD:
31373470867bSRichard Henderson m_op = "rr";
31383470867bSRichard Henderson break;
31393470867bSRichard Henderson case TCG_MO_LD_ST:
31403470867bSRichard Henderson m_op = "rw";
31413470867bSRichard Henderson break;
31423470867bSRichard Henderson case TCG_MO_ST_LD:
31433470867bSRichard Henderson m_op = "wr";
31443470867bSRichard Henderson break;
31453470867bSRichard Henderson case TCG_MO_ST_ST:
31463470867bSRichard Henderson m_op = "ww";
31473470867bSRichard Henderson break;
31483470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_LD_ST:
31493470867bSRichard Henderson m_op = "rr+rw";
31503470867bSRichard Henderson break;
31513470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_ST_LD:
31523470867bSRichard Henderson m_op = "rr+wr";
31533470867bSRichard Henderson break;
31543470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_ST_ST:
31553470867bSRichard Henderson m_op = "rr+ww";
31563470867bSRichard Henderson break;
31573470867bSRichard Henderson case TCG_MO_LD_ST | TCG_MO_ST_LD:
31583470867bSRichard Henderson m_op = "rw+wr";
31593470867bSRichard Henderson break;
31603470867bSRichard Henderson case TCG_MO_LD_ST | TCG_MO_ST_ST:
31613470867bSRichard Henderson m_op = "rw+ww";
31623470867bSRichard Henderson break;
31633470867bSRichard Henderson case TCG_MO_ST_LD | TCG_MO_ST_ST:
31643470867bSRichard Henderson m_op = "wr+ww";
31653470867bSRichard Henderson break;
31663470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_MO_ST_LD:
31673470867bSRichard Henderson m_op = "rr+rw+wr";
31683470867bSRichard Henderson break;
31693470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_MO_ST_ST:
31703470867bSRichard Henderson m_op = "rr+rw+ww";
31713470867bSRichard Henderson break;
31723470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_ST_LD | TCG_MO_ST_ST:
31733470867bSRichard Henderson m_op = "rr+wr+ww";
31743470867bSRichard Henderson break;
31753470867bSRichard Henderson case TCG_MO_LD_ST | TCG_MO_ST_LD | TCG_MO_ST_ST:
31763470867bSRichard Henderson m_op = "rw+wr+ww";
31773470867bSRichard Henderson break;
31783470867bSRichard Henderson case TCG_MO_ALL:
31793470867bSRichard Henderson m_op = "all";
31803470867bSRichard Henderson break;
31813470867bSRichard Henderson default:
31823470867bSRichard Henderson g_assert_not_reached();
31833470867bSRichard Henderson }
31843470867bSRichard Henderson
31853470867bSRichard Henderson col += ne_fprintf(f, "%s%s:%s", (k ? "," : ""), b_op, m_op);
31863470867bSRichard Henderson i++, k++;
31873470867bSRichard Henderson }
31883470867bSRichard Henderson break;
318951e3972cSRichard Henderson default:
319051e3972cSRichard Henderson break;
3191eeacee4dSBlue Swirl }
319251e3972cSRichard Henderson for (; i < nb_cargs; i++, k++) {
3193b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s$0x%" TCG_PRIlx, k ? "," : "",
3194b7a83ff8SRichard Henderson op->args[k]);
3195bdfb460eSRichard Henderson }
3196bdfb460eSRichard Henderson }
3197bdfb460eSRichard Henderson
31981894f69aSRichard Henderson if (have_prefs || op->life) {
31991894f69aSRichard Henderson for (; col < 40; ++col) {
3200b7a83ff8SRichard Henderson putc(' ', f);
3201bdfb460eSRichard Henderson }
32021894f69aSRichard Henderson }
32031894f69aSRichard Henderson
32041894f69aSRichard Henderson if (op->life) {
32051894f69aSRichard Henderson unsigned life = op->life;
3206bdfb460eSRichard Henderson
3207bdfb460eSRichard Henderson if (life & (SYNC_ARG * 3)) {
3208b7a83ff8SRichard Henderson ne_fprintf(f, " sync:");
3209bdfb460eSRichard Henderson for (i = 0; i < 2; ++i) {
3210bdfb460eSRichard Henderson if (life & (SYNC_ARG << i)) {
3211b7a83ff8SRichard Henderson ne_fprintf(f, " %d", i);
3212bdfb460eSRichard Henderson }
3213bdfb460eSRichard Henderson }
3214bdfb460eSRichard Henderson }
3215bdfb460eSRichard Henderson life /= DEAD_ARG;
3216bdfb460eSRichard Henderson if (life) {
3217b7a83ff8SRichard Henderson ne_fprintf(f, " dead:");
3218bdfb460eSRichard Henderson for (i = 0; life; ++i, life >>= 1) {
3219bdfb460eSRichard Henderson if (life & 1) {
3220b7a83ff8SRichard Henderson ne_fprintf(f, " %d", i);
3221bdfb460eSRichard Henderson }
3222bdfb460eSRichard Henderson }
3223c896fe29Sbellard }
3224b03cce8eSbellard }
32251894f69aSRichard Henderson
32261894f69aSRichard Henderson if (have_prefs) {
32271894f69aSRichard Henderson for (i = 0; i < nb_oargs; ++i) {
322831fd884bSRichard Henderson TCGRegSet set = output_pref(op, i);
32291894f69aSRichard Henderson
32301894f69aSRichard Henderson if (i == 0) {
3231b7a83ff8SRichard Henderson ne_fprintf(f, " pref=");
32321894f69aSRichard Henderson } else {
3233b7a83ff8SRichard Henderson ne_fprintf(f, ",");
32341894f69aSRichard Henderson }
32351894f69aSRichard Henderson if (set == 0) {
3236b7a83ff8SRichard Henderson ne_fprintf(f, "none");
32371894f69aSRichard Henderson } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) {
3238b7a83ff8SRichard Henderson ne_fprintf(f, "all");
32391894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG
32401894f69aSRichard Henderson } else if (tcg_regset_single(set)) {
32411894f69aSRichard Henderson TCGReg reg = tcg_regset_first(set);
3242b7a83ff8SRichard Henderson ne_fprintf(f, "%s", tcg_target_reg_names[reg]);
32431894f69aSRichard Henderson #endif
32441894f69aSRichard Henderson } else if (TCG_TARGET_NB_REGS <= 32) {
3245b7a83ff8SRichard Henderson ne_fprintf(f, "0x%x", (uint32_t)set);
32461894f69aSRichard Henderson } else {
3247b7a83ff8SRichard Henderson ne_fprintf(f, "0x%" PRIx64, (uint64_t)set);
32481894f69aSRichard Henderson }
32491894f69aSRichard Henderson }
32501894f69aSRichard Henderson }
32511894f69aSRichard Henderson
3252b7a83ff8SRichard Henderson putc('\n', f);
3253c896fe29Sbellard }
3254c896fe29Sbellard }
3255c896fe29Sbellard
3256c896fe29Sbellard /* we give more priority to constraints with less registers */
get_constraint_priority(const TCGArgConstraint * arg_ct,int k)32573e80824eSRichard Henderson static int get_constraint_priority(const TCGArgConstraint *arg_ct, int k)
3258c896fe29Sbellard {
32593e80824eSRichard Henderson int n;
32603e80824eSRichard Henderson
32613e80824eSRichard Henderson arg_ct += k;
32623e80824eSRichard Henderson n = ctpop64(arg_ct->regs);
3263c896fe29Sbellard
326429f5e925SRichard Henderson /*
326529f5e925SRichard Henderson * Sort constraints of a single register first, which includes output
326629f5e925SRichard Henderson * aliases (which must exactly match the input already allocated).
326729f5e925SRichard Henderson */
326829f5e925SRichard Henderson if (n == 1 || arg_ct->oalias) {
326929f5e925SRichard Henderson return INT_MAX;
3270c896fe29Sbellard }
327129f5e925SRichard Henderson
327229f5e925SRichard Henderson /*
327329f5e925SRichard Henderson * Sort register pairs next, first then second immediately after.
327429f5e925SRichard Henderson * Arbitrarily sort multiple pairs by the index of the first reg;
327529f5e925SRichard Henderson * there shouldn't be many pairs.
327629f5e925SRichard Henderson */
327729f5e925SRichard Henderson switch (arg_ct->pair) {
327829f5e925SRichard Henderson case 1:
327929f5e925SRichard Henderson case 3:
328029f5e925SRichard Henderson return (k + 1) * 2;
328129f5e925SRichard Henderson case 2:
328229f5e925SRichard Henderson return (arg_ct->pair_index + 1) * 2 - 1;
328329f5e925SRichard Henderson }
328429f5e925SRichard Henderson
328529f5e925SRichard Henderson /* Finally, sort by decreasing register count. */
328629f5e925SRichard Henderson assert(n > 1);
328729f5e925SRichard Henderson return -n;
3288c896fe29Sbellard }
3289c896fe29Sbellard
3290c896fe29Sbellard /* sort from highest priority to lowest */
sort_constraints(TCGArgConstraint * a,int start,int n)32913e80824eSRichard Henderson static void sort_constraints(TCGArgConstraint *a, int start, int n)
3292c896fe29Sbellard {
329366792f90SRichard Henderson int i, j;
3294c896fe29Sbellard
329566792f90SRichard Henderson for (i = 0; i < n; i++) {
329666792f90SRichard Henderson a[start + i].sort_index = start + i;
329766792f90SRichard Henderson }
329866792f90SRichard Henderson if (n <= 1) {
3299c896fe29Sbellard return;
330066792f90SRichard Henderson }
3301c896fe29Sbellard for (i = 0; i < n - 1; i++) {
3302c896fe29Sbellard for (j = i + 1; j < n; j++) {
33033e80824eSRichard Henderson int p1 = get_constraint_priority(a, a[start + i].sort_index);
33043e80824eSRichard Henderson int p2 = get_constraint_priority(a, a[start + j].sort_index);
3305c896fe29Sbellard if (p1 < p2) {
330666792f90SRichard Henderson int tmp = a[start + i].sort_index;
330766792f90SRichard Henderson a[start + i].sort_index = a[start + j].sort_index;
330866792f90SRichard Henderson a[start + j].sort_index = tmp;
3309c896fe29Sbellard }
3310c896fe29Sbellard }
3311c896fe29Sbellard }
3312c896fe29Sbellard }
3313c896fe29Sbellard
33143e80824eSRichard Henderson static const TCGArgConstraint empty_cts[TCG_MAX_OP_ARGS];
33153e80824eSRichard Henderson static TCGArgConstraint all_cts[ARRAY_SIZE(constraint_sets)][TCG_MAX_OP_ARGS];
33163e80824eSRichard Henderson
process_constraint_sets(void)3317501fb3daSRichard Henderson static void process_constraint_sets(void)
3318c896fe29Sbellard {
33193e80824eSRichard Henderson for (size_t c = 0; c < ARRAY_SIZE(constraint_sets); ++c) {
33203e80824eSRichard Henderson const TCGConstraintSet *tdefs = &constraint_sets[c];
33213e80824eSRichard Henderson TCGArgConstraint *args_ct = all_cts[c];
33223e80824eSRichard Henderson int nb_oargs = tdefs->nb_oargs;
33233e80824eSRichard Henderson int nb_iargs = tdefs->nb_iargs;
33243e80824eSRichard Henderson int nb_args = nb_oargs + nb_iargs;
332529f5e925SRichard Henderson bool saw_alias_pair = false;
3326f69d277eSRichard Henderson
33273e80824eSRichard Henderson for (int i = 0; i < nb_args; i++) {
3328f69d277eSRichard Henderson const char *ct_str = tdefs->args_ct_str[i];
33293e80824eSRichard Henderson bool input_p = i >= nb_oargs;
33303e80824eSRichard Henderson int o;
3331f69d277eSRichard Henderson
333217280ff4SRichard Henderson switch (*ct_str) {
333317280ff4SRichard Henderson case '0' ... '9':
33348940ea0dSPhilippe Mathieu-Daudé o = *ct_str - '0';
33358940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(input_p);
33363e80824eSRichard Henderson tcg_debug_assert(o < nb_oargs);
33373e80824eSRichard Henderson tcg_debug_assert(args_ct[o].regs != 0);
33383e80824eSRichard Henderson tcg_debug_assert(!args_ct[o].oalias);
33393e80824eSRichard Henderson args_ct[i] = args_ct[o];
3340bc2b17e6SRichard Henderson /* The output sets oalias. */
33413e80824eSRichard Henderson args_ct[o].oalias = 1;
33423e80824eSRichard Henderson args_ct[o].alias_index = i;
3343bc2b17e6SRichard Henderson /* The input sets ialias. */
33443e80824eSRichard Henderson args_ct[i].ialias = 1;
33453e80824eSRichard Henderson args_ct[i].alias_index = o;
33463e80824eSRichard Henderson if (args_ct[i].pair) {
334729f5e925SRichard Henderson saw_alias_pair = true;
334829f5e925SRichard Henderson }
33498940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(ct_str[1] == '\0');
33508940ea0dSPhilippe Mathieu-Daudé continue;
33518940ea0dSPhilippe Mathieu-Daudé
335282790a87SRichard Henderson case '&':
33538940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(!input_p);
33543e80824eSRichard Henderson args_ct[i].newreg = true;
335582790a87SRichard Henderson ct_str++;
335682790a87SRichard Henderson break;
335729f5e925SRichard Henderson
335829f5e925SRichard Henderson case 'p': /* plus */
335929f5e925SRichard Henderson /* Allocate to the register after the previous. */
33603e80824eSRichard Henderson tcg_debug_assert(i > (input_p ? nb_oargs : 0));
336129f5e925SRichard Henderson o = i - 1;
33623e80824eSRichard Henderson tcg_debug_assert(!args_ct[o].pair);
33633e80824eSRichard Henderson tcg_debug_assert(!args_ct[o].ct);
33643e80824eSRichard Henderson args_ct[i] = (TCGArgConstraint){
336529f5e925SRichard Henderson .pair = 2,
336629f5e925SRichard Henderson .pair_index = o,
33673e80824eSRichard Henderson .regs = args_ct[o].regs << 1,
33683e80824eSRichard Henderson .newreg = args_ct[o].newreg,
336929f5e925SRichard Henderson };
33703e80824eSRichard Henderson args_ct[o].pair = 1;
33713e80824eSRichard Henderson args_ct[o].pair_index = i;
337229f5e925SRichard Henderson tcg_debug_assert(ct_str[1] == '\0');
337329f5e925SRichard Henderson continue;
337429f5e925SRichard Henderson
337529f5e925SRichard Henderson case 'm': /* minus */
337629f5e925SRichard Henderson /* Allocate to the register before the previous. */
33773e80824eSRichard Henderson tcg_debug_assert(i > (input_p ? nb_oargs : 0));
337829f5e925SRichard Henderson o = i - 1;
33793e80824eSRichard Henderson tcg_debug_assert(!args_ct[o].pair);
33803e80824eSRichard Henderson tcg_debug_assert(!args_ct[o].ct);
33813e80824eSRichard Henderson args_ct[i] = (TCGArgConstraint){
338229f5e925SRichard Henderson .pair = 1,
338329f5e925SRichard Henderson .pair_index = o,
33843e80824eSRichard Henderson .regs = args_ct[o].regs >> 1,
33853e80824eSRichard Henderson .newreg = args_ct[o].newreg,
338629f5e925SRichard Henderson };
33873e80824eSRichard Henderson args_ct[o].pair = 2;
33883e80824eSRichard Henderson args_ct[o].pair_index = i;
338929f5e925SRichard Henderson tcg_debug_assert(ct_str[1] == '\0');
339029f5e925SRichard Henderson continue;
33918940ea0dSPhilippe Mathieu-Daudé }
33928940ea0dSPhilippe Mathieu-Daudé
33938940ea0dSPhilippe Mathieu-Daudé do {
33948940ea0dSPhilippe Mathieu-Daudé switch (*ct_str) {
3395c896fe29Sbellard case 'i':
33963e80824eSRichard Henderson args_ct[i].ct |= TCG_CT_CONST;
3397c896fe29Sbellard break;
33986b8abd24SRichard Henderson #ifdef TCG_REG_ZERO
33996b8abd24SRichard Henderson case 'z':
34006b8abd24SRichard Henderson args_ct[i].ct |= TCG_CT_REG_ZERO;
34016b8abd24SRichard Henderson break;
34026b8abd24SRichard Henderson #endif
3403358b4923SRichard Henderson
3404358b4923SRichard Henderson /* Include all of the target-specific constraints. */
3405358b4923SRichard Henderson
3406358b4923SRichard Henderson #undef CONST
3407358b4923SRichard Henderson #define CONST(CASE, MASK) \
34083e80824eSRichard Henderson case CASE: args_ct[i].ct |= MASK; break;
3409358b4923SRichard Henderson #define REGS(CASE, MASK) \
34103e80824eSRichard Henderson case CASE: args_ct[i].regs |= MASK; break;
3411358b4923SRichard Henderson
3412358b4923SRichard Henderson #include "tcg-target-con-str.h"
3413358b4923SRichard Henderson
3414358b4923SRichard Henderson #undef REGS
3415358b4923SRichard Henderson #undef CONST
3416c896fe29Sbellard default:
34178940ea0dSPhilippe Mathieu-Daudé case '0' ... '9':
34188940ea0dSPhilippe Mathieu-Daudé case '&':
341929f5e925SRichard Henderson case 'p':
342029f5e925SRichard Henderson case 'm':
34213e80824eSRichard Henderson /* Typo in TCGConstraintSet constraint. */
3422358b4923SRichard Henderson g_assert_not_reached();
3423358b4923SRichard Henderson }
34248940ea0dSPhilippe Mathieu-Daudé } while (*++ct_str != '\0');
3425c896fe29Sbellard }
3426c896fe29Sbellard
342729f5e925SRichard Henderson /*
342829f5e925SRichard Henderson * Fix up output pairs that are aliased with inputs.
342929f5e925SRichard Henderson * When we created the alias, we copied pair from the output.
343029f5e925SRichard Henderson * There are three cases:
343129f5e925SRichard Henderson * (1a) Pairs of inputs alias pairs of outputs.
343229f5e925SRichard Henderson * (1b) One input aliases the first of a pair of outputs.
343329f5e925SRichard Henderson * (2) One input aliases the second of a pair of outputs.
343429f5e925SRichard Henderson *
343529f5e925SRichard Henderson * Case 1a is handled by making sure that the pair_index'es are
343629f5e925SRichard Henderson * properly updated so that they appear the same as a pair of inputs.
343729f5e925SRichard Henderson *
343829f5e925SRichard Henderson * Case 1b is handled by setting the pair_index of the input to
343929f5e925SRichard Henderson * itself, simply so it doesn't point to an unrelated argument.
344029f5e925SRichard Henderson * Since we don't encounter the "second" during the input allocation
344129f5e925SRichard Henderson * phase, nothing happens with the second half of the input pair.
344229f5e925SRichard Henderson *
344329f5e925SRichard Henderson * Case 2 is handled by setting the second input to pair=3, the
344429f5e925SRichard Henderson * first output to pair=3, and the pair_index'es to match.
344529f5e925SRichard Henderson */
344629f5e925SRichard Henderson if (saw_alias_pair) {
34473e80824eSRichard Henderson for (int i = nb_oargs; i < nb_args; i++) {
34483e80824eSRichard Henderson int o, o2, i2;
34493e80824eSRichard Henderson
345029f5e925SRichard Henderson /*
345129f5e925SRichard Henderson * Since [0-9pm] must be alone in the constraint string,
345229f5e925SRichard Henderson * the only way they can both be set is if the pair comes
345329f5e925SRichard Henderson * from the output alias.
345429f5e925SRichard Henderson */
34553e80824eSRichard Henderson if (!args_ct[i].ialias) {
345629f5e925SRichard Henderson continue;
345729f5e925SRichard Henderson }
34583e80824eSRichard Henderson switch (args_ct[i].pair) {
345929f5e925SRichard Henderson case 0:
346029f5e925SRichard Henderson break;
346129f5e925SRichard Henderson case 1:
34623e80824eSRichard Henderson o = args_ct[i].alias_index;
34633e80824eSRichard Henderson o2 = args_ct[o].pair_index;
34643e80824eSRichard Henderson tcg_debug_assert(args_ct[o].pair == 1);
34653e80824eSRichard Henderson tcg_debug_assert(args_ct[o2].pair == 2);
34663e80824eSRichard Henderson if (args_ct[o2].oalias) {
346729f5e925SRichard Henderson /* Case 1a */
34683e80824eSRichard Henderson i2 = args_ct[o2].alias_index;
34693e80824eSRichard Henderson tcg_debug_assert(args_ct[i2].pair == 2);
34703e80824eSRichard Henderson args_ct[i2].pair_index = i;
34713e80824eSRichard Henderson args_ct[i].pair_index = i2;
347229f5e925SRichard Henderson } else {
347329f5e925SRichard Henderson /* Case 1b */
34743e80824eSRichard Henderson args_ct[i].pair_index = i;
347529f5e925SRichard Henderson }
347629f5e925SRichard Henderson break;
347729f5e925SRichard Henderson case 2:
34783e80824eSRichard Henderson o = args_ct[i].alias_index;
34793e80824eSRichard Henderson o2 = args_ct[o].pair_index;
34803e80824eSRichard Henderson tcg_debug_assert(args_ct[o].pair == 2);
34813e80824eSRichard Henderson tcg_debug_assert(args_ct[o2].pair == 1);
34823e80824eSRichard Henderson if (args_ct[o2].oalias) {
348329f5e925SRichard Henderson /* Case 1a */
34843e80824eSRichard Henderson i2 = args_ct[o2].alias_index;
34853e80824eSRichard Henderson tcg_debug_assert(args_ct[i2].pair == 1);
34863e80824eSRichard Henderson args_ct[i2].pair_index = i;
34873e80824eSRichard Henderson args_ct[i].pair_index = i2;
348829f5e925SRichard Henderson } else {
348929f5e925SRichard Henderson /* Case 2 */
34903e80824eSRichard Henderson args_ct[i].pair = 3;
34913e80824eSRichard Henderson args_ct[o2].pair = 3;
34923e80824eSRichard Henderson args_ct[i].pair_index = o2;
34933e80824eSRichard Henderson args_ct[o2].pair_index = i;
349429f5e925SRichard Henderson }
349529f5e925SRichard Henderson break;
349629f5e925SRichard Henderson default:
349729f5e925SRichard Henderson g_assert_not_reached();
349829f5e925SRichard Henderson }
349929f5e925SRichard Henderson }
350029f5e925SRichard Henderson }
350129f5e925SRichard Henderson
3502c896fe29Sbellard /* sort the constraints (XXX: this is just an heuristic) */
35033e80824eSRichard Henderson sort_constraints(args_ct, 0, nb_oargs);
35043e80824eSRichard Henderson sort_constraints(args_ct, nb_oargs, nb_iargs);
35053e80824eSRichard Henderson }
3506501fb3daSRichard Henderson }
35073e80824eSRichard Henderson
opcode_args_ct(const TCGOp * op)3508501fb3daSRichard Henderson static const TCGArgConstraint *opcode_args_ct(const TCGOp *op)
3509501fb3daSRichard Henderson {
35105500bd9eSRichard Henderson TCGOpcode opc = op->opc;
35115500bd9eSRichard Henderson TCGType type = TCGOP_TYPE(op);
35125500bd9eSRichard Henderson unsigned flags = TCGOP_FLAGS(op);
35135500bd9eSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc];
35145500bd9eSRichard Henderson const TCGOutOp *outop = all_outop[opc];
35153e80824eSRichard Henderson TCGConstraintSetIndex con_set;
35163e80824eSRichard Henderson
35173e80824eSRichard Henderson if (def->flags & TCG_OPF_NOT_PRESENT) {
3518501fb3daSRichard Henderson return empty_cts;
35193e80824eSRichard Henderson }
35203e80824eSRichard Henderson
35215500bd9eSRichard Henderson if (outop) {
35225500bd9eSRichard Henderson con_set = outop->static_constraint;
35235500bd9eSRichard Henderson if (con_set == C_Dynamic) {
35245500bd9eSRichard Henderson con_set = outop->dynamic_constraint(type, flags);
35255500bd9eSRichard Henderson }
35265500bd9eSRichard Henderson } else {
35275500bd9eSRichard Henderson con_set = tcg_target_op_def(opc, type, flags);
35285500bd9eSRichard Henderson }
35295500bd9eSRichard Henderson tcg_debug_assert(con_set >= 0);
35305500bd9eSRichard Henderson tcg_debug_assert(con_set < ARRAY_SIZE(constraint_sets));
35313e80824eSRichard Henderson
35323e80824eSRichard Henderson /* The constraint arguments must match TCGOpcode arguments. */
3533501fb3daSRichard Henderson tcg_debug_assert(constraint_sets[con_set].nb_oargs == def->nb_oargs);
3534501fb3daSRichard Henderson tcg_debug_assert(constraint_sets[con_set].nb_iargs == def->nb_iargs);
35353e80824eSRichard Henderson
3536501fb3daSRichard Henderson return all_cts[con_set];
3537c896fe29Sbellard }
3538c896fe29Sbellard
remove_label_use(TCGOp * op,int idx)3539f85b1fc4SRichard Henderson static void remove_label_use(TCGOp *op, int idx)
3540f85b1fc4SRichard Henderson {
3541f85b1fc4SRichard Henderson TCGLabel *label = arg_label(op->args[idx]);
3542f85b1fc4SRichard Henderson TCGLabelUse *use;
3543f85b1fc4SRichard Henderson
3544f85b1fc4SRichard Henderson QSIMPLEQ_FOREACH(use, &label->branches, next) {
3545f85b1fc4SRichard Henderson if (use->op == op) {
3546f85b1fc4SRichard Henderson QSIMPLEQ_REMOVE(&label->branches, use, TCGLabelUse, next);
3547f85b1fc4SRichard Henderson return;
3548f85b1fc4SRichard Henderson }
3549f85b1fc4SRichard Henderson }
3550f85b1fc4SRichard Henderson g_assert_not_reached();
3551f85b1fc4SRichard Henderson }
3552f85b1fc4SRichard Henderson
tcg_op_remove(TCGContext * s,TCGOp * op)35530c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op)
35540c627cdcSRichard Henderson {
3555d88a117eSRichard Henderson switch (op->opc) {
3556d88a117eSRichard Henderson case INDEX_op_br:
3557f85b1fc4SRichard Henderson remove_label_use(op, 0);
3558d88a117eSRichard Henderson break;
3559b6d69fceSRichard Henderson case INDEX_op_brcond:
3560f85b1fc4SRichard Henderson remove_label_use(op, 3);
3561d88a117eSRichard Henderson break;
3562d88a117eSRichard Henderson case INDEX_op_brcond2_i32:
3563f85b1fc4SRichard Henderson remove_label_use(op, 5);
3564d88a117eSRichard Henderson break;
3565d88a117eSRichard Henderson default:
3566d88a117eSRichard Henderson break;
3567d88a117eSRichard Henderson }
3568d88a117eSRichard Henderson
356915fa08f8SRichard Henderson QTAILQ_REMOVE(&s->ops, op, link);
357015fa08f8SRichard Henderson QTAILQ_INSERT_TAIL(&s->free_ops, op, link);
3571abebf925SRichard Henderson s->nb_ops--;
35720c627cdcSRichard Henderson }
35730c627cdcSRichard Henderson
tcg_remove_ops_after(TCGOp * op)3574a80cdd31SRichard Henderson void tcg_remove_ops_after(TCGOp *op)
3575a80cdd31SRichard Henderson {
3576a80cdd31SRichard Henderson TCGContext *s = tcg_ctx;
3577a80cdd31SRichard Henderson
3578a80cdd31SRichard Henderson while (true) {
3579a80cdd31SRichard Henderson TCGOp *last = tcg_last_op();
3580a80cdd31SRichard Henderson if (last == op) {
3581a80cdd31SRichard Henderson return;
3582a80cdd31SRichard Henderson }
3583a80cdd31SRichard Henderson tcg_op_remove(s, last);
3584a80cdd31SRichard Henderson }
3585a80cdd31SRichard Henderson }
3586a80cdd31SRichard Henderson
tcg_op_alloc(TCGOpcode opc,unsigned nargs)3587d4478943SPhilippe Mathieu-Daudé static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs)
358815fa08f8SRichard Henderson {
358915fa08f8SRichard Henderson TCGContext *s = tcg_ctx;
3590cb10bc63SRichard Henderson TCGOp *op = NULL;
359115fa08f8SRichard Henderson
3592cb10bc63SRichard Henderson if (unlikely(!QTAILQ_EMPTY(&s->free_ops))) {
3593cb10bc63SRichard Henderson QTAILQ_FOREACH(op, &s->free_ops, link) {
3594cb10bc63SRichard Henderson if (nargs <= op->nargs) {
359515fa08f8SRichard Henderson QTAILQ_REMOVE(&s->free_ops, op, link);
3596cb10bc63SRichard Henderson nargs = op->nargs;
3597cb10bc63SRichard Henderson goto found;
359815fa08f8SRichard Henderson }
3599cb10bc63SRichard Henderson }
3600cb10bc63SRichard Henderson }
3601cb10bc63SRichard Henderson
3602cb10bc63SRichard Henderson /* Most opcodes have 3 or 4 operands: reduce fragmentation. */
3603cb10bc63SRichard Henderson nargs = MAX(4, nargs);
3604cb10bc63SRichard Henderson op = tcg_malloc(sizeof(TCGOp) + sizeof(TCGArg) * nargs);
3605cb10bc63SRichard Henderson
3606cb10bc63SRichard Henderson found:
360715fa08f8SRichard Henderson memset(op, 0, offsetof(TCGOp, link));
360815fa08f8SRichard Henderson op->opc = opc;
3609cb10bc63SRichard Henderson op->nargs = nargs;
361015fa08f8SRichard Henderson
3611cb10bc63SRichard Henderson /* Check for bitfield overflow. */
3612cb10bc63SRichard Henderson tcg_debug_assert(op->nargs == nargs);
3613cb10bc63SRichard Henderson
3614cb10bc63SRichard Henderson s->nb_ops++;
361515fa08f8SRichard Henderson return op;
361615fa08f8SRichard Henderson }
361715fa08f8SRichard Henderson
tcg_emit_op(TCGOpcode opc,unsigned nargs)3618d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_emit_op(TCGOpcode opc, unsigned nargs)
361915fa08f8SRichard Henderson {
3620d4478943SPhilippe Mathieu-Daudé TCGOp *op = tcg_op_alloc(opc, nargs);
362107843f75SRichard Henderson
362207843f75SRichard Henderson if (tcg_ctx->emit_before_op) {
362307843f75SRichard Henderson QTAILQ_INSERT_BEFORE(tcg_ctx->emit_before_op, op, link);
362407843f75SRichard Henderson } else {
362515fa08f8SRichard Henderson QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
362607843f75SRichard Henderson }
362715fa08f8SRichard Henderson return op;
362815fa08f8SRichard Henderson }
362915fa08f8SRichard Henderson
tcg_op_insert_before(TCGContext * s,TCGOp * old_op,TCGOpcode opc,TCGType type,unsigned nargs)3630d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op,
3631cf5c9f69SRichard Henderson TCGOpcode opc, TCGType type, unsigned nargs)
36325a18407fSRichard Henderson {
3633d4478943SPhilippe Mathieu-Daudé TCGOp *new_op = tcg_op_alloc(opc, nargs);
3634fb744eceSRichard Henderson
3635cf5c9f69SRichard Henderson TCGOP_TYPE(new_op) = type;
363615fa08f8SRichard Henderson QTAILQ_INSERT_BEFORE(old_op, new_op, link);
36375a18407fSRichard Henderson return new_op;
36385a18407fSRichard Henderson }
36395a18407fSRichard Henderson
tcg_op_insert_after(TCGContext * s,TCGOp * old_op,TCGOpcode opc,TCGType type,unsigned nargs)3640d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op,
3641cf5c9f69SRichard Henderson TCGOpcode opc, TCGType type, unsigned nargs)
36425a18407fSRichard Henderson {
3643d4478943SPhilippe Mathieu-Daudé TCGOp *new_op = tcg_op_alloc(opc, nargs);
3644fb744eceSRichard Henderson
3645cf5c9f69SRichard Henderson TCGOP_TYPE(new_op) = type;
364615fa08f8SRichard Henderson QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link);
36475a18407fSRichard Henderson return new_op;
36485a18407fSRichard Henderson }
36495a18407fSRichard Henderson
move_label_uses(TCGLabel * to,TCGLabel * from)3650968f305eSRichard Henderson static void move_label_uses(TCGLabel *to, TCGLabel *from)
3651968f305eSRichard Henderson {
3652968f305eSRichard Henderson TCGLabelUse *u;
3653968f305eSRichard Henderson
3654968f305eSRichard Henderson QSIMPLEQ_FOREACH(u, &from->branches, next) {
3655968f305eSRichard Henderson TCGOp *op = u->op;
3656968f305eSRichard Henderson switch (op->opc) {
3657968f305eSRichard Henderson case INDEX_op_br:
3658968f305eSRichard Henderson op->args[0] = label_arg(to);
3659968f305eSRichard Henderson break;
3660b6d69fceSRichard Henderson case INDEX_op_brcond:
3661968f305eSRichard Henderson op->args[3] = label_arg(to);
3662968f305eSRichard Henderson break;
3663968f305eSRichard Henderson case INDEX_op_brcond2_i32:
3664968f305eSRichard Henderson op->args[5] = label_arg(to);
3665968f305eSRichard Henderson break;
3666968f305eSRichard Henderson default:
3667968f305eSRichard Henderson g_assert_not_reached();
3668968f305eSRichard Henderson }
3669968f305eSRichard Henderson }
3670968f305eSRichard Henderson
3671968f305eSRichard Henderson QSIMPLEQ_CONCAT(&to->branches, &from->branches);
3672968f305eSRichard Henderson }
3673968f305eSRichard Henderson
3674b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code. */
36759bbee4c0SRichard Henderson static void __attribute__((noinline))
reachable_code_pass(TCGContext * s)36769bbee4c0SRichard Henderson reachable_code_pass(TCGContext *s)
3677b4fc67c7SRichard Henderson {
36784d89d0bbSRichard Henderson TCGOp *op, *op_next, *op_prev;
3679b4fc67c7SRichard Henderson bool dead = false;
3680b4fc67c7SRichard Henderson
3681b4fc67c7SRichard Henderson QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
3682b4fc67c7SRichard Henderson bool remove = dead;
3683b4fc67c7SRichard Henderson TCGLabel *label;
3684b4fc67c7SRichard Henderson
3685b4fc67c7SRichard Henderson switch (op->opc) {
3686b4fc67c7SRichard Henderson case INDEX_op_set_label:
3687b4fc67c7SRichard Henderson label = arg_label(op->args[0]);
36884d89d0bbSRichard Henderson
36894d89d0bbSRichard Henderson /*
3690968f305eSRichard Henderson * Note that the first op in the TB is always a load,
3691968f305eSRichard Henderson * so there is always something before a label.
3692968f305eSRichard Henderson */
3693968f305eSRichard Henderson op_prev = QTAILQ_PREV(op, link);
3694968f305eSRichard Henderson
3695968f305eSRichard Henderson /*
3696968f305eSRichard Henderson * If we find two sequential labels, move all branches to
3697968f305eSRichard Henderson * reference the second label and remove the first label.
3698968f305eSRichard Henderson * Do this before branch to next optimization, so that the
3699968f305eSRichard Henderson * middle label is out of the way.
3700968f305eSRichard Henderson */
3701968f305eSRichard Henderson if (op_prev->opc == INDEX_op_set_label) {
3702968f305eSRichard Henderson move_label_uses(label, arg_label(op_prev->args[0]));
3703968f305eSRichard Henderson tcg_op_remove(s, op_prev);
3704968f305eSRichard Henderson op_prev = QTAILQ_PREV(op, link);
3705968f305eSRichard Henderson }
3706968f305eSRichard Henderson
3707968f305eSRichard Henderson /*
37084d89d0bbSRichard Henderson * Optimization can fold conditional branches to unconditional.
37094d89d0bbSRichard Henderson * If we find a label which is preceded by an unconditional
37104d89d0bbSRichard Henderson * branch to next, remove the branch. We couldn't do this when
37114d89d0bbSRichard Henderson * processing the branch because any dead code between the branch
37124d89d0bbSRichard Henderson * and label had not yet been removed.
37134d89d0bbSRichard Henderson */
37144d89d0bbSRichard Henderson if (op_prev->opc == INDEX_op_br &&
37154d89d0bbSRichard Henderson label == arg_label(op_prev->args[0])) {
37164d89d0bbSRichard Henderson tcg_op_remove(s, op_prev);
37174d89d0bbSRichard Henderson /* Fall through means insns become live again. */
37184d89d0bbSRichard Henderson dead = false;
37194d89d0bbSRichard Henderson }
37204d89d0bbSRichard Henderson
3721f85b1fc4SRichard Henderson if (QSIMPLEQ_EMPTY(&label->branches)) {
3722b4fc67c7SRichard Henderson /*
3723b4fc67c7SRichard Henderson * While there is an occasional backward branch, virtually
3724b4fc67c7SRichard Henderson * all branches generated by the translators are forward.
3725b4fc67c7SRichard Henderson * Which means that generally we will have already removed
3726b4fc67c7SRichard Henderson * all references to the label that will be, and there is
3727b4fc67c7SRichard Henderson * little to be gained by iterating.
3728b4fc67c7SRichard Henderson */
3729b4fc67c7SRichard Henderson remove = true;
3730b4fc67c7SRichard Henderson } else {
3731b4fc67c7SRichard Henderson /* Once we see a label, insns become live again. */
3732b4fc67c7SRichard Henderson dead = false;
3733b4fc67c7SRichard Henderson remove = false;
3734b4fc67c7SRichard Henderson }
3735b4fc67c7SRichard Henderson break;
3736b4fc67c7SRichard Henderson
3737b4fc67c7SRichard Henderson case INDEX_op_br:
3738b4fc67c7SRichard Henderson case INDEX_op_exit_tb:
3739b4fc67c7SRichard Henderson case INDEX_op_goto_ptr:
3740b4fc67c7SRichard Henderson /* Unconditional branches; everything following is dead. */
3741b4fc67c7SRichard Henderson dead = true;
3742b4fc67c7SRichard Henderson break;
3743b4fc67c7SRichard Henderson
3744b4fc67c7SRichard Henderson case INDEX_op_call:
3745b4fc67c7SRichard Henderson /* Notice noreturn helper calls, raising exceptions. */
374690163900SRichard Henderson if (tcg_call_flags(op) & TCG_CALL_NO_RETURN) {
3747b4fc67c7SRichard Henderson dead = true;
3748b4fc67c7SRichard Henderson }
3749b4fc67c7SRichard Henderson break;
3750b4fc67c7SRichard Henderson
3751b4fc67c7SRichard Henderson case INDEX_op_insn_start:
3752b4fc67c7SRichard Henderson /* Never remove -- we need to keep these for unwind. */
3753b4fc67c7SRichard Henderson remove = false;
3754b4fc67c7SRichard Henderson break;
3755b4fc67c7SRichard Henderson
3756b4fc67c7SRichard Henderson default:
3757b4fc67c7SRichard Henderson break;
3758b4fc67c7SRichard Henderson }
3759b4fc67c7SRichard Henderson
3760b4fc67c7SRichard Henderson if (remove) {
3761b4fc67c7SRichard Henderson tcg_op_remove(s, op);
3762b4fc67c7SRichard Henderson }
3763b4fc67c7SRichard Henderson }
3764b4fc67c7SRichard Henderson }
3765b4fc67c7SRichard Henderson
3766c70fbf0aSRichard Henderson #define TS_DEAD 1
3767c70fbf0aSRichard Henderson #define TS_MEM 2
3768c70fbf0aSRichard Henderson
37695a18407fSRichard Henderson #define IS_DEAD_ARG(n) (arg_life & (DEAD_ARG << (n)))
37705a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n)))
37715a18407fSRichard Henderson
377225f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp. */
la_temp_pref(TCGTemp * ts)377325f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts)
377425f49c5fSRichard Henderson {
377525f49c5fSRichard Henderson return ts->state_ptr;
377625f49c5fSRichard Henderson }
377725f49c5fSRichard Henderson
377825f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the
377925f49c5fSRichard Henderson * maximal regset for its type.
378025f49c5fSRichard Henderson */
la_reset_pref(TCGTemp * ts)378125f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts)
378225f49c5fSRichard Henderson {
378325f49c5fSRichard Henderson *la_temp_pref(ts)
378425f49c5fSRichard Henderson = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]);
378525f49c5fSRichard Henderson }
378625f49c5fSRichard Henderson
37879c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals
37889c43b68dSAurelien Jarno should be in memory. */
la_func_end(TCGContext * s,int ng,int nt)37892616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt)
3790c896fe29Sbellard {
3791b83eabeaSRichard Henderson int i;
3792b83eabeaSRichard Henderson
3793b83eabeaSRichard Henderson for (i = 0; i < ng; ++i) {
3794b83eabeaSRichard Henderson s->temps[i].state = TS_DEAD | TS_MEM;
379525f49c5fSRichard Henderson la_reset_pref(&s->temps[i]);
3796b83eabeaSRichard Henderson }
3797b83eabeaSRichard Henderson for (i = ng; i < nt; ++i) {
3798b83eabeaSRichard Henderson s->temps[i].state = TS_DEAD;
379925f49c5fSRichard Henderson la_reset_pref(&s->temps[i]);
3800b83eabeaSRichard Henderson }
3801c896fe29Sbellard }
3802c896fe29Sbellard
38039c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals
38049c43b68dSAurelien Jarno and local temps should be in memory. */
la_bb_end(TCGContext * s,int ng,int nt)38052616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt)
3806641d5fbeSbellard {
3807b83eabeaSRichard Henderson int i;
3808641d5fbeSbellard
3809ee17db83SRichard Henderson for (i = 0; i < nt; ++i) {
3810ee17db83SRichard Henderson TCGTemp *ts = &s->temps[i];
3811ee17db83SRichard Henderson int state;
3812ee17db83SRichard Henderson
3813ee17db83SRichard Henderson switch (ts->kind) {
3814ee17db83SRichard Henderson case TEMP_FIXED:
3815ee17db83SRichard Henderson case TEMP_GLOBAL:
3816f57c6915SRichard Henderson case TEMP_TB:
3817ee17db83SRichard Henderson state = TS_DEAD | TS_MEM;
3818ee17db83SRichard Henderson break;
3819c7482438SRichard Henderson case TEMP_EBB:
3820c0522136SRichard Henderson case TEMP_CONST:
3821ee17db83SRichard Henderson state = TS_DEAD;
3822ee17db83SRichard Henderson break;
3823ee17db83SRichard Henderson default:
3824ee17db83SRichard Henderson g_assert_not_reached();
3825c70fbf0aSRichard Henderson }
3826ee17db83SRichard Henderson ts->state = state;
3827ee17db83SRichard Henderson la_reset_pref(ts);
3828641d5fbeSbellard }
3829641d5fbeSbellard }
3830641d5fbeSbellard
3831f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory. */
la_global_sync(TCGContext * s,int ng)3832f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng)
3833f65a061cSRichard Henderson {
3834f65a061cSRichard Henderson int i;
3835f65a061cSRichard Henderson
3836f65a061cSRichard Henderson for (i = 0; i < ng; ++i) {
383725f49c5fSRichard Henderson int state = s->temps[i].state;
383825f49c5fSRichard Henderson s->temps[i].state = state | TS_MEM;
383925f49c5fSRichard Henderson if (state == TS_DEAD) {
384025f49c5fSRichard Henderson /* If the global was previously dead, reset prefs. */
384125f49c5fSRichard Henderson la_reset_pref(&s->temps[i]);
384225f49c5fSRichard Henderson }
3843f65a061cSRichard Henderson }
3844f65a061cSRichard Henderson }
3845f65a061cSRichard Henderson
3846b4cb76e6SRichard Henderson /*
3847c7482438SRichard Henderson * liveness analysis: conditional branch: all temps are dead unless
3848c7482438SRichard Henderson * explicitly live-across-conditional-branch, globals and local temps
3849c7482438SRichard Henderson * should be synced.
3850b4cb76e6SRichard Henderson */
la_bb_sync(TCGContext * s,int ng,int nt)3851b4cb76e6SRichard Henderson static void la_bb_sync(TCGContext *s, int ng, int nt)
3852b4cb76e6SRichard Henderson {
3853b4cb76e6SRichard Henderson la_global_sync(s, ng);
3854b4cb76e6SRichard Henderson
3855b4cb76e6SRichard Henderson for (int i = ng; i < nt; ++i) {
3856c0522136SRichard Henderson TCGTemp *ts = &s->temps[i];
3857c0522136SRichard Henderson int state;
3858c0522136SRichard Henderson
3859c0522136SRichard Henderson switch (ts->kind) {
3860f57c6915SRichard Henderson case TEMP_TB:
3861c0522136SRichard Henderson state = ts->state;
3862c0522136SRichard Henderson ts->state = state | TS_MEM;
3863b4cb76e6SRichard Henderson if (state != TS_DEAD) {
3864b4cb76e6SRichard Henderson continue;
3865b4cb76e6SRichard Henderson }
3866c0522136SRichard Henderson break;
3867c7482438SRichard Henderson case TEMP_EBB:
3868c0522136SRichard Henderson case TEMP_CONST:
3869c0522136SRichard Henderson continue;
3870c0522136SRichard Henderson default:
3871c0522136SRichard Henderson g_assert_not_reached();
3872b4cb76e6SRichard Henderson }
3873b4cb76e6SRichard Henderson la_reset_pref(&s->temps[i]);
3874b4cb76e6SRichard Henderson }
3875b4cb76e6SRichard Henderson }
3876b4cb76e6SRichard Henderson
3877f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill. */
la_global_kill(TCGContext * s,int ng)3878f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng)
3879f65a061cSRichard Henderson {
3880f65a061cSRichard Henderson int i;
3881f65a061cSRichard Henderson
3882f65a061cSRichard Henderson for (i = 0; i < ng; i++) {
3883f65a061cSRichard Henderson s->temps[i].state = TS_DEAD | TS_MEM;
388425f49c5fSRichard Henderson la_reset_pref(&s->temps[i]);
388525f49c5fSRichard Henderson }
388625f49c5fSRichard Henderson }
388725f49c5fSRichard Henderson
388825f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls. */
la_cross_call(TCGContext * s,int nt)388925f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt)
389025f49c5fSRichard Henderson {
389125f49c5fSRichard Henderson TCGRegSet mask = ~tcg_target_call_clobber_regs;
389225f49c5fSRichard Henderson int i;
389325f49c5fSRichard Henderson
389425f49c5fSRichard Henderson for (i = 0; i < nt; i++) {
389525f49c5fSRichard Henderson TCGTemp *ts = &s->temps[i];
389625f49c5fSRichard Henderson if (!(ts->state & TS_DEAD)) {
389725f49c5fSRichard Henderson TCGRegSet *pset = la_temp_pref(ts);
389825f49c5fSRichard Henderson TCGRegSet set = *pset;
389925f49c5fSRichard Henderson
390025f49c5fSRichard Henderson set &= mask;
390125f49c5fSRichard Henderson /* If the combination is not possible, restart. */
390225f49c5fSRichard Henderson if (set == 0) {
390325f49c5fSRichard Henderson set = tcg_target_available_regs[ts->type] & mask;
390425f49c5fSRichard Henderson }
390525f49c5fSRichard Henderson *pset = set;
390625f49c5fSRichard Henderson }
3907f65a061cSRichard Henderson }
3908f65a061cSRichard Henderson }
3909f65a061cSRichard Henderson
3910874b8574SRichard Henderson /*
3911874b8574SRichard Henderson * Liveness analysis: Verify the lifetime of TEMP_TB, and reduce
3912874b8574SRichard Henderson * to TEMP_EBB, if possible.
3913874b8574SRichard Henderson */
3914874b8574SRichard Henderson static void __attribute__((noinline))
liveness_pass_0(TCGContext * s)3915874b8574SRichard Henderson liveness_pass_0(TCGContext *s)
3916874b8574SRichard Henderson {
3917874b8574SRichard Henderson void * const multiple_ebb = (void *)(uintptr_t)-1;
3918874b8574SRichard Henderson int nb_temps = s->nb_temps;
3919874b8574SRichard Henderson TCGOp *op, *ebb;
3920874b8574SRichard Henderson
3921874b8574SRichard Henderson for (int i = s->nb_globals; i < nb_temps; ++i) {
3922874b8574SRichard Henderson s->temps[i].state_ptr = NULL;
3923874b8574SRichard Henderson }
3924874b8574SRichard Henderson
3925874b8574SRichard Henderson /*
3926874b8574SRichard Henderson * Represent each EBB by the op at which it begins. In the case of
3927874b8574SRichard Henderson * the first EBB, this is the first op, otherwise it is a label.
3928874b8574SRichard Henderson * Collect the uses of each TEMP_TB: NULL for unused, EBB for use
3929874b8574SRichard Henderson * within a single EBB, else MULTIPLE_EBB.
3930874b8574SRichard Henderson */
3931874b8574SRichard Henderson ebb = QTAILQ_FIRST(&s->ops);
3932874b8574SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) {
3933874b8574SRichard Henderson const TCGOpDef *def;
3934874b8574SRichard Henderson int nb_oargs, nb_iargs;
3935874b8574SRichard Henderson
3936874b8574SRichard Henderson switch (op->opc) {
3937874b8574SRichard Henderson case INDEX_op_set_label:
3938874b8574SRichard Henderson ebb = op;
3939874b8574SRichard Henderson continue;
3940874b8574SRichard Henderson case INDEX_op_discard:
3941874b8574SRichard Henderson continue;
3942874b8574SRichard Henderson case INDEX_op_call:
3943874b8574SRichard Henderson nb_oargs = TCGOP_CALLO(op);
3944874b8574SRichard Henderson nb_iargs = TCGOP_CALLI(op);
3945874b8574SRichard Henderson break;
3946874b8574SRichard Henderson default:
3947874b8574SRichard Henderson def = &tcg_op_defs[op->opc];
3948874b8574SRichard Henderson nb_oargs = def->nb_oargs;
3949874b8574SRichard Henderson nb_iargs = def->nb_iargs;
3950874b8574SRichard Henderson break;
3951874b8574SRichard Henderson }
3952874b8574SRichard Henderson
3953874b8574SRichard Henderson for (int i = 0; i < nb_oargs + nb_iargs; ++i) {
3954874b8574SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]);
3955874b8574SRichard Henderson
3956874b8574SRichard Henderson if (ts->kind != TEMP_TB) {
3957874b8574SRichard Henderson continue;
3958874b8574SRichard Henderson }
3959874b8574SRichard Henderson if (ts->state_ptr == NULL) {
3960874b8574SRichard Henderson ts->state_ptr = ebb;
3961874b8574SRichard Henderson } else if (ts->state_ptr != ebb) {
3962874b8574SRichard Henderson ts->state_ptr = multiple_ebb;
3963874b8574SRichard Henderson }
3964874b8574SRichard Henderson }
3965874b8574SRichard Henderson }
3966874b8574SRichard Henderson
3967874b8574SRichard Henderson /*
3968874b8574SRichard Henderson * For TEMP_TB that turned out not to be used beyond one EBB,
3969874b8574SRichard Henderson * reduce the liveness to TEMP_EBB.
3970874b8574SRichard Henderson */
3971874b8574SRichard Henderson for (int i = s->nb_globals; i < nb_temps; ++i) {
3972874b8574SRichard Henderson TCGTemp *ts = &s->temps[i];
3973874b8574SRichard Henderson if (ts->kind == TEMP_TB && ts->state_ptr != multiple_ebb) {
3974874b8574SRichard Henderson ts->kind = TEMP_EBB;
3975874b8574SRichard Henderson }
3976874b8574SRichard Henderson }
3977874b8574SRichard Henderson }
3978874b8574SRichard Henderson
assert_carry_dead(TCGContext * s)397976f42780SRichard Henderson static void assert_carry_dead(TCGContext *s)
398076f42780SRichard Henderson {
398176f42780SRichard Henderson /*
398276f42780SRichard Henderson * Carry operations can be separated by a few insns like mov,
398376f42780SRichard Henderson * load or store, but they should always be "close", and
398476f42780SRichard Henderson * carry-out operations should always be paired with carry-in.
398576f42780SRichard Henderson * At various boundaries, carry must have been consumed.
398676f42780SRichard Henderson */
398776f42780SRichard Henderson tcg_debug_assert(!s->carry_live);
398876f42780SRichard Henderson }
398976f42780SRichard Henderson
3990a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a
3991c896fe29Sbellard given input arguments is dead. Instructions updating dead
3992c896fe29Sbellard temporaries are removed. */
39939bbee4c0SRichard Henderson static void __attribute__((noinline))
liveness_pass_1(TCGContext * s)39949bbee4c0SRichard Henderson liveness_pass_1(TCGContext *s)
3995c896fe29Sbellard {
3996c70fbf0aSRichard Henderson int nb_globals = s->nb_globals;
39972616c808SRichard Henderson int nb_temps = s->nb_temps;
399815fa08f8SRichard Henderson TCGOp *op, *op_prev;
399925f49c5fSRichard Henderson TCGRegSet *prefs;
400025f49c5fSRichard Henderson
400125f49c5fSRichard Henderson prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps);
40027d10d8e0SRichard Henderson for (int i = 0; i < nb_temps; ++i) {
400325f49c5fSRichard Henderson s->temps[i].state_ptr = prefs + i;
400425f49c5fSRichard Henderson }
4005c896fe29Sbellard
4006ae36a246SRichard Henderson /* ??? Should be redundant with the exit_tb that ends the TB. */
40072616c808SRichard Henderson la_func_end(s, nb_globals, nb_temps);
4008c896fe29Sbellard
400976f42780SRichard Henderson s->carry_live = false;
4010eae3eb3eSPaolo Bonzini QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) {
401125f49c5fSRichard Henderson int nb_iargs, nb_oargs;
4012c45cb8bbSRichard Henderson TCGOpcode opc_new, opc_new2;
4013a1b3c48dSRichard Henderson TCGLifeData arg_life = 0;
401425f49c5fSRichard Henderson TCGTemp *ts;
4015c45cb8bbSRichard Henderson TCGOpcode opc = op->opc;
401676f42780SRichard Henderson const TCGOpDef *def;
4017501fb3daSRichard Henderson const TCGArgConstraint *args_ct;
4018c45cb8bbSRichard Henderson
4019c45cb8bbSRichard Henderson switch (opc) {
4020c896fe29Sbellard case INDEX_op_call:
402176f42780SRichard Henderson assert_carry_dead(s);
4022c6e113f5Sbellard {
402339004a71SRichard Henderson const TCGHelperInfo *info = tcg_call_info(op);
402439004a71SRichard Henderson int call_flags = tcg_call_flags(op);
4025c6e113f5Sbellard
4026cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op);
4027cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op);
4028c6e113f5Sbellard
4029c45cb8bbSRichard Henderson /* pure functions can be removed if their result is unused */
403078505279SAurelien Jarno if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) {
40317d10d8e0SRichard Henderson for (int i = 0; i < nb_oargs; i++) {
403225f49c5fSRichard Henderson ts = arg_temp(op->args[i]);
403325f49c5fSRichard Henderson if (ts->state != TS_DEAD) {
4034c6e113f5Sbellard goto do_not_remove_call;
4035c6e113f5Sbellard }
40369c43b68dSAurelien Jarno }
4037c45cb8bbSRichard Henderson goto do_remove;
4038152c35aaSRichard Henderson }
4039c6e113f5Sbellard do_not_remove_call:
4040c896fe29Sbellard
404125f49c5fSRichard Henderson /* Output args are dead. */
40427d10d8e0SRichard Henderson for (int i = 0; i < nb_oargs; i++) {
404325f49c5fSRichard Henderson ts = arg_temp(op->args[i]);
404425f49c5fSRichard Henderson if (ts->state & TS_DEAD) {
4045a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i;
40466b64b624SAurelien Jarno }
404725f49c5fSRichard Henderson if (ts->state & TS_MEM) {
4048a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i;
40499c43b68dSAurelien Jarno }
405025f49c5fSRichard Henderson ts->state = TS_DEAD;
405125f49c5fSRichard Henderson la_reset_pref(ts);
4052c896fe29Sbellard }
4053c896fe29Sbellard
405431fd884bSRichard Henderson /* Not used -- it will be tcg_target_call_oarg_reg(). */
405531fd884bSRichard Henderson memset(op->output_pref, 0, sizeof(op->output_pref));
405631fd884bSRichard Henderson
405778505279SAurelien Jarno if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS |
405878505279SAurelien Jarno TCG_CALL_NO_READ_GLOBALS))) {
4059f65a061cSRichard Henderson la_global_kill(s, nb_globals);
4060c70fbf0aSRichard Henderson } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) {
4061f65a061cSRichard Henderson la_global_sync(s, nb_globals);
4062b9c18f56Saurel32 }
4063c896fe29Sbellard
406425f49c5fSRichard Henderson /* Record arguments that die in this helper. */
40657d10d8e0SRichard Henderson for (int i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
406625f49c5fSRichard Henderson ts = arg_temp(op->args[i]);
406739004a71SRichard Henderson if (ts->state & TS_DEAD) {
4068a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i;
4069c896fe29Sbellard }
4070c896fe29Sbellard }
407125f49c5fSRichard Henderson
407225f49c5fSRichard Henderson /* For all live registers, remove call-clobbered prefs. */
407325f49c5fSRichard Henderson la_cross_call(s, nb_temps);
407425f49c5fSRichard Henderson
407539004a71SRichard Henderson /*
407639004a71SRichard Henderson * Input arguments are live for preceding opcodes.
407739004a71SRichard Henderson *
407839004a71SRichard Henderson * For those arguments that die, and will be allocated in
407939004a71SRichard Henderson * registers, clear the register set for that arg, to be
408039004a71SRichard Henderson * filled in below. For args that will be on the stack,
408139004a71SRichard Henderson * reset to any available reg. Process arguments in reverse
408239004a71SRichard Henderson * order so that if a temp is used more than once, the stack
408339004a71SRichard Henderson * reset to max happens before the register reset to 0.
408425f49c5fSRichard Henderson */
40857d10d8e0SRichard Henderson for (int i = nb_iargs - 1; i >= 0; i--) {
408639004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i];
408739004a71SRichard Henderson ts = arg_temp(op->args[nb_oargs + i]);
408839004a71SRichard Henderson
408939004a71SRichard Henderson if (ts->state & TS_DEAD) {
409039004a71SRichard Henderson switch (loc->kind) {
409139004a71SRichard Henderson case TCG_CALL_ARG_NORMAL:
409239004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U:
409339004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S:
4094338b61e9SRichard Henderson if (arg_slot_reg_p(loc->arg_slot)) {
409539004a71SRichard Henderson *la_temp_pref(ts) = 0;
409639004a71SRichard Henderson break;
409739004a71SRichard Henderson }
409839004a71SRichard Henderson /* fall through */
409939004a71SRichard Henderson default:
410039004a71SRichard Henderson *la_temp_pref(ts) =
410139004a71SRichard Henderson tcg_target_available_regs[ts->type];
410239004a71SRichard Henderson break;
410339004a71SRichard Henderson }
410425f49c5fSRichard Henderson ts->state &= ~TS_DEAD;
410525f49c5fSRichard Henderson }
410625f49c5fSRichard Henderson }
410725f49c5fSRichard Henderson
410839004a71SRichard Henderson /*
410939004a71SRichard Henderson * For each input argument, add its input register to prefs.
411039004a71SRichard Henderson * If a temp is used once, this produces a single set bit;
411139004a71SRichard Henderson * if a temp is used multiple times, this produces a set.
411239004a71SRichard Henderson */
41137d10d8e0SRichard Henderson for (int i = 0; i < nb_iargs; i++) {
411439004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i];
411539004a71SRichard Henderson ts = arg_temp(op->args[nb_oargs + i]);
411639004a71SRichard Henderson
411739004a71SRichard Henderson switch (loc->kind) {
411839004a71SRichard Henderson case TCG_CALL_ARG_NORMAL:
411939004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U:
412039004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S:
4121338b61e9SRichard Henderson if (arg_slot_reg_p(loc->arg_slot)) {
412225f49c5fSRichard Henderson tcg_regset_set_reg(*la_temp_pref(ts),
412339004a71SRichard Henderson tcg_target_call_iarg_regs[loc->arg_slot]);
412439004a71SRichard Henderson }
412539004a71SRichard Henderson break;
412639004a71SRichard Henderson default:
412739004a71SRichard Henderson break;
4128c70fbf0aSRichard Henderson }
4129c19f47bfSAurelien Jarno }
4130c6e113f5Sbellard }
4131c896fe29Sbellard break;
4132765b842aSRichard Henderson case INDEX_op_insn_start:
413376f42780SRichard Henderson assert_carry_dead(s);
4134c896fe29Sbellard break;
41355ff9d6a4Sbellard case INDEX_op_discard:
41365ff9d6a4Sbellard /* mark the temporary as dead */
413725f49c5fSRichard Henderson ts = arg_temp(op->args[0]);
413825f49c5fSRichard Henderson ts->state = TS_DEAD;
413925f49c5fSRichard Henderson la_reset_pref(ts);
41405ff9d6a4Sbellard break;
41411305c451SRichard Henderson
4142bfe96480SRichard Henderson case INDEX_op_muls2:
4143d2c3ecadSRichard Henderson opc_new = INDEX_op_mul;
4144c742824dSRichard Henderson opc_new2 = INDEX_op_mulsh;
4145f1fae40cSRichard Henderson goto do_mul2;
4146d776198cSRichard Henderson case INDEX_op_mulu2:
4147d2c3ecadSRichard Henderson opc_new = INDEX_op_mul;
4148aa28c9efSRichard Henderson opc_new2 = INDEX_op_muluh;
4149f1fae40cSRichard Henderson do_mul2:
415076f42780SRichard Henderson assert_carry_dead(s);
4151b83eabeaSRichard Henderson if (arg_temp(op->args[1])->state == TS_DEAD) {
4152b83eabeaSRichard Henderson if (arg_temp(op->args[0])->state == TS_DEAD) {
415303271524SRichard Henderson /* Both parts of the operation are dead. */
41541414968aSRichard Henderson goto do_remove;
41551414968aSRichard Henderson }
415603271524SRichard Henderson /* The high part of the operation is dead; generate the low. */
4157c45cb8bbSRichard Henderson op->opc = opc = opc_new;
4158efee3746SRichard Henderson op->args[1] = op->args[2];
4159efee3746SRichard Henderson op->args[2] = op->args[3];
4160937246f2SRichard Henderson } else if (arg_temp(op->args[0])->state == TS_DEAD &&
4161937246f2SRichard Henderson tcg_op_supported(opc_new2, TCGOP_TYPE(op), 0)) {
416203271524SRichard Henderson /* The low part of the operation is dead; generate the high. */
4163c45cb8bbSRichard Henderson op->opc = opc = opc_new2;
4164efee3746SRichard Henderson op->args[0] = op->args[1];
4165efee3746SRichard Henderson op->args[1] = op->args[2];
4166efee3746SRichard Henderson op->args[2] = op->args[3];
416703271524SRichard Henderson } else {
416803271524SRichard Henderson goto do_not_remove;
416903271524SRichard Henderson }
417003271524SRichard Henderson /* Mark the single-word operation live. */
41711414968aSRichard Henderson goto do_not_remove;
41721414968aSRichard Henderson
417376f42780SRichard Henderson case INDEX_op_addco:
417476f42780SRichard Henderson if (s->carry_live) {
417576f42780SRichard Henderson goto do_not_remove;
417676f42780SRichard Henderson }
417776f42780SRichard Henderson op->opc = opc = INDEX_op_add;
417876f42780SRichard Henderson goto do_default;
417976f42780SRichard Henderson
418076f42780SRichard Henderson case INDEX_op_addcio:
418176f42780SRichard Henderson if (s->carry_live) {
418276f42780SRichard Henderson goto do_not_remove;
418376f42780SRichard Henderson }
418476f42780SRichard Henderson op->opc = opc = INDEX_op_addci;
418576f42780SRichard Henderson goto do_default;
418676f42780SRichard Henderson
418776f42780SRichard Henderson case INDEX_op_subbo:
418876f42780SRichard Henderson if (s->carry_live) {
418976f42780SRichard Henderson goto do_not_remove;
419076f42780SRichard Henderson }
419176f42780SRichard Henderson /* Lower to sub, but this may also require canonicalization. */
419276f42780SRichard Henderson op->opc = opc = INDEX_op_sub;
419376f42780SRichard Henderson ts = arg_temp(op->args[2]);
419476f42780SRichard Henderson if (ts->kind == TEMP_CONST) {
419576f42780SRichard Henderson ts = tcg_constant_internal(ts->type, -ts->val);
419676f42780SRichard Henderson if (ts->state_ptr == NULL) {
419776f42780SRichard Henderson tcg_debug_assert(temp_idx(ts) == nb_temps);
419876f42780SRichard Henderson nb_temps++;
419976f42780SRichard Henderson ts->state_ptr = tcg_malloc(sizeof(TCGRegSet));
420076f42780SRichard Henderson ts->state = TS_DEAD;
420176f42780SRichard Henderson la_reset_pref(ts);
420276f42780SRichard Henderson }
420376f42780SRichard Henderson op->args[2] = temp_arg(ts);
420476f42780SRichard Henderson op->opc = opc = INDEX_op_add;
420576f42780SRichard Henderson }
420676f42780SRichard Henderson goto do_default;
420776f42780SRichard Henderson
420876f42780SRichard Henderson case INDEX_op_subbio:
420976f42780SRichard Henderson if (s->carry_live) {
421076f42780SRichard Henderson goto do_not_remove;
421176f42780SRichard Henderson }
421276f42780SRichard Henderson op->opc = opc = INDEX_op_subbi;
421376f42780SRichard Henderson goto do_default;
421476f42780SRichard Henderson
421576f42780SRichard Henderson case INDEX_op_addc1o:
421676f42780SRichard Henderson if (s->carry_live) {
421776f42780SRichard Henderson goto do_not_remove;
421876f42780SRichard Henderson }
421976f42780SRichard Henderson /* Lower to add, add +1. */
422076f42780SRichard Henderson op_prev = tcg_op_insert_before(s, op, INDEX_op_add,
422176f42780SRichard Henderson TCGOP_TYPE(op), 3);
422276f42780SRichard Henderson op_prev->args[0] = op->args[0];
422376f42780SRichard Henderson op_prev->args[1] = op->args[1];
422476f42780SRichard Henderson op_prev->args[2] = op->args[2];
422576f42780SRichard Henderson op->opc = opc = INDEX_op_add;
422676f42780SRichard Henderson op->args[1] = op->args[0];
422776f42780SRichard Henderson ts = arg_temp(op->args[0]);
422876f42780SRichard Henderson ts = tcg_constant_internal(ts->type, 1);
422976f42780SRichard Henderson op->args[2] = temp_arg(ts);
423076f42780SRichard Henderson goto do_default;
423176f42780SRichard Henderson
423276f42780SRichard Henderson case INDEX_op_subb1o:
423376f42780SRichard Henderson if (s->carry_live) {
423476f42780SRichard Henderson goto do_not_remove;
423576f42780SRichard Henderson }
423676f42780SRichard Henderson /* Lower to sub, add -1. */
423776f42780SRichard Henderson op_prev = tcg_op_insert_before(s, op, INDEX_op_sub,
423876f42780SRichard Henderson TCGOP_TYPE(op), 3);
423976f42780SRichard Henderson op_prev->args[0] = op->args[0];
424076f42780SRichard Henderson op_prev->args[1] = op->args[1];
424176f42780SRichard Henderson op_prev->args[2] = op->args[2];
424276f42780SRichard Henderson op->opc = opc = INDEX_op_add;
424376f42780SRichard Henderson op->args[1] = op->args[0];
424476f42780SRichard Henderson ts = arg_temp(op->args[0]);
424576f42780SRichard Henderson ts = tcg_constant_internal(ts->type, -1);
424676f42780SRichard Henderson op->args[2] = temp_arg(ts);
424776f42780SRichard Henderson goto do_default;
424876f42780SRichard Henderson
4249c896fe29Sbellard default:
425076f42780SRichard Henderson do_default:
425176f42780SRichard Henderson /*
425276f42780SRichard Henderson * Test if the operation can be removed because all
425376f42780SRichard Henderson * its outputs are dead. We assume that nb_oargs == 0
425476f42780SRichard Henderson * implies side effects.
425576f42780SRichard Henderson */
42563e3689dfSRichard Henderson def = &tcg_op_defs[opc];
42573e3689dfSRichard Henderson if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && def->nb_oargs != 0) {
42583e3689dfSRichard Henderson for (int i = def->nb_oargs - 1; i >= 0; i--) {
4259b83eabeaSRichard Henderson if (arg_temp(op->args[i])->state != TS_DEAD) {
4260c896fe29Sbellard goto do_not_remove;
4261c896fe29Sbellard }
42629c43b68dSAurelien Jarno }
4263152c35aaSRichard Henderson goto do_remove;
4264152c35aaSRichard Henderson }
4265152c35aaSRichard Henderson goto do_not_remove;
4266152c35aaSRichard Henderson
42671305c451SRichard Henderson do_remove:
42680c627cdcSRichard Henderson tcg_op_remove(s, op);
4269152c35aaSRichard Henderson break;
4270152c35aaSRichard Henderson
4271c896fe29Sbellard do_not_remove:
42723e3689dfSRichard Henderson def = &tcg_op_defs[opc];
42733e3689dfSRichard Henderson nb_iargs = def->nb_iargs;
42743e3689dfSRichard Henderson nb_oargs = def->nb_oargs;
42753e3689dfSRichard Henderson
42767d10d8e0SRichard Henderson for (int i = 0; i < nb_oargs; i++) {
427725f49c5fSRichard Henderson ts = arg_temp(op->args[i]);
427825f49c5fSRichard Henderson
427925f49c5fSRichard Henderson /* Remember the preference of the uses that followed. */
428031fd884bSRichard Henderson if (i < ARRAY_SIZE(op->output_pref)) {
428125f49c5fSRichard Henderson op->output_pref[i] = *la_temp_pref(ts);
428231fd884bSRichard Henderson }
428325f49c5fSRichard Henderson
428425f49c5fSRichard Henderson /* Output args are dead. */
428525f49c5fSRichard Henderson if (ts->state & TS_DEAD) {
4286a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i;
42876b64b624SAurelien Jarno }
428825f49c5fSRichard Henderson if (ts->state & TS_MEM) {
4289a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i;
42909c43b68dSAurelien Jarno }
429125f49c5fSRichard Henderson ts->state = TS_DEAD;
429225f49c5fSRichard Henderson la_reset_pref(ts);
4293c896fe29Sbellard }
4294c896fe29Sbellard
429525f49c5fSRichard Henderson /* If end of basic block, update. */
4296ae36a246SRichard Henderson if (def->flags & TCG_OPF_BB_EXIT) {
429776f42780SRichard Henderson assert_carry_dead(s);
4298ae36a246SRichard Henderson la_func_end(s, nb_globals, nb_temps);
4299b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_COND_BRANCH) {
430076f42780SRichard Henderson assert_carry_dead(s);
4301b4cb76e6SRichard Henderson la_bb_sync(s, nb_globals, nb_temps);
4302ae36a246SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) {
430376f42780SRichard Henderson assert_carry_dead(s);
43042616c808SRichard Henderson la_bb_end(s, nb_globals, nb_temps);
43053d5c5f87SAurelien Jarno } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
430676f42780SRichard Henderson assert_carry_dead(s);
4307f65a061cSRichard Henderson la_global_sync(s, nb_globals);
430825f49c5fSRichard Henderson if (def->flags & TCG_OPF_CALL_CLOBBER) {
430925f49c5fSRichard Henderson la_cross_call(s, nb_temps);
431025f49c5fSRichard Henderson }
4311c896fe29Sbellard }
4312c896fe29Sbellard
431325f49c5fSRichard Henderson /* Record arguments that die in this opcode. */
43147d10d8e0SRichard Henderson for (int i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
431525f49c5fSRichard Henderson ts = arg_temp(op->args[i]);
431625f49c5fSRichard Henderson if (ts->state & TS_DEAD) {
4317a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i;
4318c896fe29Sbellard }
4319c19f47bfSAurelien Jarno }
432076f42780SRichard Henderson if (def->flags & TCG_OPF_CARRY_OUT) {
432176f42780SRichard Henderson s->carry_live = false;
432276f42780SRichard Henderson }
432325f49c5fSRichard Henderson
432425f49c5fSRichard Henderson /* Input arguments are live for preceding opcodes. */
43257d10d8e0SRichard Henderson for (int i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
432625f49c5fSRichard Henderson ts = arg_temp(op->args[i]);
432725f49c5fSRichard Henderson if (ts->state & TS_DEAD) {
432825f49c5fSRichard Henderson /* For operands that were dead, initially allow
432925f49c5fSRichard Henderson all regs for the type. */
433025f49c5fSRichard Henderson *la_temp_pref(ts) = tcg_target_available_regs[ts->type];
433125f49c5fSRichard Henderson ts->state &= ~TS_DEAD;
433225f49c5fSRichard Henderson }
433325f49c5fSRichard Henderson }
433476f42780SRichard Henderson if (def->flags & TCG_OPF_CARRY_IN) {
433576f42780SRichard Henderson s->carry_live = true;
433676f42780SRichard Henderson }
433725f49c5fSRichard Henderson
433825f49c5fSRichard Henderson /* Incorporate constraints for this operand. */
433925f49c5fSRichard Henderson switch (opc) {
4340b5701261SRichard Henderson case INDEX_op_mov:
434125f49c5fSRichard Henderson /* Note that these are TCG_OPF_NOT_PRESENT and do not
434225f49c5fSRichard Henderson have proper constraints. That said, special case
434325f49c5fSRichard Henderson moves to propagate preferences backward. */
434425f49c5fSRichard Henderson if (IS_DEAD_ARG(1)) {
434525f49c5fSRichard Henderson *la_temp_pref(arg_temp(op->args[0]))
434625f49c5fSRichard Henderson = *la_temp_pref(arg_temp(op->args[1]));
434725f49c5fSRichard Henderson }
434825f49c5fSRichard Henderson break;
434925f49c5fSRichard Henderson
435025f49c5fSRichard Henderson default:
4351501fb3daSRichard Henderson args_ct = opcode_args_ct(op);
43527d10d8e0SRichard Henderson for (int i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
4353501fb3daSRichard Henderson const TCGArgConstraint *ct = &args_ct[i];
435425f49c5fSRichard Henderson TCGRegSet set, *pset;
435525f49c5fSRichard Henderson
435625f49c5fSRichard Henderson ts = arg_temp(op->args[i]);
435725f49c5fSRichard Henderson pset = la_temp_pref(ts);
435825f49c5fSRichard Henderson set = *pset;
435925f49c5fSRichard Henderson
43609be0d080SRichard Henderson set &= ct->regs;
4361bc2b17e6SRichard Henderson if (ct->ialias) {
436231fd884bSRichard Henderson set &= output_pref(op, ct->alias_index);
436325f49c5fSRichard Henderson }
436425f49c5fSRichard Henderson /* If the combination is not possible, restart. */
436525f49c5fSRichard Henderson if (set == 0) {
43669be0d080SRichard Henderson set = ct->regs;
436725f49c5fSRichard Henderson }
436825f49c5fSRichard Henderson *pset = set;
436925f49c5fSRichard Henderson }
437025f49c5fSRichard Henderson break;
4371c896fe29Sbellard }
4372c896fe29Sbellard break;
4373c896fe29Sbellard }
4374bee158cbSRichard Henderson op->life = arg_life;
4375c896fe29Sbellard }
437676f42780SRichard Henderson assert_carry_dead(s);
43771ff0a2c5SEvgeny Voevodin }
4378c896fe29Sbellard
43795a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries. */
43809bbee4c0SRichard Henderson static bool __attribute__((noinline))
liveness_pass_2(TCGContext * s)43819bbee4c0SRichard Henderson liveness_pass_2(TCGContext *s)
43825a18407fSRichard Henderson {
43835a18407fSRichard Henderson int nb_globals = s->nb_globals;
438415fa08f8SRichard Henderson int nb_temps, i;
43855a18407fSRichard Henderson bool changes = false;
438615fa08f8SRichard Henderson TCGOp *op, *op_next;
43875a18407fSRichard Henderson
43885a18407fSRichard Henderson /* Create a temporary for each indirect global. */
43895a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) {
43905a18407fSRichard Henderson TCGTemp *its = &s->temps[i];
43915a18407fSRichard Henderson if (its->indirect_reg) {
43925a18407fSRichard Henderson TCGTemp *dts = tcg_temp_alloc(s);
43935a18407fSRichard Henderson dts->type = its->type;
43945a18407fSRichard Henderson dts->base_type = its->base_type;
4395e1e64652SRichard Henderson dts->temp_subindex = its->temp_subindex;
4396c7482438SRichard Henderson dts->kind = TEMP_EBB;
4397b83eabeaSRichard Henderson its->state_ptr = dts;
4398b83eabeaSRichard Henderson } else {
4399b83eabeaSRichard Henderson its->state_ptr = NULL;
44005a18407fSRichard Henderson }
4401b83eabeaSRichard Henderson /* All globals begin dead. */
4402b83eabeaSRichard Henderson its->state = TS_DEAD;
44035a18407fSRichard Henderson }
4404b83eabeaSRichard Henderson for (nb_temps = s->nb_temps; i < nb_temps; ++i) {
4405b83eabeaSRichard Henderson TCGTemp *its = &s->temps[i];
4406b83eabeaSRichard Henderson its->state_ptr = NULL;
4407b83eabeaSRichard Henderson its->state = TS_DEAD;
4408b83eabeaSRichard Henderson }
44095a18407fSRichard Henderson
441015fa08f8SRichard Henderson QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
44115a18407fSRichard Henderson TCGOpcode opc = op->opc;
44125a18407fSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc];
44135a18407fSRichard Henderson TCGLifeData arg_life = op->life;
44145a18407fSRichard Henderson int nb_iargs, nb_oargs, call_flags;
4415b83eabeaSRichard Henderson TCGTemp *arg_ts, *dir_ts;
44165a18407fSRichard Henderson
44175a18407fSRichard Henderson if (opc == INDEX_op_call) {
4418cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op);
4419cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op);
442090163900SRichard Henderson call_flags = tcg_call_flags(op);
44215a18407fSRichard Henderson } else {
44225a18407fSRichard Henderson nb_iargs = def->nb_iargs;
44235a18407fSRichard Henderson nb_oargs = def->nb_oargs;
44245a18407fSRichard Henderson
44255a18407fSRichard Henderson /* Set flags similar to how calls require. */
4426b4cb76e6SRichard Henderson if (def->flags & TCG_OPF_COND_BRANCH) {
4427b4cb76e6SRichard Henderson /* Like reading globals: sync_globals */
4428b4cb76e6SRichard Henderson call_flags = TCG_CALL_NO_WRITE_GLOBALS;
4429b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) {
44305a18407fSRichard Henderson /* Like writing globals: save_globals */
44315a18407fSRichard Henderson call_flags = 0;
44325a18407fSRichard Henderson } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
44335a18407fSRichard Henderson /* Like reading globals: sync_globals */
44345a18407fSRichard Henderson call_flags = TCG_CALL_NO_WRITE_GLOBALS;
44355a18407fSRichard Henderson } else {
44365a18407fSRichard Henderson /* No effect on globals. */
44375a18407fSRichard Henderson call_flags = (TCG_CALL_NO_READ_GLOBALS |
44385a18407fSRichard Henderson TCG_CALL_NO_WRITE_GLOBALS);
44395a18407fSRichard Henderson }
44405a18407fSRichard Henderson }
44415a18407fSRichard Henderson
44425a18407fSRichard Henderson /* Make sure that input arguments are available. */
44435a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
4444b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]);
4445b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr;
4446b83eabeaSRichard Henderson if (dir_ts && arg_ts->state == TS_DEAD) {
4447e996804dSRichard Henderson TCGOp *lop = tcg_op_insert_before(s, op, INDEX_op_ld,
4448cf5c9f69SRichard Henderson arg_ts->type, 3);
44495a18407fSRichard Henderson
4450b83eabeaSRichard Henderson lop->args[0] = temp_arg(dir_ts);
4451b83eabeaSRichard Henderson lop->args[1] = temp_arg(arg_ts->mem_base);
4452b83eabeaSRichard Henderson lop->args[2] = arg_ts->mem_offset;
44535a18407fSRichard Henderson
44545a18407fSRichard Henderson /* Loaded, but synced with memory. */
4455b83eabeaSRichard Henderson arg_ts->state = TS_MEM;
44565a18407fSRichard Henderson }
44575a18407fSRichard Henderson }
44585a18407fSRichard Henderson
44595a18407fSRichard Henderson /* Perform input replacement, and mark inputs that became dead.
44605a18407fSRichard Henderson No action is required except keeping temp_state up to date
44615a18407fSRichard Henderson so that we reload when needed. */
44625a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
4463b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]);
4464b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr;
4465b83eabeaSRichard Henderson if (dir_ts) {
4466b83eabeaSRichard Henderson op->args[i] = temp_arg(dir_ts);
44675a18407fSRichard Henderson changes = true;
44685a18407fSRichard Henderson if (IS_DEAD_ARG(i)) {
4469b83eabeaSRichard Henderson arg_ts->state = TS_DEAD;
44705a18407fSRichard Henderson }
44715a18407fSRichard Henderson }
44725a18407fSRichard Henderson }
44735a18407fSRichard Henderson
44745a18407fSRichard Henderson /* Liveness analysis should ensure that the following are
44755a18407fSRichard Henderson all correct, for call sites and basic block end points. */
44765a18407fSRichard Henderson if (call_flags & TCG_CALL_NO_READ_GLOBALS) {
44775a18407fSRichard Henderson /* Nothing to do */
44785a18407fSRichard Henderson } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) {
44795a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) {
44805a18407fSRichard Henderson /* Liveness should see that globals are synced back,
44815a18407fSRichard Henderson that is, either TS_DEAD or TS_MEM. */
4482b83eabeaSRichard Henderson arg_ts = &s->temps[i];
4483b83eabeaSRichard Henderson tcg_debug_assert(arg_ts->state_ptr == 0
4484b83eabeaSRichard Henderson || arg_ts->state != 0);
44855a18407fSRichard Henderson }
44865a18407fSRichard Henderson } else {
44875a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) {
44885a18407fSRichard Henderson /* Liveness should see that globals are saved back,
44895a18407fSRichard Henderson that is, TS_DEAD, waiting to be reloaded. */
4490b83eabeaSRichard Henderson arg_ts = &s->temps[i];
4491b83eabeaSRichard Henderson tcg_debug_assert(arg_ts->state_ptr == 0
4492b83eabeaSRichard Henderson || arg_ts->state == TS_DEAD);
44935a18407fSRichard Henderson }
44945a18407fSRichard Henderson }
44955a18407fSRichard Henderson
44965a18407fSRichard Henderson /* Outputs become available. */
4497b5701261SRichard Henderson if (opc == INDEX_op_mov) {
449861f15c48SRichard Henderson arg_ts = arg_temp(op->args[0]);
449961f15c48SRichard Henderson dir_ts = arg_ts->state_ptr;
450061f15c48SRichard Henderson if (dir_ts) {
450161f15c48SRichard Henderson op->args[0] = temp_arg(dir_ts);
450261f15c48SRichard Henderson changes = true;
450361f15c48SRichard Henderson
450461f15c48SRichard Henderson /* The output is now live and modified. */
450561f15c48SRichard Henderson arg_ts->state = 0;
450661f15c48SRichard Henderson
450761f15c48SRichard Henderson if (NEED_SYNC_ARG(0)) {
4508a28f151dSRichard Henderson TCGOp *sop = tcg_op_insert_after(s, op, INDEX_op_st,
4509cf5c9f69SRichard Henderson arg_ts->type, 3);
451061f15c48SRichard Henderson TCGTemp *out_ts = dir_ts;
451161f15c48SRichard Henderson
451261f15c48SRichard Henderson if (IS_DEAD_ARG(0)) {
451361f15c48SRichard Henderson out_ts = arg_temp(op->args[1]);
451461f15c48SRichard Henderson arg_ts->state = TS_DEAD;
451561f15c48SRichard Henderson tcg_op_remove(s, op);
451661f15c48SRichard Henderson } else {
451761f15c48SRichard Henderson arg_ts->state = TS_MEM;
451861f15c48SRichard Henderson }
451961f15c48SRichard Henderson
452061f15c48SRichard Henderson sop->args[0] = temp_arg(out_ts);
452161f15c48SRichard Henderson sop->args[1] = temp_arg(arg_ts->mem_base);
452261f15c48SRichard Henderson sop->args[2] = arg_ts->mem_offset;
452361f15c48SRichard Henderson } else {
452461f15c48SRichard Henderson tcg_debug_assert(!IS_DEAD_ARG(0));
452561f15c48SRichard Henderson }
452661f15c48SRichard Henderson }
452761f15c48SRichard Henderson } else {
45285a18407fSRichard Henderson for (i = 0; i < nb_oargs; i++) {
4529b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]);
4530b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr;
4531b83eabeaSRichard Henderson if (!dir_ts) {
45325a18407fSRichard Henderson continue;
45335a18407fSRichard Henderson }
4534b83eabeaSRichard Henderson op->args[i] = temp_arg(dir_ts);
45355a18407fSRichard Henderson changes = true;
45365a18407fSRichard Henderson
45375a18407fSRichard Henderson /* The output is now live and modified. */
4538b83eabeaSRichard Henderson arg_ts->state = 0;
45395a18407fSRichard Henderson
45405a18407fSRichard Henderson /* Sync outputs upon their last write. */
45415a18407fSRichard Henderson if (NEED_SYNC_ARG(i)) {
4542a28f151dSRichard Henderson TCGOp *sop = tcg_op_insert_after(s, op, INDEX_op_st,
4543cf5c9f69SRichard Henderson arg_ts->type, 3);
45445a18407fSRichard Henderson
4545b83eabeaSRichard Henderson sop->args[0] = temp_arg(dir_ts);
4546b83eabeaSRichard Henderson sop->args[1] = temp_arg(arg_ts->mem_base);
4547b83eabeaSRichard Henderson sop->args[2] = arg_ts->mem_offset;
45485a18407fSRichard Henderson
4549b83eabeaSRichard Henderson arg_ts->state = TS_MEM;
45505a18407fSRichard Henderson }
45515a18407fSRichard Henderson /* Drop outputs that are dead. */
45525a18407fSRichard Henderson if (IS_DEAD_ARG(i)) {
4553b83eabeaSRichard Henderson arg_ts->state = TS_DEAD;
45545a18407fSRichard Henderson }
45555a18407fSRichard Henderson }
45565a18407fSRichard Henderson }
455761f15c48SRichard Henderson }
45585a18407fSRichard Henderson
45595a18407fSRichard Henderson return changes;
45605a18407fSRichard Henderson }
45615a18407fSRichard Henderson
temp_allocate_frame(TCGContext * s,TCGTemp * ts)45622272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts)
4563c896fe29Sbellard {
456431c96417SRichard Henderson intptr_t off;
4565273eb50cSRichard Henderson int size, align;
4566c1c09194SRichard Henderson
4567273eb50cSRichard Henderson /* When allocating an object, look at the full type. */
4568273eb50cSRichard Henderson size = tcg_type_size(ts->base_type);
4569273eb50cSRichard Henderson switch (ts->base_type) {
4570c1c09194SRichard Henderson case TCG_TYPE_I32:
457131c96417SRichard Henderson align = 4;
4572c1c09194SRichard Henderson break;
4573c1c09194SRichard Henderson case TCG_TYPE_I64:
4574c1c09194SRichard Henderson case TCG_TYPE_V64:
457531c96417SRichard Henderson align = 8;
4576c1c09194SRichard Henderson break;
457743eef72fSRichard Henderson case TCG_TYPE_I128:
4578c1c09194SRichard Henderson case TCG_TYPE_V128:
4579c1c09194SRichard Henderson case TCG_TYPE_V256:
458043eef72fSRichard Henderson /*
458143eef72fSRichard Henderson * Note that we do not require aligned storage for V256,
458243eef72fSRichard Henderson * and that we provide alignment for I128 to match V128,
458343eef72fSRichard Henderson * even if that's above what the host ABI requires.
458443eef72fSRichard Henderson */
458531c96417SRichard Henderson align = 16;
4586c1c09194SRichard Henderson break;
4587c1c09194SRichard Henderson default:
4588c1c09194SRichard Henderson g_assert_not_reached();
4589b591dc59SBlue Swirl }
4590c1c09194SRichard Henderson
4591b9537d59SRichard Henderson /*
4592b9537d59SRichard Henderson * Assume the stack is sufficiently aligned.
4593b9537d59SRichard Henderson * This affects e.g. ARM NEON, where we have 8 byte stack alignment
4594b9537d59SRichard Henderson * and do not require 16 byte vector alignment. This seems slightly
4595b9537d59SRichard Henderson * easier than fully parameterizing the above switch statement.
4596b9537d59SRichard Henderson */
4597b9537d59SRichard Henderson align = MIN(TCG_TARGET_STACK_ALIGN, align);
4598c1c09194SRichard Henderson off = ROUND_UP(s->current_frame_offset, align);
4599732d5897SRichard Henderson
4600732d5897SRichard Henderson /* If we've exhausted the stack frame, restart with a smaller TB. */
4601732d5897SRichard Henderson if (off + size > s->frame_end) {
4602732d5897SRichard Henderson tcg_raise_tb_overflow(s);
4603732d5897SRichard Henderson }
4604c1c09194SRichard Henderson s->current_frame_offset = off + size;
46059defd1bdSRichard Henderson #if defined(__sparc__)
4606273eb50cSRichard Henderson off += TCG_TARGET_STACK_BIAS;
46079defd1bdSRichard Henderson #endif
4608273eb50cSRichard Henderson
4609273eb50cSRichard Henderson /* If the object was subdivided, assign memory to all the parts. */
4610273eb50cSRichard Henderson if (ts->base_type != ts->type) {
4611273eb50cSRichard Henderson int part_size = tcg_type_size(ts->type);
4612273eb50cSRichard Henderson int part_count = size / part_size;
4613273eb50cSRichard Henderson
4614273eb50cSRichard Henderson /*
4615273eb50cSRichard Henderson * Each part is allocated sequentially in tcg_temp_new_internal.
4616273eb50cSRichard Henderson * Jump back to the first part by subtracting the current index.
4617273eb50cSRichard Henderson */
4618273eb50cSRichard Henderson ts -= ts->temp_subindex;
4619273eb50cSRichard Henderson for (int i = 0; i < part_count; ++i) {
4620273eb50cSRichard Henderson ts[i].mem_offset = off + i * part_size;
4621273eb50cSRichard Henderson ts[i].mem_base = s->frame_temp;
4622273eb50cSRichard Henderson ts[i].mem_allocated = 1;
4623273eb50cSRichard Henderson }
4624273eb50cSRichard Henderson } else {
4625273eb50cSRichard Henderson ts->mem_offset = off;
4626b3a62939SRichard Henderson ts->mem_base = s->frame_temp;
4627c896fe29Sbellard ts->mem_allocated = 1;
4628c896fe29Sbellard }
4629273eb50cSRichard Henderson }
4630c896fe29Sbellard
4631098859f1SRichard Henderson /* Assign @reg to @ts, and update reg_to_temp[]. */
set_temp_val_reg(TCGContext * s,TCGTemp * ts,TCGReg reg)4632098859f1SRichard Henderson static void set_temp_val_reg(TCGContext *s, TCGTemp *ts, TCGReg reg)
4633098859f1SRichard Henderson {
4634098859f1SRichard Henderson if (ts->val_type == TEMP_VAL_REG) {
4635098859f1SRichard Henderson TCGReg old = ts->reg;
4636098859f1SRichard Henderson tcg_debug_assert(s->reg_to_temp[old] == ts);
4637098859f1SRichard Henderson if (old == reg) {
4638098859f1SRichard Henderson return;
4639098859f1SRichard Henderson }
4640098859f1SRichard Henderson s->reg_to_temp[old] = NULL;
4641098859f1SRichard Henderson }
4642098859f1SRichard Henderson tcg_debug_assert(s->reg_to_temp[reg] == NULL);
4643098859f1SRichard Henderson s->reg_to_temp[reg] = ts;
4644098859f1SRichard Henderson ts->val_type = TEMP_VAL_REG;
4645098859f1SRichard Henderson ts->reg = reg;
4646098859f1SRichard Henderson }
4647098859f1SRichard Henderson
4648098859f1SRichard Henderson /* Assign a non-register value type to @ts, and update reg_to_temp[]. */
set_temp_val_nonreg(TCGContext * s,TCGTemp * ts,TCGTempVal type)4649098859f1SRichard Henderson static void set_temp_val_nonreg(TCGContext *s, TCGTemp *ts, TCGTempVal type)
4650098859f1SRichard Henderson {
4651098859f1SRichard Henderson tcg_debug_assert(type != TEMP_VAL_REG);
4652098859f1SRichard Henderson if (ts->val_type == TEMP_VAL_REG) {
4653098859f1SRichard Henderson TCGReg reg = ts->reg;
4654098859f1SRichard Henderson tcg_debug_assert(s->reg_to_temp[reg] == ts);
4655098859f1SRichard Henderson s->reg_to_temp[reg] = NULL;
4656098859f1SRichard Henderson }
4657098859f1SRichard Henderson ts->val_type = type;
4658098859f1SRichard Henderson }
4659098859f1SRichard Henderson
4660b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet);
4661b3915dbbSRichard Henderson
466259d7c14eSRichard Henderson /* Mark a temporary as free or dead. If 'free_or_dead' is negative,
466359d7c14eSRichard Henderson mark it free; otherwise mark it dead. */
temp_free_or_dead(TCGContext * s,TCGTemp * ts,int free_or_dead)466459d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead)
4665c896fe29Sbellard {
4666c0522136SRichard Henderson TCGTempVal new_type;
4667c0522136SRichard Henderson
4668c0522136SRichard Henderson switch (ts->kind) {
4669c0522136SRichard Henderson case TEMP_FIXED:
467059d7c14eSRichard Henderson return;
4671c0522136SRichard Henderson case TEMP_GLOBAL:
4672f57c6915SRichard Henderson case TEMP_TB:
4673c0522136SRichard Henderson new_type = TEMP_VAL_MEM;
4674c0522136SRichard Henderson break;
4675c7482438SRichard Henderson case TEMP_EBB:
4676c0522136SRichard Henderson new_type = free_or_dead < 0 ? TEMP_VAL_MEM : TEMP_VAL_DEAD;
4677c0522136SRichard Henderson break;
4678c0522136SRichard Henderson case TEMP_CONST:
4679c0522136SRichard Henderson new_type = TEMP_VAL_CONST;
4680c0522136SRichard Henderson break;
4681c0522136SRichard Henderson default:
4682c0522136SRichard Henderson g_assert_not_reached();
468359d7c14eSRichard Henderson }
4684098859f1SRichard Henderson set_temp_val_nonreg(s, ts, new_type);
468559d7c14eSRichard Henderson }
4686c896fe29Sbellard
468759d7c14eSRichard Henderson /* Mark a temporary as dead. */
temp_dead(TCGContext * s,TCGTemp * ts)468859d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts)
468959d7c14eSRichard Henderson {
469059d7c14eSRichard Henderson temp_free_or_dead(s, ts, 1);
469159d7c14eSRichard Henderson }
469259d7c14eSRichard Henderson
469359d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary
469459d7c14eSRichard Henderson registers needs to be allocated to store a constant. If 'free_or_dead'
469559d7c14eSRichard Henderson is non-zero, subsequently release the temporary; if it is positive, the
469659d7c14eSRichard Henderson temp is dead; if it is negative, the temp is free. */
temp_sync(TCGContext * s,TCGTemp * ts,TCGRegSet allocated_regs,TCGRegSet preferred_regs,int free_or_dead)469798b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs,
469898b4e186SRichard Henderson TCGRegSet preferred_regs, int free_or_dead)
469959d7c14eSRichard Henderson {
4700c0522136SRichard Henderson if (!temp_readonly(ts) && !ts->mem_coherent) {
47017f6ceedfSAurelien Jarno if (!ts->mem_allocated) {
47022272e4a7SRichard Henderson temp_allocate_frame(s, ts);
470359d7c14eSRichard Henderson }
470459d7c14eSRichard Henderson switch (ts->val_type) {
470559d7c14eSRichard Henderson case TEMP_VAL_CONST:
470659d7c14eSRichard Henderson /* If we're going to free the temp immediately, then we won't
470759d7c14eSRichard Henderson require it later in a register, so attempt to store the
470859d7c14eSRichard Henderson constant to memory directly. */
470959d7c14eSRichard Henderson if (free_or_dead
471059d7c14eSRichard Henderson && tcg_out_sti(s, ts->type, ts->val,
471159d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset)) {
471259d7c14eSRichard Henderson break;
471359d7c14eSRichard Henderson }
471459d7c14eSRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type],
471598b4e186SRichard Henderson allocated_regs, preferred_regs);
471659d7c14eSRichard Henderson /* fallthrough */
471759d7c14eSRichard Henderson
471859d7c14eSRichard Henderson case TEMP_VAL_REG:
471959d7c14eSRichard Henderson tcg_out_st(s, ts->type, ts->reg,
472059d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset);
472159d7c14eSRichard Henderson break;
472259d7c14eSRichard Henderson
472359d7c14eSRichard Henderson case TEMP_VAL_MEM:
472459d7c14eSRichard Henderson break;
472559d7c14eSRichard Henderson
472659d7c14eSRichard Henderson case TEMP_VAL_DEAD:
472759d7c14eSRichard Henderson default:
4728732e89f4SRichard Henderson g_assert_not_reached();
4729c896fe29Sbellard }
47307f6ceedfSAurelien Jarno ts->mem_coherent = 1;
47317f6ceedfSAurelien Jarno }
473259d7c14eSRichard Henderson if (free_or_dead) {
473359d7c14eSRichard Henderson temp_free_or_dead(s, ts, free_or_dead);
473459d7c14eSRichard Henderson }
473559d7c14eSRichard Henderson }
47367f6ceedfSAurelien Jarno
47377f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */
tcg_reg_free(TCGContext * s,TCGReg reg,TCGRegSet allocated_regs)4738b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs)
47397f6ceedfSAurelien Jarno {
4740f8b2f202SRichard Henderson TCGTemp *ts = s->reg_to_temp[reg];
4741f8b2f202SRichard Henderson if (ts != NULL) {
474298b4e186SRichard Henderson temp_sync(s, ts, allocated_regs, 0, -1);
4743c896fe29Sbellard }
4744c896fe29Sbellard }
4745c896fe29Sbellard
4746b016486eSRichard Henderson /**
4747b016486eSRichard Henderson * tcg_reg_alloc:
4748b016486eSRichard Henderson * @required_regs: Set of registers in which we must allocate.
4749b016486eSRichard Henderson * @allocated_regs: Set of registers which must be avoided.
4750b016486eSRichard Henderson * @preferred_regs: Set of registers we should prefer.
4751b016486eSRichard Henderson * @rev: True if we search the registers in "indirect" order.
4752b016486eSRichard Henderson *
4753b016486eSRichard Henderson * The allocated register must be in @required_regs & ~@allocated_regs,
4754b016486eSRichard Henderson * but if we can put it in @preferred_regs we may save a move later.
4755b016486eSRichard Henderson */
tcg_reg_alloc(TCGContext * s,TCGRegSet required_regs,TCGRegSet allocated_regs,TCGRegSet preferred_regs,bool rev)4756b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs,
4757b016486eSRichard Henderson TCGRegSet allocated_regs,
4758b016486eSRichard Henderson TCGRegSet preferred_regs, bool rev)
4759c896fe29Sbellard {
4760b016486eSRichard Henderson int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
4761b016486eSRichard Henderson TCGRegSet reg_ct[2];
476291478cefSRichard Henderson const int *order;
4763c896fe29Sbellard
4764b016486eSRichard Henderson reg_ct[1] = required_regs & ~allocated_regs;
4765b016486eSRichard Henderson tcg_debug_assert(reg_ct[1] != 0);
4766b016486eSRichard Henderson reg_ct[0] = reg_ct[1] & preferred_regs;
4767b016486eSRichard Henderson
4768b016486eSRichard Henderson /* Skip the preferred_regs option if it cannot be satisfied,
4769b016486eSRichard Henderson or if the preference made no difference. */
4770b016486eSRichard Henderson f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1];
4771b016486eSRichard Henderson
477291478cefSRichard Henderson order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
4773c896fe29Sbellard
4774b016486eSRichard Henderson /* Try free registers, preferences first. */
4775b016486eSRichard Henderson for (j = f; j < 2; j++) {
4776b016486eSRichard Henderson TCGRegSet set = reg_ct[j];
4777b016486eSRichard Henderson
4778b016486eSRichard Henderson if (tcg_regset_single(set)) {
4779b016486eSRichard Henderson /* One register in the set. */
4780b016486eSRichard Henderson TCGReg reg = tcg_regset_first(set);
4781b016486eSRichard Henderson if (s->reg_to_temp[reg] == NULL) {
4782c896fe29Sbellard return reg;
4783c896fe29Sbellard }
4784b016486eSRichard Henderson } else {
478591478cefSRichard Henderson for (i = 0; i < n; i++) {
4786b016486eSRichard Henderson TCGReg reg = order[i];
4787b016486eSRichard Henderson if (s->reg_to_temp[reg] == NULL &&
4788b016486eSRichard Henderson tcg_regset_test_reg(set, reg)) {
4789b016486eSRichard Henderson return reg;
4790b016486eSRichard Henderson }
4791b016486eSRichard Henderson }
4792b016486eSRichard Henderson }
4793b016486eSRichard Henderson }
4794b016486eSRichard Henderson
4795b016486eSRichard Henderson /* We must spill something. */
4796b016486eSRichard Henderson for (j = f; j < 2; j++) {
4797b016486eSRichard Henderson TCGRegSet set = reg_ct[j];
4798b016486eSRichard Henderson
4799b016486eSRichard Henderson if (tcg_regset_single(set)) {
4800b016486eSRichard Henderson /* One register in the set. */
4801b016486eSRichard Henderson TCGReg reg = tcg_regset_first(set);
4802b3915dbbSRichard Henderson tcg_reg_free(s, reg, allocated_regs);
4803c896fe29Sbellard return reg;
4804b016486eSRichard Henderson } else {
4805b016486eSRichard Henderson for (i = 0; i < n; i++) {
4806b016486eSRichard Henderson TCGReg reg = order[i];
4807b016486eSRichard Henderson if (tcg_regset_test_reg(set, reg)) {
4808b016486eSRichard Henderson tcg_reg_free(s, reg, allocated_regs);
4809b016486eSRichard Henderson return reg;
4810b016486eSRichard Henderson }
4811b016486eSRichard Henderson }
4812c896fe29Sbellard }
4813c896fe29Sbellard }
4814c896fe29Sbellard
4815732e89f4SRichard Henderson g_assert_not_reached();
4816c896fe29Sbellard }
4817c896fe29Sbellard
tcg_reg_alloc_pair(TCGContext * s,TCGRegSet required_regs,TCGRegSet allocated_regs,TCGRegSet preferred_regs,bool rev)481829f5e925SRichard Henderson static TCGReg tcg_reg_alloc_pair(TCGContext *s, TCGRegSet required_regs,
481929f5e925SRichard Henderson TCGRegSet allocated_regs,
482029f5e925SRichard Henderson TCGRegSet preferred_regs, bool rev)
482129f5e925SRichard Henderson {
482229f5e925SRichard Henderson int i, j, k, fmin, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
482329f5e925SRichard Henderson TCGRegSet reg_ct[2];
482429f5e925SRichard Henderson const int *order;
482529f5e925SRichard Henderson
482629f5e925SRichard Henderson /* Ensure that if I is not in allocated_regs, I+1 is not either. */
482729f5e925SRichard Henderson reg_ct[1] = required_regs & ~(allocated_regs | (allocated_regs >> 1));
482829f5e925SRichard Henderson tcg_debug_assert(reg_ct[1] != 0);
482929f5e925SRichard Henderson reg_ct[0] = reg_ct[1] & preferred_regs;
483029f5e925SRichard Henderson
483129f5e925SRichard Henderson order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
483229f5e925SRichard Henderson
483329f5e925SRichard Henderson /*
483429f5e925SRichard Henderson * Skip the preferred_regs option if it cannot be satisfied,
483529f5e925SRichard Henderson * or if the preference made no difference.
483629f5e925SRichard Henderson */
483729f5e925SRichard Henderson k = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1];
483829f5e925SRichard Henderson
483929f5e925SRichard Henderson /*
484029f5e925SRichard Henderson * Minimize the number of flushes by looking for 2 free registers first,
484129f5e925SRichard Henderson * then a single flush, then two flushes.
484229f5e925SRichard Henderson */
484329f5e925SRichard Henderson for (fmin = 2; fmin >= 0; fmin--) {
484429f5e925SRichard Henderson for (j = k; j < 2; j++) {
484529f5e925SRichard Henderson TCGRegSet set = reg_ct[j];
484629f5e925SRichard Henderson
484729f5e925SRichard Henderson for (i = 0; i < n; i++) {
484829f5e925SRichard Henderson TCGReg reg = order[i];
484929f5e925SRichard Henderson
485029f5e925SRichard Henderson if (tcg_regset_test_reg(set, reg)) {
485129f5e925SRichard Henderson int f = !s->reg_to_temp[reg] + !s->reg_to_temp[reg + 1];
485229f5e925SRichard Henderson if (f >= fmin) {
485329f5e925SRichard Henderson tcg_reg_free(s, reg, allocated_regs);
485429f5e925SRichard Henderson tcg_reg_free(s, reg + 1, allocated_regs);
485529f5e925SRichard Henderson return reg;
485629f5e925SRichard Henderson }
485729f5e925SRichard Henderson }
485829f5e925SRichard Henderson }
485929f5e925SRichard Henderson }
486029f5e925SRichard Henderson }
4861732e89f4SRichard Henderson g_assert_not_reached();
486229f5e925SRichard Henderson }
486329f5e925SRichard Henderson
486440ae5c62SRichard Henderson /* Make sure the temporary is in a register. If needed, allocate the register
486540ae5c62SRichard Henderson from DESIRED while avoiding ALLOCATED. */
temp_load(TCGContext * s,TCGTemp * ts,TCGRegSet desired_regs,TCGRegSet allocated_regs,TCGRegSet preferred_regs)486640ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs,
4867b722452aSRichard Henderson TCGRegSet allocated_regs, TCGRegSet preferred_regs)
486840ae5c62SRichard Henderson {
486940ae5c62SRichard Henderson TCGReg reg;
487040ae5c62SRichard Henderson
487140ae5c62SRichard Henderson switch (ts->val_type) {
487240ae5c62SRichard Henderson case TEMP_VAL_REG:
487340ae5c62SRichard Henderson return;
487440ae5c62SRichard Henderson case TEMP_VAL_CONST:
4875b016486eSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
4876b722452aSRichard Henderson preferred_regs, ts->indirect_base);
48770a6a8bc8SRichard Henderson if (ts->type <= TCG_TYPE_I64) {
487840ae5c62SRichard Henderson tcg_out_movi(s, ts->type, reg, ts->val);
48790a6a8bc8SRichard Henderson } else {
48804e186175SRichard Henderson uint64_t val = ts->val;
48814e186175SRichard Henderson MemOp vece = MO_64;
48824e186175SRichard Henderson
48834e186175SRichard Henderson /*
48844e186175SRichard Henderson * Find the minimal vector element that matches the constant.
48854e186175SRichard Henderson * The targets will, in general, have to do this search anyway,
48864e186175SRichard Henderson * do this generically.
48874e186175SRichard Henderson */
48884e186175SRichard Henderson if (val == dup_const(MO_8, val)) {
48894e186175SRichard Henderson vece = MO_8;
48904e186175SRichard Henderson } else if (val == dup_const(MO_16, val)) {
48914e186175SRichard Henderson vece = MO_16;
48920b4286ddSRichard Henderson } else if (val == dup_const(MO_32, val)) {
48934e186175SRichard Henderson vece = MO_32;
48944e186175SRichard Henderson }
48954e186175SRichard Henderson
48964e186175SRichard Henderson tcg_out_dupi_vec(s, ts->type, vece, reg, ts->val);
48970a6a8bc8SRichard Henderson }
489840ae5c62SRichard Henderson ts->mem_coherent = 0;
489940ae5c62SRichard Henderson break;
490040ae5c62SRichard Henderson case TEMP_VAL_MEM:
4901e139bc4bSPhilippe Mathieu-Daudé if (!ts->mem_allocated) {
4902e139bc4bSPhilippe Mathieu-Daudé temp_allocate_frame(s, ts);
4903e139bc4bSPhilippe Mathieu-Daudé }
4904b016486eSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
4905b722452aSRichard Henderson preferred_regs, ts->indirect_base);
490640ae5c62SRichard Henderson tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset);
490740ae5c62SRichard Henderson ts->mem_coherent = 1;
490840ae5c62SRichard Henderson break;
490940ae5c62SRichard Henderson case TEMP_VAL_DEAD:
491040ae5c62SRichard Henderson default:
4911732e89f4SRichard Henderson g_assert_not_reached();
491240ae5c62SRichard Henderson }
4913098859f1SRichard Henderson set_temp_val_reg(s, ts, reg);
491440ae5c62SRichard Henderson }
491540ae5c62SRichard Henderson
491659d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a
4917e8996ee0Sbellard temporary registers needs to be allocated to store a constant. */
temp_save(TCGContext * s,TCGTemp * ts,TCGRegSet allocated_regs)491859d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs)
49191ad80729SAurelien Jarno {
49202c0366f0SAurelien Jarno /* The liveness analysis already ensures that globals are back
4921eabb7b91SAurelien Jarno in memory. Keep an tcg_debug_assert for safety. */
4922e01fa97dSRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || temp_readonly(ts));
49231ad80729SAurelien Jarno }
49241ad80729SAurelien Jarno
49259814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be
4926641d5fbeSbellard modified be the following code. 'allocated_regs' is used in case a
4927641d5fbeSbellard temporary registers needs to be allocated to store a constant. */
save_globals(TCGContext * s,TCGRegSet allocated_regs)4928641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
4929641d5fbeSbellard {
4930ac3b8891SRichard Henderson int i, n;
4931641d5fbeSbellard
4932ac3b8891SRichard Henderson for (i = 0, n = s->nb_globals; i < n; i++) {
4933b13eb728SRichard Henderson temp_save(s, &s->temps[i], allocated_regs);
4934641d5fbeSbellard }
4935e5097dc8Sbellard }
4936e5097dc8Sbellard
49373d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be
49383d5c5f87SAurelien Jarno read by the following code. 'allocated_regs' is used in case a
49393d5c5f87SAurelien Jarno temporary registers needs to be allocated to store a constant. */
sync_globals(TCGContext * s,TCGRegSet allocated_regs)49403d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs)
49413d5c5f87SAurelien Jarno {
4942ac3b8891SRichard Henderson int i, n;
49433d5c5f87SAurelien Jarno
4944ac3b8891SRichard Henderson for (i = 0, n = s->nb_globals; i < n; i++) {
494512b9b11aSRichard Henderson TCGTemp *ts = &s->temps[i];
494612b9b11aSRichard Henderson tcg_debug_assert(ts->val_type != TEMP_VAL_REG
4947ee17db83SRichard Henderson || ts->kind == TEMP_FIXED
494812b9b11aSRichard Henderson || ts->mem_coherent);
49493d5c5f87SAurelien Jarno }
49503d5c5f87SAurelien Jarno }
49513d5c5f87SAurelien Jarno
4952e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and
4953e8996ee0Sbellard all globals are stored at their canonical location. */
tcg_reg_alloc_bb_end(TCGContext * s,TCGRegSet allocated_regs)4954e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
4955e5097dc8Sbellard {
495676f42780SRichard Henderson assert_carry_dead(s);
495776f42780SRichard Henderson for (int i = s->nb_globals; i < s->nb_temps; i++) {
4958b13eb728SRichard Henderson TCGTemp *ts = &s->temps[i];
4959c0522136SRichard Henderson
4960c0522136SRichard Henderson switch (ts->kind) {
4961f57c6915SRichard Henderson case TEMP_TB:
4962b13eb728SRichard Henderson temp_save(s, ts, allocated_regs);
4963c0522136SRichard Henderson break;
4964c7482438SRichard Henderson case TEMP_EBB:
49652c0366f0SAurelien Jarno /* The liveness analysis already ensures that temps are dead.
4966eabb7b91SAurelien Jarno Keep an tcg_debug_assert for safety. */
4967eabb7b91SAurelien Jarno tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
4968c0522136SRichard Henderson break;
4969c0522136SRichard Henderson case TEMP_CONST:
4970c0522136SRichard Henderson /* Similarly, we should have freed any allocated register. */
4971c0522136SRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_CONST);
4972c0522136SRichard Henderson break;
4973c0522136SRichard Henderson default:
4974c0522136SRichard Henderson g_assert_not_reached();
4975c896fe29Sbellard }
4976641d5fbeSbellard }
4977e8996ee0Sbellard
4978e8996ee0Sbellard save_globals(s, allocated_regs);
4979c896fe29Sbellard }
4980c896fe29Sbellard
4981bab1671fSRichard Henderson /*
4982c7482438SRichard Henderson * At a conditional branch, we assume all temporaries are dead unless
4983c7482438SRichard Henderson * explicitly live-across-conditional-branch; all globals and local
4984c7482438SRichard Henderson * temps are synced to their location.
4985b4cb76e6SRichard Henderson */
tcg_reg_alloc_cbranch(TCGContext * s,TCGRegSet allocated_regs)4986b4cb76e6SRichard Henderson static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs)
4987b4cb76e6SRichard Henderson {
498876f42780SRichard Henderson assert_carry_dead(s);
4989b4cb76e6SRichard Henderson sync_globals(s, allocated_regs);
4990b4cb76e6SRichard Henderson
4991b4cb76e6SRichard Henderson for (int i = s->nb_globals; i < s->nb_temps; i++) {
4992b4cb76e6SRichard Henderson TCGTemp *ts = &s->temps[i];
4993b4cb76e6SRichard Henderson /*
4994b4cb76e6SRichard Henderson * The liveness analysis already ensures that temps are dead.
4995b4cb76e6SRichard Henderson * Keep tcg_debug_asserts for safety.
4996b4cb76e6SRichard Henderson */
4997c0522136SRichard Henderson switch (ts->kind) {
4998f57c6915SRichard Henderson case TEMP_TB:
4999b4cb76e6SRichard Henderson tcg_debug_assert(ts->val_type != TEMP_VAL_REG || ts->mem_coherent);
5000c0522136SRichard Henderson break;
5001c7482438SRichard Henderson case TEMP_EBB:
5002c0522136SRichard Henderson case TEMP_CONST:
5003c0522136SRichard Henderson break;
5004c0522136SRichard Henderson default:
5005c0522136SRichard Henderson g_assert_not_reached();
5006b4cb76e6SRichard Henderson }
5007b4cb76e6SRichard Henderson }
5008b4cb76e6SRichard Henderson }
5009b4cb76e6SRichard Henderson
5010b4cb76e6SRichard Henderson /*
5011c58f4c97SRichard Henderson * Specialized code generation for INDEX_op_mov_* with a constant.
5012bab1671fSRichard Henderson */
tcg_reg_alloc_do_movi(TCGContext * s,TCGTemp * ots,tcg_target_ulong val,TCGLifeData arg_life,TCGRegSet preferred_regs)50130fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots,
5014ba87719cSRichard Henderson tcg_target_ulong val, TCGLifeData arg_life,
5015ba87719cSRichard Henderson TCGRegSet preferred_regs)
5016e8996ee0Sbellard {
5017d63e3b6eSRichard Henderson /* ENV should not be modified. */
5018e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ots));
501959d7c14eSRichard Henderson
502059d7c14eSRichard Henderson /* The movi is not explicitly generated here. */
5021098859f1SRichard Henderson set_temp_val_nonreg(s, ots, TEMP_VAL_CONST);
5022e8996ee0Sbellard ots->val = val;
502359d7c14eSRichard Henderson ots->mem_coherent = 0;
5024ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) {
5025ba87719cSRichard Henderson temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0));
502659d7c14eSRichard Henderson } else if (IS_DEAD_ARG(0)) {
5027f8bf00f1SRichard Henderson temp_dead(s, ots);
50284c4e1ab2SAurelien Jarno }
5029e8996ee0Sbellard }
5030e8996ee0Sbellard
5031bab1671fSRichard Henderson /*
5032bab1671fSRichard Henderson * Specialized code generation for INDEX_op_mov_*.
5033bab1671fSRichard Henderson */
tcg_reg_alloc_mov(TCGContext * s,const TCGOp * op)5034dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op)
5035c896fe29Sbellard {
5036dd186292SRichard Henderson const TCGLifeData arg_life = op->life;
503769e3706dSRichard Henderson TCGRegSet allocated_regs, preferred_regs;
5038c896fe29Sbellard TCGTemp *ts, *ots;
5039450445d5SRichard Henderson TCGType otype, itype;
5040098859f1SRichard Henderson TCGReg oreg, ireg;
5041c896fe29Sbellard
5042d21369f5SRichard Henderson allocated_regs = s->reserved_regs;
504331fd884bSRichard Henderson preferred_regs = output_pref(op, 0);
504443439139SRichard Henderson ots = arg_temp(op->args[0]);
504543439139SRichard Henderson ts = arg_temp(op->args[1]);
5046450445d5SRichard Henderson
5047d63e3b6eSRichard Henderson /* ENV should not be modified. */
5048e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ots));
5049d63e3b6eSRichard Henderson
5050450445d5SRichard Henderson /* Note that otype != itype for no-op truncation. */
5051450445d5SRichard Henderson otype = ots->type;
5052450445d5SRichard Henderson itype = ts->type;
5053c896fe29Sbellard
50540fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_CONST) {
50550fe4fca4SPaolo Bonzini /* propagate constant or generate sti */
50560fe4fca4SPaolo Bonzini tcg_target_ulong val = ts->val;
50570fe4fca4SPaolo Bonzini if (IS_DEAD_ARG(1)) {
50580fe4fca4SPaolo Bonzini temp_dead(s, ts);
50590fe4fca4SPaolo Bonzini }
506069e3706dSRichard Henderson tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs);
50610fe4fca4SPaolo Bonzini return;
50620fe4fca4SPaolo Bonzini }
50630fe4fca4SPaolo Bonzini
50640fe4fca4SPaolo Bonzini /* If the source value is in memory we're going to be forced
50650fe4fca4SPaolo Bonzini to have it in a register in order to perform the copy. Copy
50660fe4fca4SPaolo Bonzini the SOURCE value into its own register first, that way we
50670fe4fca4SPaolo Bonzini don't have to reload SOURCE the next time it is used. */
50680fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_MEM) {
506969e3706dSRichard Henderson temp_load(s, ts, tcg_target_available_regs[itype],
507069e3706dSRichard Henderson allocated_regs, preferred_regs);
5071c29c1d7eSAurelien Jarno }
50720fe4fca4SPaolo Bonzini tcg_debug_assert(ts->val_type == TEMP_VAL_REG);
5073098859f1SRichard Henderson ireg = ts->reg;
5074098859f1SRichard Henderson
5075d63e3b6eSRichard Henderson if (IS_DEAD_ARG(0)) {
5076c29c1d7eSAurelien Jarno /* mov to a non-saved dead register makes no sense (even with
5077c29c1d7eSAurelien Jarno liveness analysis disabled). */
5078eabb7b91SAurelien Jarno tcg_debug_assert(NEED_SYNC_ARG(0));
5079c29c1d7eSAurelien Jarno if (!ots->mem_allocated) {
50802272e4a7SRichard Henderson temp_allocate_frame(s, ots);
5081c29c1d7eSAurelien Jarno }
5082098859f1SRichard Henderson tcg_out_st(s, otype, ireg, ots->mem_base->reg, ots->mem_offset);
5083c29c1d7eSAurelien Jarno if (IS_DEAD_ARG(1)) {
5084f8bf00f1SRichard Henderson temp_dead(s, ts);
5085c29c1d7eSAurelien Jarno }
5086f8bf00f1SRichard Henderson temp_dead(s, ots);
5087098859f1SRichard Henderson return;
5088098859f1SRichard Henderson }
5089098859f1SRichard Henderson
5090ee17db83SRichard Henderson if (IS_DEAD_ARG(1) && ts->kind != TEMP_FIXED) {
5091098859f1SRichard Henderson /*
5092098859f1SRichard Henderson * The mov can be suppressed. Kill input first, so that it
5093098859f1SRichard Henderson * is unlinked from reg_to_temp, then set the output to the
5094098859f1SRichard Henderson * reg that we saved from the input.
5095098859f1SRichard Henderson */
5096f8bf00f1SRichard Henderson temp_dead(s, ts);
5097098859f1SRichard Henderson oreg = ireg;
5098c29c1d7eSAurelien Jarno } else {
5099098859f1SRichard Henderson if (ots->val_type == TEMP_VAL_REG) {
5100098859f1SRichard Henderson oreg = ots->reg;
5101098859f1SRichard Henderson } else {
5102098859f1SRichard Henderson /* Make sure to not spill the input register during allocation. */
5103098859f1SRichard Henderson oreg = tcg_reg_alloc(s, tcg_target_available_regs[otype],
5104098859f1SRichard Henderson allocated_regs | ((TCGRegSet)1 << ireg),
5105098859f1SRichard Henderson preferred_regs, ots->indirect_base);
5106c29c1d7eSAurelien Jarno }
5107098859f1SRichard Henderson if (!tcg_out_mov(s, otype, oreg, ireg)) {
5108240c08d0SRichard Henderson /*
5109240c08d0SRichard Henderson * Cross register class move not supported.
5110240c08d0SRichard Henderson * Store the source register into the destination slot
5111240c08d0SRichard Henderson * and leave the destination temp as TEMP_VAL_MEM.
5112240c08d0SRichard Henderson */
5113e01fa97dSRichard Henderson assert(!temp_readonly(ots));
5114240c08d0SRichard Henderson if (!ts->mem_allocated) {
5115240c08d0SRichard Henderson temp_allocate_frame(s, ots);
5116240c08d0SRichard Henderson }
5117098859f1SRichard Henderson tcg_out_st(s, ts->type, ireg, ots->mem_base->reg, ots->mem_offset);
5118098859f1SRichard Henderson set_temp_val_nonreg(s, ts, TEMP_VAL_MEM);
5119240c08d0SRichard Henderson ots->mem_coherent = 1;
5120240c08d0SRichard Henderson return;
512178113e83SRichard Henderson }
5122c29c1d7eSAurelien Jarno }
5123098859f1SRichard Henderson set_temp_val_reg(s, ots, oreg);
5124c896fe29Sbellard ots->mem_coherent = 0;
5125098859f1SRichard Henderson
5126ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) {
512798b4e186SRichard Henderson temp_sync(s, ots, allocated_regs, 0, 0);
5128c29c1d7eSAurelien Jarno }
5129ec7a869dSAurelien Jarno }
5130c896fe29Sbellard
5131bab1671fSRichard Henderson /*
5132bab1671fSRichard Henderson * Specialized code generation for INDEX_op_dup_vec.
5133bab1671fSRichard Henderson */
tcg_reg_alloc_dup(TCGContext * s,const TCGOp * op)5134bab1671fSRichard Henderson static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op)
5135bab1671fSRichard Henderson {
5136bab1671fSRichard Henderson const TCGLifeData arg_life = op->life;
5137bab1671fSRichard Henderson TCGRegSet dup_out_regs, dup_in_regs;
5138501fb3daSRichard Henderson const TCGArgConstraint *dup_args_ct;
5139bab1671fSRichard Henderson TCGTemp *its, *ots;
5140bab1671fSRichard Henderson TCGType itype, vtype;
5141bab1671fSRichard Henderson unsigned vece;
514231c96417SRichard Henderson int lowpart_ofs;
5143bab1671fSRichard Henderson bool ok;
5144bab1671fSRichard Henderson
5145bab1671fSRichard Henderson ots = arg_temp(op->args[0]);
5146bab1671fSRichard Henderson its = arg_temp(op->args[1]);
5147bab1671fSRichard Henderson
5148bab1671fSRichard Henderson /* ENV should not be modified. */
5149e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ots));
5150bab1671fSRichard Henderson
5151bab1671fSRichard Henderson itype = its->type;
5152bab1671fSRichard Henderson vece = TCGOP_VECE(op);
51534d872218SRichard Henderson vtype = TCGOP_TYPE(op);
5154bab1671fSRichard Henderson
5155bab1671fSRichard Henderson if (its->val_type == TEMP_VAL_CONST) {
5156bab1671fSRichard Henderson /* Propagate constant via movi -> dupi. */
5157bab1671fSRichard Henderson tcg_target_ulong val = its->val;
5158bab1671fSRichard Henderson if (IS_DEAD_ARG(1)) {
5159bab1671fSRichard Henderson temp_dead(s, its);
5160bab1671fSRichard Henderson }
516131fd884bSRichard Henderson tcg_reg_alloc_do_movi(s, ots, val, arg_life, output_pref(op, 0));
5162bab1671fSRichard Henderson return;
5163bab1671fSRichard Henderson }
5164bab1671fSRichard Henderson
5165501fb3daSRichard Henderson dup_args_ct = opcode_args_ct(op);
5166501fb3daSRichard Henderson dup_out_regs = dup_args_ct[0].regs;
5167501fb3daSRichard Henderson dup_in_regs = dup_args_ct[1].regs;
5168bab1671fSRichard Henderson
5169bab1671fSRichard Henderson /* Allocate the output register now. */
5170bab1671fSRichard Henderson if (ots->val_type != TEMP_VAL_REG) {
5171bab1671fSRichard Henderson TCGRegSet allocated_regs = s->reserved_regs;
5172098859f1SRichard Henderson TCGReg oreg;
5173bab1671fSRichard Henderson
5174bab1671fSRichard Henderson if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) {
5175bab1671fSRichard Henderson /* Make sure to not spill the input register. */
5176bab1671fSRichard Henderson tcg_regset_set_reg(allocated_regs, its->reg);
5177bab1671fSRichard Henderson }
5178098859f1SRichard Henderson oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
517931fd884bSRichard Henderson output_pref(op, 0), ots->indirect_base);
5180098859f1SRichard Henderson set_temp_val_reg(s, ots, oreg);
5181bab1671fSRichard Henderson }
5182bab1671fSRichard Henderson
5183bab1671fSRichard Henderson switch (its->val_type) {
5184bab1671fSRichard Henderson case TEMP_VAL_REG:
5185bab1671fSRichard Henderson /*
5186bab1671fSRichard Henderson * The dup constriaints must be broad, covering all possible VECE.
5187bab1671fSRichard Henderson * However, tcg_op_dup_vec() gets to see the VECE and we allow it
5188bab1671fSRichard Henderson * to fail, indicating that extra moves are required for that case.
5189bab1671fSRichard Henderson */
5190bab1671fSRichard Henderson if (tcg_regset_test_reg(dup_in_regs, its->reg)) {
5191bab1671fSRichard Henderson if (tcg_out_dup_vec(s, vtype, vece, ots->reg, its->reg)) {
5192bab1671fSRichard Henderson goto done;
5193bab1671fSRichard Henderson }
5194bab1671fSRichard Henderson /* Try again from memory or a vector input register. */
5195bab1671fSRichard Henderson }
5196bab1671fSRichard Henderson if (!its->mem_coherent) {
5197bab1671fSRichard Henderson /*
5198bab1671fSRichard Henderson * The input register is not synced, and so an extra store
5199bab1671fSRichard Henderson * would be required to use memory. Attempt an integer-vector
5200bab1671fSRichard Henderson * register move first. We do not have a TCGRegSet for this.
5201bab1671fSRichard Henderson */
5202bab1671fSRichard Henderson if (tcg_out_mov(s, itype, ots->reg, its->reg)) {
5203bab1671fSRichard Henderson break;
5204bab1671fSRichard Henderson }
5205bab1671fSRichard Henderson /* Sync the temp back to its slot and load from there. */
5206bab1671fSRichard Henderson temp_sync(s, its, s->reserved_regs, 0, 0);
5207bab1671fSRichard Henderson }
5208bab1671fSRichard Henderson /* fall through */
5209bab1671fSRichard Henderson
5210bab1671fSRichard Henderson case TEMP_VAL_MEM:
521131c96417SRichard Henderson lowpart_ofs = 0;
521231c96417SRichard Henderson if (HOST_BIG_ENDIAN) {
521331c96417SRichard Henderson lowpart_ofs = tcg_type_size(itype) - (1 << vece);
521431c96417SRichard Henderson }
5215d6ecb4a9SRichard Henderson if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg,
521631c96417SRichard Henderson its->mem_offset + lowpart_ofs)) {
5217d6ecb4a9SRichard Henderson goto done;
5218d6ecb4a9SRichard Henderson }
5219098859f1SRichard Henderson /* Load the input into the destination vector register. */
5220bab1671fSRichard Henderson tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset);
5221bab1671fSRichard Henderson break;
5222bab1671fSRichard Henderson
5223bab1671fSRichard Henderson default:
5224bab1671fSRichard Henderson g_assert_not_reached();
5225bab1671fSRichard Henderson }
5226bab1671fSRichard Henderson
5227bab1671fSRichard Henderson /* We now have a vector input register, so dup must succeed. */
5228bab1671fSRichard Henderson ok = tcg_out_dup_vec(s, vtype, vece, ots->reg, ots->reg);
5229bab1671fSRichard Henderson tcg_debug_assert(ok);
5230bab1671fSRichard Henderson
5231bab1671fSRichard Henderson done:
523236f5539cSRichard Henderson ots->mem_coherent = 0;
5233bab1671fSRichard Henderson if (IS_DEAD_ARG(1)) {
5234bab1671fSRichard Henderson temp_dead(s, its);
5235bab1671fSRichard Henderson }
5236bab1671fSRichard Henderson if (NEED_SYNC_ARG(0)) {
5237bab1671fSRichard Henderson temp_sync(s, ots, s->reserved_regs, 0, 0);
5238bab1671fSRichard Henderson }
5239bab1671fSRichard Henderson if (IS_DEAD_ARG(0)) {
5240bab1671fSRichard Henderson temp_dead(s, ots);
5241bab1671fSRichard Henderson }
5242bab1671fSRichard Henderson }
5243bab1671fSRichard Henderson
tcg_reg_alloc_op(TCGContext * s,const TCGOp * op)5244dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op)
5245c896fe29Sbellard {
5246dd186292SRichard Henderson const TCGLifeData arg_life = op->life;
5247dd186292SRichard Henderson const TCGOpDef * const def = &tcg_op_defs[op->opc];
524882790a87SRichard Henderson TCGRegSet i_allocated_regs;
524982790a87SRichard Henderson TCGRegSet o_allocated_regs;
5250b6638662SRichard Henderson int i, k, nb_iargs, nb_oargs;
5251b6638662SRichard Henderson TCGReg reg;
5252c896fe29Sbellard TCGArg arg;
5253501fb3daSRichard Henderson const TCGArgConstraint *args_ct;
5254c896fe29Sbellard const TCGArgConstraint *arg_ct;
5255c896fe29Sbellard TCGTemp *ts;
5256c896fe29Sbellard TCGArg new_args[TCG_MAX_OP_ARGS];
5257c896fe29Sbellard int const_args[TCG_MAX_OP_ARGS];
525821e9a8aeSRichard Henderson TCGCond op_cond;
5259c896fe29Sbellard
526076f42780SRichard Henderson if (def->flags & TCG_OPF_CARRY_IN) {
526176f42780SRichard Henderson tcg_debug_assert(s->carry_live);
526276f42780SRichard Henderson }
526376f42780SRichard Henderson
5264c896fe29Sbellard nb_oargs = def->nb_oargs;
5265c896fe29Sbellard nb_iargs = def->nb_iargs;
5266c896fe29Sbellard
5267c896fe29Sbellard /* copy constants */
5268c896fe29Sbellard memcpy(new_args + nb_oargs + nb_iargs,
5269dd186292SRichard Henderson op->args + nb_oargs + nb_iargs,
5270c896fe29Sbellard sizeof(TCGArg) * def->nb_cargs);
5271c896fe29Sbellard
5272d21369f5SRichard Henderson i_allocated_regs = s->reserved_regs;
5273d21369f5SRichard Henderson o_allocated_regs = s->reserved_regs;
527482790a87SRichard Henderson
527521e9a8aeSRichard Henderson switch (op->opc) {
5276b6d69fceSRichard Henderson case INDEX_op_brcond:
527721e9a8aeSRichard Henderson op_cond = op->args[2];
527821e9a8aeSRichard Henderson break;
5279a363e1e1SRichard Henderson case INDEX_op_setcond:
5280a363e1e1SRichard Henderson case INDEX_op_negsetcond:
528121e9a8aeSRichard Henderson case INDEX_op_cmp_vec:
528221e9a8aeSRichard Henderson op_cond = op->args[3];
528321e9a8aeSRichard Henderson break;
528421e9a8aeSRichard Henderson case INDEX_op_brcond2_i32:
528521e9a8aeSRichard Henderson op_cond = op->args[4];
528621e9a8aeSRichard Henderson break;
5287ea46c4bcSRichard Henderson case INDEX_op_movcond:
528821e9a8aeSRichard Henderson case INDEX_op_setcond2_i32:
528921e9a8aeSRichard Henderson case INDEX_op_cmpsel_vec:
529021e9a8aeSRichard Henderson op_cond = op->args[5];
529121e9a8aeSRichard Henderson break;
529221e9a8aeSRichard Henderson default:
529321e9a8aeSRichard Henderson /* No condition within opcode. */
529421e9a8aeSRichard Henderson op_cond = TCG_COND_ALWAYS;
529521e9a8aeSRichard Henderson break;
529621e9a8aeSRichard Henderson }
529721e9a8aeSRichard Henderson
5298501fb3daSRichard Henderson args_ct = opcode_args_ct(op);
5299501fb3daSRichard Henderson
5300c896fe29Sbellard /* satisfy input constraints */
5301c896fe29Sbellard for (k = 0; k < nb_iargs; k++) {
530229f5e925SRichard Henderson TCGRegSet i_preferred_regs, i_required_regs;
530329f5e925SRichard Henderson bool allocate_new_reg, copyto_new_reg;
530429f5e925SRichard Henderson TCGTemp *ts2;
530529f5e925SRichard Henderson int i1, i2;
5306d62816f2SRichard Henderson
5307501fb3daSRichard Henderson i = args_ct[nb_oargs + k].sort_index;
5308dd186292SRichard Henderson arg = op->args[i];
5309501fb3daSRichard Henderson arg_ct = &args_ct[i];
531043439139SRichard Henderson ts = arg_temp(arg);
531140ae5c62SRichard Henderson
53126b8abd24SRichard Henderson if (ts->val_type == TEMP_VAL_CONST) {
53136b8abd24SRichard Henderson #ifdef TCG_REG_ZERO
53146b8abd24SRichard Henderson if (ts->val == 0 && (arg_ct->ct & TCG_CT_REG_ZERO)) {
53156b8abd24SRichard Henderson /* Hardware zero register: indicate register via non-const. */
53166b8abd24SRichard Henderson const_args[i] = 0;
53176b8abd24SRichard Henderson new_args[i] = TCG_REG_ZERO;
53186b8abd24SRichard Henderson continue;
53196b8abd24SRichard Henderson }
53206b8abd24SRichard Henderson #endif
53216b8abd24SRichard Henderson
53226b8abd24SRichard Henderson if (tcg_target_const_match(ts->val, arg_ct->ct, ts->type,
532321e9a8aeSRichard Henderson op_cond, TCGOP_VECE(op))) {
5324c896fe29Sbellard /* constant is OK for instruction */
5325c896fe29Sbellard const_args[i] = 1;
5326c896fe29Sbellard new_args[i] = ts->val;
5327d62816f2SRichard Henderson continue;
5328c896fe29Sbellard }
53296b8abd24SRichard Henderson }
533040ae5c62SRichard Henderson
53311c1824dcSRichard Henderson reg = ts->reg;
53321c1824dcSRichard Henderson i_preferred_regs = 0;
533329f5e925SRichard Henderson i_required_regs = arg_ct->regs;
53341c1824dcSRichard Henderson allocate_new_reg = false;
533529f5e925SRichard Henderson copyto_new_reg = false;
53361c1824dcSRichard Henderson
533729f5e925SRichard Henderson switch (arg_ct->pair) {
533829f5e925SRichard Henderson case 0: /* not paired */
5339bc2b17e6SRichard Henderson if (arg_ct->ialias) {
534031fd884bSRichard Henderson i_preferred_regs = output_pref(op, arg_ct->alias_index);
5341c0522136SRichard Henderson
5342c0522136SRichard Henderson /*
5343c0522136SRichard Henderson * If the input is readonly, then it cannot also be an
5344c0522136SRichard Henderson * output and aliased to itself. If the input is not
5345c0522136SRichard Henderson * dead after the instruction, we must allocate a new
5346c0522136SRichard Henderson * register and move it.
5347c0522136SRichard Henderson */
534822d2e535SIlya Leoshkevich if (temp_readonly(ts) || !IS_DEAD_ARG(i)
5349501fb3daSRichard Henderson || args_ct[arg_ct->alias_index].newreg) {
53501c1824dcSRichard Henderson allocate_new_reg = true;
53511c1824dcSRichard Henderson } else if (ts->val_type == TEMP_VAL_REG) {
5352c0522136SRichard Henderson /*
53531c1824dcSRichard Henderson * Check if the current register has already been
53541c1824dcSRichard Henderson * allocated for another input.
5355c0522136SRichard Henderson */
535629f5e925SRichard Henderson allocate_new_reg =
535729f5e925SRichard Henderson tcg_regset_test_reg(i_allocated_regs, reg);
53587e1df267SAurelien Jarno }
53597e1df267SAurelien Jarno }
53601c1824dcSRichard Henderson if (!allocate_new_reg) {
536129f5e925SRichard Henderson temp_load(s, ts, i_required_regs, i_allocated_regs,
536229f5e925SRichard Henderson i_preferred_regs);
5363c896fe29Sbellard reg = ts->reg;
536429f5e925SRichard Henderson allocate_new_reg = !tcg_regset_test_reg(i_required_regs, reg);
53651c1824dcSRichard Henderson }
53661c1824dcSRichard Henderson if (allocate_new_reg) {
5367c0522136SRichard Henderson /*
5368c0522136SRichard Henderson * Allocate a new register matching the constraint
5369c0522136SRichard Henderson * and move the temporary register into it.
5370c0522136SRichard Henderson */
5371d62816f2SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type],
5372d62816f2SRichard Henderson i_allocated_regs, 0);
537329f5e925SRichard Henderson reg = tcg_reg_alloc(s, i_required_regs, i_allocated_regs,
53741c1824dcSRichard Henderson i_preferred_regs, ts->indirect_base);
537529f5e925SRichard Henderson copyto_new_reg = true;
537629f5e925SRichard Henderson }
537729f5e925SRichard Henderson break;
537829f5e925SRichard Henderson
537929f5e925SRichard Henderson case 1:
538029f5e925SRichard Henderson /* First of an input pair; if i1 == i2, the second is an output. */
538129f5e925SRichard Henderson i1 = i;
538229f5e925SRichard Henderson i2 = arg_ct->pair_index;
538329f5e925SRichard Henderson ts2 = i1 != i2 ? arg_temp(op->args[i2]) : NULL;
538429f5e925SRichard Henderson
538529f5e925SRichard Henderson /*
538629f5e925SRichard Henderson * It is easier to default to allocating a new pair
538729f5e925SRichard Henderson * and to identify a few cases where it's not required.
538829f5e925SRichard Henderson */
538929f5e925SRichard Henderson if (arg_ct->ialias) {
539031fd884bSRichard Henderson i_preferred_regs = output_pref(op, arg_ct->alias_index);
539129f5e925SRichard Henderson if (IS_DEAD_ARG(i1) &&
539229f5e925SRichard Henderson IS_DEAD_ARG(i2) &&
539329f5e925SRichard Henderson !temp_readonly(ts) &&
539429f5e925SRichard Henderson ts->val_type == TEMP_VAL_REG &&
539529f5e925SRichard Henderson ts->reg < TCG_TARGET_NB_REGS - 1 &&
539629f5e925SRichard Henderson tcg_regset_test_reg(i_required_regs, reg) &&
539729f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg) &&
539829f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg + 1) &&
539929f5e925SRichard Henderson (ts2
540029f5e925SRichard Henderson ? ts2->val_type == TEMP_VAL_REG &&
540129f5e925SRichard Henderson ts2->reg == reg + 1 &&
540229f5e925SRichard Henderson !temp_readonly(ts2)
540329f5e925SRichard Henderson : s->reg_to_temp[reg + 1] == NULL)) {
540429f5e925SRichard Henderson break;
540529f5e925SRichard Henderson }
540629f5e925SRichard Henderson } else {
540729f5e925SRichard Henderson /* Without aliasing, the pair must also be an input. */
540829f5e925SRichard Henderson tcg_debug_assert(ts2);
540929f5e925SRichard Henderson if (ts->val_type == TEMP_VAL_REG &&
541029f5e925SRichard Henderson ts2->val_type == TEMP_VAL_REG &&
541129f5e925SRichard Henderson ts2->reg == reg + 1 &&
541229f5e925SRichard Henderson tcg_regset_test_reg(i_required_regs, reg)) {
541329f5e925SRichard Henderson break;
541429f5e925SRichard Henderson }
541529f5e925SRichard Henderson }
541629f5e925SRichard Henderson reg = tcg_reg_alloc_pair(s, i_required_regs, i_allocated_regs,
541729f5e925SRichard Henderson 0, ts->indirect_base);
541829f5e925SRichard Henderson goto do_pair;
541929f5e925SRichard Henderson
542029f5e925SRichard Henderson case 2: /* pair second */
542129f5e925SRichard Henderson reg = new_args[arg_ct->pair_index] + 1;
542229f5e925SRichard Henderson goto do_pair;
542329f5e925SRichard Henderson
542429f5e925SRichard Henderson case 3: /* ialias with second output, no first input */
542529f5e925SRichard Henderson tcg_debug_assert(arg_ct->ialias);
542631fd884bSRichard Henderson i_preferred_regs = output_pref(op, arg_ct->alias_index);
542729f5e925SRichard Henderson
542829f5e925SRichard Henderson if (IS_DEAD_ARG(i) &&
542929f5e925SRichard Henderson !temp_readonly(ts) &&
543029f5e925SRichard Henderson ts->val_type == TEMP_VAL_REG &&
543129f5e925SRichard Henderson reg > 0 &&
543229f5e925SRichard Henderson s->reg_to_temp[reg - 1] == NULL &&
543329f5e925SRichard Henderson tcg_regset_test_reg(i_required_regs, reg) &&
543429f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg) &&
543529f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg - 1)) {
543629f5e925SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg - 1);
543729f5e925SRichard Henderson break;
543829f5e925SRichard Henderson }
543929f5e925SRichard Henderson reg = tcg_reg_alloc_pair(s, i_required_regs >> 1,
544029f5e925SRichard Henderson i_allocated_regs, 0,
544129f5e925SRichard Henderson ts->indirect_base);
544229f5e925SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg);
544329f5e925SRichard Henderson reg += 1;
544429f5e925SRichard Henderson goto do_pair;
544529f5e925SRichard Henderson
544629f5e925SRichard Henderson do_pair:
544729f5e925SRichard Henderson /*
544829f5e925SRichard Henderson * If an aliased input is not dead after the instruction,
544929f5e925SRichard Henderson * we must allocate a new register and move it.
545029f5e925SRichard Henderson */
545129f5e925SRichard Henderson if (arg_ct->ialias && (!IS_DEAD_ARG(i) || temp_readonly(ts))) {
545229f5e925SRichard Henderson TCGRegSet t_allocated_regs = i_allocated_regs;
545329f5e925SRichard Henderson
545429f5e925SRichard Henderson /*
545529f5e925SRichard Henderson * Because of the alias, and the continued life, make sure
545629f5e925SRichard Henderson * that the temp is somewhere *other* than the reg pair,
545729f5e925SRichard Henderson * and we get a copy in reg.
545829f5e925SRichard Henderson */
545929f5e925SRichard Henderson tcg_regset_set_reg(t_allocated_regs, reg);
546029f5e925SRichard Henderson tcg_regset_set_reg(t_allocated_regs, reg + 1);
546129f5e925SRichard Henderson if (ts->val_type == TEMP_VAL_REG && ts->reg == reg) {
546229f5e925SRichard Henderson /* If ts was already in reg, copy it somewhere else. */
546329f5e925SRichard Henderson TCGReg nr;
546429f5e925SRichard Henderson bool ok;
546529f5e925SRichard Henderson
546629f5e925SRichard Henderson tcg_debug_assert(ts->kind != TEMP_FIXED);
546729f5e925SRichard Henderson nr = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
546829f5e925SRichard Henderson t_allocated_regs, 0, ts->indirect_base);
546929f5e925SRichard Henderson ok = tcg_out_mov(s, ts->type, nr, reg);
547029f5e925SRichard Henderson tcg_debug_assert(ok);
547129f5e925SRichard Henderson
547229f5e925SRichard Henderson set_temp_val_reg(s, ts, nr);
547329f5e925SRichard Henderson } else {
547429f5e925SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type],
547529f5e925SRichard Henderson t_allocated_regs, 0);
547629f5e925SRichard Henderson copyto_new_reg = true;
547729f5e925SRichard Henderson }
547829f5e925SRichard Henderson } else {
547929f5e925SRichard Henderson /* Preferably allocate to reg, otherwise copy. */
548029f5e925SRichard Henderson i_required_regs = (TCGRegSet)1 << reg;
548129f5e925SRichard Henderson temp_load(s, ts, i_required_regs, i_allocated_regs,
548229f5e925SRichard Henderson i_preferred_regs);
548329f5e925SRichard Henderson copyto_new_reg = ts->reg != reg;
548429f5e925SRichard Henderson }
548529f5e925SRichard Henderson break;
548629f5e925SRichard Henderson
548729f5e925SRichard Henderson default:
548829f5e925SRichard Henderson g_assert_not_reached();
548929f5e925SRichard Henderson }
549029f5e925SRichard Henderson
549129f5e925SRichard Henderson if (copyto_new_reg) {
549278113e83SRichard Henderson if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
5493240c08d0SRichard Henderson /*
5494240c08d0SRichard Henderson * Cross register class move not supported. Sync the
5495240c08d0SRichard Henderson * temp back to its slot and load from there.
5496240c08d0SRichard Henderson */
5497240c08d0SRichard Henderson temp_sync(s, ts, i_allocated_regs, 0, 0);
5498240c08d0SRichard Henderson tcg_out_ld(s, ts->type, reg,
5499240c08d0SRichard Henderson ts->mem_base->reg, ts->mem_offset);
550078113e83SRichard Henderson }
5501c896fe29Sbellard }
5502c896fe29Sbellard new_args[i] = reg;
5503c896fe29Sbellard const_args[i] = 0;
550482790a87SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg);
5505c896fe29Sbellard }
5506c896fe29Sbellard
5507c896fe29Sbellard /* mark dead temporaries and free the associated registers */
5508866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
5509866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) {
551043439139SRichard Henderson temp_dead(s, arg_temp(op->args[i]));
5511c896fe29Sbellard }
5512c896fe29Sbellard }
5513c896fe29Sbellard
5514b4cb76e6SRichard Henderson if (def->flags & TCG_OPF_COND_BRANCH) {
5515b4cb76e6SRichard Henderson tcg_reg_alloc_cbranch(s, i_allocated_regs);
5516b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) {
551782790a87SRichard Henderson tcg_reg_alloc_bb_end(s, i_allocated_regs);
5518a52ad07eSAurelien Jarno } else {
5519c896fe29Sbellard if (def->flags & TCG_OPF_CALL_CLOBBER) {
552076f42780SRichard Henderson assert_carry_dead(s);
5521b03cce8eSbellard /* XXX: permit generic clobber register list ? */
5522c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
5523c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
552482790a87SRichard Henderson tcg_reg_free(s, i, i_allocated_regs);
5525c896fe29Sbellard }
5526c896fe29Sbellard }
55273d5c5f87SAurelien Jarno }
55283d5c5f87SAurelien Jarno if (def->flags & TCG_OPF_SIDE_EFFECTS) {
55293d5c5f87SAurelien Jarno /* sync globals if the op has side effects and might trigger
55303d5c5f87SAurelien Jarno an exception. */
553182790a87SRichard Henderson sync_globals(s, i_allocated_regs);
5532c896fe29Sbellard }
5533c896fe29Sbellard
5534c896fe29Sbellard /* satisfy the output constraints */
5535c896fe29Sbellard for (k = 0; k < nb_oargs; k++) {
5536501fb3daSRichard Henderson i = args_ct[k].sort_index;
5537dd186292SRichard Henderson arg = op->args[i];
5538501fb3daSRichard Henderson arg_ct = &args_ct[i];
553943439139SRichard Henderson ts = arg_temp(arg);
5540d63e3b6eSRichard Henderson
5541d63e3b6eSRichard Henderson /* ENV should not be modified. */
5542e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ts));
5543d63e3b6eSRichard Henderson
554429f5e925SRichard Henderson switch (arg_ct->pair) {
554529f5e925SRichard Henderson case 0: /* not paired */
5546bc2b17e6SRichard Henderson if (arg_ct->oalias && !const_args[arg_ct->alias_index]) {
55475ff9d6a4Sbellard reg = new_args[arg_ct->alias_index];
5548bc2b17e6SRichard Henderson } else if (arg_ct->newreg) {
55499be0d080SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->regs,
555082790a87SRichard Henderson i_allocated_regs | o_allocated_regs,
555131fd884bSRichard Henderson output_pref(op, k), ts->indirect_base);
5552c896fe29Sbellard } else {
55539be0d080SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs,
555431fd884bSRichard Henderson output_pref(op, k), ts->indirect_base);
5555c896fe29Sbellard }
555629f5e925SRichard Henderson break;
555729f5e925SRichard Henderson
555829f5e925SRichard Henderson case 1: /* first of pair */
555929f5e925SRichard Henderson if (arg_ct->oalias) {
556029f5e925SRichard Henderson reg = new_args[arg_ct->alias_index];
5561ca5bed07SRichard Henderson } else if (arg_ct->newreg) {
5562ca5bed07SRichard Henderson reg = tcg_reg_alloc_pair(s, arg_ct->regs,
5563ca5bed07SRichard Henderson i_allocated_regs | o_allocated_regs,
5564ca5bed07SRichard Henderson output_pref(op, k),
5565ca5bed07SRichard Henderson ts->indirect_base);
5566ca5bed07SRichard Henderson } else {
556729f5e925SRichard Henderson reg = tcg_reg_alloc_pair(s, arg_ct->regs, o_allocated_regs,
5568ca5bed07SRichard Henderson output_pref(op, k),
5569ca5bed07SRichard Henderson ts->indirect_base);
5570ca5bed07SRichard Henderson }
557129f5e925SRichard Henderson break;
557229f5e925SRichard Henderson
557329f5e925SRichard Henderson case 2: /* second of pair */
557429f5e925SRichard Henderson if (arg_ct->oalias) {
557529f5e925SRichard Henderson reg = new_args[arg_ct->alias_index];
557629f5e925SRichard Henderson } else {
557729f5e925SRichard Henderson reg = new_args[arg_ct->pair_index] + 1;
557829f5e925SRichard Henderson }
557929f5e925SRichard Henderson break;
558029f5e925SRichard Henderson
558129f5e925SRichard Henderson case 3: /* first of pair, aliasing with a second input */
558229f5e925SRichard Henderson tcg_debug_assert(!arg_ct->newreg);
558329f5e925SRichard Henderson reg = new_args[arg_ct->pair_index] - 1;
558429f5e925SRichard Henderson break;
558529f5e925SRichard Henderson
558629f5e925SRichard Henderson default:
558729f5e925SRichard Henderson g_assert_not_reached();
558829f5e925SRichard Henderson }
558982790a87SRichard Henderson tcg_regset_set_reg(o_allocated_regs, reg);
5590098859f1SRichard Henderson set_temp_val_reg(s, ts, reg);
5591c896fe29Sbellard ts->mem_coherent = 0;
5592c896fe29Sbellard new_args[i] = reg;
5593c896fe29Sbellard }
5594e8996ee0Sbellard }
5595c896fe29Sbellard
5596c896fe29Sbellard /* emit instruction */
5597662cdbcfSRichard Henderson TCGType type = TCGOP_TYPE(op);
5598678155b2SRichard Henderson switch (op->opc) {
5599ee603152SRichard Henderson case INDEX_op_addc1o:
5600ee603152SRichard Henderson tcg_out_set_carry(s);
5601ee603152SRichard Henderson /* fall through */
560279602f63SRichard Henderson case INDEX_op_add:
5603ee603152SRichard Henderson case INDEX_op_addcio:
5604ee603152SRichard Henderson case INDEX_op_addco:
5605c3b920b3SRichard Henderson case INDEX_op_and:
560646f96bffSRichard Henderson case INDEX_op_andc:
56075a5bb0a5SRichard Henderson case INDEX_op_clz:
5608c96447d8SRichard Henderson case INDEX_op_ctz:
5609b2c514f9SRichard Henderson case INDEX_op_divs:
5610961b80aeSRichard Henderson case INDEX_op_divu:
56115c0968a7SRichard Henderson case INDEX_op_eqv:
5612d2c3ecadSRichard Henderson case INDEX_op_mul:
5613c742824dSRichard Henderson case INDEX_op_mulsh:
5614aa28c9efSRichard Henderson case INDEX_op_muluh:
561559379a45SRichard Henderson case INDEX_op_nand:
56163a8c4e9eSRichard Henderson case INDEX_op_nor:
561749bd7514SRichard Henderson case INDEX_op_or:
56186aba25ebSRichard Henderson case INDEX_op_orc:
56199a6bc184SRichard Henderson case INDEX_op_rems:
5620cd9acd20SRichard Henderson case INDEX_op_remu:
5621005a87e1SRichard Henderson case INDEX_op_rotl:
5622005a87e1SRichard Henderson case INDEX_op_rotr:
56233949f365SRichard Henderson case INDEX_op_sar:
56246ca59451SRichard Henderson case INDEX_op_shl:
562574dbd36fSRichard Henderson case INDEX_op_shr:
5626fffd3dc9SRichard Henderson case INDEX_op_xor:
5627662cdbcfSRichard Henderson {
5628662cdbcfSRichard Henderson const TCGOutOpBinary *out =
5629662cdbcfSRichard Henderson container_of(all_outop[op->opc], TCGOutOpBinary, base);
5630662cdbcfSRichard Henderson
5631662cdbcfSRichard Henderson /* Constants should never appear in the first source operand. */
5632662cdbcfSRichard Henderson tcg_debug_assert(!const_args[1]);
5633662cdbcfSRichard Henderson if (const_args[2]) {
5634662cdbcfSRichard Henderson out->out_rri(s, type, new_args[0], new_args[1], new_args[2]);
5635662cdbcfSRichard Henderson } else {
5636662cdbcfSRichard Henderson out->out_rrr(s, type, new_args[0], new_args[1], new_args[2]);
5637662cdbcfSRichard Henderson }
5638662cdbcfSRichard Henderson }
5639662cdbcfSRichard Henderson break;
5640662cdbcfSRichard Henderson
564160f34f55SRichard Henderson case INDEX_op_sub:
56423f057e24SRichard Henderson {
5643ee603152SRichard Henderson const TCGOutOpSubtract *out = &outop_sub;
56443f057e24SRichard Henderson
56453f057e24SRichard Henderson /*
56463f057e24SRichard Henderson * Constants should never appear in the second source operand.
56473f057e24SRichard Henderson * These are folded to add with negative constant.
56483f057e24SRichard Henderson */
56493f057e24SRichard Henderson tcg_debug_assert(!const_args[2]);
56503f057e24SRichard Henderson if (const_args[1]) {
56513f057e24SRichard Henderson out->out_rir(s, type, new_args[0], new_args[1], new_args[2]);
56523f057e24SRichard Henderson } else {
56533f057e24SRichard Henderson out->out_rrr(s, type, new_args[0], new_args[1], new_args[2]);
56543f057e24SRichard Henderson }
56553f057e24SRichard Henderson }
56563f057e24SRichard Henderson break;
56573f057e24SRichard Henderson
5658ee603152SRichard Henderson case INDEX_op_subb1o:
5659ee603152SRichard Henderson tcg_out_set_borrow(s);
5660ee603152SRichard Henderson /* fall through */
566176f42780SRichard Henderson case INDEX_op_addci:
566276f42780SRichard Henderson case INDEX_op_subbi:
566376f42780SRichard Henderson case INDEX_op_subbio:
5664ee603152SRichard Henderson case INDEX_op_subbo:
5665ee603152SRichard Henderson {
5666ee603152SRichard Henderson const TCGOutOpAddSubCarry *out =
5667ee603152SRichard Henderson container_of(all_outop[op->opc], TCGOutOpAddSubCarry, base);
5668ee603152SRichard Henderson
5669ee603152SRichard Henderson if (const_args[2]) {
5670ee603152SRichard Henderson if (const_args[1]) {
5671ee603152SRichard Henderson out->out_rii(s, type, new_args[0],
5672ee603152SRichard Henderson new_args[1], new_args[2]);
5673ee603152SRichard Henderson } else {
5674ee603152SRichard Henderson out->out_rri(s, type, new_args[0],
5675ee603152SRichard Henderson new_args[1], new_args[2]);
5676ee603152SRichard Henderson }
5677ee603152SRichard Henderson } else if (const_args[1]) {
5678ee603152SRichard Henderson out->out_rir(s, type, new_args[0], new_args[1], new_args[2]);
5679ee603152SRichard Henderson } else {
5680ee603152SRichard Henderson out->out_rrr(s, type, new_args[0], new_args[1], new_args[2]);
5681ee603152SRichard Henderson }
5682ee603152SRichard Henderson }
5683ee603152SRichard Henderson break;
568476f42780SRichard Henderson
56853ad5d4ccSRichard Henderson case INDEX_op_bswap64:
5686b7b7347fSRichard Henderson case INDEX_op_ext_i32_i64:
5687c1ad25deSRichard Henderson case INDEX_op_extu_i32_i64:
56881e6fec9dSRichard Henderson case INDEX_op_extrl_i64_i32:
5689b3b13976SRichard Henderson case INDEX_op_extrh_i64_i32:
5690613b571cSRichard Henderson assert(TCG_TARGET_REG_BITS == 64);
5691613b571cSRichard Henderson /* fall through */
569297218ae9SRichard Henderson case INDEX_op_ctpop:
569369713587SRichard Henderson case INDEX_op_neg:
56945c62d377SRichard Henderson case INDEX_op_not:
5695e126a91cSRichard Henderson {
5696e126a91cSRichard Henderson const TCGOutOpUnary *out =
5697e126a91cSRichard Henderson container_of(all_outop[op->opc], TCGOutOpUnary, base);
5698e126a91cSRichard Henderson
5699e126a91cSRichard Henderson /* Constants should have been folded. */
5700e126a91cSRichard Henderson tcg_debug_assert(!const_args[1]);
5701e126a91cSRichard Henderson out->out_rr(s, type, new_args[0], new_args[1]);
5702e126a91cSRichard Henderson }
5703e126a91cSRichard Henderson break;
5704e126a91cSRichard Henderson
57050dd07ee1SRichard Henderson case INDEX_op_bswap16:
57067498d882SRichard Henderson case INDEX_op_bswap32:
57075fa8e138SRichard Henderson {
57085fa8e138SRichard Henderson const TCGOutOpBswap *out =
57095fa8e138SRichard Henderson container_of(all_outop[op->opc], TCGOutOpBswap, base);
57105fa8e138SRichard Henderson
57115fa8e138SRichard Henderson tcg_debug_assert(!const_args[1]);
57125fa8e138SRichard Henderson out->out_rr(s, type, new_args[0], new_args[1], new_args[2]);
57135fa8e138SRichard Henderson }
57145fa8e138SRichard Henderson break;
57155fa8e138SRichard Henderson
57164d137ff8SRichard Henderson case INDEX_op_deposit:
5717cf4905c0SRichard Henderson {
5718cf4905c0SRichard Henderson const TCGOutOpDeposit *out = &outop_deposit;
5719cf4905c0SRichard Henderson
5720cf4905c0SRichard Henderson if (const_args[2]) {
5721cf4905c0SRichard Henderson tcg_debug_assert(!const_args[1]);
5722cf4905c0SRichard Henderson out->out_rri(s, type, new_args[0], new_args[1],
5723cf4905c0SRichard Henderson new_args[2], new_args[3], new_args[4]);
5724cf4905c0SRichard Henderson } else if (const_args[1]) {
5725cf4905c0SRichard Henderson tcg_debug_assert(new_args[1] == 0);
5726cf4905c0SRichard Henderson tcg_debug_assert(!const_args[2]);
5727cf4905c0SRichard Henderson out->out_rzr(s, type, new_args[0], new_args[2],
5728cf4905c0SRichard Henderson new_args[3], new_args[4]);
5729cf4905c0SRichard Henderson } else {
5730cf4905c0SRichard Henderson out->out_rrr(s, type, new_args[0], new_args[1],
5731cf4905c0SRichard Henderson new_args[2], new_args[3], new_args[4]);
5732cf4905c0SRichard Henderson }
5733cf4905c0SRichard Henderson }
5734cf4905c0SRichard Henderson break;
5735cf4905c0SRichard Henderson
5736ee1805b9SRichard Henderson case INDEX_op_divs2:
57378109598bSRichard Henderson case INDEX_op_divu2:
5738d6cad9c9SRichard Henderson {
5739d6cad9c9SRichard Henderson const TCGOutOpDivRem *out =
5740d6cad9c9SRichard Henderson container_of(all_outop[op->opc], TCGOutOpDivRem, base);
5741d6cad9c9SRichard Henderson
5742d6cad9c9SRichard Henderson /* Only used by x86 and s390x, which use matching constraints. */
5743d6cad9c9SRichard Henderson tcg_debug_assert(new_args[0] == new_args[2]);
5744d6cad9c9SRichard Henderson tcg_debug_assert(new_args[1] == new_args[3]);
5745d6cad9c9SRichard Henderson tcg_debug_assert(!const_args[4]);
5746d6cad9c9SRichard Henderson out->out_rr01r(s, type, new_args[0], new_args[1], new_args[4]);
5747d6cad9c9SRichard Henderson }
5748d6cad9c9SRichard Henderson break;
5749d6cad9c9SRichard Henderson
575007d5d502SRichard Henderson case INDEX_op_extract:
5751fa361eefSRichard Henderson case INDEX_op_sextract:
57525a4d034fSRichard Henderson {
57535a4d034fSRichard Henderson const TCGOutOpExtract *out =
57545a4d034fSRichard Henderson container_of(all_outop[op->opc], TCGOutOpExtract, base);
57555a4d034fSRichard Henderson
57565a4d034fSRichard Henderson tcg_debug_assert(!const_args[1]);
57575a4d034fSRichard Henderson out->out_rr(s, type, new_args[0], new_args[1],
57585a4d034fSRichard Henderson new_args[2], new_args[3]);
57595a4d034fSRichard Henderson }
57605a4d034fSRichard Henderson break;
57615a4d034fSRichard Henderson
576261d6a876SRichard Henderson case INDEX_op_extract2:
5763c8f9f700SRichard Henderson {
5764c8f9f700SRichard Henderson const TCGOutOpExtract2 *out = &outop_extract2;
5765c8f9f700SRichard Henderson
5766c8f9f700SRichard Henderson tcg_debug_assert(!const_args[1]);
5767c8f9f700SRichard Henderson tcg_debug_assert(!const_args[2]);
5768c8f9f700SRichard Henderson out->out_rrr(s, type, new_args[0], new_args[1],
5769c8f9f700SRichard Henderson new_args[2], new_args[3]);
5770c8f9f700SRichard Henderson }
5771c8f9f700SRichard Henderson break;
5772c8f9f700SRichard Henderson
5773e996804dSRichard Henderson case INDEX_op_ld8u:
5774e996804dSRichard Henderson case INDEX_op_ld8s:
5775e996804dSRichard Henderson case INDEX_op_ld16u:
5776e996804dSRichard Henderson case INDEX_op_ld16s:
5777e996804dSRichard Henderson case INDEX_op_ld32u:
5778e996804dSRichard Henderson case INDEX_op_ld32s:
5779e996804dSRichard Henderson case INDEX_op_ld:
57800de5c9d1SRichard Henderson {
57810de5c9d1SRichard Henderson const TCGOutOpLoad *out =
57820de5c9d1SRichard Henderson container_of(all_outop[op->opc], TCGOutOpLoad, base);
57830de5c9d1SRichard Henderson
57840de5c9d1SRichard Henderson tcg_debug_assert(!const_args[1]);
57850de5c9d1SRichard Henderson out->out(s, type, new_args[0], new_args[1], new_args[2]);
57860de5c9d1SRichard Henderson }
57870de5c9d1SRichard Henderson break;
57880de5c9d1SRichard Henderson
5789bfe96480SRichard Henderson case INDEX_op_muls2:
5790d776198cSRichard Henderson case INDEX_op_mulu2:
57915641afdfSRichard Henderson {
57925641afdfSRichard Henderson const TCGOutOpMul2 *out =
57935641afdfSRichard Henderson container_of(all_outop[op->opc], TCGOutOpMul2, base);
57945641afdfSRichard Henderson
57955641afdfSRichard Henderson tcg_debug_assert(!const_args[2]);
57965641afdfSRichard Henderson tcg_debug_assert(!const_args[3]);
57975641afdfSRichard Henderson out->out_rrrr(s, type, new_args[0], new_args[1],
57985641afdfSRichard Henderson new_args[2], new_args[3]);
57995641afdfSRichard Henderson }
58005641afdfSRichard Henderson break;
58015641afdfSRichard Henderson
5802a28f151dSRichard Henderson case INDEX_op_st32:
58034a686aa9SRichard Henderson /* Use tcg_op_st w/ I32. */
58044a686aa9SRichard Henderson type = TCG_TYPE_I32;
58054a686aa9SRichard Henderson /* fall through */
5806a28f151dSRichard Henderson case INDEX_op_st:
5807a28f151dSRichard Henderson case INDEX_op_st8:
5808a28f151dSRichard Henderson case INDEX_op_st16:
58094a686aa9SRichard Henderson {
58104a686aa9SRichard Henderson const TCGOutOpStore *out =
58114a686aa9SRichard Henderson container_of(all_outop[op->opc], TCGOutOpStore, base);
58124a686aa9SRichard Henderson
58134a686aa9SRichard Henderson if (const_args[0]) {
58144a686aa9SRichard Henderson out->out_i(s, type, new_args[0], new_args[1], new_args[2]);
58154a686aa9SRichard Henderson } else {
58164a686aa9SRichard Henderson out->out_r(s, type, new_args[0], new_args[1], new_args[2]);
58174a686aa9SRichard Henderson }
58184a686aa9SRichard Henderson }
58194a686aa9SRichard Henderson break;
58204a686aa9SRichard Henderson
58213bedb9d3SRichard Henderson case INDEX_op_qemu_ld:
582286fe5c25SRichard Henderson case INDEX_op_qemu_st:
58233bedb9d3SRichard Henderson {
582486fe5c25SRichard Henderson const TCGOutOpQemuLdSt *out =
582586fe5c25SRichard Henderson container_of(all_outop[op->opc], TCGOutOpQemuLdSt, base);
582686fe5c25SRichard Henderson
58273bedb9d3SRichard Henderson out->out(s, type, new_args[0], new_args[1], new_args[2]);
58283bedb9d3SRichard Henderson }
58293bedb9d3SRichard Henderson break;
58303bedb9d3SRichard Henderson
58313bedb9d3SRichard Henderson case INDEX_op_qemu_ld2:
583286fe5c25SRichard Henderson case INDEX_op_qemu_st2:
58333bedb9d3SRichard Henderson {
583486fe5c25SRichard Henderson const TCGOutOpQemuLdSt2 *out =
583586fe5c25SRichard Henderson container_of(all_outop[op->opc], TCGOutOpQemuLdSt2, base);
583686fe5c25SRichard Henderson
58373bedb9d3SRichard Henderson out->out(s, type, new_args[0], new_args[1],
58383bedb9d3SRichard Henderson new_args[2], new_args[3]);
58393bedb9d3SRichard Henderson }
58403bedb9d3SRichard Henderson break;
58413bedb9d3SRichard Henderson
5842b6d69fceSRichard Henderson case INDEX_op_brcond:
584399ac4706SRichard Henderson {
584499ac4706SRichard Henderson const TCGOutOpBrcond *out = &outop_brcond;
584599ac4706SRichard Henderson TCGCond cond = new_args[2];
584699ac4706SRichard Henderson TCGLabel *label = arg_label(new_args[3]);
584799ac4706SRichard Henderson
584899ac4706SRichard Henderson tcg_debug_assert(!const_args[0]);
584999ac4706SRichard Henderson if (const_args[1]) {
585099ac4706SRichard Henderson out->out_ri(s, type, cond, new_args[0], new_args[1], label);
585199ac4706SRichard Henderson } else {
585299ac4706SRichard Henderson out->out_rr(s, type, cond, new_args[0], new_args[1], label);
585399ac4706SRichard Henderson }
585499ac4706SRichard Henderson }
585599ac4706SRichard Henderson break;
585699ac4706SRichard Henderson
5857ea46c4bcSRichard Henderson case INDEX_op_movcond:
58581f406e46SRichard Henderson {
58591f406e46SRichard Henderson const TCGOutOpMovcond *out = &outop_movcond;
58601f406e46SRichard Henderson TCGCond cond = new_args[5];
58611f406e46SRichard Henderson
58621f406e46SRichard Henderson tcg_debug_assert(!const_args[1]);
58631f406e46SRichard Henderson out->out(s, type, cond, new_args[0],
58641f406e46SRichard Henderson new_args[1], new_args[2], const_args[2],
58651f406e46SRichard Henderson new_args[3], const_args[3],
58661f406e46SRichard Henderson new_args[4], const_args[4]);
58671f406e46SRichard Henderson }
58681f406e46SRichard Henderson break;
58691f406e46SRichard Henderson
5870a363e1e1SRichard Henderson case INDEX_op_setcond:
5871a363e1e1SRichard Henderson case INDEX_op_negsetcond:
58725a7b38c8SRichard Henderson {
58735a7b38c8SRichard Henderson const TCGOutOpSetcond *out =
58745a7b38c8SRichard Henderson container_of(all_outop[op->opc], TCGOutOpSetcond, base);
58755a7b38c8SRichard Henderson TCGCond cond = new_args[3];
58765a7b38c8SRichard Henderson
58775a7b38c8SRichard Henderson tcg_debug_assert(!const_args[1]);
58785a7b38c8SRichard Henderson if (const_args[2]) {
58795a7b38c8SRichard Henderson out->out_rri(s, type, cond,
58805a7b38c8SRichard Henderson new_args[0], new_args[1], new_args[2]);
58815a7b38c8SRichard Henderson } else {
58825a7b38c8SRichard Henderson out->out_rrr(s, type, cond,
58835a7b38c8SRichard Henderson new_args[0], new_args[1], new_args[2]);
58845a7b38c8SRichard Henderson }
58855a7b38c8SRichard Henderson }
58865a7b38c8SRichard Henderson break;
58875641afdfSRichard Henderson
5888f408df58SRichard Henderson #if TCG_TARGET_REG_BITS == 32
5889f408df58SRichard Henderson case INDEX_op_brcond2_i32:
5890f408df58SRichard Henderson {
5891f408df58SRichard Henderson const TCGOutOpBrcond2 *out = &outop_brcond2;
5892f408df58SRichard Henderson TCGCond cond = new_args[4];
5893f408df58SRichard Henderson TCGLabel *label = arg_label(new_args[5]);
5894f408df58SRichard Henderson
5895f408df58SRichard Henderson tcg_debug_assert(!const_args[0]);
5896f408df58SRichard Henderson tcg_debug_assert(!const_args[1]);
5897f408df58SRichard Henderson out->out(s, cond, new_args[0], new_args[1],
5898f408df58SRichard Henderson new_args[2], const_args[2],
5899f408df58SRichard Henderson new_args[3], const_args[3], label);
5900f408df58SRichard Henderson }
5901f408df58SRichard Henderson break;
5902e579c717SRichard Henderson case INDEX_op_setcond2_i32:
5903e579c717SRichard Henderson {
5904e579c717SRichard Henderson const TCGOutOpSetcond2 *out = &outop_setcond2;
5905e579c717SRichard Henderson TCGCond cond = new_args[5];
5906e579c717SRichard Henderson
5907e579c717SRichard Henderson tcg_debug_assert(!const_args[1]);
5908e579c717SRichard Henderson tcg_debug_assert(!const_args[2]);
5909e579c717SRichard Henderson out->out(s, cond, new_args[0], new_args[1], new_args[2],
5910e579c717SRichard Henderson new_args[3], const_args[3], new_args[4], const_args[4]);
5911e579c717SRichard Henderson }
5912e579c717SRichard Henderson break;
5913f408df58SRichard Henderson #else
5914f408df58SRichard Henderson case INDEX_op_brcond2_i32:
5915e579c717SRichard Henderson case INDEX_op_setcond2_i32:
5916f408df58SRichard Henderson g_assert_not_reached();
5917f408df58SRichard Henderson #endif
5918f408df58SRichard Henderson
5919fee03fddSRichard Henderson case INDEX_op_goto_ptr:
5920fee03fddSRichard Henderson tcg_debug_assert(!const_args[0]);
5921fee03fddSRichard Henderson tcg_out_goto_ptr(s, new_args[0]);
5922fee03fddSRichard Henderson break;
5923fee03fddSRichard Henderson
5924678155b2SRichard Henderson default:
5925eafecf08SRichard Henderson tcg_debug_assert(def->flags & TCG_OPF_VECTOR);
5926662cdbcfSRichard Henderson tcg_out_vec_op(s, op->opc, type - TCG_TYPE_V64,
59274d872218SRichard Henderson TCGOP_VECE(op), new_args, const_args);
5928678155b2SRichard Henderson break;
5929678155b2SRichard Henderson }
5930c896fe29Sbellard
593176f42780SRichard Henderson if (def->flags & TCG_OPF_CARRY_IN) {
593276f42780SRichard Henderson s->carry_live = false;
593376f42780SRichard Henderson }
593476f42780SRichard Henderson if (def->flags & TCG_OPF_CARRY_OUT) {
593576f42780SRichard Henderson s->carry_live = true;
593676f42780SRichard Henderson }
593776f42780SRichard Henderson
5938c896fe29Sbellard /* move the outputs in the correct register if needed */
5939c896fe29Sbellard for(i = 0; i < nb_oargs; i++) {
594043439139SRichard Henderson ts = arg_temp(op->args[i]);
5941d63e3b6eSRichard Henderson
5942d63e3b6eSRichard Henderson /* ENV should not be modified. */
5943e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ts));
5944d63e3b6eSRichard Henderson
5945ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) {
594698b4e186SRichard Henderson temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i));
594759d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) {
5948f8bf00f1SRichard Henderson temp_dead(s, ts);
5949ec7a869dSAurelien Jarno }
5950c896fe29Sbellard }
5951c896fe29Sbellard }
5952c896fe29Sbellard
tcg_reg_alloc_dup2(TCGContext * s,const TCGOp * op)5953efe86b21SRichard Henderson static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op)
5954efe86b21SRichard Henderson {
5955efe86b21SRichard Henderson const TCGLifeData arg_life = op->life;
5956efe86b21SRichard Henderson TCGTemp *ots, *itsl, *itsh;
59574d872218SRichard Henderson TCGType vtype = TCGOP_TYPE(op);
5958efe86b21SRichard Henderson
5959efe86b21SRichard Henderson /* This opcode is only valid for 32-bit hosts, for 64-bit elements. */
5960efe86b21SRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 32);
5961efe86b21SRichard Henderson tcg_debug_assert(TCGOP_VECE(op) == MO_64);
5962efe86b21SRichard Henderson
5963efe86b21SRichard Henderson ots = arg_temp(op->args[0]);
5964efe86b21SRichard Henderson itsl = arg_temp(op->args[1]);
5965efe86b21SRichard Henderson itsh = arg_temp(op->args[2]);
5966efe86b21SRichard Henderson
5967efe86b21SRichard Henderson /* ENV should not be modified. */
5968efe86b21SRichard Henderson tcg_debug_assert(!temp_readonly(ots));
5969efe86b21SRichard Henderson
5970efe86b21SRichard Henderson /* Allocate the output register now. */
5971efe86b21SRichard Henderson if (ots->val_type != TEMP_VAL_REG) {
5972efe86b21SRichard Henderson TCGRegSet allocated_regs = s->reserved_regs;
5973501fb3daSRichard Henderson TCGRegSet dup_out_regs = opcode_args_ct(op)[0].regs;
5974098859f1SRichard Henderson TCGReg oreg;
5975efe86b21SRichard Henderson
5976efe86b21SRichard Henderson /* Make sure to not spill the input registers. */
5977efe86b21SRichard Henderson if (!IS_DEAD_ARG(1) && itsl->val_type == TEMP_VAL_REG) {
5978efe86b21SRichard Henderson tcg_regset_set_reg(allocated_regs, itsl->reg);
5979efe86b21SRichard Henderson }
5980efe86b21SRichard Henderson if (!IS_DEAD_ARG(2) && itsh->val_type == TEMP_VAL_REG) {
5981efe86b21SRichard Henderson tcg_regset_set_reg(allocated_regs, itsh->reg);
5982efe86b21SRichard Henderson }
5983efe86b21SRichard Henderson
5984098859f1SRichard Henderson oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
598531fd884bSRichard Henderson output_pref(op, 0), ots->indirect_base);
5986098859f1SRichard Henderson set_temp_val_reg(s, ots, oreg);
5987efe86b21SRichard Henderson }
5988efe86b21SRichard Henderson
5989efe86b21SRichard Henderson /* Promote dup2 of immediates to dupi_vec. */
5990efe86b21SRichard Henderson if (itsl->val_type == TEMP_VAL_CONST && itsh->val_type == TEMP_VAL_CONST) {
5991efe86b21SRichard Henderson uint64_t val = deposit64(itsl->val, 32, 32, itsh->val);
5992efe86b21SRichard Henderson MemOp vece = MO_64;
5993efe86b21SRichard Henderson
5994efe86b21SRichard Henderson if (val == dup_const(MO_8, val)) {
5995efe86b21SRichard Henderson vece = MO_8;
5996efe86b21SRichard Henderson } else if (val == dup_const(MO_16, val)) {
5997efe86b21SRichard Henderson vece = MO_16;
5998efe86b21SRichard Henderson } else if (val == dup_const(MO_32, val)) {
5999efe86b21SRichard Henderson vece = MO_32;
6000efe86b21SRichard Henderson }
6001efe86b21SRichard Henderson
6002efe86b21SRichard Henderson tcg_out_dupi_vec(s, vtype, vece, ots->reg, val);
6003efe86b21SRichard Henderson goto done;
6004efe86b21SRichard Henderson }
6005efe86b21SRichard Henderson
6006efe86b21SRichard Henderson /* If the two inputs form one 64-bit value, try dupm_vec. */
6007aef85402SRichard Henderson if (itsl->temp_subindex == HOST_BIG_ENDIAN &&
6008aef85402SRichard Henderson itsh->temp_subindex == !HOST_BIG_ENDIAN &&
6009aef85402SRichard Henderson itsl == itsh + (HOST_BIG_ENDIAN ? 1 : -1)) {
6010aef85402SRichard Henderson TCGTemp *its = itsl - HOST_BIG_ENDIAN;
6011aef85402SRichard Henderson
6012aef85402SRichard Henderson temp_sync(s, its + 0, s->reserved_regs, 0, 0);
6013aef85402SRichard Henderson temp_sync(s, its + 1, s->reserved_regs, 0, 0);
6014aef85402SRichard Henderson
6015efe86b21SRichard Henderson if (tcg_out_dupm_vec(s, vtype, MO_64, ots->reg,
6016efe86b21SRichard Henderson its->mem_base->reg, its->mem_offset)) {
6017efe86b21SRichard Henderson goto done;
6018efe86b21SRichard Henderson }
6019efe86b21SRichard Henderson }
6020efe86b21SRichard Henderson
6021efe86b21SRichard Henderson /* Fall back to generic expansion. */
6022efe86b21SRichard Henderson return false;
6023efe86b21SRichard Henderson
6024efe86b21SRichard Henderson done:
602536f5539cSRichard Henderson ots->mem_coherent = 0;
6026efe86b21SRichard Henderson if (IS_DEAD_ARG(1)) {
6027efe86b21SRichard Henderson temp_dead(s, itsl);
6028efe86b21SRichard Henderson }
6029efe86b21SRichard Henderson if (IS_DEAD_ARG(2)) {
6030efe86b21SRichard Henderson temp_dead(s, itsh);
6031efe86b21SRichard Henderson }
6032efe86b21SRichard Henderson if (NEED_SYNC_ARG(0)) {
6033efe86b21SRichard Henderson temp_sync(s, ots, s->reserved_regs, 0, IS_DEAD_ARG(0));
6034efe86b21SRichard Henderson } else if (IS_DEAD_ARG(0)) {
6035efe86b21SRichard Henderson temp_dead(s, ots);
6036efe86b21SRichard Henderson }
6037efe86b21SRichard Henderson return true;
6038efe86b21SRichard Henderson }
6039efe86b21SRichard Henderson
load_arg_reg(TCGContext * s,TCGReg reg,TCGTemp * ts,TCGRegSet allocated_regs)604039004a71SRichard Henderson static void load_arg_reg(TCGContext *s, TCGReg reg, TCGTemp *ts,
604139004a71SRichard Henderson TCGRegSet allocated_regs)
6042c896fe29Sbellard {
6043c896fe29Sbellard if (ts->val_type == TEMP_VAL_REG) {
6044c896fe29Sbellard if (ts->reg != reg) {
60454250da10SRichard Henderson tcg_reg_free(s, reg, allocated_regs);
604678113e83SRichard Henderson if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
6047240c08d0SRichard Henderson /*
6048240c08d0SRichard Henderson * Cross register class move not supported. Sync the
6049240c08d0SRichard Henderson * temp back to its slot and load from there.
6050240c08d0SRichard Henderson */
6051240c08d0SRichard Henderson temp_sync(s, ts, allocated_regs, 0, 0);
6052240c08d0SRichard Henderson tcg_out_ld(s, ts->type, reg,
6053240c08d0SRichard Henderson ts->mem_base->reg, ts->mem_offset);
605478113e83SRichard Henderson }
6055c896fe29Sbellard }
6056c896fe29Sbellard } else {
6057ccb1bb66SRichard Henderson TCGRegSet arg_set = 0;
605840ae5c62SRichard Henderson
60594250da10SRichard Henderson tcg_reg_free(s, reg, allocated_regs);
606040ae5c62SRichard Henderson tcg_regset_set_reg(arg_set, reg);
6061b722452aSRichard Henderson temp_load(s, ts, arg_set, allocated_regs, 0);
6062c896fe29Sbellard }
606339004a71SRichard Henderson }
606440ae5c62SRichard Henderson
load_arg_stk(TCGContext * s,unsigned arg_slot,TCGTemp * ts,TCGRegSet allocated_regs)6065d78e4a4fSRichard Henderson static void load_arg_stk(TCGContext *s, unsigned arg_slot, TCGTemp *ts,
606639004a71SRichard Henderson TCGRegSet allocated_regs)
606739004a71SRichard Henderson {
606839004a71SRichard Henderson /*
606939004a71SRichard Henderson * When the destination is on the stack, load up the temp and store.
607039004a71SRichard Henderson * If there are many call-saved registers, the temp might live to
607139004a71SRichard Henderson * see another use; otherwise it'll be discarded.
607239004a71SRichard Henderson */
607339004a71SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], allocated_regs, 0);
607439004a71SRichard Henderson tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK,
6075d78e4a4fSRichard Henderson arg_slot_stk_ofs(arg_slot));
607639004a71SRichard Henderson }
607739004a71SRichard Henderson
load_arg_normal(TCGContext * s,const TCGCallArgumentLoc * l,TCGTemp * ts,TCGRegSet * allocated_regs)607839004a71SRichard Henderson static void load_arg_normal(TCGContext *s, const TCGCallArgumentLoc *l,
607939004a71SRichard Henderson TCGTemp *ts, TCGRegSet *allocated_regs)
608039004a71SRichard Henderson {
6081338b61e9SRichard Henderson if (arg_slot_reg_p(l->arg_slot)) {
608239004a71SRichard Henderson TCGReg reg = tcg_target_call_iarg_regs[l->arg_slot];
608339004a71SRichard Henderson load_arg_reg(s, reg, ts, *allocated_regs);
608439004a71SRichard Henderson tcg_regset_set_reg(*allocated_regs, reg);
608539004a71SRichard Henderson } else {
6086d78e4a4fSRichard Henderson load_arg_stk(s, l->arg_slot, ts, *allocated_regs);
6087c896fe29Sbellard }
608839cf05d3Sbellard }
6089c896fe29Sbellard
load_arg_ref(TCGContext * s,unsigned arg_slot,TCGReg ref_base,intptr_t ref_off,TCGRegSet * allocated_regs)6090d78e4a4fSRichard Henderson static void load_arg_ref(TCGContext *s, unsigned arg_slot, TCGReg ref_base,
6091313bdea8SRichard Henderson intptr_t ref_off, TCGRegSet *allocated_regs)
6092313bdea8SRichard Henderson {
6093313bdea8SRichard Henderson TCGReg reg;
6094313bdea8SRichard Henderson
6095d78e4a4fSRichard Henderson if (arg_slot_reg_p(arg_slot)) {
6096313bdea8SRichard Henderson reg = tcg_target_call_iarg_regs[arg_slot];
6097313bdea8SRichard Henderson tcg_reg_free(s, reg, *allocated_regs);
6098313bdea8SRichard Henderson tcg_out_addi_ptr(s, reg, ref_base, ref_off);
6099313bdea8SRichard Henderson tcg_regset_set_reg(*allocated_regs, reg);
6100313bdea8SRichard Henderson } else {
6101313bdea8SRichard Henderson reg = tcg_reg_alloc(s, tcg_target_available_regs[TCG_TYPE_PTR],
6102313bdea8SRichard Henderson *allocated_regs, 0, false);
6103313bdea8SRichard Henderson tcg_out_addi_ptr(s, reg, ref_base, ref_off);
6104313bdea8SRichard Henderson tcg_out_st(s, TCG_TYPE_PTR, reg, TCG_REG_CALL_STACK,
6105d78e4a4fSRichard Henderson arg_slot_stk_ofs(arg_slot));
6106313bdea8SRichard Henderson }
6107313bdea8SRichard Henderson }
6108313bdea8SRichard Henderson
tcg_reg_alloc_call(TCGContext * s,TCGOp * op)610939004a71SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op)
611039004a71SRichard Henderson {
611139004a71SRichard Henderson const int nb_oargs = TCGOP_CALLO(op);
611239004a71SRichard Henderson const int nb_iargs = TCGOP_CALLI(op);
611339004a71SRichard Henderson const TCGLifeData arg_life = op->life;
611439004a71SRichard Henderson const TCGHelperInfo *info = tcg_call_info(op);
611539004a71SRichard Henderson TCGRegSet allocated_regs = s->reserved_regs;
611639004a71SRichard Henderson int i;
611739004a71SRichard Henderson
611839004a71SRichard Henderson /*
611939004a71SRichard Henderson * Move inputs into place in reverse order,
612039004a71SRichard Henderson * so that we place stacked arguments first.
612139004a71SRichard Henderson */
612239004a71SRichard Henderson for (i = nb_iargs - 1; i >= 0; --i) {
612339004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i];
612439004a71SRichard Henderson TCGTemp *ts = arg_temp(op->args[nb_oargs + i]);
612539004a71SRichard Henderson
612639004a71SRichard Henderson switch (loc->kind) {
612739004a71SRichard Henderson case TCG_CALL_ARG_NORMAL:
612839004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U:
612939004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S:
613039004a71SRichard Henderson load_arg_normal(s, loc, ts, &allocated_regs);
613139004a71SRichard Henderson break;
6132313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF:
6133313bdea8SRichard Henderson load_arg_stk(s, loc->ref_slot, ts, allocated_regs);
6134313bdea8SRichard Henderson load_arg_ref(s, loc->arg_slot, TCG_REG_CALL_STACK,
6135d78e4a4fSRichard Henderson arg_slot_stk_ofs(loc->ref_slot),
6136313bdea8SRichard Henderson &allocated_regs);
6137313bdea8SRichard Henderson break;
6138313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF_N:
6139313bdea8SRichard Henderson load_arg_stk(s, loc->ref_slot, ts, allocated_regs);
6140313bdea8SRichard Henderson break;
614139004a71SRichard Henderson default:
614239004a71SRichard Henderson g_assert_not_reached();
614339004a71SRichard Henderson }
614439004a71SRichard Henderson }
614539004a71SRichard Henderson
614639004a71SRichard Henderson /* Mark dead temporaries and free the associated registers. */
6147866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
6148866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) {
614943439139SRichard Henderson temp_dead(s, arg_temp(op->args[i]));
6150c896fe29Sbellard }
6151c896fe29Sbellard }
6152c896fe29Sbellard
615339004a71SRichard Henderson /* Clobber call registers. */
6154c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
6155c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
6156b3915dbbSRichard Henderson tcg_reg_free(s, i, allocated_regs);
6157c896fe29Sbellard }
6158c896fe29Sbellard }
6159c896fe29Sbellard
616039004a71SRichard Henderson /*
616139004a71SRichard Henderson * Save globals if they might be written by the helper,
616239004a71SRichard Henderson * sync them if they might be read.
616339004a71SRichard Henderson */
616439004a71SRichard Henderson if (info->flags & TCG_CALL_NO_READ_GLOBALS) {
616578505279SAurelien Jarno /* Nothing to do */
616639004a71SRichard Henderson } else if (info->flags & TCG_CALL_NO_WRITE_GLOBALS) {
616778505279SAurelien Jarno sync_globals(s, allocated_regs);
616878505279SAurelien Jarno } else {
6169e8996ee0Sbellard save_globals(s, allocated_regs);
6170b9c18f56Saurel32 }
6171c896fe29Sbellard
6172313bdea8SRichard Henderson /*
6173313bdea8SRichard Henderson * If the ABI passes a pointer to the returned struct as the first
6174313bdea8SRichard Henderson * argument, load that now. Pass a pointer to the output home slot.
6175313bdea8SRichard Henderson */
6176313bdea8SRichard Henderson if (info->out_kind == TCG_CALL_RET_BY_REF) {
6177313bdea8SRichard Henderson TCGTemp *ts = arg_temp(op->args[0]);
6178313bdea8SRichard Henderson
6179313bdea8SRichard Henderson if (!ts->mem_allocated) {
6180313bdea8SRichard Henderson temp_allocate_frame(s, ts);
6181313bdea8SRichard Henderson }
6182313bdea8SRichard Henderson load_arg_ref(s, 0, ts->mem_base->reg, ts->mem_offset, &allocated_regs);
6183313bdea8SRichard Henderson }
6184313bdea8SRichard Henderson
6185cee44b03SRichard Henderson tcg_out_call(s, tcg_call_func(op), info);
6186c896fe29Sbellard
618739004a71SRichard Henderson /* Assign output registers and emit moves if needed. */
618839004a71SRichard Henderson switch (info->out_kind) {
618939004a71SRichard Henderson case TCG_CALL_RET_NORMAL:
6190c896fe29Sbellard for (i = 0; i < nb_oargs; i++) {
619139004a71SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]);
61925e3d0c19SRichard Henderson TCGReg reg = tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, i);
6193d63e3b6eSRichard Henderson
6194d63e3b6eSRichard Henderson /* ENV should not be modified. */
6195e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ts));
6196d63e3b6eSRichard Henderson
6197098859f1SRichard Henderson set_temp_val_reg(s, ts, reg);
6198c896fe29Sbellard ts->mem_coherent = 0;
619939004a71SRichard Henderson }
620039004a71SRichard Henderson break;
6201313bdea8SRichard Henderson
6202c6556aa0SRichard Henderson case TCG_CALL_RET_BY_VEC:
6203c6556aa0SRichard Henderson {
6204c6556aa0SRichard Henderson TCGTemp *ts = arg_temp(op->args[0]);
6205c6556aa0SRichard Henderson
6206c6556aa0SRichard Henderson tcg_debug_assert(ts->base_type == TCG_TYPE_I128);
6207c6556aa0SRichard Henderson tcg_debug_assert(ts->temp_subindex == 0);
6208c6556aa0SRichard Henderson if (!ts->mem_allocated) {
6209c6556aa0SRichard Henderson temp_allocate_frame(s, ts);
6210c6556aa0SRichard Henderson }
6211c6556aa0SRichard Henderson tcg_out_st(s, TCG_TYPE_V128,
6212c6556aa0SRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0),
6213c6556aa0SRichard Henderson ts->mem_base->reg, ts->mem_offset);
6214c6556aa0SRichard Henderson }
6215c6556aa0SRichard Henderson /* fall through to mark all parts in memory */
6216c6556aa0SRichard Henderson
6217313bdea8SRichard Henderson case TCG_CALL_RET_BY_REF:
6218313bdea8SRichard Henderson /* The callee has performed a write through the reference. */
6219313bdea8SRichard Henderson for (i = 0; i < nb_oargs; i++) {
6220313bdea8SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]);
6221313bdea8SRichard Henderson ts->val_type = TEMP_VAL_MEM;
6222313bdea8SRichard Henderson }
6223313bdea8SRichard Henderson break;
6224313bdea8SRichard Henderson
622539004a71SRichard Henderson default:
622639004a71SRichard Henderson g_assert_not_reached();
622739004a71SRichard Henderson }
622839004a71SRichard Henderson
622939004a71SRichard Henderson /* Flush or discard output registers as needed. */
623039004a71SRichard Henderson for (i = 0; i < nb_oargs; i++) {
623139004a71SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]);
6232ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) {
623339004a71SRichard Henderson temp_sync(s, ts, s->reserved_regs, 0, IS_DEAD_ARG(i));
623459d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) {
6235f8bf00f1SRichard Henderson temp_dead(s, ts);
6236c896fe29Sbellard }
6237c896fe29Sbellard }
62388c11ad25SAurelien Jarno }
6239c896fe29Sbellard
6240e63b8a29SRichard Henderson /**
6241e63b8a29SRichard Henderson * atom_and_align_for_opc:
6242e63b8a29SRichard Henderson * @s: tcg context
6243e63b8a29SRichard Henderson * @opc: memory operation code
6244e63b8a29SRichard Henderson * @host_atom: MO_ATOM_{IFALIGN,WITHIN16,SUBALIGN} for host operations
6245e63b8a29SRichard Henderson * @allow_two_ops: true if we are prepared to issue two operations
6246e63b8a29SRichard Henderson *
6247e63b8a29SRichard Henderson * Return the alignment and atomicity to use for the inline fast path
6248e63b8a29SRichard Henderson * for the given memory operation. The alignment may be larger than
6249e63b8a29SRichard Henderson * that specified in @opc, and the correct alignment will be diagnosed
6250e63b8a29SRichard Henderson * by the slow path helper.
6251e63b8a29SRichard Henderson *
6252e63b8a29SRichard Henderson * If @allow_two_ops, the host is prepared to test for 2x alignment,
6253e63b8a29SRichard Henderson * and issue two loads or stores for subalignment.
6254e63b8a29SRichard Henderson */
atom_and_align_for_opc(TCGContext * s,MemOp opc,MemOp host_atom,bool allow_two_ops)6255e63b8a29SRichard Henderson static TCGAtomAlign atom_and_align_for_opc(TCGContext *s, MemOp opc,
6256e63b8a29SRichard Henderson MemOp host_atom, bool allow_two_ops)
6257e63b8a29SRichard Henderson {
6258c5809eeeSRichard Henderson MemOp align = memop_alignment_bits(opc);
6259e63b8a29SRichard Henderson MemOp size = opc & MO_SIZE;
6260e63b8a29SRichard Henderson MemOp half = size ? size - 1 : 0;
6261cbb14556SRichard Henderson MemOp atom = opc & MO_ATOM_MASK;
6262e63b8a29SRichard Henderson MemOp atmax;
6263e63b8a29SRichard Henderson
6264e63b8a29SRichard Henderson switch (atom) {
6265e63b8a29SRichard Henderson case MO_ATOM_NONE:
6266e63b8a29SRichard Henderson /* The operation requires no specific atomicity. */
6267e63b8a29SRichard Henderson atmax = MO_8;
6268e63b8a29SRichard Henderson break;
6269e63b8a29SRichard Henderson
6270e63b8a29SRichard Henderson case MO_ATOM_IFALIGN:
6271e63b8a29SRichard Henderson atmax = size;
6272e63b8a29SRichard Henderson break;
6273e63b8a29SRichard Henderson
6274e63b8a29SRichard Henderson case MO_ATOM_IFALIGN_PAIR:
6275e63b8a29SRichard Henderson atmax = half;
6276e63b8a29SRichard Henderson break;
6277e63b8a29SRichard Henderson
6278e63b8a29SRichard Henderson case MO_ATOM_WITHIN16:
6279e63b8a29SRichard Henderson atmax = size;
6280e63b8a29SRichard Henderson if (size == MO_128) {
6281e63b8a29SRichard Henderson /* Misalignment implies !within16, and therefore no atomicity. */
6282e63b8a29SRichard Henderson } else if (host_atom != MO_ATOM_WITHIN16) {
6283e63b8a29SRichard Henderson /* The host does not implement within16, so require alignment. */
6284e63b8a29SRichard Henderson align = MAX(align, size);
6285e63b8a29SRichard Henderson }
6286e63b8a29SRichard Henderson break;
6287e63b8a29SRichard Henderson
6288e63b8a29SRichard Henderson case MO_ATOM_WITHIN16_PAIR:
6289e63b8a29SRichard Henderson atmax = size;
6290e63b8a29SRichard Henderson /*
6291e63b8a29SRichard Henderson * Misalignment implies !within16, and therefore half atomicity.
6292e63b8a29SRichard Henderson * Any host prepared for two operations can implement this with
6293e63b8a29SRichard Henderson * half alignment.
6294e63b8a29SRichard Henderson */
6295e63b8a29SRichard Henderson if (host_atom != MO_ATOM_WITHIN16 && allow_two_ops) {
6296e63b8a29SRichard Henderson align = MAX(align, half);
6297e63b8a29SRichard Henderson }
6298e63b8a29SRichard Henderson break;
6299e63b8a29SRichard Henderson
6300e63b8a29SRichard Henderson case MO_ATOM_SUBALIGN:
6301e63b8a29SRichard Henderson atmax = size;
6302e63b8a29SRichard Henderson if (host_atom != MO_ATOM_SUBALIGN) {
6303e63b8a29SRichard Henderson /* If unaligned but not odd, there are subobjects up to half. */
6304e63b8a29SRichard Henderson if (allow_two_ops) {
6305e63b8a29SRichard Henderson align = MAX(align, half);
6306e63b8a29SRichard Henderson } else {
6307e63b8a29SRichard Henderson align = MAX(align, size);
6308e63b8a29SRichard Henderson }
6309e63b8a29SRichard Henderson }
6310e63b8a29SRichard Henderson break;
6311e63b8a29SRichard Henderson
6312e63b8a29SRichard Henderson default:
6313e63b8a29SRichard Henderson g_assert_not_reached();
6314e63b8a29SRichard Henderson }
6315e63b8a29SRichard Henderson
6316e63b8a29SRichard Henderson return (TCGAtomAlign){ .atom = atmax, .align = align };
6317e63b8a29SRichard Henderson }
6318e63b8a29SRichard Henderson
63198429a1caSRichard Henderson /*
63208429a1caSRichard Henderson * Similarly for qemu_ld/st slow path helpers.
63218429a1caSRichard Henderson * We must re-implement tcg_gen_callN and tcg_reg_alloc_call simultaneously,
63228429a1caSRichard Henderson * using only the provided backend tcg_out_* functions.
63238429a1caSRichard Henderson */
63248429a1caSRichard Henderson
tcg_out_helper_stk_ofs(TCGType type,unsigned slot)63258429a1caSRichard Henderson static int tcg_out_helper_stk_ofs(TCGType type, unsigned slot)
63268429a1caSRichard Henderson {
63278429a1caSRichard Henderson int ofs = arg_slot_stk_ofs(slot);
63288429a1caSRichard Henderson
63298429a1caSRichard Henderson /*
63308429a1caSRichard Henderson * Each stack slot is TCG_TARGET_LONG_BITS. If the host does not
63318429a1caSRichard Henderson * require extension to uint64_t, adjust the address for uint32_t.
63328429a1caSRichard Henderson */
63338429a1caSRichard Henderson if (HOST_BIG_ENDIAN &&
63348429a1caSRichard Henderson TCG_TARGET_REG_BITS == 64 &&
63358429a1caSRichard Henderson type == TCG_TYPE_I32) {
63368429a1caSRichard Henderson ofs += 4;
63378429a1caSRichard Henderson }
63388429a1caSRichard Henderson return ofs;
63398429a1caSRichard Henderson }
63408429a1caSRichard Henderson
tcg_out_helper_load_slots(TCGContext * s,unsigned nmov,TCGMovExtend * mov,const TCGLdstHelperParam * parm)63418d314041SRichard Henderson static void tcg_out_helper_load_slots(TCGContext *s,
63428429a1caSRichard Henderson unsigned nmov, TCGMovExtend *mov,
63432462e30eSRichard Henderson const TCGLdstHelperParam *parm)
63448429a1caSRichard Henderson {
63458d314041SRichard Henderson unsigned i;
63462462e30eSRichard Henderson TCGReg dst3;
63472462e30eSRichard Henderson
63488d314041SRichard Henderson /*
63498d314041SRichard Henderson * Start from the end, storing to the stack first.
63508d314041SRichard Henderson * This frees those registers, so we need not consider overlap.
63518d314041SRichard Henderson */
63528d314041SRichard Henderson for (i = nmov; i-- > 0; ) {
63538d314041SRichard Henderson unsigned slot = mov[i].dst;
63548d314041SRichard Henderson
63558d314041SRichard Henderson if (arg_slot_reg_p(slot)) {
63568d314041SRichard Henderson goto found_reg;
63578d314041SRichard Henderson }
63588d314041SRichard Henderson
63598d314041SRichard Henderson TCGReg src = mov[i].src;
63608d314041SRichard Henderson TCGType dst_type = mov[i].dst_type;
63618d314041SRichard Henderson MemOp dst_mo = dst_type == TCG_TYPE_I32 ? MO_32 : MO_64;
63628d314041SRichard Henderson
63638d314041SRichard Henderson /* The argument is going onto the stack; extend into scratch. */
63648d314041SRichard Henderson if ((mov[i].src_ext & MO_SIZE) != dst_mo) {
63658d314041SRichard Henderson tcg_debug_assert(parm->ntmp != 0);
63668d314041SRichard Henderson mov[i].dst = src = parm->tmp[0];
63678d314041SRichard Henderson tcg_out_movext1(s, &mov[i]);
63688d314041SRichard Henderson }
63698d314041SRichard Henderson
63708d314041SRichard Henderson tcg_out_st(s, dst_type, src, TCG_REG_CALL_STACK,
63718d314041SRichard Henderson tcg_out_helper_stk_ofs(dst_type, slot));
63728d314041SRichard Henderson }
63738d314041SRichard Henderson return;
63748d314041SRichard Henderson
63758d314041SRichard Henderson found_reg:
63768d314041SRichard Henderson /*
63778d314041SRichard Henderson * The remaining arguments are in registers.
63788d314041SRichard Henderson * Convert slot numbers to argument registers.
63798d314041SRichard Henderson */
63808d314041SRichard Henderson nmov = i + 1;
63818d314041SRichard Henderson for (i = 0; i < nmov; ++i) {
63828d314041SRichard Henderson mov[i].dst = tcg_target_call_iarg_regs[mov[i].dst];
63838d314041SRichard Henderson }
63848d314041SRichard Henderson
63858429a1caSRichard Henderson switch (nmov) {
63862462e30eSRichard Henderson case 4:
63878429a1caSRichard Henderson /* The backend must have provided enough temps for the worst case. */
63882462e30eSRichard Henderson tcg_debug_assert(parm->ntmp >= 2);
63898429a1caSRichard Henderson
63902462e30eSRichard Henderson dst3 = mov[3].dst;
63912462e30eSRichard Henderson for (unsigned j = 0; j < 3; ++j) {
63922462e30eSRichard Henderson if (dst3 == mov[j].src) {
63938429a1caSRichard Henderson /*
63942462e30eSRichard Henderson * Conflict. Copy the source to a temporary, perform the
63952462e30eSRichard Henderson * remaining moves, then the extension from our scratch
63962462e30eSRichard Henderson * on the way out.
63978429a1caSRichard Henderson */
63982462e30eSRichard Henderson TCGReg scratch = parm->tmp[1];
63998429a1caSRichard Henderson
64002462e30eSRichard Henderson tcg_out_mov(s, mov[3].src_type, scratch, mov[3].src);
64012462e30eSRichard Henderson tcg_out_movext3(s, mov, mov + 1, mov + 2, parm->tmp[0]);
64022462e30eSRichard Henderson tcg_out_movext1_new_src(s, &mov[3], scratch);
64032462e30eSRichard Henderson break;
64048429a1caSRichard Henderson }
64058429a1caSRichard Henderson }
64068429a1caSRichard Henderson
64078429a1caSRichard Henderson /* No conflicts: perform this move and continue. */
64082462e30eSRichard Henderson tcg_out_movext1(s, &mov[3]);
64092462e30eSRichard Henderson /* fall through */
64108429a1caSRichard Henderson
64112462e30eSRichard Henderson case 3:
64122462e30eSRichard Henderson tcg_out_movext3(s, mov, mov + 1, mov + 2,
64132462e30eSRichard Henderson parm->ntmp ? parm->tmp[0] : -1);
64142462e30eSRichard Henderson break;
64158429a1caSRichard Henderson case 2:
64162462e30eSRichard Henderson tcg_out_movext2(s, mov, mov + 1,
64172462e30eSRichard Henderson parm->ntmp ? parm->tmp[0] : -1);
64182462e30eSRichard Henderson break;
64198429a1caSRichard Henderson case 1:
64208429a1caSRichard Henderson tcg_out_movext1(s, mov);
64212462e30eSRichard Henderson break;
64222462e30eSRichard Henderson default:
64238429a1caSRichard Henderson g_assert_not_reached();
64248429a1caSRichard Henderson }
64258429a1caSRichard Henderson }
64268429a1caSRichard Henderson
tcg_out_helper_load_imm(TCGContext * s,unsigned slot,TCGType type,tcg_target_long imm,const TCGLdstHelperParam * parm)64278429a1caSRichard Henderson static void tcg_out_helper_load_imm(TCGContext *s, unsigned slot,
64288429a1caSRichard Henderson TCGType type, tcg_target_long imm,
64298429a1caSRichard Henderson const TCGLdstHelperParam *parm)
64308429a1caSRichard Henderson {
64318429a1caSRichard Henderson if (arg_slot_reg_p(slot)) {
64328429a1caSRichard Henderson tcg_out_movi(s, type, tcg_target_call_iarg_regs[slot], imm);
64338429a1caSRichard Henderson } else {
64348429a1caSRichard Henderson int ofs = tcg_out_helper_stk_ofs(type, slot);
64358429a1caSRichard Henderson if (!tcg_out_sti(s, type, imm, TCG_REG_CALL_STACK, ofs)) {
64368429a1caSRichard Henderson tcg_debug_assert(parm->ntmp != 0);
64378429a1caSRichard Henderson tcg_out_movi(s, type, parm->tmp[0], imm);
64388429a1caSRichard Henderson tcg_out_st(s, type, parm->tmp[0], TCG_REG_CALL_STACK, ofs);
64398429a1caSRichard Henderson }
64408429a1caSRichard Henderson }
64418429a1caSRichard Henderson }
64428429a1caSRichard Henderson
tcg_out_helper_load_common_args(TCGContext * s,const TCGLabelQemuLdst * ldst,const TCGLdstHelperParam * parm,const TCGHelperInfo * info,unsigned next_arg)64438429a1caSRichard Henderson static void tcg_out_helper_load_common_args(TCGContext *s,
64448429a1caSRichard Henderson const TCGLabelQemuLdst *ldst,
64458429a1caSRichard Henderson const TCGLdstHelperParam *parm,
64468429a1caSRichard Henderson const TCGHelperInfo *info,
64478429a1caSRichard Henderson unsigned next_arg)
64488429a1caSRichard Henderson {
64498429a1caSRichard Henderson TCGMovExtend ptr_mov = {
64508429a1caSRichard Henderson .dst_type = TCG_TYPE_PTR,
64518429a1caSRichard Henderson .src_type = TCG_TYPE_PTR,
64528429a1caSRichard Henderson .src_ext = sizeof(void *) == 4 ? MO_32 : MO_64
64538429a1caSRichard Henderson };
64548429a1caSRichard Henderson const TCGCallArgumentLoc *loc = &info->in[0];
64558429a1caSRichard Henderson TCGType type;
64568429a1caSRichard Henderson unsigned slot;
64578429a1caSRichard Henderson tcg_target_ulong imm;
64588429a1caSRichard Henderson
64598429a1caSRichard Henderson /*
64608429a1caSRichard Henderson * Handle env, which is always first.
64618429a1caSRichard Henderson */
64628429a1caSRichard Henderson ptr_mov.dst = loc->arg_slot;
64638429a1caSRichard Henderson ptr_mov.src = TCG_AREG0;
64648429a1caSRichard Henderson tcg_out_helper_load_slots(s, 1, &ptr_mov, parm);
64658429a1caSRichard Henderson
64668429a1caSRichard Henderson /*
64678429a1caSRichard Henderson * Handle oi.
64688429a1caSRichard Henderson */
64698429a1caSRichard Henderson imm = ldst->oi;
64708429a1caSRichard Henderson loc = &info->in[next_arg];
64718429a1caSRichard Henderson type = TCG_TYPE_I32;
64728429a1caSRichard Henderson switch (loc->kind) {
64738429a1caSRichard Henderson case TCG_CALL_ARG_NORMAL:
64748429a1caSRichard Henderson break;
64758429a1caSRichard Henderson case TCG_CALL_ARG_EXTEND_U:
64768429a1caSRichard Henderson case TCG_CALL_ARG_EXTEND_S:
64778429a1caSRichard Henderson /* No extension required for MemOpIdx. */
64788429a1caSRichard Henderson tcg_debug_assert(imm <= INT32_MAX);
64798429a1caSRichard Henderson type = TCG_TYPE_REG;
64808429a1caSRichard Henderson break;
64818429a1caSRichard Henderson default:
64828429a1caSRichard Henderson g_assert_not_reached();
64838429a1caSRichard Henderson }
64848429a1caSRichard Henderson tcg_out_helper_load_imm(s, loc->arg_slot, type, imm, parm);
64858429a1caSRichard Henderson next_arg++;
64868429a1caSRichard Henderson
64878429a1caSRichard Henderson /*
64888429a1caSRichard Henderson * Handle ra.
64898429a1caSRichard Henderson */
64908429a1caSRichard Henderson loc = &info->in[next_arg];
64918429a1caSRichard Henderson slot = loc->arg_slot;
64928429a1caSRichard Henderson if (parm->ra_gen) {
64938429a1caSRichard Henderson int arg_reg = -1;
64948429a1caSRichard Henderson TCGReg ra_reg;
64958429a1caSRichard Henderson
64968429a1caSRichard Henderson if (arg_slot_reg_p(slot)) {
64978429a1caSRichard Henderson arg_reg = tcg_target_call_iarg_regs[slot];
64988429a1caSRichard Henderson }
64998429a1caSRichard Henderson ra_reg = parm->ra_gen(s, ldst, arg_reg);
65008429a1caSRichard Henderson
65018429a1caSRichard Henderson ptr_mov.dst = slot;
65028429a1caSRichard Henderson ptr_mov.src = ra_reg;
65038429a1caSRichard Henderson tcg_out_helper_load_slots(s, 1, &ptr_mov, parm);
65048429a1caSRichard Henderson } else {
65058429a1caSRichard Henderson imm = (uintptr_t)ldst->raddr;
65068429a1caSRichard Henderson tcg_out_helper_load_imm(s, slot, TCG_TYPE_PTR, imm, parm);
65078429a1caSRichard Henderson }
65088429a1caSRichard Henderson }
65098429a1caSRichard Henderson
tcg_out_helper_add_mov(TCGMovExtend * mov,const TCGCallArgumentLoc * loc,TCGType dst_type,TCGType src_type,TCGReg lo,TCGReg hi)65108429a1caSRichard Henderson static unsigned tcg_out_helper_add_mov(TCGMovExtend *mov,
65118429a1caSRichard Henderson const TCGCallArgumentLoc *loc,
65128429a1caSRichard Henderson TCGType dst_type, TCGType src_type,
65138429a1caSRichard Henderson TCGReg lo, TCGReg hi)
65148429a1caSRichard Henderson {
6515ebebea53SRichard Henderson MemOp reg_mo;
6516ebebea53SRichard Henderson
65178429a1caSRichard Henderson if (dst_type <= TCG_TYPE_REG) {
65188429a1caSRichard Henderson MemOp src_ext;
65198429a1caSRichard Henderson
65208429a1caSRichard Henderson switch (loc->kind) {
65218429a1caSRichard Henderson case TCG_CALL_ARG_NORMAL:
65228429a1caSRichard Henderson src_ext = src_type == TCG_TYPE_I32 ? MO_32 : MO_64;
65238429a1caSRichard Henderson break;
65248429a1caSRichard Henderson case TCG_CALL_ARG_EXTEND_U:
65258429a1caSRichard Henderson dst_type = TCG_TYPE_REG;
65268429a1caSRichard Henderson src_ext = MO_UL;
65278429a1caSRichard Henderson break;
65288429a1caSRichard Henderson case TCG_CALL_ARG_EXTEND_S:
65298429a1caSRichard Henderson dst_type = TCG_TYPE_REG;
65308429a1caSRichard Henderson src_ext = MO_SL;
65318429a1caSRichard Henderson break;
65328429a1caSRichard Henderson default:
65338429a1caSRichard Henderson g_assert_not_reached();
65348429a1caSRichard Henderson }
65358429a1caSRichard Henderson
65368429a1caSRichard Henderson mov[0].dst = loc->arg_slot;
65378429a1caSRichard Henderson mov[0].dst_type = dst_type;
65388429a1caSRichard Henderson mov[0].src = lo;
65398429a1caSRichard Henderson mov[0].src_type = src_type;
65408429a1caSRichard Henderson mov[0].src_ext = src_ext;
65418429a1caSRichard Henderson return 1;
65428429a1caSRichard Henderson }
65438429a1caSRichard Henderson
6544ebebea53SRichard Henderson if (TCG_TARGET_REG_BITS == 32) {
6545ebebea53SRichard Henderson assert(dst_type == TCG_TYPE_I64);
6546ebebea53SRichard Henderson reg_mo = MO_32;
6547ebebea53SRichard Henderson } else {
6548ebebea53SRichard Henderson assert(dst_type == TCG_TYPE_I128);
6549ebebea53SRichard Henderson reg_mo = MO_64;
6550ebebea53SRichard Henderson }
65518429a1caSRichard Henderson
65528429a1caSRichard Henderson mov[0].dst = loc[HOST_BIG_ENDIAN].arg_slot;
65538429a1caSRichard Henderson mov[0].src = lo;
6554ebebea53SRichard Henderson mov[0].dst_type = TCG_TYPE_REG;
6555ebebea53SRichard Henderson mov[0].src_type = TCG_TYPE_REG;
6556ebebea53SRichard Henderson mov[0].src_ext = reg_mo;
65578429a1caSRichard Henderson
65588429a1caSRichard Henderson mov[1].dst = loc[!HOST_BIG_ENDIAN].arg_slot;
65598429a1caSRichard Henderson mov[1].src = hi;
6560ebebea53SRichard Henderson mov[1].dst_type = TCG_TYPE_REG;
6561ebebea53SRichard Henderson mov[1].src_type = TCG_TYPE_REG;
6562ebebea53SRichard Henderson mov[1].src_ext = reg_mo;
65638429a1caSRichard Henderson
65648429a1caSRichard Henderson return 2;
65658429a1caSRichard Henderson }
65668429a1caSRichard Henderson
tcg_out_ld_helper_args(TCGContext * s,const TCGLabelQemuLdst * ldst,const TCGLdstHelperParam * parm)65678429a1caSRichard Henderson static void tcg_out_ld_helper_args(TCGContext *s, const TCGLabelQemuLdst *ldst,
65688429a1caSRichard Henderson const TCGLdstHelperParam *parm)
65698429a1caSRichard Henderson {
65708429a1caSRichard Henderson const TCGHelperInfo *info;
65718429a1caSRichard Henderson const TCGCallArgumentLoc *loc;
65728429a1caSRichard Henderson TCGMovExtend mov[2];
65738429a1caSRichard Henderson unsigned next_arg, nmov;
65748429a1caSRichard Henderson MemOp mop = get_memop(ldst->oi);
65758429a1caSRichard Henderson
65768429a1caSRichard Henderson switch (mop & MO_SIZE) {
65778429a1caSRichard Henderson case MO_8:
65788429a1caSRichard Henderson case MO_16:
65798429a1caSRichard Henderson case MO_32:
65808429a1caSRichard Henderson info = &info_helper_ld32_mmu;
65818429a1caSRichard Henderson break;
65828429a1caSRichard Henderson case MO_64:
65838429a1caSRichard Henderson info = &info_helper_ld64_mmu;
65848429a1caSRichard Henderson break;
6585ebebea53SRichard Henderson case MO_128:
6586ebebea53SRichard Henderson info = &info_helper_ld128_mmu;
6587ebebea53SRichard Henderson break;
65888429a1caSRichard Henderson default:
65898429a1caSRichard Henderson g_assert_not_reached();
65908429a1caSRichard Henderson }
65918429a1caSRichard Henderson
65928429a1caSRichard Henderson /* Defer env argument. */
65938429a1caSRichard Henderson next_arg = 1;
65948429a1caSRichard Henderson
65958429a1caSRichard Henderson loc = &info->in[next_arg];
6596c31e5fa4SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && s->addr_type == TCG_TYPE_I32) {
659724e46e6cSRichard Henderson /*
659824e46e6cSRichard Henderson * 32-bit host with 32-bit guest: zero-extend the guest address
659924e46e6cSRichard Henderson * to 64-bits for the helper by storing the low part, then
660024e46e6cSRichard Henderson * load a zero for the high part.
660124e46e6cSRichard Henderson */
660224e46e6cSRichard Henderson tcg_out_helper_add_mov(mov, loc + HOST_BIG_ENDIAN,
660324e46e6cSRichard Henderson TCG_TYPE_I32, TCG_TYPE_I32,
66040cd38379SRichard Henderson ldst->addr_reg, -1);
660524e46e6cSRichard Henderson tcg_out_helper_load_slots(s, 1, mov, parm);
660624e46e6cSRichard Henderson
660724e46e6cSRichard Henderson tcg_out_helper_load_imm(s, loc[!HOST_BIG_ENDIAN].arg_slot,
660824e46e6cSRichard Henderson TCG_TYPE_I32, 0, parm);
660924e46e6cSRichard Henderson next_arg += 2;
6610c31e5fa4SRichard Henderson } else {
6611c31e5fa4SRichard Henderson nmov = tcg_out_helper_add_mov(mov, loc, TCG_TYPE_I64, s->addr_type,
66120cd38379SRichard Henderson ldst->addr_reg, -1);
6613c31e5fa4SRichard Henderson tcg_out_helper_load_slots(s, nmov, mov, parm);
6614c31e5fa4SRichard Henderson next_arg += nmov;
661524e46e6cSRichard Henderson }
66168429a1caSRichard Henderson
6617ebebea53SRichard Henderson switch (info->out_kind) {
6618ebebea53SRichard Henderson case TCG_CALL_RET_NORMAL:
6619ebebea53SRichard Henderson case TCG_CALL_RET_BY_VEC:
6620ebebea53SRichard Henderson break;
6621ebebea53SRichard Henderson case TCG_CALL_RET_BY_REF:
6622ebebea53SRichard Henderson /*
6623ebebea53SRichard Henderson * The return reference is in the first argument slot.
6624ebebea53SRichard Henderson * We need memory in which to return: re-use the top of stack.
6625ebebea53SRichard Henderson */
6626ebebea53SRichard Henderson {
6627ebebea53SRichard Henderson int ofs_slot0 = TCG_TARGET_CALL_STACK_OFFSET;
6628ebebea53SRichard Henderson
6629ebebea53SRichard Henderson if (arg_slot_reg_p(0)) {
6630ebebea53SRichard Henderson tcg_out_addi_ptr(s, tcg_target_call_iarg_regs[0],
6631ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0);
6632ebebea53SRichard Henderson } else {
6633ebebea53SRichard Henderson tcg_debug_assert(parm->ntmp != 0);
6634ebebea53SRichard Henderson tcg_out_addi_ptr(s, parm->tmp[0],
6635ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0);
6636ebebea53SRichard Henderson tcg_out_st(s, TCG_TYPE_PTR, parm->tmp[0],
6637ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0);
6638ebebea53SRichard Henderson }
6639ebebea53SRichard Henderson }
6640ebebea53SRichard Henderson break;
6641ebebea53SRichard Henderson default:
6642ebebea53SRichard Henderson g_assert_not_reached();
6643ebebea53SRichard Henderson }
66448429a1caSRichard Henderson
66458429a1caSRichard Henderson tcg_out_helper_load_common_args(s, ldst, parm, info, next_arg);
66468429a1caSRichard Henderson }
66478429a1caSRichard Henderson
tcg_out_ld_helper_ret(TCGContext * s,const TCGLabelQemuLdst * ldst,bool load_sign,const TCGLdstHelperParam * parm)66488429a1caSRichard Henderson static void tcg_out_ld_helper_ret(TCGContext *s, const TCGLabelQemuLdst *ldst,
66498429a1caSRichard Henderson bool load_sign,
66508429a1caSRichard Henderson const TCGLdstHelperParam *parm)
66518429a1caSRichard Henderson {
66528429a1caSRichard Henderson MemOp mop = get_memop(ldst->oi);
6653ebebea53SRichard Henderson TCGMovExtend mov[2];
6654ebebea53SRichard Henderson int ofs_slot0;
66558429a1caSRichard Henderson
6656ebebea53SRichard Henderson switch (ldst->type) {
6657ebebea53SRichard Henderson case TCG_TYPE_I64:
6658ebebea53SRichard Henderson if (TCG_TARGET_REG_BITS == 32) {
6659ebebea53SRichard Henderson break;
6660ebebea53SRichard Henderson }
6661ebebea53SRichard Henderson /* fall through */
6662ebebea53SRichard Henderson
6663ebebea53SRichard Henderson case TCG_TYPE_I32:
66648429a1caSRichard Henderson mov[0].dst = ldst->datalo_reg;
66658429a1caSRichard Henderson mov[0].src = tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, 0);
66668429a1caSRichard Henderson mov[0].dst_type = ldst->type;
66678429a1caSRichard Henderson mov[0].src_type = TCG_TYPE_REG;
66688429a1caSRichard Henderson
66698429a1caSRichard Henderson /*
66708429a1caSRichard Henderson * If load_sign, then we allowed the helper to perform the
66718429a1caSRichard Henderson * appropriate sign extension to tcg_target_ulong, and all
66728429a1caSRichard Henderson * we need now is a plain move.
66738429a1caSRichard Henderson *
66748429a1caSRichard Henderson * If they do not, then we expect the relevant extension
66758429a1caSRichard Henderson * instruction to be no more expensive than a move, and
66768429a1caSRichard Henderson * we thus save the icache etc by only using one of two
66778429a1caSRichard Henderson * helper functions.
66788429a1caSRichard Henderson */
66798429a1caSRichard Henderson if (load_sign || !(mop & MO_SIGN)) {
66808429a1caSRichard Henderson if (TCG_TARGET_REG_BITS == 32 || ldst->type == TCG_TYPE_I32) {
66818429a1caSRichard Henderson mov[0].src_ext = MO_32;
66828429a1caSRichard Henderson } else {
66838429a1caSRichard Henderson mov[0].src_ext = MO_64;
66848429a1caSRichard Henderson }
66858429a1caSRichard Henderson } else {
66868429a1caSRichard Henderson mov[0].src_ext = mop & MO_SSIZE;
66878429a1caSRichard Henderson }
66888429a1caSRichard Henderson tcg_out_movext1(s, mov);
6689ebebea53SRichard Henderson return;
6690ebebea53SRichard Henderson
6691ebebea53SRichard Henderson case TCG_TYPE_I128:
6692ebebea53SRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 64);
6693ebebea53SRichard Henderson ofs_slot0 = TCG_TARGET_CALL_STACK_OFFSET;
6694ebebea53SRichard Henderson switch (TCG_TARGET_CALL_RET_I128) {
6695ebebea53SRichard Henderson case TCG_CALL_RET_NORMAL:
6696ebebea53SRichard Henderson break;
6697ebebea53SRichard Henderson case TCG_CALL_RET_BY_VEC:
6698ebebea53SRichard Henderson tcg_out_st(s, TCG_TYPE_V128,
6699ebebea53SRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0),
6700ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0);
6701ebebea53SRichard Henderson /* fall through */
6702ebebea53SRichard Henderson case TCG_CALL_RET_BY_REF:
6703ebebea53SRichard Henderson tcg_out_ld(s, TCG_TYPE_I64, ldst->datalo_reg,
6704ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0 + 8 * HOST_BIG_ENDIAN);
6705ebebea53SRichard Henderson tcg_out_ld(s, TCG_TYPE_I64, ldst->datahi_reg,
6706ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0 + 8 * !HOST_BIG_ENDIAN);
6707ebebea53SRichard Henderson return;
6708ebebea53SRichard Henderson default:
6709ebebea53SRichard Henderson g_assert_not_reached();
6710ebebea53SRichard Henderson }
6711ebebea53SRichard Henderson break;
6712ebebea53SRichard Henderson
6713ebebea53SRichard Henderson default:
6714ebebea53SRichard Henderson g_assert_not_reached();
6715ebebea53SRichard Henderson }
67168429a1caSRichard Henderson
67178429a1caSRichard Henderson mov[0].dst = ldst->datalo_reg;
67188429a1caSRichard Henderson mov[0].src =
67198429a1caSRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, HOST_BIG_ENDIAN);
6720723d3a27SRichard Henderson mov[0].dst_type = TCG_TYPE_REG;
6721723d3a27SRichard Henderson mov[0].src_type = TCG_TYPE_REG;
6722ebebea53SRichard Henderson mov[0].src_ext = TCG_TARGET_REG_BITS == 32 ? MO_32 : MO_64;
67238429a1caSRichard Henderson
67248429a1caSRichard Henderson mov[1].dst = ldst->datahi_reg;
67258429a1caSRichard Henderson mov[1].src =
67268429a1caSRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, !HOST_BIG_ENDIAN);
67278429a1caSRichard Henderson mov[1].dst_type = TCG_TYPE_REG;
67288429a1caSRichard Henderson mov[1].src_type = TCG_TYPE_REG;
6729ebebea53SRichard Henderson mov[1].src_ext = TCG_TARGET_REG_BITS == 32 ? MO_32 : MO_64;
67308429a1caSRichard Henderson
67318429a1caSRichard Henderson tcg_out_movext2(s, mov, mov + 1, parm->ntmp ? parm->tmp[0] : -1);
67328429a1caSRichard Henderson }
67338429a1caSRichard Henderson
tcg_out_st_helper_args(TCGContext * s,const TCGLabelQemuLdst * ldst,const TCGLdstHelperParam * parm)67348429a1caSRichard Henderson static void tcg_out_st_helper_args(TCGContext *s, const TCGLabelQemuLdst *ldst,
67358429a1caSRichard Henderson const TCGLdstHelperParam *parm)
67368429a1caSRichard Henderson {
67378429a1caSRichard Henderson const TCGHelperInfo *info;
67388429a1caSRichard Henderson const TCGCallArgumentLoc *loc;
67398429a1caSRichard Henderson TCGMovExtend mov[4];
67408429a1caSRichard Henderson TCGType data_type;
67418429a1caSRichard Henderson unsigned next_arg, nmov, n;
67428429a1caSRichard Henderson MemOp mop = get_memop(ldst->oi);
67438429a1caSRichard Henderson
67448429a1caSRichard Henderson switch (mop & MO_SIZE) {
67458429a1caSRichard Henderson case MO_8:
67468429a1caSRichard Henderson case MO_16:
67478429a1caSRichard Henderson case MO_32:
67488429a1caSRichard Henderson info = &info_helper_st32_mmu;
67498429a1caSRichard Henderson data_type = TCG_TYPE_I32;
67508429a1caSRichard Henderson break;
67518429a1caSRichard Henderson case MO_64:
67528429a1caSRichard Henderson info = &info_helper_st64_mmu;
67538429a1caSRichard Henderson data_type = TCG_TYPE_I64;
67548429a1caSRichard Henderson break;
6755ebebea53SRichard Henderson case MO_128:
6756ebebea53SRichard Henderson info = &info_helper_st128_mmu;
6757ebebea53SRichard Henderson data_type = TCG_TYPE_I128;
6758ebebea53SRichard Henderson break;
67598429a1caSRichard Henderson default:
67608429a1caSRichard Henderson g_assert_not_reached();
67618429a1caSRichard Henderson }
67628429a1caSRichard Henderson
67638429a1caSRichard Henderson /* Defer env argument. */
67648429a1caSRichard Henderson next_arg = 1;
67658429a1caSRichard Henderson nmov = 0;
67668429a1caSRichard Henderson
67678429a1caSRichard Henderson /* Handle addr argument. */
67688429a1caSRichard Henderson loc = &info->in[next_arg];
67690cd38379SRichard Henderson tcg_debug_assert(s->addr_type <= TCG_TYPE_REG);
67700cd38379SRichard Henderson if (TCG_TARGET_REG_BITS == 32) {
677124e46e6cSRichard Henderson /*
67720cd38379SRichard Henderson * 32-bit host (and thus 32-bit guest): zero-extend the guest address
677324e46e6cSRichard Henderson * to 64-bits for the helper by storing the low part. Later,
677424e46e6cSRichard Henderson * after we have processed the register inputs, we will load a
677524e46e6cSRichard Henderson * zero for the high part.
677624e46e6cSRichard Henderson */
677724e46e6cSRichard Henderson tcg_out_helper_add_mov(mov, loc + HOST_BIG_ENDIAN,
677824e46e6cSRichard Henderson TCG_TYPE_I32, TCG_TYPE_I32,
67790cd38379SRichard Henderson ldst->addr_reg, -1);
678024e46e6cSRichard Henderson next_arg += 2;
678124e46e6cSRichard Henderson nmov += 1;
6782c31e5fa4SRichard Henderson } else {
6783c31e5fa4SRichard Henderson n = tcg_out_helper_add_mov(mov, loc, TCG_TYPE_I64, s->addr_type,
67840cd38379SRichard Henderson ldst->addr_reg, -1);
6785c31e5fa4SRichard Henderson next_arg += n;
6786c31e5fa4SRichard Henderson nmov += n;
678724e46e6cSRichard Henderson }
67888429a1caSRichard Henderson
67898429a1caSRichard Henderson /* Handle data argument. */
67908429a1caSRichard Henderson loc = &info->in[next_arg];
6791ebebea53SRichard Henderson switch (loc->kind) {
6792ebebea53SRichard Henderson case TCG_CALL_ARG_NORMAL:
6793ebebea53SRichard Henderson case TCG_CALL_ARG_EXTEND_U:
6794ebebea53SRichard Henderson case TCG_CALL_ARG_EXTEND_S:
67958429a1caSRichard Henderson n = tcg_out_helper_add_mov(mov + nmov, loc, data_type, ldst->type,
67968429a1caSRichard Henderson ldst->datalo_reg, ldst->datahi_reg);
67978429a1caSRichard Henderson next_arg += n;
67988429a1caSRichard Henderson nmov += n;
6799ebebea53SRichard Henderson tcg_out_helper_load_slots(s, nmov, mov, parm);
6800ebebea53SRichard Henderson break;
6801ebebea53SRichard Henderson
6802ebebea53SRichard Henderson case TCG_CALL_ARG_BY_REF:
6803ebebea53SRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 64);
6804ebebea53SRichard Henderson tcg_debug_assert(data_type == TCG_TYPE_I128);
6805ebebea53SRichard Henderson tcg_out_st(s, TCG_TYPE_I64,
6806ebebea53SRichard Henderson HOST_BIG_ENDIAN ? ldst->datahi_reg : ldst->datalo_reg,
6807ebebea53SRichard Henderson TCG_REG_CALL_STACK, arg_slot_stk_ofs(loc[0].ref_slot));
6808ebebea53SRichard Henderson tcg_out_st(s, TCG_TYPE_I64,
6809ebebea53SRichard Henderson HOST_BIG_ENDIAN ? ldst->datalo_reg : ldst->datahi_reg,
6810ebebea53SRichard Henderson TCG_REG_CALL_STACK, arg_slot_stk_ofs(loc[1].ref_slot));
68118429a1caSRichard Henderson
68128429a1caSRichard Henderson tcg_out_helper_load_slots(s, nmov, mov, parm);
6813ebebea53SRichard Henderson
6814ebebea53SRichard Henderson if (arg_slot_reg_p(loc->arg_slot)) {
6815ebebea53SRichard Henderson tcg_out_addi_ptr(s, tcg_target_call_iarg_regs[loc->arg_slot],
6816ebebea53SRichard Henderson TCG_REG_CALL_STACK,
6817ebebea53SRichard Henderson arg_slot_stk_ofs(loc->ref_slot));
6818ebebea53SRichard Henderson } else {
6819ebebea53SRichard Henderson tcg_debug_assert(parm->ntmp != 0);
6820ebebea53SRichard Henderson tcg_out_addi_ptr(s, parm->tmp[0], TCG_REG_CALL_STACK,
6821ebebea53SRichard Henderson arg_slot_stk_ofs(loc->ref_slot));
6822ebebea53SRichard Henderson tcg_out_st(s, TCG_TYPE_PTR, parm->tmp[0],
6823ebebea53SRichard Henderson TCG_REG_CALL_STACK, arg_slot_stk_ofs(loc->arg_slot));
6824ebebea53SRichard Henderson }
6825ebebea53SRichard Henderson next_arg += 2;
6826ebebea53SRichard Henderson break;
6827ebebea53SRichard Henderson
6828ebebea53SRichard Henderson default:
6829ebebea53SRichard Henderson g_assert_not_reached();
6830ebebea53SRichard Henderson }
6831ebebea53SRichard Henderson
68320cd38379SRichard Henderson if (TCG_TARGET_REG_BITS == 32) {
6833c31e5fa4SRichard Henderson /* Zero extend the address by loading a zero for the high part. */
683424e46e6cSRichard Henderson loc = &info->in[1 + !HOST_BIG_ENDIAN];
683524e46e6cSRichard Henderson tcg_out_helper_load_imm(s, loc->arg_slot, TCG_TYPE_I32, 0, parm);
683624e46e6cSRichard Henderson }
683724e46e6cSRichard Henderson
68388429a1caSRichard Henderson tcg_out_helper_load_common_args(s, ldst, parm, info, next_arg);
68398429a1caSRichard Henderson }
68408429a1caSRichard Henderson
tcg_gen_code(TCGContext * s,TranslationBlock * tb,uint64_t pc_start)684176cef4b2SRichard Henderson int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start)
6842c896fe29Sbellard {
6843e1d8fabcSRichard Henderson int i, num_insns;
684415fa08f8SRichard Henderson TCGOp *op;
6845c896fe29Sbellard
6846d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)
6847fbf59aadSRichard Henderson && qemu_log_in_addr_range(pc_start))) {
6848c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock();
684978b54858SRichard Henderson if (logfile) {
685078b54858SRichard Henderson fprintf(logfile, "OP:\n");
6851b7a83ff8SRichard Henderson tcg_dump_ops(s, logfile, false);
685278b54858SRichard Henderson fprintf(logfile, "\n");
6853fc59d2d8SRobert Foley qemu_log_unlock(logfile);
6854c896fe29Sbellard }
685578b54858SRichard Henderson }
6856c896fe29Sbellard
6857bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG
6858bef16ab4SRichard Henderson /* Ensure all labels referenced have been emitted. */
6859bef16ab4SRichard Henderson {
6860bef16ab4SRichard Henderson TCGLabel *l;
6861bef16ab4SRichard Henderson bool error = false;
6862bef16ab4SRichard Henderson
6863bef16ab4SRichard Henderson QSIMPLEQ_FOREACH(l, &s->labels, next) {
6864f85b1fc4SRichard Henderson if (unlikely(!l->present) && !QSIMPLEQ_EMPTY(&l->branches)) {
6865bef16ab4SRichard Henderson qemu_log_mask(CPU_LOG_TB_OP,
6866bef16ab4SRichard Henderson "$L%d referenced but not present.\n", l->id);
6867bef16ab4SRichard Henderson error = true;
6868bef16ab4SRichard Henderson }
6869bef16ab4SRichard Henderson }
6870bef16ab4SRichard Henderson assert(!error);
6871bef16ab4SRichard Henderson }
6872bef16ab4SRichard Henderson #endif
6873bef16ab4SRichard Henderson
687404e006abSRichard Henderson /* Do not reuse any EBB that may be allocated within the TB. */
687504e006abSRichard Henderson tcg_temp_ebb_reset_freed(s);
687604e006abSRichard Henderson
6877c45cb8bbSRichard Henderson tcg_optimize(s);
68788f2e8c07SKirill Batuzov
6879b4fc67c7SRichard Henderson reachable_code_pass(s);
6880874b8574SRichard Henderson liveness_pass_0(s);
6881b83eabeaSRichard Henderson liveness_pass_1(s);
68825a18407fSRichard Henderson
68835a18407fSRichard Henderson if (s->nb_indirects > 0) {
68845a18407fSRichard Henderson if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND)
6885fbf59aadSRichard Henderson && qemu_log_in_addr_range(pc_start))) {
6886c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock();
688778b54858SRichard Henderson if (logfile) {
688878b54858SRichard Henderson fprintf(logfile, "OP before indirect lowering:\n");
6889b7a83ff8SRichard Henderson tcg_dump_ops(s, logfile, false);
689078b54858SRichard Henderson fprintf(logfile, "\n");
6891fc59d2d8SRobert Foley qemu_log_unlock(logfile);
68925a18407fSRichard Henderson }
689378b54858SRichard Henderson }
6894645e3a81SRichard Henderson
68955a18407fSRichard Henderson /* Replace indirect temps with direct temps. */
6896b83eabeaSRichard Henderson if (liveness_pass_2(s)) {
68975a18407fSRichard Henderson /* If changes were made, re-run liveness. */
6898b83eabeaSRichard Henderson liveness_pass_1(s);
68995a18407fSRichard Henderson }
69005a18407fSRichard Henderson }
6901c5cc28ffSAurelien Jarno
6902d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT)
6903fbf59aadSRichard Henderson && qemu_log_in_addr_range(pc_start))) {
6904c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock();
690578b54858SRichard Henderson if (logfile) {
690678b54858SRichard Henderson fprintf(logfile, "OP after optimization and liveness analysis:\n");
6907b7a83ff8SRichard Henderson tcg_dump_ops(s, logfile, true);
690878b54858SRichard Henderson fprintf(logfile, "\n");
6909fc59d2d8SRobert Foley qemu_log_unlock(logfile);
6910c896fe29Sbellard }
691178b54858SRichard Henderson }
6912c896fe29Sbellard
691335abb009SRichard Henderson /* Initialize goto_tb jump offsets. */
69143a50f424SRichard Henderson tb->jmp_reset_offset[0] = TB_JMP_OFFSET_INVALID;
69153a50f424SRichard Henderson tb->jmp_reset_offset[1] = TB_JMP_OFFSET_INVALID;
69169da6079bSRichard Henderson tb->jmp_insn_offset[0] = TB_JMP_OFFSET_INVALID;
69179da6079bSRichard Henderson tb->jmp_insn_offset[1] = TB_JMP_OFFSET_INVALID;
691835abb009SRichard Henderson
6919c896fe29Sbellard tcg_reg_alloc_start(s);
6920c896fe29Sbellard
6921db0c51a3SRichard Henderson /*
6922db0c51a3SRichard Henderson * Reset the buffer pointers when restarting after overflow.
6923db0c51a3SRichard Henderson * TODO: Move this into translate-all.c with the rest of the
6924db0c51a3SRichard Henderson * buffer management. Having only this done here is confusing.
6925db0c51a3SRichard Henderson */
6926db0c51a3SRichard Henderson s->code_buf = tcg_splitwx_to_rw(tb->tc.ptr);
6927db0c51a3SRichard Henderson s->code_ptr = s->code_buf;
6928a7cfd751SRichard Henderson s->data_gen_ptr = NULL;
6929c896fe29Sbellard
69306001f772SLaurent Vivier QSIMPLEQ_INIT(&s->ldst_labels);
693157a26946SRichard Henderson s->pool_labels = NULL;
69329ecefc84SRichard Henderson
6933747bd69dSRichard Henderson s->gen_insn_data =
6934e1d8fabcSRichard Henderson tcg_malloc(sizeof(uint64_t) * s->gen_tb->icount * INSN_START_WORDS);
6935747bd69dSRichard Henderson
69369358fbbfSRichard Henderson tcg_out_tb_start(s);
69379358fbbfSRichard Henderson
6938fca8a500SRichard Henderson num_insns = -1;
693976f42780SRichard Henderson s->carry_live = false;
694015fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) {
6941c45cb8bbSRichard Henderson TCGOpcode opc = op->opc;
6942b3db8758Sblueswir1
6943c896fe29Sbellard switch (opc) {
69441e6fec9dSRichard Henderson case INDEX_op_extrl_i64_i32:
69451e6fec9dSRichard Henderson assert(TCG_TARGET_REG_BITS == 64);
69461e6fec9dSRichard Henderson /*
69471e6fec9dSRichard Henderson * If TCG_TYPE_I32 is represented in some canonical form,
69481e6fec9dSRichard Henderson * e.g. zero or sign-extended, then emit as a unary op.
69491e6fec9dSRichard Henderson * Otherwise we can treat this as a plain move.
69501e6fec9dSRichard Henderson * If the output dies, treat this as a plain move, because
69511e6fec9dSRichard Henderson * this will be implemented with a store.
69521e6fec9dSRichard Henderson */
69531e6fec9dSRichard Henderson if (TCG_TARGET_HAS_extr_i64_i32) {
69541e6fec9dSRichard Henderson TCGLifeData arg_life = op->life;
69551e6fec9dSRichard Henderson if (!IS_DEAD_ARG(0)) {
69561e6fec9dSRichard Henderson goto do_default;
69571e6fec9dSRichard Henderson }
69581e6fec9dSRichard Henderson }
69591e6fec9dSRichard Henderson /* fall through */
6960b5701261SRichard Henderson case INDEX_op_mov:
6961d2fd745fSRichard Henderson case INDEX_op_mov_vec:
6962dd186292SRichard Henderson tcg_reg_alloc_mov(s, op);
6963c896fe29Sbellard break;
6964bab1671fSRichard Henderson case INDEX_op_dup_vec:
6965bab1671fSRichard Henderson tcg_reg_alloc_dup(s, op);
6966bab1671fSRichard Henderson break;
6967765b842aSRichard Henderson case INDEX_op_insn_start:
696876f42780SRichard Henderson assert_carry_dead(s);
6969fca8a500SRichard Henderson if (num_insns >= 0) {
69709f754620SRichard Henderson size_t off = tcg_current_code_size(s);
69719f754620SRichard Henderson s->gen_insn_end_off[num_insns] = off;
69729f754620SRichard Henderson /* Assert that we do not overflow our stored offset. */
69739f754620SRichard Henderson assert(s->gen_insn_end_off[num_insns] == off);
6974fca8a500SRichard Henderson }
6975fca8a500SRichard Henderson num_insns++;
6976e1d8fabcSRichard Henderson for (i = 0; i < INSN_START_WORDS; ++i) {
6977e1d8fabcSRichard Henderson s->gen_insn_data[num_insns * INSN_START_WORDS + i] =
6978c9ad8d27SRichard Henderson tcg_get_insn_start_param(op, i);
6979bad729e2SRichard Henderson }
6980c896fe29Sbellard break;
69815ff9d6a4Sbellard case INDEX_op_discard:
698243439139SRichard Henderson temp_dead(s, arg_temp(op->args[0]));
69835ff9d6a4Sbellard break;
6984c896fe29Sbellard case INDEX_op_set_label:
6985e8996ee0Sbellard tcg_reg_alloc_bb_end(s, s->reserved_regs);
698692ab8e7dSRichard Henderson tcg_out_label(s, arg_label(op->args[0]));
6987c896fe29Sbellard break;
6988c896fe29Sbellard case INDEX_op_call:
698976f42780SRichard Henderson assert_carry_dead(s);
6990dd186292SRichard Henderson tcg_reg_alloc_call(s, op);
6991c45cb8bbSRichard Henderson break;
6992b55a8d9dSRichard Henderson case INDEX_op_exit_tb:
6993b55a8d9dSRichard Henderson tcg_out_exit_tb(s, op->args[0]);
6994b55a8d9dSRichard Henderson break;
6995cf7d6b8eSRichard Henderson case INDEX_op_goto_tb:
6996cf7d6b8eSRichard Henderson tcg_out_goto_tb(s, op->args[0]);
6997cf7d6b8eSRichard Henderson break;
69983752a5a5SRichard Henderson case INDEX_op_br:
69993752a5a5SRichard Henderson tcg_out_br(s, arg_label(op->args[0]));
70003752a5a5SRichard Henderson break;
7001e038696cSRichard Henderson case INDEX_op_mb:
7002e038696cSRichard Henderson tcg_out_mb(s, op->args[0]);
7003e038696cSRichard Henderson break;
7004efe86b21SRichard Henderson case INDEX_op_dup2_vec:
7005efe86b21SRichard Henderson if (tcg_reg_alloc_dup2(s, op)) {
7006efe86b21SRichard Henderson break;
7007efe86b21SRichard Henderson }
7008efe86b21SRichard Henderson /* fall through */
7009c896fe29Sbellard default:
70101e6fec9dSRichard Henderson do_default:
701125c4d9ccSRichard Henderson /* Sanity check that we've not introduced any unhandled opcodes. */
7012771a5925SRichard Henderson tcg_debug_assert(tcg_op_supported(opc, TCGOP_TYPE(op),
7013771a5925SRichard Henderson TCGOP_FLAGS(op)));
7014c896fe29Sbellard /* Note: in order to speed up the code, it would be much
7015c896fe29Sbellard faster to have specialized register allocator functions for
7016c896fe29Sbellard some common argument patterns */
7017dd186292SRichard Henderson tcg_reg_alloc_op(s, op);
7018c896fe29Sbellard break;
7019c896fe29Sbellard }
7020b125f9dcSRichard Henderson /* Test for (pending) buffer overflow. The assumption is that any
7021b125f9dcSRichard Henderson one operation beginning below the high water mark cannot overrun
7022b125f9dcSRichard Henderson the buffer completely. Thus we can test for overflow after
7023b125f9dcSRichard Henderson generating code without having to check during generation. */
7024644da9b3SJohn Clarke if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) {
7025b125f9dcSRichard Henderson return -1;
7026b125f9dcSRichard Henderson }
70276e6c4efeSRichard Henderson /* Test for TB overflow, as seen by gen_insn_end_off. */
70286e6c4efeSRichard Henderson if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) {
70296e6c4efeSRichard Henderson return -2;
70306e6c4efeSRichard Henderson }
7031c896fe29Sbellard }
703276f42780SRichard Henderson assert_carry_dead(s);
703376f42780SRichard Henderson
7034747bd69dSRichard Henderson tcg_debug_assert(num_insns + 1 == s->gen_tb->icount);
7035fca8a500SRichard Henderson s->gen_insn_end_off[num_insns] = tcg_current_code_size(s);
7036c45cb8bbSRichard Henderson
7037b76f0d8cSYeongkyoon Lee /* Generate TB finalization at the end of block */
7038aeee05f5SRichard Henderson i = tcg_out_ldst_finalize(s);
7039aeee05f5SRichard Henderson if (i < 0) {
7040aeee05f5SRichard Henderson return i;
704123dceda6SRichard Henderson }
70421768987bSRichard Henderson i = tcg_out_pool_finalize(s);
70431768987bSRichard Henderson if (i < 0) {
70441768987bSRichard Henderson return i;
704557a26946SRichard Henderson }
70467ecd02a0SRichard Henderson if (!tcg_resolve_relocs(s)) {
70477ecd02a0SRichard Henderson return -2;
70487ecd02a0SRichard Henderson }
7049c896fe29Sbellard
7050df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
7051c896fe29Sbellard /* flush instruction cache */
7052db0c51a3SRichard Henderson flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf),
7053db0c51a3SRichard Henderson (uintptr_t)s->code_buf,
70541da8de39SRichard Henderson tcg_ptr_byte_diff(s->code_ptr, s->code_buf));
7055df5d2b16SRichard Henderson #endif
70562aeabc08SStefan Weil
70571813e175SRichard Henderson return tcg_current_code_size(s);
7058c896fe29Sbellard }
7059c896fe29Sbellard
7060813da627SRichard Henderson #ifdef ELF_HOST_MACHINE
70615872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things:
70625872bbf2SRichard Henderson
70635872bbf2SRichard Henderson (1) Define ELF_HOST_MACHINE to indicate both what value to
70645872bbf2SRichard Henderson put into the ELF image and to indicate support for the feature.
70655872bbf2SRichard Henderson
70665872bbf2SRichard Henderson (2) Define tcg_register_jit. This should create a buffer containing
70675872bbf2SRichard Henderson the contents of a .debug_frame section that describes the post-
70685872bbf2SRichard Henderson prologue unwind info for the tcg machine.
70695872bbf2SRichard Henderson
70705872bbf2SRichard Henderson (3) Call tcg_register_jit_int, with the constructed .debug_frame.
70715872bbf2SRichard Henderson */
7072813da627SRichard Henderson
7073813da627SRichard Henderson /* Begin GDB interface. THE FOLLOWING MUST MATCH GDB DOCS. */
7074813da627SRichard Henderson typedef enum {
7075813da627SRichard Henderson JIT_NOACTION = 0,
7076813da627SRichard Henderson JIT_REGISTER_FN,
7077813da627SRichard Henderson JIT_UNREGISTER_FN
7078813da627SRichard Henderson } jit_actions_t;
7079813da627SRichard Henderson
7080813da627SRichard Henderson struct jit_code_entry {
7081813da627SRichard Henderson struct jit_code_entry *next_entry;
7082813da627SRichard Henderson struct jit_code_entry *prev_entry;
7083813da627SRichard Henderson const void *symfile_addr;
7084813da627SRichard Henderson uint64_t symfile_size;
7085813da627SRichard Henderson };
7086813da627SRichard Henderson
7087813da627SRichard Henderson struct jit_descriptor {
7088813da627SRichard Henderson uint32_t version;
7089813da627SRichard Henderson uint32_t action_flag;
7090813da627SRichard Henderson struct jit_code_entry *relevant_entry;
7091813da627SRichard Henderson struct jit_code_entry *first_entry;
7092813da627SRichard Henderson };
7093813da627SRichard Henderson
7094813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline));
__jit_debug_register_code(void)7095813da627SRichard Henderson void __jit_debug_register_code(void)
7096813da627SRichard Henderson {
7097813da627SRichard Henderson asm("");
7098813da627SRichard Henderson }
7099813da627SRichard Henderson
7100813da627SRichard Henderson /* Must statically initialize the version, because GDB may check
7101813da627SRichard Henderson the version before we can set it. */
7102813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
7103813da627SRichard Henderson
7104813da627SRichard Henderson /* End GDB interface. */
7105813da627SRichard Henderson
find_string(const char * strtab,const char * str)7106813da627SRichard Henderson static int find_string(const char *strtab, const char *str)
7107813da627SRichard Henderson {
7108813da627SRichard Henderson const char *p = strtab + 1;
7109813da627SRichard Henderson
7110813da627SRichard Henderson while (1) {
7111813da627SRichard Henderson if (strcmp(p, str) == 0) {
7112813da627SRichard Henderson return p - strtab;
7113813da627SRichard Henderson }
7114813da627SRichard Henderson p += strlen(p) + 1;
7115813da627SRichard Henderson }
7116813da627SRichard Henderson }
7117813da627SRichard Henderson
tcg_register_jit_int(const void * buf_ptr,size_t buf_size,const void * debug_frame,size_t debug_frame_size)7118755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf_ptr, size_t buf_size,
71192c90784aSRichard Henderson const void *debug_frame,
71202c90784aSRichard Henderson size_t debug_frame_size)
7121813da627SRichard Henderson {
71225872bbf2SRichard Henderson struct __attribute__((packed)) DebugInfo {
71235872bbf2SRichard Henderson uint32_t len;
71245872bbf2SRichard Henderson uint16_t version;
71255872bbf2SRichard Henderson uint32_t abbrev;
71265872bbf2SRichard Henderson uint8_t ptr_size;
71275872bbf2SRichard Henderson uint8_t cu_die;
71285872bbf2SRichard Henderson uint16_t cu_lang;
71295872bbf2SRichard Henderson uintptr_t cu_low_pc;
71305872bbf2SRichard Henderson uintptr_t cu_high_pc;
71315872bbf2SRichard Henderson uint8_t fn_die;
71325872bbf2SRichard Henderson char fn_name[16];
71335872bbf2SRichard Henderson uintptr_t fn_low_pc;
71345872bbf2SRichard Henderson uintptr_t fn_high_pc;
71355872bbf2SRichard Henderson uint8_t cu_eoc;
71365872bbf2SRichard Henderson };
7137813da627SRichard Henderson
7138813da627SRichard Henderson struct ElfImage {
7139813da627SRichard Henderson ElfW(Ehdr) ehdr;
7140813da627SRichard Henderson ElfW(Phdr) phdr;
71415872bbf2SRichard Henderson ElfW(Shdr) shdr[7];
71425872bbf2SRichard Henderson ElfW(Sym) sym[2];
71435872bbf2SRichard Henderson struct DebugInfo di;
71445872bbf2SRichard Henderson uint8_t da[24];
71455872bbf2SRichard Henderson char str[80];
71465872bbf2SRichard Henderson };
71475872bbf2SRichard Henderson
71485872bbf2SRichard Henderson struct ElfImage *img;
71495872bbf2SRichard Henderson
71505872bbf2SRichard Henderson static const struct ElfImage img_template = {
71515872bbf2SRichard Henderson .ehdr = {
71525872bbf2SRichard Henderson .e_ident[EI_MAG0] = ELFMAG0,
71535872bbf2SRichard Henderson .e_ident[EI_MAG1] = ELFMAG1,
71545872bbf2SRichard Henderson .e_ident[EI_MAG2] = ELFMAG2,
71555872bbf2SRichard Henderson .e_ident[EI_MAG3] = ELFMAG3,
71565872bbf2SRichard Henderson .e_ident[EI_CLASS] = ELF_CLASS,
71575872bbf2SRichard Henderson .e_ident[EI_DATA] = ELF_DATA,
71585872bbf2SRichard Henderson .e_ident[EI_VERSION] = EV_CURRENT,
71595872bbf2SRichard Henderson .e_type = ET_EXEC,
71605872bbf2SRichard Henderson .e_machine = ELF_HOST_MACHINE,
71615872bbf2SRichard Henderson .e_version = EV_CURRENT,
71625872bbf2SRichard Henderson .e_phoff = offsetof(struct ElfImage, phdr),
71635872bbf2SRichard Henderson .e_shoff = offsetof(struct ElfImage, shdr),
71645872bbf2SRichard Henderson .e_ehsize = sizeof(ElfW(Shdr)),
71655872bbf2SRichard Henderson .e_phentsize = sizeof(ElfW(Phdr)),
71665872bbf2SRichard Henderson .e_phnum = 1,
71675872bbf2SRichard Henderson .e_shentsize = sizeof(ElfW(Shdr)),
71685872bbf2SRichard Henderson .e_shnum = ARRAY_SIZE(img->shdr),
71695872bbf2SRichard Henderson .e_shstrndx = ARRAY_SIZE(img->shdr) - 1,
7170abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS
7171abbb3eaeSRichard Henderson .e_flags = ELF_HOST_FLAGS,
7172abbb3eaeSRichard Henderson #endif
7173abbb3eaeSRichard Henderson #ifdef ELF_OSABI
7174abbb3eaeSRichard Henderson .e_ident[EI_OSABI] = ELF_OSABI,
7175abbb3eaeSRichard Henderson #endif
71765872bbf2SRichard Henderson },
71775872bbf2SRichard Henderson .phdr = {
71785872bbf2SRichard Henderson .p_type = PT_LOAD,
71795872bbf2SRichard Henderson .p_flags = PF_X,
71805872bbf2SRichard Henderson },
71815872bbf2SRichard Henderson .shdr = {
71825872bbf2SRichard Henderson [0] = { .sh_type = SHT_NULL },
71835872bbf2SRichard Henderson /* Trick: The contents of code_gen_buffer are not present in
71845872bbf2SRichard Henderson this fake ELF file; that got allocated elsewhere. Therefore
71855872bbf2SRichard Henderson we mark .text as SHT_NOBITS (similar to .bss) so that readers
71865872bbf2SRichard Henderson will not look for contents. We can record any address. */
71875872bbf2SRichard Henderson [1] = { /* .text */
71885872bbf2SRichard Henderson .sh_type = SHT_NOBITS,
71895872bbf2SRichard Henderson .sh_flags = SHF_EXECINSTR | SHF_ALLOC,
71905872bbf2SRichard Henderson },
71915872bbf2SRichard Henderson [2] = { /* .debug_info */
71925872bbf2SRichard Henderson .sh_type = SHT_PROGBITS,
71935872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, di),
71945872bbf2SRichard Henderson .sh_size = sizeof(struct DebugInfo),
71955872bbf2SRichard Henderson },
71965872bbf2SRichard Henderson [3] = { /* .debug_abbrev */
71975872bbf2SRichard Henderson .sh_type = SHT_PROGBITS,
71985872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, da),
71995872bbf2SRichard Henderson .sh_size = sizeof(img->da),
72005872bbf2SRichard Henderson },
72015872bbf2SRichard Henderson [4] = { /* .debug_frame */
72025872bbf2SRichard Henderson .sh_type = SHT_PROGBITS,
72035872bbf2SRichard Henderson .sh_offset = sizeof(struct ElfImage),
72045872bbf2SRichard Henderson },
72055872bbf2SRichard Henderson [5] = { /* .symtab */
72065872bbf2SRichard Henderson .sh_type = SHT_SYMTAB,
72075872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, sym),
72085872bbf2SRichard Henderson .sh_size = sizeof(img->sym),
72095872bbf2SRichard Henderson .sh_info = 1,
72105872bbf2SRichard Henderson .sh_link = ARRAY_SIZE(img->shdr) - 1,
72115872bbf2SRichard Henderson .sh_entsize = sizeof(ElfW(Sym)),
72125872bbf2SRichard Henderson },
72135872bbf2SRichard Henderson [6] = { /* .strtab */
72145872bbf2SRichard Henderson .sh_type = SHT_STRTAB,
72155872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, str),
72165872bbf2SRichard Henderson .sh_size = sizeof(img->str),
72175872bbf2SRichard Henderson }
72185872bbf2SRichard Henderson },
72195872bbf2SRichard Henderson .sym = {
72205872bbf2SRichard Henderson [1] = { /* code_gen_buffer */
72215872bbf2SRichard Henderson .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC),
72225872bbf2SRichard Henderson .st_shndx = 1,
72235872bbf2SRichard Henderson }
72245872bbf2SRichard Henderson },
72255872bbf2SRichard Henderson .di = {
72265872bbf2SRichard Henderson .len = sizeof(struct DebugInfo) - 4,
72275872bbf2SRichard Henderson .version = 2,
72285872bbf2SRichard Henderson .ptr_size = sizeof(void *),
72295872bbf2SRichard Henderson .cu_die = 1,
72305872bbf2SRichard Henderson .cu_lang = 0x8001, /* DW_LANG_Mips_Assembler */
72315872bbf2SRichard Henderson .fn_die = 2,
72325872bbf2SRichard Henderson .fn_name = "code_gen_buffer"
72335872bbf2SRichard Henderson },
72345872bbf2SRichard Henderson .da = {
72355872bbf2SRichard Henderson 1, /* abbrev number (the cu) */
72365872bbf2SRichard Henderson 0x11, 1, /* DW_TAG_compile_unit, has children */
72375872bbf2SRichard Henderson 0x13, 0x5, /* DW_AT_language, DW_FORM_data2 */
72385872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */
72395872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */
72405872bbf2SRichard Henderson 0, 0, /* end of abbrev */
72415872bbf2SRichard Henderson 2, /* abbrev number (the fn) */
72425872bbf2SRichard Henderson 0x2e, 0, /* DW_TAG_subprogram, no children */
72435872bbf2SRichard Henderson 0x3, 0x8, /* DW_AT_name, DW_FORM_string */
72445872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */
72455872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */
72465872bbf2SRichard Henderson 0, 0, /* end of abbrev */
72475872bbf2SRichard Henderson 0 /* no more abbrev */
72485872bbf2SRichard Henderson },
72495872bbf2SRichard Henderson .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0"
72505872bbf2SRichard Henderson ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer",
7251813da627SRichard Henderson };
7252813da627SRichard Henderson
7253813da627SRichard Henderson /* We only need a single jit entry; statically allocate it. */
7254813da627SRichard Henderson static struct jit_code_entry one_entry;
7255813da627SRichard Henderson
72565872bbf2SRichard Henderson uintptr_t buf = (uintptr_t)buf_ptr;
7257813da627SRichard Henderson size_t img_size = sizeof(struct ElfImage) + debug_frame_size;
72582c90784aSRichard Henderson DebugFrameHeader *dfh;
7259813da627SRichard Henderson
72605872bbf2SRichard Henderson img = g_malloc(img_size);
72615872bbf2SRichard Henderson *img = img_template;
7262813da627SRichard Henderson
72635872bbf2SRichard Henderson img->phdr.p_vaddr = buf;
72645872bbf2SRichard Henderson img->phdr.p_paddr = buf;
72655872bbf2SRichard Henderson img->phdr.p_memsz = buf_size;
7266813da627SRichard Henderson
72675872bbf2SRichard Henderson img->shdr[1].sh_name = find_string(img->str, ".text");
72685872bbf2SRichard Henderson img->shdr[1].sh_addr = buf;
72695872bbf2SRichard Henderson img->shdr[1].sh_size = buf_size;
7270813da627SRichard Henderson
72715872bbf2SRichard Henderson img->shdr[2].sh_name = find_string(img->str, ".debug_info");
72725872bbf2SRichard Henderson img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev");
72735872bbf2SRichard Henderson
72745872bbf2SRichard Henderson img->shdr[4].sh_name = find_string(img->str, ".debug_frame");
72755872bbf2SRichard Henderson img->shdr[4].sh_size = debug_frame_size;
72765872bbf2SRichard Henderson
72775872bbf2SRichard Henderson img->shdr[5].sh_name = find_string(img->str, ".symtab");
72785872bbf2SRichard Henderson img->shdr[6].sh_name = find_string(img->str, ".strtab");
72795872bbf2SRichard Henderson
72805872bbf2SRichard Henderson img->sym[1].st_name = find_string(img->str, "code_gen_buffer");
72815872bbf2SRichard Henderson img->sym[1].st_value = buf;
72825872bbf2SRichard Henderson img->sym[1].st_size = buf_size;
72835872bbf2SRichard Henderson
72845872bbf2SRichard Henderson img->di.cu_low_pc = buf;
728545aba097SRichard Henderson img->di.cu_high_pc = buf + buf_size;
72865872bbf2SRichard Henderson img->di.fn_low_pc = buf;
728745aba097SRichard Henderson img->di.fn_high_pc = buf + buf_size;
7288813da627SRichard Henderson
72892c90784aSRichard Henderson dfh = (DebugFrameHeader *)(img + 1);
72902c90784aSRichard Henderson memcpy(dfh, debug_frame, debug_frame_size);
72912c90784aSRichard Henderson dfh->fde.func_start = buf;
72922c90784aSRichard Henderson dfh->fde.func_len = buf_size;
72932c90784aSRichard Henderson
7294813da627SRichard Henderson #ifdef DEBUG_JIT
7295813da627SRichard Henderson /* Enable this block to be able to debug the ELF image file creation.
7296813da627SRichard Henderson One can use readelf, objdump, or other inspection utilities. */
7297813da627SRichard Henderson {
7298eb6b2edfSBin Meng g_autofree char *jit = g_strdup_printf("%s/qemu.jit", g_get_tmp_dir());
7299eb6b2edfSBin Meng FILE *f = fopen(jit, "w+b");
7300813da627SRichard Henderson if (f) {
73015872bbf2SRichard Henderson if (fwrite(img, img_size, 1, f) != img_size) {
7302813da627SRichard Henderson /* Avoid stupid unused return value warning for fwrite. */
7303813da627SRichard Henderson }
7304813da627SRichard Henderson fclose(f);
7305813da627SRichard Henderson }
7306813da627SRichard Henderson }
7307813da627SRichard Henderson #endif
7308813da627SRichard Henderson
7309813da627SRichard Henderson one_entry.symfile_addr = img;
7310813da627SRichard Henderson one_entry.symfile_size = img_size;
7311813da627SRichard Henderson
7312813da627SRichard Henderson __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
7313813da627SRichard Henderson __jit_debug_descriptor.relevant_entry = &one_entry;
7314813da627SRichard Henderson __jit_debug_descriptor.first_entry = &one_entry;
7315813da627SRichard Henderson __jit_debug_register_code();
7316813da627SRichard Henderson }
7317813da627SRichard Henderson #else
73185872bbf2SRichard Henderson /* No support for the feature. Provide the entry point expected by exec.c,
73195872bbf2SRichard Henderson and implement the internal function we declared earlier. */
7320813da627SRichard Henderson
tcg_register_jit_int(const void * buf,size_t size,const void * debug_frame,size_t debug_frame_size)7321755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size,
73222c90784aSRichard Henderson const void *debug_frame,
73232c90784aSRichard Henderson size_t debug_frame_size)
7324813da627SRichard Henderson {
7325813da627SRichard Henderson }
7326813da627SRichard Henderson
tcg_register_jit(const void * buf,size_t buf_size)7327755bf9e5SRichard Henderson void tcg_register_jit(const void *buf, size_t buf_size)
7328813da627SRichard Henderson {
7329813da627SRichard Henderson }
7330813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */
7331db432672SRichard Henderson
7332db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec
tcg_expand_vec_op(TCGOpcode o,TCGType t,unsigned e,TCGArg a0,...)7333db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...)
7334db432672SRichard Henderson {
7335db432672SRichard Henderson g_assert_not_reached();
7336db432672SRichard Henderson }
7337db432672SRichard Henderson #endif
7338