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"
37cac9b0fdSRichard Henderson #include "exec/translation-block.h"
38d0a9bb5eSRichard Henderson #include "exec/tlb-common.h"
39d7ec12f8SRichard Henderson #include "tcg/startup.h"
40ad3d0e4dSRichard Henderson #include "tcg/tcg-op-common.h"
41813da627SRichard Henderson
42edee2579SRichard Henderson #if UINTPTR_MAX == UINT32_MAX
43813da627SRichard Henderson # define ELF_CLASS ELFCLASS32
44edee2579SRichard Henderson #else
45edee2579SRichard Henderson # define ELF_CLASS ELFCLASS64
46813da627SRichard Henderson #endif
47e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN
48813da627SRichard Henderson # define ELF_DATA ELFDATA2MSB
49813da627SRichard Henderson #else
50813da627SRichard Henderson # define ELF_DATA ELFDATA2LSB
51813da627SRichard Henderson #endif
52813da627SRichard Henderson
53c896fe29Sbellard #include "elf.h"
54508127e2SPaolo Bonzini #include "exec/log.h"
55d2ba8026SRichard Henderson #include "tcg/tcg-ldst.h"
5647f7313dSRichard Henderson #include "tcg/tcg-temp-internal.h"
575ff7258cSRichard Henderson #include "tcg-internal.h"
58327b75a4SIlya Leoshkevich #include "tcg/perf.h"
597d478306SRichard Henderson #ifdef CONFIG_USER_ONLY
60d3cbde74SPhilippe Mathieu-Daudé #include "user/guest-base.h"
617d478306SRichard Henderson #endif
62c896fe29Sbellard
63139c1837SPaolo Bonzini /* Forward declarations for functions declared in tcg-target.c.inc and
64ce151109SPeter Maydell used here. */
65e4d58b41SRichard Henderson static void tcg_target_init(TCGContext *s);
66e4d58b41SRichard Henderson static void tcg_target_qemu_prologue(TCGContext *s);
676ac17786SRichard Henderson static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
682ba7fae2SRichard Henderson intptr_t value, intptr_t addend);
69c896fe29Sbellard
70497a22ebSRichard Henderson /* The CIE and FDE header definitions will be common to all hosts. */
71497a22ebSRichard Henderson typedef struct {
72497a22ebSRichard Henderson uint32_t len __attribute__((aligned((sizeof(void *)))));
73497a22ebSRichard Henderson uint32_t id;
74497a22ebSRichard Henderson uint8_t version;
75497a22ebSRichard Henderson char augmentation[1];
76497a22ebSRichard Henderson uint8_t code_align;
77497a22ebSRichard Henderson uint8_t data_align;
78497a22ebSRichard Henderson uint8_t return_column;
79497a22ebSRichard Henderson } DebugFrameCIE;
80497a22ebSRichard Henderson
81497a22ebSRichard Henderson typedef struct QEMU_PACKED {
82497a22ebSRichard Henderson uint32_t len __attribute__((aligned((sizeof(void *)))));
83497a22ebSRichard Henderson uint32_t cie_offset;
84edee2579SRichard Henderson uintptr_t func_start;
85edee2579SRichard Henderson uintptr_t func_len;
86497a22ebSRichard Henderson } DebugFrameFDEHeader;
87497a22ebSRichard Henderson
882c90784aSRichard Henderson typedef struct QEMU_PACKED {
892c90784aSRichard Henderson DebugFrameCIE cie;
902c90784aSRichard Henderson DebugFrameFDEHeader fde;
912c90784aSRichard Henderson } DebugFrameHeader;
922c90784aSRichard Henderson
932528f771SRichard Henderson typedef struct TCGLabelQemuLdst {
942528f771SRichard Henderson bool is_ld; /* qemu_ld: true, qemu_st: false */
952528f771SRichard Henderson MemOpIdx oi;
962528f771SRichard Henderson TCGType type; /* result type of a load */
972528f771SRichard Henderson TCGReg addrlo_reg; /* reg index for low word of guest virtual addr */
982528f771SRichard Henderson TCGReg addrhi_reg; /* reg index for high word of guest virtual addr */
992528f771SRichard Henderson TCGReg datalo_reg; /* reg index for low word to be loaded or stored */
1002528f771SRichard Henderson TCGReg datahi_reg; /* reg index for high word to be loaded or stored */
1012528f771SRichard Henderson const tcg_insn_unit *raddr; /* addr of the next IR of qemu_ld/st IR */
1022528f771SRichard Henderson tcg_insn_unit *label_ptr[2]; /* label pointers to be updated */
1032528f771SRichard Henderson QSIMPLEQ_ENTRY(TCGLabelQemuLdst) next;
1042528f771SRichard Henderson } TCGLabelQemuLdst;
1052528f771SRichard Henderson
106755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size,
1072c90784aSRichard Henderson const void *debug_frame,
1082c90784aSRichard Henderson size_t debug_frame_size)
109813da627SRichard Henderson __attribute__((unused));
110813da627SRichard Henderson
111139c1837SPaolo Bonzini /* Forward declarations for functions declared and used in tcg-target.c.inc. */
1129358fbbfSRichard Henderson static void tcg_out_tb_start(TCGContext *s);
1132a534affSRichard Henderson static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
114a05b5b9bSRichard Henderson intptr_t arg2);
11578113e83SRichard Henderson static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
116c0ad3001SStefan Weil static void tcg_out_movi(TCGContext *s, TCGType type,
1172a534affSRichard Henderson TCGReg ret, tcg_target_long arg);
118678155b2SRichard Henderson static void tcg_out_ext8s(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
119753e42eaSRichard Henderson static void tcg_out_ext16s(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
120d0e66c89SRichard Henderson static void tcg_out_ext8u(TCGContext *s, TCGReg ret, TCGReg arg);
121379afdffSRichard Henderson static void tcg_out_ext16u(TCGContext *s, TCGReg ret, TCGReg arg);
12252bf3398SRichard Henderson static void tcg_out_ext32s(TCGContext *s, TCGReg ret, TCGReg arg);
1239ecf5f61SRichard Henderson static void tcg_out_ext32u(TCGContext *s, TCGReg ret, TCGReg arg);
1249c6aa274SRichard Henderson static void tcg_out_exts_i32_i64(TCGContext *s, TCGReg ret, TCGReg arg);
125b9bfe000SRichard Henderson static void tcg_out_extu_i32_i64(TCGContext *s, TCGReg ret, TCGReg arg);
126b8b94ac6SRichard Henderson static void tcg_out_extrl_i64_i32(TCGContext *s, TCGReg ret, TCGReg arg);
127313bdea8SRichard Henderson static void tcg_out_addi_ptr(TCGContext *s, TCGReg, TCGReg, tcg_target_long);
128129f1f9eSRichard Henderson static bool tcg_out_xchg(TCGContext *s, TCGType type, TCGReg r1, TCGReg r2);
129b55a8d9dSRichard Henderson static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg);
130cf7d6b8eSRichard Henderson static void tcg_out_goto_tb(TCGContext *s, int which);
1315e8892dbSMiroslav Rezanina static void tcg_out_op(TCGContext *s, TCGOpcode opc,
1325e8892dbSMiroslav Rezanina const TCGArg args[TCG_MAX_OP_ARGS],
1335e8892dbSMiroslav Rezanina const int const_args[TCG_MAX_OP_ARGS]);
134d2fd745fSRichard Henderson #if TCG_TARGET_MAYBE_vec
135e7632cfaSRichard Henderson static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
136e7632cfaSRichard Henderson TCGReg dst, TCGReg src);
137d6ecb4a9SRichard Henderson static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
138d6ecb4a9SRichard Henderson TCGReg dst, TCGReg base, intptr_t offset);
1394e186175SRichard Henderson static void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece,
1404e186175SRichard Henderson TCGReg dst, int64_t arg);
1415e8892dbSMiroslav Rezanina static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
1425e8892dbSMiroslav Rezanina unsigned vecl, unsigned vece,
1435e8892dbSMiroslav Rezanina const TCGArg args[TCG_MAX_OP_ARGS],
1445e8892dbSMiroslav Rezanina const int const_args[TCG_MAX_OP_ARGS]);
145d2fd745fSRichard Henderson #else
tcg_out_dup_vec(TCGContext * s,TCGType type,unsigned vece,TCGReg dst,TCGReg src)146e7632cfaSRichard Henderson static inline bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
147e7632cfaSRichard Henderson TCGReg dst, TCGReg src)
148e7632cfaSRichard Henderson {
149e7632cfaSRichard Henderson g_assert_not_reached();
150e7632cfaSRichard Henderson }
tcg_out_dupm_vec(TCGContext * s,TCGType type,unsigned vece,TCGReg dst,TCGReg base,intptr_t offset)151d6ecb4a9SRichard Henderson static inline bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
152d6ecb4a9SRichard Henderson TCGReg dst, TCGReg base, intptr_t offset)
153d6ecb4a9SRichard Henderson {
154d6ecb4a9SRichard Henderson g_assert_not_reached();
155d6ecb4a9SRichard Henderson }
tcg_out_dupi_vec(TCGContext * s,TCGType type,unsigned vece,TCGReg dst,int64_t arg)1564e186175SRichard Henderson static inline void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece,
1574e186175SRichard Henderson TCGReg dst, int64_t arg)
158e7632cfaSRichard Henderson {
159e7632cfaSRichard Henderson g_assert_not_reached();
160e7632cfaSRichard 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])1615e8892dbSMiroslav Rezanina static inline void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
1625e8892dbSMiroslav Rezanina unsigned vecl, unsigned vece,
1635e8892dbSMiroslav Rezanina const TCGArg args[TCG_MAX_OP_ARGS],
1645e8892dbSMiroslav Rezanina const int const_args[TCG_MAX_OP_ARGS])
165d2fd745fSRichard Henderson {
166d2fd745fSRichard Henderson g_assert_not_reached();
167d2fd745fSRichard Henderson }
168d2fd745fSRichard Henderson #endif
1692a534affSRichard Henderson static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
170a05b5b9bSRichard Henderson intptr_t arg2);
17159d7c14eSRichard Henderson static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
17259d7c14eSRichard Henderson TCGReg base, intptr_t ofs);
1737b7d8b2dSRichard Henderson static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target,
174cee44b03SRichard Henderson const TCGHelperInfo *info);
1755e3d0c19SRichard Henderson static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot);
17621e9a8aeSRichard Henderson static bool tcg_target_const_match(int64_t val, int ct,
17721e9a8aeSRichard Henderson TCGType type, TCGCond cond, int vece);
178659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
179aeee05f5SRichard Henderson static int tcg_out_ldst_finalize(TCGContext *s);
180659ef5cbSRichard Henderson #endif
181c896fe29Sbellard
18223088ca0SRichard Henderson #ifndef CONFIG_USER_ONLY
18323088ca0SRichard Henderson #define guest_base ({ qemu_build_not_reached(); (uintptr_t)0; })
18423088ca0SRichard Henderson #endif
18523088ca0SRichard Henderson
1868429a1caSRichard Henderson typedef struct TCGLdstHelperParam {
1878429a1caSRichard Henderson TCGReg (*ra_gen)(TCGContext *s, const TCGLabelQemuLdst *l, int arg_reg);
1888429a1caSRichard Henderson unsigned ntmp;
1898429a1caSRichard Henderson int tmp[3];
1908429a1caSRichard Henderson } TCGLdstHelperParam;
1918429a1caSRichard Henderson
1928429a1caSRichard Henderson static void tcg_out_ld_helper_args(TCGContext *s, const TCGLabelQemuLdst *l,
1938429a1caSRichard Henderson const TCGLdstHelperParam *p)
1948429a1caSRichard Henderson __attribute__((unused));
1958429a1caSRichard Henderson static void tcg_out_ld_helper_ret(TCGContext *s, const TCGLabelQemuLdst *l,
1968429a1caSRichard Henderson bool load_sign, const TCGLdstHelperParam *p)
1978429a1caSRichard Henderson __attribute__((unused));
1988429a1caSRichard Henderson static void tcg_out_st_helper_args(TCGContext *s, const TCGLabelQemuLdst *l,
1998429a1caSRichard Henderson const TCGLdstHelperParam *p)
2008429a1caSRichard Henderson __attribute__((unused));
2018429a1caSRichard Henderson
202de95016dSRichard Henderson static void * const qemu_ld_helpers[MO_SSIZE + 1] __attribute__((unused)) = {
2030cadc1edSRichard Henderson [MO_UB] = helper_ldub_mmu,
2040cadc1edSRichard Henderson [MO_SB] = helper_ldsb_mmu,
2050cadc1edSRichard Henderson [MO_UW] = helper_lduw_mmu,
2060cadc1edSRichard Henderson [MO_SW] = helper_ldsw_mmu,
2070cadc1edSRichard Henderson [MO_UL] = helper_ldul_mmu,
2080cadc1edSRichard Henderson [MO_UQ] = helper_ldq_mmu,
2090cadc1edSRichard Henderson #if TCG_TARGET_REG_BITS == 64
2100cadc1edSRichard Henderson [MO_SL] = helper_ldsl_mmu,
211ebebea53SRichard Henderson [MO_128] = helper_ld16_mmu,
2120cadc1edSRichard Henderson #endif
2130cadc1edSRichard Henderson };
2140cadc1edSRichard Henderson
215de95016dSRichard Henderson static void * const qemu_st_helpers[MO_SIZE + 1] __attribute__((unused)) = {
2160cadc1edSRichard Henderson [MO_8] = helper_stb_mmu,
2170cadc1edSRichard Henderson [MO_16] = helper_stw_mmu,
2180cadc1edSRichard Henderson [MO_32] = helper_stl_mmu,
2190cadc1edSRichard Henderson [MO_64] = helper_stq_mmu,
220ebebea53SRichard Henderson #if TCG_TARGET_REG_BITS == 64
221ebebea53SRichard Henderson [MO_128] = helper_st16_mmu,
222ebebea53SRichard Henderson #endif
2230cadc1edSRichard Henderson };
2240cadc1edSRichard Henderson
225e63b8a29SRichard Henderson typedef struct {
226e63b8a29SRichard Henderson MemOp atom; /* lg2 bits of atomicity required */
227e63b8a29SRichard Henderson MemOp align; /* lg2 bits of alignment to use */
228e63b8a29SRichard Henderson } TCGAtomAlign;
229e63b8a29SRichard Henderson
230e63b8a29SRichard Henderson static TCGAtomAlign atom_and_align_for_opc(TCGContext *s, MemOp opc,
231e63b8a29SRichard Henderson MemOp host_atom, bool allow_two_ops)
232e63b8a29SRichard Henderson __attribute__((unused));
233e63b8a29SRichard Henderson
234397cabaaSRichard Henderson #ifdef CONFIG_USER_ONLY
235397cabaaSRichard Henderson bool tcg_use_softmmu;
236397cabaaSRichard Henderson #endif
237397cabaaSRichard Henderson
23842eb6dfcSRichard Henderson TCGContext tcg_init_ctx;
23942eb6dfcSRichard Henderson __thread TCGContext *tcg_ctx;
24042eb6dfcSRichard Henderson
2415ff7258cSRichard Henderson TCGContext **tcg_ctxs;
2420e2d61cfSRichard Henderson unsigned int tcg_cur_ctxs;
2430e2d61cfSRichard Henderson unsigned int tcg_max_ctxs;
244ad75a51eSRichard Henderson TCGv_env tcg_env;
245c8bc1168SRichard Henderson const void *tcg_code_gen_epilogue;
246db0c51a3SRichard Henderson uintptr_t tcg_splitwx_diff;
247df2cce29SEmilio G. Cota
248b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
249b91ccb31SRichard Henderson tcg_prologue_fn *tcg_qemu_tb_exec;
250b91ccb31SRichard Henderson #endif
251b91ccb31SRichard Henderson
252d2fd745fSRichard Henderson static TCGRegSet tcg_target_available_regs[TCG_TYPE_COUNT];
253b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs;
254c896fe29Sbellard
2551813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1
tcg_out8(TCGContext * s,uint8_t v)2564196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v)
257c896fe29Sbellard {
258c896fe29Sbellard *s->code_ptr++ = v;
259c896fe29Sbellard }
260c896fe29Sbellard
tcg_patch8(tcg_insn_unit * p,uint8_t v)2614196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p,
2624196dca6SPeter Maydell uint8_t v)
2635c53bb81SPeter Maydell {
2641813e175SRichard Henderson *p = v;
2655c53bb81SPeter Maydell }
2661813e175SRichard Henderson #endif
2675c53bb81SPeter Maydell
2681813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2
tcg_out16(TCGContext * s,uint16_t v)2694196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v)
270c896fe29Sbellard {
2711813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
2721813e175SRichard Henderson *s->code_ptr++ = v;
2731813e175SRichard Henderson } else {
2741813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr;
2754387345aSPeter Maydell memcpy(p, &v, sizeof(v));
2761813e175SRichard Henderson s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE);
2771813e175SRichard Henderson }
278c896fe29Sbellard }
279c896fe29Sbellard
tcg_patch16(tcg_insn_unit * p,uint16_t v)2804196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p,
2814196dca6SPeter Maydell uint16_t v)
2825c53bb81SPeter Maydell {
2831813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
2841813e175SRichard Henderson *p = v;
2851813e175SRichard Henderson } else {
2865c53bb81SPeter Maydell memcpy(p, &v, sizeof(v));
2875c53bb81SPeter Maydell }
2881813e175SRichard Henderson }
2891813e175SRichard Henderson #endif
2905c53bb81SPeter Maydell
2911813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4
tcg_out32(TCGContext * s,uint32_t v)2924196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v)
293c896fe29Sbellard {
2941813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
2951813e175SRichard Henderson *s->code_ptr++ = v;
2961813e175SRichard Henderson } else {
2971813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr;
2984387345aSPeter Maydell memcpy(p, &v, sizeof(v));
2991813e175SRichard Henderson s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE);
3001813e175SRichard Henderson }
301c896fe29Sbellard }
302c896fe29Sbellard
tcg_patch32(tcg_insn_unit * p,uint32_t v)3034196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p,
3044196dca6SPeter Maydell uint32_t v)
3055c53bb81SPeter Maydell {
3061813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
3071813e175SRichard Henderson *p = v;
3081813e175SRichard Henderson } else {
3095c53bb81SPeter Maydell memcpy(p, &v, sizeof(v));
3105c53bb81SPeter Maydell }
3111813e175SRichard Henderson }
3121813e175SRichard Henderson #endif
3135c53bb81SPeter Maydell
3141813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 8
tcg_out64(TCGContext * s,uint64_t v)3154196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v)
316ac26eb69SRichard Henderson {
3171813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
3181813e175SRichard Henderson *s->code_ptr++ = v;
3191813e175SRichard Henderson } else {
3201813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr;
3214387345aSPeter Maydell memcpy(p, &v, sizeof(v));
3221813e175SRichard Henderson s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE);
3231813e175SRichard Henderson }
324ac26eb69SRichard Henderson }
325ac26eb69SRichard Henderson
tcg_patch64(tcg_insn_unit * p,uint64_t v)3264196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p,
3274196dca6SPeter Maydell uint64_t v)
3285c53bb81SPeter Maydell {
3291813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
3301813e175SRichard Henderson *p = v;
3311813e175SRichard Henderson } else {
3325c53bb81SPeter Maydell memcpy(p, &v, sizeof(v));
3335c53bb81SPeter Maydell }
3341813e175SRichard Henderson }
3351813e175SRichard Henderson #endif
3365c53bb81SPeter Maydell
337c896fe29Sbellard /* label relocation processing */
338c896fe29Sbellard
tcg_out_reloc(TCGContext * s,tcg_insn_unit * code_ptr,int type,TCGLabel * l,intptr_t addend)3391813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
340bec16311SRichard Henderson TCGLabel *l, intptr_t addend)
341c896fe29Sbellard {
3427ecd02a0SRichard Henderson TCGRelocation *r = tcg_malloc(sizeof(TCGRelocation));
343c896fe29Sbellard
344c896fe29Sbellard r->type = type;
345c896fe29Sbellard r->ptr = code_ptr;
346c896fe29Sbellard r->addend = addend;
3477ecd02a0SRichard Henderson QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next);
348c896fe29Sbellard }
349c896fe29Sbellard
tcg_out_label(TCGContext * s,TCGLabel * l)35092ab8e7dSRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l)
351c896fe29Sbellard {
352eabb7b91SAurelien Jarno tcg_debug_assert(!l->has_value);
353c896fe29Sbellard l->has_value = 1;
35492ab8e7dSRichard Henderson l->u.value_ptr = tcg_splitwx_to_rx(s->code_ptr);
355c896fe29Sbellard }
356c896fe29Sbellard
gen_new_label(void)35742a268c2SRichard Henderson TCGLabel *gen_new_label(void)
358c896fe29Sbellard {
359b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx;
36051e3972cSRichard Henderson TCGLabel *l = tcg_malloc(sizeof(TCGLabel));
361c896fe29Sbellard
3627ecd02a0SRichard Henderson memset(l, 0, sizeof(TCGLabel));
3637ecd02a0SRichard Henderson l->id = s->nb_labels++;
364f85b1fc4SRichard Henderson QSIMPLEQ_INIT(&l->branches);
3657ecd02a0SRichard Henderson QSIMPLEQ_INIT(&l->relocs);
3667ecd02a0SRichard Henderson
367bef16ab4SRichard Henderson QSIMPLEQ_INSERT_TAIL(&s->labels, l, next);
36842a268c2SRichard Henderson
36942a268c2SRichard Henderson return l;
370c896fe29Sbellard }
371c896fe29Sbellard
tcg_resolve_relocs(TCGContext * s)3727ecd02a0SRichard Henderson static bool tcg_resolve_relocs(TCGContext *s)
3737ecd02a0SRichard Henderson {
3747ecd02a0SRichard Henderson TCGLabel *l;
3757ecd02a0SRichard Henderson
3767ecd02a0SRichard Henderson QSIMPLEQ_FOREACH(l, &s->labels, next) {
3777ecd02a0SRichard Henderson TCGRelocation *r;
3787ecd02a0SRichard Henderson uintptr_t value = l->u.value;
3797ecd02a0SRichard Henderson
3807ecd02a0SRichard Henderson QSIMPLEQ_FOREACH(r, &l->relocs, next) {
3817ecd02a0SRichard Henderson if (!patch_reloc(r->ptr, r->type, value, r->addend)) {
3827ecd02a0SRichard Henderson return false;
3837ecd02a0SRichard Henderson }
3847ecd02a0SRichard Henderson }
3857ecd02a0SRichard Henderson }
3867ecd02a0SRichard Henderson return true;
3877ecd02a0SRichard Henderson }
3887ecd02a0SRichard Henderson
set_jmp_reset_offset(TCGContext * s,int which)3899f754620SRichard Henderson static void set_jmp_reset_offset(TCGContext *s, int which)
3909f754620SRichard Henderson {
391f14bed3fSRichard Henderson /*
392f14bed3fSRichard Henderson * We will check for overflow at the end of the opcode loop in
393f14bed3fSRichard Henderson * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX.
394f14bed3fSRichard Henderson */
395b7e4afbdSRichard Henderson s->gen_tb->jmp_reset_offset[which] = tcg_current_code_size(s);
3969f754620SRichard Henderson }
3979f754620SRichard Henderson
set_jmp_insn_offset(TCGContext * s,int which)398b52a2c03SRichard Henderson static void G_GNUC_UNUSED set_jmp_insn_offset(TCGContext *s, int which)
399b52a2c03SRichard Henderson {
400b52a2c03SRichard Henderson /*
401b52a2c03SRichard Henderson * We will check for overflow at the end of the opcode loop in
402b52a2c03SRichard Henderson * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX.
403b52a2c03SRichard Henderson */
4049da6079bSRichard Henderson s->gen_tb->jmp_insn_offset[which] = tcg_current_code_size(s);
405b52a2c03SRichard Henderson }
406b52a2c03SRichard Henderson
get_jmp_target_addr(TCGContext * s,int which)407becc452aSRichard Henderson static uintptr_t G_GNUC_UNUSED get_jmp_target_addr(TCGContext *s, int which)
408becc452aSRichard Henderson {
409becc452aSRichard Henderson /*
410becc452aSRichard Henderson * Return the read-execute version of the pointer, for the benefit
411becc452aSRichard Henderson * of any pc-relative addressing mode.
412becc452aSRichard Henderson */
4139da6079bSRichard Henderson return (uintptr_t)tcg_splitwx_to_rx(&s->gen_tb->jmp_target_addr[which]);
414becc452aSRichard Henderson }
415becc452aSRichard Henderson
416397cabaaSRichard Henderson static int __attribute__((unused))
tlb_mask_table_ofs(TCGContext * s,int which)417397cabaaSRichard Henderson tlb_mask_table_ofs(TCGContext *s, int which)
418d0a9bb5eSRichard Henderson {
4197857ee11SRichard Henderson return (offsetof(CPUNegativeOffsetState, tlb.f[which]) -
4207857ee11SRichard Henderson sizeof(CPUNegativeOffsetState));
421d0a9bb5eSRichard Henderson }
422d0a9bb5eSRichard Henderson
423db6b7d0cSRichard Henderson /* Signal overflow, starting over with fewer guest insns. */
4248905770bSMarc-André Lureau static G_NORETURN
tcg_raise_tb_overflow(TCGContext * s)4258905770bSMarc-André Lureau void tcg_raise_tb_overflow(TCGContext *s)
426db6b7d0cSRichard Henderson {
427db6b7d0cSRichard Henderson siglongjmp(s->jmp_trans, -2);
428db6b7d0cSRichard Henderson }
429db6b7d0cSRichard Henderson
4308429a1caSRichard Henderson /*
4318429a1caSRichard Henderson * Used by tcg_out_movext{1,2} to hold the arguments for tcg_out_movext.
4328429a1caSRichard Henderson * By the time we arrive at tcg_out_movext1, @dst is always a TCGReg.
4338429a1caSRichard Henderson *
4348429a1caSRichard Henderson * However, tcg_out_helper_load_slots reuses this field to hold an
4358429a1caSRichard Henderson * argument slot number (which may designate a argument register or an
4368429a1caSRichard Henderson * argument stack slot), converting to TCGReg once all arguments that
4378429a1caSRichard Henderson * are destined for the stack are processed.
4388429a1caSRichard Henderson */
439129f1f9eSRichard Henderson typedef struct TCGMovExtend {
4408429a1caSRichard Henderson unsigned dst;
441129f1f9eSRichard Henderson TCGReg src;
442129f1f9eSRichard Henderson TCGType dst_type;
443129f1f9eSRichard Henderson TCGType src_type;
444129f1f9eSRichard Henderson MemOp src_ext;
445129f1f9eSRichard Henderson } TCGMovExtend;
446129f1f9eSRichard Henderson
447b3dfd5fcSRichard Henderson /**
448b3dfd5fcSRichard Henderson * tcg_out_movext -- move and extend
449b3dfd5fcSRichard Henderson * @s: tcg context
450b3dfd5fcSRichard Henderson * @dst_type: integral type for destination
451b3dfd5fcSRichard Henderson * @dst: destination register
452b3dfd5fcSRichard Henderson * @src_type: integral type for source
453b3dfd5fcSRichard Henderson * @src_ext: extension to apply to source
454b3dfd5fcSRichard Henderson * @src: source register
455b3dfd5fcSRichard Henderson *
456b3dfd5fcSRichard Henderson * Move or extend @src into @dst, depending on @src_ext and the types.
457b3dfd5fcSRichard Henderson */
tcg_out_movext(TCGContext * s,TCGType dst_type,TCGReg dst,TCGType src_type,MemOp src_ext,TCGReg src)458129f1f9eSRichard Henderson static void tcg_out_movext(TCGContext *s, TCGType dst_type, TCGReg dst,
459b3dfd5fcSRichard Henderson TCGType src_type, MemOp src_ext, TCGReg src)
460b3dfd5fcSRichard Henderson {
461b3dfd5fcSRichard Henderson switch (src_ext) {
462b3dfd5fcSRichard Henderson case MO_UB:
463b3dfd5fcSRichard Henderson tcg_out_ext8u(s, dst, src);
464b3dfd5fcSRichard Henderson break;
465b3dfd5fcSRichard Henderson case MO_SB:
466b3dfd5fcSRichard Henderson tcg_out_ext8s(s, dst_type, dst, src);
467b3dfd5fcSRichard Henderson break;
468b3dfd5fcSRichard Henderson case MO_UW:
469b3dfd5fcSRichard Henderson tcg_out_ext16u(s, dst, src);
470b3dfd5fcSRichard Henderson break;
471b3dfd5fcSRichard Henderson case MO_SW:
472b3dfd5fcSRichard Henderson tcg_out_ext16s(s, dst_type, dst, src);
473b3dfd5fcSRichard Henderson break;
474b3dfd5fcSRichard Henderson case MO_UL:
475b3dfd5fcSRichard Henderson case MO_SL:
476b3dfd5fcSRichard Henderson if (dst_type == TCG_TYPE_I32) {
477b3dfd5fcSRichard Henderson if (src_type == TCG_TYPE_I32) {
478b3dfd5fcSRichard Henderson tcg_out_mov(s, TCG_TYPE_I32, dst, src);
479b3dfd5fcSRichard Henderson } else {
480b3dfd5fcSRichard Henderson tcg_out_extrl_i64_i32(s, dst, src);
481b3dfd5fcSRichard Henderson }
482b3dfd5fcSRichard Henderson } else if (src_type == TCG_TYPE_I32) {
483b3dfd5fcSRichard Henderson if (src_ext & MO_SIGN) {
484b3dfd5fcSRichard Henderson tcg_out_exts_i32_i64(s, dst, src);
485b3dfd5fcSRichard Henderson } else {
486b3dfd5fcSRichard Henderson tcg_out_extu_i32_i64(s, dst, src);
487b3dfd5fcSRichard Henderson }
488b3dfd5fcSRichard Henderson } else {
489b3dfd5fcSRichard Henderson if (src_ext & MO_SIGN) {
490b3dfd5fcSRichard Henderson tcg_out_ext32s(s, dst, src);
491b3dfd5fcSRichard Henderson } else {
492b3dfd5fcSRichard Henderson tcg_out_ext32u(s, dst, src);
493b3dfd5fcSRichard Henderson }
494b3dfd5fcSRichard Henderson }
495b3dfd5fcSRichard Henderson break;
496b3dfd5fcSRichard Henderson case MO_UQ:
497b3dfd5fcSRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 64);
498b3dfd5fcSRichard Henderson if (dst_type == TCG_TYPE_I32) {
499b3dfd5fcSRichard Henderson tcg_out_extrl_i64_i32(s, dst, src);
500b3dfd5fcSRichard Henderson } else {
501b3dfd5fcSRichard Henderson tcg_out_mov(s, TCG_TYPE_I64, dst, src);
502b3dfd5fcSRichard Henderson }
503b3dfd5fcSRichard Henderson break;
504b3dfd5fcSRichard Henderson default:
505b3dfd5fcSRichard Henderson g_assert_not_reached();
506b3dfd5fcSRichard Henderson }
507b3dfd5fcSRichard Henderson }
508b3dfd5fcSRichard Henderson
509129f1f9eSRichard Henderson /* Minor variations on a theme, using a structure. */
tcg_out_movext1_new_src(TCGContext * s,const TCGMovExtend * i,TCGReg src)510129f1f9eSRichard Henderson static void tcg_out_movext1_new_src(TCGContext *s, const TCGMovExtend *i,
511129f1f9eSRichard Henderson TCGReg src)
512129f1f9eSRichard Henderson {
513129f1f9eSRichard Henderson tcg_out_movext(s, i->dst_type, i->dst, i->src_type, i->src_ext, src);
514129f1f9eSRichard Henderson }
515129f1f9eSRichard Henderson
tcg_out_movext1(TCGContext * s,const TCGMovExtend * i)516129f1f9eSRichard Henderson static void tcg_out_movext1(TCGContext *s, const TCGMovExtend *i)
517129f1f9eSRichard Henderson {
518129f1f9eSRichard Henderson tcg_out_movext1_new_src(s, i, i->src);
519129f1f9eSRichard Henderson }
520129f1f9eSRichard Henderson
521129f1f9eSRichard Henderson /**
522129f1f9eSRichard Henderson * tcg_out_movext2 -- move and extend two pair
523129f1f9eSRichard Henderson * @s: tcg context
524129f1f9eSRichard Henderson * @i1: first move description
525129f1f9eSRichard Henderson * @i2: second move description
526129f1f9eSRichard Henderson * @scratch: temporary register, or -1 for none
527129f1f9eSRichard Henderson *
528129f1f9eSRichard Henderson * As tcg_out_movext, for both @i1 and @i2, caring for overlap
529129f1f9eSRichard Henderson * between the sources and destinations.
530129f1f9eSRichard Henderson */
531129f1f9eSRichard Henderson
tcg_out_movext2(TCGContext * s,const TCGMovExtend * i1,const TCGMovExtend * i2,int scratch)5328429a1caSRichard Henderson static void tcg_out_movext2(TCGContext *s, const TCGMovExtend *i1,
533129f1f9eSRichard Henderson const TCGMovExtend *i2, int scratch)
534129f1f9eSRichard Henderson {
535129f1f9eSRichard Henderson TCGReg src1 = i1->src;
536129f1f9eSRichard Henderson TCGReg src2 = i2->src;
537129f1f9eSRichard Henderson
538129f1f9eSRichard Henderson if (i1->dst != src2) {
539129f1f9eSRichard Henderson tcg_out_movext1(s, i1);
540129f1f9eSRichard Henderson tcg_out_movext1(s, i2);
541129f1f9eSRichard Henderson return;
542129f1f9eSRichard Henderson }
543129f1f9eSRichard Henderson if (i2->dst == src1) {
544129f1f9eSRichard Henderson TCGType src1_type = i1->src_type;
545129f1f9eSRichard Henderson TCGType src2_type = i2->src_type;
546129f1f9eSRichard Henderson
547129f1f9eSRichard Henderson if (tcg_out_xchg(s, MAX(src1_type, src2_type), src1, src2)) {
548129f1f9eSRichard Henderson /* The data is now in the correct registers, now extend. */
549129f1f9eSRichard Henderson src1 = i2->src;
550129f1f9eSRichard Henderson src2 = i1->src;
551129f1f9eSRichard Henderson } else {
552129f1f9eSRichard Henderson tcg_debug_assert(scratch >= 0);
553129f1f9eSRichard Henderson tcg_out_mov(s, src1_type, scratch, src1);
554129f1f9eSRichard Henderson src1 = scratch;
555129f1f9eSRichard Henderson }
556129f1f9eSRichard Henderson }
557129f1f9eSRichard Henderson tcg_out_movext1_new_src(s, i2, src2);
558129f1f9eSRichard Henderson tcg_out_movext1_new_src(s, i1, src1);
559129f1f9eSRichard Henderson }
560129f1f9eSRichard Henderson
5612462e30eSRichard Henderson /**
5622462e30eSRichard Henderson * tcg_out_movext3 -- move and extend three pair
5632462e30eSRichard Henderson * @s: tcg context
5642462e30eSRichard Henderson * @i1: first move description
5652462e30eSRichard Henderson * @i2: second move description
5662462e30eSRichard Henderson * @i3: third move description
5672462e30eSRichard Henderson * @scratch: temporary register, or -1 for none
5682462e30eSRichard Henderson *
5692462e30eSRichard Henderson * As tcg_out_movext, for all of @i1, @i2 and @i3, caring for overlap
5702462e30eSRichard Henderson * between the sources and destinations.
5712462e30eSRichard Henderson */
5722462e30eSRichard Henderson
tcg_out_movext3(TCGContext * s,const TCGMovExtend * i1,const TCGMovExtend * i2,const TCGMovExtend * i3,int scratch)5732462e30eSRichard Henderson static void tcg_out_movext3(TCGContext *s, const TCGMovExtend *i1,
5742462e30eSRichard Henderson const TCGMovExtend *i2, const TCGMovExtend *i3,
5752462e30eSRichard Henderson int scratch)
5762462e30eSRichard Henderson {
5772462e30eSRichard Henderson TCGReg src1 = i1->src;
5782462e30eSRichard Henderson TCGReg src2 = i2->src;
5792462e30eSRichard Henderson TCGReg src3 = i3->src;
5802462e30eSRichard Henderson
5812462e30eSRichard Henderson if (i1->dst != src2 && i1->dst != src3) {
5822462e30eSRichard Henderson tcg_out_movext1(s, i1);
5832462e30eSRichard Henderson tcg_out_movext2(s, i2, i3, scratch);
5842462e30eSRichard Henderson return;
5852462e30eSRichard Henderson }
5862462e30eSRichard Henderson if (i2->dst != src1 && i2->dst != src3) {
5872462e30eSRichard Henderson tcg_out_movext1(s, i2);
5882462e30eSRichard Henderson tcg_out_movext2(s, i1, i3, scratch);
5892462e30eSRichard Henderson return;
5902462e30eSRichard Henderson }
5912462e30eSRichard Henderson if (i3->dst != src1 && i3->dst != src2) {
5922462e30eSRichard Henderson tcg_out_movext1(s, i3);
5932462e30eSRichard Henderson tcg_out_movext2(s, i1, i2, scratch);
5942462e30eSRichard Henderson return;
5952462e30eSRichard Henderson }
5962462e30eSRichard Henderson
5972462e30eSRichard Henderson /*
5982462e30eSRichard Henderson * There is a cycle. Since there are only 3 nodes, the cycle is
5992462e30eSRichard Henderson * either "clockwise" or "anti-clockwise", and can be solved with
6002462e30eSRichard Henderson * a single scratch or two xchg.
6012462e30eSRichard Henderson */
6022462e30eSRichard Henderson if (i1->dst == src2 && i2->dst == src3 && i3->dst == src1) {
6032462e30eSRichard Henderson /* "Clockwise" */
6042462e30eSRichard Henderson if (tcg_out_xchg(s, MAX(i1->src_type, i2->src_type), src1, src2)) {
6052462e30eSRichard Henderson tcg_out_xchg(s, MAX(i2->src_type, i3->src_type), src2, src3);
6062462e30eSRichard Henderson /* The data is now in the correct registers, now extend. */
6072462e30eSRichard Henderson tcg_out_movext1_new_src(s, i1, i1->dst);
6082462e30eSRichard Henderson tcg_out_movext1_new_src(s, i2, i2->dst);
6092462e30eSRichard Henderson tcg_out_movext1_new_src(s, i3, i3->dst);
6102462e30eSRichard Henderson } else {
6112462e30eSRichard Henderson tcg_debug_assert(scratch >= 0);
6122462e30eSRichard Henderson tcg_out_mov(s, i1->src_type, scratch, src1);
6132462e30eSRichard Henderson tcg_out_movext1(s, i3);
6142462e30eSRichard Henderson tcg_out_movext1(s, i2);
6152462e30eSRichard Henderson tcg_out_movext1_new_src(s, i1, scratch);
6162462e30eSRichard Henderson }
6172462e30eSRichard Henderson } else if (i1->dst == src3 && i2->dst == src1 && i3->dst == src2) {
6182462e30eSRichard Henderson /* "Anti-clockwise" */
6192462e30eSRichard Henderson if (tcg_out_xchg(s, MAX(i2->src_type, i3->src_type), src2, src3)) {
6202462e30eSRichard Henderson tcg_out_xchg(s, MAX(i1->src_type, i2->src_type), src1, src2);
6212462e30eSRichard Henderson /* The data is now in the correct registers, now extend. */
6222462e30eSRichard Henderson tcg_out_movext1_new_src(s, i1, i1->dst);
6232462e30eSRichard Henderson tcg_out_movext1_new_src(s, i2, i2->dst);
6242462e30eSRichard Henderson tcg_out_movext1_new_src(s, i3, i3->dst);
6252462e30eSRichard Henderson } else {
6262462e30eSRichard Henderson tcg_debug_assert(scratch >= 0);
6272462e30eSRichard Henderson tcg_out_mov(s, i1->src_type, scratch, src1);
6282462e30eSRichard Henderson tcg_out_movext1(s, i2);
6292462e30eSRichard Henderson tcg_out_movext1(s, i3);
6302462e30eSRichard Henderson tcg_out_movext1_new_src(s, i1, scratch);
6312462e30eSRichard Henderson }
6322462e30eSRichard Henderson } else {
6332462e30eSRichard Henderson g_assert_not_reached();
6342462e30eSRichard Henderson }
6352462e30eSRichard Henderson }
6362462e30eSRichard Henderson
6374c22e840SRichard Henderson #define C_PFX1(P, A) P##A
6384c22e840SRichard Henderson #define C_PFX2(P, A, B) P##A##_##B
6394c22e840SRichard Henderson #define C_PFX3(P, A, B, C) P##A##_##B##_##C
6404c22e840SRichard Henderson #define C_PFX4(P, A, B, C, D) P##A##_##B##_##C##_##D
6414c22e840SRichard Henderson #define C_PFX5(P, A, B, C, D, E) P##A##_##B##_##C##_##D##_##E
6424c22e840SRichard Henderson #define C_PFX6(P, A, B, C, D, E, F) P##A##_##B##_##C##_##D##_##E##_##F
6434c22e840SRichard Henderson
6444c22e840SRichard Henderson /* Define an enumeration for the various combinations. */
6454c22e840SRichard Henderson
6464c22e840SRichard Henderson #define C_O0_I1(I1) C_PFX1(c_o0_i1_, I1),
6474c22e840SRichard Henderson #define C_O0_I2(I1, I2) C_PFX2(c_o0_i2_, I1, I2),
6484c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3) C_PFX3(c_o0_i3_, I1, I2, I3),
6494c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4) C_PFX4(c_o0_i4_, I1, I2, I3, I4),
6504c22e840SRichard Henderson
6514c22e840SRichard Henderson #define C_O1_I1(O1, I1) C_PFX2(c_o1_i1_, O1, I1),
6524c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2) C_PFX3(c_o1_i2_, O1, I1, I2),
6534c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3) C_PFX4(c_o1_i3_, O1, I1, I2, I3),
6544c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4) C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4),
6554c22e840SRichard Henderson
6564c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2) C_PFX3(c_n1_i2_, O1, I1, I2),
657ca5bed07SRichard Henderson #define C_N1O1_I1(O1, O2, I1) C_PFX3(c_n1o1_i1_, O1, O2, I1),
658fa645b48SRichard Henderson #define C_N2_I1(O1, O2, I1) C_PFX3(c_n2_i1_, O1, O2, I1),
6594c22e840SRichard Henderson
6604c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1) C_PFX3(c_o2_i1_, O1, O2, I1),
6614c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2) C_PFX4(c_o2_i2_, O1, O2, I1, I2),
6624c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3) C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3),
6634c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4),
66422d2e535SIlya Leoshkevich #define C_N1_O1_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_n1_o1_i4_, O1, O2, I1, I2, I3, I4),
6654c22e840SRichard Henderson
6664c22e840SRichard Henderson typedef enum {
6674c22e840SRichard Henderson #include "tcg-target-con-set.h"
6684c22e840SRichard Henderson } TCGConstraintSetIndex;
6694c22e840SRichard Henderson
6704c22e840SRichard Henderson static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode);
6714c22e840SRichard Henderson
6724c22e840SRichard Henderson #undef C_O0_I1
6734c22e840SRichard Henderson #undef C_O0_I2
6744c22e840SRichard Henderson #undef C_O0_I3
6754c22e840SRichard Henderson #undef C_O0_I4
6764c22e840SRichard Henderson #undef C_O1_I1
6774c22e840SRichard Henderson #undef C_O1_I2
6784c22e840SRichard Henderson #undef C_O1_I3
6794c22e840SRichard Henderson #undef C_O1_I4
6804c22e840SRichard Henderson #undef C_N1_I2
681ca5bed07SRichard Henderson #undef C_N1O1_I1
682fa645b48SRichard Henderson #undef C_N2_I1
6834c22e840SRichard Henderson #undef C_O2_I1
6844c22e840SRichard Henderson #undef C_O2_I2
6854c22e840SRichard Henderson #undef C_O2_I3
6864c22e840SRichard Henderson #undef C_O2_I4
68722d2e535SIlya Leoshkevich #undef C_N1_O1_I4
6884c22e840SRichard Henderson
6894c22e840SRichard Henderson /* Put all of the constraint sets into an array, indexed by the enum. */
6904c22e840SRichard Henderson
6914c22e840SRichard Henderson #define C_O0_I1(I1) { .args_ct_str = { #I1 } },
6924c22e840SRichard Henderson #define C_O0_I2(I1, I2) { .args_ct_str = { #I1, #I2 } },
6934c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3) { .args_ct_str = { #I1, #I2, #I3 } },
6944c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4) { .args_ct_str = { #I1, #I2, #I3, #I4 } },
6954c22e840SRichard Henderson
6964c22e840SRichard Henderson #define C_O1_I1(O1, I1) { .args_ct_str = { #O1, #I1 } },
6974c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2) { .args_ct_str = { #O1, #I1, #I2 } },
6984c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3) { .args_ct_str = { #O1, #I1, #I2, #I3 } },
6994c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4) { .args_ct_str = { #O1, #I1, #I2, #I3, #I4 } },
7004c22e840SRichard Henderson
7014c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2) { .args_ct_str = { "&" #O1, #I1, #I2 } },
702ca5bed07SRichard Henderson #define C_N1O1_I1(O1, O2, I1) { .args_ct_str = { "&" #O1, #O2, #I1 } },
703fa645b48SRichard Henderson #define C_N2_I1(O1, O2, I1) { .args_ct_str = { "&" #O1, "&" #O2, #I1 } },
7044c22e840SRichard Henderson
7054c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1) { .args_ct_str = { #O1, #O2, #I1 } },
7064c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2) { .args_ct_str = { #O1, #O2, #I1, #I2 } },
7074c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3) { .args_ct_str = { #O1, #O2, #I1, #I2, #I3 } },
7084c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) { .args_ct_str = { #O1, #O2, #I1, #I2, #I3, #I4 } },
70922d2e535SIlya Leoshkevich #define C_N1_O1_I4(O1, O2, I1, I2, I3, I4) { .args_ct_str = { "&" #O1, #O2, #I1, #I2, #I3, #I4 } },
7104c22e840SRichard Henderson
7114c22e840SRichard Henderson static const TCGTargetOpDef constraint_sets[] = {
7124c22e840SRichard Henderson #include "tcg-target-con-set.h"
7134c22e840SRichard Henderson };
7144c22e840SRichard Henderson
7154c22e840SRichard Henderson
7164c22e840SRichard Henderson #undef C_O0_I1
7174c22e840SRichard Henderson #undef C_O0_I2
7184c22e840SRichard Henderson #undef C_O0_I3
7194c22e840SRichard Henderson #undef C_O0_I4
7204c22e840SRichard Henderson #undef C_O1_I1
7214c22e840SRichard Henderson #undef C_O1_I2
7224c22e840SRichard Henderson #undef C_O1_I3
7234c22e840SRichard Henderson #undef C_O1_I4
7244c22e840SRichard Henderson #undef C_N1_I2
725ca5bed07SRichard Henderson #undef C_N1O1_I1
726fa645b48SRichard Henderson #undef C_N2_I1
7274c22e840SRichard Henderson #undef C_O2_I1
7284c22e840SRichard Henderson #undef C_O2_I2
7294c22e840SRichard Henderson #undef C_O2_I3
7304c22e840SRichard Henderson #undef C_O2_I4
73122d2e535SIlya Leoshkevich #undef C_N1_O1_I4
7324c22e840SRichard Henderson
7334c22e840SRichard Henderson /* Expand the enumerator to be returned from tcg_target_op_def(). */
7344c22e840SRichard Henderson
7354c22e840SRichard Henderson #define C_O0_I1(I1) C_PFX1(c_o0_i1_, I1)
7364c22e840SRichard Henderson #define C_O0_I2(I1, I2) C_PFX2(c_o0_i2_, I1, I2)
7374c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3) C_PFX3(c_o0_i3_, I1, I2, I3)
7384c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4) C_PFX4(c_o0_i4_, I1, I2, I3, I4)
7394c22e840SRichard Henderson
7404c22e840SRichard Henderson #define C_O1_I1(O1, I1) C_PFX2(c_o1_i1_, O1, I1)
7414c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2) C_PFX3(c_o1_i2_, O1, I1, I2)
7424c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3) C_PFX4(c_o1_i3_, O1, I1, I2, I3)
7434c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4) C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4)
7444c22e840SRichard Henderson
7454c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2) C_PFX3(c_n1_i2_, O1, I1, I2)
746ca5bed07SRichard Henderson #define C_N1O1_I1(O1, O2, I1) C_PFX3(c_n1o1_i1_, O1, O2, I1)
747fa645b48SRichard Henderson #define C_N2_I1(O1, O2, I1) C_PFX3(c_n2_i1_, O1, O2, I1)
7484c22e840SRichard Henderson
7494c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1) C_PFX3(c_o2_i1_, O1, O2, I1)
7504c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2) C_PFX4(c_o2_i2_, O1, O2, I1, I2)
7514c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3) C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3)
7524c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4)
75322d2e535SIlya Leoshkevich #define C_N1_O1_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_n1_o1_i4_, O1, O2, I1, I2, I3, I4)
7544c22e840SRichard Henderson
755139c1837SPaolo Bonzini #include "tcg-target.c.inc"
756c896fe29Sbellard
7577857ee11SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
7587857ee11SRichard Henderson /* Validate CPUTLBDescFast placement. */
7597857ee11SRichard Henderson QEMU_BUILD_BUG_ON((int)(offsetof(CPUNegativeOffsetState, tlb.f[0]) -
7607857ee11SRichard Henderson sizeof(CPUNegativeOffsetState))
7617857ee11SRichard Henderson < MIN_TLB_MASK_TABLE_OFS);
7627857ee11SRichard Henderson #endif
7637857ee11SRichard Henderson
764e8feb96fSEmilio G. Cota /*
7653468b59eSEmilio G. Cota * All TCG threads except the parent (i.e. the one that called tcg_context_init
7663468b59eSEmilio G. Cota * and registered the target's TCG globals) must register with this function
7673468b59eSEmilio G. Cota * before initiating translation.
7683468b59eSEmilio G. Cota *
7693468b59eSEmilio G. Cota * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation
7703468b59eSEmilio G. Cota * of tcg_region_init() for the reasoning behind this.
7713468b59eSEmilio G. Cota *
7727893e42dSPhilippe Mathieu-Daudé * In system-mode each caller registers its context in tcg_ctxs[]. Note that in
7737893e42dSPhilippe Mathieu-Daudé * system-mode tcg_ctxs[] does not track tcg_ctx_init, since the initial context
7743468b59eSEmilio G. Cota * is not used anymore for translation once this function is called.
7753468b59eSEmilio G. Cota *
7767893e42dSPhilippe Mathieu-Daudé * Not tracking tcg_init_ctx in tcg_ctxs[] in system-mode keeps code that
7777893e42dSPhilippe Mathieu-Daudé * iterates over the array (e.g. tcg_code_size() the same for both system/user
7787893e42dSPhilippe Mathieu-Daudé * modes.
7793468b59eSEmilio G. Cota */
7803468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
tcg_register_thread(void)7813468b59eSEmilio G. Cota void tcg_register_thread(void)
7823468b59eSEmilio G. Cota {
7833468b59eSEmilio G. Cota tcg_ctx = &tcg_init_ctx;
7843468b59eSEmilio G. Cota }
7853468b59eSEmilio G. Cota #else
tcg_register_thread(void)7863468b59eSEmilio G. Cota void tcg_register_thread(void)
7873468b59eSEmilio G. Cota {
7883468b59eSEmilio G. Cota TCGContext *s = g_malloc(sizeof(*s));
7893468b59eSEmilio G. Cota unsigned int i, n;
7903468b59eSEmilio G. Cota
7913468b59eSEmilio G. Cota *s = tcg_init_ctx;
7923468b59eSEmilio G. Cota
7933468b59eSEmilio G. Cota /* Relink mem_base. */
7943468b59eSEmilio G. Cota for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) {
7953468b59eSEmilio G. Cota if (tcg_init_ctx.temps[i].mem_base) {
7963468b59eSEmilio G. Cota ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps;
7973468b59eSEmilio G. Cota tcg_debug_assert(b >= 0 && b < n);
7983468b59eSEmilio G. Cota s->temps[i].mem_base = &s->temps[b];
7993468b59eSEmilio G. Cota }
8003468b59eSEmilio G. Cota }
8013468b59eSEmilio G. Cota
8023468b59eSEmilio G. Cota /* Claim an entry in tcg_ctxs */
8030e2d61cfSRichard Henderson n = qatomic_fetch_inc(&tcg_cur_ctxs);
8040e2d61cfSRichard Henderson g_assert(n < tcg_max_ctxs);
805d73415a3SStefan Hajnoczi qatomic_set(&tcg_ctxs[n], s);
8063468b59eSEmilio G. Cota
80738b47b19SEmilio G. Cota if (n > 0) {
808bf042e8eSRichard Henderson tcg_region_initial_alloc(s);
80938b47b19SEmilio G. Cota }
81038b47b19SEmilio G. Cota
8113468b59eSEmilio G. Cota tcg_ctx = s;
8123468b59eSEmilio G. Cota }
8133468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */
8143468b59eSEmilio G. Cota
815c896fe29Sbellard /* pool based memory allocation */
tcg_malloc_internal(TCGContext * s,int size)816c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size)
817c896fe29Sbellard {
818c896fe29Sbellard TCGPool *p;
819c896fe29Sbellard int pool_size;
820c896fe29Sbellard
821c896fe29Sbellard if (size > TCG_POOL_CHUNK_SIZE) {
822c896fe29Sbellard /* big malloc: insert a new pool (XXX: could optimize) */
8237267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + size);
824c896fe29Sbellard p->size = size;
8254055299eSKirill Batuzov p->next = s->pool_first_large;
8264055299eSKirill Batuzov s->pool_first_large = p;
8274055299eSKirill Batuzov return p->data;
828c896fe29Sbellard } else {
829c896fe29Sbellard p = s->pool_current;
830c896fe29Sbellard if (!p) {
831c896fe29Sbellard p = s->pool_first;
832c896fe29Sbellard if (!p)
833c896fe29Sbellard goto new_pool;
834c896fe29Sbellard } else {
835c896fe29Sbellard if (!p->next) {
836c896fe29Sbellard new_pool:
837c896fe29Sbellard pool_size = TCG_POOL_CHUNK_SIZE;
8387267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + pool_size);
839c896fe29Sbellard p->size = pool_size;
840c896fe29Sbellard p->next = NULL;
841a813e36fSRichard Henderson if (s->pool_current) {
842c896fe29Sbellard s->pool_current->next = p;
843a813e36fSRichard Henderson } else {
844c896fe29Sbellard s->pool_first = p;
845a813e36fSRichard Henderson }
846c896fe29Sbellard } else {
847c896fe29Sbellard p = p->next;
848c896fe29Sbellard }
849c896fe29Sbellard }
850c896fe29Sbellard }
851c896fe29Sbellard s->pool_current = p;
852c896fe29Sbellard s->pool_cur = p->data + size;
853c896fe29Sbellard s->pool_end = p->data + p->size;
854c896fe29Sbellard return p->data;
855c896fe29Sbellard }
856c896fe29Sbellard
tcg_pool_reset(TCGContext * s)857c896fe29Sbellard void tcg_pool_reset(TCGContext *s)
858c896fe29Sbellard {
8594055299eSKirill Batuzov TCGPool *p, *t;
8604055299eSKirill Batuzov for (p = s->pool_first_large; p; p = t) {
8614055299eSKirill Batuzov t = p->next;
8624055299eSKirill Batuzov g_free(p);
8634055299eSKirill Batuzov }
8644055299eSKirill Batuzov s->pool_first_large = NULL;
865c896fe29Sbellard s->pool_cur = s->pool_end = NULL;
866c896fe29Sbellard s->pool_current = NULL;
867c896fe29Sbellard }
868c896fe29Sbellard
8698429a1caSRichard Henderson /*
8708429a1caSRichard Henderson * Create TCGHelperInfo structures for "tcg/tcg-ldst.h" functions,
8718429a1caSRichard Henderson * akin to what "exec/helper-tcg.h" does with DEF_HELPER_FLAGS_N.
8728429a1caSRichard Henderson * We only use these for layout in tcg_out_ld_helper_ret and
8738429a1caSRichard Henderson * tcg_out_st_helper_args, and share them between several of
8748429a1caSRichard Henderson * the helpers, with the end result that it's easier to build manually.
8758429a1caSRichard Henderson */
8768429a1caSRichard Henderson
8778429a1caSRichard Henderson #if TCG_TARGET_REG_BITS == 32
8788429a1caSRichard Henderson # define dh_typecode_ttl dh_typecode_i32
8798429a1caSRichard Henderson #else
8808429a1caSRichard Henderson # define dh_typecode_ttl dh_typecode_i64
8818429a1caSRichard Henderson #endif
8828429a1caSRichard Henderson
8838429a1caSRichard Henderson static TCGHelperInfo info_helper_ld32_mmu = {
8848429a1caSRichard Henderson .flags = TCG_CALL_NO_WG,
8858429a1caSRichard Henderson .typemask = dh_typemask(ttl, 0) /* return tcg_target_ulong */
8868429a1caSRichard Henderson | dh_typemask(env, 1)
88724e46e6cSRichard Henderson | dh_typemask(i64, 2) /* uint64_t addr */
8888429a1caSRichard Henderson | dh_typemask(i32, 3) /* unsigned oi */
8898429a1caSRichard Henderson | dh_typemask(ptr, 4) /* uintptr_t ra */
8908429a1caSRichard Henderson };
8918429a1caSRichard Henderson
8928429a1caSRichard Henderson static TCGHelperInfo info_helper_ld64_mmu = {
8938429a1caSRichard Henderson .flags = TCG_CALL_NO_WG,
8948429a1caSRichard Henderson .typemask = dh_typemask(i64, 0) /* return uint64_t */
8958429a1caSRichard Henderson | dh_typemask(env, 1)
89624e46e6cSRichard Henderson | dh_typemask(i64, 2) /* uint64_t addr */
8978429a1caSRichard Henderson | dh_typemask(i32, 3) /* unsigned oi */
8988429a1caSRichard Henderson | dh_typemask(ptr, 4) /* uintptr_t ra */
8998429a1caSRichard Henderson };
9008429a1caSRichard Henderson
901ebebea53SRichard Henderson static TCGHelperInfo info_helper_ld128_mmu = {
902ebebea53SRichard Henderson .flags = TCG_CALL_NO_WG,
903ebebea53SRichard Henderson .typemask = dh_typemask(i128, 0) /* return Int128 */
904ebebea53SRichard Henderson | dh_typemask(env, 1)
90524e46e6cSRichard Henderson | dh_typemask(i64, 2) /* uint64_t addr */
906ebebea53SRichard Henderson | dh_typemask(i32, 3) /* unsigned oi */
907ebebea53SRichard Henderson | dh_typemask(ptr, 4) /* uintptr_t ra */
908ebebea53SRichard Henderson };
909ebebea53SRichard Henderson
9108429a1caSRichard Henderson static TCGHelperInfo info_helper_st32_mmu = {
9118429a1caSRichard Henderson .flags = TCG_CALL_NO_WG,
9128429a1caSRichard Henderson .typemask = dh_typemask(void, 0)
9138429a1caSRichard Henderson | dh_typemask(env, 1)
91424e46e6cSRichard Henderson | dh_typemask(i64, 2) /* uint64_t addr */
9158429a1caSRichard Henderson | dh_typemask(i32, 3) /* uint32_t data */
9168429a1caSRichard Henderson | dh_typemask(i32, 4) /* unsigned oi */
9178429a1caSRichard Henderson | dh_typemask(ptr, 5) /* uintptr_t ra */
9188429a1caSRichard Henderson };
9198429a1caSRichard Henderson
9208429a1caSRichard Henderson static TCGHelperInfo info_helper_st64_mmu = {
9218429a1caSRichard Henderson .flags = TCG_CALL_NO_WG,
9228429a1caSRichard Henderson .typemask = dh_typemask(void, 0)
9238429a1caSRichard Henderson | dh_typemask(env, 1)
92424e46e6cSRichard Henderson | dh_typemask(i64, 2) /* uint64_t addr */
9258429a1caSRichard Henderson | dh_typemask(i64, 3) /* uint64_t data */
9268429a1caSRichard Henderson | dh_typemask(i32, 4) /* unsigned oi */
9278429a1caSRichard Henderson | dh_typemask(ptr, 5) /* uintptr_t ra */
9288429a1caSRichard Henderson };
9298429a1caSRichard Henderson
930ebebea53SRichard Henderson static TCGHelperInfo info_helper_st128_mmu = {
931ebebea53SRichard Henderson .flags = TCG_CALL_NO_WG,
932ebebea53SRichard Henderson .typemask = dh_typemask(void, 0)
933ebebea53SRichard Henderson | dh_typemask(env, 1)
93424e46e6cSRichard Henderson | dh_typemask(i64, 2) /* uint64_t addr */
935ebebea53SRichard Henderson | dh_typemask(i128, 3) /* Int128 data */
936ebebea53SRichard Henderson | dh_typemask(i32, 4) /* unsigned oi */
937ebebea53SRichard Henderson | dh_typemask(ptr, 5) /* uintptr_t ra */
938ebebea53SRichard Henderson };
939ebebea53SRichard Henderson
94022f15579SRichard Henderson #ifdef CONFIG_TCG_INTERPRETER
typecode_to_ffi(int argmask)941c6ef8c7bSPhilippe Mathieu-Daudé static ffi_type *typecode_to_ffi(int argmask)
942c6ef8c7bSPhilippe Mathieu-Daudé {
943e9709e17SRichard Henderson /*
944e9709e17SRichard Henderson * libffi does not support __int128_t, so we have forced Int128
945e9709e17SRichard Henderson * to use the structure definition instead of the builtin type.
946e9709e17SRichard Henderson */
947e9709e17SRichard Henderson static ffi_type *ffi_type_i128_elements[3] = {
948e9709e17SRichard Henderson &ffi_type_uint64,
949e9709e17SRichard Henderson &ffi_type_uint64,
950e9709e17SRichard Henderson NULL
951e9709e17SRichard Henderson };
952e9709e17SRichard Henderson static ffi_type ffi_type_i128 = {
953e9709e17SRichard Henderson .size = 16,
954e9709e17SRichard Henderson .alignment = __alignof__(Int128),
955e9709e17SRichard Henderson .type = FFI_TYPE_STRUCT,
956e9709e17SRichard Henderson .elements = ffi_type_i128_elements,
957e9709e17SRichard Henderson };
958e9709e17SRichard Henderson
959c6ef8c7bSPhilippe Mathieu-Daudé switch (argmask) {
960c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_void:
961c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_void;
962c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_i32:
963c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_uint32;
964c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_s32:
965c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_sint32;
966c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_i64:
967c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_uint64;
968c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_s64:
969c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_sint64;
970c6ef8c7bSPhilippe Mathieu-Daudé case dh_typecode_ptr:
971c6ef8c7bSPhilippe Mathieu-Daudé return &ffi_type_pointer;
972e9709e17SRichard Henderson case dh_typecode_i128:
973e9709e17SRichard Henderson return &ffi_type_i128;
974c6ef8c7bSPhilippe Mathieu-Daudé }
975c6ef8c7bSPhilippe Mathieu-Daudé g_assert_not_reached();
976c6ef8c7bSPhilippe Mathieu-Daudé }
9770c22e176SPhilippe Mathieu-Daudé
init_ffi_layout(TCGHelperInfo * info)978d53106c9SRichard Henderson static ffi_cif *init_ffi_layout(TCGHelperInfo *info)
9790c22e176SPhilippe Mathieu-Daudé {
980f9c4bb80SRichard Henderson unsigned typemask = info->typemask;
9810c22e176SPhilippe Mathieu-Daudé struct {
9820c22e176SPhilippe Mathieu-Daudé ffi_cif cif;
9830c22e176SPhilippe Mathieu-Daudé ffi_type *args[];
9840c22e176SPhilippe Mathieu-Daudé } *ca;
9850c22e176SPhilippe Mathieu-Daudé ffi_status status;
9860c22e176SPhilippe Mathieu-Daudé int nargs;
9870c22e176SPhilippe Mathieu-Daudé
9880c22e176SPhilippe Mathieu-Daudé /* Ignoring the return type, find the last non-zero field. */
9890c22e176SPhilippe Mathieu-Daudé nargs = 32 - clz32(typemask >> 3);
9900c22e176SPhilippe Mathieu-Daudé nargs = DIV_ROUND_UP(nargs, 3);
991e9709e17SRichard Henderson assert(nargs <= MAX_CALL_IARGS);
9920c22e176SPhilippe Mathieu-Daudé
9930c22e176SPhilippe Mathieu-Daudé ca = g_malloc0(sizeof(*ca) + nargs * sizeof(ffi_type *));
9940c22e176SPhilippe Mathieu-Daudé ca->cif.rtype = typecode_to_ffi(typemask & 7);
9950c22e176SPhilippe Mathieu-Daudé ca->cif.nargs = nargs;
9960c22e176SPhilippe Mathieu-Daudé
9970c22e176SPhilippe Mathieu-Daudé if (nargs != 0) {
9980c22e176SPhilippe Mathieu-Daudé ca->cif.arg_types = ca->args;
9990c22e176SPhilippe Mathieu-Daudé for (int j = 0; j < nargs; ++j) {
10000c22e176SPhilippe Mathieu-Daudé int typecode = extract32(typemask, (j + 1) * 3, 3);
10010c22e176SPhilippe Mathieu-Daudé ca->args[j] = typecode_to_ffi(typecode);
10020c22e176SPhilippe Mathieu-Daudé }
10030c22e176SPhilippe Mathieu-Daudé }
10040c22e176SPhilippe Mathieu-Daudé
10050c22e176SPhilippe Mathieu-Daudé status = ffi_prep_cif(&ca->cif, FFI_DEFAULT_ABI, nargs,
10060c22e176SPhilippe Mathieu-Daudé ca->cif.rtype, ca->cif.arg_types);
10070c22e176SPhilippe Mathieu-Daudé assert(status == FFI_OK);
10080c22e176SPhilippe Mathieu-Daudé
1009d53106c9SRichard Henderson return &ca->cif;
10100c22e176SPhilippe Mathieu-Daudé }
1011f9c4bb80SRichard Henderson
1012d53106c9SRichard Henderson #define HELPER_INFO_INIT(I) (&(I)->cif)
1013d53106c9SRichard Henderson #define HELPER_INFO_INIT_VAL(I) init_ffi_layout(I)
1014d53106c9SRichard Henderson #else
1015d53106c9SRichard Henderson #define HELPER_INFO_INIT(I) (&(I)->init)
1016d53106c9SRichard Henderson #define HELPER_INFO_INIT_VAL(I) 1
10170c22e176SPhilippe Mathieu-Daudé #endif /* CONFIG_TCG_INTERPRETER */
101822f15579SRichard Henderson
arg_slot_reg_p(unsigned arg_slot)1019338b61e9SRichard Henderson static inline bool arg_slot_reg_p(unsigned arg_slot)
1020338b61e9SRichard Henderson {
1021338b61e9SRichard Henderson /*
1022338b61e9SRichard Henderson * Split the sizeof away from the comparison to avoid Werror from
1023338b61e9SRichard Henderson * "unsigned < 0 is always false", when iarg_regs is empty.
1024338b61e9SRichard Henderson */
1025338b61e9SRichard Henderson unsigned nreg = ARRAY_SIZE(tcg_target_call_iarg_regs);
1026338b61e9SRichard Henderson return arg_slot < nreg;
1027338b61e9SRichard Henderson }
1028338b61e9SRichard Henderson
arg_slot_stk_ofs(unsigned arg_slot)1029d78e4a4fSRichard Henderson static inline int arg_slot_stk_ofs(unsigned arg_slot)
1030d78e4a4fSRichard Henderson {
1031d78e4a4fSRichard Henderson unsigned max = TCG_STATIC_CALL_ARGS_SIZE / sizeof(tcg_target_long);
1032d78e4a4fSRichard Henderson unsigned stk_slot = arg_slot - ARRAY_SIZE(tcg_target_call_iarg_regs);
1033d78e4a4fSRichard Henderson
1034d78e4a4fSRichard Henderson tcg_debug_assert(stk_slot < max);
1035d78e4a4fSRichard Henderson return TCG_TARGET_CALL_STACK_OFFSET + stk_slot * sizeof(tcg_target_long);
1036d78e4a4fSRichard Henderson }
1037d78e4a4fSRichard Henderson
103839004a71SRichard Henderson typedef struct TCGCumulativeArgs {
103939004a71SRichard Henderson int arg_idx; /* tcg_gen_callN args[] */
104039004a71SRichard Henderson int info_in_idx; /* TCGHelperInfo in[] */
104139004a71SRichard Henderson int arg_slot; /* regs+stack slot */
104239004a71SRichard Henderson int ref_slot; /* stack slots for references */
104339004a71SRichard Henderson } TCGCumulativeArgs;
104439004a71SRichard Henderson
layout_arg_even(TCGCumulativeArgs * cum)104539004a71SRichard Henderson static void layout_arg_even(TCGCumulativeArgs *cum)
104639004a71SRichard Henderson {
104739004a71SRichard Henderson cum->arg_slot += cum->arg_slot & 1;
104839004a71SRichard Henderson }
104939004a71SRichard Henderson
layout_arg_1(TCGCumulativeArgs * cum,TCGHelperInfo * info,TCGCallArgumentKind kind)105039004a71SRichard Henderson static void layout_arg_1(TCGCumulativeArgs *cum, TCGHelperInfo *info,
105139004a71SRichard Henderson TCGCallArgumentKind kind)
105239004a71SRichard Henderson {
105339004a71SRichard Henderson TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx];
105439004a71SRichard Henderson
105539004a71SRichard Henderson *loc = (TCGCallArgumentLoc){
105639004a71SRichard Henderson .kind = kind,
105739004a71SRichard Henderson .arg_idx = cum->arg_idx,
105839004a71SRichard Henderson .arg_slot = cum->arg_slot,
105939004a71SRichard Henderson };
106039004a71SRichard Henderson cum->info_in_idx++;
106139004a71SRichard Henderson cum->arg_slot++;
106239004a71SRichard Henderson }
106339004a71SRichard Henderson
layout_arg_normal_n(TCGCumulativeArgs * cum,TCGHelperInfo * info,int n)106439004a71SRichard Henderson static void layout_arg_normal_n(TCGCumulativeArgs *cum,
106539004a71SRichard Henderson TCGHelperInfo *info, int n)
106639004a71SRichard Henderson {
106739004a71SRichard Henderson TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx];
106839004a71SRichard Henderson
106939004a71SRichard Henderson for (int i = 0; i < n; ++i) {
107039004a71SRichard Henderson /* Layout all using the same arg_idx, adjusting the subindex. */
107139004a71SRichard Henderson loc[i] = (TCGCallArgumentLoc){
107239004a71SRichard Henderson .kind = TCG_CALL_ARG_NORMAL,
107339004a71SRichard Henderson .arg_idx = cum->arg_idx,
107439004a71SRichard Henderson .tmp_subindex = i,
107539004a71SRichard Henderson .arg_slot = cum->arg_slot + i,
107639004a71SRichard Henderson };
107739004a71SRichard Henderson }
107839004a71SRichard Henderson cum->info_in_idx += n;
107939004a71SRichard Henderson cum->arg_slot += n;
108039004a71SRichard Henderson }
108139004a71SRichard Henderson
layout_arg_by_ref(TCGCumulativeArgs * cum,TCGHelperInfo * info)1082313bdea8SRichard Henderson static void layout_arg_by_ref(TCGCumulativeArgs *cum, TCGHelperInfo *info)
1083313bdea8SRichard Henderson {
1084313bdea8SRichard Henderson TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx];
1085313bdea8SRichard Henderson int n = 128 / TCG_TARGET_REG_BITS;
1086313bdea8SRichard Henderson
1087313bdea8SRichard Henderson /* The first subindex carries the pointer. */
1088313bdea8SRichard Henderson layout_arg_1(cum, info, TCG_CALL_ARG_BY_REF);
1089313bdea8SRichard Henderson
1090313bdea8SRichard Henderson /*
1091313bdea8SRichard Henderson * The callee is allowed to clobber memory associated with
1092313bdea8SRichard Henderson * structure pass by-reference. Therefore we must make copies.
1093313bdea8SRichard Henderson * Allocate space from "ref_slot", which will be adjusted to
1094313bdea8SRichard Henderson * follow the parameters on the stack.
1095313bdea8SRichard Henderson */
1096313bdea8SRichard Henderson loc[0].ref_slot = cum->ref_slot;
1097313bdea8SRichard Henderson
1098313bdea8SRichard Henderson /*
1099313bdea8SRichard Henderson * Subsequent words also go into the reference slot, but
1100313bdea8SRichard Henderson * do not accumulate into the regular arguments.
1101313bdea8SRichard Henderson */
1102313bdea8SRichard Henderson for (int i = 1; i < n; ++i) {
1103313bdea8SRichard Henderson loc[i] = (TCGCallArgumentLoc){
1104313bdea8SRichard Henderson .kind = TCG_CALL_ARG_BY_REF_N,
1105313bdea8SRichard Henderson .arg_idx = cum->arg_idx,
1106313bdea8SRichard Henderson .tmp_subindex = i,
1107313bdea8SRichard Henderson .ref_slot = cum->ref_slot + i,
1108313bdea8SRichard Henderson };
1109313bdea8SRichard Henderson }
1110e18ed26cSRichard Henderson cum->info_in_idx += n - 1; /* i=0 accounted for in layout_arg_1 */
1111313bdea8SRichard Henderson cum->ref_slot += n;
1112313bdea8SRichard Henderson }
1113313bdea8SRichard Henderson
init_call_layout(TCGHelperInfo * info)111439004a71SRichard Henderson static void init_call_layout(TCGHelperInfo *info)
111539004a71SRichard Henderson {
111639004a71SRichard Henderson int max_reg_slots = ARRAY_SIZE(tcg_target_call_iarg_regs);
111739004a71SRichard Henderson int max_stk_slots = TCG_STATIC_CALL_ARGS_SIZE / sizeof(tcg_target_long);
111839004a71SRichard Henderson unsigned typemask = info->typemask;
111939004a71SRichard Henderson unsigned typecode;
112039004a71SRichard Henderson TCGCumulativeArgs cum = { };
112139004a71SRichard Henderson
112239004a71SRichard Henderson /*
112339004a71SRichard Henderson * Parse and place any function return value.
112439004a71SRichard Henderson */
112539004a71SRichard Henderson typecode = typemask & 7;
112639004a71SRichard Henderson switch (typecode) {
112739004a71SRichard Henderson case dh_typecode_void:
112839004a71SRichard Henderson info->nr_out = 0;
112939004a71SRichard Henderson break;
113039004a71SRichard Henderson case dh_typecode_i32:
113139004a71SRichard Henderson case dh_typecode_s32:
113239004a71SRichard Henderson case dh_typecode_ptr:
113339004a71SRichard Henderson info->nr_out = 1;
113439004a71SRichard Henderson info->out_kind = TCG_CALL_RET_NORMAL;
113539004a71SRichard Henderson break;
113639004a71SRichard Henderson case dh_typecode_i64:
113739004a71SRichard Henderson case dh_typecode_s64:
113839004a71SRichard Henderson info->nr_out = 64 / TCG_TARGET_REG_BITS;
113939004a71SRichard Henderson info->out_kind = TCG_CALL_RET_NORMAL;
11405e3d0c19SRichard Henderson /* Query the last register now to trigger any assert early. */
11415e3d0c19SRichard Henderson tcg_target_call_oarg_reg(info->out_kind, info->nr_out - 1);
1142466d3759SRichard Henderson break;
1143466d3759SRichard Henderson case dh_typecode_i128:
1144466d3759SRichard Henderson info->nr_out = 128 / TCG_TARGET_REG_BITS;
11455427a9a7SRichard Henderson info->out_kind = TCG_TARGET_CALL_RET_I128;
11465427a9a7SRichard Henderson switch (TCG_TARGET_CALL_RET_I128) {
1147466d3759SRichard Henderson case TCG_CALL_RET_NORMAL:
11485e3d0c19SRichard Henderson /* Query the last register now to trigger any assert early. */
11495e3d0c19SRichard Henderson tcg_target_call_oarg_reg(info->out_kind, info->nr_out - 1);
1150466d3759SRichard Henderson break;
1151c6556aa0SRichard Henderson case TCG_CALL_RET_BY_VEC:
1152c6556aa0SRichard Henderson /* Query the single register now to trigger any assert early. */
1153c6556aa0SRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0);
1154c6556aa0SRichard Henderson break;
1155313bdea8SRichard Henderson case TCG_CALL_RET_BY_REF:
1156313bdea8SRichard Henderson /*
1157313bdea8SRichard Henderson * Allocate the first argument to the output.
1158313bdea8SRichard Henderson * We don't need to store this anywhere, just make it
1159313bdea8SRichard Henderson * unavailable for use in the input loop below.
1160313bdea8SRichard Henderson */
1161313bdea8SRichard Henderson cum.arg_slot = 1;
1162313bdea8SRichard Henderson break;
1163466d3759SRichard Henderson default:
1164466d3759SRichard Henderson qemu_build_not_reached();
1165466d3759SRichard Henderson }
116639004a71SRichard Henderson break;
116739004a71SRichard Henderson default:
116839004a71SRichard Henderson g_assert_not_reached();
116939004a71SRichard Henderson }
117039004a71SRichard Henderson
117139004a71SRichard Henderson /*
117239004a71SRichard Henderson * Parse and place function arguments.
117339004a71SRichard Henderson */
117439004a71SRichard Henderson for (typemask >>= 3; typemask; typemask >>= 3, cum.arg_idx++) {
117539004a71SRichard Henderson TCGCallArgumentKind kind;
117639004a71SRichard Henderson TCGType type;
117739004a71SRichard Henderson
117839004a71SRichard Henderson typecode = typemask & 7;
117939004a71SRichard Henderson switch (typecode) {
118039004a71SRichard Henderson case dh_typecode_i32:
118139004a71SRichard Henderson case dh_typecode_s32:
118239004a71SRichard Henderson type = TCG_TYPE_I32;
118339004a71SRichard Henderson break;
118439004a71SRichard Henderson case dh_typecode_i64:
118539004a71SRichard Henderson case dh_typecode_s64:
118639004a71SRichard Henderson type = TCG_TYPE_I64;
118739004a71SRichard Henderson break;
118839004a71SRichard Henderson case dh_typecode_ptr:
118939004a71SRichard Henderson type = TCG_TYPE_PTR;
119039004a71SRichard Henderson break;
1191466d3759SRichard Henderson case dh_typecode_i128:
1192466d3759SRichard Henderson type = TCG_TYPE_I128;
1193466d3759SRichard Henderson break;
119439004a71SRichard Henderson default:
119539004a71SRichard Henderson g_assert_not_reached();
119639004a71SRichard Henderson }
119739004a71SRichard Henderson
119839004a71SRichard Henderson switch (type) {
119939004a71SRichard Henderson case TCG_TYPE_I32:
120039004a71SRichard Henderson switch (TCG_TARGET_CALL_ARG_I32) {
120139004a71SRichard Henderson case TCG_CALL_ARG_EVEN:
120239004a71SRichard Henderson layout_arg_even(&cum);
120339004a71SRichard Henderson /* fall through */
120439004a71SRichard Henderson case TCG_CALL_ARG_NORMAL:
120539004a71SRichard Henderson layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL);
120639004a71SRichard Henderson break;
120739004a71SRichard Henderson case TCG_CALL_ARG_EXTEND:
120839004a71SRichard Henderson kind = TCG_CALL_ARG_EXTEND_U + (typecode & 1);
120939004a71SRichard Henderson layout_arg_1(&cum, info, kind);
121039004a71SRichard Henderson break;
121139004a71SRichard Henderson default:
121239004a71SRichard Henderson qemu_build_not_reached();
121339004a71SRichard Henderson }
121439004a71SRichard Henderson break;
121539004a71SRichard Henderson
121639004a71SRichard Henderson case TCG_TYPE_I64:
121739004a71SRichard Henderson switch (TCG_TARGET_CALL_ARG_I64) {
121839004a71SRichard Henderson case TCG_CALL_ARG_EVEN:
121939004a71SRichard Henderson layout_arg_even(&cum);
122039004a71SRichard Henderson /* fall through */
122139004a71SRichard Henderson case TCG_CALL_ARG_NORMAL:
122239004a71SRichard Henderson if (TCG_TARGET_REG_BITS == 32) {
122339004a71SRichard Henderson layout_arg_normal_n(&cum, info, 2);
122439004a71SRichard Henderson } else {
122539004a71SRichard Henderson layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL);
122639004a71SRichard Henderson }
122739004a71SRichard Henderson break;
122839004a71SRichard Henderson default:
122939004a71SRichard Henderson qemu_build_not_reached();
123039004a71SRichard Henderson }
123139004a71SRichard Henderson break;
123239004a71SRichard Henderson
1233466d3759SRichard Henderson case TCG_TYPE_I128:
12345427a9a7SRichard Henderson switch (TCG_TARGET_CALL_ARG_I128) {
1235466d3759SRichard Henderson case TCG_CALL_ARG_EVEN:
1236466d3759SRichard Henderson layout_arg_even(&cum);
1237466d3759SRichard Henderson /* fall through */
1238466d3759SRichard Henderson case TCG_CALL_ARG_NORMAL:
1239466d3759SRichard Henderson layout_arg_normal_n(&cum, info, 128 / TCG_TARGET_REG_BITS);
1240466d3759SRichard Henderson break;
1241313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF:
1242313bdea8SRichard Henderson layout_arg_by_ref(&cum, info);
1243313bdea8SRichard Henderson break;
1244466d3759SRichard Henderson default:
1245466d3759SRichard Henderson qemu_build_not_reached();
1246466d3759SRichard Henderson }
1247466d3759SRichard Henderson break;
1248466d3759SRichard Henderson
124939004a71SRichard Henderson default:
125039004a71SRichard Henderson g_assert_not_reached();
125139004a71SRichard Henderson }
125239004a71SRichard Henderson }
125339004a71SRichard Henderson info->nr_in = cum.info_in_idx;
125439004a71SRichard Henderson
125539004a71SRichard Henderson /* Validate that we didn't overrun the input array. */
125639004a71SRichard Henderson assert(cum.info_in_idx <= ARRAY_SIZE(info->in));
125739004a71SRichard Henderson /* Validate the backend has enough argument space. */
125839004a71SRichard Henderson assert(cum.arg_slot <= max_reg_slots + max_stk_slots);
1259313bdea8SRichard Henderson
1260313bdea8SRichard Henderson /*
1261313bdea8SRichard Henderson * Relocate the "ref_slot" area to the end of the parameters.
1262313bdea8SRichard Henderson * Minimizing this stack offset helps code size for x86,
1263313bdea8SRichard Henderson * which has a signed 8-bit offset encoding.
1264313bdea8SRichard Henderson */
1265313bdea8SRichard Henderson if (cum.ref_slot != 0) {
1266313bdea8SRichard Henderson int ref_base = 0;
1267313bdea8SRichard Henderson
1268313bdea8SRichard Henderson if (cum.arg_slot > max_reg_slots) {
1269313bdea8SRichard Henderson int align = __alignof(Int128) / sizeof(tcg_target_long);
1270313bdea8SRichard Henderson
1271313bdea8SRichard Henderson ref_base = cum.arg_slot - max_reg_slots;
1272313bdea8SRichard Henderson if (align > 1) {
1273313bdea8SRichard Henderson ref_base = ROUND_UP(ref_base, align);
1274313bdea8SRichard Henderson }
1275313bdea8SRichard Henderson }
1276313bdea8SRichard Henderson assert(ref_base + cum.ref_slot <= max_stk_slots);
1277d78e4a4fSRichard Henderson ref_base += max_reg_slots;
1278313bdea8SRichard Henderson
1279313bdea8SRichard Henderson if (ref_base != 0) {
1280313bdea8SRichard Henderson for (int i = cum.info_in_idx - 1; i >= 0; --i) {
1281313bdea8SRichard Henderson TCGCallArgumentLoc *loc = &info->in[i];
1282313bdea8SRichard Henderson switch (loc->kind) {
1283313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF:
1284313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF_N:
1285313bdea8SRichard Henderson loc->ref_slot += ref_base;
1286313bdea8SRichard Henderson break;
1287313bdea8SRichard Henderson default:
1288313bdea8SRichard Henderson break;
1289313bdea8SRichard Henderson }
1290313bdea8SRichard Henderson }
1291313bdea8SRichard Henderson }
1292313bdea8SRichard Henderson }
129339004a71SRichard Henderson }
129439004a71SRichard Henderson
129591478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)];
1296f69d277eSRichard Henderson static void process_op_defs(TCGContext *s);
12971c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
12981c2adb95SRichard Henderson TCGReg reg, const char *name);
129991478cefSRichard Henderson
tcg_context_init(unsigned max_cpus)130043b972b7SRichard Henderson static void tcg_context_init(unsigned max_cpus)
1301c896fe29Sbellard {
1302a76aabd3SRichard Henderson TCGContext *s = &tcg_init_ctx;
1303100b5e01SRichard Henderson int op, total_args, n, i;
1304c896fe29Sbellard TCGOpDef *def;
1305c896fe29Sbellard TCGArgConstraint *args_ct;
13061c2adb95SRichard Henderson TCGTemp *ts;
1307c896fe29Sbellard
1308c896fe29Sbellard memset(s, 0, sizeof(*s));
1309c896fe29Sbellard s->nb_globals = 0;
1310c896fe29Sbellard
1311c896fe29Sbellard /* Count total number of arguments and allocate the corresponding
1312c896fe29Sbellard space */
1313c896fe29Sbellard total_args = 0;
1314c896fe29Sbellard for(op = 0; op < NB_OPS; op++) {
1315c896fe29Sbellard def = &tcg_op_defs[op];
1316c896fe29Sbellard n = def->nb_iargs + def->nb_oargs;
1317c896fe29Sbellard total_args += n;
1318c896fe29Sbellard }
1319c896fe29Sbellard
1320bc2b17e6SRichard Henderson args_ct = g_new0(TCGArgConstraint, total_args);
1321c896fe29Sbellard
1322c896fe29Sbellard for(op = 0; op < NB_OPS; op++) {
1323c896fe29Sbellard def = &tcg_op_defs[op];
1324c896fe29Sbellard def->args_ct = args_ct;
1325c896fe29Sbellard n = def->nb_iargs + def->nb_oargs;
1326c896fe29Sbellard args_ct += n;
1327c896fe29Sbellard }
1328c896fe29Sbellard
13298429a1caSRichard Henderson init_call_layout(&info_helper_ld32_mmu);
13308429a1caSRichard Henderson init_call_layout(&info_helper_ld64_mmu);
1331ebebea53SRichard Henderson init_call_layout(&info_helper_ld128_mmu);
13328429a1caSRichard Henderson init_call_layout(&info_helper_st32_mmu);
13338429a1caSRichard Henderson init_call_layout(&info_helper_st64_mmu);
1334ebebea53SRichard Henderson init_call_layout(&info_helper_st128_mmu);
13358429a1caSRichard Henderson
1336c896fe29Sbellard tcg_target_init(s);
1337f69d277eSRichard Henderson process_op_defs(s);
133891478cefSRichard Henderson
133991478cefSRichard Henderson /* Reverse the order of the saved registers, assuming they're all at
134091478cefSRichard Henderson the start of tcg_target_reg_alloc_order. */
134191478cefSRichard Henderson for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) {
134291478cefSRichard Henderson int r = tcg_target_reg_alloc_order[n];
134391478cefSRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) {
134491478cefSRichard Henderson break;
134591478cefSRichard Henderson }
134691478cefSRichard Henderson }
134791478cefSRichard Henderson for (i = 0; i < n; ++i) {
134891478cefSRichard Henderson indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i];
134991478cefSRichard Henderson }
135091478cefSRichard Henderson for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) {
135191478cefSRichard Henderson indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i];
135291478cefSRichard Henderson }
1353b1311c4aSEmilio G. Cota
1354b1311c4aSEmilio G. Cota tcg_ctx = s;
13553468b59eSEmilio G. Cota /*
13563468b59eSEmilio G. Cota * In user-mode we simply share the init context among threads, since we
13573468b59eSEmilio G. Cota * use a single region. See the documentation tcg_region_init() for the
13583468b59eSEmilio G. Cota * reasoning behind this.
13597893e42dSPhilippe Mathieu-Daudé * In system-mode we will have at most max_cpus TCG threads.
13603468b59eSEmilio G. Cota */
13613468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
1362df2cce29SEmilio G. Cota tcg_ctxs = &tcg_ctx;
13630e2d61cfSRichard Henderson tcg_cur_ctxs = 1;
13640e2d61cfSRichard Henderson tcg_max_ctxs = 1;
13653468b59eSEmilio G. Cota #else
13660e2d61cfSRichard Henderson tcg_max_ctxs = max_cpus;
13670e2d61cfSRichard Henderson tcg_ctxs = g_new0(TCGContext *, max_cpus);
13683468b59eSEmilio G. Cota #endif
13691c2adb95SRichard Henderson
13701c2adb95SRichard Henderson tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0));
13711c2adb95SRichard Henderson ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env");
1372ad75a51eSRichard Henderson tcg_env = temp_tcgv_ptr(ts);
13739002ec79SRichard Henderson }
1374b03cce8eSbellard
tcg_init(size_t tb_size,int splitwx,unsigned max_cpus)137543b972b7SRichard Henderson void tcg_init(size_t tb_size, int splitwx, unsigned max_cpus)
1376a76aabd3SRichard Henderson {
137743b972b7SRichard Henderson tcg_context_init(max_cpus);
137843b972b7SRichard Henderson tcg_region_init(tb_size, splitwx, max_cpus);
1379a76aabd3SRichard Henderson }
1380a76aabd3SRichard Henderson
13816e3b2bfdSEmilio G. Cota /*
13826e3b2bfdSEmilio G. Cota * Allocate TBs right before their corresponding translated code, making
13836e3b2bfdSEmilio G. Cota * sure that TBs and code are on different cache lines.
13846e3b2bfdSEmilio G. Cota */
tcg_tb_alloc(TCGContext * s)13856e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s)
13866e3b2bfdSEmilio G. Cota {
13876e3b2bfdSEmilio G. Cota uintptr_t align = qemu_icache_linesize;
13886e3b2bfdSEmilio G. Cota TranslationBlock *tb;
13896e3b2bfdSEmilio G. Cota void *next;
13906e3b2bfdSEmilio G. Cota
1391e8feb96fSEmilio G. Cota retry:
13926e3b2bfdSEmilio G. Cota tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align);
13936e3b2bfdSEmilio G. Cota next = (void *)ROUND_UP((uintptr_t)(tb + 1), align);
13946e3b2bfdSEmilio G. Cota
13956e3b2bfdSEmilio G. Cota if (unlikely(next > s->code_gen_highwater)) {
1396e8feb96fSEmilio G. Cota if (tcg_region_alloc(s)) {
13976e3b2bfdSEmilio G. Cota return NULL;
13986e3b2bfdSEmilio G. Cota }
1399e8feb96fSEmilio G. Cota goto retry;
1400e8feb96fSEmilio G. Cota }
1401d73415a3SStefan Hajnoczi qatomic_set(&s->code_gen_ptr, next);
14026e3b2bfdSEmilio G. Cota return tb;
14036e3b2bfdSEmilio G. Cota }
14046e3b2bfdSEmilio G. Cota
tcg_prologue_init(void)1405935f75aeSRichard Henderson void tcg_prologue_init(void)
14069002ec79SRichard Henderson {
1407935f75aeSRichard Henderson TCGContext *s = tcg_ctx;
1408b0a0794aSRichard Henderson size_t prologue_size;
14098163b749SRichard Henderson
1410b0a0794aSRichard Henderson s->code_ptr = s->code_gen_ptr;
1411b0a0794aSRichard Henderson s->code_buf = s->code_gen_ptr;
14125b38ee31SRichard Henderson s->data_gen_ptr = NULL;
1413b91ccb31SRichard Henderson
1414b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
1415b0a0794aSRichard Henderson tcg_qemu_tb_exec = (tcg_prologue_fn *)tcg_splitwx_to_rx(s->code_ptr);
1416b91ccb31SRichard Henderson #endif
14178163b749SRichard Henderson
14185b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
14195b38ee31SRichard Henderson s->pool_labels = NULL;
14205b38ee31SRichard Henderson #endif
14215b38ee31SRichard Henderson
1422653b87ebSRoman Bolshakov qemu_thread_jit_write();
14238163b749SRichard Henderson /* Generate the prologue. */
1424b03cce8eSbellard tcg_target_qemu_prologue(s);
14255b38ee31SRichard Henderson
14265b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
14275b38ee31SRichard Henderson /* Allow the prologue to put e.g. guest_base into a pool entry. */
14285b38ee31SRichard Henderson {
14291768987bSRichard Henderson int result = tcg_out_pool_finalize(s);
14301768987bSRichard Henderson tcg_debug_assert(result == 0);
14315b38ee31SRichard Henderson }
14325b38ee31SRichard Henderson #endif
14335b38ee31SRichard Henderson
1434b0a0794aSRichard Henderson prologue_size = tcg_current_code_size(s);
14355584e2dbSIlya Leoshkevich perf_report_prologue(s->code_gen_ptr, prologue_size);
1436b0a0794aSRichard Henderson
1437df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
1438b0a0794aSRichard Henderson flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf),
1439b0a0794aSRichard Henderson (uintptr_t)s->code_buf, prologue_size);
1440df5d2b16SRichard Henderson #endif
14418163b749SRichard Henderson
1442d6b64b2bSRichard Henderson if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) {
1443c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock();
144478b54858SRichard Henderson if (logfile) {
144578b54858SRichard Henderson fprintf(logfile, "PROLOGUE: [size=%zu]\n", prologue_size);
14465b38ee31SRichard Henderson if (s->data_gen_ptr) {
1447b0a0794aSRichard Henderson size_t code_size = s->data_gen_ptr - s->code_gen_ptr;
14485b38ee31SRichard Henderson size_t data_size = prologue_size - code_size;
14495b38ee31SRichard Henderson size_t i;
14505b38ee31SRichard Henderson
145178b54858SRichard Henderson disas(logfile, s->code_gen_ptr, code_size);
14525b38ee31SRichard Henderson
14535b38ee31SRichard Henderson for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) {
14545b38ee31SRichard Henderson if (sizeof(tcg_target_ulong) == 8) {
145578b54858SRichard Henderson fprintf(logfile,
145678b54858SRichard Henderson "0x%08" PRIxPTR ": .quad 0x%016" PRIx64 "\n",
14575b38ee31SRichard Henderson (uintptr_t)s->data_gen_ptr + i,
14585b38ee31SRichard Henderson *(uint64_t *)(s->data_gen_ptr + i));
14595b38ee31SRichard Henderson } else {
146078b54858SRichard Henderson fprintf(logfile,
146178b54858SRichard Henderson "0x%08" PRIxPTR ": .long 0x%08x\n",
14625b38ee31SRichard Henderson (uintptr_t)s->data_gen_ptr + i,
14635b38ee31SRichard Henderson *(uint32_t *)(s->data_gen_ptr + i));
14645b38ee31SRichard Henderson }
14655b38ee31SRichard Henderson }
14665b38ee31SRichard Henderson } else {
146778b54858SRichard Henderson disas(logfile, s->code_gen_ptr, prologue_size);
14685b38ee31SRichard Henderson }
146978b54858SRichard Henderson fprintf(logfile, "\n");
1470fc59d2d8SRobert Foley qemu_log_unlock(logfile);
1471d6b64b2bSRichard Henderson }
147278b54858SRichard Henderson }
1473cedbcb01SEmilio G. Cota
14746eea0434SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
14756eea0434SRichard Henderson /*
14766eea0434SRichard Henderson * Assert that goto_ptr is implemented completely, setting an epilogue.
14776eea0434SRichard Henderson * For tci, we use NULL as the signal to return from the interpreter,
14786eea0434SRichard Henderson * so skip this check.
14796eea0434SRichard Henderson */
14808b5c2b62SRichard Henderson tcg_debug_assert(tcg_code_gen_epilogue != NULL);
14816eea0434SRichard Henderson #endif
1482d1c74ab3SRichard Henderson
1483d1c74ab3SRichard Henderson tcg_region_prologue_set(s);
1484c896fe29Sbellard }
1485c896fe29Sbellard
tcg_func_start(TCGContext * s)1486c896fe29Sbellard void tcg_func_start(TCGContext *s)
1487c896fe29Sbellard {
1488c896fe29Sbellard tcg_pool_reset(s);
1489c896fe29Sbellard s->nb_temps = s->nb_globals;
14900ec9eabcSRichard Henderson
14910ec9eabcSRichard Henderson /* No temps have been previously allocated for size or locality. */
1492*f838a7e3SRichard Henderson tcg_temp_ebb_reset_freed(s);
14930ec9eabcSRichard Henderson
1494c0522136SRichard Henderson /* No constant temps have been previously allocated. */
1495c0522136SRichard Henderson for (int i = 0; i < TCG_TYPE_COUNT; ++i) {
1496c0522136SRichard Henderson if (s->const_table[i]) {
1497c0522136SRichard Henderson g_hash_table_remove_all(s->const_table[i]);
1498c0522136SRichard Henderson }
1499c0522136SRichard Henderson }
1500c0522136SRichard Henderson
1501abebf925SRichard Henderson s->nb_ops = 0;
1502c896fe29Sbellard s->nb_labels = 0;
1503c896fe29Sbellard s->current_frame_offset = s->frame_start;
1504c896fe29Sbellard
15050a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG
15060a209d4bSRichard Henderson s->goto_tb_issue_mask = 0;
15070a209d4bSRichard Henderson #endif
15080a209d4bSRichard Henderson
150915fa08f8SRichard Henderson QTAILQ_INIT(&s->ops);
151015fa08f8SRichard Henderson QTAILQ_INIT(&s->free_ops);
151107843f75SRichard Henderson s->emit_before_op = NULL;
1512bef16ab4SRichard Henderson QSIMPLEQ_INIT(&s->labels);
15134baf3978SRichard Henderson
15144baf3978SRichard Henderson tcg_debug_assert(s->addr_type == TCG_TYPE_I32 ||
15154baf3978SRichard Henderson s->addr_type == TCG_TYPE_I64);
1516d0a9bb5eSRichard Henderson
1517747bd69dSRichard Henderson tcg_debug_assert(s->insn_start_words > 0);
1518c896fe29Sbellard }
1519c896fe29Sbellard
tcg_temp_alloc(TCGContext * s)1520ae30e866SRichard Henderson static TCGTemp *tcg_temp_alloc(TCGContext *s)
15217ca4b752SRichard Henderson {
15227ca4b752SRichard Henderson int n = s->nb_temps++;
1523ae30e866SRichard Henderson
1524ae30e866SRichard Henderson if (n >= TCG_MAX_TEMPS) {
1525db6b7d0cSRichard Henderson tcg_raise_tb_overflow(s);
1526ae30e866SRichard Henderson }
15277ca4b752SRichard Henderson return memset(&s->temps[n], 0, sizeof(TCGTemp));
15287ca4b752SRichard Henderson }
15297ca4b752SRichard Henderson
tcg_global_alloc(TCGContext * s)1530ae30e866SRichard Henderson static TCGTemp *tcg_global_alloc(TCGContext *s)
15317ca4b752SRichard Henderson {
1532fa477d25SRichard Henderson TCGTemp *ts;
1533fa477d25SRichard Henderson
15347ca4b752SRichard Henderson tcg_debug_assert(s->nb_globals == s->nb_temps);
1535ae30e866SRichard Henderson tcg_debug_assert(s->nb_globals < TCG_MAX_TEMPS);
15367ca4b752SRichard Henderson s->nb_globals++;
1537fa477d25SRichard Henderson ts = tcg_temp_alloc(s);
1538ee17db83SRichard Henderson ts->kind = TEMP_GLOBAL;
1539fa477d25SRichard Henderson
1540fa477d25SRichard Henderson return ts;
1541c896fe29Sbellard }
1542c896fe29Sbellard
tcg_global_reg_new_internal(TCGContext * s,TCGType type,TCGReg reg,const char * name)1543085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
1544b6638662SRichard Henderson TCGReg reg, const char *name)
1545c896fe29Sbellard {
1546c896fe29Sbellard TCGTemp *ts;
1547c896fe29Sbellard
15481a057554SRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 64 || type == TCG_TYPE_I32);
15497ca4b752SRichard Henderson
15507ca4b752SRichard Henderson ts = tcg_global_alloc(s);
1551c896fe29Sbellard ts->base_type = type;
1552c896fe29Sbellard ts->type = type;
1553ee17db83SRichard Henderson ts->kind = TEMP_FIXED;
1554c896fe29Sbellard ts->reg = reg;
1555c896fe29Sbellard ts->name = name;
1556c896fe29Sbellard tcg_regset_set_reg(s->reserved_regs, reg);
15577ca4b752SRichard Henderson
1558085272b3SRichard Henderson return ts;
1559a7812ae4Spbrook }
1560a7812ae4Spbrook
tcg_set_frame(TCGContext * s,TCGReg reg,intptr_t start,intptr_t size)1561b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size)
1562a7812ae4Spbrook {
1563b3a62939SRichard Henderson s->frame_start = start;
1564b3a62939SRichard Henderson s->frame_end = start + size;
1565085272b3SRichard Henderson s->frame_temp
1566085272b3SRichard Henderson = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame");
1567b3a62939SRichard Henderson }
1568a7812ae4Spbrook
tcg_global_mem_new_internal(TCGv_ptr base,intptr_t offset,const char * name,TCGType type)15694643f3e0SRichard Henderson static TCGTemp *tcg_global_mem_new_internal(TCGv_ptr base, intptr_t offset,
15704643f3e0SRichard Henderson const char *name, TCGType type)
1571c896fe29Sbellard {
1572b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx;
1573dc41aa7dSRichard Henderson TCGTemp *base_ts = tcgv_ptr_temp(base);
15747ca4b752SRichard Henderson TCGTemp *ts = tcg_global_alloc(s);
1575aef85402SRichard Henderson int indirect_reg = 0;
1576c896fe29Sbellard
1577c0522136SRichard Henderson switch (base_ts->kind) {
1578c0522136SRichard Henderson case TEMP_FIXED:
1579c0522136SRichard Henderson break;
1580c0522136SRichard Henderson case TEMP_GLOBAL:
15815a18407fSRichard Henderson /* We do not support double-indirect registers. */
15825a18407fSRichard Henderson tcg_debug_assert(!base_ts->indirect_reg);
1583b3915dbbSRichard Henderson base_ts->indirect_base = 1;
15845a18407fSRichard Henderson s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64
15855a18407fSRichard Henderson ? 2 : 1);
15865a18407fSRichard Henderson indirect_reg = 1;
1587c0522136SRichard Henderson break;
1588c0522136SRichard Henderson default:
1589c0522136SRichard Henderson g_assert_not_reached();
1590b3915dbbSRichard Henderson }
1591b3915dbbSRichard Henderson
15927ca4b752SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
15937ca4b752SRichard Henderson TCGTemp *ts2 = tcg_global_alloc(s);
1594c896fe29Sbellard char buf[64];
15957ca4b752SRichard Henderson
15967ca4b752SRichard Henderson ts->base_type = TCG_TYPE_I64;
1597c896fe29Sbellard ts->type = TCG_TYPE_I32;
1598b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg;
1599c896fe29Sbellard ts->mem_allocated = 1;
1600b3a62939SRichard Henderson ts->mem_base = base_ts;
1601aef85402SRichard Henderson ts->mem_offset = offset;
1602c896fe29Sbellard pstrcpy(buf, sizeof(buf), name);
1603c896fe29Sbellard pstrcat(buf, sizeof(buf), "_0");
1604c896fe29Sbellard ts->name = strdup(buf);
1605c896fe29Sbellard
16067ca4b752SRichard Henderson tcg_debug_assert(ts2 == ts + 1);
16077ca4b752SRichard Henderson ts2->base_type = TCG_TYPE_I64;
16087ca4b752SRichard Henderson ts2->type = TCG_TYPE_I32;
1609b3915dbbSRichard Henderson ts2->indirect_reg = indirect_reg;
16107ca4b752SRichard Henderson ts2->mem_allocated = 1;
16117ca4b752SRichard Henderson ts2->mem_base = base_ts;
1612aef85402SRichard Henderson ts2->mem_offset = offset + 4;
1613fac87bd2SRichard Henderson ts2->temp_subindex = 1;
1614c896fe29Sbellard pstrcpy(buf, sizeof(buf), name);
1615c896fe29Sbellard pstrcat(buf, sizeof(buf), "_1");
1616120c1084SRichard Henderson ts2->name = strdup(buf);
16177ca4b752SRichard Henderson } else {
1618c896fe29Sbellard ts->base_type = type;
1619c896fe29Sbellard ts->type = type;
1620b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg;
1621c896fe29Sbellard ts->mem_allocated = 1;
1622b3a62939SRichard Henderson ts->mem_base = base_ts;
1623c896fe29Sbellard ts->mem_offset = offset;
1624c896fe29Sbellard ts->name = name;
1625c896fe29Sbellard }
1626085272b3SRichard Henderson return ts;
1627c896fe29Sbellard }
1628c896fe29Sbellard
tcg_global_mem_new_i32(TCGv_ptr reg,intptr_t off,const char * name)16294643f3e0SRichard Henderson TCGv_i32 tcg_global_mem_new_i32(TCGv_ptr reg, intptr_t off, const char *name)
16304643f3e0SRichard Henderson {
16314643f3e0SRichard Henderson TCGTemp *ts = tcg_global_mem_new_internal(reg, off, name, TCG_TYPE_I32);
16324643f3e0SRichard Henderson return temp_tcgv_i32(ts);
16334643f3e0SRichard Henderson }
16344643f3e0SRichard Henderson
tcg_global_mem_new_i64(TCGv_ptr reg,intptr_t off,const char * name)16354643f3e0SRichard Henderson TCGv_i64 tcg_global_mem_new_i64(TCGv_ptr reg, intptr_t off, const char *name)
16364643f3e0SRichard Henderson {
16374643f3e0SRichard Henderson TCGTemp *ts = tcg_global_mem_new_internal(reg, off, name, TCG_TYPE_I64);
16384643f3e0SRichard Henderson return temp_tcgv_i64(ts);
16394643f3e0SRichard Henderson }
16404643f3e0SRichard Henderson
tcg_global_mem_new_ptr(TCGv_ptr reg,intptr_t off,const char * name)16414643f3e0SRichard Henderson TCGv_ptr tcg_global_mem_new_ptr(TCGv_ptr reg, intptr_t off, const char *name)
16424643f3e0SRichard Henderson {
16434643f3e0SRichard Henderson TCGTemp *ts = tcg_global_mem_new_internal(reg, off, name, TCG_TYPE_PTR);
16444643f3e0SRichard Henderson return temp_tcgv_ptr(ts);
16454643f3e0SRichard Henderson }
16464643f3e0SRichard Henderson
tcg_temp_new_internal(TCGType type,TCGTempKind kind)1647fb04ab7dSRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, TCGTempKind kind)
1648c896fe29Sbellard {
1649b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx;
1650c896fe29Sbellard TCGTemp *ts;
1651e1c08b00SRichard Henderson int n;
1652c896fe29Sbellard
1653e1c08b00SRichard Henderson if (kind == TEMP_EBB) {
1654e1c08b00SRichard Henderson int idx = find_first_bit(s->free_temps[type].l, TCG_MAX_TEMPS);
1655e1c08b00SRichard Henderson
16560ec9eabcSRichard Henderson if (idx < TCG_MAX_TEMPS) {
16570ec9eabcSRichard Henderson /* There is already an available temp with the right type. */
1658e1c08b00SRichard Henderson clear_bit(idx, s->free_temps[type].l);
16590ec9eabcSRichard Henderson
1660e8996ee0Sbellard ts = &s->temps[idx];
1661e8996ee0Sbellard ts->temp_allocated = 1;
16627ca4b752SRichard Henderson tcg_debug_assert(ts->base_type == type);
1663ee17db83SRichard Henderson tcg_debug_assert(ts->kind == kind);
16642f2e911dSRichard Henderson return ts;
1665e1c08b00SRichard Henderson }
1666e8996ee0Sbellard } else {
1667e1c08b00SRichard Henderson tcg_debug_assert(kind == TEMP_TB);
1668e1c08b00SRichard Henderson }
166943eef72fSRichard Henderson
167043eef72fSRichard Henderson switch (type) {
167143eef72fSRichard Henderson case TCG_TYPE_I32:
167243eef72fSRichard Henderson case TCG_TYPE_V64:
167343eef72fSRichard Henderson case TCG_TYPE_V128:
167443eef72fSRichard Henderson case TCG_TYPE_V256:
167543eef72fSRichard Henderson n = 1;
167643eef72fSRichard Henderson break;
167743eef72fSRichard Henderson case TCG_TYPE_I64:
167843eef72fSRichard Henderson n = 64 / TCG_TARGET_REG_BITS;
167943eef72fSRichard Henderson break;
168043eef72fSRichard Henderson case TCG_TYPE_I128:
168143eef72fSRichard Henderson n = 128 / TCG_TARGET_REG_BITS;
168243eef72fSRichard Henderson break;
168343eef72fSRichard Henderson default:
168443eef72fSRichard Henderson g_assert_not_reached();
168543eef72fSRichard Henderson }
168643eef72fSRichard Henderson
16877ca4b752SRichard Henderson ts = tcg_temp_alloc(s);
168843eef72fSRichard Henderson ts->base_type = type;
168943eef72fSRichard Henderson ts->temp_allocated = 1;
169043eef72fSRichard Henderson ts->kind = kind;
169143eef72fSRichard Henderson
169243eef72fSRichard Henderson if (n == 1) {
169343eef72fSRichard Henderson ts->type = type;
169443eef72fSRichard Henderson } else {
169543eef72fSRichard Henderson ts->type = TCG_TYPE_REG;
169643eef72fSRichard Henderson
1697e1c08b00SRichard Henderson for (int i = 1; i < n; ++i) {
16987ca4b752SRichard Henderson TCGTemp *ts2 = tcg_temp_alloc(s);
16997ca4b752SRichard Henderson
170043eef72fSRichard Henderson tcg_debug_assert(ts2 == ts + i);
170143eef72fSRichard Henderson ts2->base_type = type;
170243eef72fSRichard Henderson ts2->type = TCG_TYPE_REG;
17037ca4b752SRichard Henderson ts2->temp_allocated = 1;
170443eef72fSRichard Henderson ts2->temp_subindex = i;
1705ee17db83SRichard Henderson ts2->kind = kind;
170643eef72fSRichard Henderson }
1707c896fe29Sbellard }
1708085272b3SRichard Henderson return ts;
1709c896fe29Sbellard }
1710c896fe29Sbellard
tcg_temp_new_i32(void)17114643f3e0SRichard Henderson TCGv_i32 tcg_temp_new_i32(void)
17124643f3e0SRichard Henderson {
17134643f3e0SRichard Henderson return temp_tcgv_i32(tcg_temp_new_internal(TCG_TYPE_I32, TEMP_TB));
17144643f3e0SRichard Henderson }
17154643f3e0SRichard Henderson
tcg_temp_ebb_new_i32(void)17164643f3e0SRichard Henderson TCGv_i32 tcg_temp_ebb_new_i32(void)
17174643f3e0SRichard Henderson {
17184643f3e0SRichard Henderson return temp_tcgv_i32(tcg_temp_new_internal(TCG_TYPE_I32, TEMP_EBB));
17194643f3e0SRichard Henderson }
17204643f3e0SRichard Henderson
tcg_temp_new_i64(void)17214643f3e0SRichard Henderson TCGv_i64 tcg_temp_new_i64(void)
17224643f3e0SRichard Henderson {
17234643f3e0SRichard Henderson return temp_tcgv_i64(tcg_temp_new_internal(TCG_TYPE_I64, TEMP_TB));
17244643f3e0SRichard Henderson }
17254643f3e0SRichard Henderson
tcg_temp_ebb_new_i64(void)17264643f3e0SRichard Henderson TCGv_i64 tcg_temp_ebb_new_i64(void)
17274643f3e0SRichard Henderson {
17284643f3e0SRichard Henderson return temp_tcgv_i64(tcg_temp_new_internal(TCG_TYPE_I64, TEMP_EBB));
17294643f3e0SRichard Henderson }
17304643f3e0SRichard Henderson
tcg_temp_new_ptr(void)17314643f3e0SRichard Henderson TCGv_ptr tcg_temp_new_ptr(void)
17324643f3e0SRichard Henderson {
17334643f3e0SRichard Henderson return temp_tcgv_ptr(tcg_temp_new_internal(TCG_TYPE_PTR, TEMP_TB));
17344643f3e0SRichard Henderson }
17354643f3e0SRichard Henderson
tcg_temp_ebb_new_ptr(void)17364643f3e0SRichard Henderson TCGv_ptr tcg_temp_ebb_new_ptr(void)
17374643f3e0SRichard Henderson {
17384643f3e0SRichard Henderson return temp_tcgv_ptr(tcg_temp_new_internal(TCG_TYPE_PTR, TEMP_EBB));
17394643f3e0SRichard Henderson }
17404643f3e0SRichard Henderson
tcg_temp_new_i128(void)17414643f3e0SRichard Henderson TCGv_i128 tcg_temp_new_i128(void)
17424643f3e0SRichard Henderson {
17434643f3e0SRichard Henderson return temp_tcgv_i128(tcg_temp_new_internal(TCG_TYPE_I128, TEMP_TB));
17444643f3e0SRichard Henderson }
17454643f3e0SRichard Henderson
tcg_temp_ebb_new_i128(void)17464643f3e0SRichard Henderson TCGv_i128 tcg_temp_ebb_new_i128(void)
17474643f3e0SRichard Henderson {
17484643f3e0SRichard Henderson return temp_tcgv_i128(tcg_temp_new_internal(TCG_TYPE_I128, TEMP_EBB));
17494643f3e0SRichard Henderson }
17504643f3e0SRichard Henderson
tcg_temp_new_vec(TCGType type)1751d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type)
1752d2fd745fSRichard Henderson {
1753d2fd745fSRichard Henderson TCGTemp *t;
1754d2fd745fSRichard Henderson
1755d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG
1756d2fd745fSRichard Henderson switch (type) {
1757d2fd745fSRichard Henderson case TCG_TYPE_V64:
1758d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v64);
1759d2fd745fSRichard Henderson break;
1760d2fd745fSRichard Henderson case TCG_TYPE_V128:
1761d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v128);
1762d2fd745fSRichard Henderson break;
1763d2fd745fSRichard Henderson case TCG_TYPE_V256:
1764d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v256);
1765d2fd745fSRichard Henderson break;
1766d2fd745fSRichard Henderson default:
1767d2fd745fSRichard Henderson g_assert_not_reached();
1768d2fd745fSRichard Henderson }
1769d2fd745fSRichard Henderson #endif
1770d2fd745fSRichard Henderson
1771bbf989bfSRichard Henderson t = tcg_temp_new_internal(type, TEMP_EBB);
1772d2fd745fSRichard Henderson return temp_tcgv_vec(t);
1773d2fd745fSRichard Henderson }
1774d2fd745fSRichard Henderson
1775d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp. */
tcg_temp_new_vec_matching(TCGv_vec match)1776d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match)
1777d2fd745fSRichard Henderson {
1778d2fd745fSRichard Henderson TCGTemp *t = tcgv_vec_temp(match);
1779d2fd745fSRichard Henderson
1780d2fd745fSRichard Henderson tcg_debug_assert(t->temp_allocated != 0);
1781d2fd745fSRichard Henderson
1782bbf989bfSRichard Henderson t = tcg_temp_new_internal(t->base_type, TEMP_EBB);
1783d2fd745fSRichard Henderson return temp_tcgv_vec(t);
1784d2fd745fSRichard Henderson }
1785d2fd745fSRichard Henderson
tcg_temp_free_internal(TCGTemp * ts)17865bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts)
1787c896fe29Sbellard {
1788b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx;
1789c896fe29Sbellard
1790c7482438SRichard Henderson switch (ts->kind) {
1791c7482438SRichard Henderson case TEMP_CONST:
1792f57c6915SRichard Henderson case TEMP_TB:
17932f2e911dSRichard Henderson /* Silently ignore free. */
1794c7482438SRichard Henderson break;
17952f2e911dSRichard Henderson case TEMP_EBB:
1796eabb7b91SAurelien Jarno tcg_debug_assert(ts->temp_allocated != 0);
1797e8996ee0Sbellard ts->temp_allocated = 0;
17982f2e911dSRichard Henderson set_bit(temp_idx(ts), s->free_temps[ts->base_type].l);
17992f2e911dSRichard Henderson break;
18002f2e911dSRichard Henderson default:
18012f2e911dSRichard Henderson /* It never made sense to free TEMP_FIXED or TEMP_GLOBAL. */
18022f2e911dSRichard Henderson g_assert_not_reached();
1803e1c08b00SRichard Henderson }
1804e8996ee0Sbellard }
1805e8996ee0Sbellard
tcg_temp_free_i32(TCGv_i32 arg)180658b79713SRichard Henderson void tcg_temp_free_i32(TCGv_i32 arg)
180758b79713SRichard Henderson {
180858b79713SRichard Henderson tcg_temp_free_internal(tcgv_i32_temp(arg));
180958b79713SRichard Henderson }
181058b79713SRichard Henderson
tcg_temp_free_i64(TCGv_i64 arg)181158b79713SRichard Henderson void tcg_temp_free_i64(TCGv_i64 arg)
181258b79713SRichard Henderson {
181358b79713SRichard Henderson tcg_temp_free_internal(tcgv_i64_temp(arg));
181458b79713SRichard Henderson }
181558b79713SRichard Henderson
tcg_temp_free_i128(TCGv_i128 arg)181658b79713SRichard Henderson void tcg_temp_free_i128(TCGv_i128 arg)
181758b79713SRichard Henderson {
181858b79713SRichard Henderson tcg_temp_free_internal(tcgv_i128_temp(arg));
181958b79713SRichard Henderson }
182058b79713SRichard Henderson
tcg_temp_free_ptr(TCGv_ptr arg)182158b79713SRichard Henderson void tcg_temp_free_ptr(TCGv_ptr arg)
182258b79713SRichard Henderson {
182358b79713SRichard Henderson tcg_temp_free_internal(tcgv_ptr_temp(arg));
182458b79713SRichard Henderson }
182558b79713SRichard Henderson
tcg_temp_free_vec(TCGv_vec arg)182658b79713SRichard Henderson void tcg_temp_free_vec(TCGv_vec arg)
182758b79713SRichard Henderson {
182858b79713SRichard Henderson tcg_temp_free_internal(tcgv_vec_temp(arg));
182958b79713SRichard Henderson }
183058b79713SRichard Henderson
tcg_constant_internal(TCGType type,int64_t val)1831c0522136SRichard Henderson TCGTemp *tcg_constant_internal(TCGType type, int64_t val)
1832c0522136SRichard Henderson {
1833c0522136SRichard Henderson TCGContext *s = tcg_ctx;
1834c0522136SRichard Henderson GHashTable *h = s->const_table[type];
1835c0522136SRichard Henderson TCGTemp *ts;
1836c0522136SRichard Henderson
1837c0522136SRichard Henderson if (h == NULL) {
1838c0522136SRichard Henderson h = g_hash_table_new(g_int64_hash, g_int64_equal);
1839c0522136SRichard Henderson s->const_table[type] = h;
1840c0522136SRichard Henderson }
1841c0522136SRichard Henderson
1842c0522136SRichard Henderson ts = g_hash_table_lookup(h, &val);
1843c0522136SRichard Henderson if (ts == NULL) {
1844aef85402SRichard Henderson int64_t *val_ptr;
1845aef85402SRichard Henderson
1846c0522136SRichard Henderson ts = tcg_temp_alloc(s);
1847c0522136SRichard Henderson
1848c0522136SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
1849c0522136SRichard Henderson TCGTemp *ts2 = tcg_temp_alloc(s);
1850c0522136SRichard Henderson
1851aef85402SRichard Henderson tcg_debug_assert(ts2 == ts + 1);
1852aef85402SRichard Henderson
1853c0522136SRichard Henderson ts->base_type = TCG_TYPE_I64;
1854c0522136SRichard Henderson ts->type = TCG_TYPE_I32;
1855c0522136SRichard Henderson ts->kind = TEMP_CONST;
1856c0522136SRichard Henderson ts->temp_allocated = 1;
1857c0522136SRichard Henderson
1858c0522136SRichard Henderson ts2->base_type = TCG_TYPE_I64;
1859c0522136SRichard Henderson ts2->type = TCG_TYPE_I32;
1860c0522136SRichard Henderson ts2->kind = TEMP_CONST;
1861c0522136SRichard Henderson ts2->temp_allocated = 1;
1862fac87bd2SRichard Henderson ts2->temp_subindex = 1;
1863aef85402SRichard Henderson
1864aef85402SRichard Henderson /*
1865aef85402SRichard Henderson * Retain the full value of the 64-bit constant in the low
1866aef85402SRichard Henderson * part, so that the hash table works. Actual uses will
1867aef85402SRichard Henderson * truncate the value to the low part.
1868aef85402SRichard Henderson */
1869aef85402SRichard Henderson ts[HOST_BIG_ENDIAN].val = val;
1870aef85402SRichard Henderson ts[!HOST_BIG_ENDIAN].val = val >> 32;
1871aef85402SRichard Henderson val_ptr = &ts[HOST_BIG_ENDIAN].val;
1872c0522136SRichard Henderson } else {
1873c0522136SRichard Henderson ts->base_type = type;
1874c0522136SRichard Henderson ts->type = type;
1875c0522136SRichard Henderson ts->kind = TEMP_CONST;
1876c0522136SRichard Henderson ts->temp_allocated = 1;
1877c0522136SRichard Henderson ts->val = val;
1878aef85402SRichard Henderson val_ptr = &ts->val;
1879c0522136SRichard Henderson }
1880aef85402SRichard Henderson g_hash_table_insert(h, val_ptr, ts);
1881c0522136SRichard Henderson }
1882c0522136SRichard Henderson
1883c0522136SRichard Henderson return ts;
1884c0522136SRichard Henderson }
1885c0522136SRichard Henderson
tcg_constant_i32(int32_t val)188616edaee7SRichard Henderson TCGv_i32 tcg_constant_i32(int32_t val)
188716edaee7SRichard Henderson {
188816edaee7SRichard Henderson return temp_tcgv_i32(tcg_constant_internal(TCG_TYPE_I32, val));
188916edaee7SRichard Henderson }
189016edaee7SRichard Henderson
tcg_constant_i64(int64_t val)189116edaee7SRichard Henderson TCGv_i64 tcg_constant_i64(int64_t val)
189216edaee7SRichard Henderson {
189316edaee7SRichard Henderson return temp_tcgv_i64(tcg_constant_internal(TCG_TYPE_I64, val));
189416edaee7SRichard Henderson }
189516edaee7SRichard Henderson
tcg_constant_ptr_int(intptr_t val)189616edaee7SRichard Henderson TCGv_ptr tcg_constant_ptr_int(intptr_t val)
189716edaee7SRichard Henderson {
189816edaee7SRichard Henderson return temp_tcgv_ptr(tcg_constant_internal(TCG_TYPE_PTR, val));
189916edaee7SRichard Henderson }
190016edaee7SRichard Henderson
tcg_constant_vec(TCGType type,unsigned vece,int64_t val)1901c0522136SRichard Henderson TCGv_vec tcg_constant_vec(TCGType type, unsigned vece, int64_t val)
1902c0522136SRichard Henderson {
1903c0522136SRichard Henderson val = dup_const(vece, val);
1904c0522136SRichard Henderson return temp_tcgv_vec(tcg_constant_internal(type, val));
1905c0522136SRichard Henderson }
1906c0522136SRichard Henderson
tcg_constant_vec_matching(TCGv_vec match,unsigned vece,int64_t val)190788d4005bSRichard Henderson TCGv_vec tcg_constant_vec_matching(TCGv_vec match, unsigned vece, int64_t val)
190888d4005bSRichard Henderson {
190988d4005bSRichard Henderson TCGTemp *t = tcgv_vec_temp(match);
191088d4005bSRichard Henderson
191188d4005bSRichard Henderson tcg_debug_assert(t->temp_allocated != 0);
191288d4005bSRichard Henderson return tcg_constant_vec(t->base_type, vece, val);
191388d4005bSRichard Henderson }
191488d4005bSRichard Henderson
1915177f648fSRichard Henderson #ifdef CONFIG_DEBUG_TCG
temp_idx(TCGTemp * ts)1916177f648fSRichard Henderson size_t temp_idx(TCGTemp *ts)
1917177f648fSRichard Henderson {
1918177f648fSRichard Henderson ptrdiff_t n = ts - tcg_ctx->temps;
1919177f648fSRichard Henderson assert(n >= 0 && n < tcg_ctx->nb_temps);
1920177f648fSRichard Henderson return n;
1921177f648fSRichard Henderson }
1922177f648fSRichard Henderson
tcgv_i32_temp(TCGv_i32 v)1923177f648fSRichard Henderson TCGTemp *tcgv_i32_temp(TCGv_i32 v)
1924177f648fSRichard Henderson {
1925177f648fSRichard Henderson uintptr_t o = (uintptr_t)v - offsetof(TCGContext, temps);
1926177f648fSRichard Henderson
1927177f648fSRichard Henderson assert(o < sizeof(TCGTemp) * tcg_ctx->nb_temps);
1928177f648fSRichard Henderson assert(o % sizeof(TCGTemp) == 0);
1929177f648fSRichard Henderson
1930177f648fSRichard Henderson return (void *)tcg_ctx + (uintptr_t)v;
1931177f648fSRichard Henderson }
1932177f648fSRichard Henderson #endif /* CONFIG_DEBUG_TCG */
1933177f648fSRichard Henderson
1934be0f34b5SRichard Henderson /* Return true if OP may appear in the opcode stream.
1935be0f34b5SRichard Henderson Test the runtime variable that controls each opcode. */
tcg_op_supported(TCGOpcode op)1936be0f34b5SRichard Henderson bool tcg_op_supported(TCGOpcode op)
1937be0f34b5SRichard Henderson {
1938d2fd745fSRichard Henderson const bool have_vec
1939d2fd745fSRichard Henderson = TCG_TARGET_HAS_v64 | TCG_TARGET_HAS_v128 | TCG_TARGET_HAS_v256;
1940d2fd745fSRichard Henderson
1941be0f34b5SRichard Henderson switch (op) {
1942be0f34b5SRichard Henderson case INDEX_op_discard:
1943be0f34b5SRichard Henderson case INDEX_op_set_label:
1944be0f34b5SRichard Henderson case INDEX_op_call:
1945be0f34b5SRichard Henderson case INDEX_op_br:
1946be0f34b5SRichard Henderson case INDEX_op_mb:
1947be0f34b5SRichard Henderson case INDEX_op_insn_start:
1948be0f34b5SRichard Henderson case INDEX_op_exit_tb:
1949be0f34b5SRichard Henderson case INDEX_op_goto_tb:
1950f4e01e30SRichard Henderson case INDEX_op_goto_ptr:
1951fecccfccSRichard Henderson case INDEX_op_qemu_ld_a32_i32:
1952fecccfccSRichard Henderson case INDEX_op_qemu_ld_a64_i32:
1953fecccfccSRichard Henderson case INDEX_op_qemu_st_a32_i32:
1954fecccfccSRichard Henderson case INDEX_op_qemu_st_a64_i32:
1955fecccfccSRichard Henderson case INDEX_op_qemu_ld_a32_i64:
1956fecccfccSRichard Henderson case INDEX_op_qemu_ld_a64_i64:
1957fecccfccSRichard Henderson case INDEX_op_qemu_st_a32_i64:
1958fecccfccSRichard Henderson case INDEX_op_qemu_st_a64_i64:
1959be0f34b5SRichard Henderson return true;
1960be0f34b5SRichard Henderson
1961fecccfccSRichard Henderson case INDEX_op_qemu_st8_a32_i32:
1962fecccfccSRichard Henderson case INDEX_op_qemu_st8_a64_i32:
196307ce0b05SRichard Henderson return TCG_TARGET_HAS_qemu_st8_i32;
196407ce0b05SRichard Henderson
1965fecccfccSRichard Henderson case INDEX_op_qemu_ld_a32_i128:
1966fecccfccSRichard Henderson case INDEX_op_qemu_ld_a64_i128:
1967fecccfccSRichard Henderson case INDEX_op_qemu_st_a32_i128:
1968fecccfccSRichard Henderson case INDEX_op_qemu_st_a64_i128:
196912fde9bcSRichard Henderson return TCG_TARGET_HAS_qemu_ldst_i128;
197012fde9bcSRichard Henderson
1971be0f34b5SRichard Henderson case INDEX_op_mov_i32:
1972be0f34b5SRichard Henderson case INDEX_op_setcond_i32:
1973be0f34b5SRichard Henderson case INDEX_op_brcond_i32:
19743871be75SRichard Henderson case INDEX_op_movcond_i32:
1975be0f34b5SRichard Henderson case INDEX_op_ld8u_i32:
1976be0f34b5SRichard Henderson case INDEX_op_ld8s_i32:
1977be0f34b5SRichard Henderson case INDEX_op_ld16u_i32:
1978be0f34b5SRichard Henderson case INDEX_op_ld16s_i32:
1979be0f34b5SRichard Henderson case INDEX_op_ld_i32:
1980be0f34b5SRichard Henderson case INDEX_op_st8_i32:
1981be0f34b5SRichard Henderson case INDEX_op_st16_i32:
1982be0f34b5SRichard Henderson case INDEX_op_st_i32:
1983be0f34b5SRichard Henderson case INDEX_op_add_i32:
1984be0f34b5SRichard Henderson case INDEX_op_sub_i32:
1985b701f195SRichard Henderson case INDEX_op_neg_i32:
1986be0f34b5SRichard Henderson case INDEX_op_mul_i32:
1987be0f34b5SRichard Henderson case INDEX_op_and_i32:
1988be0f34b5SRichard Henderson case INDEX_op_or_i32:
1989be0f34b5SRichard Henderson case INDEX_op_xor_i32:
1990be0f34b5SRichard Henderson case INDEX_op_shl_i32:
1991be0f34b5SRichard Henderson case INDEX_op_shr_i32:
1992be0f34b5SRichard Henderson case INDEX_op_sar_i32:
1993be0f34b5SRichard Henderson return true;
1994be0f34b5SRichard Henderson
19953635502dSRichard Henderson case INDEX_op_negsetcond_i32:
19963635502dSRichard Henderson return TCG_TARGET_HAS_negsetcond_i32;
1997be0f34b5SRichard Henderson case INDEX_op_div_i32:
1998be0f34b5SRichard Henderson case INDEX_op_divu_i32:
1999be0f34b5SRichard Henderson return TCG_TARGET_HAS_div_i32;
2000be0f34b5SRichard Henderson case INDEX_op_rem_i32:
2001be0f34b5SRichard Henderson case INDEX_op_remu_i32:
2002be0f34b5SRichard Henderson return TCG_TARGET_HAS_rem_i32;
2003be0f34b5SRichard Henderson case INDEX_op_div2_i32:
2004be0f34b5SRichard Henderson case INDEX_op_divu2_i32:
2005be0f34b5SRichard Henderson return TCG_TARGET_HAS_div2_i32;
2006be0f34b5SRichard Henderson case INDEX_op_rotl_i32:
2007be0f34b5SRichard Henderson case INDEX_op_rotr_i32:
2008be0f34b5SRichard Henderson return TCG_TARGET_HAS_rot_i32;
2009be0f34b5SRichard Henderson case INDEX_op_deposit_i32:
2010be0f34b5SRichard Henderson return TCG_TARGET_HAS_deposit_i32;
2011be0f34b5SRichard Henderson case INDEX_op_extract_i32:
2012be0f34b5SRichard Henderson return TCG_TARGET_HAS_extract_i32;
2013be0f34b5SRichard Henderson case INDEX_op_sextract_i32:
2014be0f34b5SRichard Henderson return TCG_TARGET_HAS_sextract_i32;
2015fce1296fSRichard Henderson case INDEX_op_extract2_i32:
2016fce1296fSRichard Henderson return TCG_TARGET_HAS_extract2_i32;
2017be0f34b5SRichard Henderson case INDEX_op_add2_i32:
2018be0f34b5SRichard Henderson return TCG_TARGET_HAS_add2_i32;
2019be0f34b5SRichard Henderson case INDEX_op_sub2_i32:
2020be0f34b5SRichard Henderson return TCG_TARGET_HAS_sub2_i32;
2021be0f34b5SRichard Henderson case INDEX_op_mulu2_i32:
2022be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulu2_i32;
2023be0f34b5SRichard Henderson case INDEX_op_muls2_i32:
2024be0f34b5SRichard Henderson return TCG_TARGET_HAS_muls2_i32;
2025be0f34b5SRichard Henderson case INDEX_op_muluh_i32:
2026be0f34b5SRichard Henderson return TCG_TARGET_HAS_muluh_i32;
2027be0f34b5SRichard Henderson case INDEX_op_mulsh_i32:
2028be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulsh_i32;
2029be0f34b5SRichard Henderson case INDEX_op_ext8s_i32:
2030be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8s_i32;
2031be0f34b5SRichard Henderson case INDEX_op_ext16s_i32:
2032be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16s_i32;
2033be0f34b5SRichard Henderson case INDEX_op_ext8u_i32:
2034be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8u_i32;
2035be0f34b5SRichard Henderson case INDEX_op_ext16u_i32:
2036be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16u_i32;
2037be0f34b5SRichard Henderson case INDEX_op_bswap16_i32:
2038be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap16_i32;
2039be0f34b5SRichard Henderson case INDEX_op_bswap32_i32:
2040be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap32_i32;
2041be0f34b5SRichard Henderson case INDEX_op_not_i32:
2042be0f34b5SRichard Henderson return TCG_TARGET_HAS_not_i32;
2043be0f34b5SRichard Henderson case INDEX_op_andc_i32:
2044be0f34b5SRichard Henderson return TCG_TARGET_HAS_andc_i32;
2045be0f34b5SRichard Henderson case INDEX_op_orc_i32:
2046be0f34b5SRichard Henderson return TCG_TARGET_HAS_orc_i32;
2047be0f34b5SRichard Henderson case INDEX_op_eqv_i32:
2048be0f34b5SRichard Henderson return TCG_TARGET_HAS_eqv_i32;
2049be0f34b5SRichard Henderson case INDEX_op_nand_i32:
2050be0f34b5SRichard Henderson return TCG_TARGET_HAS_nand_i32;
2051be0f34b5SRichard Henderson case INDEX_op_nor_i32:
2052be0f34b5SRichard Henderson return TCG_TARGET_HAS_nor_i32;
2053be0f34b5SRichard Henderson case INDEX_op_clz_i32:
2054be0f34b5SRichard Henderson return TCG_TARGET_HAS_clz_i32;
2055be0f34b5SRichard Henderson case INDEX_op_ctz_i32:
2056be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctz_i32;
2057be0f34b5SRichard Henderson case INDEX_op_ctpop_i32:
2058be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctpop_i32;
2059be0f34b5SRichard Henderson
2060be0f34b5SRichard Henderson case INDEX_op_brcond2_i32:
2061be0f34b5SRichard Henderson case INDEX_op_setcond2_i32:
2062be0f34b5SRichard Henderson return TCG_TARGET_REG_BITS == 32;
2063be0f34b5SRichard Henderson
2064be0f34b5SRichard Henderson case INDEX_op_mov_i64:
2065be0f34b5SRichard Henderson case INDEX_op_setcond_i64:
2066be0f34b5SRichard Henderson case INDEX_op_brcond_i64:
20673871be75SRichard Henderson case INDEX_op_movcond_i64:
2068be0f34b5SRichard Henderson case INDEX_op_ld8u_i64:
2069be0f34b5SRichard Henderson case INDEX_op_ld8s_i64:
2070be0f34b5SRichard Henderson case INDEX_op_ld16u_i64:
2071be0f34b5SRichard Henderson case INDEX_op_ld16s_i64:
2072be0f34b5SRichard Henderson case INDEX_op_ld32u_i64:
2073be0f34b5SRichard Henderson case INDEX_op_ld32s_i64:
2074be0f34b5SRichard Henderson case INDEX_op_ld_i64:
2075be0f34b5SRichard Henderson case INDEX_op_st8_i64:
2076be0f34b5SRichard Henderson case INDEX_op_st16_i64:
2077be0f34b5SRichard Henderson case INDEX_op_st32_i64:
2078be0f34b5SRichard Henderson case INDEX_op_st_i64:
2079be0f34b5SRichard Henderson case INDEX_op_add_i64:
2080be0f34b5SRichard Henderson case INDEX_op_sub_i64:
2081b701f195SRichard Henderson case INDEX_op_neg_i64:
2082be0f34b5SRichard Henderson case INDEX_op_mul_i64:
2083be0f34b5SRichard Henderson case INDEX_op_and_i64:
2084be0f34b5SRichard Henderson case INDEX_op_or_i64:
2085be0f34b5SRichard Henderson case INDEX_op_xor_i64:
2086be0f34b5SRichard Henderson case INDEX_op_shl_i64:
2087be0f34b5SRichard Henderson case INDEX_op_shr_i64:
2088be0f34b5SRichard Henderson case INDEX_op_sar_i64:
2089be0f34b5SRichard Henderson case INDEX_op_ext_i32_i64:
2090be0f34b5SRichard Henderson case INDEX_op_extu_i32_i64:
2091be0f34b5SRichard Henderson return TCG_TARGET_REG_BITS == 64;
2092be0f34b5SRichard Henderson
20933635502dSRichard Henderson case INDEX_op_negsetcond_i64:
20943635502dSRichard Henderson return TCG_TARGET_HAS_negsetcond_i64;
2095be0f34b5SRichard Henderson case INDEX_op_div_i64:
2096be0f34b5SRichard Henderson case INDEX_op_divu_i64:
2097be0f34b5SRichard Henderson return TCG_TARGET_HAS_div_i64;
2098be0f34b5SRichard Henderson case INDEX_op_rem_i64:
2099be0f34b5SRichard Henderson case INDEX_op_remu_i64:
2100be0f34b5SRichard Henderson return TCG_TARGET_HAS_rem_i64;
2101be0f34b5SRichard Henderson case INDEX_op_div2_i64:
2102be0f34b5SRichard Henderson case INDEX_op_divu2_i64:
2103be0f34b5SRichard Henderson return TCG_TARGET_HAS_div2_i64;
2104be0f34b5SRichard Henderson case INDEX_op_rotl_i64:
2105be0f34b5SRichard Henderson case INDEX_op_rotr_i64:
2106be0f34b5SRichard Henderson return TCG_TARGET_HAS_rot_i64;
2107be0f34b5SRichard Henderson case INDEX_op_deposit_i64:
2108be0f34b5SRichard Henderson return TCG_TARGET_HAS_deposit_i64;
2109be0f34b5SRichard Henderson case INDEX_op_extract_i64:
2110be0f34b5SRichard Henderson return TCG_TARGET_HAS_extract_i64;
2111be0f34b5SRichard Henderson case INDEX_op_sextract_i64:
2112be0f34b5SRichard Henderson return TCG_TARGET_HAS_sextract_i64;
2113fce1296fSRichard Henderson case INDEX_op_extract2_i64:
2114fce1296fSRichard Henderson return TCG_TARGET_HAS_extract2_i64;
2115be0f34b5SRichard Henderson case INDEX_op_extrl_i64_i32:
2116be0f34b5SRichard Henderson case INDEX_op_extrh_i64_i32:
211713d885b0SRichard Henderson return TCG_TARGET_HAS_extr_i64_i32;
2118be0f34b5SRichard Henderson case INDEX_op_ext8s_i64:
2119be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8s_i64;
2120be0f34b5SRichard Henderson case INDEX_op_ext16s_i64:
2121be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16s_i64;
2122be0f34b5SRichard Henderson case INDEX_op_ext32s_i64:
2123be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext32s_i64;
2124be0f34b5SRichard Henderson case INDEX_op_ext8u_i64:
2125be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8u_i64;
2126be0f34b5SRichard Henderson case INDEX_op_ext16u_i64:
2127be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16u_i64;
2128be0f34b5SRichard Henderson case INDEX_op_ext32u_i64:
2129be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext32u_i64;
2130be0f34b5SRichard Henderson case INDEX_op_bswap16_i64:
2131be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap16_i64;
2132be0f34b5SRichard Henderson case INDEX_op_bswap32_i64:
2133be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap32_i64;
2134be0f34b5SRichard Henderson case INDEX_op_bswap64_i64:
2135be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap64_i64;
2136be0f34b5SRichard Henderson case INDEX_op_not_i64:
2137be0f34b5SRichard Henderson return TCG_TARGET_HAS_not_i64;
2138be0f34b5SRichard Henderson case INDEX_op_andc_i64:
2139be0f34b5SRichard Henderson return TCG_TARGET_HAS_andc_i64;
2140be0f34b5SRichard Henderson case INDEX_op_orc_i64:
2141be0f34b5SRichard Henderson return TCG_TARGET_HAS_orc_i64;
2142be0f34b5SRichard Henderson case INDEX_op_eqv_i64:
2143be0f34b5SRichard Henderson return TCG_TARGET_HAS_eqv_i64;
2144be0f34b5SRichard Henderson case INDEX_op_nand_i64:
2145be0f34b5SRichard Henderson return TCG_TARGET_HAS_nand_i64;
2146be0f34b5SRichard Henderson case INDEX_op_nor_i64:
2147be0f34b5SRichard Henderson return TCG_TARGET_HAS_nor_i64;
2148be0f34b5SRichard Henderson case INDEX_op_clz_i64:
2149be0f34b5SRichard Henderson return TCG_TARGET_HAS_clz_i64;
2150be0f34b5SRichard Henderson case INDEX_op_ctz_i64:
2151be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctz_i64;
2152be0f34b5SRichard Henderson case INDEX_op_ctpop_i64:
2153be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctpop_i64;
2154be0f34b5SRichard Henderson case INDEX_op_add2_i64:
2155be0f34b5SRichard Henderson return TCG_TARGET_HAS_add2_i64;
2156be0f34b5SRichard Henderson case INDEX_op_sub2_i64:
2157be0f34b5SRichard Henderson return TCG_TARGET_HAS_sub2_i64;
2158be0f34b5SRichard Henderson case INDEX_op_mulu2_i64:
2159be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulu2_i64;
2160be0f34b5SRichard Henderson case INDEX_op_muls2_i64:
2161be0f34b5SRichard Henderson return TCG_TARGET_HAS_muls2_i64;
2162be0f34b5SRichard Henderson case INDEX_op_muluh_i64:
2163be0f34b5SRichard Henderson return TCG_TARGET_HAS_muluh_i64;
2164be0f34b5SRichard Henderson case INDEX_op_mulsh_i64:
2165be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulsh_i64;
2166be0f34b5SRichard Henderson
2167d2fd745fSRichard Henderson case INDEX_op_mov_vec:
2168d2fd745fSRichard Henderson case INDEX_op_dup_vec:
216937ee55a0SRichard Henderson case INDEX_op_dupm_vec:
2170d2fd745fSRichard Henderson case INDEX_op_ld_vec:
2171d2fd745fSRichard Henderson case INDEX_op_st_vec:
2172d2fd745fSRichard Henderson case INDEX_op_add_vec:
2173d2fd745fSRichard Henderson case INDEX_op_sub_vec:
2174d2fd745fSRichard Henderson case INDEX_op_and_vec:
2175d2fd745fSRichard Henderson case INDEX_op_or_vec:
2176d2fd745fSRichard Henderson case INDEX_op_xor_vec:
2177212be173SRichard Henderson case INDEX_op_cmp_vec:
2178d2fd745fSRichard Henderson return have_vec;
2179d2fd745fSRichard Henderson case INDEX_op_dup2_vec:
2180d2fd745fSRichard Henderson return have_vec && TCG_TARGET_REG_BITS == 32;
2181d2fd745fSRichard Henderson case INDEX_op_not_vec:
2182d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_not_vec;
2183d2fd745fSRichard Henderson case INDEX_op_neg_vec:
2184d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_neg_vec;
2185bcefc902SRichard Henderson case INDEX_op_abs_vec:
2186bcefc902SRichard Henderson return have_vec && TCG_TARGET_HAS_abs_vec;
2187d2fd745fSRichard Henderson case INDEX_op_andc_vec:
2188d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_andc_vec;
2189d2fd745fSRichard Henderson case INDEX_op_orc_vec:
2190d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_orc_vec;
2191ed523473SRichard Henderson case INDEX_op_nand_vec:
2192ed523473SRichard Henderson return have_vec && TCG_TARGET_HAS_nand_vec;
2193ed523473SRichard Henderson case INDEX_op_nor_vec:
2194ed523473SRichard Henderson return have_vec && TCG_TARGET_HAS_nor_vec;
2195ed523473SRichard Henderson case INDEX_op_eqv_vec:
2196ed523473SRichard Henderson return have_vec && TCG_TARGET_HAS_eqv_vec;
21973774030aSRichard Henderson case INDEX_op_mul_vec:
21983774030aSRichard Henderson return have_vec && TCG_TARGET_HAS_mul_vec;
2199d0ec9796SRichard Henderson case INDEX_op_shli_vec:
2200d0ec9796SRichard Henderson case INDEX_op_shri_vec:
2201d0ec9796SRichard Henderson case INDEX_op_sari_vec:
2202d0ec9796SRichard Henderson return have_vec && TCG_TARGET_HAS_shi_vec;
2203d0ec9796SRichard Henderson case INDEX_op_shls_vec:
2204d0ec9796SRichard Henderson case INDEX_op_shrs_vec:
2205d0ec9796SRichard Henderson case INDEX_op_sars_vec:
2206d0ec9796SRichard Henderson return have_vec && TCG_TARGET_HAS_shs_vec;
2207d0ec9796SRichard Henderson case INDEX_op_shlv_vec:
2208d0ec9796SRichard Henderson case INDEX_op_shrv_vec:
2209d0ec9796SRichard Henderson case INDEX_op_sarv_vec:
2210d0ec9796SRichard Henderson return have_vec && TCG_TARGET_HAS_shv_vec;
2211b0f7e744SRichard Henderson case INDEX_op_rotli_vec:
2212b0f7e744SRichard Henderson return have_vec && TCG_TARGET_HAS_roti_vec;
221323850a74SRichard Henderson case INDEX_op_rotls_vec:
221423850a74SRichard Henderson return have_vec && TCG_TARGET_HAS_rots_vec;
22155d0ceda9SRichard Henderson case INDEX_op_rotlv_vec:
22165d0ceda9SRichard Henderson case INDEX_op_rotrv_vec:
22175d0ceda9SRichard Henderson return have_vec && TCG_TARGET_HAS_rotv_vec;
22188afaf050SRichard Henderson case INDEX_op_ssadd_vec:
22198afaf050SRichard Henderson case INDEX_op_usadd_vec:
22208afaf050SRichard Henderson case INDEX_op_sssub_vec:
22218afaf050SRichard Henderson case INDEX_op_ussub_vec:
22228afaf050SRichard Henderson return have_vec && TCG_TARGET_HAS_sat_vec;
2223dd0a0fcdSRichard Henderson case INDEX_op_smin_vec:
2224dd0a0fcdSRichard Henderson case INDEX_op_umin_vec:
2225dd0a0fcdSRichard Henderson case INDEX_op_smax_vec:
2226dd0a0fcdSRichard Henderson case INDEX_op_umax_vec:
2227dd0a0fcdSRichard Henderson return have_vec && TCG_TARGET_HAS_minmax_vec;
222838dc1294SRichard Henderson case INDEX_op_bitsel_vec:
222938dc1294SRichard Henderson return have_vec && TCG_TARGET_HAS_bitsel_vec;
2230f75da298SRichard Henderson case INDEX_op_cmpsel_vec:
2231f75da298SRichard Henderson return have_vec && TCG_TARGET_HAS_cmpsel_vec;
2232d2fd745fSRichard Henderson
2233db432672SRichard Henderson default:
2234db432672SRichard Henderson tcg_debug_assert(op > INDEX_op_last_generic && op < NB_OPS);
2235db432672SRichard Henderson return true;
2236be0f34b5SRichard Henderson }
2237be0f34b5SRichard Henderson }
2238be0f34b5SRichard Henderson
223939004a71SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs);
224039004a71SRichard Henderson
tcg_gen_callN(void * func,TCGHelperInfo * info,TCGTemp * ret,TCGTemp ** args)224183a0ad26SRichard Henderson static void tcg_gen_callN(void *func, TCGHelperInfo *info,
224283a0ad26SRichard Henderson TCGTemp *ret, TCGTemp **args)
2243c896fe29Sbellard {
224439004a71SRichard Henderson TCGv_i64 extend_free[MAX_CALL_IARGS];
224539004a71SRichard Henderson int n_extend = 0;
224675e8b9b7SRichard Henderson TCGOp *op;
224739004a71SRichard Henderson int i, n, pi = 0, total_args;
2248afb49896SRichard Henderson
2249d53106c9SRichard Henderson if (unlikely(g_once_init_enter(HELPER_INFO_INIT(info)))) {
2250d53106c9SRichard Henderson init_call_layout(info);
2251d53106c9SRichard Henderson g_once_init_leave(HELPER_INFO_INIT(info), HELPER_INFO_INIT_VAL(info));
2252d53106c9SRichard Henderson }
2253d53106c9SRichard Henderson
225439004a71SRichard Henderson total_args = info->nr_out + info->nr_in + 2;
225539004a71SRichard Henderson op = tcg_op_alloc(INDEX_op_call, total_args);
22562bece2c8SRichard Henderson
225738b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN
225817083f6fSEmilio Cota /* Flag helpers that may affect guest state */
2259b0748975SRichard Henderson if (tcg_ctx->plugin_insn && !(info->flags & TCG_CALL_NO_SIDE_EFFECTS)) {
226038b47b19SEmilio G. Cota tcg_ctx->plugin_insn->calls_helpers = true;
226138b47b19SEmilio G. Cota }
226238b47b19SEmilio G. Cota #endif
226338b47b19SEmilio G. Cota
226439004a71SRichard Henderson TCGOP_CALLO(op) = n = info->nr_out;
226539004a71SRichard Henderson switch (n) {
226639004a71SRichard Henderson case 0:
226739004a71SRichard Henderson tcg_debug_assert(ret == NULL);
226839004a71SRichard Henderson break;
226939004a71SRichard Henderson case 1:
227039004a71SRichard Henderson tcg_debug_assert(ret != NULL);
227139004a71SRichard Henderson op->args[pi++] = temp_arg(ret);
227239004a71SRichard Henderson break;
227339004a71SRichard Henderson case 2:
2274466d3759SRichard Henderson case 4:
227539004a71SRichard Henderson tcg_debug_assert(ret != NULL);
2276466d3759SRichard Henderson tcg_debug_assert(ret->base_type == ret->type + ctz32(n));
227739004a71SRichard Henderson tcg_debug_assert(ret->temp_subindex == 0);
2278466d3759SRichard Henderson for (i = 0; i < n; ++i) {
2279466d3759SRichard Henderson op->args[pi++] = temp_arg(ret + i);
2280466d3759SRichard Henderson }
228139004a71SRichard Henderson break;
228239004a71SRichard Henderson default:
228339004a71SRichard Henderson g_assert_not_reached();
228439004a71SRichard Henderson }
22857319d83aSRichard Henderson
228639004a71SRichard Henderson TCGOP_CALLI(op) = n = info->nr_in;
228739004a71SRichard Henderson for (i = 0; i < n; i++) {
228839004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i];
228939004a71SRichard Henderson TCGTemp *ts = args[loc->arg_idx] + loc->tmp_subindex;
229039004a71SRichard Henderson
229139004a71SRichard Henderson switch (loc->kind) {
229239004a71SRichard Henderson case TCG_CALL_ARG_NORMAL:
2293313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF:
2294313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF_N:
229539004a71SRichard Henderson op->args[pi++] = temp_arg(ts);
229639004a71SRichard Henderson break;
229739004a71SRichard Henderson
229839004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U:
229939004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S:
230039004a71SRichard Henderson {
23015dd48602SRichard Henderson TCGv_i64 temp = tcg_temp_ebb_new_i64();
230239004a71SRichard Henderson TCGv_i32 orig = temp_tcgv_i32(ts);
230339004a71SRichard Henderson
230439004a71SRichard Henderson if (loc->kind == TCG_CALL_ARG_EXTEND_S) {
230518cf3d07SRichard Henderson tcg_gen_ext_i32_i64(temp, orig);
23062bece2c8SRichard Henderson } else {
230718cf3d07SRichard Henderson tcg_gen_extu_i32_i64(temp, orig);
23082bece2c8SRichard Henderson }
230939004a71SRichard Henderson op->args[pi++] = tcgv_i64_arg(temp);
231039004a71SRichard Henderson extend_free[n_extend++] = temp;
23112bece2c8SRichard Henderson }
231239004a71SRichard Henderson break;
23132bece2c8SRichard Henderson
2314e2a9dd6bSRichard Henderson default:
2315e2a9dd6bSRichard Henderson g_assert_not_reached();
2316e2a9dd6bSRichard Henderson }
2317c896fe29Sbellard }
231883a0ad26SRichard Henderson op->args[pi++] = (uintptr_t)func;
23193e92aa34SRichard Henderson op->args[pi++] = (uintptr_t)info;
232039004a71SRichard Henderson tcg_debug_assert(pi == total_args);
2321a7812ae4Spbrook
232207843f75SRichard Henderson if (tcg_ctx->emit_before_op) {
232307843f75SRichard Henderson QTAILQ_INSERT_BEFORE(tcg_ctx->emit_before_op, op, link);
232407843f75SRichard Henderson } else {
232539004a71SRichard Henderson QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
232607843f75SRichard Henderson }
23272bece2c8SRichard Henderson
232839004a71SRichard Henderson tcg_debug_assert(n_extend < ARRAY_SIZE(extend_free));
232939004a71SRichard Henderson for (i = 0; i < n_extend; ++i) {
233039004a71SRichard Henderson tcg_temp_free_i64(extend_free[i]);
2331eb8b0224SRichard Henderson }
2332a7812ae4Spbrook }
2333c896fe29Sbellard
tcg_gen_call0(void * func,TCGHelperInfo * info,TCGTemp * ret)233483a0ad26SRichard Henderson void tcg_gen_call0(void *func, TCGHelperInfo *info, TCGTemp *ret)
2335a3a692b8SRichard Henderson {
233683a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, NULL);
2337a3a692b8SRichard Henderson }
2338a3a692b8SRichard Henderson
tcg_gen_call1(void * func,TCGHelperInfo * info,TCGTemp * ret,TCGTemp * t1)233983a0ad26SRichard Henderson void tcg_gen_call1(void *func, TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1)
2340a3a692b8SRichard Henderson {
234183a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, &t1);
2342a3a692b8SRichard Henderson }
2343a3a692b8SRichard Henderson
tcg_gen_call2(void * func,TCGHelperInfo * info,TCGTemp * ret,TCGTemp * t1,TCGTemp * t2)234483a0ad26SRichard Henderson void tcg_gen_call2(void *func, TCGHelperInfo *info, TCGTemp *ret,
234583a0ad26SRichard Henderson TCGTemp *t1, TCGTemp *t2)
2346a3a692b8SRichard Henderson {
2347a3a692b8SRichard Henderson TCGTemp *args[2] = { t1, t2 };
234883a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, args);
2349a3a692b8SRichard Henderson }
2350a3a692b8SRichard Henderson
tcg_gen_call3(void * func,TCGHelperInfo * info,TCGTemp * ret,TCGTemp * t1,TCGTemp * t2,TCGTemp * t3)235183a0ad26SRichard Henderson void tcg_gen_call3(void *func, TCGHelperInfo *info, TCGTemp *ret,
235283a0ad26SRichard Henderson TCGTemp *t1, TCGTemp *t2, TCGTemp *t3)
2353a3a692b8SRichard Henderson {
2354a3a692b8SRichard Henderson TCGTemp *args[3] = { t1, t2, t3 };
235583a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, args);
2356a3a692b8SRichard Henderson }
2357a3a692b8SRichard Henderson
tcg_gen_call4(void * func,TCGHelperInfo * info,TCGTemp * ret,TCGTemp * t1,TCGTemp * t2,TCGTemp * t3,TCGTemp * t4)235883a0ad26SRichard Henderson void tcg_gen_call4(void *func, TCGHelperInfo *info, TCGTemp *ret,
235983a0ad26SRichard Henderson TCGTemp *t1, TCGTemp *t2, TCGTemp *t3, TCGTemp *t4)
2360a3a692b8SRichard Henderson {
2361a3a692b8SRichard Henderson TCGTemp *args[4] = { t1, t2, t3, t4 };
236283a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, args);
2363a3a692b8SRichard Henderson }
2364a3a692b8SRichard Henderson
tcg_gen_call5(void * func,TCGHelperInfo * info,TCGTemp * ret,TCGTemp * t1,TCGTemp * t2,TCGTemp * t3,TCGTemp * t4,TCGTemp * t5)236583a0ad26SRichard Henderson void tcg_gen_call5(void *func, TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1,
2366a3a692b8SRichard Henderson TCGTemp *t2, TCGTemp *t3, TCGTemp *t4, TCGTemp *t5)
2367a3a692b8SRichard Henderson {
2368a3a692b8SRichard Henderson TCGTemp *args[5] = { t1, t2, t3, t4, t5 };
236983a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, args);
2370a3a692b8SRichard Henderson }
2371a3a692b8SRichard Henderson
tcg_gen_call6(void * func,TCGHelperInfo * info,TCGTemp * ret,TCGTemp * t1,TCGTemp * t2,TCGTemp * t3,TCGTemp * t4,TCGTemp * t5,TCGTemp * t6)237283a0ad26SRichard Henderson void tcg_gen_call6(void *func, TCGHelperInfo *info, TCGTemp *ret,
237383a0ad26SRichard Henderson TCGTemp *t1, TCGTemp *t2, TCGTemp *t3,
237483a0ad26SRichard Henderson TCGTemp *t4, TCGTemp *t5, TCGTemp *t6)
2375a3a692b8SRichard Henderson {
2376a3a692b8SRichard Henderson TCGTemp *args[6] = { t1, t2, t3, t4, t5, t6 };
237783a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, args);
2378a3a692b8SRichard Henderson }
2379a3a692b8SRichard Henderson
tcg_gen_call7(void * func,TCGHelperInfo * info,TCGTemp * ret,TCGTemp * t1,TCGTemp * t2,TCGTemp * t3,TCGTemp * t4,TCGTemp * t5,TCGTemp * t6,TCGTemp * t7)238083a0ad26SRichard Henderson void tcg_gen_call7(void *func, TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1,
2381a3a692b8SRichard Henderson TCGTemp *t2, TCGTemp *t3, TCGTemp *t4,
2382a3a692b8SRichard Henderson TCGTemp *t5, TCGTemp *t6, TCGTemp *t7)
2383a3a692b8SRichard Henderson {
2384a3a692b8SRichard Henderson TCGTemp *args[7] = { t1, t2, t3, t4, t5, t6, t7 };
238583a0ad26SRichard Henderson tcg_gen_callN(func, info, ret, args);
2386a3a692b8SRichard Henderson }
2387a3a692b8SRichard Henderson
tcg_reg_alloc_start(TCGContext * s)23888fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s)
2389c896fe29Sbellard {
2390ac3b8891SRichard Henderson int i, n;
2391ac3b8891SRichard Henderson
2392ee17db83SRichard Henderson for (i = 0, n = s->nb_temps; i < n; i++) {
2393ee17db83SRichard Henderson TCGTemp *ts = &s->temps[i];
2394ee17db83SRichard Henderson TCGTempVal val = TEMP_VAL_MEM;
2395ee17db83SRichard Henderson
2396ee17db83SRichard Henderson switch (ts->kind) {
2397c0522136SRichard Henderson case TEMP_CONST:
2398c0522136SRichard Henderson val = TEMP_VAL_CONST;
2399c0522136SRichard Henderson break;
2400ee17db83SRichard Henderson case TEMP_FIXED:
2401ee17db83SRichard Henderson val = TEMP_VAL_REG;
2402ee17db83SRichard Henderson break;
2403ee17db83SRichard Henderson case TEMP_GLOBAL:
2404ee17db83SRichard Henderson break;
2405c7482438SRichard Henderson case TEMP_EBB:
2406ee17db83SRichard Henderson val = TEMP_VAL_DEAD;
2407ee17db83SRichard Henderson /* fall through */
2408f57c6915SRichard Henderson case TEMP_TB:
2409e8996ee0Sbellard ts->mem_allocated = 0;
2410ee17db83SRichard Henderson break;
2411ee17db83SRichard Henderson default:
2412ee17db83SRichard Henderson g_assert_not_reached();
2413ee17db83SRichard Henderson }
2414ee17db83SRichard Henderson ts->val_type = val;
2415e8996ee0Sbellard }
2416f8b2f202SRichard Henderson
2417f8b2f202SRichard Henderson memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp));
2418c896fe29Sbellard }
2419c896fe29Sbellard
tcg_get_arg_str_ptr(TCGContext * s,char * buf,int buf_size,TCGTemp * ts)2420f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size,
2421f8b2f202SRichard Henderson TCGTemp *ts)
2422c896fe29Sbellard {
24231807f4c4SRichard Henderson int idx = temp_idx(ts);
2424ac56dd48Spbrook
2425ee17db83SRichard Henderson switch (ts->kind) {
2426ee17db83SRichard Henderson case TEMP_FIXED:
2427ee17db83SRichard Henderson case TEMP_GLOBAL:
2428ac56dd48Spbrook pstrcpy(buf, buf_size, ts->name);
2429ee17db83SRichard Henderson break;
2430f57c6915SRichard Henderson case TEMP_TB:
2431641d5fbeSbellard snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
2432ee17db83SRichard Henderson break;
2433c7482438SRichard Henderson case TEMP_EBB:
2434ac56dd48Spbrook snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
2435ee17db83SRichard Henderson break;
2436c0522136SRichard Henderson case TEMP_CONST:
2437c0522136SRichard Henderson switch (ts->type) {
2438c0522136SRichard Henderson case TCG_TYPE_I32:
2439c0522136SRichard Henderson snprintf(buf, buf_size, "$0x%x", (int32_t)ts->val);
2440c0522136SRichard Henderson break;
2441c0522136SRichard Henderson #if TCG_TARGET_REG_BITS > 32
2442c0522136SRichard Henderson case TCG_TYPE_I64:
2443c0522136SRichard Henderson snprintf(buf, buf_size, "$0x%" PRIx64, ts->val);
2444c0522136SRichard Henderson break;
2445c0522136SRichard Henderson #endif
2446c0522136SRichard Henderson case TCG_TYPE_V64:
2447c0522136SRichard Henderson case TCG_TYPE_V128:
2448c0522136SRichard Henderson case TCG_TYPE_V256:
2449c0522136SRichard Henderson snprintf(buf, buf_size, "v%d$0x%" PRIx64,
2450c0522136SRichard Henderson 64 << (ts->type - TCG_TYPE_V64), ts->val);
2451c0522136SRichard Henderson break;
2452c0522136SRichard Henderson default:
2453c0522136SRichard Henderson g_assert_not_reached();
2454c0522136SRichard Henderson }
2455c0522136SRichard Henderson break;
2456c896fe29Sbellard }
2457c896fe29Sbellard return buf;
2458c896fe29Sbellard }
2459c896fe29Sbellard
tcg_get_arg_str(TCGContext * s,char * buf,int buf_size,TCGArg arg)246043439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf,
246143439139SRichard Henderson int buf_size, TCGArg arg)
2462f8b2f202SRichard Henderson {
246343439139SRichard Henderson return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg));
2464f8b2f202SRichard Henderson }
2465f8b2f202SRichard Henderson
2466f48f3edeSblueswir1 static const char * const cond_name[] =
2467f48f3edeSblueswir1 {
24680aed257fSRichard Henderson [TCG_COND_NEVER] = "never",
24690aed257fSRichard Henderson [TCG_COND_ALWAYS] = "always",
2470f48f3edeSblueswir1 [TCG_COND_EQ] = "eq",
2471f48f3edeSblueswir1 [TCG_COND_NE] = "ne",
2472f48f3edeSblueswir1 [TCG_COND_LT] = "lt",
2473f48f3edeSblueswir1 [TCG_COND_GE] = "ge",
2474f48f3edeSblueswir1 [TCG_COND_LE] = "le",
2475f48f3edeSblueswir1 [TCG_COND_GT] = "gt",
2476f48f3edeSblueswir1 [TCG_COND_LTU] = "ltu",
2477f48f3edeSblueswir1 [TCG_COND_GEU] = "geu",
2478f48f3edeSblueswir1 [TCG_COND_LEU] = "leu",
2479d48097d0SRichard Henderson [TCG_COND_GTU] = "gtu",
2480d48097d0SRichard Henderson [TCG_COND_TSTEQ] = "tsteq",
2481d48097d0SRichard Henderson [TCG_COND_TSTNE] = "tstne",
2482f48f3edeSblueswir1 };
2483f48f3edeSblueswir1
248412fde9bcSRichard Henderson static const char * const ldst_name[(MO_BSWAP | MO_SSIZE) + 1] =
2485f713d6adSRichard Henderson {
2486f713d6adSRichard Henderson [MO_UB] = "ub",
2487f713d6adSRichard Henderson [MO_SB] = "sb",
2488f713d6adSRichard Henderson [MO_LEUW] = "leuw",
2489f713d6adSRichard Henderson [MO_LESW] = "lesw",
2490f713d6adSRichard Henderson [MO_LEUL] = "leul",
2491f713d6adSRichard Henderson [MO_LESL] = "lesl",
2492fc313c64SFrédéric Pétrot [MO_LEUQ] = "leq",
2493f713d6adSRichard Henderson [MO_BEUW] = "beuw",
2494f713d6adSRichard Henderson [MO_BESW] = "besw",
2495f713d6adSRichard Henderson [MO_BEUL] = "beul",
2496f713d6adSRichard Henderson [MO_BESL] = "besl",
2497fc313c64SFrédéric Pétrot [MO_BEUQ] = "beq",
249812fde9bcSRichard Henderson [MO_128 + MO_BE] = "beo",
249912fde9bcSRichard Henderson [MO_128 + MO_LE] = "leo",
2500f713d6adSRichard Henderson };
2501f713d6adSRichard Henderson
25021f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = {
25031f00b27fSSergey Sorokin [MO_UNALN >> MO_ASHIFT] = "un+",
25041f00b27fSSergey Sorokin [MO_ALIGN >> MO_ASHIFT] = "al+",
25051f00b27fSSergey Sorokin [MO_ALIGN_2 >> MO_ASHIFT] = "al2+",
25061f00b27fSSergey Sorokin [MO_ALIGN_4 >> MO_ASHIFT] = "al4+",
25071f00b27fSSergey Sorokin [MO_ALIGN_8 >> MO_ASHIFT] = "al8+",
25081f00b27fSSergey Sorokin [MO_ALIGN_16 >> MO_ASHIFT] = "al16+",
25091f00b27fSSergey Sorokin [MO_ALIGN_32 >> MO_ASHIFT] = "al32+",
25101f00b27fSSergey Sorokin [MO_ALIGN_64 >> MO_ASHIFT] = "al64+",
25111f00b27fSSergey Sorokin };
25121f00b27fSSergey Sorokin
251337031fefSRichard Henderson static const char * const atom_name[(MO_ATOM_MASK >> MO_ATOM_SHIFT) + 1] = {
251437031fefSRichard Henderson [MO_ATOM_IFALIGN >> MO_ATOM_SHIFT] = "",
251537031fefSRichard Henderson [MO_ATOM_IFALIGN_PAIR >> MO_ATOM_SHIFT] = "pair+",
251637031fefSRichard Henderson [MO_ATOM_WITHIN16 >> MO_ATOM_SHIFT] = "w16+",
251737031fefSRichard Henderson [MO_ATOM_WITHIN16_PAIR >> MO_ATOM_SHIFT] = "w16p+",
251837031fefSRichard Henderson [MO_ATOM_SUBALIGN >> MO_ATOM_SHIFT] = "sub+",
251937031fefSRichard Henderson [MO_ATOM_NONE >> MO_ATOM_SHIFT] = "noat+",
252037031fefSRichard Henderson };
252137031fefSRichard Henderson
2522587195bdSRichard Henderson static const char bswap_flag_name[][6] = {
2523587195bdSRichard Henderson [TCG_BSWAP_IZ] = "iz",
2524587195bdSRichard Henderson [TCG_BSWAP_OZ] = "oz",
2525587195bdSRichard Henderson [TCG_BSWAP_OS] = "os",
2526587195bdSRichard Henderson [TCG_BSWAP_IZ | TCG_BSWAP_OZ] = "iz,oz",
2527587195bdSRichard Henderson [TCG_BSWAP_IZ | TCG_BSWAP_OS] = "iz,os",
2528587195bdSRichard Henderson };
2529587195bdSRichard Henderson
2530b384c734SRichard Henderson #ifdef CONFIG_PLUGIN
2531b384c734SRichard Henderson static const char * const plugin_from_name[] = {
2532b384c734SRichard Henderson "from-tb",
2533b384c734SRichard Henderson "from-insn",
2534b384c734SRichard Henderson "after-insn",
2535b384c734SRichard Henderson "after-tb",
2536b384c734SRichard Henderson };
2537b384c734SRichard Henderson #endif
2538b384c734SRichard Henderson
tcg_regset_single(TCGRegSet d)2539b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d)
2540b016486eSRichard Henderson {
2541b016486eSRichard Henderson return (d & (d - 1)) == 0;
2542b016486eSRichard Henderson }
2543b016486eSRichard Henderson
tcg_regset_first(TCGRegSet d)2544b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d)
2545b016486eSRichard Henderson {
2546b016486eSRichard Henderson if (TCG_TARGET_NB_REGS <= 32) {
2547b016486eSRichard Henderson return ctz32(d);
2548b016486eSRichard Henderson } else {
2549b016486eSRichard Henderson return ctz64(d);
2550b016486eSRichard Henderson }
2551b016486eSRichard Henderson }
2552b016486eSRichard Henderson
2553b7a83ff8SRichard Henderson /* Return only the number of characters output -- no error return. */
2554b7a83ff8SRichard Henderson #define ne_fprintf(...) \
2555b7a83ff8SRichard Henderson ({ int ret_ = fprintf(__VA_ARGS__); ret_ >= 0 ? ret_ : 0; })
2556b7a83ff8SRichard Henderson
tcg_dump_ops(TCGContext * s,FILE * f,bool have_prefs)2557b384c734SRichard Henderson void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs)
2558c896fe29Sbellard {
2559c896fe29Sbellard char buf[128];
2560c45cb8bbSRichard Henderson TCGOp *op;
2561c896fe29Sbellard
256215fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) {
2563c45cb8bbSRichard Henderson int i, k, nb_oargs, nb_iargs, nb_cargs;
2564c45cb8bbSRichard Henderson const TCGOpDef *def;
2565c45cb8bbSRichard Henderson TCGOpcode c;
2566bdfb460eSRichard Henderson int col = 0;
2567c45cb8bbSRichard Henderson
2568c45cb8bbSRichard Henderson c = op->opc;
2569c896fe29Sbellard def = &tcg_op_defs[c];
2570c45cb8bbSRichard Henderson
2571765b842aSRichard Henderson if (c == INDEX_op_insn_start) {
2572b016486eSRichard Henderson nb_oargs = 0;
2573b7a83ff8SRichard Henderson col += ne_fprintf(f, "\n ----");
25749aef40edSRichard Henderson
2575747bd69dSRichard Henderson for (i = 0, k = s->insn_start_words; i < k; ++i) {
2576c9ad8d27SRichard Henderson col += ne_fprintf(f, " %016" PRIx64,
2577c9ad8d27SRichard Henderson tcg_get_insn_start_param(op, i));
2578eeacee4dSBlue Swirl }
25797e4597d7Sbellard } else if (c == INDEX_op_call) {
25803e92aa34SRichard Henderson const TCGHelperInfo *info = tcg_call_info(op);
2581fa52e660SRichard Henderson void *func = tcg_call_func(op);
25823e92aa34SRichard Henderson
2583c896fe29Sbellard /* variable number of arguments */
2584cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op);
2585cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op);
2586c896fe29Sbellard nb_cargs = def->nb_cargs;
2587b03cce8eSbellard
2588b7a83ff8SRichard Henderson col += ne_fprintf(f, " %s ", def->name);
25893e92aa34SRichard Henderson
25903e92aa34SRichard Henderson /*
25913e92aa34SRichard Henderson * Print the function name from TCGHelperInfo, if available.
25923e92aa34SRichard Henderson * Note that plugins have a template function for the info,
25933e92aa34SRichard Henderson * but the actual function pointer comes from the plugin.
25943e92aa34SRichard Henderson */
25953e92aa34SRichard Henderson if (func == info->func) {
2596b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s", info->name);
25973e92aa34SRichard Henderson } else {
2598b7a83ff8SRichard Henderson col += ne_fprintf(f, "plugin(%p)", func);
25993e92aa34SRichard Henderson }
26003e92aa34SRichard Henderson
2601b7a83ff8SRichard Henderson col += ne_fprintf(f, ",$0x%x,$%d", info->flags, nb_oargs);
2602b03cce8eSbellard for (i = 0; i < nb_oargs; i++) {
2603b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", tcg_get_arg_str(s, buf, sizeof(buf),
2604efee3746SRichard Henderson op->args[i]));
2605b03cce8eSbellard }
2606cf066674SRichard Henderson for (i = 0; i < nb_iargs; i++) {
2607efee3746SRichard Henderson TCGArg arg = op->args[nb_oargs + i];
260839004a71SRichard Henderson const char *t = tcg_get_arg_str(s, buf, sizeof(buf), arg);
2609b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", t);
2610e8996ee0Sbellard }
2611b03cce8eSbellard } else {
2612b7a83ff8SRichard Henderson col += ne_fprintf(f, " %s ", def->name);
2613c45cb8bbSRichard Henderson
2614c896fe29Sbellard nb_oargs = def->nb_oargs;
2615c896fe29Sbellard nb_iargs = def->nb_iargs;
2616c896fe29Sbellard nb_cargs = def->nb_cargs;
2617c896fe29Sbellard
2618d2fd745fSRichard Henderson if (def->flags & TCG_OPF_VECTOR) {
2619b7a83ff8SRichard Henderson col += ne_fprintf(f, "v%d,e%d,", 64 << TCGOP_VECL(op),
2620d2fd745fSRichard Henderson 8 << TCGOP_VECE(op));
2621d2fd745fSRichard Henderson }
2622d2fd745fSRichard Henderson
2623c896fe29Sbellard k = 0;
2624c896fe29Sbellard for (i = 0; i < nb_oargs; i++) {
2625b7a83ff8SRichard Henderson const char *sep = k ? "," : "";
2626b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s%s", sep,
2627b7a83ff8SRichard Henderson tcg_get_arg_str(s, buf, sizeof(buf),
2628efee3746SRichard Henderson op->args[k++]));
2629c896fe29Sbellard }
2630c896fe29Sbellard for (i = 0; i < nb_iargs; i++) {
2631b7a83ff8SRichard Henderson const char *sep = k ? "," : "";
2632b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s%s", sep,
2633b7a83ff8SRichard Henderson tcg_get_arg_str(s, buf, sizeof(buf),
2634efee3746SRichard Henderson op->args[k++]));
2635c896fe29Sbellard }
2636be210acbSRichard Henderson switch (c) {
2637be210acbSRichard Henderson case INDEX_op_brcond_i32:
2638ffc5ea09SRichard Henderson case INDEX_op_setcond_i32:
26393635502dSRichard Henderson case INDEX_op_negsetcond_i32:
2640ffc5ea09SRichard Henderson case INDEX_op_movcond_i32:
2641be210acbSRichard Henderson case INDEX_op_brcond2_i32:
2642be210acbSRichard Henderson case INDEX_op_setcond2_i32:
2643ffc5ea09SRichard Henderson case INDEX_op_brcond_i64:
2644be210acbSRichard Henderson case INDEX_op_setcond_i64:
26453635502dSRichard Henderson case INDEX_op_negsetcond_i64:
2646ffc5ea09SRichard Henderson case INDEX_op_movcond_i64:
2647212be173SRichard Henderson case INDEX_op_cmp_vec:
2648f75da298SRichard Henderson case INDEX_op_cmpsel_vec:
2649efee3746SRichard Henderson if (op->args[k] < ARRAY_SIZE(cond_name)
2650efee3746SRichard Henderson && cond_name[op->args[k]]) {
2651b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", cond_name[op->args[k++]]);
2652eeacee4dSBlue Swirl } else {
2653b7a83ff8SRichard Henderson col += ne_fprintf(f, ",$0x%" TCG_PRIlx, op->args[k++]);
2654eeacee4dSBlue Swirl }
2655f48f3edeSblueswir1 i = 1;
2656be210acbSRichard Henderson break;
2657fecccfccSRichard Henderson case INDEX_op_qemu_ld_a32_i32:
2658fecccfccSRichard Henderson case INDEX_op_qemu_ld_a64_i32:
2659fecccfccSRichard Henderson case INDEX_op_qemu_st_a32_i32:
2660fecccfccSRichard Henderson case INDEX_op_qemu_st_a64_i32:
2661fecccfccSRichard Henderson case INDEX_op_qemu_st8_a32_i32:
2662fecccfccSRichard Henderson case INDEX_op_qemu_st8_a64_i32:
2663fecccfccSRichard Henderson case INDEX_op_qemu_ld_a32_i64:
2664fecccfccSRichard Henderson case INDEX_op_qemu_ld_a64_i64:
2665fecccfccSRichard Henderson case INDEX_op_qemu_st_a32_i64:
2666fecccfccSRichard Henderson case INDEX_op_qemu_st_a64_i64:
2667fecccfccSRichard Henderson case INDEX_op_qemu_ld_a32_i128:
2668fecccfccSRichard Henderson case INDEX_op_qemu_ld_a64_i128:
2669fecccfccSRichard Henderson case INDEX_op_qemu_st_a32_i128:
2670fecccfccSRichard Henderson case INDEX_op_qemu_st_a64_i128:
267159227d5dSRichard Henderson {
267237031fefSRichard Henderson const char *s_al, *s_op, *s_at;
26739002ffcbSRichard Henderson MemOpIdx oi = op->args[k++];
26749a239c6eSPhilippe Mathieu-Daudé MemOp mop = get_memop(oi);
267559227d5dSRichard Henderson unsigned ix = get_mmuidx(oi);
267659227d5dSRichard Henderson
26779a239c6eSPhilippe Mathieu-Daudé s_al = alignment_name[(mop & MO_AMASK) >> MO_ASHIFT];
26789a239c6eSPhilippe Mathieu-Daudé s_op = ldst_name[mop & (MO_BSWAP | MO_SSIZE)];
26799a239c6eSPhilippe Mathieu-Daudé s_at = atom_name[(mop & MO_ATOM_MASK) >> MO_ATOM_SHIFT];
26809a239c6eSPhilippe Mathieu-Daudé mop &= ~(MO_AMASK | MO_BSWAP | MO_SSIZE | MO_ATOM_MASK);
268137031fefSRichard Henderson
268237031fefSRichard Henderson /* If all fields are accounted for, print symbolically. */
26839a239c6eSPhilippe Mathieu-Daudé if (!mop && s_al && s_op && s_at) {
268437031fefSRichard Henderson col += ne_fprintf(f, ",%s%s%s,%u",
268537031fefSRichard Henderson s_at, s_al, s_op, ix);
268637031fefSRichard Henderson } else {
26879a239c6eSPhilippe Mathieu-Daudé mop = get_memop(oi);
26889a239c6eSPhilippe Mathieu-Daudé col += ne_fprintf(f, ",$0x%x,%u", mop, ix);
2689f713d6adSRichard Henderson }
2690f713d6adSRichard Henderson i = 1;
269159227d5dSRichard Henderson }
2692f713d6adSRichard Henderson break;
2693587195bdSRichard Henderson case INDEX_op_bswap16_i32:
2694587195bdSRichard Henderson case INDEX_op_bswap16_i64:
2695587195bdSRichard Henderson case INDEX_op_bswap32_i32:
2696587195bdSRichard Henderson case INDEX_op_bswap32_i64:
2697587195bdSRichard Henderson case INDEX_op_bswap64_i64:
2698587195bdSRichard Henderson {
2699587195bdSRichard Henderson TCGArg flags = op->args[k];
2700587195bdSRichard Henderson const char *name = NULL;
2701587195bdSRichard Henderson
2702587195bdSRichard Henderson if (flags < ARRAY_SIZE(bswap_flag_name)) {
2703587195bdSRichard Henderson name = bswap_flag_name[flags];
2704587195bdSRichard Henderson }
2705587195bdSRichard Henderson if (name) {
2706b7a83ff8SRichard Henderson col += ne_fprintf(f, ",%s", name);
2707587195bdSRichard Henderson } else {
2708b7a83ff8SRichard Henderson col += ne_fprintf(f, ",$0x%" TCG_PRIlx, flags);
2709587195bdSRichard Henderson }
2710587195bdSRichard Henderson i = k = 1;
2711587195bdSRichard Henderson }
2712587195bdSRichard Henderson break;
2713b384c734SRichard Henderson #ifdef CONFIG_PLUGIN
2714b384c734SRichard Henderson case INDEX_op_plugin_cb:
2715b384c734SRichard Henderson {
2716b384c734SRichard Henderson TCGArg from = op->args[k++];
2717b384c734SRichard Henderson const char *name = NULL;
2718b384c734SRichard Henderson
2719b384c734SRichard Henderson if (from < ARRAY_SIZE(plugin_from_name)) {
2720b384c734SRichard Henderson name = plugin_from_name[from];
2721b384c734SRichard Henderson }
2722b384c734SRichard Henderson if (name) {
2723b384c734SRichard Henderson col += ne_fprintf(f, "%s", name);
2724b384c734SRichard Henderson } else {
2725b384c734SRichard Henderson col += ne_fprintf(f, "$0x%" TCG_PRIlx, from);
2726b384c734SRichard Henderson }
2727b384c734SRichard Henderson i = 1;
2728b384c734SRichard Henderson }
2729b384c734SRichard Henderson break;
2730b384c734SRichard Henderson #endif
2731be210acbSRichard Henderson default:
2732f48f3edeSblueswir1 i = 0;
2733be210acbSRichard Henderson break;
2734be210acbSRichard Henderson }
273551e3972cSRichard Henderson switch (c) {
273651e3972cSRichard Henderson case INDEX_op_set_label:
273751e3972cSRichard Henderson case INDEX_op_br:
273851e3972cSRichard Henderson case INDEX_op_brcond_i32:
273951e3972cSRichard Henderson case INDEX_op_brcond_i64:
274051e3972cSRichard Henderson case INDEX_op_brcond2_i32:
2741b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s$L%d", k ? "," : "",
2742efee3746SRichard Henderson arg_label(op->args[k])->id);
274351e3972cSRichard Henderson i++, k++;
274451e3972cSRichard Henderson break;
27453470867bSRichard Henderson case INDEX_op_mb:
27463470867bSRichard Henderson {
27473470867bSRichard Henderson TCGBar membar = op->args[k];
27483470867bSRichard Henderson const char *b_op, *m_op;
27493470867bSRichard Henderson
27503470867bSRichard Henderson switch (membar & TCG_BAR_SC) {
27513470867bSRichard Henderson case 0:
27523470867bSRichard Henderson b_op = "none";
27533470867bSRichard Henderson break;
27543470867bSRichard Henderson case TCG_BAR_LDAQ:
27553470867bSRichard Henderson b_op = "acq";
27563470867bSRichard Henderson break;
27573470867bSRichard Henderson case TCG_BAR_STRL:
27583470867bSRichard Henderson b_op = "rel";
27593470867bSRichard Henderson break;
27603470867bSRichard Henderson case TCG_BAR_SC:
27613470867bSRichard Henderson b_op = "seq";
27623470867bSRichard Henderson break;
27633470867bSRichard Henderson default:
27643470867bSRichard Henderson g_assert_not_reached();
27653470867bSRichard Henderson }
27663470867bSRichard Henderson
27673470867bSRichard Henderson switch (membar & TCG_MO_ALL) {
27683470867bSRichard Henderson case 0:
27693470867bSRichard Henderson m_op = "none";
27703470867bSRichard Henderson break;
27713470867bSRichard Henderson case TCG_MO_LD_LD:
27723470867bSRichard Henderson m_op = "rr";
27733470867bSRichard Henderson break;
27743470867bSRichard Henderson case TCG_MO_LD_ST:
27753470867bSRichard Henderson m_op = "rw";
27763470867bSRichard Henderson break;
27773470867bSRichard Henderson case TCG_MO_ST_LD:
27783470867bSRichard Henderson m_op = "wr";
27793470867bSRichard Henderson break;
27803470867bSRichard Henderson case TCG_MO_ST_ST:
27813470867bSRichard Henderson m_op = "ww";
27823470867bSRichard Henderson break;
27833470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_LD_ST:
27843470867bSRichard Henderson m_op = "rr+rw";
27853470867bSRichard Henderson break;
27863470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_ST_LD:
27873470867bSRichard Henderson m_op = "rr+wr";
27883470867bSRichard Henderson break;
27893470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_ST_ST:
27903470867bSRichard Henderson m_op = "rr+ww";
27913470867bSRichard Henderson break;
27923470867bSRichard Henderson case TCG_MO_LD_ST | TCG_MO_ST_LD:
27933470867bSRichard Henderson m_op = "rw+wr";
27943470867bSRichard Henderson break;
27953470867bSRichard Henderson case TCG_MO_LD_ST | TCG_MO_ST_ST:
27963470867bSRichard Henderson m_op = "rw+ww";
27973470867bSRichard Henderson break;
27983470867bSRichard Henderson case TCG_MO_ST_LD | TCG_MO_ST_ST:
27993470867bSRichard Henderson m_op = "wr+ww";
28003470867bSRichard Henderson break;
28013470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_MO_ST_LD:
28023470867bSRichard Henderson m_op = "rr+rw+wr";
28033470867bSRichard Henderson break;
28043470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_MO_ST_ST:
28053470867bSRichard Henderson m_op = "rr+rw+ww";
28063470867bSRichard Henderson break;
28073470867bSRichard Henderson case TCG_MO_LD_LD | TCG_MO_ST_LD | TCG_MO_ST_ST:
28083470867bSRichard Henderson m_op = "rr+wr+ww";
28093470867bSRichard Henderson break;
28103470867bSRichard Henderson case TCG_MO_LD_ST | TCG_MO_ST_LD | TCG_MO_ST_ST:
28113470867bSRichard Henderson m_op = "rw+wr+ww";
28123470867bSRichard Henderson break;
28133470867bSRichard Henderson case TCG_MO_ALL:
28143470867bSRichard Henderson m_op = "all";
28153470867bSRichard Henderson break;
28163470867bSRichard Henderson default:
28173470867bSRichard Henderson g_assert_not_reached();
28183470867bSRichard Henderson }
28193470867bSRichard Henderson
28203470867bSRichard Henderson col += ne_fprintf(f, "%s%s:%s", (k ? "," : ""), b_op, m_op);
28213470867bSRichard Henderson i++, k++;
28223470867bSRichard Henderson }
28233470867bSRichard Henderson break;
282451e3972cSRichard Henderson default:
282551e3972cSRichard Henderson break;
2826eeacee4dSBlue Swirl }
282751e3972cSRichard Henderson for (; i < nb_cargs; i++, k++) {
2828b7a83ff8SRichard Henderson col += ne_fprintf(f, "%s$0x%" TCG_PRIlx, k ? "," : "",
2829b7a83ff8SRichard Henderson op->args[k]);
2830bdfb460eSRichard Henderson }
2831bdfb460eSRichard Henderson }
2832bdfb460eSRichard Henderson
28331894f69aSRichard Henderson if (have_prefs || op->life) {
28341894f69aSRichard Henderson for (; col < 40; ++col) {
2835b7a83ff8SRichard Henderson putc(' ', f);
2836bdfb460eSRichard Henderson }
28371894f69aSRichard Henderson }
28381894f69aSRichard Henderson
28391894f69aSRichard Henderson if (op->life) {
28401894f69aSRichard Henderson unsigned life = op->life;
2841bdfb460eSRichard Henderson
2842bdfb460eSRichard Henderson if (life & (SYNC_ARG * 3)) {
2843b7a83ff8SRichard Henderson ne_fprintf(f, " sync:");
2844bdfb460eSRichard Henderson for (i = 0; i < 2; ++i) {
2845bdfb460eSRichard Henderson if (life & (SYNC_ARG << i)) {
2846b7a83ff8SRichard Henderson ne_fprintf(f, " %d", i);
2847bdfb460eSRichard Henderson }
2848bdfb460eSRichard Henderson }
2849bdfb460eSRichard Henderson }
2850bdfb460eSRichard Henderson life /= DEAD_ARG;
2851bdfb460eSRichard Henderson if (life) {
2852b7a83ff8SRichard Henderson ne_fprintf(f, " dead:");
2853bdfb460eSRichard Henderson for (i = 0; life; ++i, life >>= 1) {
2854bdfb460eSRichard Henderson if (life & 1) {
2855b7a83ff8SRichard Henderson ne_fprintf(f, " %d", i);
2856bdfb460eSRichard Henderson }
2857bdfb460eSRichard Henderson }
2858c896fe29Sbellard }
2859b03cce8eSbellard }
28601894f69aSRichard Henderson
28611894f69aSRichard Henderson if (have_prefs) {
28621894f69aSRichard Henderson for (i = 0; i < nb_oargs; ++i) {
286331fd884bSRichard Henderson TCGRegSet set = output_pref(op, i);
28641894f69aSRichard Henderson
28651894f69aSRichard Henderson if (i == 0) {
2866b7a83ff8SRichard Henderson ne_fprintf(f, " pref=");
28671894f69aSRichard Henderson } else {
2868b7a83ff8SRichard Henderson ne_fprintf(f, ",");
28691894f69aSRichard Henderson }
28701894f69aSRichard Henderson if (set == 0) {
2871b7a83ff8SRichard Henderson ne_fprintf(f, "none");
28721894f69aSRichard Henderson } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) {
2873b7a83ff8SRichard Henderson ne_fprintf(f, "all");
28741894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG
28751894f69aSRichard Henderson } else if (tcg_regset_single(set)) {
28761894f69aSRichard Henderson TCGReg reg = tcg_regset_first(set);
2877b7a83ff8SRichard Henderson ne_fprintf(f, "%s", tcg_target_reg_names[reg]);
28781894f69aSRichard Henderson #endif
28791894f69aSRichard Henderson } else if (TCG_TARGET_NB_REGS <= 32) {
2880b7a83ff8SRichard Henderson ne_fprintf(f, "0x%x", (uint32_t)set);
28811894f69aSRichard Henderson } else {
2882b7a83ff8SRichard Henderson ne_fprintf(f, "0x%" PRIx64, (uint64_t)set);
28831894f69aSRichard Henderson }
28841894f69aSRichard Henderson }
28851894f69aSRichard Henderson }
28861894f69aSRichard Henderson
2887b7a83ff8SRichard Henderson putc('\n', f);
2888c896fe29Sbellard }
2889c896fe29Sbellard }
2890c896fe29Sbellard
2891c896fe29Sbellard /* we give more priority to constraints with less registers */
get_constraint_priority(const TCGOpDef * def,int k)2892c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k)
2893c896fe29Sbellard {
289474a11790SRichard Henderson const TCGArgConstraint *arg_ct = &def->args_ct[k];
289529f5e925SRichard Henderson int n = ctpop64(arg_ct->regs);
2896c896fe29Sbellard
289729f5e925SRichard Henderson /*
289829f5e925SRichard Henderson * Sort constraints of a single register first, which includes output
289929f5e925SRichard Henderson * aliases (which must exactly match the input already allocated).
290029f5e925SRichard Henderson */
290129f5e925SRichard Henderson if (n == 1 || arg_ct->oalias) {
290229f5e925SRichard Henderson return INT_MAX;
2903c896fe29Sbellard }
290429f5e925SRichard Henderson
290529f5e925SRichard Henderson /*
290629f5e925SRichard Henderson * Sort register pairs next, first then second immediately after.
290729f5e925SRichard Henderson * Arbitrarily sort multiple pairs by the index of the first reg;
290829f5e925SRichard Henderson * there shouldn't be many pairs.
290929f5e925SRichard Henderson */
291029f5e925SRichard Henderson switch (arg_ct->pair) {
291129f5e925SRichard Henderson case 1:
291229f5e925SRichard Henderson case 3:
291329f5e925SRichard Henderson return (k + 1) * 2;
291429f5e925SRichard Henderson case 2:
291529f5e925SRichard Henderson return (arg_ct->pair_index + 1) * 2 - 1;
291629f5e925SRichard Henderson }
291729f5e925SRichard Henderson
291829f5e925SRichard Henderson /* Finally, sort by decreasing register count. */
291929f5e925SRichard Henderson assert(n > 1);
292029f5e925SRichard Henderson return -n;
2921c896fe29Sbellard }
2922c896fe29Sbellard
2923c896fe29Sbellard /* sort from highest priority to lowest */
sort_constraints(TCGOpDef * def,int start,int n)2924c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n)
2925c896fe29Sbellard {
292666792f90SRichard Henderson int i, j;
292766792f90SRichard Henderson TCGArgConstraint *a = def->args_ct;
2928c896fe29Sbellard
292966792f90SRichard Henderson for (i = 0; i < n; i++) {
293066792f90SRichard Henderson a[start + i].sort_index = start + i;
293166792f90SRichard Henderson }
293266792f90SRichard Henderson if (n <= 1) {
2933c896fe29Sbellard return;
293466792f90SRichard Henderson }
2935c896fe29Sbellard for (i = 0; i < n - 1; i++) {
2936c896fe29Sbellard for (j = i + 1; j < n; j++) {
293766792f90SRichard Henderson int p1 = get_constraint_priority(def, a[start + i].sort_index);
293866792f90SRichard Henderson int p2 = get_constraint_priority(def, a[start + j].sort_index);
2939c896fe29Sbellard if (p1 < p2) {
294066792f90SRichard Henderson int tmp = a[start + i].sort_index;
294166792f90SRichard Henderson a[start + i].sort_index = a[start + j].sort_index;
294266792f90SRichard Henderson a[start + j].sort_index = tmp;
2943c896fe29Sbellard }
2944c896fe29Sbellard }
2945c896fe29Sbellard }
2946c896fe29Sbellard }
2947c896fe29Sbellard
process_op_defs(TCGContext * s)2948f69d277eSRichard Henderson static void process_op_defs(TCGContext *s)
2949c896fe29Sbellard {
2950a9751609SRichard Henderson TCGOpcode op;
2951c896fe29Sbellard
2952f69d277eSRichard Henderson for (op = 0; op < NB_OPS; op++) {
2953f69d277eSRichard Henderson TCGOpDef *def = &tcg_op_defs[op];
2954f69d277eSRichard Henderson const TCGTargetOpDef *tdefs;
295529f5e925SRichard Henderson bool saw_alias_pair = false;
295629f5e925SRichard Henderson int i, o, i2, o2, nb_args;
2957f69d277eSRichard Henderson
2958f69d277eSRichard Henderson if (def->flags & TCG_OPF_NOT_PRESENT) {
2959f69d277eSRichard Henderson continue;
2960f69d277eSRichard Henderson }
2961f69d277eSRichard Henderson
2962c896fe29Sbellard nb_args = def->nb_iargs + def->nb_oargs;
2963f69d277eSRichard Henderson if (nb_args == 0) {
2964f69d277eSRichard Henderson continue;
2965f69d277eSRichard Henderson }
2966f69d277eSRichard Henderson
29674c22e840SRichard Henderson /*
29684c22e840SRichard Henderson * Macro magic should make it impossible, but double-check that
29694c22e840SRichard Henderson * the array index is in range. Since the signness of an enum
29704c22e840SRichard Henderson * is implementation defined, force the result to unsigned.
29714c22e840SRichard Henderson */
29724c22e840SRichard Henderson unsigned con_set = tcg_target_op_def(op);
29734c22e840SRichard Henderson tcg_debug_assert(con_set < ARRAY_SIZE(constraint_sets));
29744c22e840SRichard Henderson tdefs = &constraint_sets[con_set];
2975f69d277eSRichard Henderson
2976c896fe29Sbellard for (i = 0; i < nb_args; i++) {
2977f69d277eSRichard Henderson const char *ct_str = tdefs->args_ct_str[i];
29788940ea0dSPhilippe Mathieu-Daudé bool input_p = i >= def->nb_oargs;
29798940ea0dSPhilippe Mathieu-Daudé
2980f69d277eSRichard Henderson /* Incomplete TCGTargetOpDef entry. */
2981eabb7b91SAurelien Jarno tcg_debug_assert(ct_str != NULL);
2982f69d277eSRichard Henderson
298317280ff4SRichard Henderson switch (*ct_str) {
298417280ff4SRichard Henderson case '0' ... '9':
29858940ea0dSPhilippe Mathieu-Daudé o = *ct_str - '0';
29868940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(input_p);
29878940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(o < def->nb_oargs);
29888940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(def->args_ct[o].regs != 0);
29898940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(!def->args_ct[o].oalias);
29908940ea0dSPhilippe Mathieu-Daudé def->args_ct[i] = def->args_ct[o];
2991bc2b17e6SRichard Henderson /* The output sets oalias. */
29928940ea0dSPhilippe Mathieu-Daudé def->args_ct[o].oalias = 1;
29938940ea0dSPhilippe Mathieu-Daudé def->args_ct[o].alias_index = i;
2994bc2b17e6SRichard Henderson /* The input sets ialias. */
29958940ea0dSPhilippe Mathieu-Daudé def->args_ct[i].ialias = 1;
29968940ea0dSPhilippe Mathieu-Daudé def->args_ct[i].alias_index = o;
299729f5e925SRichard Henderson if (def->args_ct[i].pair) {
299829f5e925SRichard Henderson saw_alias_pair = true;
299929f5e925SRichard Henderson }
30008940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(ct_str[1] == '\0');
30018940ea0dSPhilippe Mathieu-Daudé continue;
30028940ea0dSPhilippe Mathieu-Daudé
300382790a87SRichard Henderson case '&':
30048940ea0dSPhilippe Mathieu-Daudé tcg_debug_assert(!input_p);
3005bc2b17e6SRichard Henderson def->args_ct[i].newreg = true;
300682790a87SRichard Henderson ct_str++;
300782790a87SRichard Henderson break;
300829f5e925SRichard Henderson
300929f5e925SRichard Henderson case 'p': /* plus */
301029f5e925SRichard Henderson /* Allocate to the register after the previous. */
301129f5e925SRichard Henderson tcg_debug_assert(i > (input_p ? def->nb_oargs : 0));
301229f5e925SRichard Henderson o = i - 1;
301329f5e925SRichard Henderson tcg_debug_assert(!def->args_ct[o].pair);
301429f5e925SRichard Henderson tcg_debug_assert(!def->args_ct[o].ct);
301529f5e925SRichard Henderson def->args_ct[i] = (TCGArgConstraint){
301629f5e925SRichard Henderson .pair = 2,
301729f5e925SRichard Henderson .pair_index = o,
301829f5e925SRichard Henderson .regs = def->args_ct[o].regs << 1,
3019ca5bed07SRichard Henderson .newreg = def->args_ct[o].newreg,
302029f5e925SRichard Henderson };
302129f5e925SRichard Henderson def->args_ct[o].pair = 1;
302229f5e925SRichard Henderson def->args_ct[o].pair_index = i;
302329f5e925SRichard Henderson tcg_debug_assert(ct_str[1] == '\0');
302429f5e925SRichard Henderson continue;
302529f5e925SRichard Henderson
302629f5e925SRichard Henderson case 'm': /* minus */
302729f5e925SRichard Henderson /* Allocate to the register before the previous. */
302829f5e925SRichard Henderson tcg_debug_assert(i > (input_p ? def->nb_oargs : 0));
302929f5e925SRichard Henderson o = i - 1;
303029f5e925SRichard Henderson tcg_debug_assert(!def->args_ct[o].pair);
303129f5e925SRichard Henderson tcg_debug_assert(!def->args_ct[o].ct);
303229f5e925SRichard Henderson def->args_ct[i] = (TCGArgConstraint){
303329f5e925SRichard Henderson .pair = 1,
303429f5e925SRichard Henderson .pair_index = o,
303529f5e925SRichard Henderson .regs = def->args_ct[o].regs >> 1,
3036ca5bed07SRichard Henderson .newreg = def->args_ct[o].newreg,
303729f5e925SRichard Henderson };
303829f5e925SRichard Henderson def->args_ct[o].pair = 2;
303929f5e925SRichard Henderson def->args_ct[o].pair_index = i;
304029f5e925SRichard Henderson tcg_debug_assert(ct_str[1] == '\0');
304129f5e925SRichard Henderson continue;
30428940ea0dSPhilippe Mathieu-Daudé }
30438940ea0dSPhilippe Mathieu-Daudé
30448940ea0dSPhilippe Mathieu-Daudé do {
30458940ea0dSPhilippe Mathieu-Daudé switch (*ct_str) {
3046c896fe29Sbellard case 'i':
3047c896fe29Sbellard def->args_ct[i].ct |= TCG_CT_CONST;
3048c896fe29Sbellard break;
3049358b4923SRichard Henderson
3050358b4923SRichard Henderson /* Include all of the target-specific constraints. */
3051358b4923SRichard Henderson
3052358b4923SRichard Henderson #undef CONST
3053358b4923SRichard Henderson #define CONST(CASE, MASK) \
30548940ea0dSPhilippe Mathieu-Daudé case CASE: def->args_ct[i].ct |= MASK; break;
3055358b4923SRichard Henderson #define REGS(CASE, MASK) \
30568940ea0dSPhilippe Mathieu-Daudé case CASE: def->args_ct[i].regs |= MASK; break;
3057358b4923SRichard Henderson
3058358b4923SRichard Henderson #include "tcg-target-con-str.h"
3059358b4923SRichard Henderson
3060358b4923SRichard Henderson #undef REGS
3061358b4923SRichard Henderson #undef CONST
3062c896fe29Sbellard default:
30638940ea0dSPhilippe Mathieu-Daudé case '0' ... '9':
30648940ea0dSPhilippe Mathieu-Daudé case '&':
306529f5e925SRichard Henderson case 'p':
306629f5e925SRichard Henderson case 'm':
3067358b4923SRichard Henderson /* Typo in TCGTargetOpDef constraint. */
3068358b4923SRichard Henderson g_assert_not_reached();
3069358b4923SRichard Henderson }
30708940ea0dSPhilippe Mathieu-Daudé } while (*++ct_str != '\0');
3071c896fe29Sbellard }
3072c896fe29Sbellard
3073c68aaa18SStefan Weil /* TCGTargetOpDef entry with too much information? */
3074eabb7b91SAurelien Jarno tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
3075c68aaa18SStefan Weil
307629f5e925SRichard Henderson /*
307729f5e925SRichard Henderson * Fix up output pairs that are aliased with inputs.
307829f5e925SRichard Henderson * When we created the alias, we copied pair from the output.
307929f5e925SRichard Henderson * There are three cases:
308029f5e925SRichard Henderson * (1a) Pairs of inputs alias pairs of outputs.
308129f5e925SRichard Henderson * (1b) One input aliases the first of a pair of outputs.
308229f5e925SRichard Henderson * (2) One input aliases the second of a pair of outputs.
308329f5e925SRichard Henderson *
308429f5e925SRichard Henderson * Case 1a is handled by making sure that the pair_index'es are
308529f5e925SRichard Henderson * properly updated so that they appear the same as a pair of inputs.
308629f5e925SRichard Henderson *
308729f5e925SRichard Henderson * Case 1b is handled by setting the pair_index of the input to
308829f5e925SRichard Henderson * itself, simply so it doesn't point to an unrelated argument.
308929f5e925SRichard Henderson * Since we don't encounter the "second" during the input allocation
309029f5e925SRichard Henderson * phase, nothing happens with the second half of the input pair.
309129f5e925SRichard Henderson *
309229f5e925SRichard Henderson * Case 2 is handled by setting the second input to pair=3, the
309329f5e925SRichard Henderson * first output to pair=3, and the pair_index'es to match.
309429f5e925SRichard Henderson */
309529f5e925SRichard Henderson if (saw_alias_pair) {
309629f5e925SRichard Henderson for (i = def->nb_oargs; i < nb_args; i++) {
309729f5e925SRichard Henderson /*
309829f5e925SRichard Henderson * Since [0-9pm] must be alone in the constraint string,
309929f5e925SRichard Henderson * the only way they can both be set is if the pair comes
310029f5e925SRichard Henderson * from the output alias.
310129f5e925SRichard Henderson */
310229f5e925SRichard Henderson if (!def->args_ct[i].ialias) {
310329f5e925SRichard Henderson continue;
310429f5e925SRichard Henderson }
310529f5e925SRichard Henderson switch (def->args_ct[i].pair) {
310629f5e925SRichard Henderson case 0:
310729f5e925SRichard Henderson break;
310829f5e925SRichard Henderson case 1:
310929f5e925SRichard Henderson o = def->args_ct[i].alias_index;
311029f5e925SRichard Henderson o2 = def->args_ct[o].pair_index;
311129f5e925SRichard Henderson tcg_debug_assert(def->args_ct[o].pair == 1);
311229f5e925SRichard Henderson tcg_debug_assert(def->args_ct[o2].pair == 2);
311329f5e925SRichard Henderson if (def->args_ct[o2].oalias) {
311429f5e925SRichard Henderson /* Case 1a */
311529f5e925SRichard Henderson i2 = def->args_ct[o2].alias_index;
311629f5e925SRichard Henderson tcg_debug_assert(def->args_ct[i2].pair == 2);
311729f5e925SRichard Henderson def->args_ct[i2].pair_index = i;
311829f5e925SRichard Henderson def->args_ct[i].pair_index = i2;
311929f5e925SRichard Henderson } else {
312029f5e925SRichard Henderson /* Case 1b */
312129f5e925SRichard Henderson def->args_ct[i].pair_index = i;
312229f5e925SRichard Henderson }
312329f5e925SRichard Henderson break;
312429f5e925SRichard Henderson case 2:
312529f5e925SRichard Henderson o = def->args_ct[i].alias_index;
312629f5e925SRichard Henderson o2 = def->args_ct[o].pair_index;
312729f5e925SRichard Henderson tcg_debug_assert(def->args_ct[o].pair == 2);
312829f5e925SRichard Henderson tcg_debug_assert(def->args_ct[o2].pair == 1);
312929f5e925SRichard Henderson if (def->args_ct[o2].oalias) {
313029f5e925SRichard Henderson /* Case 1a */
313129f5e925SRichard Henderson i2 = def->args_ct[o2].alias_index;
313229f5e925SRichard Henderson tcg_debug_assert(def->args_ct[i2].pair == 1);
313329f5e925SRichard Henderson def->args_ct[i2].pair_index = i;
313429f5e925SRichard Henderson def->args_ct[i].pair_index = i2;
313529f5e925SRichard Henderson } else {
313629f5e925SRichard Henderson /* Case 2 */
313729f5e925SRichard Henderson def->args_ct[i].pair = 3;
313829f5e925SRichard Henderson def->args_ct[o2].pair = 3;
313929f5e925SRichard Henderson def->args_ct[i].pair_index = o2;
314029f5e925SRichard Henderson def->args_ct[o2].pair_index = i;
314129f5e925SRichard Henderson }
314229f5e925SRichard Henderson break;
314329f5e925SRichard Henderson default:
314429f5e925SRichard Henderson g_assert_not_reached();
314529f5e925SRichard Henderson }
314629f5e925SRichard Henderson }
314729f5e925SRichard Henderson }
314829f5e925SRichard Henderson
3149c896fe29Sbellard /* sort the constraints (XXX: this is just an heuristic) */
3150c896fe29Sbellard sort_constraints(def, 0, def->nb_oargs);
3151c896fe29Sbellard sort_constraints(def, def->nb_oargs, def->nb_iargs);
3152c896fe29Sbellard }
3153c896fe29Sbellard }
3154c896fe29Sbellard
remove_label_use(TCGOp * op,int idx)3155f85b1fc4SRichard Henderson static void remove_label_use(TCGOp *op, int idx)
3156f85b1fc4SRichard Henderson {
3157f85b1fc4SRichard Henderson TCGLabel *label = arg_label(op->args[idx]);
3158f85b1fc4SRichard Henderson TCGLabelUse *use;
3159f85b1fc4SRichard Henderson
3160f85b1fc4SRichard Henderson QSIMPLEQ_FOREACH(use, &label->branches, next) {
3161f85b1fc4SRichard Henderson if (use->op == op) {
3162f85b1fc4SRichard Henderson QSIMPLEQ_REMOVE(&label->branches, use, TCGLabelUse, next);
3163f85b1fc4SRichard Henderson return;
3164f85b1fc4SRichard Henderson }
3165f85b1fc4SRichard Henderson }
3166f85b1fc4SRichard Henderson g_assert_not_reached();
3167f85b1fc4SRichard Henderson }
3168f85b1fc4SRichard Henderson
tcg_op_remove(TCGContext * s,TCGOp * op)31690c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op)
31700c627cdcSRichard Henderson {
3171d88a117eSRichard Henderson switch (op->opc) {
3172d88a117eSRichard Henderson case INDEX_op_br:
3173f85b1fc4SRichard Henderson remove_label_use(op, 0);
3174d88a117eSRichard Henderson break;
3175d88a117eSRichard Henderson case INDEX_op_brcond_i32:
3176d88a117eSRichard Henderson case INDEX_op_brcond_i64:
3177f85b1fc4SRichard Henderson remove_label_use(op, 3);
3178d88a117eSRichard Henderson break;
3179d88a117eSRichard Henderson case INDEX_op_brcond2_i32:
3180f85b1fc4SRichard Henderson remove_label_use(op, 5);
3181d88a117eSRichard Henderson break;
3182d88a117eSRichard Henderson default:
3183d88a117eSRichard Henderson break;
3184d88a117eSRichard Henderson }
3185d88a117eSRichard Henderson
318615fa08f8SRichard Henderson QTAILQ_REMOVE(&s->ops, op, link);
318715fa08f8SRichard Henderson QTAILQ_INSERT_TAIL(&s->free_ops, op, link);
3188abebf925SRichard Henderson s->nb_ops--;
31890c627cdcSRichard Henderson }
31900c627cdcSRichard Henderson
tcg_remove_ops_after(TCGOp * op)3191a80cdd31SRichard Henderson void tcg_remove_ops_after(TCGOp *op)
3192a80cdd31SRichard Henderson {
3193a80cdd31SRichard Henderson TCGContext *s = tcg_ctx;
3194a80cdd31SRichard Henderson
3195a80cdd31SRichard Henderson while (true) {
3196a80cdd31SRichard Henderson TCGOp *last = tcg_last_op();
3197a80cdd31SRichard Henderson if (last == op) {
3198a80cdd31SRichard Henderson return;
3199a80cdd31SRichard Henderson }
3200a80cdd31SRichard Henderson tcg_op_remove(s, last);
3201a80cdd31SRichard Henderson }
3202a80cdd31SRichard Henderson }
3203a80cdd31SRichard Henderson
tcg_op_alloc(TCGOpcode opc,unsigned nargs)3204d4478943SPhilippe Mathieu-Daudé static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs)
320515fa08f8SRichard Henderson {
320615fa08f8SRichard Henderson TCGContext *s = tcg_ctx;
3207cb10bc63SRichard Henderson TCGOp *op = NULL;
320815fa08f8SRichard Henderson
3209cb10bc63SRichard Henderson if (unlikely(!QTAILQ_EMPTY(&s->free_ops))) {
3210cb10bc63SRichard Henderson QTAILQ_FOREACH(op, &s->free_ops, link) {
3211cb10bc63SRichard Henderson if (nargs <= op->nargs) {
321215fa08f8SRichard Henderson QTAILQ_REMOVE(&s->free_ops, op, link);
3213cb10bc63SRichard Henderson nargs = op->nargs;
3214cb10bc63SRichard Henderson goto found;
321515fa08f8SRichard Henderson }
3216cb10bc63SRichard Henderson }
3217cb10bc63SRichard Henderson }
3218cb10bc63SRichard Henderson
3219cb10bc63SRichard Henderson /* Most opcodes have 3 or 4 operands: reduce fragmentation. */
3220cb10bc63SRichard Henderson nargs = MAX(4, nargs);
3221cb10bc63SRichard Henderson op = tcg_malloc(sizeof(TCGOp) + sizeof(TCGArg) * nargs);
3222cb10bc63SRichard Henderson
3223cb10bc63SRichard Henderson found:
322415fa08f8SRichard Henderson memset(op, 0, offsetof(TCGOp, link));
322515fa08f8SRichard Henderson op->opc = opc;
3226cb10bc63SRichard Henderson op->nargs = nargs;
322715fa08f8SRichard Henderson
3228cb10bc63SRichard Henderson /* Check for bitfield overflow. */
3229cb10bc63SRichard Henderson tcg_debug_assert(op->nargs == nargs);
3230cb10bc63SRichard Henderson
3231cb10bc63SRichard Henderson s->nb_ops++;
323215fa08f8SRichard Henderson return op;
323315fa08f8SRichard Henderson }
323415fa08f8SRichard Henderson
tcg_emit_op(TCGOpcode opc,unsigned nargs)3235d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_emit_op(TCGOpcode opc, unsigned nargs)
323615fa08f8SRichard Henderson {
3237d4478943SPhilippe Mathieu-Daudé TCGOp *op = tcg_op_alloc(opc, nargs);
323807843f75SRichard Henderson
323907843f75SRichard Henderson if (tcg_ctx->emit_before_op) {
324007843f75SRichard Henderson QTAILQ_INSERT_BEFORE(tcg_ctx->emit_before_op, op, link);
324107843f75SRichard Henderson } else {
324215fa08f8SRichard Henderson QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
324307843f75SRichard Henderson }
324415fa08f8SRichard Henderson return op;
324515fa08f8SRichard Henderson }
324615fa08f8SRichard Henderson
tcg_op_insert_before(TCGContext * s,TCGOp * old_op,TCGOpcode opc,unsigned nargs)3247d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op,
3248d4478943SPhilippe Mathieu-Daudé TCGOpcode opc, unsigned nargs)
32495a18407fSRichard Henderson {
3250d4478943SPhilippe Mathieu-Daudé TCGOp *new_op = tcg_op_alloc(opc, nargs);
325115fa08f8SRichard Henderson QTAILQ_INSERT_BEFORE(old_op, new_op, link);
32525a18407fSRichard Henderson return new_op;
32535a18407fSRichard Henderson }
32545a18407fSRichard Henderson
tcg_op_insert_after(TCGContext * s,TCGOp * old_op,TCGOpcode opc,unsigned nargs)3255d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op,
3256d4478943SPhilippe Mathieu-Daudé TCGOpcode opc, unsigned nargs)
32575a18407fSRichard Henderson {
3258d4478943SPhilippe Mathieu-Daudé TCGOp *new_op = tcg_op_alloc(opc, nargs);
325915fa08f8SRichard Henderson QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link);
32605a18407fSRichard Henderson return new_op;
32615a18407fSRichard Henderson }
32625a18407fSRichard Henderson
move_label_uses(TCGLabel * to,TCGLabel * from)3263968f305eSRichard Henderson static void move_label_uses(TCGLabel *to, TCGLabel *from)
3264968f305eSRichard Henderson {
3265968f305eSRichard Henderson TCGLabelUse *u;
3266968f305eSRichard Henderson
3267968f305eSRichard Henderson QSIMPLEQ_FOREACH(u, &from->branches, next) {
3268968f305eSRichard Henderson TCGOp *op = u->op;
3269968f305eSRichard Henderson switch (op->opc) {
3270968f305eSRichard Henderson case INDEX_op_br:
3271968f305eSRichard Henderson op->args[0] = label_arg(to);
3272968f305eSRichard Henderson break;
3273968f305eSRichard Henderson case INDEX_op_brcond_i32:
3274968f305eSRichard Henderson case INDEX_op_brcond_i64:
3275968f305eSRichard Henderson op->args[3] = label_arg(to);
3276968f305eSRichard Henderson break;
3277968f305eSRichard Henderson case INDEX_op_brcond2_i32:
3278968f305eSRichard Henderson op->args[5] = label_arg(to);
3279968f305eSRichard Henderson break;
3280968f305eSRichard Henderson default:
3281968f305eSRichard Henderson g_assert_not_reached();
3282968f305eSRichard Henderson }
3283968f305eSRichard Henderson }
3284968f305eSRichard Henderson
3285968f305eSRichard Henderson QSIMPLEQ_CONCAT(&to->branches, &from->branches);
3286968f305eSRichard Henderson }
3287968f305eSRichard Henderson
3288b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code. */
32899bbee4c0SRichard Henderson static void __attribute__((noinline))
reachable_code_pass(TCGContext * s)32909bbee4c0SRichard Henderson reachable_code_pass(TCGContext *s)
3291b4fc67c7SRichard Henderson {
32924d89d0bbSRichard Henderson TCGOp *op, *op_next, *op_prev;
3293b4fc67c7SRichard Henderson bool dead = false;
3294b4fc67c7SRichard Henderson
3295b4fc67c7SRichard Henderson QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
3296b4fc67c7SRichard Henderson bool remove = dead;
3297b4fc67c7SRichard Henderson TCGLabel *label;
3298b4fc67c7SRichard Henderson
3299b4fc67c7SRichard Henderson switch (op->opc) {
3300b4fc67c7SRichard Henderson case INDEX_op_set_label:
3301b4fc67c7SRichard Henderson label = arg_label(op->args[0]);
33024d89d0bbSRichard Henderson
33034d89d0bbSRichard Henderson /*
3304968f305eSRichard Henderson * Note that the first op in the TB is always a load,
3305968f305eSRichard Henderson * so there is always something before a label.
3306968f305eSRichard Henderson */
3307968f305eSRichard Henderson op_prev = QTAILQ_PREV(op, link);
3308968f305eSRichard Henderson
3309968f305eSRichard Henderson /*
3310968f305eSRichard Henderson * If we find two sequential labels, move all branches to
3311968f305eSRichard Henderson * reference the second label and remove the first label.
3312968f305eSRichard Henderson * Do this before branch to next optimization, so that the
3313968f305eSRichard Henderson * middle label is out of the way.
3314968f305eSRichard Henderson */
3315968f305eSRichard Henderson if (op_prev->opc == INDEX_op_set_label) {
3316968f305eSRichard Henderson move_label_uses(label, arg_label(op_prev->args[0]));
3317968f305eSRichard Henderson tcg_op_remove(s, op_prev);
3318968f305eSRichard Henderson op_prev = QTAILQ_PREV(op, link);
3319968f305eSRichard Henderson }
3320968f305eSRichard Henderson
3321968f305eSRichard Henderson /*
33224d89d0bbSRichard Henderson * Optimization can fold conditional branches to unconditional.
33234d89d0bbSRichard Henderson * If we find a label which is preceded by an unconditional
33244d89d0bbSRichard Henderson * branch to next, remove the branch. We couldn't do this when
33254d89d0bbSRichard Henderson * processing the branch because any dead code between the branch
33264d89d0bbSRichard Henderson * and label had not yet been removed.
33274d89d0bbSRichard Henderson */
33284d89d0bbSRichard Henderson if (op_prev->opc == INDEX_op_br &&
33294d89d0bbSRichard Henderson label == arg_label(op_prev->args[0])) {
33304d89d0bbSRichard Henderson tcg_op_remove(s, op_prev);
33314d89d0bbSRichard Henderson /* Fall through means insns become live again. */
33324d89d0bbSRichard Henderson dead = false;
33334d89d0bbSRichard Henderson }
33344d89d0bbSRichard Henderson
3335f85b1fc4SRichard Henderson if (QSIMPLEQ_EMPTY(&label->branches)) {
3336b4fc67c7SRichard Henderson /*
3337b4fc67c7SRichard Henderson * While there is an occasional backward branch, virtually
3338b4fc67c7SRichard Henderson * all branches generated by the translators are forward.
3339b4fc67c7SRichard Henderson * Which means that generally we will have already removed
3340b4fc67c7SRichard Henderson * all references to the label that will be, and there is
3341b4fc67c7SRichard Henderson * little to be gained by iterating.
3342b4fc67c7SRichard Henderson */
3343b4fc67c7SRichard Henderson remove = true;
3344b4fc67c7SRichard Henderson } else {
3345b4fc67c7SRichard Henderson /* Once we see a label, insns become live again. */
3346b4fc67c7SRichard Henderson dead = false;
3347b4fc67c7SRichard Henderson remove = false;
3348b4fc67c7SRichard Henderson }
3349b4fc67c7SRichard Henderson break;
3350b4fc67c7SRichard Henderson
3351b4fc67c7SRichard Henderson case INDEX_op_br:
3352b4fc67c7SRichard Henderson case INDEX_op_exit_tb:
3353b4fc67c7SRichard Henderson case INDEX_op_goto_ptr:
3354b4fc67c7SRichard Henderson /* Unconditional branches; everything following is dead. */
3355b4fc67c7SRichard Henderson dead = true;
3356b4fc67c7SRichard Henderson break;
3357b4fc67c7SRichard Henderson
3358b4fc67c7SRichard Henderson case INDEX_op_call:
3359b4fc67c7SRichard Henderson /* Notice noreturn helper calls, raising exceptions. */
336090163900SRichard Henderson if (tcg_call_flags(op) & TCG_CALL_NO_RETURN) {
3361b4fc67c7SRichard Henderson dead = true;
3362b4fc67c7SRichard Henderson }
3363b4fc67c7SRichard Henderson break;
3364b4fc67c7SRichard Henderson
3365b4fc67c7SRichard Henderson case INDEX_op_insn_start:
3366b4fc67c7SRichard Henderson /* Never remove -- we need to keep these for unwind. */
3367b4fc67c7SRichard Henderson remove = false;
3368b4fc67c7SRichard Henderson break;
3369b4fc67c7SRichard Henderson
3370b4fc67c7SRichard Henderson default:
3371b4fc67c7SRichard Henderson break;
3372b4fc67c7SRichard Henderson }
3373b4fc67c7SRichard Henderson
3374b4fc67c7SRichard Henderson if (remove) {
3375b4fc67c7SRichard Henderson tcg_op_remove(s, op);
3376b4fc67c7SRichard Henderson }
3377b4fc67c7SRichard Henderson }
3378b4fc67c7SRichard Henderson }
3379b4fc67c7SRichard Henderson
3380c70fbf0aSRichard Henderson #define TS_DEAD 1
3381c70fbf0aSRichard Henderson #define TS_MEM 2
3382c70fbf0aSRichard Henderson
33835a18407fSRichard Henderson #define IS_DEAD_ARG(n) (arg_life & (DEAD_ARG << (n)))
33845a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n)))
33855a18407fSRichard Henderson
338625f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp. */
la_temp_pref(TCGTemp * ts)338725f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts)
338825f49c5fSRichard Henderson {
338925f49c5fSRichard Henderson return ts->state_ptr;
339025f49c5fSRichard Henderson }
339125f49c5fSRichard Henderson
339225f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the
339325f49c5fSRichard Henderson * maximal regset for its type.
339425f49c5fSRichard Henderson */
la_reset_pref(TCGTemp * ts)339525f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts)
339625f49c5fSRichard Henderson {
339725f49c5fSRichard Henderson *la_temp_pref(ts)
339825f49c5fSRichard Henderson = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]);
339925f49c5fSRichard Henderson }
340025f49c5fSRichard Henderson
34019c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals
34029c43b68dSAurelien Jarno should be in memory. */
la_func_end(TCGContext * s,int ng,int nt)34032616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt)
3404c896fe29Sbellard {
3405b83eabeaSRichard Henderson int i;
3406b83eabeaSRichard Henderson
3407b83eabeaSRichard Henderson for (i = 0; i < ng; ++i) {
3408b83eabeaSRichard Henderson s->temps[i].state = TS_DEAD | TS_MEM;
340925f49c5fSRichard Henderson la_reset_pref(&s->temps[i]);
3410b83eabeaSRichard Henderson }
3411b83eabeaSRichard Henderson for (i = ng; i < nt; ++i) {
3412b83eabeaSRichard Henderson s->temps[i].state = TS_DEAD;
341325f49c5fSRichard Henderson la_reset_pref(&s->temps[i]);
3414b83eabeaSRichard Henderson }
3415c896fe29Sbellard }
3416c896fe29Sbellard
34179c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals
34189c43b68dSAurelien Jarno and local temps should be in memory. */
la_bb_end(TCGContext * s,int ng,int nt)34192616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt)
3420641d5fbeSbellard {
3421b83eabeaSRichard Henderson int i;
3422641d5fbeSbellard
3423ee17db83SRichard Henderson for (i = 0; i < nt; ++i) {
3424ee17db83SRichard Henderson TCGTemp *ts = &s->temps[i];
3425ee17db83SRichard Henderson int state;
3426ee17db83SRichard Henderson
3427ee17db83SRichard Henderson switch (ts->kind) {
3428ee17db83SRichard Henderson case TEMP_FIXED:
3429ee17db83SRichard Henderson case TEMP_GLOBAL:
3430f57c6915SRichard Henderson case TEMP_TB:
3431ee17db83SRichard Henderson state = TS_DEAD | TS_MEM;
3432ee17db83SRichard Henderson break;
3433c7482438SRichard Henderson case TEMP_EBB:
3434c0522136SRichard Henderson case TEMP_CONST:
3435ee17db83SRichard Henderson state = TS_DEAD;
3436ee17db83SRichard Henderson break;
3437ee17db83SRichard Henderson default:
3438ee17db83SRichard Henderson g_assert_not_reached();
3439c70fbf0aSRichard Henderson }
3440ee17db83SRichard Henderson ts->state = state;
3441ee17db83SRichard Henderson la_reset_pref(ts);
3442641d5fbeSbellard }
3443641d5fbeSbellard }
3444641d5fbeSbellard
3445f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory. */
la_global_sync(TCGContext * s,int ng)3446f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng)
3447f65a061cSRichard Henderson {
3448f65a061cSRichard Henderson int i;
3449f65a061cSRichard Henderson
3450f65a061cSRichard Henderson for (i = 0; i < ng; ++i) {
345125f49c5fSRichard Henderson int state = s->temps[i].state;
345225f49c5fSRichard Henderson s->temps[i].state = state | TS_MEM;
345325f49c5fSRichard Henderson if (state == TS_DEAD) {
345425f49c5fSRichard Henderson /* If the global was previously dead, reset prefs. */
345525f49c5fSRichard Henderson la_reset_pref(&s->temps[i]);
345625f49c5fSRichard Henderson }
3457f65a061cSRichard Henderson }
3458f65a061cSRichard Henderson }
3459f65a061cSRichard Henderson
3460b4cb76e6SRichard Henderson /*
3461c7482438SRichard Henderson * liveness analysis: conditional branch: all temps are dead unless
3462c7482438SRichard Henderson * explicitly live-across-conditional-branch, globals and local temps
3463c7482438SRichard Henderson * should be synced.
3464b4cb76e6SRichard Henderson */
la_bb_sync(TCGContext * s,int ng,int nt)3465b4cb76e6SRichard Henderson static void la_bb_sync(TCGContext *s, int ng, int nt)
3466b4cb76e6SRichard Henderson {
3467b4cb76e6SRichard Henderson la_global_sync(s, ng);
3468b4cb76e6SRichard Henderson
3469b4cb76e6SRichard Henderson for (int i = ng; i < nt; ++i) {
3470c0522136SRichard Henderson TCGTemp *ts = &s->temps[i];
3471c0522136SRichard Henderson int state;
3472c0522136SRichard Henderson
3473c0522136SRichard Henderson switch (ts->kind) {
3474f57c6915SRichard Henderson case TEMP_TB:
3475c0522136SRichard Henderson state = ts->state;
3476c0522136SRichard Henderson ts->state = state | TS_MEM;
3477b4cb76e6SRichard Henderson if (state != TS_DEAD) {
3478b4cb76e6SRichard Henderson continue;
3479b4cb76e6SRichard Henderson }
3480c0522136SRichard Henderson break;
3481c7482438SRichard Henderson case TEMP_EBB:
3482c0522136SRichard Henderson case TEMP_CONST:
3483c0522136SRichard Henderson continue;
3484c0522136SRichard Henderson default:
3485c0522136SRichard Henderson g_assert_not_reached();
3486b4cb76e6SRichard Henderson }
3487b4cb76e6SRichard Henderson la_reset_pref(&s->temps[i]);
3488b4cb76e6SRichard Henderson }
3489b4cb76e6SRichard Henderson }
3490b4cb76e6SRichard Henderson
3491f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill. */
la_global_kill(TCGContext * s,int ng)3492f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng)
3493f65a061cSRichard Henderson {
3494f65a061cSRichard Henderson int i;
3495f65a061cSRichard Henderson
3496f65a061cSRichard Henderson for (i = 0; i < ng; i++) {
3497f65a061cSRichard Henderson s->temps[i].state = TS_DEAD | TS_MEM;
349825f49c5fSRichard Henderson la_reset_pref(&s->temps[i]);
349925f49c5fSRichard Henderson }
350025f49c5fSRichard Henderson }
350125f49c5fSRichard Henderson
350225f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls. */
la_cross_call(TCGContext * s,int nt)350325f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt)
350425f49c5fSRichard Henderson {
350525f49c5fSRichard Henderson TCGRegSet mask = ~tcg_target_call_clobber_regs;
350625f49c5fSRichard Henderson int i;
350725f49c5fSRichard Henderson
350825f49c5fSRichard Henderson for (i = 0; i < nt; i++) {
350925f49c5fSRichard Henderson TCGTemp *ts = &s->temps[i];
351025f49c5fSRichard Henderson if (!(ts->state & TS_DEAD)) {
351125f49c5fSRichard Henderson TCGRegSet *pset = la_temp_pref(ts);
351225f49c5fSRichard Henderson TCGRegSet set = *pset;
351325f49c5fSRichard Henderson
351425f49c5fSRichard Henderson set &= mask;
351525f49c5fSRichard Henderson /* If the combination is not possible, restart. */
351625f49c5fSRichard Henderson if (set == 0) {
351725f49c5fSRichard Henderson set = tcg_target_available_regs[ts->type] & mask;
351825f49c5fSRichard Henderson }
351925f49c5fSRichard Henderson *pset = set;
352025f49c5fSRichard Henderson }
3521f65a061cSRichard Henderson }
3522f65a061cSRichard Henderson }
3523f65a061cSRichard Henderson
3524874b8574SRichard Henderson /*
3525874b8574SRichard Henderson * Liveness analysis: Verify the lifetime of TEMP_TB, and reduce
3526874b8574SRichard Henderson * to TEMP_EBB, if possible.
3527874b8574SRichard Henderson */
3528874b8574SRichard Henderson static void __attribute__((noinline))
liveness_pass_0(TCGContext * s)3529874b8574SRichard Henderson liveness_pass_0(TCGContext *s)
3530874b8574SRichard Henderson {
3531874b8574SRichard Henderson void * const multiple_ebb = (void *)(uintptr_t)-1;
3532874b8574SRichard Henderson int nb_temps = s->nb_temps;
3533874b8574SRichard Henderson TCGOp *op, *ebb;
3534874b8574SRichard Henderson
3535874b8574SRichard Henderson for (int i = s->nb_globals; i < nb_temps; ++i) {
3536874b8574SRichard Henderson s->temps[i].state_ptr = NULL;
3537874b8574SRichard Henderson }
3538874b8574SRichard Henderson
3539874b8574SRichard Henderson /*
3540874b8574SRichard Henderson * Represent each EBB by the op at which it begins. In the case of
3541874b8574SRichard Henderson * the first EBB, this is the first op, otherwise it is a label.
3542874b8574SRichard Henderson * Collect the uses of each TEMP_TB: NULL for unused, EBB for use
3543874b8574SRichard Henderson * within a single EBB, else MULTIPLE_EBB.
3544874b8574SRichard Henderson */
3545874b8574SRichard Henderson ebb = QTAILQ_FIRST(&s->ops);
3546874b8574SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) {
3547874b8574SRichard Henderson const TCGOpDef *def;
3548874b8574SRichard Henderson int nb_oargs, nb_iargs;
3549874b8574SRichard Henderson
3550874b8574SRichard Henderson switch (op->opc) {
3551874b8574SRichard Henderson case INDEX_op_set_label:
3552874b8574SRichard Henderson ebb = op;
3553874b8574SRichard Henderson continue;
3554874b8574SRichard Henderson case INDEX_op_discard:
3555874b8574SRichard Henderson continue;
3556874b8574SRichard Henderson case INDEX_op_call:
3557874b8574SRichard Henderson nb_oargs = TCGOP_CALLO(op);
3558874b8574SRichard Henderson nb_iargs = TCGOP_CALLI(op);
3559874b8574SRichard Henderson break;
3560874b8574SRichard Henderson default:
3561874b8574SRichard Henderson def = &tcg_op_defs[op->opc];
3562874b8574SRichard Henderson nb_oargs = def->nb_oargs;
3563874b8574SRichard Henderson nb_iargs = def->nb_iargs;
3564874b8574SRichard Henderson break;
3565874b8574SRichard Henderson }
3566874b8574SRichard Henderson
3567874b8574SRichard Henderson for (int i = 0; i < nb_oargs + nb_iargs; ++i) {
3568874b8574SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]);
3569874b8574SRichard Henderson
3570874b8574SRichard Henderson if (ts->kind != TEMP_TB) {
3571874b8574SRichard Henderson continue;
3572874b8574SRichard Henderson }
3573874b8574SRichard Henderson if (ts->state_ptr == NULL) {
3574874b8574SRichard Henderson ts->state_ptr = ebb;
3575874b8574SRichard Henderson } else if (ts->state_ptr != ebb) {
3576874b8574SRichard Henderson ts->state_ptr = multiple_ebb;
3577874b8574SRichard Henderson }
3578874b8574SRichard Henderson }
3579874b8574SRichard Henderson }
3580874b8574SRichard Henderson
3581874b8574SRichard Henderson /*
3582874b8574SRichard Henderson * For TEMP_TB that turned out not to be used beyond one EBB,
3583874b8574SRichard Henderson * reduce the liveness to TEMP_EBB.
3584874b8574SRichard Henderson */
3585874b8574SRichard Henderson for (int i = s->nb_globals; i < nb_temps; ++i) {
3586874b8574SRichard Henderson TCGTemp *ts = &s->temps[i];
3587874b8574SRichard Henderson if (ts->kind == TEMP_TB && ts->state_ptr != multiple_ebb) {
3588874b8574SRichard Henderson ts->kind = TEMP_EBB;
3589874b8574SRichard Henderson }
3590874b8574SRichard Henderson }
3591874b8574SRichard Henderson }
3592874b8574SRichard Henderson
3593a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a
3594c896fe29Sbellard given input arguments is dead. Instructions updating dead
3595c896fe29Sbellard temporaries are removed. */
35969bbee4c0SRichard Henderson static void __attribute__((noinline))
liveness_pass_1(TCGContext * s)35979bbee4c0SRichard Henderson liveness_pass_1(TCGContext *s)
3598c896fe29Sbellard {
3599c70fbf0aSRichard Henderson int nb_globals = s->nb_globals;
36002616c808SRichard Henderson int nb_temps = s->nb_temps;
360115fa08f8SRichard Henderson TCGOp *op, *op_prev;
360225f49c5fSRichard Henderson TCGRegSet *prefs;
360325f49c5fSRichard Henderson int i;
360425f49c5fSRichard Henderson
360525f49c5fSRichard Henderson prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps);
360625f49c5fSRichard Henderson for (i = 0; i < nb_temps; ++i) {
360725f49c5fSRichard Henderson s->temps[i].state_ptr = prefs + i;
360825f49c5fSRichard Henderson }
3609c896fe29Sbellard
3610ae36a246SRichard Henderson /* ??? Should be redundant with the exit_tb that ends the TB. */
36112616c808SRichard Henderson la_func_end(s, nb_globals, nb_temps);
3612c896fe29Sbellard
3613eae3eb3eSPaolo Bonzini QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) {
361425f49c5fSRichard Henderson int nb_iargs, nb_oargs;
3615c45cb8bbSRichard Henderson TCGOpcode opc_new, opc_new2;
3616c45cb8bbSRichard Henderson bool have_opc_new2;
3617a1b3c48dSRichard Henderson TCGLifeData arg_life = 0;
361825f49c5fSRichard Henderson TCGTemp *ts;
3619c45cb8bbSRichard Henderson TCGOpcode opc = op->opc;
3620c45cb8bbSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc];
3621c45cb8bbSRichard Henderson
3622c45cb8bbSRichard Henderson switch (opc) {
3623c896fe29Sbellard case INDEX_op_call:
3624c6e113f5Sbellard {
362539004a71SRichard Henderson const TCGHelperInfo *info = tcg_call_info(op);
362639004a71SRichard Henderson int call_flags = tcg_call_flags(op);
3627c6e113f5Sbellard
3628cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op);
3629cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op);
3630c6e113f5Sbellard
3631c45cb8bbSRichard Henderson /* pure functions can be removed if their result is unused */
363278505279SAurelien Jarno if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) {
3633c6e113f5Sbellard for (i = 0; i < nb_oargs; i++) {
363425f49c5fSRichard Henderson ts = arg_temp(op->args[i]);
363525f49c5fSRichard Henderson if (ts->state != TS_DEAD) {
3636c6e113f5Sbellard goto do_not_remove_call;
3637c6e113f5Sbellard }
36389c43b68dSAurelien Jarno }
3639c45cb8bbSRichard Henderson goto do_remove;
3640152c35aaSRichard Henderson }
3641c6e113f5Sbellard do_not_remove_call:
3642c896fe29Sbellard
364325f49c5fSRichard Henderson /* Output args are dead. */
3644c896fe29Sbellard for (i = 0; i < nb_oargs; i++) {
364525f49c5fSRichard Henderson ts = arg_temp(op->args[i]);
364625f49c5fSRichard Henderson if (ts->state & TS_DEAD) {
3647a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i;
36486b64b624SAurelien Jarno }
364925f49c5fSRichard Henderson if (ts->state & TS_MEM) {
3650a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i;
36519c43b68dSAurelien Jarno }
365225f49c5fSRichard Henderson ts->state = TS_DEAD;
365325f49c5fSRichard Henderson la_reset_pref(ts);
3654c896fe29Sbellard }
3655c896fe29Sbellard
365631fd884bSRichard Henderson /* Not used -- it will be tcg_target_call_oarg_reg(). */
365731fd884bSRichard Henderson memset(op->output_pref, 0, sizeof(op->output_pref));
365831fd884bSRichard Henderson
365978505279SAurelien Jarno if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS |
366078505279SAurelien Jarno TCG_CALL_NO_READ_GLOBALS))) {
3661f65a061cSRichard Henderson la_global_kill(s, nb_globals);
3662c70fbf0aSRichard Henderson } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) {
3663f65a061cSRichard Henderson la_global_sync(s, nb_globals);
3664b9c18f56Saurel32 }
3665c896fe29Sbellard
366625f49c5fSRichard Henderson /* Record arguments that die in this helper. */
3667866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
366825f49c5fSRichard Henderson ts = arg_temp(op->args[i]);
366939004a71SRichard Henderson if (ts->state & TS_DEAD) {
3670a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i;
3671c896fe29Sbellard }
3672c896fe29Sbellard }
367325f49c5fSRichard Henderson
367425f49c5fSRichard Henderson /* For all live registers, remove call-clobbered prefs. */
367525f49c5fSRichard Henderson la_cross_call(s, nb_temps);
367625f49c5fSRichard Henderson
367739004a71SRichard Henderson /*
367839004a71SRichard Henderson * Input arguments are live for preceding opcodes.
367939004a71SRichard Henderson *
368039004a71SRichard Henderson * For those arguments that die, and will be allocated in
368139004a71SRichard Henderson * registers, clear the register set for that arg, to be
368239004a71SRichard Henderson * filled in below. For args that will be on the stack,
368339004a71SRichard Henderson * reset to any available reg. Process arguments in reverse
368439004a71SRichard Henderson * order so that if a temp is used more than once, the stack
368539004a71SRichard Henderson * reset to max happens before the register reset to 0.
368625f49c5fSRichard Henderson */
368739004a71SRichard Henderson for (i = nb_iargs - 1; i >= 0; i--) {
368839004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i];
368939004a71SRichard Henderson ts = arg_temp(op->args[nb_oargs + i]);
369039004a71SRichard Henderson
369139004a71SRichard Henderson if (ts->state & TS_DEAD) {
369239004a71SRichard Henderson switch (loc->kind) {
369339004a71SRichard Henderson case TCG_CALL_ARG_NORMAL:
369439004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U:
369539004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S:
3696338b61e9SRichard Henderson if (arg_slot_reg_p(loc->arg_slot)) {
369739004a71SRichard Henderson *la_temp_pref(ts) = 0;
369839004a71SRichard Henderson break;
369939004a71SRichard Henderson }
370039004a71SRichard Henderson /* fall through */
370139004a71SRichard Henderson default:
370239004a71SRichard Henderson *la_temp_pref(ts) =
370339004a71SRichard Henderson tcg_target_available_regs[ts->type];
370439004a71SRichard Henderson break;
370539004a71SRichard Henderson }
370625f49c5fSRichard Henderson ts->state &= ~TS_DEAD;
370725f49c5fSRichard Henderson }
370825f49c5fSRichard Henderson }
370925f49c5fSRichard Henderson
371039004a71SRichard Henderson /*
371139004a71SRichard Henderson * For each input argument, add its input register to prefs.
371239004a71SRichard Henderson * If a temp is used once, this produces a single set bit;
371339004a71SRichard Henderson * if a temp is used multiple times, this produces a set.
371439004a71SRichard Henderson */
371539004a71SRichard Henderson for (i = 0; i < nb_iargs; i++) {
371639004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i];
371739004a71SRichard Henderson ts = arg_temp(op->args[nb_oargs + i]);
371839004a71SRichard Henderson
371939004a71SRichard Henderson switch (loc->kind) {
372039004a71SRichard Henderson case TCG_CALL_ARG_NORMAL:
372139004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U:
372239004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S:
3723338b61e9SRichard Henderson if (arg_slot_reg_p(loc->arg_slot)) {
372425f49c5fSRichard Henderson tcg_regset_set_reg(*la_temp_pref(ts),
372539004a71SRichard Henderson tcg_target_call_iarg_regs[loc->arg_slot]);
372639004a71SRichard Henderson }
372739004a71SRichard Henderson break;
372839004a71SRichard Henderson default:
372939004a71SRichard Henderson break;
3730c70fbf0aSRichard Henderson }
3731c19f47bfSAurelien Jarno }
3732c6e113f5Sbellard }
3733c896fe29Sbellard break;
3734765b842aSRichard Henderson case INDEX_op_insn_start:
3735c896fe29Sbellard break;
37365ff9d6a4Sbellard case INDEX_op_discard:
37375ff9d6a4Sbellard /* mark the temporary as dead */
373825f49c5fSRichard Henderson ts = arg_temp(op->args[0]);
373925f49c5fSRichard Henderson ts->state = TS_DEAD;
374025f49c5fSRichard Henderson la_reset_pref(ts);
37415ff9d6a4Sbellard break;
37421305c451SRichard Henderson
37431305c451SRichard Henderson case INDEX_op_add2_i32:
3744c45cb8bbSRichard Henderson opc_new = INDEX_op_add_i32;
3745f1fae40cSRichard Henderson goto do_addsub2;
37461305c451SRichard Henderson case INDEX_op_sub2_i32:
3747c45cb8bbSRichard Henderson opc_new = INDEX_op_sub_i32;
3748f1fae40cSRichard Henderson goto do_addsub2;
3749f1fae40cSRichard Henderson case INDEX_op_add2_i64:
3750c45cb8bbSRichard Henderson opc_new = INDEX_op_add_i64;
3751f1fae40cSRichard Henderson goto do_addsub2;
3752f1fae40cSRichard Henderson case INDEX_op_sub2_i64:
3753c45cb8bbSRichard Henderson opc_new = INDEX_op_sub_i64;
3754f1fae40cSRichard Henderson do_addsub2:
37551305c451SRichard Henderson nb_iargs = 4;
37561305c451SRichard Henderson nb_oargs = 2;
37571305c451SRichard Henderson /* Test if the high part of the operation is dead, but not
37581305c451SRichard Henderson the low part. The result can be optimized to a simple
37591305c451SRichard Henderson add or sub. This happens often for x86_64 guest when the
37601305c451SRichard Henderson cpu mode is set to 32 bit. */
3761b83eabeaSRichard Henderson if (arg_temp(op->args[1])->state == TS_DEAD) {
3762b83eabeaSRichard Henderson if (arg_temp(op->args[0])->state == TS_DEAD) {
37631305c451SRichard Henderson goto do_remove;
37641305c451SRichard Henderson }
3765c45cb8bbSRichard Henderson /* Replace the opcode and adjust the args in place,
3766c45cb8bbSRichard Henderson leaving 3 unused args at the end. */
3767c45cb8bbSRichard Henderson op->opc = opc = opc_new;
3768efee3746SRichard Henderson op->args[1] = op->args[2];
3769efee3746SRichard Henderson op->args[2] = op->args[4];
37701305c451SRichard Henderson /* Fall through and mark the single-word operation live. */
37711305c451SRichard Henderson nb_iargs = 2;
37721305c451SRichard Henderson nb_oargs = 1;
37731305c451SRichard Henderson }
37741305c451SRichard Henderson goto do_not_remove;
37751305c451SRichard Henderson
37761414968aSRichard Henderson case INDEX_op_mulu2_i32:
3777c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i32;
3778c45cb8bbSRichard Henderson opc_new2 = INDEX_op_muluh_i32;
3779c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_muluh_i32;
378003271524SRichard Henderson goto do_mul2;
3781f1fae40cSRichard Henderson case INDEX_op_muls2_i32:
3782c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i32;
3783c45cb8bbSRichard Henderson opc_new2 = INDEX_op_mulsh_i32;
3784c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_mulsh_i32;
3785f1fae40cSRichard Henderson goto do_mul2;
3786f1fae40cSRichard Henderson case INDEX_op_mulu2_i64:
3787c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i64;
3788c45cb8bbSRichard Henderson opc_new2 = INDEX_op_muluh_i64;
3789c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_muluh_i64;
379003271524SRichard Henderson goto do_mul2;
3791f1fae40cSRichard Henderson case INDEX_op_muls2_i64:
3792c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i64;
3793c45cb8bbSRichard Henderson opc_new2 = INDEX_op_mulsh_i64;
3794c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_mulsh_i64;
379503271524SRichard Henderson goto do_mul2;
3796f1fae40cSRichard Henderson do_mul2:
37971414968aSRichard Henderson nb_iargs = 2;
37981414968aSRichard Henderson nb_oargs = 2;
3799b83eabeaSRichard Henderson if (arg_temp(op->args[1])->state == TS_DEAD) {
3800b83eabeaSRichard Henderson if (arg_temp(op->args[0])->state == TS_DEAD) {
380103271524SRichard Henderson /* Both parts of the operation are dead. */
38021414968aSRichard Henderson goto do_remove;
38031414968aSRichard Henderson }
380403271524SRichard Henderson /* The high part of the operation is dead; generate the low. */
3805c45cb8bbSRichard Henderson op->opc = opc = opc_new;
3806efee3746SRichard Henderson op->args[1] = op->args[2];
3807efee3746SRichard Henderson op->args[2] = op->args[3];
3808b83eabeaSRichard Henderson } else if (arg_temp(op->args[0])->state == TS_DEAD && have_opc_new2) {
380903271524SRichard Henderson /* The low part of the operation is dead; generate the high. */
3810c45cb8bbSRichard Henderson op->opc = opc = opc_new2;
3811efee3746SRichard Henderson op->args[0] = op->args[1];
3812efee3746SRichard Henderson op->args[1] = op->args[2];
3813efee3746SRichard Henderson op->args[2] = op->args[3];
381403271524SRichard Henderson } else {
381503271524SRichard Henderson goto do_not_remove;
381603271524SRichard Henderson }
381703271524SRichard Henderson /* Mark the single-word operation live. */
38181414968aSRichard Henderson nb_oargs = 1;
38191414968aSRichard Henderson goto do_not_remove;
38201414968aSRichard Henderson
3821c896fe29Sbellard default:
38221305c451SRichard Henderson /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
3823c896fe29Sbellard nb_iargs = def->nb_iargs;
3824c896fe29Sbellard nb_oargs = def->nb_oargs;
3825c896fe29Sbellard
3826c896fe29Sbellard /* Test if the operation can be removed because all
38275ff9d6a4Sbellard its outputs are dead. We assume that nb_oargs == 0
38285ff9d6a4Sbellard implies side effects */
38295ff9d6a4Sbellard if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
3830c896fe29Sbellard for (i = 0; i < nb_oargs; i++) {
3831b83eabeaSRichard Henderson if (arg_temp(op->args[i])->state != TS_DEAD) {
3832c896fe29Sbellard goto do_not_remove;
3833c896fe29Sbellard }
38349c43b68dSAurelien Jarno }
3835152c35aaSRichard Henderson goto do_remove;
3836152c35aaSRichard Henderson }
3837152c35aaSRichard Henderson goto do_not_remove;
3838152c35aaSRichard Henderson
38391305c451SRichard Henderson do_remove:
38400c627cdcSRichard Henderson tcg_op_remove(s, op);
3841152c35aaSRichard Henderson break;
3842152c35aaSRichard Henderson
3843c896fe29Sbellard do_not_remove:
3844c896fe29Sbellard for (i = 0; i < nb_oargs; i++) {
384525f49c5fSRichard Henderson ts = arg_temp(op->args[i]);
384625f49c5fSRichard Henderson
384725f49c5fSRichard Henderson /* Remember the preference of the uses that followed. */
384831fd884bSRichard Henderson if (i < ARRAY_SIZE(op->output_pref)) {
384925f49c5fSRichard Henderson op->output_pref[i] = *la_temp_pref(ts);
385031fd884bSRichard Henderson }
385125f49c5fSRichard Henderson
385225f49c5fSRichard Henderson /* Output args are dead. */
385325f49c5fSRichard Henderson if (ts->state & TS_DEAD) {
3854a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i;
38556b64b624SAurelien Jarno }
385625f49c5fSRichard Henderson if (ts->state & TS_MEM) {
3857a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i;
38589c43b68dSAurelien Jarno }
385925f49c5fSRichard Henderson ts->state = TS_DEAD;
386025f49c5fSRichard Henderson la_reset_pref(ts);
3861c896fe29Sbellard }
3862c896fe29Sbellard
386325f49c5fSRichard Henderson /* If end of basic block, update. */
3864ae36a246SRichard Henderson if (def->flags & TCG_OPF_BB_EXIT) {
3865ae36a246SRichard Henderson la_func_end(s, nb_globals, nb_temps);
3866b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_COND_BRANCH) {
3867b4cb76e6SRichard Henderson la_bb_sync(s, nb_globals, nb_temps);
3868ae36a246SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) {
38692616c808SRichard Henderson la_bb_end(s, nb_globals, nb_temps);
38703d5c5f87SAurelien Jarno } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
3871f65a061cSRichard Henderson la_global_sync(s, nb_globals);
387225f49c5fSRichard Henderson if (def->flags & TCG_OPF_CALL_CLOBBER) {
387325f49c5fSRichard Henderson la_cross_call(s, nb_temps);
387425f49c5fSRichard Henderson }
3875c896fe29Sbellard }
3876c896fe29Sbellard
387725f49c5fSRichard Henderson /* Record arguments that die in this opcode. */
3878866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
387925f49c5fSRichard Henderson ts = arg_temp(op->args[i]);
388025f49c5fSRichard Henderson if (ts->state & TS_DEAD) {
3881a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i;
3882c896fe29Sbellard }
3883c19f47bfSAurelien Jarno }
388425f49c5fSRichard Henderson
388525f49c5fSRichard Henderson /* Input arguments are live for preceding opcodes. */
3886c19f47bfSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
388725f49c5fSRichard Henderson ts = arg_temp(op->args[i]);
388825f49c5fSRichard Henderson if (ts->state & TS_DEAD) {
388925f49c5fSRichard Henderson /* For operands that were dead, initially allow
389025f49c5fSRichard Henderson all regs for the type. */
389125f49c5fSRichard Henderson *la_temp_pref(ts) = tcg_target_available_regs[ts->type];
389225f49c5fSRichard Henderson ts->state &= ~TS_DEAD;
389325f49c5fSRichard Henderson }
389425f49c5fSRichard Henderson }
389525f49c5fSRichard Henderson
389625f49c5fSRichard Henderson /* Incorporate constraints for this operand. */
389725f49c5fSRichard Henderson switch (opc) {
389825f49c5fSRichard Henderson case INDEX_op_mov_i32:
389925f49c5fSRichard Henderson case INDEX_op_mov_i64:
390025f49c5fSRichard Henderson /* Note that these are TCG_OPF_NOT_PRESENT and do not
390125f49c5fSRichard Henderson have proper constraints. That said, special case
390225f49c5fSRichard Henderson moves to propagate preferences backward. */
390325f49c5fSRichard Henderson if (IS_DEAD_ARG(1)) {
390425f49c5fSRichard Henderson *la_temp_pref(arg_temp(op->args[0]))
390525f49c5fSRichard Henderson = *la_temp_pref(arg_temp(op->args[1]));
390625f49c5fSRichard Henderson }
390725f49c5fSRichard Henderson break;
390825f49c5fSRichard Henderson
390925f49c5fSRichard Henderson default:
391025f49c5fSRichard Henderson for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
391125f49c5fSRichard Henderson const TCGArgConstraint *ct = &def->args_ct[i];
391225f49c5fSRichard Henderson TCGRegSet set, *pset;
391325f49c5fSRichard Henderson
391425f49c5fSRichard Henderson ts = arg_temp(op->args[i]);
391525f49c5fSRichard Henderson pset = la_temp_pref(ts);
391625f49c5fSRichard Henderson set = *pset;
391725f49c5fSRichard Henderson
39189be0d080SRichard Henderson set &= ct->regs;
3919bc2b17e6SRichard Henderson if (ct->ialias) {
392031fd884bSRichard Henderson set &= output_pref(op, ct->alias_index);
392125f49c5fSRichard Henderson }
392225f49c5fSRichard Henderson /* If the combination is not possible, restart. */
392325f49c5fSRichard Henderson if (set == 0) {
39249be0d080SRichard Henderson set = ct->regs;
392525f49c5fSRichard Henderson }
392625f49c5fSRichard Henderson *pset = set;
392725f49c5fSRichard Henderson }
392825f49c5fSRichard Henderson break;
3929c896fe29Sbellard }
3930c896fe29Sbellard break;
3931c896fe29Sbellard }
3932bee158cbSRichard Henderson op->life = arg_life;
3933c896fe29Sbellard }
39341ff0a2c5SEvgeny Voevodin }
3935c896fe29Sbellard
39365a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries. */
39379bbee4c0SRichard Henderson static bool __attribute__((noinline))
liveness_pass_2(TCGContext * s)39389bbee4c0SRichard Henderson liveness_pass_2(TCGContext *s)
39395a18407fSRichard Henderson {
39405a18407fSRichard Henderson int nb_globals = s->nb_globals;
394115fa08f8SRichard Henderson int nb_temps, i;
39425a18407fSRichard Henderson bool changes = false;
394315fa08f8SRichard Henderson TCGOp *op, *op_next;
39445a18407fSRichard Henderson
39455a18407fSRichard Henderson /* Create a temporary for each indirect global. */
39465a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) {
39475a18407fSRichard Henderson TCGTemp *its = &s->temps[i];
39485a18407fSRichard Henderson if (its->indirect_reg) {
39495a18407fSRichard Henderson TCGTemp *dts = tcg_temp_alloc(s);
39505a18407fSRichard Henderson dts->type = its->type;
39515a18407fSRichard Henderson dts->base_type = its->base_type;
3952e1e64652SRichard Henderson dts->temp_subindex = its->temp_subindex;
3953c7482438SRichard Henderson dts->kind = TEMP_EBB;
3954b83eabeaSRichard Henderson its->state_ptr = dts;
3955b83eabeaSRichard Henderson } else {
3956b83eabeaSRichard Henderson its->state_ptr = NULL;
39575a18407fSRichard Henderson }
3958b83eabeaSRichard Henderson /* All globals begin dead. */
3959b83eabeaSRichard Henderson its->state = TS_DEAD;
39605a18407fSRichard Henderson }
3961b83eabeaSRichard Henderson for (nb_temps = s->nb_temps; i < nb_temps; ++i) {
3962b83eabeaSRichard Henderson TCGTemp *its = &s->temps[i];
3963b83eabeaSRichard Henderson its->state_ptr = NULL;
3964b83eabeaSRichard Henderson its->state = TS_DEAD;
3965b83eabeaSRichard Henderson }
39665a18407fSRichard Henderson
396715fa08f8SRichard Henderson QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
39685a18407fSRichard Henderson TCGOpcode opc = op->opc;
39695a18407fSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc];
39705a18407fSRichard Henderson TCGLifeData arg_life = op->life;
39715a18407fSRichard Henderson int nb_iargs, nb_oargs, call_flags;
3972b83eabeaSRichard Henderson TCGTemp *arg_ts, *dir_ts;
39735a18407fSRichard Henderson
39745a18407fSRichard Henderson if (opc == INDEX_op_call) {
3975cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op);
3976cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op);
397790163900SRichard Henderson call_flags = tcg_call_flags(op);
39785a18407fSRichard Henderson } else {
39795a18407fSRichard Henderson nb_iargs = def->nb_iargs;
39805a18407fSRichard Henderson nb_oargs = def->nb_oargs;
39815a18407fSRichard Henderson
39825a18407fSRichard Henderson /* Set flags similar to how calls require. */
3983b4cb76e6SRichard Henderson if (def->flags & TCG_OPF_COND_BRANCH) {
3984b4cb76e6SRichard Henderson /* Like reading globals: sync_globals */
3985b4cb76e6SRichard Henderson call_flags = TCG_CALL_NO_WRITE_GLOBALS;
3986b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) {
39875a18407fSRichard Henderson /* Like writing globals: save_globals */
39885a18407fSRichard Henderson call_flags = 0;
39895a18407fSRichard Henderson } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
39905a18407fSRichard Henderson /* Like reading globals: sync_globals */
39915a18407fSRichard Henderson call_flags = TCG_CALL_NO_WRITE_GLOBALS;
39925a18407fSRichard Henderson } else {
39935a18407fSRichard Henderson /* No effect on globals. */
39945a18407fSRichard Henderson call_flags = (TCG_CALL_NO_READ_GLOBALS |
39955a18407fSRichard Henderson TCG_CALL_NO_WRITE_GLOBALS);
39965a18407fSRichard Henderson }
39975a18407fSRichard Henderson }
39985a18407fSRichard Henderson
39995a18407fSRichard Henderson /* Make sure that input arguments are available. */
40005a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
4001b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]);
4002b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr;
4003b83eabeaSRichard Henderson if (dir_ts && arg_ts->state == TS_DEAD) {
4004b83eabeaSRichard Henderson TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32
40055a18407fSRichard Henderson ? INDEX_op_ld_i32
40065a18407fSRichard Henderson : INDEX_op_ld_i64);
4007d4478943SPhilippe Mathieu-Daudé TCGOp *lop = tcg_op_insert_before(s, op, lopc, 3);
40085a18407fSRichard Henderson
4009b83eabeaSRichard Henderson lop->args[0] = temp_arg(dir_ts);
4010b83eabeaSRichard Henderson lop->args[1] = temp_arg(arg_ts->mem_base);
4011b83eabeaSRichard Henderson lop->args[2] = arg_ts->mem_offset;
40125a18407fSRichard Henderson
40135a18407fSRichard Henderson /* Loaded, but synced with memory. */
4014b83eabeaSRichard Henderson arg_ts->state = TS_MEM;
40155a18407fSRichard Henderson }
40165a18407fSRichard Henderson }
40175a18407fSRichard Henderson
40185a18407fSRichard Henderson /* Perform input replacement, and mark inputs that became dead.
40195a18407fSRichard Henderson No action is required except keeping temp_state up to date
40205a18407fSRichard Henderson so that we reload when needed. */
40215a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
4022b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]);
4023b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr;
4024b83eabeaSRichard Henderson if (dir_ts) {
4025b83eabeaSRichard Henderson op->args[i] = temp_arg(dir_ts);
40265a18407fSRichard Henderson changes = true;
40275a18407fSRichard Henderson if (IS_DEAD_ARG(i)) {
4028b83eabeaSRichard Henderson arg_ts->state = TS_DEAD;
40295a18407fSRichard Henderson }
40305a18407fSRichard Henderson }
40315a18407fSRichard Henderson }
40325a18407fSRichard Henderson
40335a18407fSRichard Henderson /* Liveness analysis should ensure that the following are
40345a18407fSRichard Henderson all correct, for call sites and basic block end points. */
40355a18407fSRichard Henderson if (call_flags & TCG_CALL_NO_READ_GLOBALS) {
40365a18407fSRichard Henderson /* Nothing to do */
40375a18407fSRichard Henderson } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) {
40385a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) {
40395a18407fSRichard Henderson /* Liveness should see that globals are synced back,
40405a18407fSRichard Henderson that is, either TS_DEAD or TS_MEM. */
4041b83eabeaSRichard Henderson arg_ts = &s->temps[i];
4042b83eabeaSRichard Henderson tcg_debug_assert(arg_ts->state_ptr == 0
4043b83eabeaSRichard Henderson || arg_ts->state != 0);
40445a18407fSRichard Henderson }
40455a18407fSRichard Henderson } else {
40465a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) {
40475a18407fSRichard Henderson /* Liveness should see that globals are saved back,
40485a18407fSRichard Henderson that is, TS_DEAD, waiting to be reloaded. */
4049b83eabeaSRichard Henderson arg_ts = &s->temps[i];
4050b83eabeaSRichard Henderson tcg_debug_assert(arg_ts->state_ptr == 0
4051b83eabeaSRichard Henderson || arg_ts->state == TS_DEAD);
40525a18407fSRichard Henderson }
40535a18407fSRichard Henderson }
40545a18407fSRichard Henderson
40555a18407fSRichard Henderson /* Outputs become available. */
405661f15c48SRichard Henderson if (opc == INDEX_op_mov_i32 || opc == INDEX_op_mov_i64) {
405761f15c48SRichard Henderson arg_ts = arg_temp(op->args[0]);
405861f15c48SRichard Henderson dir_ts = arg_ts->state_ptr;
405961f15c48SRichard Henderson if (dir_ts) {
406061f15c48SRichard Henderson op->args[0] = temp_arg(dir_ts);
406161f15c48SRichard Henderson changes = true;
406261f15c48SRichard Henderson
406361f15c48SRichard Henderson /* The output is now live and modified. */
406461f15c48SRichard Henderson arg_ts->state = 0;
406561f15c48SRichard Henderson
406661f15c48SRichard Henderson if (NEED_SYNC_ARG(0)) {
406761f15c48SRichard Henderson TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
406861f15c48SRichard Henderson ? INDEX_op_st_i32
406961f15c48SRichard Henderson : INDEX_op_st_i64);
4070d4478943SPhilippe Mathieu-Daudé TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3);
407161f15c48SRichard Henderson TCGTemp *out_ts = dir_ts;
407261f15c48SRichard Henderson
407361f15c48SRichard Henderson if (IS_DEAD_ARG(0)) {
407461f15c48SRichard Henderson out_ts = arg_temp(op->args[1]);
407561f15c48SRichard Henderson arg_ts->state = TS_DEAD;
407661f15c48SRichard Henderson tcg_op_remove(s, op);
407761f15c48SRichard Henderson } else {
407861f15c48SRichard Henderson arg_ts->state = TS_MEM;
407961f15c48SRichard Henderson }
408061f15c48SRichard Henderson
408161f15c48SRichard Henderson sop->args[0] = temp_arg(out_ts);
408261f15c48SRichard Henderson sop->args[1] = temp_arg(arg_ts->mem_base);
408361f15c48SRichard Henderson sop->args[2] = arg_ts->mem_offset;
408461f15c48SRichard Henderson } else {
408561f15c48SRichard Henderson tcg_debug_assert(!IS_DEAD_ARG(0));
408661f15c48SRichard Henderson }
408761f15c48SRichard Henderson }
408861f15c48SRichard Henderson } else {
40895a18407fSRichard Henderson for (i = 0; i < nb_oargs; i++) {
4090b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]);
4091b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr;
4092b83eabeaSRichard Henderson if (!dir_ts) {
40935a18407fSRichard Henderson continue;
40945a18407fSRichard Henderson }
4095b83eabeaSRichard Henderson op->args[i] = temp_arg(dir_ts);
40965a18407fSRichard Henderson changes = true;
40975a18407fSRichard Henderson
40985a18407fSRichard Henderson /* The output is now live and modified. */
4099b83eabeaSRichard Henderson arg_ts->state = 0;
41005a18407fSRichard Henderson
41015a18407fSRichard Henderson /* Sync outputs upon their last write. */
41025a18407fSRichard Henderson if (NEED_SYNC_ARG(i)) {
4103b83eabeaSRichard Henderson TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
41045a18407fSRichard Henderson ? INDEX_op_st_i32
41055a18407fSRichard Henderson : INDEX_op_st_i64);
4106d4478943SPhilippe Mathieu-Daudé TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3);
41075a18407fSRichard Henderson
4108b83eabeaSRichard Henderson sop->args[0] = temp_arg(dir_ts);
4109b83eabeaSRichard Henderson sop->args[1] = temp_arg(arg_ts->mem_base);
4110b83eabeaSRichard Henderson sop->args[2] = arg_ts->mem_offset;
41115a18407fSRichard Henderson
4112b83eabeaSRichard Henderson arg_ts->state = TS_MEM;
41135a18407fSRichard Henderson }
41145a18407fSRichard Henderson /* Drop outputs that are dead. */
41155a18407fSRichard Henderson if (IS_DEAD_ARG(i)) {
4116b83eabeaSRichard Henderson arg_ts->state = TS_DEAD;
41175a18407fSRichard Henderson }
41185a18407fSRichard Henderson }
41195a18407fSRichard Henderson }
412061f15c48SRichard Henderson }
41215a18407fSRichard Henderson
41225a18407fSRichard Henderson return changes;
41235a18407fSRichard Henderson }
41245a18407fSRichard Henderson
temp_allocate_frame(TCGContext * s,TCGTemp * ts)41252272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts)
4126c896fe29Sbellard {
412731c96417SRichard Henderson intptr_t off;
4128273eb50cSRichard Henderson int size, align;
4129c1c09194SRichard Henderson
4130273eb50cSRichard Henderson /* When allocating an object, look at the full type. */
4131273eb50cSRichard Henderson size = tcg_type_size(ts->base_type);
4132273eb50cSRichard Henderson switch (ts->base_type) {
4133c1c09194SRichard Henderson case TCG_TYPE_I32:
413431c96417SRichard Henderson align = 4;
4135c1c09194SRichard Henderson break;
4136c1c09194SRichard Henderson case TCG_TYPE_I64:
4137c1c09194SRichard Henderson case TCG_TYPE_V64:
413831c96417SRichard Henderson align = 8;
4139c1c09194SRichard Henderson break;
414043eef72fSRichard Henderson case TCG_TYPE_I128:
4141c1c09194SRichard Henderson case TCG_TYPE_V128:
4142c1c09194SRichard Henderson case TCG_TYPE_V256:
414343eef72fSRichard Henderson /*
414443eef72fSRichard Henderson * Note that we do not require aligned storage for V256,
414543eef72fSRichard Henderson * and that we provide alignment for I128 to match V128,
414643eef72fSRichard Henderson * even if that's above what the host ABI requires.
414743eef72fSRichard Henderson */
414831c96417SRichard Henderson align = 16;
4149c1c09194SRichard Henderson break;
4150c1c09194SRichard Henderson default:
4151c1c09194SRichard Henderson g_assert_not_reached();
4152b591dc59SBlue Swirl }
4153c1c09194SRichard Henderson
4154b9537d59SRichard Henderson /*
4155b9537d59SRichard Henderson * Assume the stack is sufficiently aligned.
4156b9537d59SRichard Henderson * This affects e.g. ARM NEON, where we have 8 byte stack alignment
4157b9537d59SRichard Henderson * and do not require 16 byte vector alignment. This seems slightly
4158b9537d59SRichard Henderson * easier than fully parameterizing the above switch statement.
4159b9537d59SRichard Henderson */
4160b9537d59SRichard Henderson align = MIN(TCG_TARGET_STACK_ALIGN, align);
4161c1c09194SRichard Henderson off = ROUND_UP(s->current_frame_offset, align);
4162732d5897SRichard Henderson
4163732d5897SRichard Henderson /* If we've exhausted the stack frame, restart with a smaller TB. */
4164732d5897SRichard Henderson if (off + size > s->frame_end) {
4165732d5897SRichard Henderson tcg_raise_tb_overflow(s);
4166732d5897SRichard Henderson }
4167c1c09194SRichard Henderson s->current_frame_offset = off + size;
41689defd1bdSRichard Henderson #if defined(__sparc__)
4169273eb50cSRichard Henderson off += TCG_TARGET_STACK_BIAS;
41709defd1bdSRichard Henderson #endif
4171273eb50cSRichard Henderson
4172273eb50cSRichard Henderson /* If the object was subdivided, assign memory to all the parts. */
4173273eb50cSRichard Henderson if (ts->base_type != ts->type) {
4174273eb50cSRichard Henderson int part_size = tcg_type_size(ts->type);
4175273eb50cSRichard Henderson int part_count = size / part_size;
4176273eb50cSRichard Henderson
4177273eb50cSRichard Henderson /*
4178273eb50cSRichard Henderson * Each part is allocated sequentially in tcg_temp_new_internal.
4179273eb50cSRichard Henderson * Jump back to the first part by subtracting the current index.
4180273eb50cSRichard Henderson */
4181273eb50cSRichard Henderson ts -= ts->temp_subindex;
4182273eb50cSRichard Henderson for (int i = 0; i < part_count; ++i) {
4183273eb50cSRichard Henderson ts[i].mem_offset = off + i * part_size;
4184273eb50cSRichard Henderson ts[i].mem_base = s->frame_temp;
4185273eb50cSRichard Henderson ts[i].mem_allocated = 1;
4186273eb50cSRichard Henderson }
4187273eb50cSRichard Henderson } else {
4188273eb50cSRichard Henderson ts->mem_offset = off;
4189b3a62939SRichard Henderson ts->mem_base = s->frame_temp;
4190c896fe29Sbellard ts->mem_allocated = 1;
4191c896fe29Sbellard }
4192273eb50cSRichard Henderson }
4193c896fe29Sbellard
4194098859f1SRichard Henderson /* Assign @reg to @ts, and update reg_to_temp[]. */
set_temp_val_reg(TCGContext * s,TCGTemp * ts,TCGReg reg)4195098859f1SRichard Henderson static void set_temp_val_reg(TCGContext *s, TCGTemp *ts, TCGReg reg)
4196098859f1SRichard Henderson {
4197098859f1SRichard Henderson if (ts->val_type == TEMP_VAL_REG) {
4198098859f1SRichard Henderson TCGReg old = ts->reg;
4199098859f1SRichard Henderson tcg_debug_assert(s->reg_to_temp[old] == ts);
4200098859f1SRichard Henderson if (old == reg) {
4201098859f1SRichard Henderson return;
4202098859f1SRichard Henderson }
4203098859f1SRichard Henderson s->reg_to_temp[old] = NULL;
4204098859f1SRichard Henderson }
4205098859f1SRichard Henderson tcg_debug_assert(s->reg_to_temp[reg] == NULL);
4206098859f1SRichard Henderson s->reg_to_temp[reg] = ts;
4207098859f1SRichard Henderson ts->val_type = TEMP_VAL_REG;
4208098859f1SRichard Henderson ts->reg = reg;
4209098859f1SRichard Henderson }
4210098859f1SRichard Henderson
4211098859f1SRichard Henderson /* Assign a non-register value type to @ts, and update reg_to_temp[]. */
set_temp_val_nonreg(TCGContext * s,TCGTemp * ts,TCGTempVal type)4212098859f1SRichard Henderson static void set_temp_val_nonreg(TCGContext *s, TCGTemp *ts, TCGTempVal type)
4213098859f1SRichard Henderson {
4214098859f1SRichard Henderson tcg_debug_assert(type != TEMP_VAL_REG);
4215098859f1SRichard Henderson if (ts->val_type == TEMP_VAL_REG) {
4216098859f1SRichard Henderson TCGReg reg = ts->reg;
4217098859f1SRichard Henderson tcg_debug_assert(s->reg_to_temp[reg] == ts);
4218098859f1SRichard Henderson s->reg_to_temp[reg] = NULL;
4219098859f1SRichard Henderson }
4220098859f1SRichard Henderson ts->val_type = type;
4221098859f1SRichard Henderson }
4222098859f1SRichard Henderson
4223b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet);
4224b3915dbbSRichard Henderson
422559d7c14eSRichard Henderson /* Mark a temporary as free or dead. If 'free_or_dead' is negative,
422659d7c14eSRichard Henderson mark it free; otherwise mark it dead. */
temp_free_or_dead(TCGContext * s,TCGTemp * ts,int free_or_dead)422759d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead)
4228c896fe29Sbellard {
4229c0522136SRichard Henderson TCGTempVal new_type;
4230c0522136SRichard Henderson
4231c0522136SRichard Henderson switch (ts->kind) {
4232c0522136SRichard Henderson case TEMP_FIXED:
423359d7c14eSRichard Henderson return;
4234c0522136SRichard Henderson case TEMP_GLOBAL:
4235f57c6915SRichard Henderson case TEMP_TB:
4236c0522136SRichard Henderson new_type = TEMP_VAL_MEM;
4237c0522136SRichard Henderson break;
4238c7482438SRichard Henderson case TEMP_EBB:
4239c0522136SRichard Henderson new_type = free_or_dead < 0 ? TEMP_VAL_MEM : TEMP_VAL_DEAD;
4240c0522136SRichard Henderson break;
4241c0522136SRichard Henderson case TEMP_CONST:
4242c0522136SRichard Henderson new_type = TEMP_VAL_CONST;
4243c0522136SRichard Henderson break;
4244c0522136SRichard Henderson default:
4245c0522136SRichard Henderson g_assert_not_reached();
424659d7c14eSRichard Henderson }
4247098859f1SRichard Henderson set_temp_val_nonreg(s, ts, new_type);
424859d7c14eSRichard Henderson }
4249c896fe29Sbellard
425059d7c14eSRichard Henderson /* Mark a temporary as dead. */
temp_dead(TCGContext * s,TCGTemp * ts)425159d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts)
425259d7c14eSRichard Henderson {
425359d7c14eSRichard Henderson temp_free_or_dead(s, ts, 1);
425459d7c14eSRichard Henderson }
425559d7c14eSRichard Henderson
425659d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary
425759d7c14eSRichard Henderson registers needs to be allocated to store a constant. If 'free_or_dead'
425859d7c14eSRichard Henderson is non-zero, subsequently release the temporary; if it is positive, the
425959d7c14eSRichard 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)426098b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs,
426198b4e186SRichard Henderson TCGRegSet preferred_regs, int free_or_dead)
426259d7c14eSRichard Henderson {
4263c0522136SRichard Henderson if (!temp_readonly(ts) && !ts->mem_coherent) {
42647f6ceedfSAurelien Jarno if (!ts->mem_allocated) {
42652272e4a7SRichard Henderson temp_allocate_frame(s, ts);
426659d7c14eSRichard Henderson }
426759d7c14eSRichard Henderson switch (ts->val_type) {
426859d7c14eSRichard Henderson case TEMP_VAL_CONST:
426959d7c14eSRichard Henderson /* If we're going to free the temp immediately, then we won't
427059d7c14eSRichard Henderson require it later in a register, so attempt to store the
427159d7c14eSRichard Henderson constant to memory directly. */
427259d7c14eSRichard Henderson if (free_or_dead
427359d7c14eSRichard Henderson && tcg_out_sti(s, ts->type, ts->val,
427459d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset)) {
427559d7c14eSRichard Henderson break;
427659d7c14eSRichard Henderson }
427759d7c14eSRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type],
427898b4e186SRichard Henderson allocated_regs, preferred_regs);
427959d7c14eSRichard Henderson /* fallthrough */
428059d7c14eSRichard Henderson
428159d7c14eSRichard Henderson case TEMP_VAL_REG:
428259d7c14eSRichard Henderson tcg_out_st(s, ts->type, ts->reg,
428359d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset);
428459d7c14eSRichard Henderson break;
428559d7c14eSRichard Henderson
428659d7c14eSRichard Henderson case TEMP_VAL_MEM:
428759d7c14eSRichard Henderson break;
428859d7c14eSRichard Henderson
428959d7c14eSRichard Henderson case TEMP_VAL_DEAD:
429059d7c14eSRichard Henderson default:
4291732e89f4SRichard Henderson g_assert_not_reached();
4292c896fe29Sbellard }
42937f6ceedfSAurelien Jarno ts->mem_coherent = 1;
42947f6ceedfSAurelien Jarno }
429559d7c14eSRichard Henderson if (free_or_dead) {
429659d7c14eSRichard Henderson temp_free_or_dead(s, ts, free_or_dead);
429759d7c14eSRichard Henderson }
429859d7c14eSRichard Henderson }
42997f6ceedfSAurelien Jarno
43007f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */
tcg_reg_free(TCGContext * s,TCGReg reg,TCGRegSet allocated_regs)4301b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs)
43027f6ceedfSAurelien Jarno {
4303f8b2f202SRichard Henderson TCGTemp *ts = s->reg_to_temp[reg];
4304f8b2f202SRichard Henderson if (ts != NULL) {
430598b4e186SRichard Henderson temp_sync(s, ts, allocated_regs, 0, -1);
4306c896fe29Sbellard }
4307c896fe29Sbellard }
4308c896fe29Sbellard
4309b016486eSRichard Henderson /**
4310b016486eSRichard Henderson * tcg_reg_alloc:
4311b016486eSRichard Henderson * @required_regs: Set of registers in which we must allocate.
4312b016486eSRichard Henderson * @allocated_regs: Set of registers which must be avoided.
4313b016486eSRichard Henderson * @preferred_regs: Set of registers we should prefer.
4314b016486eSRichard Henderson * @rev: True if we search the registers in "indirect" order.
4315b016486eSRichard Henderson *
4316b016486eSRichard Henderson * The allocated register must be in @required_regs & ~@allocated_regs,
4317b016486eSRichard Henderson * but if we can put it in @preferred_regs we may save a move later.
4318b016486eSRichard Henderson */
tcg_reg_alloc(TCGContext * s,TCGRegSet required_regs,TCGRegSet allocated_regs,TCGRegSet preferred_regs,bool rev)4319b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs,
4320b016486eSRichard Henderson TCGRegSet allocated_regs,
4321b016486eSRichard Henderson TCGRegSet preferred_regs, bool rev)
4322c896fe29Sbellard {
4323b016486eSRichard Henderson int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
4324b016486eSRichard Henderson TCGRegSet reg_ct[2];
432591478cefSRichard Henderson const int *order;
4326c896fe29Sbellard
4327b016486eSRichard Henderson reg_ct[1] = required_regs & ~allocated_regs;
4328b016486eSRichard Henderson tcg_debug_assert(reg_ct[1] != 0);
4329b016486eSRichard Henderson reg_ct[0] = reg_ct[1] & preferred_regs;
4330b016486eSRichard Henderson
4331b016486eSRichard Henderson /* Skip the preferred_regs option if it cannot be satisfied,
4332b016486eSRichard Henderson or if the preference made no difference. */
4333b016486eSRichard Henderson f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1];
4334b016486eSRichard Henderson
433591478cefSRichard Henderson order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
4336c896fe29Sbellard
4337b016486eSRichard Henderson /* Try free registers, preferences first. */
4338b016486eSRichard Henderson for (j = f; j < 2; j++) {
4339b016486eSRichard Henderson TCGRegSet set = reg_ct[j];
4340b016486eSRichard Henderson
4341b016486eSRichard Henderson if (tcg_regset_single(set)) {
4342b016486eSRichard Henderson /* One register in the set. */
4343b016486eSRichard Henderson TCGReg reg = tcg_regset_first(set);
4344b016486eSRichard Henderson if (s->reg_to_temp[reg] == NULL) {
4345c896fe29Sbellard return reg;
4346c896fe29Sbellard }
4347b016486eSRichard Henderson } else {
434891478cefSRichard Henderson for (i = 0; i < n; i++) {
4349b016486eSRichard Henderson TCGReg reg = order[i];
4350b016486eSRichard Henderson if (s->reg_to_temp[reg] == NULL &&
4351b016486eSRichard Henderson tcg_regset_test_reg(set, reg)) {
4352b016486eSRichard Henderson return reg;
4353b016486eSRichard Henderson }
4354b016486eSRichard Henderson }
4355b016486eSRichard Henderson }
4356b016486eSRichard Henderson }
4357b016486eSRichard Henderson
4358b016486eSRichard Henderson /* We must spill something. */
4359b016486eSRichard Henderson for (j = f; j < 2; j++) {
4360b016486eSRichard Henderson TCGRegSet set = reg_ct[j];
4361b016486eSRichard Henderson
4362b016486eSRichard Henderson if (tcg_regset_single(set)) {
4363b016486eSRichard Henderson /* One register in the set. */
4364b016486eSRichard Henderson TCGReg reg = tcg_regset_first(set);
4365b3915dbbSRichard Henderson tcg_reg_free(s, reg, allocated_regs);
4366c896fe29Sbellard return reg;
4367b016486eSRichard Henderson } else {
4368b016486eSRichard Henderson for (i = 0; i < n; i++) {
4369b016486eSRichard Henderson TCGReg reg = order[i];
4370b016486eSRichard Henderson if (tcg_regset_test_reg(set, reg)) {
4371b016486eSRichard Henderson tcg_reg_free(s, reg, allocated_regs);
4372b016486eSRichard Henderson return reg;
4373b016486eSRichard Henderson }
4374b016486eSRichard Henderson }
4375c896fe29Sbellard }
4376c896fe29Sbellard }
4377c896fe29Sbellard
4378732e89f4SRichard Henderson g_assert_not_reached();
4379c896fe29Sbellard }
4380c896fe29Sbellard
tcg_reg_alloc_pair(TCGContext * s,TCGRegSet required_regs,TCGRegSet allocated_regs,TCGRegSet preferred_regs,bool rev)438129f5e925SRichard Henderson static TCGReg tcg_reg_alloc_pair(TCGContext *s, TCGRegSet required_regs,
438229f5e925SRichard Henderson TCGRegSet allocated_regs,
438329f5e925SRichard Henderson TCGRegSet preferred_regs, bool rev)
438429f5e925SRichard Henderson {
438529f5e925SRichard Henderson int i, j, k, fmin, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
438629f5e925SRichard Henderson TCGRegSet reg_ct[2];
438729f5e925SRichard Henderson const int *order;
438829f5e925SRichard Henderson
438929f5e925SRichard Henderson /* Ensure that if I is not in allocated_regs, I+1 is not either. */
439029f5e925SRichard Henderson reg_ct[1] = required_regs & ~(allocated_regs | (allocated_regs >> 1));
439129f5e925SRichard Henderson tcg_debug_assert(reg_ct[1] != 0);
439229f5e925SRichard Henderson reg_ct[0] = reg_ct[1] & preferred_regs;
439329f5e925SRichard Henderson
439429f5e925SRichard Henderson order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
439529f5e925SRichard Henderson
439629f5e925SRichard Henderson /*
439729f5e925SRichard Henderson * Skip the preferred_regs option if it cannot be satisfied,
439829f5e925SRichard Henderson * or if the preference made no difference.
439929f5e925SRichard Henderson */
440029f5e925SRichard Henderson k = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1];
440129f5e925SRichard Henderson
440229f5e925SRichard Henderson /*
440329f5e925SRichard Henderson * Minimize the number of flushes by looking for 2 free registers first,
440429f5e925SRichard Henderson * then a single flush, then two flushes.
440529f5e925SRichard Henderson */
440629f5e925SRichard Henderson for (fmin = 2; fmin >= 0; fmin--) {
440729f5e925SRichard Henderson for (j = k; j < 2; j++) {
440829f5e925SRichard Henderson TCGRegSet set = reg_ct[j];
440929f5e925SRichard Henderson
441029f5e925SRichard Henderson for (i = 0; i < n; i++) {
441129f5e925SRichard Henderson TCGReg reg = order[i];
441229f5e925SRichard Henderson
441329f5e925SRichard Henderson if (tcg_regset_test_reg(set, reg)) {
441429f5e925SRichard Henderson int f = !s->reg_to_temp[reg] + !s->reg_to_temp[reg + 1];
441529f5e925SRichard Henderson if (f >= fmin) {
441629f5e925SRichard Henderson tcg_reg_free(s, reg, allocated_regs);
441729f5e925SRichard Henderson tcg_reg_free(s, reg + 1, allocated_regs);
441829f5e925SRichard Henderson return reg;
441929f5e925SRichard Henderson }
442029f5e925SRichard Henderson }
442129f5e925SRichard Henderson }
442229f5e925SRichard Henderson }
442329f5e925SRichard Henderson }
4424732e89f4SRichard Henderson g_assert_not_reached();
442529f5e925SRichard Henderson }
442629f5e925SRichard Henderson
442740ae5c62SRichard Henderson /* Make sure the temporary is in a register. If needed, allocate the register
442840ae5c62SRichard Henderson from DESIRED while avoiding ALLOCATED. */
temp_load(TCGContext * s,TCGTemp * ts,TCGRegSet desired_regs,TCGRegSet allocated_regs,TCGRegSet preferred_regs)442940ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs,
4430b722452aSRichard Henderson TCGRegSet allocated_regs, TCGRegSet preferred_regs)
443140ae5c62SRichard Henderson {
443240ae5c62SRichard Henderson TCGReg reg;
443340ae5c62SRichard Henderson
443440ae5c62SRichard Henderson switch (ts->val_type) {
443540ae5c62SRichard Henderson case TEMP_VAL_REG:
443640ae5c62SRichard Henderson return;
443740ae5c62SRichard Henderson case TEMP_VAL_CONST:
4438b016486eSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
4439b722452aSRichard Henderson preferred_regs, ts->indirect_base);
44400a6a8bc8SRichard Henderson if (ts->type <= TCG_TYPE_I64) {
444140ae5c62SRichard Henderson tcg_out_movi(s, ts->type, reg, ts->val);
44420a6a8bc8SRichard Henderson } else {
44434e186175SRichard Henderson uint64_t val = ts->val;
44444e186175SRichard Henderson MemOp vece = MO_64;
44454e186175SRichard Henderson
44464e186175SRichard Henderson /*
44474e186175SRichard Henderson * Find the minimal vector element that matches the constant.
44484e186175SRichard Henderson * The targets will, in general, have to do this search anyway,
44494e186175SRichard Henderson * do this generically.
44504e186175SRichard Henderson */
44514e186175SRichard Henderson if (val == dup_const(MO_8, val)) {
44524e186175SRichard Henderson vece = MO_8;
44534e186175SRichard Henderson } else if (val == dup_const(MO_16, val)) {
44544e186175SRichard Henderson vece = MO_16;
44550b4286ddSRichard Henderson } else if (val == dup_const(MO_32, val)) {
44564e186175SRichard Henderson vece = MO_32;
44574e186175SRichard Henderson }
44584e186175SRichard Henderson
44594e186175SRichard Henderson tcg_out_dupi_vec(s, ts->type, vece, reg, ts->val);
44600a6a8bc8SRichard Henderson }
446140ae5c62SRichard Henderson ts->mem_coherent = 0;
446240ae5c62SRichard Henderson break;
446340ae5c62SRichard Henderson case TEMP_VAL_MEM:
4464b016486eSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
4465b722452aSRichard Henderson preferred_regs, ts->indirect_base);
446640ae5c62SRichard Henderson tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset);
446740ae5c62SRichard Henderson ts->mem_coherent = 1;
446840ae5c62SRichard Henderson break;
446940ae5c62SRichard Henderson case TEMP_VAL_DEAD:
447040ae5c62SRichard Henderson default:
4471732e89f4SRichard Henderson g_assert_not_reached();
447240ae5c62SRichard Henderson }
4473098859f1SRichard Henderson set_temp_val_reg(s, ts, reg);
447440ae5c62SRichard Henderson }
447540ae5c62SRichard Henderson
447659d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a
4477e8996ee0Sbellard temporary registers needs to be allocated to store a constant. */
temp_save(TCGContext * s,TCGTemp * ts,TCGRegSet allocated_regs)447859d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs)
44791ad80729SAurelien Jarno {
44802c0366f0SAurelien Jarno /* The liveness analysis already ensures that globals are back
4481eabb7b91SAurelien Jarno in memory. Keep an tcg_debug_assert for safety. */
4482e01fa97dSRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || temp_readonly(ts));
44831ad80729SAurelien Jarno }
44841ad80729SAurelien Jarno
44859814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be
4486641d5fbeSbellard modified be the following code. 'allocated_regs' is used in case a
4487641d5fbeSbellard temporary registers needs to be allocated to store a constant. */
save_globals(TCGContext * s,TCGRegSet allocated_regs)4488641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
4489641d5fbeSbellard {
4490ac3b8891SRichard Henderson int i, n;
4491641d5fbeSbellard
4492ac3b8891SRichard Henderson for (i = 0, n = s->nb_globals; i < n; i++) {
4493b13eb728SRichard Henderson temp_save(s, &s->temps[i], allocated_regs);
4494641d5fbeSbellard }
4495e5097dc8Sbellard }
4496e5097dc8Sbellard
44973d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be
44983d5c5f87SAurelien Jarno read by the following code. 'allocated_regs' is used in case a
44993d5c5f87SAurelien Jarno temporary registers needs to be allocated to store a constant. */
sync_globals(TCGContext * s,TCGRegSet allocated_regs)45003d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs)
45013d5c5f87SAurelien Jarno {
4502ac3b8891SRichard Henderson int i, n;
45033d5c5f87SAurelien Jarno
4504ac3b8891SRichard Henderson for (i = 0, n = s->nb_globals; i < n; i++) {
450512b9b11aSRichard Henderson TCGTemp *ts = &s->temps[i];
450612b9b11aSRichard Henderson tcg_debug_assert(ts->val_type != TEMP_VAL_REG
4507ee17db83SRichard Henderson || ts->kind == TEMP_FIXED
450812b9b11aSRichard Henderson || ts->mem_coherent);
45093d5c5f87SAurelien Jarno }
45103d5c5f87SAurelien Jarno }
45113d5c5f87SAurelien Jarno
4512e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and
4513e8996ee0Sbellard all globals are stored at their canonical location. */
tcg_reg_alloc_bb_end(TCGContext * s,TCGRegSet allocated_regs)4514e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
4515e5097dc8Sbellard {
4516e5097dc8Sbellard int i;
4517e5097dc8Sbellard
4518c896fe29Sbellard for (i = s->nb_globals; i < s->nb_temps; i++) {
4519b13eb728SRichard Henderson TCGTemp *ts = &s->temps[i];
4520c0522136SRichard Henderson
4521c0522136SRichard Henderson switch (ts->kind) {
4522f57c6915SRichard Henderson case TEMP_TB:
4523b13eb728SRichard Henderson temp_save(s, ts, allocated_regs);
4524c0522136SRichard Henderson break;
4525c7482438SRichard Henderson case TEMP_EBB:
45262c0366f0SAurelien Jarno /* The liveness analysis already ensures that temps are dead.
4527eabb7b91SAurelien Jarno Keep an tcg_debug_assert for safety. */
4528eabb7b91SAurelien Jarno tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
4529c0522136SRichard Henderson break;
4530c0522136SRichard Henderson case TEMP_CONST:
4531c0522136SRichard Henderson /* Similarly, we should have freed any allocated register. */
4532c0522136SRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_CONST);
4533c0522136SRichard Henderson break;
4534c0522136SRichard Henderson default:
4535c0522136SRichard Henderson g_assert_not_reached();
4536c896fe29Sbellard }
4537641d5fbeSbellard }
4538e8996ee0Sbellard
4539e8996ee0Sbellard save_globals(s, allocated_regs);
4540c896fe29Sbellard }
4541c896fe29Sbellard
4542bab1671fSRichard Henderson /*
4543c7482438SRichard Henderson * At a conditional branch, we assume all temporaries are dead unless
4544c7482438SRichard Henderson * explicitly live-across-conditional-branch; all globals and local
4545c7482438SRichard Henderson * temps are synced to their location.
4546b4cb76e6SRichard Henderson */
tcg_reg_alloc_cbranch(TCGContext * s,TCGRegSet allocated_regs)4547b4cb76e6SRichard Henderson static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs)
4548b4cb76e6SRichard Henderson {
4549b4cb76e6SRichard Henderson sync_globals(s, allocated_regs);
4550b4cb76e6SRichard Henderson
4551b4cb76e6SRichard Henderson for (int i = s->nb_globals; i < s->nb_temps; i++) {
4552b4cb76e6SRichard Henderson TCGTemp *ts = &s->temps[i];
4553b4cb76e6SRichard Henderson /*
4554b4cb76e6SRichard Henderson * The liveness analysis already ensures that temps are dead.
4555b4cb76e6SRichard Henderson * Keep tcg_debug_asserts for safety.
4556b4cb76e6SRichard Henderson */
4557c0522136SRichard Henderson switch (ts->kind) {
4558f57c6915SRichard Henderson case TEMP_TB:
4559b4cb76e6SRichard Henderson tcg_debug_assert(ts->val_type != TEMP_VAL_REG || ts->mem_coherent);
4560c0522136SRichard Henderson break;
4561c7482438SRichard Henderson case TEMP_EBB:
4562c0522136SRichard Henderson case TEMP_CONST:
4563c0522136SRichard Henderson break;
4564c0522136SRichard Henderson default:
4565c0522136SRichard Henderson g_assert_not_reached();
4566b4cb76e6SRichard Henderson }
4567b4cb76e6SRichard Henderson }
4568b4cb76e6SRichard Henderson }
4569b4cb76e6SRichard Henderson
4570b4cb76e6SRichard Henderson /*
4571c58f4c97SRichard Henderson * Specialized code generation for INDEX_op_mov_* with a constant.
4572bab1671fSRichard Henderson */
tcg_reg_alloc_do_movi(TCGContext * s,TCGTemp * ots,tcg_target_ulong val,TCGLifeData arg_life,TCGRegSet preferred_regs)45730fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots,
4574ba87719cSRichard Henderson tcg_target_ulong val, TCGLifeData arg_life,
4575ba87719cSRichard Henderson TCGRegSet preferred_regs)
4576e8996ee0Sbellard {
4577d63e3b6eSRichard Henderson /* ENV should not be modified. */
4578e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ots));
457959d7c14eSRichard Henderson
458059d7c14eSRichard Henderson /* The movi is not explicitly generated here. */
4581098859f1SRichard Henderson set_temp_val_nonreg(s, ots, TEMP_VAL_CONST);
4582e8996ee0Sbellard ots->val = val;
458359d7c14eSRichard Henderson ots->mem_coherent = 0;
4584ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) {
4585ba87719cSRichard Henderson temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0));
458659d7c14eSRichard Henderson } else if (IS_DEAD_ARG(0)) {
4587f8bf00f1SRichard Henderson temp_dead(s, ots);
45884c4e1ab2SAurelien Jarno }
4589e8996ee0Sbellard }
4590e8996ee0Sbellard
4591bab1671fSRichard Henderson /*
4592bab1671fSRichard Henderson * Specialized code generation for INDEX_op_mov_*.
4593bab1671fSRichard Henderson */
tcg_reg_alloc_mov(TCGContext * s,const TCGOp * op)4594dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op)
4595c896fe29Sbellard {
4596dd186292SRichard Henderson const TCGLifeData arg_life = op->life;
459769e3706dSRichard Henderson TCGRegSet allocated_regs, preferred_regs;
4598c896fe29Sbellard TCGTemp *ts, *ots;
4599450445d5SRichard Henderson TCGType otype, itype;
4600098859f1SRichard Henderson TCGReg oreg, ireg;
4601c896fe29Sbellard
4602d21369f5SRichard Henderson allocated_regs = s->reserved_regs;
460331fd884bSRichard Henderson preferred_regs = output_pref(op, 0);
460443439139SRichard Henderson ots = arg_temp(op->args[0]);
460543439139SRichard Henderson ts = arg_temp(op->args[1]);
4606450445d5SRichard Henderson
4607d63e3b6eSRichard Henderson /* ENV should not be modified. */
4608e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ots));
4609d63e3b6eSRichard Henderson
4610450445d5SRichard Henderson /* Note that otype != itype for no-op truncation. */
4611450445d5SRichard Henderson otype = ots->type;
4612450445d5SRichard Henderson itype = ts->type;
4613c896fe29Sbellard
46140fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_CONST) {
46150fe4fca4SPaolo Bonzini /* propagate constant or generate sti */
46160fe4fca4SPaolo Bonzini tcg_target_ulong val = ts->val;
46170fe4fca4SPaolo Bonzini if (IS_DEAD_ARG(1)) {
46180fe4fca4SPaolo Bonzini temp_dead(s, ts);
46190fe4fca4SPaolo Bonzini }
462069e3706dSRichard Henderson tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs);
46210fe4fca4SPaolo Bonzini return;
46220fe4fca4SPaolo Bonzini }
46230fe4fca4SPaolo Bonzini
46240fe4fca4SPaolo Bonzini /* If the source value is in memory we're going to be forced
46250fe4fca4SPaolo Bonzini to have it in a register in order to perform the copy. Copy
46260fe4fca4SPaolo Bonzini the SOURCE value into its own register first, that way we
46270fe4fca4SPaolo Bonzini don't have to reload SOURCE the next time it is used. */
46280fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_MEM) {
462969e3706dSRichard Henderson temp_load(s, ts, tcg_target_available_regs[itype],
463069e3706dSRichard Henderson allocated_regs, preferred_regs);
4631c29c1d7eSAurelien Jarno }
46320fe4fca4SPaolo Bonzini tcg_debug_assert(ts->val_type == TEMP_VAL_REG);
4633098859f1SRichard Henderson ireg = ts->reg;
4634098859f1SRichard Henderson
4635d63e3b6eSRichard Henderson if (IS_DEAD_ARG(0)) {
4636c29c1d7eSAurelien Jarno /* mov to a non-saved dead register makes no sense (even with
4637c29c1d7eSAurelien Jarno liveness analysis disabled). */
4638eabb7b91SAurelien Jarno tcg_debug_assert(NEED_SYNC_ARG(0));
4639c29c1d7eSAurelien Jarno if (!ots->mem_allocated) {
46402272e4a7SRichard Henderson temp_allocate_frame(s, ots);
4641c29c1d7eSAurelien Jarno }
4642098859f1SRichard Henderson tcg_out_st(s, otype, ireg, ots->mem_base->reg, ots->mem_offset);
4643c29c1d7eSAurelien Jarno if (IS_DEAD_ARG(1)) {
4644f8bf00f1SRichard Henderson temp_dead(s, ts);
4645c29c1d7eSAurelien Jarno }
4646f8bf00f1SRichard Henderson temp_dead(s, ots);
4647098859f1SRichard Henderson return;
4648098859f1SRichard Henderson }
4649098859f1SRichard Henderson
4650ee17db83SRichard Henderson if (IS_DEAD_ARG(1) && ts->kind != TEMP_FIXED) {
4651098859f1SRichard Henderson /*
4652098859f1SRichard Henderson * The mov can be suppressed. Kill input first, so that it
4653098859f1SRichard Henderson * is unlinked from reg_to_temp, then set the output to the
4654098859f1SRichard Henderson * reg that we saved from the input.
4655098859f1SRichard Henderson */
4656f8bf00f1SRichard Henderson temp_dead(s, ts);
4657098859f1SRichard Henderson oreg = ireg;
4658c29c1d7eSAurelien Jarno } else {
4659098859f1SRichard Henderson if (ots->val_type == TEMP_VAL_REG) {
4660098859f1SRichard Henderson oreg = ots->reg;
4661098859f1SRichard Henderson } else {
4662098859f1SRichard Henderson /* Make sure to not spill the input register during allocation. */
4663098859f1SRichard Henderson oreg = tcg_reg_alloc(s, tcg_target_available_regs[otype],
4664098859f1SRichard Henderson allocated_regs | ((TCGRegSet)1 << ireg),
4665098859f1SRichard Henderson preferred_regs, ots->indirect_base);
4666c29c1d7eSAurelien Jarno }
4667098859f1SRichard Henderson if (!tcg_out_mov(s, otype, oreg, ireg)) {
4668240c08d0SRichard Henderson /*
4669240c08d0SRichard Henderson * Cross register class move not supported.
4670240c08d0SRichard Henderson * Store the source register into the destination slot
4671240c08d0SRichard Henderson * and leave the destination temp as TEMP_VAL_MEM.
4672240c08d0SRichard Henderson */
4673e01fa97dSRichard Henderson assert(!temp_readonly(ots));
4674240c08d0SRichard Henderson if (!ts->mem_allocated) {
4675240c08d0SRichard Henderson temp_allocate_frame(s, ots);
4676240c08d0SRichard Henderson }
4677098859f1SRichard Henderson tcg_out_st(s, ts->type, ireg, ots->mem_base->reg, ots->mem_offset);
4678098859f1SRichard Henderson set_temp_val_nonreg(s, ts, TEMP_VAL_MEM);
4679240c08d0SRichard Henderson ots->mem_coherent = 1;
4680240c08d0SRichard Henderson return;
468178113e83SRichard Henderson }
4682c29c1d7eSAurelien Jarno }
4683098859f1SRichard Henderson set_temp_val_reg(s, ots, oreg);
4684c896fe29Sbellard ots->mem_coherent = 0;
4685098859f1SRichard Henderson
4686ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) {
468798b4e186SRichard Henderson temp_sync(s, ots, allocated_regs, 0, 0);
4688c29c1d7eSAurelien Jarno }
4689ec7a869dSAurelien Jarno }
4690c896fe29Sbellard
4691bab1671fSRichard Henderson /*
4692bab1671fSRichard Henderson * Specialized code generation for INDEX_op_dup_vec.
4693bab1671fSRichard Henderson */
tcg_reg_alloc_dup(TCGContext * s,const TCGOp * op)4694bab1671fSRichard Henderson static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op)
4695bab1671fSRichard Henderson {
4696bab1671fSRichard Henderson const TCGLifeData arg_life = op->life;
4697bab1671fSRichard Henderson TCGRegSet dup_out_regs, dup_in_regs;
4698bab1671fSRichard Henderson TCGTemp *its, *ots;
4699bab1671fSRichard Henderson TCGType itype, vtype;
4700bab1671fSRichard Henderson unsigned vece;
470131c96417SRichard Henderson int lowpart_ofs;
4702bab1671fSRichard Henderson bool ok;
4703bab1671fSRichard Henderson
4704bab1671fSRichard Henderson ots = arg_temp(op->args[0]);
4705bab1671fSRichard Henderson its = arg_temp(op->args[1]);
4706bab1671fSRichard Henderson
4707bab1671fSRichard Henderson /* ENV should not be modified. */
4708e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ots));
4709bab1671fSRichard Henderson
4710bab1671fSRichard Henderson itype = its->type;
4711bab1671fSRichard Henderson vece = TCGOP_VECE(op);
4712bab1671fSRichard Henderson vtype = TCGOP_VECL(op) + TCG_TYPE_V64;
4713bab1671fSRichard Henderson
4714bab1671fSRichard Henderson if (its->val_type == TEMP_VAL_CONST) {
4715bab1671fSRichard Henderson /* Propagate constant via movi -> dupi. */
4716bab1671fSRichard Henderson tcg_target_ulong val = its->val;
4717bab1671fSRichard Henderson if (IS_DEAD_ARG(1)) {
4718bab1671fSRichard Henderson temp_dead(s, its);
4719bab1671fSRichard Henderson }
472031fd884bSRichard Henderson tcg_reg_alloc_do_movi(s, ots, val, arg_life, output_pref(op, 0));
4721bab1671fSRichard Henderson return;
4722bab1671fSRichard Henderson }
4723bab1671fSRichard Henderson
47249be0d080SRichard Henderson dup_out_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs;
47259be0d080SRichard Henderson dup_in_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[1].regs;
4726bab1671fSRichard Henderson
4727bab1671fSRichard Henderson /* Allocate the output register now. */
4728bab1671fSRichard Henderson if (ots->val_type != TEMP_VAL_REG) {
4729bab1671fSRichard Henderson TCGRegSet allocated_regs = s->reserved_regs;
4730098859f1SRichard Henderson TCGReg oreg;
4731bab1671fSRichard Henderson
4732bab1671fSRichard Henderson if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) {
4733bab1671fSRichard Henderson /* Make sure to not spill the input register. */
4734bab1671fSRichard Henderson tcg_regset_set_reg(allocated_regs, its->reg);
4735bab1671fSRichard Henderson }
4736098859f1SRichard Henderson oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
473731fd884bSRichard Henderson output_pref(op, 0), ots->indirect_base);
4738098859f1SRichard Henderson set_temp_val_reg(s, ots, oreg);
4739bab1671fSRichard Henderson }
4740bab1671fSRichard Henderson
4741bab1671fSRichard Henderson switch (its->val_type) {
4742bab1671fSRichard Henderson case TEMP_VAL_REG:
4743bab1671fSRichard Henderson /*
4744bab1671fSRichard Henderson * The dup constriaints must be broad, covering all possible VECE.
4745bab1671fSRichard Henderson * However, tcg_op_dup_vec() gets to see the VECE and we allow it
4746bab1671fSRichard Henderson * to fail, indicating that extra moves are required for that case.
4747bab1671fSRichard Henderson */
4748bab1671fSRichard Henderson if (tcg_regset_test_reg(dup_in_regs, its->reg)) {
4749bab1671fSRichard Henderson if (tcg_out_dup_vec(s, vtype, vece, ots->reg, its->reg)) {
4750bab1671fSRichard Henderson goto done;
4751bab1671fSRichard Henderson }
4752bab1671fSRichard Henderson /* Try again from memory or a vector input register. */
4753bab1671fSRichard Henderson }
4754bab1671fSRichard Henderson if (!its->mem_coherent) {
4755bab1671fSRichard Henderson /*
4756bab1671fSRichard Henderson * The input register is not synced, and so an extra store
4757bab1671fSRichard Henderson * would be required to use memory. Attempt an integer-vector
4758bab1671fSRichard Henderson * register move first. We do not have a TCGRegSet for this.
4759bab1671fSRichard Henderson */
4760bab1671fSRichard Henderson if (tcg_out_mov(s, itype, ots->reg, its->reg)) {
4761bab1671fSRichard Henderson break;
4762bab1671fSRichard Henderson }
4763bab1671fSRichard Henderson /* Sync the temp back to its slot and load from there. */
4764bab1671fSRichard Henderson temp_sync(s, its, s->reserved_regs, 0, 0);
4765bab1671fSRichard Henderson }
4766bab1671fSRichard Henderson /* fall through */
4767bab1671fSRichard Henderson
4768bab1671fSRichard Henderson case TEMP_VAL_MEM:
476931c96417SRichard Henderson lowpart_ofs = 0;
477031c96417SRichard Henderson if (HOST_BIG_ENDIAN) {
477131c96417SRichard Henderson lowpart_ofs = tcg_type_size(itype) - (1 << vece);
477231c96417SRichard Henderson }
4773d6ecb4a9SRichard Henderson if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg,
477431c96417SRichard Henderson its->mem_offset + lowpart_ofs)) {
4775d6ecb4a9SRichard Henderson goto done;
4776d6ecb4a9SRichard Henderson }
4777098859f1SRichard Henderson /* Load the input into the destination vector register. */
4778bab1671fSRichard Henderson tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset);
4779bab1671fSRichard Henderson break;
4780bab1671fSRichard Henderson
4781bab1671fSRichard Henderson default:
4782bab1671fSRichard Henderson g_assert_not_reached();
4783bab1671fSRichard Henderson }
4784bab1671fSRichard Henderson
4785bab1671fSRichard Henderson /* We now have a vector input register, so dup must succeed. */
4786bab1671fSRichard Henderson ok = tcg_out_dup_vec(s, vtype, vece, ots->reg, ots->reg);
4787bab1671fSRichard Henderson tcg_debug_assert(ok);
4788bab1671fSRichard Henderson
4789bab1671fSRichard Henderson done:
479036f5539cSRichard Henderson ots->mem_coherent = 0;
4791bab1671fSRichard Henderson if (IS_DEAD_ARG(1)) {
4792bab1671fSRichard Henderson temp_dead(s, its);
4793bab1671fSRichard Henderson }
4794bab1671fSRichard Henderson if (NEED_SYNC_ARG(0)) {
4795bab1671fSRichard Henderson temp_sync(s, ots, s->reserved_regs, 0, 0);
4796bab1671fSRichard Henderson }
4797bab1671fSRichard Henderson if (IS_DEAD_ARG(0)) {
4798bab1671fSRichard Henderson temp_dead(s, ots);
4799bab1671fSRichard Henderson }
4800bab1671fSRichard Henderson }
4801bab1671fSRichard Henderson
tcg_reg_alloc_op(TCGContext * s,const TCGOp * op)4802dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op)
4803c896fe29Sbellard {
4804dd186292SRichard Henderson const TCGLifeData arg_life = op->life;
4805dd186292SRichard Henderson const TCGOpDef * const def = &tcg_op_defs[op->opc];
480682790a87SRichard Henderson TCGRegSet i_allocated_regs;
480782790a87SRichard Henderson TCGRegSet o_allocated_regs;
4808b6638662SRichard Henderson int i, k, nb_iargs, nb_oargs;
4809b6638662SRichard Henderson TCGReg reg;
4810c896fe29Sbellard TCGArg arg;
4811c896fe29Sbellard const TCGArgConstraint *arg_ct;
4812c896fe29Sbellard TCGTemp *ts;
4813c896fe29Sbellard TCGArg new_args[TCG_MAX_OP_ARGS];
4814c896fe29Sbellard int const_args[TCG_MAX_OP_ARGS];
481521e9a8aeSRichard Henderson TCGCond op_cond;
4816c896fe29Sbellard
4817c896fe29Sbellard nb_oargs = def->nb_oargs;
4818c896fe29Sbellard nb_iargs = def->nb_iargs;
4819c896fe29Sbellard
4820c896fe29Sbellard /* copy constants */
4821c896fe29Sbellard memcpy(new_args + nb_oargs + nb_iargs,
4822dd186292SRichard Henderson op->args + nb_oargs + nb_iargs,
4823c896fe29Sbellard sizeof(TCGArg) * def->nb_cargs);
4824c896fe29Sbellard
4825d21369f5SRichard Henderson i_allocated_regs = s->reserved_regs;
4826d21369f5SRichard Henderson o_allocated_regs = s->reserved_regs;
482782790a87SRichard Henderson
482821e9a8aeSRichard Henderson switch (op->opc) {
482921e9a8aeSRichard Henderson case INDEX_op_brcond_i32:
483021e9a8aeSRichard Henderson case INDEX_op_brcond_i64:
483121e9a8aeSRichard Henderson op_cond = op->args[2];
483221e9a8aeSRichard Henderson break;
483321e9a8aeSRichard Henderson case INDEX_op_setcond_i32:
483421e9a8aeSRichard Henderson case INDEX_op_setcond_i64:
483521e9a8aeSRichard Henderson case INDEX_op_negsetcond_i32:
483621e9a8aeSRichard Henderson case INDEX_op_negsetcond_i64:
483721e9a8aeSRichard Henderson case INDEX_op_cmp_vec:
483821e9a8aeSRichard Henderson op_cond = op->args[3];
483921e9a8aeSRichard Henderson break;
484021e9a8aeSRichard Henderson case INDEX_op_brcond2_i32:
484121e9a8aeSRichard Henderson op_cond = op->args[4];
484221e9a8aeSRichard Henderson break;
484321e9a8aeSRichard Henderson case INDEX_op_movcond_i32:
484421e9a8aeSRichard Henderson case INDEX_op_movcond_i64:
484521e9a8aeSRichard Henderson case INDEX_op_setcond2_i32:
484621e9a8aeSRichard Henderson case INDEX_op_cmpsel_vec:
484721e9a8aeSRichard Henderson op_cond = op->args[5];
484821e9a8aeSRichard Henderson break;
484921e9a8aeSRichard Henderson default:
485021e9a8aeSRichard Henderson /* No condition within opcode. */
485121e9a8aeSRichard Henderson op_cond = TCG_COND_ALWAYS;
485221e9a8aeSRichard Henderson break;
485321e9a8aeSRichard Henderson }
485421e9a8aeSRichard Henderson
4855c896fe29Sbellard /* satisfy input constraints */
4856c896fe29Sbellard for (k = 0; k < nb_iargs; k++) {
485729f5e925SRichard Henderson TCGRegSet i_preferred_regs, i_required_regs;
485829f5e925SRichard Henderson bool allocate_new_reg, copyto_new_reg;
485929f5e925SRichard Henderson TCGTemp *ts2;
486029f5e925SRichard Henderson int i1, i2;
4861d62816f2SRichard Henderson
486266792f90SRichard Henderson i = def->args_ct[nb_oargs + k].sort_index;
4863dd186292SRichard Henderson arg = op->args[i];
4864c896fe29Sbellard arg_ct = &def->args_ct[i];
486543439139SRichard Henderson ts = arg_temp(arg);
486640ae5c62SRichard Henderson
486740ae5c62SRichard Henderson if (ts->val_type == TEMP_VAL_CONST
486821e9a8aeSRichard Henderson && tcg_target_const_match(ts->val, arg_ct->ct, ts->type,
486921e9a8aeSRichard Henderson op_cond, TCGOP_VECE(op))) {
4870c896fe29Sbellard /* constant is OK for instruction */
4871c896fe29Sbellard const_args[i] = 1;
4872c896fe29Sbellard new_args[i] = ts->val;
4873d62816f2SRichard Henderson continue;
4874c896fe29Sbellard }
487540ae5c62SRichard Henderson
48761c1824dcSRichard Henderson reg = ts->reg;
48771c1824dcSRichard Henderson i_preferred_regs = 0;
487829f5e925SRichard Henderson i_required_regs = arg_ct->regs;
48791c1824dcSRichard Henderson allocate_new_reg = false;
488029f5e925SRichard Henderson copyto_new_reg = false;
48811c1824dcSRichard Henderson
488229f5e925SRichard Henderson switch (arg_ct->pair) {
488329f5e925SRichard Henderson case 0: /* not paired */
4884bc2b17e6SRichard Henderson if (arg_ct->ialias) {
488531fd884bSRichard Henderson i_preferred_regs = output_pref(op, arg_ct->alias_index);
4886c0522136SRichard Henderson
4887c0522136SRichard Henderson /*
4888c0522136SRichard Henderson * If the input is readonly, then it cannot also be an
4889c0522136SRichard Henderson * output and aliased to itself. If the input is not
4890c0522136SRichard Henderson * dead after the instruction, we must allocate a new
4891c0522136SRichard Henderson * register and move it.
4892c0522136SRichard Henderson */
489322d2e535SIlya Leoshkevich if (temp_readonly(ts) || !IS_DEAD_ARG(i)
489422d2e535SIlya Leoshkevich || def->args_ct[arg_ct->alias_index].newreg) {
48951c1824dcSRichard Henderson allocate_new_reg = true;
48961c1824dcSRichard Henderson } else if (ts->val_type == TEMP_VAL_REG) {
4897c0522136SRichard Henderson /*
48981c1824dcSRichard Henderson * Check if the current register has already been
48991c1824dcSRichard Henderson * allocated for another input.
4900c0522136SRichard Henderson */
490129f5e925SRichard Henderson allocate_new_reg =
490229f5e925SRichard Henderson tcg_regset_test_reg(i_allocated_regs, reg);
49037e1df267SAurelien Jarno }
49047e1df267SAurelien Jarno }
49051c1824dcSRichard Henderson if (!allocate_new_reg) {
490629f5e925SRichard Henderson temp_load(s, ts, i_required_regs, i_allocated_regs,
490729f5e925SRichard Henderson i_preferred_regs);
4908c896fe29Sbellard reg = ts->reg;
490929f5e925SRichard Henderson allocate_new_reg = !tcg_regset_test_reg(i_required_regs, reg);
49101c1824dcSRichard Henderson }
49111c1824dcSRichard Henderson if (allocate_new_reg) {
4912c0522136SRichard Henderson /*
4913c0522136SRichard Henderson * Allocate a new register matching the constraint
4914c0522136SRichard Henderson * and move the temporary register into it.
4915c0522136SRichard Henderson */
4916d62816f2SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type],
4917d62816f2SRichard Henderson i_allocated_regs, 0);
491829f5e925SRichard Henderson reg = tcg_reg_alloc(s, i_required_regs, i_allocated_regs,
49191c1824dcSRichard Henderson i_preferred_regs, ts->indirect_base);
492029f5e925SRichard Henderson copyto_new_reg = true;
492129f5e925SRichard Henderson }
492229f5e925SRichard Henderson break;
492329f5e925SRichard Henderson
492429f5e925SRichard Henderson case 1:
492529f5e925SRichard Henderson /* First of an input pair; if i1 == i2, the second is an output. */
492629f5e925SRichard Henderson i1 = i;
492729f5e925SRichard Henderson i2 = arg_ct->pair_index;
492829f5e925SRichard Henderson ts2 = i1 != i2 ? arg_temp(op->args[i2]) : NULL;
492929f5e925SRichard Henderson
493029f5e925SRichard Henderson /*
493129f5e925SRichard Henderson * It is easier to default to allocating a new pair
493229f5e925SRichard Henderson * and to identify a few cases where it's not required.
493329f5e925SRichard Henderson */
493429f5e925SRichard Henderson if (arg_ct->ialias) {
493531fd884bSRichard Henderson i_preferred_regs = output_pref(op, arg_ct->alias_index);
493629f5e925SRichard Henderson if (IS_DEAD_ARG(i1) &&
493729f5e925SRichard Henderson IS_DEAD_ARG(i2) &&
493829f5e925SRichard Henderson !temp_readonly(ts) &&
493929f5e925SRichard Henderson ts->val_type == TEMP_VAL_REG &&
494029f5e925SRichard Henderson ts->reg < TCG_TARGET_NB_REGS - 1 &&
494129f5e925SRichard Henderson tcg_regset_test_reg(i_required_regs, reg) &&
494229f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg) &&
494329f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg + 1) &&
494429f5e925SRichard Henderson (ts2
494529f5e925SRichard Henderson ? ts2->val_type == TEMP_VAL_REG &&
494629f5e925SRichard Henderson ts2->reg == reg + 1 &&
494729f5e925SRichard Henderson !temp_readonly(ts2)
494829f5e925SRichard Henderson : s->reg_to_temp[reg + 1] == NULL)) {
494929f5e925SRichard Henderson break;
495029f5e925SRichard Henderson }
495129f5e925SRichard Henderson } else {
495229f5e925SRichard Henderson /* Without aliasing, the pair must also be an input. */
495329f5e925SRichard Henderson tcg_debug_assert(ts2);
495429f5e925SRichard Henderson if (ts->val_type == TEMP_VAL_REG &&
495529f5e925SRichard Henderson ts2->val_type == TEMP_VAL_REG &&
495629f5e925SRichard Henderson ts2->reg == reg + 1 &&
495729f5e925SRichard Henderson tcg_regset_test_reg(i_required_regs, reg)) {
495829f5e925SRichard Henderson break;
495929f5e925SRichard Henderson }
496029f5e925SRichard Henderson }
496129f5e925SRichard Henderson reg = tcg_reg_alloc_pair(s, i_required_regs, i_allocated_regs,
496229f5e925SRichard Henderson 0, ts->indirect_base);
496329f5e925SRichard Henderson goto do_pair;
496429f5e925SRichard Henderson
496529f5e925SRichard Henderson case 2: /* pair second */
496629f5e925SRichard Henderson reg = new_args[arg_ct->pair_index] + 1;
496729f5e925SRichard Henderson goto do_pair;
496829f5e925SRichard Henderson
496929f5e925SRichard Henderson case 3: /* ialias with second output, no first input */
497029f5e925SRichard Henderson tcg_debug_assert(arg_ct->ialias);
497131fd884bSRichard Henderson i_preferred_regs = output_pref(op, arg_ct->alias_index);
497229f5e925SRichard Henderson
497329f5e925SRichard Henderson if (IS_DEAD_ARG(i) &&
497429f5e925SRichard Henderson !temp_readonly(ts) &&
497529f5e925SRichard Henderson ts->val_type == TEMP_VAL_REG &&
497629f5e925SRichard Henderson reg > 0 &&
497729f5e925SRichard Henderson s->reg_to_temp[reg - 1] == NULL &&
497829f5e925SRichard Henderson tcg_regset_test_reg(i_required_regs, reg) &&
497929f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg) &&
498029f5e925SRichard Henderson !tcg_regset_test_reg(i_allocated_regs, reg - 1)) {
498129f5e925SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg - 1);
498229f5e925SRichard Henderson break;
498329f5e925SRichard Henderson }
498429f5e925SRichard Henderson reg = tcg_reg_alloc_pair(s, i_required_regs >> 1,
498529f5e925SRichard Henderson i_allocated_regs, 0,
498629f5e925SRichard Henderson ts->indirect_base);
498729f5e925SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg);
498829f5e925SRichard Henderson reg += 1;
498929f5e925SRichard Henderson goto do_pair;
499029f5e925SRichard Henderson
499129f5e925SRichard Henderson do_pair:
499229f5e925SRichard Henderson /*
499329f5e925SRichard Henderson * If an aliased input is not dead after the instruction,
499429f5e925SRichard Henderson * we must allocate a new register and move it.
499529f5e925SRichard Henderson */
499629f5e925SRichard Henderson if (arg_ct->ialias && (!IS_DEAD_ARG(i) || temp_readonly(ts))) {
499729f5e925SRichard Henderson TCGRegSet t_allocated_regs = i_allocated_regs;
499829f5e925SRichard Henderson
499929f5e925SRichard Henderson /*
500029f5e925SRichard Henderson * Because of the alias, and the continued life, make sure
500129f5e925SRichard Henderson * that the temp is somewhere *other* than the reg pair,
500229f5e925SRichard Henderson * and we get a copy in reg.
500329f5e925SRichard Henderson */
500429f5e925SRichard Henderson tcg_regset_set_reg(t_allocated_regs, reg);
500529f5e925SRichard Henderson tcg_regset_set_reg(t_allocated_regs, reg + 1);
500629f5e925SRichard Henderson if (ts->val_type == TEMP_VAL_REG && ts->reg == reg) {
500729f5e925SRichard Henderson /* If ts was already in reg, copy it somewhere else. */
500829f5e925SRichard Henderson TCGReg nr;
500929f5e925SRichard Henderson bool ok;
501029f5e925SRichard Henderson
501129f5e925SRichard Henderson tcg_debug_assert(ts->kind != TEMP_FIXED);
501229f5e925SRichard Henderson nr = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
501329f5e925SRichard Henderson t_allocated_regs, 0, ts->indirect_base);
501429f5e925SRichard Henderson ok = tcg_out_mov(s, ts->type, nr, reg);
501529f5e925SRichard Henderson tcg_debug_assert(ok);
501629f5e925SRichard Henderson
501729f5e925SRichard Henderson set_temp_val_reg(s, ts, nr);
501829f5e925SRichard Henderson } else {
501929f5e925SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type],
502029f5e925SRichard Henderson t_allocated_regs, 0);
502129f5e925SRichard Henderson copyto_new_reg = true;
502229f5e925SRichard Henderson }
502329f5e925SRichard Henderson } else {
502429f5e925SRichard Henderson /* Preferably allocate to reg, otherwise copy. */
502529f5e925SRichard Henderson i_required_regs = (TCGRegSet)1 << reg;
502629f5e925SRichard Henderson temp_load(s, ts, i_required_regs, i_allocated_regs,
502729f5e925SRichard Henderson i_preferred_regs);
502829f5e925SRichard Henderson copyto_new_reg = ts->reg != reg;
502929f5e925SRichard Henderson }
503029f5e925SRichard Henderson break;
503129f5e925SRichard Henderson
503229f5e925SRichard Henderson default:
503329f5e925SRichard Henderson g_assert_not_reached();
503429f5e925SRichard Henderson }
503529f5e925SRichard Henderson
503629f5e925SRichard Henderson if (copyto_new_reg) {
503778113e83SRichard Henderson if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
5038240c08d0SRichard Henderson /*
5039240c08d0SRichard Henderson * Cross register class move not supported. Sync the
5040240c08d0SRichard Henderson * temp back to its slot and load from there.
5041240c08d0SRichard Henderson */
5042240c08d0SRichard Henderson temp_sync(s, ts, i_allocated_regs, 0, 0);
5043240c08d0SRichard Henderson tcg_out_ld(s, ts->type, reg,
5044240c08d0SRichard Henderson ts->mem_base->reg, ts->mem_offset);
504578113e83SRichard Henderson }
5046c896fe29Sbellard }
5047c896fe29Sbellard new_args[i] = reg;
5048c896fe29Sbellard const_args[i] = 0;
504982790a87SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg);
5050c896fe29Sbellard }
5051c896fe29Sbellard
5052c896fe29Sbellard /* mark dead temporaries and free the associated registers */
5053866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
5054866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) {
505543439139SRichard Henderson temp_dead(s, arg_temp(op->args[i]));
5056c896fe29Sbellard }
5057c896fe29Sbellard }
5058c896fe29Sbellard
5059b4cb76e6SRichard Henderson if (def->flags & TCG_OPF_COND_BRANCH) {
5060b4cb76e6SRichard Henderson tcg_reg_alloc_cbranch(s, i_allocated_regs);
5061b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) {
506282790a87SRichard Henderson tcg_reg_alloc_bb_end(s, i_allocated_regs);
5063a52ad07eSAurelien Jarno } else {
5064c896fe29Sbellard if (def->flags & TCG_OPF_CALL_CLOBBER) {
5065b03cce8eSbellard /* XXX: permit generic clobber register list ? */
5066c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
5067c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
506882790a87SRichard Henderson tcg_reg_free(s, i, i_allocated_regs);
5069c896fe29Sbellard }
5070c896fe29Sbellard }
50713d5c5f87SAurelien Jarno }
50723d5c5f87SAurelien Jarno if (def->flags & TCG_OPF_SIDE_EFFECTS) {
50733d5c5f87SAurelien Jarno /* sync globals if the op has side effects and might trigger
50743d5c5f87SAurelien Jarno an exception. */
507582790a87SRichard Henderson sync_globals(s, i_allocated_regs);
5076c896fe29Sbellard }
5077c896fe29Sbellard
5078c896fe29Sbellard /* satisfy the output constraints */
5079c896fe29Sbellard for(k = 0; k < nb_oargs; k++) {
508066792f90SRichard Henderson i = def->args_ct[k].sort_index;
5081dd186292SRichard Henderson arg = op->args[i];
5082c896fe29Sbellard arg_ct = &def->args_ct[i];
508343439139SRichard Henderson ts = arg_temp(arg);
5084d63e3b6eSRichard Henderson
5085d63e3b6eSRichard Henderson /* ENV should not be modified. */
5086e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ts));
5087d63e3b6eSRichard Henderson
508829f5e925SRichard Henderson switch (arg_ct->pair) {
508929f5e925SRichard Henderson case 0: /* not paired */
5090bc2b17e6SRichard Henderson if (arg_ct->oalias && !const_args[arg_ct->alias_index]) {
50915ff9d6a4Sbellard reg = new_args[arg_ct->alias_index];
5092bc2b17e6SRichard Henderson } else if (arg_ct->newreg) {
50939be0d080SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->regs,
509482790a87SRichard Henderson i_allocated_regs | o_allocated_regs,
509531fd884bSRichard Henderson output_pref(op, k), ts->indirect_base);
5096c896fe29Sbellard } else {
50979be0d080SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs,
509831fd884bSRichard Henderson output_pref(op, k), ts->indirect_base);
5099c896fe29Sbellard }
510029f5e925SRichard Henderson break;
510129f5e925SRichard Henderson
510229f5e925SRichard Henderson case 1: /* first of pair */
510329f5e925SRichard Henderson if (arg_ct->oalias) {
510429f5e925SRichard Henderson reg = new_args[arg_ct->alias_index];
5105ca5bed07SRichard Henderson } else if (arg_ct->newreg) {
5106ca5bed07SRichard Henderson reg = tcg_reg_alloc_pair(s, arg_ct->regs,
5107ca5bed07SRichard Henderson i_allocated_regs | o_allocated_regs,
5108ca5bed07SRichard Henderson output_pref(op, k),
5109ca5bed07SRichard Henderson ts->indirect_base);
5110ca5bed07SRichard Henderson } else {
511129f5e925SRichard Henderson reg = tcg_reg_alloc_pair(s, arg_ct->regs, o_allocated_regs,
5112ca5bed07SRichard Henderson output_pref(op, k),
5113ca5bed07SRichard Henderson ts->indirect_base);
5114ca5bed07SRichard Henderson }
511529f5e925SRichard Henderson break;
511629f5e925SRichard Henderson
511729f5e925SRichard Henderson case 2: /* second of pair */
511829f5e925SRichard Henderson if (arg_ct->oalias) {
511929f5e925SRichard Henderson reg = new_args[arg_ct->alias_index];
512029f5e925SRichard Henderson } else {
512129f5e925SRichard Henderson reg = new_args[arg_ct->pair_index] + 1;
512229f5e925SRichard Henderson }
512329f5e925SRichard Henderson break;
512429f5e925SRichard Henderson
512529f5e925SRichard Henderson case 3: /* first of pair, aliasing with a second input */
512629f5e925SRichard Henderson tcg_debug_assert(!arg_ct->newreg);
512729f5e925SRichard Henderson reg = new_args[arg_ct->pair_index] - 1;
512829f5e925SRichard Henderson break;
512929f5e925SRichard Henderson
513029f5e925SRichard Henderson default:
513129f5e925SRichard Henderson g_assert_not_reached();
513229f5e925SRichard Henderson }
513382790a87SRichard Henderson tcg_regset_set_reg(o_allocated_regs, reg);
5134098859f1SRichard Henderson set_temp_val_reg(s, ts, reg);
5135c896fe29Sbellard ts->mem_coherent = 0;
5136c896fe29Sbellard new_args[i] = reg;
5137c896fe29Sbellard }
5138e8996ee0Sbellard }
5139c896fe29Sbellard
5140c896fe29Sbellard /* emit instruction */
5141678155b2SRichard Henderson switch (op->opc) {
5142678155b2SRichard Henderson case INDEX_op_ext8s_i32:
5143678155b2SRichard Henderson tcg_out_ext8s(s, TCG_TYPE_I32, new_args[0], new_args[1]);
5144678155b2SRichard Henderson break;
5145678155b2SRichard Henderson case INDEX_op_ext8s_i64:
5146678155b2SRichard Henderson tcg_out_ext8s(s, TCG_TYPE_I64, new_args[0], new_args[1]);
5147678155b2SRichard Henderson break;
5148d0e66c89SRichard Henderson case INDEX_op_ext8u_i32:
5149d0e66c89SRichard Henderson case INDEX_op_ext8u_i64:
5150d0e66c89SRichard Henderson tcg_out_ext8u(s, new_args[0], new_args[1]);
5151d0e66c89SRichard Henderson break;
5152753e42eaSRichard Henderson case INDEX_op_ext16s_i32:
5153753e42eaSRichard Henderson tcg_out_ext16s(s, TCG_TYPE_I32, new_args[0], new_args[1]);
5154753e42eaSRichard Henderson break;
5155753e42eaSRichard Henderson case INDEX_op_ext16s_i64:
5156753e42eaSRichard Henderson tcg_out_ext16s(s, TCG_TYPE_I64, new_args[0], new_args[1]);
5157753e42eaSRichard Henderson break;
5158379afdffSRichard Henderson case INDEX_op_ext16u_i32:
5159379afdffSRichard Henderson case INDEX_op_ext16u_i64:
5160379afdffSRichard Henderson tcg_out_ext16u(s, new_args[0], new_args[1]);
5161379afdffSRichard Henderson break;
516252bf3398SRichard Henderson case INDEX_op_ext32s_i64:
516352bf3398SRichard Henderson tcg_out_ext32s(s, new_args[0], new_args[1]);
516452bf3398SRichard Henderson break;
51659ecf5f61SRichard Henderson case INDEX_op_ext32u_i64:
51669ecf5f61SRichard Henderson tcg_out_ext32u(s, new_args[0], new_args[1]);
51679ecf5f61SRichard Henderson break;
51689c6aa274SRichard Henderson case INDEX_op_ext_i32_i64:
51699c6aa274SRichard Henderson tcg_out_exts_i32_i64(s, new_args[0], new_args[1]);
51709c6aa274SRichard Henderson break;
5171b9bfe000SRichard Henderson case INDEX_op_extu_i32_i64:
5172b9bfe000SRichard Henderson tcg_out_extu_i32_i64(s, new_args[0], new_args[1]);
5173b9bfe000SRichard Henderson break;
5174b8b94ac6SRichard Henderson case INDEX_op_extrl_i64_i32:
5175b8b94ac6SRichard Henderson tcg_out_extrl_i64_i32(s, new_args[0], new_args[1]);
5176b8b94ac6SRichard Henderson break;
5177678155b2SRichard Henderson default:
5178d2fd745fSRichard Henderson if (def->flags & TCG_OPF_VECTOR) {
5179d2fd745fSRichard Henderson tcg_out_vec_op(s, op->opc, TCGOP_VECL(op), TCGOP_VECE(op),
5180d2fd745fSRichard Henderson new_args, const_args);
5181d2fd745fSRichard Henderson } else {
5182dd186292SRichard Henderson tcg_out_op(s, op->opc, new_args, const_args);
5183d2fd745fSRichard Henderson }
5184678155b2SRichard Henderson break;
5185678155b2SRichard Henderson }
5186c896fe29Sbellard
5187c896fe29Sbellard /* move the outputs in the correct register if needed */
5188c896fe29Sbellard for(i = 0; i < nb_oargs; i++) {
518943439139SRichard Henderson ts = arg_temp(op->args[i]);
5190d63e3b6eSRichard Henderson
5191d63e3b6eSRichard Henderson /* ENV should not be modified. */
5192e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ts));
5193d63e3b6eSRichard Henderson
5194ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) {
519598b4e186SRichard Henderson temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i));
519659d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) {
5197f8bf00f1SRichard Henderson temp_dead(s, ts);
5198ec7a869dSAurelien Jarno }
5199c896fe29Sbellard }
5200c896fe29Sbellard }
5201c896fe29Sbellard
tcg_reg_alloc_dup2(TCGContext * s,const TCGOp * op)5202efe86b21SRichard Henderson static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op)
5203efe86b21SRichard Henderson {
5204efe86b21SRichard Henderson const TCGLifeData arg_life = op->life;
5205efe86b21SRichard Henderson TCGTemp *ots, *itsl, *itsh;
5206efe86b21SRichard Henderson TCGType vtype = TCGOP_VECL(op) + TCG_TYPE_V64;
5207efe86b21SRichard Henderson
5208efe86b21SRichard Henderson /* This opcode is only valid for 32-bit hosts, for 64-bit elements. */
5209efe86b21SRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 32);
5210efe86b21SRichard Henderson tcg_debug_assert(TCGOP_VECE(op) == MO_64);
5211efe86b21SRichard Henderson
5212efe86b21SRichard Henderson ots = arg_temp(op->args[0]);
5213efe86b21SRichard Henderson itsl = arg_temp(op->args[1]);
5214efe86b21SRichard Henderson itsh = arg_temp(op->args[2]);
5215efe86b21SRichard Henderson
5216efe86b21SRichard Henderson /* ENV should not be modified. */
5217efe86b21SRichard Henderson tcg_debug_assert(!temp_readonly(ots));
5218efe86b21SRichard Henderson
5219efe86b21SRichard Henderson /* Allocate the output register now. */
5220efe86b21SRichard Henderson if (ots->val_type != TEMP_VAL_REG) {
5221efe86b21SRichard Henderson TCGRegSet allocated_regs = s->reserved_regs;
5222efe86b21SRichard Henderson TCGRegSet dup_out_regs =
5223efe86b21SRichard Henderson tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs;
5224098859f1SRichard Henderson TCGReg oreg;
5225efe86b21SRichard Henderson
5226efe86b21SRichard Henderson /* Make sure to not spill the input registers. */
5227efe86b21SRichard Henderson if (!IS_DEAD_ARG(1) && itsl->val_type == TEMP_VAL_REG) {
5228efe86b21SRichard Henderson tcg_regset_set_reg(allocated_regs, itsl->reg);
5229efe86b21SRichard Henderson }
5230efe86b21SRichard Henderson if (!IS_DEAD_ARG(2) && itsh->val_type == TEMP_VAL_REG) {
5231efe86b21SRichard Henderson tcg_regset_set_reg(allocated_regs, itsh->reg);
5232efe86b21SRichard Henderson }
5233efe86b21SRichard Henderson
5234098859f1SRichard Henderson oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
523531fd884bSRichard Henderson output_pref(op, 0), ots->indirect_base);
5236098859f1SRichard Henderson set_temp_val_reg(s, ots, oreg);
5237efe86b21SRichard Henderson }
5238efe86b21SRichard Henderson
5239efe86b21SRichard Henderson /* Promote dup2 of immediates to dupi_vec. */
5240efe86b21SRichard Henderson if (itsl->val_type == TEMP_VAL_CONST && itsh->val_type == TEMP_VAL_CONST) {
5241efe86b21SRichard Henderson uint64_t val = deposit64(itsl->val, 32, 32, itsh->val);
5242efe86b21SRichard Henderson MemOp vece = MO_64;
5243efe86b21SRichard Henderson
5244efe86b21SRichard Henderson if (val == dup_const(MO_8, val)) {
5245efe86b21SRichard Henderson vece = MO_8;
5246efe86b21SRichard Henderson } else if (val == dup_const(MO_16, val)) {
5247efe86b21SRichard Henderson vece = MO_16;
5248efe86b21SRichard Henderson } else if (val == dup_const(MO_32, val)) {
5249efe86b21SRichard Henderson vece = MO_32;
5250efe86b21SRichard Henderson }
5251efe86b21SRichard Henderson
5252efe86b21SRichard Henderson tcg_out_dupi_vec(s, vtype, vece, ots->reg, val);
5253efe86b21SRichard Henderson goto done;
5254efe86b21SRichard Henderson }
5255efe86b21SRichard Henderson
5256efe86b21SRichard Henderson /* If the two inputs form one 64-bit value, try dupm_vec. */
5257aef85402SRichard Henderson if (itsl->temp_subindex == HOST_BIG_ENDIAN &&
5258aef85402SRichard Henderson itsh->temp_subindex == !HOST_BIG_ENDIAN &&
5259aef85402SRichard Henderson itsl == itsh + (HOST_BIG_ENDIAN ? 1 : -1)) {
5260aef85402SRichard Henderson TCGTemp *its = itsl - HOST_BIG_ENDIAN;
5261aef85402SRichard Henderson
5262aef85402SRichard Henderson temp_sync(s, its + 0, s->reserved_regs, 0, 0);
5263aef85402SRichard Henderson temp_sync(s, its + 1, s->reserved_regs, 0, 0);
5264aef85402SRichard Henderson
5265efe86b21SRichard Henderson if (tcg_out_dupm_vec(s, vtype, MO_64, ots->reg,
5266efe86b21SRichard Henderson its->mem_base->reg, its->mem_offset)) {
5267efe86b21SRichard Henderson goto done;
5268efe86b21SRichard Henderson }
5269efe86b21SRichard Henderson }
5270efe86b21SRichard Henderson
5271efe86b21SRichard Henderson /* Fall back to generic expansion. */
5272efe86b21SRichard Henderson return false;
5273efe86b21SRichard Henderson
5274efe86b21SRichard Henderson done:
527536f5539cSRichard Henderson ots->mem_coherent = 0;
5276efe86b21SRichard Henderson if (IS_DEAD_ARG(1)) {
5277efe86b21SRichard Henderson temp_dead(s, itsl);
5278efe86b21SRichard Henderson }
5279efe86b21SRichard Henderson if (IS_DEAD_ARG(2)) {
5280efe86b21SRichard Henderson temp_dead(s, itsh);
5281efe86b21SRichard Henderson }
5282efe86b21SRichard Henderson if (NEED_SYNC_ARG(0)) {
5283efe86b21SRichard Henderson temp_sync(s, ots, s->reserved_regs, 0, IS_DEAD_ARG(0));
5284efe86b21SRichard Henderson } else if (IS_DEAD_ARG(0)) {
5285efe86b21SRichard Henderson temp_dead(s, ots);
5286efe86b21SRichard Henderson }
5287efe86b21SRichard Henderson return true;
5288efe86b21SRichard Henderson }
5289efe86b21SRichard Henderson
load_arg_reg(TCGContext * s,TCGReg reg,TCGTemp * ts,TCGRegSet allocated_regs)529039004a71SRichard Henderson static void load_arg_reg(TCGContext *s, TCGReg reg, TCGTemp *ts,
529139004a71SRichard Henderson TCGRegSet allocated_regs)
5292c896fe29Sbellard {
5293c896fe29Sbellard if (ts->val_type == TEMP_VAL_REG) {
5294c896fe29Sbellard if (ts->reg != reg) {
52954250da10SRichard Henderson tcg_reg_free(s, reg, allocated_regs);
529678113e83SRichard Henderson if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
5297240c08d0SRichard Henderson /*
5298240c08d0SRichard Henderson * Cross register class move not supported. Sync the
5299240c08d0SRichard Henderson * temp back to its slot and load from there.
5300240c08d0SRichard Henderson */
5301240c08d0SRichard Henderson temp_sync(s, ts, allocated_regs, 0, 0);
5302240c08d0SRichard Henderson tcg_out_ld(s, ts->type, reg,
5303240c08d0SRichard Henderson ts->mem_base->reg, ts->mem_offset);
530478113e83SRichard Henderson }
5305c896fe29Sbellard }
5306c896fe29Sbellard } else {
5307ccb1bb66SRichard Henderson TCGRegSet arg_set = 0;
530840ae5c62SRichard Henderson
53094250da10SRichard Henderson tcg_reg_free(s, reg, allocated_regs);
531040ae5c62SRichard Henderson tcg_regset_set_reg(arg_set, reg);
5311b722452aSRichard Henderson temp_load(s, ts, arg_set, allocated_regs, 0);
5312c896fe29Sbellard }
531339004a71SRichard Henderson }
531440ae5c62SRichard Henderson
load_arg_stk(TCGContext * s,unsigned arg_slot,TCGTemp * ts,TCGRegSet allocated_regs)5315d78e4a4fSRichard Henderson static void load_arg_stk(TCGContext *s, unsigned arg_slot, TCGTemp *ts,
531639004a71SRichard Henderson TCGRegSet allocated_regs)
531739004a71SRichard Henderson {
531839004a71SRichard Henderson /*
531939004a71SRichard Henderson * When the destination is on the stack, load up the temp and store.
532039004a71SRichard Henderson * If there are many call-saved registers, the temp might live to
532139004a71SRichard Henderson * see another use; otherwise it'll be discarded.
532239004a71SRichard Henderson */
532339004a71SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], allocated_regs, 0);
532439004a71SRichard Henderson tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK,
5325d78e4a4fSRichard Henderson arg_slot_stk_ofs(arg_slot));
532639004a71SRichard Henderson }
532739004a71SRichard Henderson
load_arg_normal(TCGContext * s,const TCGCallArgumentLoc * l,TCGTemp * ts,TCGRegSet * allocated_regs)532839004a71SRichard Henderson static void load_arg_normal(TCGContext *s, const TCGCallArgumentLoc *l,
532939004a71SRichard Henderson TCGTemp *ts, TCGRegSet *allocated_regs)
533039004a71SRichard Henderson {
5331338b61e9SRichard Henderson if (arg_slot_reg_p(l->arg_slot)) {
533239004a71SRichard Henderson TCGReg reg = tcg_target_call_iarg_regs[l->arg_slot];
533339004a71SRichard Henderson load_arg_reg(s, reg, ts, *allocated_regs);
533439004a71SRichard Henderson tcg_regset_set_reg(*allocated_regs, reg);
533539004a71SRichard Henderson } else {
5336d78e4a4fSRichard Henderson load_arg_stk(s, l->arg_slot, ts, *allocated_regs);
5337c896fe29Sbellard }
533839cf05d3Sbellard }
5339c896fe29Sbellard
load_arg_ref(TCGContext * s,unsigned arg_slot,TCGReg ref_base,intptr_t ref_off,TCGRegSet * allocated_regs)5340d78e4a4fSRichard Henderson static void load_arg_ref(TCGContext *s, unsigned arg_slot, TCGReg ref_base,
5341313bdea8SRichard Henderson intptr_t ref_off, TCGRegSet *allocated_regs)
5342313bdea8SRichard Henderson {
5343313bdea8SRichard Henderson TCGReg reg;
5344313bdea8SRichard Henderson
5345d78e4a4fSRichard Henderson if (arg_slot_reg_p(arg_slot)) {
5346313bdea8SRichard Henderson reg = tcg_target_call_iarg_regs[arg_slot];
5347313bdea8SRichard Henderson tcg_reg_free(s, reg, *allocated_regs);
5348313bdea8SRichard Henderson tcg_out_addi_ptr(s, reg, ref_base, ref_off);
5349313bdea8SRichard Henderson tcg_regset_set_reg(*allocated_regs, reg);
5350313bdea8SRichard Henderson } else {
5351313bdea8SRichard Henderson reg = tcg_reg_alloc(s, tcg_target_available_regs[TCG_TYPE_PTR],
5352313bdea8SRichard Henderson *allocated_regs, 0, false);
5353313bdea8SRichard Henderson tcg_out_addi_ptr(s, reg, ref_base, ref_off);
5354313bdea8SRichard Henderson tcg_out_st(s, TCG_TYPE_PTR, reg, TCG_REG_CALL_STACK,
5355d78e4a4fSRichard Henderson arg_slot_stk_ofs(arg_slot));
5356313bdea8SRichard Henderson }
5357313bdea8SRichard Henderson }
5358313bdea8SRichard Henderson
tcg_reg_alloc_call(TCGContext * s,TCGOp * op)535939004a71SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op)
536039004a71SRichard Henderson {
536139004a71SRichard Henderson const int nb_oargs = TCGOP_CALLO(op);
536239004a71SRichard Henderson const int nb_iargs = TCGOP_CALLI(op);
536339004a71SRichard Henderson const TCGLifeData arg_life = op->life;
536439004a71SRichard Henderson const TCGHelperInfo *info = tcg_call_info(op);
536539004a71SRichard Henderson TCGRegSet allocated_regs = s->reserved_regs;
536639004a71SRichard Henderson int i;
536739004a71SRichard Henderson
536839004a71SRichard Henderson /*
536939004a71SRichard Henderson * Move inputs into place in reverse order,
537039004a71SRichard Henderson * so that we place stacked arguments first.
537139004a71SRichard Henderson */
537239004a71SRichard Henderson for (i = nb_iargs - 1; i >= 0; --i) {
537339004a71SRichard Henderson const TCGCallArgumentLoc *loc = &info->in[i];
537439004a71SRichard Henderson TCGTemp *ts = arg_temp(op->args[nb_oargs + i]);
537539004a71SRichard Henderson
537639004a71SRichard Henderson switch (loc->kind) {
537739004a71SRichard Henderson case TCG_CALL_ARG_NORMAL:
537839004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_U:
537939004a71SRichard Henderson case TCG_CALL_ARG_EXTEND_S:
538039004a71SRichard Henderson load_arg_normal(s, loc, ts, &allocated_regs);
538139004a71SRichard Henderson break;
5382313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF:
5383313bdea8SRichard Henderson load_arg_stk(s, loc->ref_slot, ts, allocated_regs);
5384313bdea8SRichard Henderson load_arg_ref(s, loc->arg_slot, TCG_REG_CALL_STACK,
5385d78e4a4fSRichard Henderson arg_slot_stk_ofs(loc->ref_slot),
5386313bdea8SRichard Henderson &allocated_regs);
5387313bdea8SRichard Henderson break;
5388313bdea8SRichard Henderson case TCG_CALL_ARG_BY_REF_N:
5389313bdea8SRichard Henderson load_arg_stk(s, loc->ref_slot, ts, allocated_regs);
5390313bdea8SRichard Henderson break;
539139004a71SRichard Henderson default:
539239004a71SRichard Henderson g_assert_not_reached();
539339004a71SRichard Henderson }
539439004a71SRichard Henderson }
539539004a71SRichard Henderson
539639004a71SRichard Henderson /* Mark dead temporaries and free the associated registers. */
5397866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
5398866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) {
539943439139SRichard Henderson temp_dead(s, arg_temp(op->args[i]));
5400c896fe29Sbellard }
5401c896fe29Sbellard }
5402c896fe29Sbellard
540339004a71SRichard Henderson /* Clobber call registers. */
5404c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
5405c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
5406b3915dbbSRichard Henderson tcg_reg_free(s, i, allocated_regs);
5407c896fe29Sbellard }
5408c896fe29Sbellard }
5409c896fe29Sbellard
541039004a71SRichard Henderson /*
541139004a71SRichard Henderson * Save globals if they might be written by the helper,
541239004a71SRichard Henderson * sync them if they might be read.
541339004a71SRichard Henderson */
541439004a71SRichard Henderson if (info->flags & TCG_CALL_NO_READ_GLOBALS) {
541578505279SAurelien Jarno /* Nothing to do */
541639004a71SRichard Henderson } else if (info->flags & TCG_CALL_NO_WRITE_GLOBALS) {
541778505279SAurelien Jarno sync_globals(s, allocated_regs);
541878505279SAurelien Jarno } else {
5419e8996ee0Sbellard save_globals(s, allocated_regs);
5420b9c18f56Saurel32 }
5421c896fe29Sbellard
5422313bdea8SRichard Henderson /*
5423313bdea8SRichard Henderson * If the ABI passes a pointer to the returned struct as the first
5424313bdea8SRichard Henderson * argument, load that now. Pass a pointer to the output home slot.
5425313bdea8SRichard Henderson */
5426313bdea8SRichard Henderson if (info->out_kind == TCG_CALL_RET_BY_REF) {
5427313bdea8SRichard Henderson TCGTemp *ts = arg_temp(op->args[0]);
5428313bdea8SRichard Henderson
5429313bdea8SRichard Henderson if (!ts->mem_allocated) {
5430313bdea8SRichard Henderson temp_allocate_frame(s, ts);
5431313bdea8SRichard Henderson }
5432313bdea8SRichard Henderson load_arg_ref(s, 0, ts->mem_base->reg, ts->mem_offset, &allocated_regs);
5433313bdea8SRichard Henderson }
5434313bdea8SRichard Henderson
5435cee44b03SRichard Henderson tcg_out_call(s, tcg_call_func(op), info);
5436c896fe29Sbellard
543739004a71SRichard Henderson /* Assign output registers and emit moves if needed. */
543839004a71SRichard Henderson switch (info->out_kind) {
543939004a71SRichard Henderson case TCG_CALL_RET_NORMAL:
5440c896fe29Sbellard for (i = 0; i < nb_oargs; i++) {
544139004a71SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]);
54425e3d0c19SRichard Henderson TCGReg reg = tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, i);
5443d63e3b6eSRichard Henderson
5444d63e3b6eSRichard Henderson /* ENV should not be modified. */
5445e01fa97dSRichard Henderson tcg_debug_assert(!temp_readonly(ts));
5446d63e3b6eSRichard Henderson
5447098859f1SRichard Henderson set_temp_val_reg(s, ts, reg);
5448c896fe29Sbellard ts->mem_coherent = 0;
544939004a71SRichard Henderson }
545039004a71SRichard Henderson break;
5451313bdea8SRichard Henderson
5452c6556aa0SRichard Henderson case TCG_CALL_RET_BY_VEC:
5453c6556aa0SRichard Henderson {
5454c6556aa0SRichard Henderson TCGTemp *ts = arg_temp(op->args[0]);
5455c6556aa0SRichard Henderson
5456c6556aa0SRichard Henderson tcg_debug_assert(ts->base_type == TCG_TYPE_I128);
5457c6556aa0SRichard Henderson tcg_debug_assert(ts->temp_subindex == 0);
5458c6556aa0SRichard Henderson if (!ts->mem_allocated) {
5459c6556aa0SRichard Henderson temp_allocate_frame(s, ts);
5460c6556aa0SRichard Henderson }
5461c6556aa0SRichard Henderson tcg_out_st(s, TCG_TYPE_V128,
5462c6556aa0SRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0),
5463c6556aa0SRichard Henderson ts->mem_base->reg, ts->mem_offset);
5464c6556aa0SRichard Henderson }
5465c6556aa0SRichard Henderson /* fall through to mark all parts in memory */
5466c6556aa0SRichard Henderson
5467313bdea8SRichard Henderson case TCG_CALL_RET_BY_REF:
5468313bdea8SRichard Henderson /* The callee has performed a write through the reference. */
5469313bdea8SRichard Henderson for (i = 0; i < nb_oargs; i++) {
5470313bdea8SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]);
5471313bdea8SRichard Henderson ts->val_type = TEMP_VAL_MEM;
5472313bdea8SRichard Henderson }
5473313bdea8SRichard Henderson break;
5474313bdea8SRichard Henderson
547539004a71SRichard Henderson default:
547639004a71SRichard Henderson g_assert_not_reached();
547739004a71SRichard Henderson }
547839004a71SRichard Henderson
547939004a71SRichard Henderson /* Flush or discard output registers as needed. */
548039004a71SRichard Henderson for (i = 0; i < nb_oargs; i++) {
548139004a71SRichard Henderson TCGTemp *ts = arg_temp(op->args[i]);
5482ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) {
548339004a71SRichard Henderson temp_sync(s, ts, s->reserved_regs, 0, IS_DEAD_ARG(i));
548459d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) {
5485f8bf00f1SRichard Henderson temp_dead(s, ts);
5486c896fe29Sbellard }
5487c896fe29Sbellard }
54888c11ad25SAurelien Jarno }
5489c896fe29Sbellard
5490e63b8a29SRichard Henderson /**
5491e63b8a29SRichard Henderson * atom_and_align_for_opc:
5492e63b8a29SRichard Henderson * @s: tcg context
5493e63b8a29SRichard Henderson * @opc: memory operation code
5494e63b8a29SRichard Henderson * @host_atom: MO_ATOM_{IFALIGN,WITHIN16,SUBALIGN} for host operations
5495e63b8a29SRichard Henderson * @allow_two_ops: true if we are prepared to issue two operations
5496e63b8a29SRichard Henderson *
5497e63b8a29SRichard Henderson * Return the alignment and atomicity to use for the inline fast path
5498e63b8a29SRichard Henderson * for the given memory operation. The alignment may be larger than
5499e63b8a29SRichard Henderson * that specified in @opc, and the correct alignment will be diagnosed
5500e63b8a29SRichard Henderson * by the slow path helper.
5501e63b8a29SRichard Henderson *
5502e63b8a29SRichard Henderson * If @allow_two_ops, the host is prepared to test for 2x alignment,
5503e63b8a29SRichard Henderson * and issue two loads or stores for subalignment.
5504e63b8a29SRichard Henderson */
atom_and_align_for_opc(TCGContext * s,MemOp opc,MemOp host_atom,bool allow_two_ops)5505e63b8a29SRichard Henderson static TCGAtomAlign atom_and_align_for_opc(TCGContext *s, MemOp opc,
5506e63b8a29SRichard Henderson MemOp host_atom, bool allow_two_ops)
5507e63b8a29SRichard Henderson {
5508c5809eeeSRichard Henderson MemOp align = memop_alignment_bits(opc);
5509e63b8a29SRichard Henderson MemOp size = opc & MO_SIZE;
5510e63b8a29SRichard Henderson MemOp half = size ? size - 1 : 0;
5511cbb14556SRichard Henderson MemOp atom = opc & MO_ATOM_MASK;
5512e63b8a29SRichard Henderson MemOp atmax;
5513e63b8a29SRichard Henderson
5514e63b8a29SRichard Henderson switch (atom) {
5515e63b8a29SRichard Henderson case MO_ATOM_NONE:
5516e63b8a29SRichard Henderson /* The operation requires no specific atomicity. */
5517e63b8a29SRichard Henderson atmax = MO_8;
5518e63b8a29SRichard Henderson break;
5519e63b8a29SRichard Henderson
5520e63b8a29SRichard Henderson case MO_ATOM_IFALIGN:
5521e63b8a29SRichard Henderson atmax = size;
5522e63b8a29SRichard Henderson break;
5523e63b8a29SRichard Henderson
5524e63b8a29SRichard Henderson case MO_ATOM_IFALIGN_PAIR:
5525e63b8a29SRichard Henderson atmax = half;
5526e63b8a29SRichard Henderson break;
5527e63b8a29SRichard Henderson
5528e63b8a29SRichard Henderson case MO_ATOM_WITHIN16:
5529e63b8a29SRichard Henderson atmax = size;
5530e63b8a29SRichard Henderson if (size == MO_128) {
5531e63b8a29SRichard Henderson /* Misalignment implies !within16, and therefore no atomicity. */
5532e63b8a29SRichard Henderson } else if (host_atom != MO_ATOM_WITHIN16) {
5533e63b8a29SRichard Henderson /* The host does not implement within16, so require alignment. */
5534e63b8a29SRichard Henderson align = MAX(align, size);
5535e63b8a29SRichard Henderson }
5536e63b8a29SRichard Henderson break;
5537e63b8a29SRichard Henderson
5538e63b8a29SRichard Henderson case MO_ATOM_WITHIN16_PAIR:
5539e63b8a29SRichard Henderson atmax = size;
5540e63b8a29SRichard Henderson /*
5541e63b8a29SRichard Henderson * Misalignment implies !within16, and therefore half atomicity.
5542e63b8a29SRichard Henderson * Any host prepared for two operations can implement this with
5543e63b8a29SRichard Henderson * half alignment.
5544e63b8a29SRichard Henderson */
5545e63b8a29SRichard Henderson if (host_atom != MO_ATOM_WITHIN16 && allow_two_ops) {
5546e63b8a29SRichard Henderson align = MAX(align, half);
5547e63b8a29SRichard Henderson }
5548e63b8a29SRichard Henderson break;
5549e63b8a29SRichard Henderson
5550e63b8a29SRichard Henderson case MO_ATOM_SUBALIGN:
5551e63b8a29SRichard Henderson atmax = size;
5552e63b8a29SRichard Henderson if (host_atom != MO_ATOM_SUBALIGN) {
5553e63b8a29SRichard Henderson /* If unaligned but not odd, there are subobjects up to half. */
5554e63b8a29SRichard Henderson if (allow_two_ops) {
5555e63b8a29SRichard Henderson align = MAX(align, half);
5556e63b8a29SRichard Henderson } else {
5557e63b8a29SRichard Henderson align = MAX(align, size);
5558e63b8a29SRichard Henderson }
5559e63b8a29SRichard Henderson }
5560e63b8a29SRichard Henderson break;
5561e63b8a29SRichard Henderson
5562e63b8a29SRichard Henderson default:
5563e63b8a29SRichard Henderson g_assert_not_reached();
5564e63b8a29SRichard Henderson }
5565e63b8a29SRichard Henderson
5566e63b8a29SRichard Henderson return (TCGAtomAlign){ .atom = atmax, .align = align };
5567e63b8a29SRichard Henderson }
5568e63b8a29SRichard Henderson
55698429a1caSRichard Henderson /*
55708429a1caSRichard Henderson * Similarly for qemu_ld/st slow path helpers.
55718429a1caSRichard Henderson * We must re-implement tcg_gen_callN and tcg_reg_alloc_call simultaneously,
55728429a1caSRichard Henderson * using only the provided backend tcg_out_* functions.
55738429a1caSRichard Henderson */
55748429a1caSRichard Henderson
tcg_out_helper_stk_ofs(TCGType type,unsigned slot)55758429a1caSRichard Henderson static int tcg_out_helper_stk_ofs(TCGType type, unsigned slot)
55768429a1caSRichard Henderson {
55778429a1caSRichard Henderson int ofs = arg_slot_stk_ofs(slot);
55788429a1caSRichard Henderson
55798429a1caSRichard Henderson /*
55808429a1caSRichard Henderson * Each stack slot is TCG_TARGET_LONG_BITS. If the host does not
55818429a1caSRichard Henderson * require extension to uint64_t, adjust the address for uint32_t.
55828429a1caSRichard Henderson */
55838429a1caSRichard Henderson if (HOST_BIG_ENDIAN &&
55848429a1caSRichard Henderson TCG_TARGET_REG_BITS == 64 &&
55858429a1caSRichard Henderson type == TCG_TYPE_I32) {
55868429a1caSRichard Henderson ofs += 4;
55878429a1caSRichard Henderson }
55888429a1caSRichard Henderson return ofs;
55898429a1caSRichard Henderson }
55908429a1caSRichard Henderson
tcg_out_helper_load_slots(TCGContext * s,unsigned nmov,TCGMovExtend * mov,const TCGLdstHelperParam * parm)55918d314041SRichard Henderson static void tcg_out_helper_load_slots(TCGContext *s,
55928429a1caSRichard Henderson unsigned nmov, TCGMovExtend *mov,
55932462e30eSRichard Henderson const TCGLdstHelperParam *parm)
55948429a1caSRichard Henderson {
55958d314041SRichard Henderson unsigned i;
55962462e30eSRichard Henderson TCGReg dst3;
55972462e30eSRichard Henderson
55988d314041SRichard Henderson /*
55998d314041SRichard Henderson * Start from the end, storing to the stack first.
56008d314041SRichard Henderson * This frees those registers, so we need not consider overlap.
56018d314041SRichard Henderson */
56028d314041SRichard Henderson for (i = nmov; i-- > 0; ) {
56038d314041SRichard Henderson unsigned slot = mov[i].dst;
56048d314041SRichard Henderson
56058d314041SRichard Henderson if (arg_slot_reg_p(slot)) {
56068d314041SRichard Henderson goto found_reg;
56078d314041SRichard Henderson }
56088d314041SRichard Henderson
56098d314041SRichard Henderson TCGReg src = mov[i].src;
56108d314041SRichard Henderson TCGType dst_type = mov[i].dst_type;
56118d314041SRichard Henderson MemOp dst_mo = dst_type == TCG_TYPE_I32 ? MO_32 : MO_64;
56128d314041SRichard Henderson
56138d314041SRichard Henderson /* The argument is going onto the stack; extend into scratch. */
56148d314041SRichard Henderson if ((mov[i].src_ext & MO_SIZE) != dst_mo) {
56158d314041SRichard Henderson tcg_debug_assert(parm->ntmp != 0);
56168d314041SRichard Henderson mov[i].dst = src = parm->tmp[0];
56178d314041SRichard Henderson tcg_out_movext1(s, &mov[i]);
56188d314041SRichard Henderson }
56198d314041SRichard Henderson
56208d314041SRichard Henderson tcg_out_st(s, dst_type, src, TCG_REG_CALL_STACK,
56218d314041SRichard Henderson tcg_out_helper_stk_ofs(dst_type, slot));
56228d314041SRichard Henderson }
56238d314041SRichard Henderson return;
56248d314041SRichard Henderson
56258d314041SRichard Henderson found_reg:
56268d314041SRichard Henderson /*
56278d314041SRichard Henderson * The remaining arguments are in registers.
56288d314041SRichard Henderson * Convert slot numbers to argument registers.
56298d314041SRichard Henderson */
56308d314041SRichard Henderson nmov = i + 1;
56318d314041SRichard Henderson for (i = 0; i < nmov; ++i) {
56328d314041SRichard Henderson mov[i].dst = tcg_target_call_iarg_regs[mov[i].dst];
56338d314041SRichard Henderson }
56348d314041SRichard Henderson
56358429a1caSRichard Henderson switch (nmov) {
56362462e30eSRichard Henderson case 4:
56378429a1caSRichard Henderson /* The backend must have provided enough temps for the worst case. */
56382462e30eSRichard Henderson tcg_debug_assert(parm->ntmp >= 2);
56398429a1caSRichard Henderson
56402462e30eSRichard Henderson dst3 = mov[3].dst;
56412462e30eSRichard Henderson for (unsigned j = 0; j < 3; ++j) {
56422462e30eSRichard Henderson if (dst3 == mov[j].src) {
56438429a1caSRichard Henderson /*
56442462e30eSRichard Henderson * Conflict. Copy the source to a temporary, perform the
56452462e30eSRichard Henderson * remaining moves, then the extension from our scratch
56462462e30eSRichard Henderson * on the way out.
56478429a1caSRichard Henderson */
56482462e30eSRichard Henderson TCGReg scratch = parm->tmp[1];
56498429a1caSRichard Henderson
56502462e30eSRichard Henderson tcg_out_mov(s, mov[3].src_type, scratch, mov[3].src);
56512462e30eSRichard Henderson tcg_out_movext3(s, mov, mov + 1, mov + 2, parm->tmp[0]);
56522462e30eSRichard Henderson tcg_out_movext1_new_src(s, &mov[3], scratch);
56532462e30eSRichard Henderson break;
56548429a1caSRichard Henderson }
56558429a1caSRichard Henderson }
56568429a1caSRichard Henderson
56578429a1caSRichard Henderson /* No conflicts: perform this move and continue. */
56582462e30eSRichard Henderson tcg_out_movext1(s, &mov[3]);
56592462e30eSRichard Henderson /* fall through */
56608429a1caSRichard Henderson
56612462e30eSRichard Henderson case 3:
56622462e30eSRichard Henderson tcg_out_movext3(s, mov, mov + 1, mov + 2,
56632462e30eSRichard Henderson parm->ntmp ? parm->tmp[0] : -1);
56642462e30eSRichard Henderson break;
56658429a1caSRichard Henderson case 2:
56662462e30eSRichard Henderson tcg_out_movext2(s, mov, mov + 1,
56672462e30eSRichard Henderson parm->ntmp ? parm->tmp[0] : -1);
56682462e30eSRichard Henderson break;
56698429a1caSRichard Henderson case 1:
56708429a1caSRichard Henderson tcg_out_movext1(s, mov);
56712462e30eSRichard Henderson break;
56722462e30eSRichard Henderson default:
56738429a1caSRichard Henderson g_assert_not_reached();
56748429a1caSRichard Henderson }
56758429a1caSRichard Henderson }
56768429a1caSRichard Henderson
tcg_out_helper_load_imm(TCGContext * s,unsigned slot,TCGType type,tcg_target_long imm,const TCGLdstHelperParam * parm)56778429a1caSRichard Henderson static void tcg_out_helper_load_imm(TCGContext *s, unsigned slot,
56788429a1caSRichard Henderson TCGType type, tcg_target_long imm,
56798429a1caSRichard Henderson const TCGLdstHelperParam *parm)
56808429a1caSRichard Henderson {
56818429a1caSRichard Henderson if (arg_slot_reg_p(slot)) {
56828429a1caSRichard Henderson tcg_out_movi(s, type, tcg_target_call_iarg_regs[slot], imm);
56838429a1caSRichard Henderson } else {
56848429a1caSRichard Henderson int ofs = tcg_out_helper_stk_ofs(type, slot);
56858429a1caSRichard Henderson if (!tcg_out_sti(s, type, imm, TCG_REG_CALL_STACK, ofs)) {
56868429a1caSRichard Henderson tcg_debug_assert(parm->ntmp != 0);
56878429a1caSRichard Henderson tcg_out_movi(s, type, parm->tmp[0], imm);
56888429a1caSRichard Henderson tcg_out_st(s, type, parm->tmp[0], TCG_REG_CALL_STACK, ofs);
56898429a1caSRichard Henderson }
56908429a1caSRichard Henderson }
56918429a1caSRichard Henderson }
56928429a1caSRichard Henderson
tcg_out_helper_load_common_args(TCGContext * s,const TCGLabelQemuLdst * ldst,const TCGLdstHelperParam * parm,const TCGHelperInfo * info,unsigned next_arg)56938429a1caSRichard Henderson static void tcg_out_helper_load_common_args(TCGContext *s,
56948429a1caSRichard Henderson const TCGLabelQemuLdst *ldst,
56958429a1caSRichard Henderson const TCGLdstHelperParam *parm,
56968429a1caSRichard Henderson const TCGHelperInfo *info,
56978429a1caSRichard Henderson unsigned next_arg)
56988429a1caSRichard Henderson {
56998429a1caSRichard Henderson TCGMovExtend ptr_mov = {
57008429a1caSRichard Henderson .dst_type = TCG_TYPE_PTR,
57018429a1caSRichard Henderson .src_type = TCG_TYPE_PTR,
57028429a1caSRichard Henderson .src_ext = sizeof(void *) == 4 ? MO_32 : MO_64
57038429a1caSRichard Henderson };
57048429a1caSRichard Henderson const TCGCallArgumentLoc *loc = &info->in[0];
57058429a1caSRichard Henderson TCGType type;
57068429a1caSRichard Henderson unsigned slot;
57078429a1caSRichard Henderson tcg_target_ulong imm;
57088429a1caSRichard Henderson
57098429a1caSRichard Henderson /*
57108429a1caSRichard Henderson * Handle env, which is always first.
57118429a1caSRichard Henderson */
57128429a1caSRichard Henderson ptr_mov.dst = loc->arg_slot;
57138429a1caSRichard Henderson ptr_mov.src = TCG_AREG0;
57148429a1caSRichard Henderson tcg_out_helper_load_slots(s, 1, &ptr_mov, parm);
57158429a1caSRichard Henderson
57168429a1caSRichard Henderson /*
57178429a1caSRichard Henderson * Handle oi.
57188429a1caSRichard Henderson */
57198429a1caSRichard Henderson imm = ldst->oi;
57208429a1caSRichard Henderson loc = &info->in[next_arg];
57218429a1caSRichard Henderson type = TCG_TYPE_I32;
57228429a1caSRichard Henderson switch (loc->kind) {
57238429a1caSRichard Henderson case TCG_CALL_ARG_NORMAL:
57248429a1caSRichard Henderson break;
57258429a1caSRichard Henderson case TCG_CALL_ARG_EXTEND_U:
57268429a1caSRichard Henderson case TCG_CALL_ARG_EXTEND_S:
57278429a1caSRichard Henderson /* No extension required for MemOpIdx. */
57288429a1caSRichard Henderson tcg_debug_assert(imm <= INT32_MAX);
57298429a1caSRichard Henderson type = TCG_TYPE_REG;
57308429a1caSRichard Henderson break;
57318429a1caSRichard Henderson default:
57328429a1caSRichard Henderson g_assert_not_reached();
57338429a1caSRichard Henderson }
57348429a1caSRichard Henderson tcg_out_helper_load_imm(s, loc->arg_slot, type, imm, parm);
57358429a1caSRichard Henderson next_arg++;
57368429a1caSRichard Henderson
57378429a1caSRichard Henderson /*
57388429a1caSRichard Henderson * Handle ra.
57398429a1caSRichard Henderson */
57408429a1caSRichard Henderson loc = &info->in[next_arg];
57418429a1caSRichard Henderson slot = loc->arg_slot;
57428429a1caSRichard Henderson if (parm->ra_gen) {
57438429a1caSRichard Henderson int arg_reg = -1;
57448429a1caSRichard Henderson TCGReg ra_reg;
57458429a1caSRichard Henderson
57468429a1caSRichard Henderson if (arg_slot_reg_p(slot)) {
57478429a1caSRichard Henderson arg_reg = tcg_target_call_iarg_regs[slot];
57488429a1caSRichard Henderson }
57498429a1caSRichard Henderson ra_reg = parm->ra_gen(s, ldst, arg_reg);
57508429a1caSRichard Henderson
57518429a1caSRichard Henderson ptr_mov.dst = slot;
57528429a1caSRichard Henderson ptr_mov.src = ra_reg;
57538429a1caSRichard Henderson tcg_out_helper_load_slots(s, 1, &ptr_mov, parm);
57548429a1caSRichard Henderson } else {
57558429a1caSRichard Henderson imm = (uintptr_t)ldst->raddr;
57568429a1caSRichard Henderson tcg_out_helper_load_imm(s, slot, TCG_TYPE_PTR, imm, parm);
57578429a1caSRichard Henderson }
57588429a1caSRichard Henderson }
57598429a1caSRichard Henderson
tcg_out_helper_add_mov(TCGMovExtend * mov,const TCGCallArgumentLoc * loc,TCGType dst_type,TCGType src_type,TCGReg lo,TCGReg hi)57608429a1caSRichard Henderson static unsigned tcg_out_helper_add_mov(TCGMovExtend *mov,
57618429a1caSRichard Henderson const TCGCallArgumentLoc *loc,
57628429a1caSRichard Henderson TCGType dst_type, TCGType src_type,
57638429a1caSRichard Henderson TCGReg lo, TCGReg hi)
57648429a1caSRichard Henderson {
5765ebebea53SRichard Henderson MemOp reg_mo;
5766ebebea53SRichard Henderson
57678429a1caSRichard Henderson if (dst_type <= TCG_TYPE_REG) {
57688429a1caSRichard Henderson MemOp src_ext;
57698429a1caSRichard Henderson
57708429a1caSRichard Henderson switch (loc->kind) {
57718429a1caSRichard Henderson case TCG_CALL_ARG_NORMAL:
57728429a1caSRichard Henderson src_ext = src_type == TCG_TYPE_I32 ? MO_32 : MO_64;
57738429a1caSRichard Henderson break;
57748429a1caSRichard Henderson case TCG_CALL_ARG_EXTEND_U:
57758429a1caSRichard Henderson dst_type = TCG_TYPE_REG;
57768429a1caSRichard Henderson src_ext = MO_UL;
57778429a1caSRichard Henderson break;
57788429a1caSRichard Henderson case TCG_CALL_ARG_EXTEND_S:
57798429a1caSRichard Henderson dst_type = TCG_TYPE_REG;
57808429a1caSRichard Henderson src_ext = MO_SL;
57818429a1caSRichard Henderson break;
57828429a1caSRichard Henderson default:
57838429a1caSRichard Henderson g_assert_not_reached();
57848429a1caSRichard Henderson }
57858429a1caSRichard Henderson
57868429a1caSRichard Henderson mov[0].dst = loc->arg_slot;
57878429a1caSRichard Henderson mov[0].dst_type = dst_type;
57888429a1caSRichard Henderson mov[0].src = lo;
57898429a1caSRichard Henderson mov[0].src_type = src_type;
57908429a1caSRichard Henderson mov[0].src_ext = src_ext;
57918429a1caSRichard Henderson return 1;
57928429a1caSRichard Henderson }
57938429a1caSRichard Henderson
5794ebebea53SRichard Henderson if (TCG_TARGET_REG_BITS == 32) {
5795ebebea53SRichard Henderson assert(dst_type == TCG_TYPE_I64);
5796ebebea53SRichard Henderson reg_mo = MO_32;
5797ebebea53SRichard Henderson } else {
5798ebebea53SRichard Henderson assert(dst_type == TCG_TYPE_I128);
5799ebebea53SRichard Henderson reg_mo = MO_64;
5800ebebea53SRichard Henderson }
58018429a1caSRichard Henderson
58028429a1caSRichard Henderson mov[0].dst = loc[HOST_BIG_ENDIAN].arg_slot;
58038429a1caSRichard Henderson mov[0].src = lo;
5804ebebea53SRichard Henderson mov[0].dst_type = TCG_TYPE_REG;
5805ebebea53SRichard Henderson mov[0].src_type = TCG_TYPE_REG;
5806ebebea53SRichard Henderson mov[0].src_ext = reg_mo;
58078429a1caSRichard Henderson
58088429a1caSRichard Henderson mov[1].dst = loc[!HOST_BIG_ENDIAN].arg_slot;
58098429a1caSRichard Henderson mov[1].src = hi;
5810ebebea53SRichard Henderson mov[1].dst_type = TCG_TYPE_REG;
5811ebebea53SRichard Henderson mov[1].src_type = TCG_TYPE_REG;
5812ebebea53SRichard Henderson mov[1].src_ext = reg_mo;
58138429a1caSRichard Henderson
58148429a1caSRichard Henderson return 2;
58158429a1caSRichard Henderson }
58168429a1caSRichard Henderson
tcg_out_ld_helper_args(TCGContext * s,const TCGLabelQemuLdst * ldst,const TCGLdstHelperParam * parm)58178429a1caSRichard Henderson static void tcg_out_ld_helper_args(TCGContext *s, const TCGLabelQemuLdst *ldst,
58188429a1caSRichard Henderson const TCGLdstHelperParam *parm)
58198429a1caSRichard Henderson {
58208429a1caSRichard Henderson const TCGHelperInfo *info;
58218429a1caSRichard Henderson const TCGCallArgumentLoc *loc;
58228429a1caSRichard Henderson TCGMovExtend mov[2];
58238429a1caSRichard Henderson unsigned next_arg, nmov;
58248429a1caSRichard Henderson MemOp mop = get_memop(ldst->oi);
58258429a1caSRichard Henderson
58268429a1caSRichard Henderson switch (mop & MO_SIZE) {
58278429a1caSRichard Henderson case MO_8:
58288429a1caSRichard Henderson case MO_16:
58298429a1caSRichard Henderson case MO_32:
58308429a1caSRichard Henderson info = &info_helper_ld32_mmu;
58318429a1caSRichard Henderson break;
58328429a1caSRichard Henderson case MO_64:
58338429a1caSRichard Henderson info = &info_helper_ld64_mmu;
58348429a1caSRichard Henderson break;
5835ebebea53SRichard Henderson case MO_128:
5836ebebea53SRichard Henderson info = &info_helper_ld128_mmu;
5837ebebea53SRichard Henderson break;
58388429a1caSRichard Henderson default:
58398429a1caSRichard Henderson g_assert_not_reached();
58408429a1caSRichard Henderson }
58418429a1caSRichard Henderson
58428429a1caSRichard Henderson /* Defer env argument. */
58438429a1caSRichard Henderson next_arg = 1;
58448429a1caSRichard Henderson
58458429a1caSRichard Henderson loc = &info->in[next_arg];
5846c31e5fa4SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && s->addr_type == TCG_TYPE_I32) {
584724e46e6cSRichard Henderson /*
584824e46e6cSRichard Henderson * 32-bit host with 32-bit guest: zero-extend the guest address
584924e46e6cSRichard Henderson * to 64-bits for the helper by storing the low part, then
585024e46e6cSRichard Henderson * load a zero for the high part.
585124e46e6cSRichard Henderson */
585224e46e6cSRichard Henderson tcg_out_helper_add_mov(mov, loc + HOST_BIG_ENDIAN,
585324e46e6cSRichard Henderson TCG_TYPE_I32, TCG_TYPE_I32,
585424e46e6cSRichard Henderson ldst->addrlo_reg, -1);
585524e46e6cSRichard Henderson tcg_out_helper_load_slots(s, 1, mov, parm);
585624e46e6cSRichard Henderson
585724e46e6cSRichard Henderson tcg_out_helper_load_imm(s, loc[!HOST_BIG_ENDIAN].arg_slot,
585824e46e6cSRichard Henderson TCG_TYPE_I32, 0, parm);
585924e46e6cSRichard Henderson next_arg += 2;
5860c31e5fa4SRichard Henderson } else {
5861c31e5fa4SRichard Henderson nmov = tcg_out_helper_add_mov(mov, loc, TCG_TYPE_I64, s->addr_type,
5862c31e5fa4SRichard Henderson ldst->addrlo_reg, ldst->addrhi_reg);
5863c31e5fa4SRichard Henderson tcg_out_helper_load_slots(s, nmov, mov, parm);
5864c31e5fa4SRichard Henderson next_arg += nmov;
586524e46e6cSRichard Henderson }
58668429a1caSRichard Henderson
5867ebebea53SRichard Henderson switch (info->out_kind) {
5868ebebea53SRichard Henderson case TCG_CALL_RET_NORMAL:
5869ebebea53SRichard Henderson case TCG_CALL_RET_BY_VEC:
5870ebebea53SRichard Henderson break;
5871ebebea53SRichard Henderson case TCG_CALL_RET_BY_REF:
5872ebebea53SRichard Henderson /*
5873ebebea53SRichard Henderson * The return reference is in the first argument slot.
5874ebebea53SRichard Henderson * We need memory in which to return: re-use the top of stack.
5875ebebea53SRichard Henderson */
5876ebebea53SRichard Henderson {
5877ebebea53SRichard Henderson int ofs_slot0 = TCG_TARGET_CALL_STACK_OFFSET;
5878ebebea53SRichard Henderson
5879ebebea53SRichard Henderson if (arg_slot_reg_p(0)) {
5880ebebea53SRichard Henderson tcg_out_addi_ptr(s, tcg_target_call_iarg_regs[0],
5881ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0);
5882ebebea53SRichard Henderson } else {
5883ebebea53SRichard Henderson tcg_debug_assert(parm->ntmp != 0);
5884ebebea53SRichard Henderson tcg_out_addi_ptr(s, parm->tmp[0],
5885ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0);
5886ebebea53SRichard Henderson tcg_out_st(s, TCG_TYPE_PTR, parm->tmp[0],
5887ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0);
5888ebebea53SRichard Henderson }
5889ebebea53SRichard Henderson }
5890ebebea53SRichard Henderson break;
5891ebebea53SRichard Henderson default:
5892ebebea53SRichard Henderson g_assert_not_reached();
5893ebebea53SRichard Henderson }
58948429a1caSRichard Henderson
58958429a1caSRichard Henderson tcg_out_helper_load_common_args(s, ldst, parm, info, next_arg);
58968429a1caSRichard Henderson }
58978429a1caSRichard Henderson
tcg_out_ld_helper_ret(TCGContext * s,const TCGLabelQemuLdst * ldst,bool load_sign,const TCGLdstHelperParam * parm)58988429a1caSRichard Henderson static void tcg_out_ld_helper_ret(TCGContext *s, const TCGLabelQemuLdst *ldst,
58998429a1caSRichard Henderson bool load_sign,
59008429a1caSRichard Henderson const TCGLdstHelperParam *parm)
59018429a1caSRichard Henderson {
59028429a1caSRichard Henderson MemOp mop = get_memop(ldst->oi);
5903ebebea53SRichard Henderson TCGMovExtend mov[2];
5904ebebea53SRichard Henderson int ofs_slot0;
59058429a1caSRichard Henderson
5906ebebea53SRichard Henderson switch (ldst->type) {
5907ebebea53SRichard Henderson case TCG_TYPE_I64:
5908ebebea53SRichard Henderson if (TCG_TARGET_REG_BITS == 32) {
5909ebebea53SRichard Henderson break;
5910ebebea53SRichard Henderson }
5911ebebea53SRichard Henderson /* fall through */
5912ebebea53SRichard Henderson
5913ebebea53SRichard Henderson case TCG_TYPE_I32:
59148429a1caSRichard Henderson mov[0].dst = ldst->datalo_reg;
59158429a1caSRichard Henderson mov[0].src = tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, 0);
59168429a1caSRichard Henderson mov[0].dst_type = ldst->type;
59178429a1caSRichard Henderson mov[0].src_type = TCG_TYPE_REG;
59188429a1caSRichard Henderson
59198429a1caSRichard Henderson /*
59208429a1caSRichard Henderson * If load_sign, then we allowed the helper to perform the
59218429a1caSRichard Henderson * appropriate sign extension to tcg_target_ulong, and all
59228429a1caSRichard Henderson * we need now is a plain move.
59238429a1caSRichard Henderson *
59248429a1caSRichard Henderson * If they do not, then we expect the relevant extension
59258429a1caSRichard Henderson * instruction to be no more expensive than a move, and
59268429a1caSRichard Henderson * we thus save the icache etc by only using one of two
59278429a1caSRichard Henderson * helper functions.
59288429a1caSRichard Henderson */
59298429a1caSRichard Henderson if (load_sign || !(mop & MO_SIGN)) {
59308429a1caSRichard Henderson if (TCG_TARGET_REG_BITS == 32 || ldst->type == TCG_TYPE_I32) {
59318429a1caSRichard Henderson mov[0].src_ext = MO_32;
59328429a1caSRichard Henderson } else {
59338429a1caSRichard Henderson mov[0].src_ext = MO_64;
59348429a1caSRichard Henderson }
59358429a1caSRichard Henderson } else {
59368429a1caSRichard Henderson mov[0].src_ext = mop & MO_SSIZE;
59378429a1caSRichard Henderson }
59388429a1caSRichard Henderson tcg_out_movext1(s, mov);
5939ebebea53SRichard Henderson return;
5940ebebea53SRichard Henderson
5941ebebea53SRichard Henderson case TCG_TYPE_I128:
5942ebebea53SRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 64);
5943ebebea53SRichard Henderson ofs_slot0 = TCG_TARGET_CALL_STACK_OFFSET;
5944ebebea53SRichard Henderson switch (TCG_TARGET_CALL_RET_I128) {
5945ebebea53SRichard Henderson case TCG_CALL_RET_NORMAL:
5946ebebea53SRichard Henderson break;
5947ebebea53SRichard Henderson case TCG_CALL_RET_BY_VEC:
5948ebebea53SRichard Henderson tcg_out_st(s, TCG_TYPE_V128,
5949ebebea53SRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0),
5950ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0);
5951ebebea53SRichard Henderson /* fall through */
5952ebebea53SRichard Henderson case TCG_CALL_RET_BY_REF:
5953ebebea53SRichard Henderson tcg_out_ld(s, TCG_TYPE_I64, ldst->datalo_reg,
5954ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0 + 8 * HOST_BIG_ENDIAN);
5955ebebea53SRichard Henderson tcg_out_ld(s, TCG_TYPE_I64, ldst->datahi_reg,
5956ebebea53SRichard Henderson TCG_REG_CALL_STACK, ofs_slot0 + 8 * !HOST_BIG_ENDIAN);
5957ebebea53SRichard Henderson return;
5958ebebea53SRichard Henderson default:
5959ebebea53SRichard Henderson g_assert_not_reached();
5960ebebea53SRichard Henderson }
5961ebebea53SRichard Henderson break;
5962ebebea53SRichard Henderson
5963ebebea53SRichard Henderson default:
5964ebebea53SRichard Henderson g_assert_not_reached();
5965ebebea53SRichard Henderson }
59668429a1caSRichard Henderson
59678429a1caSRichard Henderson mov[0].dst = ldst->datalo_reg;
59688429a1caSRichard Henderson mov[0].src =
59698429a1caSRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, HOST_BIG_ENDIAN);
5970723d3a27SRichard Henderson mov[0].dst_type = TCG_TYPE_REG;
5971723d3a27SRichard Henderson mov[0].src_type = TCG_TYPE_REG;
5972ebebea53SRichard Henderson mov[0].src_ext = TCG_TARGET_REG_BITS == 32 ? MO_32 : MO_64;
59738429a1caSRichard Henderson
59748429a1caSRichard Henderson mov[1].dst = ldst->datahi_reg;
59758429a1caSRichard Henderson mov[1].src =
59768429a1caSRichard Henderson tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, !HOST_BIG_ENDIAN);
59778429a1caSRichard Henderson mov[1].dst_type = TCG_TYPE_REG;
59788429a1caSRichard Henderson mov[1].src_type = TCG_TYPE_REG;
5979ebebea53SRichard Henderson mov[1].src_ext = TCG_TARGET_REG_BITS == 32 ? MO_32 : MO_64;
59808429a1caSRichard Henderson
59818429a1caSRichard Henderson tcg_out_movext2(s, mov, mov + 1, parm->ntmp ? parm->tmp[0] : -1);
59828429a1caSRichard Henderson }
59838429a1caSRichard Henderson
tcg_out_st_helper_args(TCGContext * s,const TCGLabelQemuLdst * ldst,const TCGLdstHelperParam * parm)59848429a1caSRichard Henderson static void tcg_out_st_helper_args(TCGContext *s, const TCGLabelQemuLdst *ldst,
59858429a1caSRichard Henderson const TCGLdstHelperParam *parm)
59868429a1caSRichard Henderson {
59878429a1caSRichard Henderson const TCGHelperInfo *info;
59888429a1caSRichard Henderson const TCGCallArgumentLoc *loc;
59898429a1caSRichard Henderson TCGMovExtend mov[4];
59908429a1caSRichard Henderson TCGType data_type;
59918429a1caSRichard Henderson unsigned next_arg, nmov, n;
59928429a1caSRichard Henderson MemOp mop = get_memop(ldst->oi);
59938429a1caSRichard Henderson
59948429a1caSRichard Henderson switch (mop & MO_SIZE) {
59958429a1caSRichard Henderson case MO_8:
59968429a1caSRichard Henderson case MO_16:
59978429a1caSRichard Henderson case MO_32:
59988429a1caSRichard Henderson info = &info_helper_st32_mmu;
59998429a1caSRichard Henderson data_type = TCG_TYPE_I32;
60008429a1caSRichard Henderson break;
60018429a1caSRichard Henderson case MO_64:
60028429a1caSRichard Henderson info = &info_helper_st64_mmu;
60038429a1caSRichard Henderson data_type = TCG_TYPE_I64;
60048429a1caSRichard Henderson break;
6005ebebea53SRichard Henderson case MO_128:
6006ebebea53SRichard Henderson info = &info_helper_st128_mmu;
6007ebebea53SRichard Henderson data_type = TCG_TYPE_I128;
6008ebebea53SRichard Henderson break;
60098429a1caSRichard Henderson default:
60108429a1caSRichard Henderson g_assert_not_reached();
60118429a1caSRichard Henderson }
60128429a1caSRichard Henderson
60138429a1caSRichard Henderson /* Defer env argument. */
60148429a1caSRichard Henderson next_arg = 1;
60158429a1caSRichard Henderson nmov = 0;
60168429a1caSRichard Henderson
60178429a1caSRichard Henderson /* Handle addr argument. */
60188429a1caSRichard Henderson loc = &info->in[next_arg];
6019c31e5fa4SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && s->addr_type == TCG_TYPE_I32) {
602024e46e6cSRichard Henderson /*
602124e46e6cSRichard Henderson * 32-bit host with 32-bit guest: zero-extend the guest address
602224e46e6cSRichard Henderson * to 64-bits for the helper by storing the low part. Later,
602324e46e6cSRichard Henderson * after we have processed the register inputs, we will load a
602424e46e6cSRichard Henderson * zero for the high part.
602524e46e6cSRichard Henderson */
602624e46e6cSRichard Henderson tcg_out_helper_add_mov(mov, loc + HOST_BIG_ENDIAN,
602724e46e6cSRichard Henderson TCG_TYPE_I32, TCG_TYPE_I32,
602824e46e6cSRichard Henderson ldst->addrlo_reg, -1);
602924e46e6cSRichard Henderson next_arg += 2;
603024e46e6cSRichard Henderson nmov += 1;
6031c31e5fa4SRichard Henderson } else {
6032c31e5fa4SRichard Henderson n = tcg_out_helper_add_mov(mov, loc, TCG_TYPE_I64, s->addr_type,
6033c31e5fa4SRichard Henderson ldst->addrlo_reg, ldst->addrhi_reg);
6034c31e5fa4SRichard Henderson next_arg += n;
6035c31e5fa4SRichard Henderson nmov += n;
603624e46e6cSRichard Henderson }
60378429a1caSRichard Henderson
60388429a1caSRichard Henderson /* Handle data argument. */
60398429a1caSRichard Henderson loc = &info->in[next_arg];
6040ebebea53SRichard Henderson switch (loc->kind) {
6041ebebea53SRichard Henderson case TCG_CALL_ARG_NORMAL:
6042ebebea53SRichard Henderson case TCG_CALL_ARG_EXTEND_U:
6043ebebea53SRichard Henderson case TCG_CALL_ARG_EXTEND_S:
60448429a1caSRichard Henderson n = tcg_out_helper_add_mov(mov + nmov, loc, data_type, ldst->type,
60458429a1caSRichard Henderson ldst->datalo_reg, ldst->datahi_reg);
60468429a1caSRichard Henderson next_arg += n;
60478429a1caSRichard Henderson nmov += n;
6048ebebea53SRichard Henderson tcg_out_helper_load_slots(s, nmov, mov, parm);
6049ebebea53SRichard Henderson break;
6050ebebea53SRichard Henderson
6051ebebea53SRichard Henderson case TCG_CALL_ARG_BY_REF:
6052ebebea53SRichard Henderson tcg_debug_assert(TCG_TARGET_REG_BITS == 64);
6053ebebea53SRichard Henderson tcg_debug_assert(data_type == TCG_TYPE_I128);
6054ebebea53SRichard Henderson tcg_out_st(s, TCG_TYPE_I64,
6055ebebea53SRichard Henderson HOST_BIG_ENDIAN ? ldst->datahi_reg : ldst->datalo_reg,
6056ebebea53SRichard Henderson TCG_REG_CALL_STACK, arg_slot_stk_ofs(loc[0].ref_slot));
6057ebebea53SRichard Henderson tcg_out_st(s, TCG_TYPE_I64,
6058ebebea53SRichard Henderson HOST_BIG_ENDIAN ? ldst->datalo_reg : ldst->datahi_reg,
6059ebebea53SRichard Henderson TCG_REG_CALL_STACK, arg_slot_stk_ofs(loc[1].ref_slot));
60608429a1caSRichard Henderson
60618429a1caSRichard Henderson tcg_out_helper_load_slots(s, nmov, mov, parm);
6062ebebea53SRichard Henderson
6063ebebea53SRichard Henderson if (arg_slot_reg_p(loc->arg_slot)) {
6064ebebea53SRichard Henderson tcg_out_addi_ptr(s, tcg_target_call_iarg_regs[loc->arg_slot],
6065ebebea53SRichard Henderson TCG_REG_CALL_STACK,
6066ebebea53SRichard Henderson arg_slot_stk_ofs(loc->ref_slot));
6067ebebea53SRichard Henderson } else {
6068ebebea53SRichard Henderson tcg_debug_assert(parm->ntmp != 0);
6069ebebea53SRichard Henderson tcg_out_addi_ptr(s, parm->tmp[0], TCG_REG_CALL_STACK,
6070ebebea53SRichard Henderson arg_slot_stk_ofs(loc->ref_slot));
6071ebebea53SRichard Henderson tcg_out_st(s, TCG_TYPE_PTR, parm->tmp[0],
6072ebebea53SRichard Henderson TCG_REG_CALL_STACK, arg_slot_stk_ofs(loc->arg_slot));
6073ebebea53SRichard Henderson }
6074ebebea53SRichard Henderson next_arg += 2;
6075ebebea53SRichard Henderson break;
6076ebebea53SRichard Henderson
6077ebebea53SRichard Henderson default:
6078ebebea53SRichard Henderson g_assert_not_reached();
6079ebebea53SRichard Henderson }
6080ebebea53SRichard Henderson
6081c31e5fa4SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && s->addr_type == TCG_TYPE_I32) {
6082c31e5fa4SRichard Henderson /* Zero extend the address by loading a zero for the high part. */
608324e46e6cSRichard Henderson loc = &info->in[1 + !HOST_BIG_ENDIAN];
608424e46e6cSRichard Henderson tcg_out_helper_load_imm(s, loc->arg_slot, TCG_TYPE_I32, 0, parm);
608524e46e6cSRichard Henderson }
608624e46e6cSRichard Henderson
60878429a1caSRichard Henderson tcg_out_helper_load_common_args(s, ldst, parm, info, next_arg);
60888429a1caSRichard Henderson }
60898429a1caSRichard Henderson
tcg_gen_code(TCGContext * s,TranslationBlock * tb,uint64_t pc_start)609076cef4b2SRichard Henderson int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start)
6091c896fe29Sbellard {
6092747bd69dSRichard Henderson int i, start_words, num_insns;
609315fa08f8SRichard Henderson TCGOp *op;
6094c896fe29Sbellard
6095d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)
6096fbf59aadSRichard Henderson && qemu_log_in_addr_range(pc_start))) {
6097c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock();
609878b54858SRichard Henderson if (logfile) {
609978b54858SRichard Henderson fprintf(logfile, "OP:\n");
6100b7a83ff8SRichard Henderson tcg_dump_ops(s, logfile, false);
610178b54858SRichard Henderson fprintf(logfile, "\n");
6102fc59d2d8SRobert Foley qemu_log_unlock(logfile);
6103c896fe29Sbellard }
610478b54858SRichard Henderson }
6105c896fe29Sbellard
6106bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG
6107bef16ab4SRichard Henderson /* Ensure all labels referenced have been emitted. */
6108bef16ab4SRichard Henderson {
6109bef16ab4SRichard Henderson TCGLabel *l;
6110bef16ab4SRichard Henderson bool error = false;
6111bef16ab4SRichard Henderson
6112bef16ab4SRichard Henderson QSIMPLEQ_FOREACH(l, &s->labels, next) {
6113f85b1fc4SRichard Henderson if (unlikely(!l->present) && !QSIMPLEQ_EMPTY(&l->branches)) {
6114bef16ab4SRichard Henderson qemu_log_mask(CPU_LOG_TB_OP,
6115bef16ab4SRichard Henderson "$L%d referenced but not present.\n", l->id);
6116bef16ab4SRichard Henderson error = true;
6117bef16ab4SRichard Henderson }
6118bef16ab4SRichard Henderson }
6119bef16ab4SRichard Henderson assert(!error);
6120bef16ab4SRichard Henderson }
6121bef16ab4SRichard Henderson #endif
6122bef16ab4SRichard Henderson
6123*f838a7e3SRichard Henderson /* Do not reuse any EBB that may be allocated within the TB. */
6124*f838a7e3SRichard Henderson tcg_temp_ebb_reset_freed(s);
6125*f838a7e3SRichard Henderson
6126c45cb8bbSRichard Henderson tcg_optimize(s);
61278f2e8c07SKirill Batuzov
6128b4fc67c7SRichard Henderson reachable_code_pass(s);
6129874b8574SRichard Henderson liveness_pass_0(s);
6130b83eabeaSRichard Henderson liveness_pass_1(s);
61315a18407fSRichard Henderson
61325a18407fSRichard Henderson if (s->nb_indirects > 0) {
61335a18407fSRichard Henderson if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND)
6134fbf59aadSRichard Henderson && qemu_log_in_addr_range(pc_start))) {
6135c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock();
613678b54858SRichard Henderson if (logfile) {
613778b54858SRichard Henderson fprintf(logfile, "OP before indirect lowering:\n");
6138b7a83ff8SRichard Henderson tcg_dump_ops(s, logfile, false);
613978b54858SRichard Henderson fprintf(logfile, "\n");
6140fc59d2d8SRobert Foley qemu_log_unlock(logfile);
61415a18407fSRichard Henderson }
614278b54858SRichard Henderson }
6143645e3a81SRichard Henderson
61445a18407fSRichard Henderson /* Replace indirect temps with direct temps. */
6145b83eabeaSRichard Henderson if (liveness_pass_2(s)) {
61465a18407fSRichard Henderson /* If changes were made, re-run liveness. */
6147b83eabeaSRichard Henderson liveness_pass_1(s);
61485a18407fSRichard Henderson }
61495a18407fSRichard Henderson }
6150c5cc28ffSAurelien Jarno
6151d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT)
6152fbf59aadSRichard Henderson && qemu_log_in_addr_range(pc_start))) {
6153c60f599bSRichard Henderson FILE *logfile = qemu_log_trylock();
615478b54858SRichard Henderson if (logfile) {
615578b54858SRichard Henderson fprintf(logfile, "OP after optimization and liveness analysis:\n");
6156b7a83ff8SRichard Henderson tcg_dump_ops(s, logfile, true);
615778b54858SRichard Henderson fprintf(logfile, "\n");
6158fc59d2d8SRobert Foley qemu_log_unlock(logfile);
6159c896fe29Sbellard }
616078b54858SRichard Henderson }
6161c896fe29Sbellard
616235abb009SRichard Henderson /* Initialize goto_tb jump offsets. */
61633a50f424SRichard Henderson tb->jmp_reset_offset[0] = TB_JMP_OFFSET_INVALID;
61643a50f424SRichard Henderson tb->jmp_reset_offset[1] = TB_JMP_OFFSET_INVALID;
61659da6079bSRichard Henderson tb->jmp_insn_offset[0] = TB_JMP_OFFSET_INVALID;
61669da6079bSRichard Henderson tb->jmp_insn_offset[1] = TB_JMP_OFFSET_INVALID;
616735abb009SRichard Henderson
6168c896fe29Sbellard tcg_reg_alloc_start(s);
6169c896fe29Sbellard
6170db0c51a3SRichard Henderson /*
6171db0c51a3SRichard Henderson * Reset the buffer pointers when restarting after overflow.
6172db0c51a3SRichard Henderson * TODO: Move this into translate-all.c with the rest of the
6173db0c51a3SRichard Henderson * buffer management. Having only this done here is confusing.
6174db0c51a3SRichard Henderson */
6175db0c51a3SRichard Henderson s->code_buf = tcg_splitwx_to_rw(tb->tc.ptr);
6176db0c51a3SRichard Henderson s->code_ptr = s->code_buf;
6177a7cfd751SRichard Henderson s->data_gen_ptr = NULL;
6178c896fe29Sbellard
6179659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
61806001f772SLaurent Vivier QSIMPLEQ_INIT(&s->ldst_labels);
6181659ef5cbSRichard Henderson #endif
618257a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
618357a26946SRichard Henderson s->pool_labels = NULL;
618457a26946SRichard Henderson #endif
61859ecefc84SRichard Henderson
6186747bd69dSRichard Henderson start_words = s->insn_start_words;
6187747bd69dSRichard Henderson s->gen_insn_data =
6188747bd69dSRichard Henderson tcg_malloc(sizeof(uint64_t) * s->gen_tb->icount * start_words);
6189747bd69dSRichard Henderson
61909358fbbfSRichard Henderson tcg_out_tb_start(s);
61919358fbbfSRichard Henderson
6192fca8a500SRichard Henderson num_insns = -1;
619315fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) {
6194c45cb8bbSRichard Henderson TCGOpcode opc = op->opc;
6195b3db8758Sblueswir1
6196c896fe29Sbellard switch (opc) {
6197c896fe29Sbellard case INDEX_op_mov_i32:
6198c896fe29Sbellard case INDEX_op_mov_i64:
6199d2fd745fSRichard Henderson case INDEX_op_mov_vec:
6200dd186292SRichard Henderson tcg_reg_alloc_mov(s, op);
6201c896fe29Sbellard break;
6202bab1671fSRichard Henderson case INDEX_op_dup_vec:
6203bab1671fSRichard Henderson tcg_reg_alloc_dup(s, op);
6204bab1671fSRichard Henderson break;
6205765b842aSRichard Henderson case INDEX_op_insn_start:
6206fca8a500SRichard Henderson if (num_insns >= 0) {
62079f754620SRichard Henderson size_t off = tcg_current_code_size(s);
62089f754620SRichard Henderson s->gen_insn_end_off[num_insns] = off;
62099f754620SRichard Henderson /* Assert that we do not overflow our stored offset. */
62109f754620SRichard Henderson assert(s->gen_insn_end_off[num_insns] == off);
6211fca8a500SRichard Henderson }
6212fca8a500SRichard Henderson num_insns++;
6213747bd69dSRichard Henderson for (i = 0; i < start_words; ++i) {
6214747bd69dSRichard Henderson s->gen_insn_data[num_insns * start_words + i] =
6215c9ad8d27SRichard Henderson tcg_get_insn_start_param(op, i);
6216bad729e2SRichard Henderson }
6217c896fe29Sbellard break;
62185ff9d6a4Sbellard case INDEX_op_discard:
621943439139SRichard Henderson temp_dead(s, arg_temp(op->args[0]));
62205ff9d6a4Sbellard break;
6221c896fe29Sbellard case INDEX_op_set_label:
6222e8996ee0Sbellard tcg_reg_alloc_bb_end(s, s->reserved_regs);
622392ab8e7dSRichard Henderson tcg_out_label(s, arg_label(op->args[0]));
6224c896fe29Sbellard break;
6225c896fe29Sbellard case INDEX_op_call:
6226dd186292SRichard Henderson tcg_reg_alloc_call(s, op);
6227c45cb8bbSRichard Henderson break;
6228b55a8d9dSRichard Henderson case INDEX_op_exit_tb:
6229b55a8d9dSRichard Henderson tcg_out_exit_tb(s, op->args[0]);
6230b55a8d9dSRichard Henderson break;
6231cf7d6b8eSRichard Henderson case INDEX_op_goto_tb:
6232cf7d6b8eSRichard Henderson tcg_out_goto_tb(s, op->args[0]);
6233cf7d6b8eSRichard Henderson break;
6234efe86b21SRichard Henderson case INDEX_op_dup2_vec:
6235efe86b21SRichard Henderson if (tcg_reg_alloc_dup2(s, op)) {
6236efe86b21SRichard Henderson break;
6237efe86b21SRichard Henderson }
6238efe86b21SRichard Henderson /* fall through */
6239c896fe29Sbellard default:
624025c4d9ccSRichard Henderson /* Sanity check that we've not introduced any unhandled opcodes. */
6241be0f34b5SRichard Henderson tcg_debug_assert(tcg_op_supported(opc));
6242c896fe29Sbellard /* Note: in order to speed up the code, it would be much
6243c896fe29Sbellard faster to have specialized register allocator functions for
6244c896fe29Sbellard some common argument patterns */
6245dd186292SRichard Henderson tcg_reg_alloc_op(s, op);
6246c896fe29Sbellard break;
6247c896fe29Sbellard }
6248b125f9dcSRichard Henderson /* Test for (pending) buffer overflow. The assumption is that any
6249b125f9dcSRichard Henderson one operation beginning below the high water mark cannot overrun
6250b125f9dcSRichard Henderson the buffer completely. Thus we can test for overflow after
6251b125f9dcSRichard Henderson generating code without having to check during generation. */
6252644da9b3SJohn Clarke if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) {
6253b125f9dcSRichard Henderson return -1;
6254b125f9dcSRichard Henderson }
62556e6c4efeSRichard Henderson /* Test for TB overflow, as seen by gen_insn_end_off. */
62566e6c4efeSRichard Henderson if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) {
62576e6c4efeSRichard Henderson return -2;
62586e6c4efeSRichard Henderson }
6259c896fe29Sbellard }
6260747bd69dSRichard Henderson tcg_debug_assert(num_insns + 1 == s->gen_tb->icount);
6261fca8a500SRichard Henderson s->gen_insn_end_off[num_insns] = tcg_current_code_size(s);
6262c45cb8bbSRichard Henderson
6263b76f0d8cSYeongkyoon Lee /* Generate TB finalization at the end of block */
6264659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
6265aeee05f5SRichard Henderson i = tcg_out_ldst_finalize(s);
6266aeee05f5SRichard Henderson if (i < 0) {
6267aeee05f5SRichard Henderson return i;
626823dceda6SRichard Henderson }
6269659ef5cbSRichard Henderson #endif
627057a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
62711768987bSRichard Henderson i = tcg_out_pool_finalize(s);
62721768987bSRichard Henderson if (i < 0) {
62731768987bSRichard Henderson return i;
627457a26946SRichard Henderson }
627557a26946SRichard Henderson #endif
62767ecd02a0SRichard Henderson if (!tcg_resolve_relocs(s)) {
62777ecd02a0SRichard Henderson return -2;
62787ecd02a0SRichard Henderson }
6279c896fe29Sbellard
6280df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
6281c896fe29Sbellard /* flush instruction cache */
6282db0c51a3SRichard Henderson flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf),
6283db0c51a3SRichard Henderson (uintptr_t)s->code_buf,
62841da8de39SRichard Henderson tcg_ptr_byte_diff(s->code_ptr, s->code_buf));
6285df5d2b16SRichard Henderson #endif
62862aeabc08SStefan Weil
62871813e175SRichard Henderson return tcg_current_code_size(s);
6288c896fe29Sbellard }
6289c896fe29Sbellard
6290813da627SRichard Henderson #ifdef ELF_HOST_MACHINE
62915872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things:
62925872bbf2SRichard Henderson
62935872bbf2SRichard Henderson (1) Define ELF_HOST_MACHINE to indicate both what value to
62945872bbf2SRichard Henderson put into the ELF image and to indicate support for the feature.
62955872bbf2SRichard Henderson
62965872bbf2SRichard Henderson (2) Define tcg_register_jit. This should create a buffer containing
62975872bbf2SRichard Henderson the contents of a .debug_frame section that describes the post-
62985872bbf2SRichard Henderson prologue unwind info for the tcg machine.
62995872bbf2SRichard Henderson
63005872bbf2SRichard Henderson (3) Call tcg_register_jit_int, with the constructed .debug_frame.
63015872bbf2SRichard Henderson */
6302813da627SRichard Henderson
6303813da627SRichard Henderson /* Begin GDB interface. THE FOLLOWING MUST MATCH GDB DOCS. */
6304813da627SRichard Henderson typedef enum {
6305813da627SRichard Henderson JIT_NOACTION = 0,
6306813da627SRichard Henderson JIT_REGISTER_FN,
6307813da627SRichard Henderson JIT_UNREGISTER_FN
6308813da627SRichard Henderson } jit_actions_t;
6309813da627SRichard Henderson
6310813da627SRichard Henderson struct jit_code_entry {
6311813da627SRichard Henderson struct jit_code_entry *next_entry;
6312813da627SRichard Henderson struct jit_code_entry *prev_entry;
6313813da627SRichard Henderson const void *symfile_addr;
6314813da627SRichard Henderson uint64_t symfile_size;
6315813da627SRichard Henderson };
6316813da627SRichard Henderson
6317813da627SRichard Henderson struct jit_descriptor {
6318813da627SRichard Henderson uint32_t version;
6319813da627SRichard Henderson uint32_t action_flag;
6320813da627SRichard Henderson struct jit_code_entry *relevant_entry;
6321813da627SRichard Henderson struct jit_code_entry *first_entry;
6322813da627SRichard Henderson };
6323813da627SRichard Henderson
6324813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline));
__jit_debug_register_code(void)6325813da627SRichard Henderson void __jit_debug_register_code(void)
6326813da627SRichard Henderson {
6327813da627SRichard Henderson asm("");
6328813da627SRichard Henderson }
6329813da627SRichard Henderson
6330813da627SRichard Henderson /* Must statically initialize the version, because GDB may check
6331813da627SRichard Henderson the version before we can set it. */
6332813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
6333813da627SRichard Henderson
6334813da627SRichard Henderson /* End GDB interface. */
6335813da627SRichard Henderson
find_string(const char * strtab,const char * str)6336813da627SRichard Henderson static int find_string(const char *strtab, const char *str)
6337813da627SRichard Henderson {
6338813da627SRichard Henderson const char *p = strtab + 1;
6339813da627SRichard Henderson
6340813da627SRichard Henderson while (1) {
6341813da627SRichard Henderson if (strcmp(p, str) == 0) {
6342813da627SRichard Henderson return p - strtab;
6343813da627SRichard Henderson }
6344813da627SRichard Henderson p += strlen(p) + 1;
6345813da627SRichard Henderson }
6346813da627SRichard Henderson }
6347813da627SRichard Henderson
tcg_register_jit_int(const void * buf_ptr,size_t buf_size,const void * debug_frame,size_t debug_frame_size)6348755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf_ptr, size_t buf_size,
63492c90784aSRichard Henderson const void *debug_frame,
63502c90784aSRichard Henderson size_t debug_frame_size)
6351813da627SRichard Henderson {
63525872bbf2SRichard Henderson struct __attribute__((packed)) DebugInfo {
63535872bbf2SRichard Henderson uint32_t len;
63545872bbf2SRichard Henderson uint16_t version;
63555872bbf2SRichard Henderson uint32_t abbrev;
63565872bbf2SRichard Henderson uint8_t ptr_size;
63575872bbf2SRichard Henderson uint8_t cu_die;
63585872bbf2SRichard Henderson uint16_t cu_lang;
63595872bbf2SRichard Henderson uintptr_t cu_low_pc;
63605872bbf2SRichard Henderson uintptr_t cu_high_pc;
63615872bbf2SRichard Henderson uint8_t fn_die;
63625872bbf2SRichard Henderson char fn_name[16];
63635872bbf2SRichard Henderson uintptr_t fn_low_pc;
63645872bbf2SRichard Henderson uintptr_t fn_high_pc;
63655872bbf2SRichard Henderson uint8_t cu_eoc;
63665872bbf2SRichard Henderson };
6367813da627SRichard Henderson
6368813da627SRichard Henderson struct ElfImage {
6369813da627SRichard Henderson ElfW(Ehdr) ehdr;
6370813da627SRichard Henderson ElfW(Phdr) phdr;
63715872bbf2SRichard Henderson ElfW(Shdr) shdr[7];
63725872bbf2SRichard Henderson ElfW(Sym) sym[2];
63735872bbf2SRichard Henderson struct DebugInfo di;
63745872bbf2SRichard Henderson uint8_t da[24];
63755872bbf2SRichard Henderson char str[80];
63765872bbf2SRichard Henderson };
63775872bbf2SRichard Henderson
63785872bbf2SRichard Henderson struct ElfImage *img;
63795872bbf2SRichard Henderson
63805872bbf2SRichard Henderson static const struct ElfImage img_template = {
63815872bbf2SRichard Henderson .ehdr = {
63825872bbf2SRichard Henderson .e_ident[EI_MAG0] = ELFMAG0,
63835872bbf2SRichard Henderson .e_ident[EI_MAG1] = ELFMAG1,
63845872bbf2SRichard Henderson .e_ident[EI_MAG2] = ELFMAG2,
63855872bbf2SRichard Henderson .e_ident[EI_MAG3] = ELFMAG3,
63865872bbf2SRichard Henderson .e_ident[EI_CLASS] = ELF_CLASS,
63875872bbf2SRichard Henderson .e_ident[EI_DATA] = ELF_DATA,
63885872bbf2SRichard Henderson .e_ident[EI_VERSION] = EV_CURRENT,
63895872bbf2SRichard Henderson .e_type = ET_EXEC,
63905872bbf2SRichard Henderson .e_machine = ELF_HOST_MACHINE,
63915872bbf2SRichard Henderson .e_version = EV_CURRENT,
63925872bbf2SRichard Henderson .e_phoff = offsetof(struct ElfImage, phdr),
63935872bbf2SRichard Henderson .e_shoff = offsetof(struct ElfImage, shdr),
63945872bbf2SRichard Henderson .e_ehsize = sizeof(ElfW(Shdr)),
63955872bbf2SRichard Henderson .e_phentsize = sizeof(ElfW(Phdr)),
63965872bbf2SRichard Henderson .e_phnum = 1,
63975872bbf2SRichard Henderson .e_shentsize = sizeof(ElfW(Shdr)),
63985872bbf2SRichard Henderson .e_shnum = ARRAY_SIZE(img->shdr),
63995872bbf2SRichard Henderson .e_shstrndx = ARRAY_SIZE(img->shdr) - 1,
6400abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS
6401abbb3eaeSRichard Henderson .e_flags = ELF_HOST_FLAGS,
6402abbb3eaeSRichard Henderson #endif
6403abbb3eaeSRichard Henderson #ifdef ELF_OSABI
6404abbb3eaeSRichard Henderson .e_ident[EI_OSABI] = ELF_OSABI,
6405abbb3eaeSRichard Henderson #endif
64065872bbf2SRichard Henderson },
64075872bbf2SRichard Henderson .phdr = {
64085872bbf2SRichard Henderson .p_type = PT_LOAD,
64095872bbf2SRichard Henderson .p_flags = PF_X,
64105872bbf2SRichard Henderson },
64115872bbf2SRichard Henderson .shdr = {
64125872bbf2SRichard Henderson [0] = { .sh_type = SHT_NULL },
64135872bbf2SRichard Henderson /* Trick: The contents of code_gen_buffer are not present in
64145872bbf2SRichard Henderson this fake ELF file; that got allocated elsewhere. Therefore
64155872bbf2SRichard Henderson we mark .text as SHT_NOBITS (similar to .bss) so that readers
64165872bbf2SRichard Henderson will not look for contents. We can record any address. */
64175872bbf2SRichard Henderson [1] = { /* .text */
64185872bbf2SRichard Henderson .sh_type = SHT_NOBITS,
64195872bbf2SRichard Henderson .sh_flags = SHF_EXECINSTR | SHF_ALLOC,
64205872bbf2SRichard Henderson },
64215872bbf2SRichard Henderson [2] = { /* .debug_info */
64225872bbf2SRichard Henderson .sh_type = SHT_PROGBITS,
64235872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, di),
64245872bbf2SRichard Henderson .sh_size = sizeof(struct DebugInfo),
64255872bbf2SRichard Henderson },
64265872bbf2SRichard Henderson [3] = { /* .debug_abbrev */
64275872bbf2SRichard Henderson .sh_type = SHT_PROGBITS,
64285872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, da),
64295872bbf2SRichard Henderson .sh_size = sizeof(img->da),
64305872bbf2SRichard Henderson },
64315872bbf2SRichard Henderson [4] = { /* .debug_frame */
64325872bbf2SRichard Henderson .sh_type = SHT_PROGBITS,
64335872bbf2SRichard Henderson .sh_offset = sizeof(struct ElfImage),
64345872bbf2SRichard Henderson },
64355872bbf2SRichard Henderson [5] = { /* .symtab */
64365872bbf2SRichard Henderson .sh_type = SHT_SYMTAB,
64375872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, sym),
64385872bbf2SRichard Henderson .sh_size = sizeof(img->sym),
64395872bbf2SRichard Henderson .sh_info = 1,
64405872bbf2SRichard Henderson .sh_link = ARRAY_SIZE(img->shdr) - 1,
64415872bbf2SRichard Henderson .sh_entsize = sizeof(ElfW(Sym)),
64425872bbf2SRichard Henderson },
64435872bbf2SRichard Henderson [6] = { /* .strtab */
64445872bbf2SRichard Henderson .sh_type = SHT_STRTAB,
64455872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, str),
64465872bbf2SRichard Henderson .sh_size = sizeof(img->str),
64475872bbf2SRichard Henderson }
64485872bbf2SRichard Henderson },
64495872bbf2SRichard Henderson .sym = {
64505872bbf2SRichard Henderson [1] = { /* code_gen_buffer */
64515872bbf2SRichard Henderson .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC),
64525872bbf2SRichard Henderson .st_shndx = 1,
64535872bbf2SRichard Henderson }
64545872bbf2SRichard Henderson },
64555872bbf2SRichard Henderson .di = {
64565872bbf2SRichard Henderson .len = sizeof(struct DebugInfo) - 4,
64575872bbf2SRichard Henderson .version = 2,
64585872bbf2SRichard Henderson .ptr_size = sizeof(void *),
64595872bbf2SRichard Henderson .cu_die = 1,
64605872bbf2SRichard Henderson .cu_lang = 0x8001, /* DW_LANG_Mips_Assembler */
64615872bbf2SRichard Henderson .fn_die = 2,
64625872bbf2SRichard Henderson .fn_name = "code_gen_buffer"
64635872bbf2SRichard Henderson },
64645872bbf2SRichard Henderson .da = {
64655872bbf2SRichard Henderson 1, /* abbrev number (the cu) */
64665872bbf2SRichard Henderson 0x11, 1, /* DW_TAG_compile_unit, has children */
64675872bbf2SRichard Henderson 0x13, 0x5, /* DW_AT_language, DW_FORM_data2 */
64685872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */
64695872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */
64705872bbf2SRichard Henderson 0, 0, /* end of abbrev */
64715872bbf2SRichard Henderson 2, /* abbrev number (the fn) */
64725872bbf2SRichard Henderson 0x2e, 0, /* DW_TAG_subprogram, no children */
64735872bbf2SRichard Henderson 0x3, 0x8, /* DW_AT_name, DW_FORM_string */
64745872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */
64755872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */
64765872bbf2SRichard Henderson 0, 0, /* end of abbrev */
64775872bbf2SRichard Henderson 0 /* no more abbrev */
64785872bbf2SRichard Henderson },
64795872bbf2SRichard Henderson .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0"
64805872bbf2SRichard Henderson ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer",
6481813da627SRichard Henderson };
6482813da627SRichard Henderson
6483813da627SRichard Henderson /* We only need a single jit entry; statically allocate it. */
6484813da627SRichard Henderson static struct jit_code_entry one_entry;
6485813da627SRichard Henderson
64865872bbf2SRichard Henderson uintptr_t buf = (uintptr_t)buf_ptr;
6487813da627SRichard Henderson size_t img_size = sizeof(struct ElfImage) + debug_frame_size;
64882c90784aSRichard Henderson DebugFrameHeader *dfh;
6489813da627SRichard Henderson
64905872bbf2SRichard Henderson img = g_malloc(img_size);
64915872bbf2SRichard Henderson *img = img_template;
6492813da627SRichard Henderson
64935872bbf2SRichard Henderson img->phdr.p_vaddr = buf;
64945872bbf2SRichard Henderson img->phdr.p_paddr = buf;
64955872bbf2SRichard Henderson img->phdr.p_memsz = buf_size;
6496813da627SRichard Henderson
64975872bbf2SRichard Henderson img->shdr[1].sh_name = find_string(img->str, ".text");
64985872bbf2SRichard Henderson img->shdr[1].sh_addr = buf;
64995872bbf2SRichard Henderson img->shdr[1].sh_size = buf_size;
6500813da627SRichard Henderson
65015872bbf2SRichard Henderson img->shdr[2].sh_name = find_string(img->str, ".debug_info");
65025872bbf2SRichard Henderson img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev");
65035872bbf2SRichard Henderson
65045872bbf2SRichard Henderson img->shdr[4].sh_name = find_string(img->str, ".debug_frame");
65055872bbf2SRichard Henderson img->shdr[4].sh_size = debug_frame_size;
65065872bbf2SRichard Henderson
65075872bbf2SRichard Henderson img->shdr[5].sh_name = find_string(img->str, ".symtab");
65085872bbf2SRichard Henderson img->shdr[6].sh_name = find_string(img->str, ".strtab");
65095872bbf2SRichard Henderson
65105872bbf2SRichard Henderson img->sym[1].st_name = find_string(img->str, "code_gen_buffer");
65115872bbf2SRichard Henderson img->sym[1].st_value = buf;
65125872bbf2SRichard Henderson img->sym[1].st_size = buf_size;
65135872bbf2SRichard Henderson
65145872bbf2SRichard Henderson img->di.cu_low_pc = buf;
651545aba097SRichard Henderson img->di.cu_high_pc = buf + buf_size;
65165872bbf2SRichard Henderson img->di.fn_low_pc = buf;
651745aba097SRichard Henderson img->di.fn_high_pc = buf + buf_size;
6518813da627SRichard Henderson
65192c90784aSRichard Henderson dfh = (DebugFrameHeader *)(img + 1);
65202c90784aSRichard Henderson memcpy(dfh, debug_frame, debug_frame_size);
65212c90784aSRichard Henderson dfh->fde.func_start = buf;
65222c90784aSRichard Henderson dfh->fde.func_len = buf_size;
65232c90784aSRichard Henderson
6524813da627SRichard Henderson #ifdef DEBUG_JIT
6525813da627SRichard Henderson /* Enable this block to be able to debug the ELF image file creation.
6526813da627SRichard Henderson One can use readelf, objdump, or other inspection utilities. */
6527813da627SRichard Henderson {
6528eb6b2edfSBin Meng g_autofree char *jit = g_strdup_printf("%s/qemu.jit", g_get_tmp_dir());
6529eb6b2edfSBin Meng FILE *f = fopen(jit, "w+b");
6530813da627SRichard Henderson if (f) {
65315872bbf2SRichard Henderson if (fwrite(img, img_size, 1, f) != img_size) {
6532813da627SRichard Henderson /* Avoid stupid unused return value warning for fwrite. */
6533813da627SRichard Henderson }
6534813da627SRichard Henderson fclose(f);
6535813da627SRichard Henderson }
6536813da627SRichard Henderson }
6537813da627SRichard Henderson #endif
6538813da627SRichard Henderson
6539813da627SRichard Henderson one_entry.symfile_addr = img;
6540813da627SRichard Henderson one_entry.symfile_size = img_size;
6541813da627SRichard Henderson
6542813da627SRichard Henderson __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
6543813da627SRichard Henderson __jit_debug_descriptor.relevant_entry = &one_entry;
6544813da627SRichard Henderson __jit_debug_descriptor.first_entry = &one_entry;
6545813da627SRichard Henderson __jit_debug_register_code();
6546813da627SRichard Henderson }
6547813da627SRichard Henderson #else
65485872bbf2SRichard Henderson /* No support for the feature. Provide the entry point expected by exec.c,
65495872bbf2SRichard Henderson and implement the internal function we declared earlier. */
6550813da627SRichard Henderson
tcg_register_jit_int(const void * buf,size_t size,const void * debug_frame,size_t debug_frame_size)6551755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size,
65522c90784aSRichard Henderson const void *debug_frame,
65532c90784aSRichard Henderson size_t debug_frame_size)
6554813da627SRichard Henderson {
6555813da627SRichard Henderson }
6556813da627SRichard Henderson
tcg_register_jit(const void * buf,size_t buf_size)6557755bf9e5SRichard Henderson void tcg_register_jit(const void *buf, size_t buf_size)
6558813da627SRichard Henderson {
6559813da627SRichard Henderson }
6560813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */
6561db432672SRichard Henderson
6562db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec
tcg_expand_vec_op(TCGOpcode o,TCGType t,unsigned e,TCGArg a0,...)6563db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...)
6564db432672SRichard Henderson {
6565db432672SRichard Henderson g_assert_not_reached();
6566db432672SRichard Henderson }
6567db432672SRichard Henderson #endif
6568