xref: /qemu/tcg/tcg.c (revision 4e350091a2b87070967c85f9caeefeb85c4d2e8d)
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"
5993280b67SRichard Henderson #include "tcg-has.h"
607d478306SRichard Henderson #ifdef CONFIG_USER_ONLY
61d3cbde74SPhilippe Mathieu-Daudé #include "user/guest-base.h"
627d478306SRichard Henderson #endif
63c896fe29Sbellard 
64139c1837SPaolo Bonzini /* Forward declarations for functions declared in tcg-target.c.inc and
65ce151109SPeter Maydell    used here. */
66e4d58b41SRichard Henderson static void tcg_target_init(TCGContext *s);
67e4d58b41SRichard Henderson static void tcg_target_qemu_prologue(TCGContext *s);
686ac17786SRichard Henderson static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
692ba7fae2SRichard Henderson                         intptr_t value, intptr_t addend);
70a417ef83SRichard Henderson static void tcg_out_nop_fill(tcg_insn_unit *p, int count);
71a417ef83SRichard Henderson 
72a417ef83SRichard Henderson typedef struct TCGLabelQemuLdst TCGLabelQemuLdst;
73a417ef83SRichard Henderson static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l);
74a417ef83SRichard Henderson static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l);
75c896fe29Sbellard 
76497a22ebSRichard Henderson /* The CIE and FDE header definitions will be common to all hosts.  */
77497a22ebSRichard Henderson typedef struct {
78497a22ebSRichard Henderson     uint32_t len __attribute__((aligned((sizeof(void *)))));
79497a22ebSRichard Henderson     uint32_t id;
80497a22ebSRichard Henderson     uint8_t version;
81497a22ebSRichard Henderson     char augmentation[1];
82497a22ebSRichard Henderson     uint8_t code_align;
83497a22ebSRichard Henderson     uint8_t data_align;
84497a22ebSRichard Henderson     uint8_t return_column;
85497a22ebSRichard Henderson } DebugFrameCIE;
86497a22ebSRichard Henderson 
87497a22ebSRichard Henderson typedef struct QEMU_PACKED {
88497a22ebSRichard Henderson     uint32_t len __attribute__((aligned((sizeof(void *)))));
89497a22ebSRichard Henderson     uint32_t cie_offset;
90edee2579SRichard Henderson     uintptr_t func_start;
91edee2579SRichard Henderson     uintptr_t func_len;
92497a22ebSRichard Henderson } DebugFrameFDEHeader;
93497a22ebSRichard Henderson 
942c90784aSRichard Henderson typedef struct QEMU_PACKED {
952c90784aSRichard Henderson     DebugFrameCIE cie;
962c90784aSRichard Henderson     DebugFrameFDEHeader fde;
972c90784aSRichard Henderson } DebugFrameHeader;
982c90784aSRichard Henderson 
99a417ef83SRichard Henderson struct TCGLabelQemuLdst {
1002528f771SRichard Henderson     bool is_ld;             /* qemu_ld: true, qemu_st: false */
1012528f771SRichard Henderson     MemOpIdx oi;
1022528f771SRichard Henderson     TCGType type;           /* result type of a load */
1032528f771SRichard Henderson     TCGReg addrlo_reg;      /* reg index for low word of guest virtual addr */
1042528f771SRichard Henderson     TCGReg addrhi_reg;      /* reg index for high word of guest virtual addr */
1052528f771SRichard Henderson     TCGReg datalo_reg;      /* reg index for low word to be loaded or stored */
1062528f771SRichard Henderson     TCGReg datahi_reg;      /* reg index for high word to be loaded or stored */
1072528f771SRichard Henderson     const tcg_insn_unit *raddr;   /* addr of the next IR of qemu_ld/st IR */
1082528f771SRichard Henderson     tcg_insn_unit *label_ptr[2]; /* label pointers to be updated */
1092528f771SRichard Henderson     QSIMPLEQ_ENTRY(TCGLabelQemuLdst) next;
110a417ef83SRichard Henderson };
1112528f771SRichard Henderson 
112755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size,
1132c90784aSRichard Henderson                                  const void *debug_frame,
1142c90784aSRichard Henderson                                  size_t debug_frame_size)
115813da627SRichard Henderson     __attribute__((unused));
116813da627SRichard Henderson 
117139c1837SPaolo Bonzini /* Forward declarations for functions declared and used in tcg-target.c.inc. */
1189358fbbfSRichard Henderson static void tcg_out_tb_start(TCGContext *s);
1192a534affSRichard Henderson static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
120a05b5b9bSRichard Henderson                        intptr_t arg2);
12178113e83SRichard Henderson static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
122c0ad3001SStefan Weil static void tcg_out_movi(TCGContext *s, TCGType type,
1232a534affSRichard Henderson                          TCGReg ret, tcg_target_long arg);
124678155b2SRichard Henderson static void tcg_out_ext8s(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
125753e42eaSRichard Henderson static void tcg_out_ext16s(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
126d0e66c89SRichard Henderson static void tcg_out_ext8u(TCGContext *s, TCGReg ret, TCGReg arg);
127379afdffSRichard Henderson static void tcg_out_ext16u(TCGContext *s, TCGReg ret, TCGReg arg);
12852bf3398SRichard Henderson static void tcg_out_ext32s(TCGContext *s, TCGReg ret, TCGReg arg);
1299ecf5f61SRichard Henderson static void tcg_out_ext32u(TCGContext *s, TCGReg ret, TCGReg arg);
1309c6aa274SRichard Henderson static void tcg_out_exts_i32_i64(TCGContext *s, TCGReg ret, TCGReg arg);
131b9bfe000SRichard Henderson static void tcg_out_extu_i32_i64(TCGContext *s, TCGReg ret, TCGReg arg);
132b8b94ac6SRichard Henderson static void tcg_out_extrl_i64_i32(TCGContext *s, TCGReg ret, TCGReg arg);
133313bdea8SRichard Henderson static void tcg_out_addi_ptr(TCGContext *s, TCGReg, TCGReg, tcg_target_long);
134129f1f9eSRichard Henderson static bool tcg_out_xchg(TCGContext *s, TCGType type, TCGReg r1, TCGReg r2);
135b55a8d9dSRichard Henderson static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg);
136cf7d6b8eSRichard Henderson static void tcg_out_goto_tb(TCGContext *s, int which);
137*4e350091SRichard Henderson static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type,
1385e8892dbSMiroslav Rezanina                        const TCGArg args[TCG_MAX_OP_ARGS],
1395e8892dbSMiroslav Rezanina                        const int const_args[TCG_MAX_OP_ARGS]);
140d2fd745fSRichard Henderson #if TCG_TARGET_MAYBE_vec
141e7632cfaSRichard Henderson static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
142e7632cfaSRichard Henderson                             TCGReg dst, TCGReg src);
143d6ecb4a9SRichard Henderson static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
144d6ecb4a9SRichard Henderson                              TCGReg dst, TCGReg base, intptr_t offset);
1454e186175SRichard Henderson static void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece,
1464e186175SRichard Henderson                              TCGReg dst, int64_t arg);
1475e8892dbSMiroslav Rezanina static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
1485e8892dbSMiroslav Rezanina                            unsigned vecl, unsigned vece,
1495e8892dbSMiroslav Rezanina                            const TCGArg args[TCG_MAX_OP_ARGS],
1505e8892dbSMiroslav Rezanina                            const int const_args[TCG_MAX_OP_ARGS]);
151d2fd745fSRichard Henderson #else
152e7632cfaSRichard Henderson static inline bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
153e7632cfaSRichard Henderson                                    TCGReg dst, TCGReg src)
154e7632cfaSRichard Henderson {
155e7632cfaSRichard Henderson     g_assert_not_reached();
156e7632cfaSRichard Henderson }
157d6ecb4a9SRichard Henderson static inline bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
158d6ecb4a9SRichard Henderson                                     TCGReg dst, TCGReg base, intptr_t offset)
159d6ecb4a9SRichard Henderson {
160d6ecb4a9SRichard Henderson     g_assert_not_reached();
161d6ecb4a9SRichard Henderson }
1624e186175SRichard Henderson static inline void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece,
1634e186175SRichard Henderson                                     TCGReg dst, int64_t arg)
164e7632cfaSRichard Henderson {
165e7632cfaSRichard Henderson     g_assert_not_reached();
166e7632cfaSRichard Henderson }
1675e8892dbSMiroslav Rezanina static inline void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
1685e8892dbSMiroslav Rezanina                                   unsigned vecl, unsigned vece,
1695e8892dbSMiroslav Rezanina                                   const TCGArg args[TCG_MAX_OP_ARGS],
1705e8892dbSMiroslav Rezanina                                   const int const_args[TCG_MAX_OP_ARGS])
171d2fd745fSRichard Henderson {
172d2fd745fSRichard Henderson     g_assert_not_reached();
173d2fd745fSRichard Henderson }
1747d3e705aSRichard Henderson int tcg_can_emit_vec_op(TCGOpcode o, TCGType t, unsigned ve)
1757d3e705aSRichard Henderson {
1767d3e705aSRichard Henderson     return 0;
1777d3e705aSRichard Henderson }
178d2fd745fSRichard Henderson #endif
1792a534affSRichard Henderson static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
180a05b5b9bSRichard Henderson                        intptr_t arg2);
18159d7c14eSRichard Henderson static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
18259d7c14eSRichard Henderson                         TCGReg base, intptr_t ofs);
1837b7d8b2dSRichard Henderson static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target,
184cee44b03SRichard Henderson                          const TCGHelperInfo *info);
1855e3d0c19SRichard Henderson static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot);
18621e9a8aeSRichard Henderson static bool tcg_target_const_match(int64_t val, int ct,
18721e9a8aeSRichard Henderson                                    TCGType type, TCGCond cond, int vece);
188c896fe29Sbellard 
18923088ca0SRichard Henderson #ifndef CONFIG_USER_ONLY
19023088ca0SRichard Henderson #define guest_base  ({ qemu_build_not_reached(); (uintptr_t)0; })
19123088ca0SRichard Henderson #endif
19223088ca0SRichard Henderson 
1938429a1caSRichard Henderson typedef struct TCGLdstHelperParam {
1948429a1caSRichard Henderson     TCGReg (*ra_gen)(TCGContext *s, const TCGLabelQemuLdst *l, int arg_reg);
1958429a1caSRichard Henderson     unsigned ntmp;
1968429a1caSRichard Henderson     int tmp[3];
1978429a1caSRichard Henderson } TCGLdstHelperParam;
1988429a1caSRichard Henderson 
1998429a1caSRichard Henderson static void tcg_out_ld_helper_args(TCGContext *s, const TCGLabelQemuLdst *l,
2008429a1caSRichard Henderson                                    const TCGLdstHelperParam *p)
2018429a1caSRichard Henderson     __attribute__((unused));
2028429a1caSRichard Henderson static void tcg_out_ld_helper_ret(TCGContext *s, const TCGLabelQemuLdst *l,
2038429a1caSRichard Henderson                                   bool load_sign, const TCGLdstHelperParam *p)
2048429a1caSRichard Henderson     __attribute__((unused));
2058429a1caSRichard Henderson static void tcg_out_st_helper_args(TCGContext *s, const TCGLabelQemuLdst *l,
2068429a1caSRichard Henderson                                    const TCGLdstHelperParam *p)
2078429a1caSRichard Henderson     __attribute__((unused));
2088429a1caSRichard Henderson 
209de95016dSRichard Henderson static void * const qemu_ld_helpers[MO_SSIZE + 1] __attribute__((unused)) = {
2100cadc1edSRichard Henderson     [MO_UB] = helper_ldub_mmu,
2110cadc1edSRichard Henderson     [MO_SB] = helper_ldsb_mmu,
2120cadc1edSRichard Henderson     [MO_UW] = helper_lduw_mmu,
2130cadc1edSRichard Henderson     [MO_SW] = helper_ldsw_mmu,
2140cadc1edSRichard Henderson     [MO_UL] = helper_ldul_mmu,
2150cadc1edSRichard Henderson     [MO_UQ] = helper_ldq_mmu,
2160cadc1edSRichard Henderson #if TCG_TARGET_REG_BITS == 64
2170cadc1edSRichard Henderson     [MO_SL] = helper_ldsl_mmu,
218ebebea53SRichard Henderson     [MO_128] = helper_ld16_mmu,
2190cadc1edSRichard Henderson #endif
2200cadc1edSRichard Henderson };
2210cadc1edSRichard Henderson 
222de95016dSRichard Henderson static void * const qemu_st_helpers[MO_SIZE + 1] __attribute__((unused)) = {
2230cadc1edSRichard Henderson     [MO_8]  = helper_stb_mmu,
2240cadc1edSRichard Henderson     [MO_16] = helper_stw_mmu,
2250cadc1edSRichard Henderson     [MO_32] = helper_stl_mmu,
2260cadc1edSRichard Henderson     [MO_64] = helper_stq_mmu,
227ebebea53SRichard Henderson #if TCG_TARGET_REG_BITS == 64
228ebebea53SRichard Henderson     [MO_128] = helper_st16_mmu,
229ebebea53SRichard Henderson #endif
2300cadc1edSRichard Henderson };
2310cadc1edSRichard Henderson 
232e63b8a29SRichard Henderson typedef struct {
233e63b8a29SRichard Henderson     MemOp atom;   /* lg2 bits of atomicity required */
234e63b8a29SRichard Henderson     MemOp align;  /* lg2 bits of alignment to use */
235e63b8a29SRichard Henderson } TCGAtomAlign;
236e63b8a29SRichard Henderson 
237e63b8a29SRichard Henderson static TCGAtomAlign atom_and_align_for_opc(TCGContext *s, MemOp opc,
238e63b8a29SRichard Henderson                                            MemOp host_atom, bool allow_two_ops)
239e63b8a29SRichard Henderson     __attribute__((unused));
240e63b8a29SRichard Henderson 
241397cabaaSRichard Henderson #ifdef CONFIG_USER_ONLY
242397cabaaSRichard Henderson bool tcg_use_softmmu;
243397cabaaSRichard Henderson #endif
244397cabaaSRichard Henderson 
24542eb6dfcSRichard Henderson TCGContext tcg_init_ctx;
24642eb6dfcSRichard Henderson __thread TCGContext *tcg_ctx;
24742eb6dfcSRichard Henderson 
2485ff7258cSRichard Henderson TCGContext **tcg_ctxs;
2490e2d61cfSRichard Henderson unsigned int tcg_cur_ctxs;
2500e2d61cfSRichard Henderson unsigned int tcg_max_ctxs;
251ad75a51eSRichard Henderson TCGv_env tcg_env;
252c8bc1168SRichard Henderson const void *tcg_code_gen_epilogue;
253db0c51a3SRichard Henderson uintptr_t tcg_splitwx_diff;
254df2cce29SEmilio G. Cota 
255b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
256b91ccb31SRichard Henderson tcg_prologue_fn *tcg_qemu_tb_exec;
257b91ccb31SRichard Henderson #endif
258b91ccb31SRichard Henderson 
259d2fd745fSRichard Henderson static TCGRegSet tcg_target_available_regs[TCG_TYPE_COUNT];
260b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs;
261c896fe29Sbellard 
2621813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1
2634196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v)
264c896fe29Sbellard {
265c896fe29Sbellard     *s->code_ptr++ = v;
266c896fe29Sbellard }
267c896fe29Sbellard 
2684196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p,
2694196dca6SPeter Maydell                                                       uint8_t v)
2705c53bb81SPeter Maydell {
2711813e175SRichard Henderson     *p = v;
2725c53bb81SPeter Maydell }
2731813e175SRichard Henderson #endif
2745c53bb81SPeter Maydell 
2751813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2
2764196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v)
277c896fe29Sbellard {
2781813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
2791813e175SRichard Henderson         *s->code_ptr++ = v;
2801813e175SRichard Henderson     } else {
2811813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2824387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2831813e175SRichard Henderson         s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE);
2841813e175SRichard Henderson     }
285c896fe29Sbellard }
286c896fe29Sbellard 
2874196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p,
2884196dca6SPeter Maydell                                                        uint16_t v)
2895c53bb81SPeter Maydell {
2901813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
2911813e175SRichard Henderson         *p = v;
2921813e175SRichard Henderson     } else {
2935c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2945c53bb81SPeter Maydell     }
2951813e175SRichard Henderson }
2961813e175SRichard Henderson #endif
2975c53bb81SPeter Maydell 
2981813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4
2994196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v)
300c896fe29Sbellard {
3011813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
3021813e175SRichard Henderson         *s->code_ptr++ = v;
3031813e175SRichard Henderson     } else {
3041813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
3054387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
3061813e175SRichard Henderson         s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE);
3071813e175SRichard Henderson     }
308c896fe29Sbellard }
309c896fe29Sbellard 
3104196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p,
3114196dca6SPeter Maydell                                                        uint32_t v)
3125c53bb81SPeter Maydell {
3131813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
3141813e175SRichard Henderson         *p = v;
3151813e175SRichard Henderson     } else {
3165c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
3175c53bb81SPeter Maydell     }
3181813e175SRichard Henderson }
3191813e175SRichard Henderson #endif
3205c53bb81SPeter Maydell 
3211813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 8
3224196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v)
323ac26eb69SRichard Henderson {
3241813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
3251813e175SRichard Henderson         *s->code_ptr++ = v;
3261813e175SRichard Henderson     } else {
3271813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
3284387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
3291813e175SRichard Henderson         s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE);
3301813e175SRichard Henderson     }
331ac26eb69SRichard Henderson }
332ac26eb69SRichard Henderson 
3334196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p,
3344196dca6SPeter Maydell                                                        uint64_t v)
3355c53bb81SPeter Maydell {
3361813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
3371813e175SRichard Henderson         *p = v;
3381813e175SRichard Henderson     } else {
3395c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
3405c53bb81SPeter Maydell     }
3411813e175SRichard Henderson }
3421813e175SRichard Henderson #endif
3435c53bb81SPeter Maydell 
344c896fe29Sbellard /* label relocation processing */
345c896fe29Sbellard 
3461813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
347bec16311SRichard Henderson                           TCGLabel *l, intptr_t addend)
348c896fe29Sbellard {
3497ecd02a0SRichard Henderson     TCGRelocation *r = tcg_malloc(sizeof(TCGRelocation));
350c896fe29Sbellard 
351c896fe29Sbellard     r->type = type;
352c896fe29Sbellard     r->ptr = code_ptr;
353c896fe29Sbellard     r->addend = addend;
3547ecd02a0SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next);
355c896fe29Sbellard }
356c896fe29Sbellard 
35792ab8e7dSRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l)
358c896fe29Sbellard {
359eabb7b91SAurelien Jarno     tcg_debug_assert(!l->has_value);
360c896fe29Sbellard     l->has_value = 1;
36192ab8e7dSRichard Henderson     l->u.value_ptr = tcg_splitwx_to_rx(s->code_ptr);
362c896fe29Sbellard }
363c896fe29Sbellard 
36442a268c2SRichard Henderson TCGLabel *gen_new_label(void)
365c896fe29Sbellard {
366b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
36751e3972cSRichard Henderson     TCGLabel *l = tcg_malloc(sizeof(TCGLabel));
368c896fe29Sbellard 
3697ecd02a0SRichard Henderson     memset(l, 0, sizeof(TCGLabel));
3707ecd02a0SRichard Henderson     l->id = s->nb_labels++;
371f85b1fc4SRichard Henderson     QSIMPLEQ_INIT(&l->branches);
3727ecd02a0SRichard Henderson     QSIMPLEQ_INIT(&l->relocs);
3737ecd02a0SRichard Henderson 
374bef16ab4SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&s->labels, l, next);
37542a268c2SRichard Henderson 
37642a268c2SRichard Henderson     return l;
377c896fe29Sbellard }
378c896fe29Sbellard 
3797ecd02a0SRichard Henderson static bool tcg_resolve_relocs(TCGContext *s)
3807ecd02a0SRichard Henderson {
3817ecd02a0SRichard Henderson     TCGLabel *l;
3827ecd02a0SRichard Henderson 
3837ecd02a0SRichard Henderson     QSIMPLEQ_FOREACH(l, &s->labels, next) {
3847ecd02a0SRichard Henderson         TCGRelocation *r;
3857ecd02a0SRichard Henderson         uintptr_t value = l->u.value;
3867ecd02a0SRichard Henderson 
3877ecd02a0SRichard Henderson         QSIMPLEQ_FOREACH(r, &l->relocs, next) {
3887ecd02a0SRichard Henderson             if (!patch_reloc(r->ptr, r->type, value, r->addend)) {
3897ecd02a0SRichard Henderson                 return false;
3907ecd02a0SRichard Henderson             }
3917ecd02a0SRichard Henderson         }
3927ecd02a0SRichard Henderson     }
3937ecd02a0SRichard Henderson     return true;
3947ecd02a0SRichard Henderson }
3957ecd02a0SRichard Henderson 
3969f754620SRichard Henderson static void set_jmp_reset_offset(TCGContext *s, int which)
3979f754620SRichard Henderson {
398f14bed3fSRichard Henderson     /*
399f14bed3fSRichard Henderson      * We will check for overflow at the end of the opcode loop in
400f14bed3fSRichard Henderson      * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX.
401f14bed3fSRichard Henderson      */
402b7e4afbdSRichard Henderson     s->gen_tb->jmp_reset_offset[which] = tcg_current_code_size(s);
4039f754620SRichard Henderson }
4049f754620SRichard Henderson 
405b52a2c03SRichard Henderson static void G_GNUC_UNUSED set_jmp_insn_offset(TCGContext *s, int which)
406b52a2c03SRichard Henderson {
407b52a2c03SRichard Henderson     /*
408b52a2c03SRichard Henderson      * We will check for overflow at the end of the opcode loop in
409b52a2c03SRichard Henderson      * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX.
410b52a2c03SRichard Henderson      */
4119da6079bSRichard Henderson     s->gen_tb->jmp_insn_offset[which] = tcg_current_code_size(s);
412b52a2c03SRichard Henderson }
413b52a2c03SRichard Henderson 
414becc452aSRichard Henderson static uintptr_t G_GNUC_UNUSED get_jmp_target_addr(TCGContext *s, int which)
415becc452aSRichard Henderson {
416becc452aSRichard Henderson     /*
417becc452aSRichard Henderson      * Return the read-execute version of the pointer, for the benefit
418becc452aSRichard Henderson      * of any pc-relative addressing mode.
419becc452aSRichard Henderson      */
4209da6079bSRichard Henderson     return (uintptr_t)tcg_splitwx_to_rx(&s->gen_tb->jmp_target_addr[which]);
421becc452aSRichard Henderson }
422becc452aSRichard Henderson 
423397cabaaSRichard Henderson static int __attribute__((unused))
424397cabaaSRichard Henderson tlb_mask_table_ofs(TCGContext *s, int which)
425d0a9bb5eSRichard Henderson {
4267857ee11SRichard Henderson     return (offsetof(CPUNegativeOffsetState, tlb.f[which]) -
4277857ee11SRichard Henderson             sizeof(CPUNegativeOffsetState));
428d0a9bb5eSRichard Henderson }
429d0a9bb5eSRichard Henderson 
430db6b7d0cSRichard Henderson /* Signal overflow, starting over with fewer guest insns. */
4318905770bSMarc-André Lureau static G_NORETURN
4328905770bSMarc-André Lureau void tcg_raise_tb_overflow(TCGContext *s)
433db6b7d0cSRichard Henderson {
434db6b7d0cSRichard Henderson     siglongjmp(s->jmp_trans, -2);
435db6b7d0cSRichard Henderson }
436db6b7d0cSRichard Henderson 
4378429a1caSRichard Henderson /*
4388429a1caSRichard Henderson  * Used by tcg_out_movext{1,2} to hold the arguments for tcg_out_movext.
4398429a1caSRichard Henderson  * By the time we arrive at tcg_out_movext1, @dst is always a TCGReg.
4408429a1caSRichard Henderson  *
4418429a1caSRichard Henderson  * However, tcg_out_helper_load_slots reuses this field to hold an
4428429a1caSRichard Henderson  * argument slot number (which may designate a argument register or an
4438429a1caSRichard Henderson  * argument stack slot), converting to TCGReg once all arguments that
4448429a1caSRichard Henderson  * are destined for the stack are processed.
4458429a1caSRichard Henderson  */
446129f1f9eSRichard Henderson typedef struct TCGMovExtend {
4478429a1caSRichard Henderson     unsigned dst;
448129f1f9eSRichard Henderson     TCGReg src;
449129f1f9eSRichard Henderson     TCGType dst_type;
450129f1f9eSRichard Henderson     TCGType src_type;
451129f1f9eSRichard Henderson     MemOp src_ext;
452129f1f9eSRichard Henderson } TCGMovExtend;
453129f1f9eSRichard Henderson 
454b3dfd5fcSRichard Henderson /**
455b3dfd5fcSRichard Henderson  * tcg_out_movext -- move and extend
456b3dfd5fcSRichard Henderson  * @s: tcg context
457b3dfd5fcSRichard Henderson  * @dst_type: integral type for destination
458b3dfd5fcSRichard Henderson  * @dst: destination register
459b3dfd5fcSRichard Henderson  * @src_type: integral type for source
460b3dfd5fcSRichard Henderson  * @src_ext: extension to apply to source
461b3dfd5fcSRichard Henderson  * @src: source register
462b3dfd5fcSRichard Henderson  *
463b3dfd5fcSRichard Henderson  * Move or extend @src into @dst, depending on @src_ext and the types.
464b3dfd5fcSRichard Henderson  */
465129f1f9eSRichard Henderson static void tcg_out_movext(TCGContext *s, TCGType dst_type, TCGReg dst,
466b3dfd5fcSRichard Henderson                            TCGType src_type, MemOp src_ext, TCGReg src)
467b3dfd5fcSRichard Henderson {
468b3dfd5fcSRichard Henderson     switch (src_ext) {
469b3dfd5fcSRichard Henderson     case MO_UB:
470b3dfd5fcSRichard Henderson         tcg_out_ext8u(s, dst, src);
471b3dfd5fcSRichard Henderson         break;
472b3dfd5fcSRichard Henderson     case MO_SB:
473b3dfd5fcSRichard Henderson         tcg_out_ext8s(s, dst_type, dst, src);
474b3dfd5fcSRichard Henderson         break;
475b3dfd5fcSRichard Henderson     case MO_UW:
476b3dfd5fcSRichard Henderson         tcg_out_ext16u(s, dst, src);
477b3dfd5fcSRichard Henderson         break;
478b3dfd5fcSRichard Henderson     case MO_SW:
479b3dfd5fcSRichard Henderson         tcg_out_ext16s(s, dst_type, dst, src);
480b3dfd5fcSRichard Henderson         break;
481b3dfd5fcSRichard Henderson     case MO_UL:
482b3dfd5fcSRichard Henderson     case MO_SL:
483b3dfd5fcSRichard Henderson         if (dst_type == TCG_TYPE_I32) {
484b3dfd5fcSRichard Henderson             if (src_type == TCG_TYPE_I32) {
485b3dfd5fcSRichard Henderson                 tcg_out_mov(s, TCG_TYPE_I32, dst, src);
486b3dfd5fcSRichard Henderson             } else {
487b3dfd5fcSRichard Henderson                 tcg_out_extrl_i64_i32(s, dst, src);
488b3dfd5fcSRichard Henderson             }
489b3dfd5fcSRichard Henderson         } else if (src_type == TCG_TYPE_I32) {
490b3dfd5fcSRichard Henderson             if (src_ext & MO_SIGN) {
491b3dfd5fcSRichard Henderson                 tcg_out_exts_i32_i64(s, dst, src);
492b3dfd5fcSRichard Henderson             } else {
493b3dfd5fcSRichard Henderson                 tcg_out_extu_i32_i64(s, dst, src);
494b3dfd5fcSRichard Henderson             }
495b3dfd5fcSRichard Henderson         } else {
496b3dfd5fcSRichard Henderson             if (src_ext & MO_SIGN) {
497b3dfd5fcSRichard Henderson                 tcg_out_ext32s(s, dst, src);
498b3dfd5fcSRichard Henderson             } else {
499b3dfd5fcSRichard Henderson                 tcg_out_ext32u(s, dst, src);
500b3dfd5fcSRichard Henderson             }
501b3dfd5fcSRichard Henderson         }
502b3dfd5fcSRichard Henderson         break;
503b3dfd5fcSRichard Henderson     case MO_UQ:
504b3dfd5fcSRichard Henderson         tcg_debug_assert(TCG_TARGET_REG_BITS == 64);
505b3dfd5fcSRichard Henderson         if (dst_type == TCG_TYPE_I32) {
506b3dfd5fcSRichard Henderson             tcg_out_extrl_i64_i32(s, dst, src);
507b3dfd5fcSRichard Henderson         } else {
508b3dfd5fcSRichard Henderson             tcg_out_mov(s, TCG_TYPE_I64, dst, src);
509b3dfd5fcSRichard Henderson         }
510b3dfd5fcSRichard Henderson         break;
511b3dfd5fcSRichard Henderson     default:
512b3dfd5fcSRichard Henderson         g_assert_not_reached();
513b3dfd5fcSRichard Henderson     }
514b3dfd5fcSRichard Henderson }
515b3dfd5fcSRichard Henderson 
516129f1f9eSRichard Henderson /* Minor variations on a theme, using a structure. */
517129f1f9eSRichard Henderson static void tcg_out_movext1_new_src(TCGContext *s, const TCGMovExtend *i,
518129f1f9eSRichard Henderson                                     TCGReg src)
519129f1f9eSRichard Henderson {
520129f1f9eSRichard Henderson     tcg_out_movext(s, i->dst_type, i->dst, i->src_type, i->src_ext, src);
521129f1f9eSRichard Henderson }
522129f1f9eSRichard Henderson 
523129f1f9eSRichard Henderson static void tcg_out_movext1(TCGContext *s, const TCGMovExtend *i)
524129f1f9eSRichard Henderson {
525129f1f9eSRichard Henderson     tcg_out_movext1_new_src(s, i, i->src);
526129f1f9eSRichard Henderson }
527129f1f9eSRichard Henderson 
528129f1f9eSRichard Henderson /**
529129f1f9eSRichard Henderson  * tcg_out_movext2 -- move and extend two pair
530129f1f9eSRichard Henderson  * @s: tcg context
531129f1f9eSRichard Henderson  * @i1: first move description
532129f1f9eSRichard Henderson  * @i2: second move description
533129f1f9eSRichard Henderson  * @scratch: temporary register, or -1 for none
534129f1f9eSRichard Henderson  *
535129f1f9eSRichard Henderson  * As tcg_out_movext, for both @i1 and @i2, caring for overlap
536129f1f9eSRichard Henderson  * between the sources and destinations.
537129f1f9eSRichard Henderson  */
538129f1f9eSRichard Henderson 
5398429a1caSRichard Henderson static void tcg_out_movext2(TCGContext *s, const TCGMovExtend *i1,
540129f1f9eSRichard Henderson                             const TCGMovExtend *i2, int scratch)
541129f1f9eSRichard Henderson {
542129f1f9eSRichard Henderson     TCGReg src1 = i1->src;
543129f1f9eSRichard Henderson     TCGReg src2 = i2->src;
544129f1f9eSRichard Henderson 
545129f1f9eSRichard Henderson     if (i1->dst != src2) {
546129f1f9eSRichard Henderson         tcg_out_movext1(s, i1);
547129f1f9eSRichard Henderson         tcg_out_movext1(s, i2);
548129f1f9eSRichard Henderson         return;
549129f1f9eSRichard Henderson     }
550129f1f9eSRichard Henderson     if (i2->dst == src1) {
551129f1f9eSRichard Henderson         TCGType src1_type = i1->src_type;
552129f1f9eSRichard Henderson         TCGType src2_type = i2->src_type;
553129f1f9eSRichard Henderson 
554129f1f9eSRichard Henderson         if (tcg_out_xchg(s, MAX(src1_type, src2_type), src1, src2)) {
555129f1f9eSRichard Henderson             /* The data is now in the correct registers, now extend. */
556129f1f9eSRichard Henderson             src1 = i2->src;
557129f1f9eSRichard Henderson             src2 = i1->src;
558129f1f9eSRichard Henderson         } else {
559129f1f9eSRichard Henderson             tcg_debug_assert(scratch >= 0);
560129f1f9eSRichard Henderson             tcg_out_mov(s, src1_type, scratch, src1);
561129f1f9eSRichard Henderson             src1 = scratch;
562129f1f9eSRichard Henderson         }
563129f1f9eSRichard Henderson     }
564129f1f9eSRichard Henderson     tcg_out_movext1_new_src(s, i2, src2);
565129f1f9eSRichard Henderson     tcg_out_movext1_new_src(s, i1, src1);
566129f1f9eSRichard Henderson }
567129f1f9eSRichard Henderson 
5682462e30eSRichard Henderson /**
5692462e30eSRichard Henderson  * tcg_out_movext3 -- move and extend three pair
5702462e30eSRichard Henderson  * @s: tcg context
5712462e30eSRichard Henderson  * @i1: first move description
5722462e30eSRichard Henderson  * @i2: second move description
5732462e30eSRichard Henderson  * @i3: third move description
5742462e30eSRichard Henderson  * @scratch: temporary register, or -1 for none
5752462e30eSRichard Henderson  *
5762462e30eSRichard Henderson  * As tcg_out_movext, for all of @i1, @i2 and @i3, caring for overlap
5772462e30eSRichard Henderson  * between the sources and destinations.
5782462e30eSRichard Henderson  */
5792462e30eSRichard Henderson 
5802462e30eSRichard Henderson static void tcg_out_movext3(TCGContext *s, const TCGMovExtend *i1,
5812462e30eSRichard Henderson                             const TCGMovExtend *i2, const TCGMovExtend *i3,
5822462e30eSRichard Henderson                             int scratch)
5832462e30eSRichard Henderson {
5842462e30eSRichard Henderson     TCGReg src1 = i1->src;
5852462e30eSRichard Henderson     TCGReg src2 = i2->src;
5862462e30eSRichard Henderson     TCGReg src3 = i3->src;
5872462e30eSRichard Henderson 
5882462e30eSRichard Henderson     if (i1->dst != src2 && i1->dst != src3) {
5892462e30eSRichard Henderson         tcg_out_movext1(s, i1);
5902462e30eSRichard Henderson         tcg_out_movext2(s, i2, i3, scratch);
5912462e30eSRichard Henderson         return;
5922462e30eSRichard Henderson     }
5932462e30eSRichard Henderson     if (i2->dst != src1 && i2->dst != src3) {
5942462e30eSRichard Henderson         tcg_out_movext1(s, i2);
5952462e30eSRichard Henderson         tcg_out_movext2(s, i1, i3, scratch);
5962462e30eSRichard Henderson         return;
5972462e30eSRichard Henderson     }
5982462e30eSRichard Henderson     if (i3->dst != src1 && i3->dst != src2) {
5992462e30eSRichard Henderson         tcg_out_movext1(s, i3);
6002462e30eSRichard Henderson         tcg_out_movext2(s, i1, i2, scratch);
6012462e30eSRichard Henderson         return;
6022462e30eSRichard Henderson     }
6032462e30eSRichard Henderson 
6042462e30eSRichard Henderson     /*
6052462e30eSRichard Henderson      * There is a cycle.  Since there are only 3 nodes, the cycle is
6062462e30eSRichard Henderson      * either "clockwise" or "anti-clockwise", and can be solved with
6072462e30eSRichard Henderson      * a single scratch or two xchg.
6082462e30eSRichard Henderson      */
6092462e30eSRichard Henderson     if (i1->dst == src2 && i2->dst == src3 && i3->dst == src1) {
6102462e30eSRichard Henderson         /* "Clockwise" */
6112462e30eSRichard Henderson         if (tcg_out_xchg(s, MAX(i1->src_type, i2->src_type), src1, src2)) {
6122462e30eSRichard Henderson             tcg_out_xchg(s, MAX(i2->src_type, i3->src_type), src2, src3);
6132462e30eSRichard Henderson             /* The data is now in the correct registers, now extend. */
6142462e30eSRichard Henderson             tcg_out_movext1_new_src(s, i1, i1->dst);
6152462e30eSRichard Henderson             tcg_out_movext1_new_src(s, i2, i2->dst);
6162462e30eSRichard Henderson             tcg_out_movext1_new_src(s, i3, i3->dst);
6172462e30eSRichard Henderson         } else {
6182462e30eSRichard Henderson             tcg_debug_assert(scratch >= 0);
6192462e30eSRichard Henderson             tcg_out_mov(s, i1->src_type, scratch, src1);
6202462e30eSRichard Henderson             tcg_out_movext1(s, i3);
6212462e30eSRichard Henderson             tcg_out_movext1(s, i2);
6222462e30eSRichard Henderson             tcg_out_movext1_new_src(s, i1, scratch);
6232462e30eSRichard Henderson         }
6242462e30eSRichard Henderson     } else if (i1->dst == src3 && i2->dst == src1 && i3->dst == src2) {
6252462e30eSRichard Henderson         /* "Anti-clockwise" */
6262462e30eSRichard Henderson         if (tcg_out_xchg(s, MAX(i2->src_type, i3->src_type), src2, src3)) {
6272462e30eSRichard Henderson             tcg_out_xchg(s, MAX(i1->src_type, i2->src_type), src1, src2);
6282462e30eSRichard Henderson             /* The data is now in the correct registers, now extend. */
6292462e30eSRichard Henderson             tcg_out_movext1_new_src(s, i1, i1->dst);
6302462e30eSRichard Henderson             tcg_out_movext1_new_src(s, i2, i2->dst);
6312462e30eSRichard Henderson             tcg_out_movext1_new_src(s, i3, i3->dst);
6322462e30eSRichard Henderson         } else {
6332462e30eSRichard Henderson             tcg_debug_assert(scratch >= 0);
6342462e30eSRichard Henderson             tcg_out_mov(s, i1->src_type, scratch, src1);
6352462e30eSRichard Henderson             tcg_out_movext1(s, i2);
6362462e30eSRichard Henderson             tcg_out_movext1(s, i3);
6372462e30eSRichard Henderson             tcg_out_movext1_new_src(s, i1, scratch);
6382462e30eSRichard Henderson         }
6392462e30eSRichard Henderson     } else {
6402462e30eSRichard Henderson         g_assert_not_reached();
6412462e30eSRichard Henderson     }
6422462e30eSRichard Henderson }
6432462e30eSRichard Henderson 
644a417ef83SRichard Henderson /*
645a417ef83SRichard Henderson  * Allocate a new TCGLabelQemuLdst entry.
646a417ef83SRichard Henderson  */
647a417ef83SRichard Henderson 
648a417ef83SRichard Henderson __attribute__((unused))
649a417ef83SRichard Henderson static TCGLabelQemuLdst *new_ldst_label(TCGContext *s)
650a417ef83SRichard Henderson {
651a417ef83SRichard Henderson     TCGLabelQemuLdst *l = tcg_malloc(sizeof(*l));
652a417ef83SRichard Henderson 
653a417ef83SRichard Henderson     memset(l, 0, sizeof(*l));
654a417ef83SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&s->ldst_labels, l, next);
655a417ef83SRichard Henderson 
656a417ef83SRichard Henderson     return l;
657a417ef83SRichard Henderson }
658a417ef83SRichard Henderson 
659a417ef83SRichard Henderson /*
660a417ef83SRichard Henderson  * Allocate new constant pool entries.
661a417ef83SRichard Henderson  */
662a417ef83SRichard Henderson 
663a417ef83SRichard Henderson typedef struct TCGLabelPoolData {
664a417ef83SRichard Henderson     struct TCGLabelPoolData *next;
665a417ef83SRichard Henderson     tcg_insn_unit *label;
666a417ef83SRichard Henderson     intptr_t addend;
667a417ef83SRichard Henderson     int rtype;
668a417ef83SRichard Henderson     unsigned nlong;
669a417ef83SRichard Henderson     tcg_target_ulong data[];
670a417ef83SRichard Henderson } TCGLabelPoolData;
671a417ef83SRichard Henderson 
672a417ef83SRichard Henderson static TCGLabelPoolData *new_pool_alloc(TCGContext *s, int nlong, int rtype,
673a417ef83SRichard Henderson                                         tcg_insn_unit *label, intptr_t addend)
674a417ef83SRichard Henderson {
675a417ef83SRichard Henderson     TCGLabelPoolData *n = tcg_malloc(sizeof(TCGLabelPoolData)
676a417ef83SRichard Henderson                                      + sizeof(tcg_target_ulong) * nlong);
677a417ef83SRichard Henderson 
678a417ef83SRichard Henderson     n->label = label;
679a417ef83SRichard Henderson     n->addend = addend;
680a417ef83SRichard Henderson     n->rtype = rtype;
681a417ef83SRichard Henderson     n->nlong = nlong;
682a417ef83SRichard Henderson     return n;
683a417ef83SRichard Henderson }
684a417ef83SRichard Henderson 
685a417ef83SRichard Henderson static void new_pool_insert(TCGContext *s, TCGLabelPoolData *n)
686a417ef83SRichard Henderson {
687a417ef83SRichard Henderson     TCGLabelPoolData *i, **pp;
688a417ef83SRichard Henderson     int nlong = n->nlong;
689a417ef83SRichard Henderson 
690a417ef83SRichard Henderson     /* Insertion sort on the pool.  */
691a417ef83SRichard Henderson     for (pp = &s->pool_labels; (i = *pp) != NULL; pp = &i->next) {
692a417ef83SRichard Henderson         if (nlong > i->nlong) {
693a417ef83SRichard Henderson             break;
694a417ef83SRichard Henderson         }
695a417ef83SRichard Henderson         if (nlong < i->nlong) {
696a417ef83SRichard Henderson             continue;
697a417ef83SRichard Henderson         }
698a417ef83SRichard Henderson         if (memcmp(n->data, i->data, sizeof(tcg_target_ulong) * nlong) >= 0) {
699a417ef83SRichard Henderson             break;
700a417ef83SRichard Henderson         }
701a417ef83SRichard Henderson     }
702a417ef83SRichard Henderson     n->next = *pp;
703a417ef83SRichard Henderson     *pp = n;
704a417ef83SRichard Henderson }
705a417ef83SRichard Henderson 
706a417ef83SRichard Henderson /* The "usual" for generic integer code.  */
707a417ef83SRichard Henderson __attribute__((unused))
708a417ef83SRichard Henderson static void new_pool_label(TCGContext *s, tcg_target_ulong d, int rtype,
709a417ef83SRichard Henderson                            tcg_insn_unit *label, intptr_t addend)
710a417ef83SRichard Henderson {
711a417ef83SRichard Henderson     TCGLabelPoolData *n = new_pool_alloc(s, 1, rtype, label, addend);
712a417ef83SRichard Henderson     n->data[0] = d;
713a417ef83SRichard Henderson     new_pool_insert(s, n);
714a417ef83SRichard Henderson }
715a417ef83SRichard Henderson 
716a417ef83SRichard Henderson /* For v64 or v128, depending on the host.  */
717a417ef83SRichard Henderson __attribute__((unused))
718a417ef83SRichard Henderson static void new_pool_l2(TCGContext *s, int rtype, tcg_insn_unit *label,
719a417ef83SRichard Henderson                         intptr_t addend, tcg_target_ulong d0,
720a417ef83SRichard Henderson                         tcg_target_ulong d1)
721a417ef83SRichard Henderson {
722a417ef83SRichard Henderson     TCGLabelPoolData *n = new_pool_alloc(s, 2, rtype, label, addend);
723a417ef83SRichard Henderson     n->data[0] = d0;
724a417ef83SRichard Henderson     n->data[1] = d1;
725a417ef83SRichard Henderson     new_pool_insert(s, n);
726a417ef83SRichard Henderson }
727a417ef83SRichard Henderson 
728a417ef83SRichard Henderson /* For v128 or v256, depending on the host.  */
729a417ef83SRichard Henderson __attribute__((unused))
730a417ef83SRichard Henderson static void new_pool_l4(TCGContext *s, int rtype, tcg_insn_unit *label,
731a417ef83SRichard Henderson                         intptr_t addend, tcg_target_ulong d0,
732a417ef83SRichard Henderson                         tcg_target_ulong d1, tcg_target_ulong d2,
733a417ef83SRichard Henderson                         tcg_target_ulong d3)
734a417ef83SRichard Henderson {
735a417ef83SRichard Henderson     TCGLabelPoolData *n = new_pool_alloc(s, 4, rtype, label, addend);
736a417ef83SRichard Henderson     n->data[0] = d0;
737a417ef83SRichard Henderson     n->data[1] = d1;
738a417ef83SRichard Henderson     n->data[2] = d2;
739a417ef83SRichard Henderson     n->data[3] = d3;
740a417ef83SRichard Henderson     new_pool_insert(s, n);
741a417ef83SRichard Henderson }
742a417ef83SRichard Henderson 
743a417ef83SRichard Henderson /* For v256, for 32-bit host.  */
744a417ef83SRichard Henderson __attribute__((unused))
745a417ef83SRichard Henderson static void new_pool_l8(TCGContext *s, int rtype, tcg_insn_unit *label,
746a417ef83SRichard Henderson                         intptr_t addend, tcg_target_ulong d0,
747a417ef83SRichard Henderson                         tcg_target_ulong d1, tcg_target_ulong d2,
748a417ef83SRichard Henderson                         tcg_target_ulong d3, tcg_target_ulong d4,
749a417ef83SRichard Henderson                         tcg_target_ulong d5, tcg_target_ulong d6,
750a417ef83SRichard Henderson                         tcg_target_ulong d7)
751a417ef83SRichard Henderson {
752a417ef83SRichard Henderson     TCGLabelPoolData *n = new_pool_alloc(s, 8, rtype, label, addend);
753a417ef83SRichard Henderson     n->data[0] = d0;
754a417ef83SRichard Henderson     n->data[1] = d1;
755a417ef83SRichard Henderson     n->data[2] = d2;
756a417ef83SRichard Henderson     n->data[3] = d3;
757a417ef83SRichard Henderson     n->data[4] = d4;
758a417ef83SRichard Henderson     n->data[5] = d5;
759a417ef83SRichard Henderson     n->data[6] = d6;
760a417ef83SRichard Henderson     n->data[7] = d7;
761a417ef83SRichard Henderson     new_pool_insert(s, n);
762a417ef83SRichard Henderson }
763a417ef83SRichard Henderson 
764a417ef83SRichard Henderson /*
765a417ef83SRichard Henderson  * Generate TB finalization at the end of block
766a417ef83SRichard Henderson  */
767a417ef83SRichard Henderson 
768a417ef83SRichard Henderson static int tcg_out_ldst_finalize(TCGContext *s)
769a417ef83SRichard Henderson {
770a417ef83SRichard Henderson     TCGLabelQemuLdst *lb;
771a417ef83SRichard Henderson 
772a417ef83SRichard Henderson     /* qemu_ld/st slow paths */
773a417ef83SRichard Henderson     QSIMPLEQ_FOREACH(lb, &s->ldst_labels, next) {
774a417ef83SRichard Henderson         if (lb->is_ld
775a417ef83SRichard Henderson             ? !tcg_out_qemu_ld_slow_path(s, lb)
776a417ef83SRichard Henderson             : !tcg_out_qemu_st_slow_path(s, lb)) {
777a417ef83SRichard Henderson             return -2;
778a417ef83SRichard Henderson         }
779a417ef83SRichard Henderson 
780a417ef83SRichard Henderson         /*
781a417ef83SRichard Henderson          * Test for (pending) buffer overflow.  The assumption is that any
782a417ef83SRichard Henderson          * one operation beginning below the high water mark cannot overrun
783a417ef83SRichard Henderson          * the buffer completely.  Thus we can test for overflow after
784a417ef83SRichard Henderson          * generating code without having to check during generation.
785a417ef83SRichard Henderson          */
786a417ef83SRichard Henderson         if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) {
787a417ef83SRichard Henderson             return -1;
788a417ef83SRichard Henderson         }
789a417ef83SRichard Henderson     }
790a417ef83SRichard Henderson     return 0;
791a417ef83SRichard Henderson }
792a417ef83SRichard Henderson 
793a417ef83SRichard Henderson static int tcg_out_pool_finalize(TCGContext *s)
794a417ef83SRichard Henderson {
795a417ef83SRichard Henderson     TCGLabelPoolData *p = s->pool_labels;
796a417ef83SRichard Henderson     TCGLabelPoolData *l = NULL;
797a417ef83SRichard Henderson     void *a;
798a417ef83SRichard Henderson 
799a417ef83SRichard Henderson     if (p == NULL) {
800a417ef83SRichard Henderson         return 0;
801a417ef83SRichard Henderson     }
802a417ef83SRichard Henderson 
803a417ef83SRichard Henderson     /*
804a417ef83SRichard Henderson      * ??? Round up to qemu_icache_linesize, but then do not round
805a417ef83SRichard Henderson      * again when allocating the next TranslationBlock structure.
806a417ef83SRichard Henderson      */
807a417ef83SRichard Henderson     a = (void *)ROUND_UP((uintptr_t)s->code_ptr,
808a417ef83SRichard Henderson                          sizeof(tcg_target_ulong) * p->nlong);
809a417ef83SRichard Henderson     tcg_out_nop_fill(s->code_ptr, (tcg_insn_unit *)a - s->code_ptr);
810a417ef83SRichard Henderson     s->data_gen_ptr = a;
811a417ef83SRichard Henderson 
812a417ef83SRichard Henderson     for (; p != NULL; p = p->next) {
813a417ef83SRichard Henderson         size_t size = sizeof(tcg_target_ulong) * p->nlong;
814a417ef83SRichard Henderson         uintptr_t value;
815a417ef83SRichard Henderson 
816a417ef83SRichard Henderson         if (!l || l->nlong != p->nlong || memcmp(l->data, p->data, size)) {
817a417ef83SRichard Henderson             if (unlikely(a > s->code_gen_highwater)) {
818a417ef83SRichard Henderson                 return -1;
819a417ef83SRichard Henderson             }
820a417ef83SRichard Henderson             memcpy(a, p->data, size);
821a417ef83SRichard Henderson             a += size;
822a417ef83SRichard Henderson             l = p;
823a417ef83SRichard Henderson         }
824a417ef83SRichard Henderson 
825a417ef83SRichard Henderson         value = (uintptr_t)tcg_splitwx_to_rx(a) - size;
826a417ef83SRichard Henderson         if (!patch_reloc(p->label, p->rtype, value, p->addend)) {
827a417ef83SRichard Henderson             return -2;
828a417ef83SRichard Henderson         }
829a417ef83SRichard Henderson     }
830a417ef83SRichard Henderson 
831a417ef83SRichard Henderson     s->code_ptr = a;
832a417ef83SRichard Henderson     return 0;
833a417ef83SRichard Henderson }
834a417ef83SRichard Henderson 
8354c22e840SRichard Henderson #define C_PFX1(P, A)                    P##A
8364c22e840SRichard Henderson #define C_PFX2(P, A, B)                 P##A##_##B
8374c22e840SRichard Henderson #define C_PFX3(P, A, B, C)              P##A##_##B##_##C
8384c22e840SRichard Henderson #define C_PFX4(P, A, B, C, D)           P##A##_##B##_##C##_##D
8394c22e840SRichard Henderson #define C_PFX5(P, A, B, C, D, E)        P##A##_##B##_##C##_##D##_##E
8404c22e840SRichard Henderson #define C_PFX6(P, A, B, C, D, E, F)     P##A##_##B##_##C##_##D##_##E##_##F
8414c22e840SRichard Henderson 
8424c22e840SRichard Henderson /* Define an enumeration for the various combinations. */
8434c22e840SRichard Henderson 
8444c22e840SRichard Henderson #define C_O0_I1(I1)                     C_PFX1(c_o0_i1_, I1),
8454c22e840SRichard Henderson #define C_O0_I2(I1, I2)                 C_PFX2(c_o0_i2_, I1, I2),
8464c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3)             C_PFX3(c_o0_i3_, I1, I2, I3),
8474c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4)         C_PFX4(c_o0_i4_, I1, I2, I3, I4),
8484c22e840SRichard Henderson 
8494c22e840SRichard Henderson #define C_O1_I1(O1, I1)                 C_PFX2(c_o1_i1_, O1, I1),
8504c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2)             C_PFX3(c_o1_i2_, O1, I1, I2),
8514c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3)         C_PFX4(c_o1_i3_, O1, I1, I2, I3),
8524c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4)     C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4),
8534c22e840SRichard Henderson 
8544c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2)             C_PFX3(c_n1_i2_, O1, I1, I2),
855ca5bed07SRichard Henderson #define C_N1O1_I1(O1, O2, I1)           C_PFX3(c_n1o1_i1_, O1, O2, I1),
856fa645b48SRichard Henderson #define C_N2_I1(O1, O2, I1)             C_PFX3(c_n2_i1_, O1, O2, I1),
8574c22e840SRichard Henderson 
8584c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1)             C_PFX3(c_o2_i1_, O1, O2, I1),
8594c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2)         C_PFX4(c_o2_i2_, O1, O2, I1, I2),
8604c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3)     C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3),
8614c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4),
86222d2e535SIlya Leoshkevich #define C_N1_O1_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_n1_o1_i4_, O1, O2, I1, I2, I3, I4),
8634c22e840SRichard Henderson 
8644c22e840SRichard Henderson typedef enum {
865da43e5e6SRichard Henderson     C_NotImplemented = -1,
8664c22e840SRichard Henderson #include "tcg-target-con-set.h"
8674c22e840SRichard Henderson } TCGConstraintSetIndex;
8684c22e840SRichard Henderson 
8696323b363SRichard Henderson static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode, TCGType, unsigned);
8704c22e840SRichard Henderson 
8714c22e840SRichard Henderson #undef C_O0_I1
8724c22e840SRichard Henderson #undef C_O0_I2
8734c22e840SRichard Henderson #undef C_O0_I3
8744c22e840SRichard Henderson #undef C_O0_I4
8754c22e840SRichard Henderson #undef C_O1_I1
8764c22e840SRichard Henderson #undef C_O1_I2
8774c22e840SRichard Henderson #undef C_O1_I3
8784c22e840SRichard Henderson #undef C_O1_I4
8794c22e840SRichard Henderson #undef C_N1_I2
880ca5bed07SRichard Henderson #undef C_N1O1_I1
881fa645b48SRichard Henderson #undef C_N2_I1
8824c22e840SRichard Henderson #undef C_O2_I1
8834c22e840SRichard Henderson #undef C_O2_I2
8844c22e840SRichard Henderson #undef C_O2_I3
8854c22e840SRichard Henderson #undef C_O2_I4
88622d2e535SIlya Leoshkevich #undef C_N1_O1_I4
8874c22e840SRichard Henderson 
8884c22e840SRichard Henderson /* Put all of the constraint sets into an array, indexed by the enum. */
8894c22e840SRichard Henderson 
8903e80824eSRichard Henderson typedef struct TCGConstraintSet {
8913e80824eSRichard Henderson     uint8_t nb_oargs, nb_iargs;
8923e80824eSRichard Henderson     const char *args_ct_str[TCG_MAX_OP_ARGS];
8933e80824eSRichard Henderson } TCGConstraintSet;
8944c22e840SRichard Henderson 
8953e80824eSRichard Henderson #define C_O0_I1(I1)                     { 0, 1, { #I1 } },
8963e80824eSRichard Henderson #define C_O0_I2(I1, I2)                 { 0, 2, { #I1, #I2 } },
8973e80824eSRichard Henderson #define C_O0_I3(I1, I2, I3)             { 0, 3, { #I1, #I2, #I3 } },
8983e80824eSRichard Henderson #define C_O0_I4(I1, I2, I3, I4)         { 0, 4, { #I1, #I2, #I3, #I4 } },
8994c22e840SRichard Henderson 
9003e80824eSRichard Henderson #define C_O1_I1(O1, I1)                 { 1, 1, { #O1, #I1 } },
9013e80824eSRichard Henderson #define C_O1_I2(O1, I1, I2)             { 1, 2, { #O1, #I1, #I2 } },
9023e80824eSRichard Henderson #define C_O1_I3(O1, I1, I2, I3)         { 1, 3, { #O1, #I1, #I2, #I3 } },
9033e80824eSRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4)     { 1, 4, { #O1, #I1, #I2, #I3, #I4 } },
9044c22e840SRichard Henderson 
9053e80824eSRichard Henderson #define C_N1_I2(O1, I1, I2)             { 1, 2, { "&" #O1, #I1, #I2 } },
9063e80824eSRichard Henderson #define C_N1O1_I1(O1, O2, I1)           { 2, 1, { "&" #O1, #O2, #I1 } },
9073e80824eSRichard Henderson #define C_N2_I1(O1, O2, I1)             { 2, 1, { "&" #O1, "&" #O2, #I1 } },
9084c22e840SRichard Henderson 
9093e80824eSRichard Henderson #define C_O2_I1(O1, O2, I1)             { 2, 1, { #O1, #O2, #I1 } },
9103e80824eSRichard Henderson #define C_O2_I2(O1, O2, I1, I2)         { 2, 2, { #O1, #O2, #I1, #I2 } },
9113e80824eSRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3)     { 2, 3, { #O1, #O2, #I1, #I2, #I3 } },
9123e80824eSRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) { 2, 4, { #O1, #O2, #I1, #I2, #I3, #I4 } },
9133e80824eSRichard Henderson #define C_N1_O1_I4(O1, O2, I1, I2, I3, I4) { 2, 4, { "&" #O1, #O2, #I1, #I2, #I3, #I4 } },
9143e80824eSRichard Henderson 
9153e80824eSRichard Henderson static const TCGConstraintSet constraint_sets[] = {
9164c22e840SRichard Henderson #include "tcg-target-con-set.h"
9174c22e840SRichard Henderson };
9184c22e840SRichard Henderson 
9194c22e840SRichard Henderson #undef C_O0_I1
9204c22e840SRichard Henderson #undef C_O0_I2
9214c22e840SRichard Henderson #undef C_O0_I3
9224c22e840SRichard Henderson #undef C_O0_I4
9234c22e840SRichard Henderson #undef C_O1_I1
9244c22e840SRichard Henderson #undef C_O1_I2
9254c22e840SRichard Henderson #undef C_O1_I3
9264c22e840SRichard Henderson #undef C_O1_I4
9274c22e840SRichard Henderson #undef C_N1_I2
928ca5bed07SRichard Henderson #undef C_N1O1_I1
929fa645b48SRichard Henderson #undef C_N2_I1
9304c22e840SRichard Henderson #undef C_O2_I1
9314c22e840SRichard Henderson #undef C_O2_I2
9324c22e840SRichard Henderson #undef C_O2_I3
9334c22e840SRichard Henderson #undef C_O2_I4
93422d2e535SIlya Leoshkevich #undef C_N1_O1_I4
9354c22e840SRichard Henderson 
9364c22e840SRichard Henderson /* Expand the enumerator to be returned from tcg_target_op_def(). */
9374c22e840SRichard Henderson 
9384c22e840SRichard Henderson #define C_O0_I1(I1)                     C_PFX1(c_o0_i1_, I1)
9394c22e840SRichard Henderson #define C_O0_I2(I1, I2)                 C_PFX2(c_o0_i2_, I1, I2)
9404c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3)             C_PFX3(c_o0_i3_, I1, I2, I3)
9414c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4)         C_PFX4(c_o0_i4_, I1, I2, I3, I4)
9424c22e840SRichard Henderson 
9434c22e840SRichard Henderson #define C_O1_I1(O1, I1)                 C_PFX2(c_o1_i1_, O1, I1)
9444c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2)             C_PFX3(c_o1_i2_, O1, I1, I2)
9454c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3)         C_PFX4(c_o1_i3_, O1, I1, I2, I3)
9464c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4)     C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4)
9474c22e840SRichard Henderson 
9484c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2)             C_PFX3(c_n1_i2_, O1, I1, I2)
949ca5bed07SRichard Henderson #define C_N1O1_I1(O1, O2, I1)           C_PFX3(c_n1o1_i1_, O1, O2, I1)
950fa645b48SRichard Henderson #define C_N2_I1(O1, O2, I1)             C_PFX3(c_n2_i1_, O1, O2, I1)
9514c22e840SRichard Henderson 
9524c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1)             C_PFX3(c_o2_i1_, O1, O2, I1)
9534c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2)         C_PFX4(c_o2_i2_, O1, O2, I1, I2)
9544c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3)     C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3)
9554c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4)
95622d2e535SIlya Leoshkevich #define C_N1_O1_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_n1_o1_i4_, O1, O2, I1, I2, I3, I4)
9574c22e840SRichard Henderson 
958139c1837SPaolo Bonzini #include "tcg-target.c.inc"
959c896fe29Sbellard 
9607857ee11SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
9617857ee11SRichard Henderson /* Validate CPUTLBDescFast placement. */
9627857ee11SRichard Henderson QEMU_BUILD_BUG_ON((int)(offsetof(CPUNegativeOffsetState, tlb.f[0]) -
9637857ee11SRichard Henderson                         sizeof(CPUNegativeOffsetState))
9647857ee11SRichard Henderson                   < MIN_TLB_MASK_TABLE_OFS);
9657857ee11SRichard Henderson #endif
9667857ee11SRichard Henderson 
967e8feb96fSEmilio G. Cota /*
9683468b59eSEmilio G. Cota  * All TCG threads except the parent (i.e. the one that called tcg_context_init
9693468b59eSEmilio G. Cota  * and registered the target's TCG globals) must register with this function
9703468b59eSEmilio G. Cota  * before initiating translation.
9713468b59eSEmilio G. Cota  *
9723468b59eSEmilio G. Cota  * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation
9733468b59eSEmilio G. Cota  * of tcg_region_init() for the reasoning behind this.
9743468b59eSEmilio G. Cota  *
9757893e42dSPhilippe Mathieu-Daudé  * In system-mode each caller registers its context in tcg_ctxs[]. Note that in
9767893e42dSPhilippe Mathieu-Daudé  * system-mode tcg_ctxs[] does not track tcg_ctx_init, since the initial context
9773468b59eSEmilio G. Cota  * is not used anymore for translation once this function is called.
9783468b59eSEmilio G. Cota  *
9797893e42dSPhilippe Mathieu-Daudé  * Not tracking tcg_init_ctx in tcg_ctxs[] in system-mode keeps code that
9807893e42dSPhilippe Mathieu-Daudé  * iterates over the array (e.g. tcg_code_size() the same for both system/user
9817893e42dSPhilippe Mathieu-Daudé  * modes.
9823468b59eSEmilio G. Cota  */
9833468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
9843468b59eSEmilio G. Cota void tcg_register_thread(void)
9853468b59eSEmilio G. Cota {
9863468b59eSEmilio G. Cota     tcg_ctx = &tcg_init_ctx;
9873468b59eSEmilio G. Cota }
9883468b59eSEmilio G. Cota #else
9893468b59eSEmilio G. Cota void tcg_register_thread(void)
9903468b59eSEmilio G. Cota {
9913468b59eSEmilio G. Cota     TCGContext *s = g_malloc(sizeof(*s));
9923468b59eSEmilio G. Cota     unsigned int i, n;
9933468b59eSEmilio G. Cota 
9943468b59eSEmilio G. Cota     *s = tcg_init_ctx;
9953468b59eSEmilio G. Cota 
9963468b59eSEmilio G. Cota     /* Relink mem_base.  */
9973468b59eSEmilio G. Cota     for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) {
9983468b59eSEmilio G. Cota         if (tcg_init_ctx.temps[i].mem_base) {
9993468b59eSEmilio G. Cota             ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps;
10003468b59eSEmilio G. Cota             tcg_debug_assert(b >= 0 && b < n);
10013468b59eSEmilio G. Cota             s->temps[i].mem_base = &s->temps[b];
10023468b59eSEmilio G. Cota         }
10033468b59eSEmilio G. Cota     }
10043468b59eSEmilio G. Cota 
10053468b59eSEmilio G. Cota     /* Claim an entry in tcg_ctxs */
10060e2d61cfSRichard Henderson     n = qatomic_fetch_inc(&tcg_cur_ctxs);
10070e2d61cfSRichard Henderson     g_assert(n < tcg_max_ctxs);
1008d73415a3SStefan Hajnoczi     qatomic_set(&tcg_ctxs[n], s);
10093468b59eSEmilio G. Cota 
101038b47b19SEmilio G. Cota     if (n > 0) {
1011bf042e8eSRichard Henderson         tcg_region_initial_alloc(s);
101238b47b19SEmilio G. Cota     }
101338b47b19SEmilio G. Cota 
10143468b59eSEmilio G. Cota     tcg_ctx = s;
10153468b59eSEmilio G. Cota }
10163468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */
10173468b59eSEmilio G. Cota 
1018c896fe29Sbellard /* pool based memory allocation */
1019c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size)
1020c896fe29Sbellard {
1021c896fe29Sbellard     TCGPool *p;
1022c896fe29Sbellard     int pool_size;
1023c896fe29Sbellard 
1024c896fe29Sbellard     if (size > TCG_POOL_CHUNK_SIZE) {
1025c896fe29Sbellard         /* big malloc: insert a new pool (XXX: could optimize) */
10267267c094SAnthony Liguori         p = g_malloc(sizeof(TCGPool) + size);
1027c896fe29Sbellard         p->size = size;
10284055299eSKirill Batuzov         p->next = s->pool_first_large;
10294055299eSKirill Batuzov         s->pool_first_large = p;
10304055299eSKirill Batuzov         return p->data;
1031c896fe29Sbellard     } else {
1032c896fe29Sbellard         p = s->pool_current;
1033c896fe29Sbellard         if (!p) {
1034c896fe29Sbellard             p = s->pool_first;
1035c896fe29Sbellard             if (!p)
1036c896fe29Sbellard                 goto new_pool;
1037c896fe29Sbellard         } else {
1038c896fe29Sbellard             if (!p->next) {
1039c896fe29Sbellard             new_pool:
1040c896fe29Sbellard                 pool_size = TCG_POOL_CHUNK_SIZE;
10417267c094SAnthony Liguori                 p = g_malloc(sizeof(TCGPool) + pool_size);
1042c896fe29Sbellard                 p->size = pool_size;
1043c896fe29Sbellard                 p->next = NULL;
1044a813e36fSRichard Henderson                 if (s->pool_current) {
1045c896fe29Sbellard                     s->pool_current->next = p;
1046a813e36fSRichard Henderson                 } else {
1047c896fe29Sbellard                     s->pool_first = p;
1048a813e36fSRichard Henderson                 }
1049c896fe29Sbellard             } else {
1050c896fe29Sbellard                 p = p->next;
1051c896fe29Sbellard             }
1052c896fe29Sbellard         }
1053c896fe29Sbellard     }
1054c896fe29Sbellard     s->pool_current = p;
1055c896fe29Sbellard     s->pool_cur = p->data + size;
1056c896fe29Sbellard     s->pool_end = p->data + p->size;
1057c896fe29Sbellard     return p->data;
1058c896fe29Sbellard }
1059c896fe29Sbellard 
1060c896fe29Sbellard void tcg_pool_reset(TCGContext *s)
1061c896fe29Sbellard {
10624055299eSKirill Batuzov     TCGPool *p, *t;
10634055299eSKirill Batuzov     for (p = s->pool_first_large; p; p = t) {
10644055299eSKirill Batuzov         t = p->next;
10654055299eSKirill Batuzov         g_free(p);
10664055299eSKirill Batuzov     }
10674055299eSKirill Batuzov     s->pool_first_large = NULL;
1068c896fe29Sbellard     s->pool_cur = s->pool_end = NULL;
1069c896fe29Sbellard     s->pool_current = NULL;
1070c896fe29Sbellard }
1071c896fe29Sbellard 
10728429a1caSRichard Henderson /*
10738429a1caSRichard Henderson  * Create TCGHelperInfo structures for "tcg/tcg-ldst.h" functions,
10748429a1caSRichard Henderson  * akin to what "exec/helper-tcg.h" does with DEF_HELPER_FLAGS_N.
10758429a1caSRichard Henderson  * We only use these for layout in tcg_out_ld_helper_ret and
10768429a1caSRichard Henderson  * tcg_out_st_helper_args, and share them between several of
10778429a1caSRichard Henderson  * the helpers, with the end result that it's easier to build manually.
10788429a1caSRichard Henderson  */
10798429a1caSRichard Henderson 
10808429a1caSRichard Henderson #if TCG_TARGET_REG_BITS == 32
10818429a1caSRichard Henderson # define dh_typecode_ttl  dh_typecode_i32
10828429a1caSRichard Henderson #else
10838429a1caSRichard Henderson # define dh_typecode_ttl  dh_typecode_i64
10848429a1caSRichard Henderson #endif
10858429a1caSRichard Henderson 
10868429a1caSRichard Henderson static TCGHelperInfo info_helper_ld32_mmu = {
10878429a1caSRichard Henderson     .flags = TCG_CALL_NO_WG,
10888429a1caSRichard Henderson     .typemask = dh_typemask(ttl, 0)  /* return tcg_target_ulong */
10898429a1caSRichard Henderson               | dh_typemask(env, 1)
109024e46e6cSRichard Henderson               | dh_typemask(i64, 2)  /* uint64_t addr */
10918429a1caSRichard Henderson               | dh_typemask(i32, 3)  /* unsigned oi */
10928429a1caSRichard Henderson               | dh_typemask(ptr, 4)  /* uintptr_t ra */
10938429a1caSRichard Henderson };
10948429a1caSRichard Henderson 
10958429a1caSRichard Henderson static TCGHelperInfo info_helper_ld64_mmu = {
10968429a1caSRichard Henderson     .flags = TCG_CALL_NO_WG,
10978429a1caSRichard Henderson     .typemask = dh_typemask(i64, 0)  /* return uint64_t */
10988429a1caSRichard Henderson               | dh_typemask(env, 1)
109924e46e6cSRichard Henderson               | dh_typemask(i64, 2)  /* uint64_t addr */
11008429a1caSRichard Henderson               | dh_typemask(i32, 3)  /* unsigned oi */
11018429a1caSRichard Henderson               | dh_typemask(ptr, 4)  /* uintptr_t ra */
11028429a1caSRichard Henderson };
11038429a1caSRichard Henderson 
1104ebebea53SRichard Henderson static TCGHelperInfo info_helper_ld128_mmu = {
1105ebebea53SRichard Henderson     .flags = TCG_CALL_NO_WG,
1106ebebea53SRichard Henderson     .typemask = dh_typemask(i128, 0) /* return Int128 */
1107ebebea53SRichard Henderson               | dh_typemask(env, 1)
110824e46e6cSRichard Henderson               | dh_typemask(i64, 2)  /* uint64_t addr */
1109ebebea53SRichard Henderson               | dh_typemask(i32, 3)  /* unsigned oi */
1110ebebea53SRichard Henderson               | dh_typemask(ptr, 4)  /* uintptr_t ra */
1111ebebea53SRichard Henderson };
1112ebebea53SRichard Henderson 
11138429a1caSRichard Henderson static TCGHelperInfo info_helper_st32_mmu = {
11148429a1caSRichard Henderson     .flags = TCG_CALL_NO_WG,
11158429a1caSRichard Henderson     .typemask = dh_typemask(void, 0)
11168429a1caSRichard Henderson               | dh_typemask(env, 1)
111724e46e6cSRichard Henderson               | dh_typemask(i64, 2)  /* uint64_t addr */
11188429a1caSRichard Henderson               | dh_typemask(i32, 3)  /* uint32_t data */
11198429a1caSRichard Henderson               | dh_typemask(i32, 4)  /* unsigned oi */
11208429a1caSRichard Henderson               | dh_typemask(ptr, 5)  /* uintptr_t ra */
11218429a1caSRichard Henderson };
11228429a1caSRichard Henderson 
11238429a1caSRichard Henderson static TCGHelperInfo info_helper_st64_mmu = {
11248429a1caSRichard Henderson     .flags = TCG_CALL_NO_WG,
11258429a1caSRichard Henderson     .typemask = dh_typemask(void, 0)
11268429a1caSRichard Henderson               | dh_typemask(env, 1)
112724e46e6cSRichard Henderson               | dh_typemask(i64, 2)  /* uint64_t addr */
11288429a1caSRichard Henderson               | dh_typemask(i64, 3)  /* uint64_t data */
11298429a1caSRichard Henderson               | dh_typemask(i32, 4)  /* unsigned oi */
11308429a1caSRichard Henderson               | dh_typemask(ptr, 5)  /* uintptr_t ra */
11318429a1caSRichard Henderson };
11328429a1caSRichard Henderson 
1133ebebea53SRichard Henderson static TCGHelperInfo info_helper_st128_mmu = {
1134ebebea53SRichard Henderson     .flags = TCG_CALL_NO_WG,
1135ebebea53SRichard Henderson     .typemask = dh_typemask(void, 0)
1136ebebea53SRichard Henderson               | dh_typemask(env, 1)
113724e46e6cSRichard Henderson               | dh_typemask(i64, 2)  /* uint64_t addr */
1138ebebea53SRichard Henderson               | dh_typemask(i128, 3) /* Int128 data */
1139ebebea53SRichard Henderson               | dh_typemask(i32, 4)  /* unsigned oi */
1140ebebea53SRichard Henderson               | dh_typemask(ptr, 5)  /* uintptr_t ra */
1141ebebea53SRichard Henderson };
1142ebebea53SRichard Henderson 
114322f15579SRichard Henderson #ifdef CONFIG_TCG_INTERPRETER
1144c6ef8c7bSPhilippe Mathieu-Daudé static ffi_type *typecode_to_ffi(int argmask)
1145c6ef8c7bSPhilippe Mathieu-Daudé {
1146e9709e17SRichard Henderson     /*
1147e9709e17SRichard Henderson      * libffi does not support __int128_t, so we have forced Int128
1148e9709e17SRichard Henderson      * to use the structure definition instead of the builtin type.
1149e9709e17SRichard Henderson      */
1150e9709e17SRichard Henderson     static ffi_type *ffi_type_i128_elements[3] = {
1151e9709e17SRichard Henderson         &ffi_type_uint64,
1152e9709e17SRichard Henderson         &ffi_type_uint64,
1153e9709e17SRichard Henderson         NULL
1154e9709e17SRichard Henderson     };
1155e9709e17SRichard Henderson     static ffi_type ffi_type_i128 = {
1156e9709e17SRichard Henderson         .size = 16,
1157e9709e17SRichard Henderson         .alignment = __alignof__(Int128),
1158e9709e17SRichard Henderson         .type = FFI_TYPE_STRUCT,
1159e9709e17SRichard Henderson         .elements = ffi_type_i128_elements,
1160e9709e17SRichard Henderson     };
1161e9709e17SRichard Henderson 
1162c6ef8c7bSPhilippe Mathieu-Daudé     switch (argmask) {
1163c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_void:
1164c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_void;
1165c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_i32:
1166c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_uint32;
1167c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_s32:
1168c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_sint32;
1169c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_i64:
1170c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_uint64;
1171c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_s64:
1172c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_sint64;
1173c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_ptr:
1174c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_pointer;
1175e9709e17SRichard Henderson     case dh_typecode_i128:
1176e9709e17SRichard Henderson         return &ffi_type_i128;
1177c6ef8c7bSPhilippe Mathieu-Daudé     }
1178c6ef8c7bSPhilippe Mathieu-Daudé     g_assert_not_reached();
1179c6ef8c7bSPhilippe Mathieu-Daudé }
11800c22e176SPhilippe Mathieu-Daudé 
1181d53106c9SRichard Henderson static ffi_cif *init_ffi_layout(TCGHelperInfo *info)
11820c22e176SPhilippe Mathieu-Daudé {
1183f9c4bb80SRichard Henderson     unsigned typemask = info->typemask;
11840c22e176SPhilippe Mathieu-Daudé     struct {
11850c22e176SPhilippe Mathieu-Daudé         ffi_cif cif;
11860c22e176SPhilippe Mathieu-Daudé         ffi_type *args[];
11870c22e176SPhilippe Mathieu-Daudé     } *ca;
11880c22e176SPhilippe Mathieu-Daudé     ffi_status status;
11890c22e176SPhilippe Mathieu-Daudé     int nargs;
11900c22e176SPhilippe Mathieu-Daudé 
11910c22e176SPhilippe Mathieu-Daudé     /* Ignoring the return type, find the last non-zero field. */
11920c22e176SPhilippe Mathieu-Daudé     nargs = 32 - clz32(typemask >> 3);
11930c22e176SPhilippe Mathieu-Daudé     nargs = DIV_ROUND_UP(nargs, 3);
1194e9709e17SRichard Henderson     assert(nargs <= MAX_CALL_IARGS);
11950c22e176SPhilippe Mathieu-Daudé 
11960c22e176SPhilippe Mathieu-Daudé     ca = g_malloc0(sizeof(*ca) + nargs * sizeof(ffi_type *));
11970c22e176SPhilippe Mathieu-Daudé     ca->cif.rtype = typecode_to_ffi(typemask & 7);
11980c22e176SPhilippe Mathieu-Daudé     ca->cif.nargs = nargs;
11990c22e176SPhilippe Mathieu-Daudé 
12000c22e176SPhilippe Mathieu-Daudé     if (nargs != 0) {
12010c22e176SPhilippe Mathieu-Daudé         ca->cif.arg_types = ca->args;
12020c22e176SPhilippe Mathieu-Daudé         for (int j = 0; j < nargs; ++j) {
12030c22e176SPhilippe Mathieu-Daudé             int typecode = extract32(typemask, (j + 1) * 3, 3);
12040c22e176SPhilippe Mathieu-Daudé             ca->args[j] = typecode_to_ffi(typecode);
12050c22e176SPhilippe Mathieu-Daudé         }
12060c22e176SPhilippe Mathieu-Daudé     }
12070c22e176SPhilippe Mathieu-Daudé 
12080c22e176SPhilippe Mathieu-Daudé     status = ffi_prep_cif(&ca->cif, FFI_DEFAULT_ABI, nargs,
12090c22e176SPhilippe Mathieu-Daudé                           ca->cif.rtype, ca->cif.arg_types);
12100c22e176SPhilippe Mathieu-Daudé     assert(status == FFI_OK);
12110c22e176SPhilippe Mathieu-Daudé 
1212d53106c9SRichard Henderson     return &ca->cif;
12130c22e176SPhilippe Mathieu-Daudé }
1214f9c4bb80SRichard Henderson 
1215d53106c9SRichard Henderson #define HELPER_INFO_INIT(I)      (&(I)->cif)
1216d53106c9SRichard Henderson #define HELPER_INFO_INIT_VAL(I)  init_ffi_layout(I)
1217d53106c9SRichard Henderson #else
1218d53106c9SRichard Henderson #define HELPER_INFO_INIT(I)      (&(I)->init)
1219d53106c9SRichard Henderson #define HELPER_INFO_INIT_VAL(I)  1
12200c22e176SPhilippe Mathieu-Daudé #endif /* CONFIG_TCG_INTERPRETER */
122122f15579SRichard Henderson 
1222338b61e9SRichard Henderson static inline bool arg_slot_reg_p(unsigned arg_slot)
1223338b61e9SRichard Henderson {
1224338b61e9SRichard Henderson     /*
1225338b61e9SRichard Henderson      * Split the sizeof away from the comparison to avoid Werror from
1226338b61e9SRichard Henderson      * "unsigned < 0 is always false", when iarg_regs is empty.
1227338b61e9SRichard Henderson      */
1228338b61e9SRichard Henderson     unsigned nreg = ARRAY_SIZE(tcg_target_call_iarg_regs);
1229338b61e9SRichard Henderson     return arg_slot < nreg;
1230338b61e9SRichard Henderson }
1231338b61e9SRichard Henderson 
1232d78e4a4fSRichard Henderson static inline int arg_slot_stk_ofs(unsigned arg_slot)
1233d78e4a4fSRichard Henderson {
1234d78e4a4fSRichard Henderson     unsigned max = TCG_STATIC_CALL_ARGS_SIZE / sizeof(tcg_target_long);
1235d78e4a4fSRichard Henderson     unsigned stk_slot = arg_slot - ARRAY_SIZE(tcg_target_call_iarg_regs);
1236d78e4a4fSRichard Henderson 
1237d78e4a4fSRichard Henderson     tcg_debug_assert(stk_slot < max);
1238d78e4a4fSRichard Henderson     return TCG_TARGET_CALL_STACK_OFFSET + stk_slot * sizeof(tcg_target_long);
1239d78e4a4fSRichard Henderson }
1240d78e4a4fSRichard Henderson 
124139004a71SRichard Henderson typedef struct TCGCumulativeArgs {
124239004a71SRichard Henderson     int arg_idx;                /* tcg_gen_callN args[] */
124339004a71SRichard Henderson     int info_in_idx;            /* TCGHelperInfo in[] */
124439004a71SRichard Henderson     int arg_slot;               /* regs+stack slot */
124539004a71SRichard Henderson     int ref_slot;               /* stack slots for references */
124639004a71SRichard Henderson } TCGCumulativeArgs;
124739004a71SRichard Henderson 
124839004a71SRichard Henderson static void layout_arg_even(TCGCumulativeArgs *cum)
124939004a71SRichard Henderson {
125039004a71SRichard Henderson     cum->arg_slot += cum->arg_slot & 1;
125139004a71SRichard Henderson }
125239004a71SRichard Henderson 
125339004a71SRichard Henderson static void layout_arg_1(TCGCumulativeArgs *cum, TCGHelperInfo *info,
125439004a71SRichard Henderson                          TCGCallArgumentKind kind)
125539004a71SRichard Henderson {
125639004a71SRichard Henderson     TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx];
125739004a71SRichard Henderson 
125839004a71SRichard Henderson     *loc = (TCGCallArgumentLoc){
125939004a71SRichard Henderson         .kind = kind,
126039004a71SRichard Henderson         .arg_idx = cum->arg_idx,
126139004a71SRichard Henderson         .arg_slot = cum->arg_slot,
126239004a71SRichard Henderson     };
126339004a71SRichard Henderson     cum->info_in_idx++;
126439004a71SRichard Henderson     cum->arg_slot++;
126539004a71SRichard Henderson }
126639004a71SRichard Henderson 
126739004a71SRichard Henderson static void layout_arg_normal_n(TCGCumulativeArgs *cum,
126839004a71SRichard Henderson                                 TCGHelperInfo *info, int n)
126939004a71SRichard Henderson {
127039004a71SRichard Henderson     TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx];
127139004a71SRichard Henderson 
127239004a71SRichard Henderson     for (int i = 0; i < n; ++i) {
127339004a71SRichard Henderson         /* Layout all using the same arg_idx, adjusting the subindex. */
127439004a71SRichard Henderson         loc[i] = (TCGCallArgumentLoc){
127539004a71SRichard Henderson             .kind = TCG_CALL_ARG_NORMAL,
127639004a71SRichard Henderson             .arg_idx = cum->arg_idx,
127739004a71SRichard Henderson             .tmp_subindex = i,
127839004a71SRichard Henderson             .arg_slot = cum->arg_slot + i,
127939004a71SRichard Henderson         };
128039004a71SRichard Henderson     }
128139004a71SRichard Henderson     cum->info_in_idx += n;
128239004a71SRichard Henderson     cum->arg_slot += n;
128339004a71SRichard Henderson }
128439004a71SRichard Henderson 
1285313bdea8SRichard Henderson static void layout_arg_by_ref(TCGCumulativeArgs *cum, TCGHelperInfo *info)
1286313bdea8SRichard Henderson {
1287313bdea8SRichard Henderson     TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx];
1288313bdea8SRichard Henderson     int n = 128 / TCG_TARGET_REG_BITS;
1289313bdea8SRichard Henderson 
1290313bdea8SRichard Henderson     /* The first subindex carries the pointer. */
1291313bdea8SRichard Henderson     layout_arg_1(cum, info, TCG_CALL_ARG_BY_REF);
1292313bdea8SRichard Henderson 
1293313bdea8SRichard Henderson     /*
1294313bdea8SRichard Henderson      * The callee is allowed to clobber memory associated with
1295313bdea8SRichard Henderson      * structure pass by-reference.  Therefore we must make copies.
1296313bdea8SRichard Henderson      * Allocate space from "ref_slot", which will be adjusted to
1297313bdea8SRichard Henderson      * follow the parameters on the stack.
1298313bdea8SRichard Henderson      */
1299313bdea8SRichard Henderson     loc[0].ref_slot = cum->ref_slot;
1300313bdea8SRichard Henderson 
1301313bdea8SRichard Henderson     /*
1302313bdea8SRichard Henderson      * Subsequent words also go into the reference slot, but
1303313bdea8SRichard Henderson      * do not accumulate into the regular arguments.
1304313bdea8SRichard Henderson      */
1305313bdea8SRichard Henderson     for (int i = 1; i < n; ++i) {
1306313bdea8SRichard Henderson         loc[i] = (TCGCallArgumentLoc){
1307313bdea8SRichard Henderson             .kind = TCG_CALL_ARG_BY_REF_N,
1308313bdea8SRichard Henderson             .arg_idx = cum->arg_idx,
1309313bdea8SRichard Henderson             .tmp_subindex = i,
1310313bdea8SRichard Henderson             .ref_slot = cum->ref_slot + i,
1311313bdea8SRichard Henderson         };
1312313bdea8SRichard Henderson     }
1313e18ed26cSRichard Henderson     cum->info_in_idx += n - 1;  /* i=0 accounted for in layout_arg_1 */
1314313bdea8SRichard Henderson     cum->ref_slot += n;
1315313bdea8SRichard Henderson }
1316313bdea8SRichard Henderson 
131739004a71SRichard Henderson static void init_call_layout(TCGHelperInfo *info)
131839004a71SRichard Henderson {
131939004a71SRichard Henderson     int max_reg_slots = ARRAY_SIZE(tcg_target_call_iarg_regs);
132039004a71SRichard Henderson     int max_stk_slots = TCG_STATIC_CALL_ARGS_SIZE / sizeof(tcg_target_long);
132139004a71SRichard Henderson     unsigned typemask = info->typemask;
132239004a71SRichard Henderson     unsigned typecode;
132339004a71SRichard Henderson     TCGCumulativeArgs cum = { };
132439004a71SRichard Henderson 
132539004a71SRichard Henderson     /*
132639004a71SRichard Henderson      * Parse and place any function return value.
132739004a71SRichard Henderson      */
132839004a71SRichard Henderson     typecode = typemask & 7;
132939004a71SRichard Henderson     switch (typecode) {
133039004a71SRichard Henderson     case dh_typecode_void:
133139004a71SRichard Henderson         info->nr_out = 0;
133239004a71SRichard Henderson         break;
133339004a71SRichard Henderson     case dh_typecode_i32:
133439004a71SRichard Henderson     case dh_typecode_s32:
133539004a71SRichard Henderson     case dh_typecode_ptr:
133639004a71SRichard Henderson         info->nr_out = 1;
133739004a71SRichard Henderson         info->out_kind = TCG_CALL_RET_NORMAL;
133839004a71SRichard Henderson         break;
133939004a71SRichard Henderson     case dh_typecode_i64:
134039004a71SRichard Henderson     case dh_typecode_s64:
134139004a71SRichard Henderson         info->nr_out = 64 / TCG_TARGET_REG_BITS;
134239004a71SRichard Henderson         info->out_kind = TCG_CALL_RET_NORMAL;
13435e3d0c19SRichard Henderson         /* Query the last register now to trigger any assert early. */
13445e3d0c19SRichard Henderson         tcg_target_call_oarg_reg(info->out_kind, info->nr_out - 1);
1345466d3759SRichard Henderson         break;
1346466d3759SRichard Henderson     case dh_typecode_i128:
1347466d3759SRichard Henderson         info->nr_out = 128 / TCG_TARGET_REG_BITS;
13485427a9a7SRichard Henderson         info->out_kind = TCG_TARGET_CALL_RET_I128;
13495427a9a7SRichard Henderson         switch (TCG_TARGET_CALL_RET_I128) {
1350466d3759SRichard Henderson         case TCG_CALL_RET_NORMAL:
13515e3d0c19SRichard Henderson             /* Query the last register now to trigger any assert early. */
13525e3d0c19SRichard Henderson             tcg_target_call_oarg_reg(info->out_kind, info->nr_out - 1);
1353466d3759SRichard Henderson             break;
1354c6556aa0SRichard Henderson         case TCG_CALL_RET_BY_VEC:
1355c6556aa0SRichard Henderson             /* Query the single register now to trigger any assert early. */
1356c6556aa0SRichard Henderson             tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0);
1357c6556aa0SRichard Henderson             break;
1358313bdea8SRichard Henderson         case TCG_CALL_RET_BY_REF:
1359313bdea8SRichard Henderson             /*
1360313bdea8SRichard Henderson              * Allocate the first argument to the output.
1361313bdea8SRichard Henderson              * We don't need to store this anywhere, just make it
1362313bdea8SRichard Henderson              * unavailable for use in the input loop below.
1363313bdea8SRichard Henderson              */
1364313bdea8SRichard Henderson             cum.arg_slot = 1;
1365313bdea8SRichard Henderson             break;
1366466d3759SRichard Henderson         default:
1367466d3759SRichard Henderson             qemu_build_not_reached();
1368466d3759SRichard Henderson         }
136939004a71SRichard Henderson         break;
137039004a71SRichard Henderson     default:
137139004a71SRichard Henderson         g_assert_not_reached();
137239004a71SRichard Henderson     }
137339004a71SRichard Henderson 
137439004a71SRichard Henderson     /*
137539004a71SRichard Henderson      * Parse and place function arguments.
137639004a71SRichard Henderson      */
137739004a71SRichard Henderson     for (typemask >>= 3; typemask; typemask >>= 3, cum.arg_idx++) {
137839004a71SRichard Henderson         TCGCallArgumentKind kind;
137939004a71SRichard Henderson         TCGType type;
138039004a71SRichard Henderson 
138139004a71SRichard Henderson         typecode = typemask & 7;
138239004a71SRichard Henderson         switch (typecode) {
138339004a71SRichard Henderson         case dh_typecode_i32:
138439004a71SRichard Henderson         case dh_typecode_s32:
138539004a71SRichard Henderson             type = TCG_TYPE_I32;
138639004a71SRichard Henderson             break;
138739004a71SRichard Henderson         case dh_typecode_i64:
138839004a71SRichard Henderson         case dh_typecode_s64:
138939004a71SRichard Henderson             type = TCG_TYPE_I64;
139039004a71SRichard Henderson             break;
139139004a71SRichard Henderson         case dh_typecode_ptr:
139239004a71SRichard Henderson             type = TCG_TYPE_PTR;
139339004a71SRichard Henderson             break;
1394466d3759SRichard Henderson         case dh_typecode_i128:
1395466d3759SRichard Henderson             type = TCG_TYPE_I128;
1396466d3759SRichard Henderson             break;
139739004a71SRichard Henderson         default:
139839004a71SRichard Henderson             g_assert_not_reached();
139939004a71SRichard Henderson         }
140039004a71SRichard Henderson 
140139004a71SRichard Henderson         switch (type) {
140239004a71SRichard Henderson         case TCG_TYPE_I32:
140339004a71SRichard Henderson             switch (TCG_TARGET_CALL_ARG_I32) {
140439004a71SRichard Henderson             case TCG_CALL_ARG_EVEN:
140539004a71SRichard Henderson                 layout_arg_even(&cum);
140639004a71SRichard Henderson                 /* fall through */
140739004a71SRichard Henderson             case TCG_CALL_ARG_NORMAL:
140839004a71SRichard Henderson                 layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL);
140939004a71SRichard Henderson                 break;
141039004a71SRichard Henderson             case TCG_CALL_ARG_EXTEND:
141139004a71SRichard Henderson                 kind = TCG_CALL_ARG_EXTEND_U + (typecode & 1);
141239004a71SRichard Henderson                 layout_arg_1(&cum, info, kind);
141339004a71SRichard Henderson                 break;
141439004a71SRichard Henderson             default:
141539004a71SRichard Henderson                 qemu_build_not_reached();
141639004a71SRichard Henderson             }
141739004a71SRichard Henderson             break;
141839004a71SRichard Henderson 
141939004a71SRichard Henderson         case TCG_TYPE_I64:
142039004a71SRichard Henderson             switch (TCG_TARGET_CALL_ARG_I64) {
142139004a71SRichard Henderson             case TCG_CALL_ARG_EVEN:
142239004a71SRichard Henderson                 layout_arg_even(&cum);
142339004a71SRichard Henderson                 /* fall through */
142439004a71SRichard Henderson             case TCG_CALL_ARG_NORMAL:
142539004a71SRichard Henderson                 if (TCG_TARGET_REG_BITS == 32) {
142639004a71SRichard Henderson                     layout_arg_normal_n(&cum, info, 2);
142739004a71SRichard Henderson                 } else {
142839004a71SRichard Henderson                     layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL);
142939004a71SRichard Henderson                 }
143039004a71SRichard Henderson                 break;
143139004a71SRichard Henderson             default:
143239004a71SRichard Henderson                 qemu_build_not_reached();
143339004a71SRichard Henderson             }
143439004a71SRichard Henderson             break;
143539004a71SRichard Henderson 
1436466d3759SRichard Henderson         case TCG_TYPE_I128:
14375427a9a7SRichard Henderson             switch (TCG_TARGET_CALL_ARG_I128) {
1438466d3759SRichard Henderson             case TCG_CALL_ARG_EVEN:
1439466d3759SRichard Henderson                 layout_arg_even(&cum);
1440466d3759SRichard Henderson                 /* fall through */
1441466d3759SRichard Henderson             case TCG_CALL_ARG_NORMAL:
1442466d3759SRichard Henderson                 layout_arg_normal_n(&cum, info, 128 / TCG_TARGET_REG_BITS);
1443466d3759SRichard Henderson                 break;
1444313bdea8SRichard Henderson             case TCG_CALL_ARG_BY_REF:
1445313bdea8SRichard Henderson                 layout_arg_by_ref(&cum, info);
1446313bdea8SRichard Henderson                 break;
1447466d3759SRichard Henderson             default:
1448466d3759SRichard Henderson                 qemu_build_not_reached();
1449466d3759SRichard Henderson             }
1450466d3759SRichard Henderson             break;
1451466d3759SRichard Henderson 
145239004a71SRichard Henderson         default:
145339004a71SRichard Henderson             g_assert_not_reached();
145439004a71SRichard Henderson         }
145539004a71SRichard Henderson     }
145639004a71SRichard Henderson     info->nr_in = cum.info_in_idx;
145739004a71SRichard Henderson 
145839004a71SRichard Henderson     /* Validate that we didn't overrun the input array. */
145939004a71SRichard Henderson     assert(cum.info_in_idx <= ARRAY_SIZE(info->in));
146039004a71SRichard Henderson     /* Validate the backend has enough argument space. */
146139004a71SRichard Henderson     assert(cum.arg_slot <= max_reg_slots + max_stk_slots);
1462313bdea8SRichard Henderson 
1463313bdea8SRichard Henderson     /*
1464313bdea8SRichard Henderson      * Relocate the "ref_slot" area to the end of the parameters.
1465313bdea8SRichard Henderson      * Minimizing this stack offset helps code size for x86,
1466313bdea8SRichard Henderson      * which has a signed 8-bit offset encoding.
1467313bdea8SRichard Henderson      */
1468313bdea8SRichard Henderson     if (cum.ref_slot != 0) {
1469313bdea8SRichard Henderson         int ref_base = 0;
1470313bdea8SRichard Henderson 
1471313bdea8SRichard Henderson         if (cum.arg_slot > max_reg_slots) {
1472313bdea8SRichard Henderson             int align = __alignof(Int128) / sizeof(tcg_target_long);
1473313bdea8SRichard Henderson 
1474313bdea8SRichard Henderson             ref_base = cum.arg_slot - max_reg_slots;
1475313bdea8SRichard Henderson             if (align > 1) {
1476313bdea8SRichard Henderson                 ref_base = ROUND_UP(ref_base, align);
1477313bdea8SRichard Henderson             }
1478313bdea8SRichard Henderson         }
1479313bdea8SRichard Henderson         assert(ref_base + cum.ref_slot <= max_stk_slots);
1480d78e4a4fSRichard Henderson         ref_base += max_reg_slots;
1481313bdea8SRichard Henderson 
1482313bdea8SRichard Henderson         if (ref_base != 0) {
1483313bdea8SRichard Henderson             for (int i = cum.info_in_idx - 1; i >= 0; --i) {
1484313bdea8SRichard Henderson                 TCGCallArgumentLoc *loc = &info->in[i];
1485313bdea8SRichard Henderson                 switch (loc->kind) {
1486313bdea8SRichard Henderson                 case TCG_CALL_ARG_BY_REF:
1487313bdea8SRichard Henderson                 case TCG_CALL_ARG_BY_REF_N:
1488313bdea8SRichard Henderson                     loc->ref_slot += ref_base;
1489313bdea8SRichard Henderson                     break;
1490313bdea8SRichard Henderson                 default:
1491313bdea8SRichard Henderson                     break;
1492313bdea8SRichard Henderson                 }
1493313bdea8SRichard Henderson             }
1494313bdea8SRichard Henderson         }
1495313bdea8SRichard Henderson     }
149639004a71SRichard Henderson }
149739004a71SRichard Henderson 
149891478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)];
1499501fb3daSRichard Henderson static void process_constraint_sets(void);
15001c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
15011c2adb95SRichard Henderson                                             TCGReg reg, const char *name);
150291478cefSRichard Henderson 
150343b972b7SRichard Henderson static void tcg_context_init(unsigned max_cpus)
1504c896fe29Sbellard {
1505a76aabd3SRichard Henderson     TCGContext *s = &tcg_init_ctx;
15063e80824eSRichard Henderson     int n, i;
15071c2adb95SRichard Henderson     TCGTemp *ts;
1508c896fe29Sbellard 
1509c896fe29Sbellard     memset(s, 0, sizeof(*s));
1510c896fe29Sbellard     s->nb_globals = 0;
1511c896fe29Sbellard 
15128429a1caSRichard Henderson     init_call_layout(&info_helper_ld32_mmu);
15138429a1caSRichard Henderson     init_call_layout(&info_helper_ld64_mmu);
1514ebebea53SRichard Henderson     init_call_layout(&info_helper_ld128_mmu);
15158429a1caSRichard Henderson     init_call_layout(&info_helper_st32_mmu);
15168429a1caSRichard Henderson     init_call_layout(&info_helper_st64_mmu);
1517ebebea53SRichard Henderson     init_call_layout(&info_helper_st128_mmu);
15188429a1caSRichard Henderson 
1519c896fe29Sbellard     tcg_target_init(s);
1520501fb3daSRichard Henderson     process_constraint_sets();
152191478cefSRichard Henderson 
152291478cefSRichard Henderson     /* Reverse the order of the saved registers, assuming they're all at
152391478cefSRichard Henderson        the start of tcg_target_reg_alloc_order.  */
152491478cefSRichard Henderson     for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) {
152591478cefSRichard Henderson         int r = tcg_target_reg_alloc_order[n];
152691478cefSRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) {
152791478cefSRichard Henderson             break;
152891478cefSRichard Henderson         }
152991478cefSRichard Henderson     }
153091478cefSRichard Henderson     for (i = 0; i < n; ++i) {
153191478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i];
153291478cefSRichard Henderson     }
153391478cefSRichard Henderson     for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) {
153491478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i];
153591478cefSRichard Henderson     }
1536b1311c4aSEmilio G. Cota 
1537b1311c4aSEmilio G. Cota     tcg_ctx = s;
15383468b59eSEmilio G. Cota     /*
15393468b59eSEmilio G. Cota      * In user-mode we simply share the init context among threads, since we
15403468b59eSEmilio G. Cota      * use a single region. See the documentation tcg_region_init() for the
15413468b59eSEmilio G. Cota      * reasoning behind this.
15427893e42dSPhilippe Mathieu-Daudé      * In system-mode we will have at most max_cpus TCG threads.
15433468b59eSEmilio G. Cota      */
15443468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
1545df2cce29SEmilio G. Cota     tcg_ctxs = &tcg_ctx;
15460e2d61cfSRichard Henderson     tcg_cur_ctxs = 1;
15470e2d61cfSRichard Henderson     tcg_max_ctxs = 1;
15483468b59eSEmilio G. Cota #else
15490e2d61cfSRichard Henderson     tcg_max_ctxs = max_cpus;
15500e2d61cfSRichard Henderson     tcg_ctxs = g_new0(TCGContext *, max_cpus);
15513468b59eSEmilio G. Cota #endif
15521c2adb95SRichard Henderson 
15531c2adb95SRichard Henderson     tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0));
15541c2adb95SRichard Henderson     ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env");
1555ad75a51eSRichard Henderson     tcg_env = temp_tcgv_ptr(ts);
15569002ec79SRichard Henderson }
1557b03cce8eSbellard 
155843b972b7SRichard Henderson void tcg_init(size_t tb_size, int splitwx, unsigned max_cpus)
1559a76aabd3SRichard Henderson {
156043b972b7SRichard Henderson     tcg_context_init(max_cpus);
156143b972b7SRichard Henderson     tcg_region_init(tb_size, splitwx, max_cpus);
1562a76aabd3SRichard Henderson }
1563a76aabd3SRichard Henderson 
15646e3b2bfdSEmilio G. Cota /*
15656e3b2bfdSEmilio G. Cota  * Allocate TBs right before their corresponding translated code, making
15666e3b2bfdSEmilio G. Cota  * sure that TBs and code are on different cache lines.
15676e3b2bfdSEmilio G. Cota  */
15686e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s)
15696e3b2bfdSEmilio G. Cota {
15706e3b2bfdSEmilio G. Cota     uintptr_t align = qemu_icache_linesize;
15716e3b2bfdSEmilio G. Cota     TranslationBlock *tb;
15726e3b2bfdSEmilio G. Cota     void *next;
15736e3b2bfdSEmilio G. Cota 
1574e8feb96fSEmilio G. Cota  retry:
15756e3b2bfdSEmilio G. Cota     tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align);
15766e3b2bfdSEmilio G. Cota     next = (void *)ROUND_UP((uintptr_t)(tb + 1), align);
15776e3b2bfdSEmilio G. Cota 
15786e3b2bfdSEmilio G. Cota     if (unlikely(next > s->code_gen_highwater)) {
1579e8feb96fSEmilio G. Cota         if (tcg_region_alloc(s)) {
15806e3b2bfdSEmilio G. Cota             return NULL;
15816e3b2bfdSEmilio G. Cota         }
1582e8feb96fSEmilio G. Cota         goto retry;
1583e8feb96fSEmilio G. Cota     }
1584d73415a3SStefan Hajnoczi     qatomic_set(&s->code_gen_ptr, next);
15856e3b2bfdSEmilio G. Cota     return tb;
15866e3b2bfdSEmilio G. Cota }
15876e3b2bfdSEmilio G. Cota 
1588935f75aeSRichard Henderson void tcg_prologue_init(void)
15899002ec79SRichard Henderson {
1590935f75aeSRichard Henderson     TCGContext *s = tcg_ctx;
1591b0a0794aSRichard Henderson     size_t prologue_size;
15928163b749SRichard Henderson 
1593b0a0794aSRichard Henderson     s->code_ptr = s->code_gen_ptr;
1594b0a0794aSRichard Henderson     s->code_buf = s->code_gen_ptr;
15955b38ee31SRichard Henderson     s->data_gen_ptr = NULL;
1596b91ccb31SRichard Henderson 
1597b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
1598b0a0794aSRichard Henderson     tcg_qemu_tb_exec = (tcg_prologue_fn *)tcg_splitwx_to_rx(s->code_ptr);
1599b91ccb31SRichard Henderson #endif
16008163b749SRichard Henderson 
16015b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
16025b38ee31SRichard Henderson     s->pool_labels = NULL;
16035b38ee31SRichard Henderson #endif
16045b38ee31SRichard Henderson 
1605653b87ebSRoman Bolshakov     qemu_thread_jit_write();
16068163b749SRichard Henderson     /* Generate the prologue.  */
1607b03cce8eSbellard     tcg_target_qemu_prologue(s);
16085b38ee31SRichard Henderson 
16095b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
16105b38ee31SRichard Henderson     /* Allow the prologue to put e.g. guest_base into a pool entry.  */
16115b38ee31SRichard Henderson     {
16121768987bSRichard Henderson         int result = tcg_out_pool_finalize(s);
16131768987bSRichard Henderson         tcg_debug_assert(result == 0);
16145b38ee31SRichard Henderson     }
16155b38ee31SRichard Henderson #endif
16165b38ee31SRichard Henderson 
1617b0a0794aSRichard Henderson     prologue_size = tcg_current_code_size(s);
16185584e2dbSIlya Leoshkevich     perf_report_prologue(s->code_gen_ptr, prologue_size);
1619b0a0794aSRichard Henderson 
1620df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
1621b0a0794aSRichard Henderson     flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf),
1622b0a0794aSRichard Henderson                         (uintptr_t)s->code_buf, prologue_size);
1623df5d2b16SRichard Henderson #endif
16248163b749SRichard Henderson 
1625d6b64b2bSRichard Henderson     if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) {
1626c60f599bSRichard Henderson         FILE *logfile = qemu_log_trylock();
162778b54858SRichard Henderson         if (logfile) {
162878b54858SRichard Henderson             fprintf(logfile, "PROLOGUE: [size=%zu]\n", prologue_size);
16295b38ee31SRichard Henderson             if (s->data_gen_ptr) {
1630b0a0794aSRichard Henderson                 size_t code_size = s->data_gen_ptr - s->code_gen_ptr;
16315b38ee31SRichard Henderson                 size_t data_size = prologue_size - code_size;
16325b38ee31SRichard Henderson                 size_t i;
16335b38ee31SRichard Henderson 
163478b54858SRichard Henderson                 disas(logfile, s->code_gen_ptr, code_size);
16355b38ee31SRichard Henderson 
16365b38ee31SRichard Henderson                 for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) {
16375b38ee31SRichard Henderson                     if (sizeof(tcg_target_ulong) == 8) {
163878b54858SRichard Henderson                         fprintf(logfile,
163978b54858SRichard Henderson                                 "0x%08" PRIxPTR ":  .quad  0x%016" PRIx64 "\n",
16405b38ee31SRichard Henderson                                 (uintptr_t)s->data_gen_ptr + i,
16415b38ee31SRichard Henderson                                 *(uint64_t *)(s->data_gen_ptr + i));
16425b38ee31SRichard Henderson                     } else {
164378b54858SRichard Henderson                         fprintf(logfile,
164478b54858SRichard Henderson                                 "0x%08" PRIxPTR ":  .long  0x%08x\n",
16455b38ee31SRichard Henderson                                 (uintptr_t)s->data_gen_ptr + i,
16465b38ee31SRichard Henderson                                 *(uint32_t *)(s->data_gen_ptr + i));
16475b38ee31SRichard Henderson                     }
16485b38ee31SRichard Henderson                 }
16495b38ee31SRichard Henderson             } else {
165078b54858SRichard Henderson                 disas(logfile, s->code_gen_ptr, prologue_size);
16515b38ee31SRichard Henderson             }
165278b54858SRichard Henderson             fprintf(logfile, "\n");
1653fc59d2d8SRobert Foley             qemu_log_unlock(logfile);
1654d6b64b2bSRichard Henderson         }
165578b54858SRichard Henderson     }
1656cedbcb01SEmilio G. Cota 
16576eea0434SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
16586eea0434SRichard Henderson     /*
16596eea0434SRichard Henderson      * Assert that goto_ptr is implemented completely, setting an epilogue.
16606eea0434SRichard Henderson      * For tci, we use NULL as the signal to return from the interpreter,
16616eea0434SRichard Henderson      * so skip this check.
16626eea0434SRichard Henderson      */
16638b5c2b62SRichard Henderson     tcg_debug_assert(tcg_code_gen_epilogue != NULL);
16646eea0434SRichard Henderson #endif
1665d1c74ab3SRichard Henderson 
1666d1c74ab3SRichard Henderson     tcg_region_prologue_set(s);
1667c896fe29Sbellard }
1668c896fe29Sbellard 
1669c896fe29Sbellard void tcg_func_start(TCGContext *s)
1670c896fe29Sbellard {
1671c896fe29Sbellard     tcg_pool_reset(s);
1672c896fe29Sbellard     s->nb_temps = s->nb_globals;
16730ec9eabcSRichard Henderson 
16740ec9eabcSRichard Henderson     /* No temps have been previously allocated for size or locality.  */
167504e006abSRichard Henderson     tcg_temp_ebb_reset_freed(s);
16760ec9eabcSRichard Henderson 
1677c0522136SRichard Henderson     /* No constant temps have been previously allocated. */
1678c0522136SRichard Henderson     for (int i = 0; i < TCG_TYPE_COUNT; ++i) {
1679c0522136SRichard Henderson         if (s->const_table[i]) {
1680c0522136SRichard Henderson             g_hash_table_remove_all(s->const_table[i]);
1681c0522136SRichard Henderson         }
1682c0522136SRichard Henderson     }
1683c0522136SRichard Henderson 
1684abebf925SRichard Henderson     s->nb_ops = 0;
1685c896fe29Sbellard     s->nb_labels = 0;
1686c896fe29Sbellard     s->current_frame_offset = s->frame_start;
1687c896fe29Sbellard 
16880a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG
16890a209d4bSRichard Henderson     s->goto_tb_issue_mask = 0;
16900a209d4bSRichard Henderson #endif
16910a209d4bSRichard Henderson 
169215fa08f8SRichard Henderson     QTAILQ_INIT(&s->ops);
169315fa08f8SRichard Henderson     QTAILQ_INIT(&s->free_ops);
169407843f75SRichard Henderson     s->emit_before_op = NULL;
1695bef16ab4SRichard Henderson     QSIMPLEQ_INIT(&s->labels);
16964baf3978SRichard Henderson 
16974baf3978SRichard Henderson     tcg_debug_assert(s->addr_type == TCG_TYPE_I32 ||
16984baf3978SRichard Henderson                      s->addr_type == TCG_TYPE_I64);
1699d0a9bb5eSRichard Henderson 
1700747bd69dSRichard Henderson     tcg_debug_assert(s->insn_start_words > 0);
1701c896fe29Sbellard }
1702c896fe29Sbellard 
1703ae30e866SRichard Henderson static TCGTemp *tcg_temp_alloc(TCGContext *s)
17047ca4b752SRichard Henderson {
17057ca4b752SRichard Henderson     int n = s->nb_temps++;
1706ae30e866SRichard Henderson 
1707ae30e866SRichard Henderson     if (n >= TCG_MAX_TEMPS) {
1708db6b7d0cSRichard Henderson         tcg_raise_tb_overflow(s);
1709ae30e866SRichard Henderson     }
17107ca4b752SRichard Henderson     return memset(&s->temps[n], 0, sizeof(TCGTemp));
17117ca4b752SRichard Henderson }
17127ca4b752SRichard Henderson 
1713ae30e866SRichard Henderson static TCGTemp *tcg_global_alloc(TCGContext *s)
17147ca4b752SRichard Henderson {
1715fa477d25SRichard Henderson     TCGTemp *ts;
1716fa477d25SRichard Henderson 
17177ca4b752SRichard Henderson     tcg_debug_assert(s->nb_globals == s->nb_temps);
1718ae30e866SRichard Henderson     tcg_debug_assert(s->nb_globals < TCG_MAX_TEMPS);
17197ca4b752SRichard Henderson     s->nb_globals++;
1720fa477d25SRichard Henderson     ts = tcg_temp_alloc(s);
1721ee17db83SRichard Henderson     ts->kind = TEMP_GLOBAL;
1722fa477d25SRichard Henderson 
1723fa477d25SRichard Henderson     return ts;
1724c896fe29Sbellard }
1725c896fe29Sbellard 
1726085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
1727b6638662SRichard Henderson                                             TCGReg reg, const char *name)
1728c896fe29Sbellard {
1729c896fe29Sbellard     TCGTemp *ts;
1730c896fe29Sbellard 
17311a057554SRichard Henderson     tcg_debug_assert(TCG_TARGET_REG_BITS == 64 || type == TCG_TYPE_I32);
17327ca4b752SRichard Henderson 
17337ca4b752SRichard Henderson     ts = tcg_global_alloc(s);
1734c896fe29Sbellard     ts->base_type = type;
1735c896fe29Sbellard     ts->type = type;
1736ee17db83SRichard Henderson     ts->kind = TEMP_FIXED;
1737c896fe29Sbellard     ts->reg = reg;
1738c896fe29Sbellard     ts->name = name;
1739c896fe29Sbellard     tcg_regset_set_reg(s->reserved_regs, reg);
17407ca4b752SRichard Henderson 
1741085272b3SRichard Henderson     return ts;
1742a7812ae4Spbrook }
1743a7812ae4Spbrook 
1744b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size)
1745a7812ae4Spbrook {
1746b3a62939SRichard Henderson     s->frame_start = start;
1747b3a62939SRichard Henderson     s->frame_end = start + size;
1748085272b3SRichard Henderson     s->frame_temp
1749085272b3SRichard Henderson         = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame");
1750b3a62939SRichard Henderson }
1751a7812ae4Spbrook 
17524643f3e0SRichard Henderson static TCGTemp *tcg_global_mem_new_internal(TCGv_ptr base, intptr_t offset,
17534643f3e0SRichard Henderson                                             const char *name, TCGType type)
1754c896fe29Sbellard {
1755b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1756dc41aa7dSRichard Henderson     TCGTemp *base_ts = tcgv_ptr_temp(base);
17577ca4b752SRichard Henderson     TCGTemp *ts = tcg_global_alloc(s);
1758aef85402SRichard Henderson     int indirect_reg = 0;
1759c896fe29Sbellard 
1760c0522136SRichard Henderson     switch (base_ts->kind) {
1761c0522136SRichard Henderson     case TEMP_FIXED:
1762c0522136SRichard Henderson         break;
1763c0522136SRichard Henderson     case TEMP_GLOBAL:
17645a18407fSRichard Henderson         /* We do not support double-indirect registers.  */
17655a18407fSRichard Henderson         tcg_debug_assert(!base_ts->indirect_reg);
1766b3915dbbSRichard Henderson         base_ts->indirect_base = 1;
17675a18407fSRichard Henderson         s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64
17685a18407fSRichard Henderson                             ? 2 : 1);
17695a18407fSRichard Henderson         indirect_reg = 1;
1770c0522136SRichard Henderson         break;
1771c0522136SRichard Henderson     default:
1772c0522136SRichard Henderson         g_assert_not_reached();
1773b3915dbbSRichard Henderson     }
1774b3915dbbSRichard Henderson 
17757ca4b752SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
17767ca4b752SRichard Henderson         TCGTemp *ts2 = tcg_global_alloc(s);
1777c896fe29Sbellard         char buf[64];
17787ca4b752SRichard Henderson 
17797ca4b752SRichard Henderson         ts->base_type = TCG_TYPE_I64;
1780c896fe29Sbellard         ts->type = TCG_TYPE_I32;
1781b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1782c896fe29Sbellard         ts->mem_allocated = 1;
1783b3a62939SRichard Henderson         ts->mem_base = base_ts;
1784aef85402SRichard Henderson         ts->mem_offset = offset;
1785c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1786c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_0");
1787c896fe29Sbellard         ts->name = strdup(buf);
1788c896fe29Sbellard 
17897ca4b752SRichard Henderson         tcg_debug_assert(ts2 == ts + 1);
17907ca4b752SRichard Henderson         ts2->base_type = TCG_TYPE_I64;
17917ca4b752SRichard Henderson         ts2->type = TCG_TYPE_I32;
1792b3915dbbSRichard Henderson         ts2->indirect_reg = indirect_reg;
17937ca4b752SRichard Henderson         ts2->mem_allocated = 1;
17947ca4b752SRichard Henderson         ts2->mem_base = base_ts;
1795aef85402SRichard Henderson         ts2->mem_offset = offset + 4;
1796fac87bd2SRichard Henderson         ts2->temp_subindex = 1;
1797c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1798c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_1");
1799120c1084SRichard Henderson         ts2->name = strdup(buf);
18007ca4b752SRichard Henderson     } else {
1801c896fe29Sbellard         ts->base_type = type;
1802c896fe29Sbellard         ts->type = type;
1803b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1804c896fe29Sbellard         ts->mem_allocated = 1;
1805b3a62939SRichard Henderson         ts->mem_base = base_ts;
1806c896fe29Sbellard         ts->mem_offset = offset;
1807c896fe29Sbellard         ts->name = name;
1808c896fe29Sbellard     }
1809085272b3SRichard Henderson     return ts;
1810c896fe29Sbellard }
1811c896fe29Sbellard 
18124643f3e0SRichard Henderson TCGv_i32 tcg_global_mem_new_i32(TCGv_ptr reg, intptr_t off, const char *name)
18134643f3e0SRichard Henderson {
18144643f3e0SRichard Henderson     TCGTemp *ts = tcg_global_mem_new_internal(reg, off, name, TCG_TYPE_I32);
18154643f3e0SRichard Henderson     return temp_tcgv_i32(ts);
18164643f3e0SRichard Henderson }
18174643f3e0SRichard Henderson 
18184643f3e0SRichard Henderson TCGv_i64 tcg_global_mem_new_i64(TCGv_ptr reg, intptr_t off, const char *name)
18194643f3e0SRichard Henderson {
18204643f3e0SRichard Henderson     TCGTemp *ts = tcg_global_mem_new_internal(reg, off, name, TCG_TYPE_I64);
18214643f3e0SRichard Henderson     return temp_tcgv_i64(ts);
18224643f3e0SRichard Henderson }
18234643f3e0SRichard Henderson 
18244643f3e0SRichard Henderson TCGv_ptr tcg_global_mem_new_ptr(TCGv_ptr reg, intptr_t off, const char *name)
18254643f3e0SRichard Henderson {
18264643f3e0SRichard Henderson     TCGTemp *ts = tcg_global_mem_new_internal(reg, off, name, TCG_TYPE_PTR);
18274643f3e0SRichard Henderson     return temp_tcgv_ptr(ts);
18284643f3e0SRichard Henderson }
18294643f3e0SRichard Henderson 
1830fb04ab7dSRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, TCGTempKind kind)
1831c896fe29Sbellard {
1832b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1833c896fe29Sbellard     TCGTemp *ts;
1834e1c08b00SRichard Henderson     int n;
1835c896fe29Sbellard 
1836e1c08b00SRichard Henderson     if (kind == TEMP_EBB) {
1837e1c08b00SRichard Henderson         int idx = find_first_bit(s->free_temps[type].l, TCG_MAX_TEMPS);
1838e1c08b00SRichard Henderson 
18390ec9eabcSRichard Henderson         if (idx < TCG_MAX_TEMPS) {
18400ec9eabcSRichard Henderson             /* There is already an available temp with the right type.  */
1841e1c08b00SRichard Henderson             clear_bit(idx, s->free_temps[type].l);
18420ec9eabcSRichard Henderson 
1843e8996ee0Sbellard             ts = &s->temps[idx];
1844e8996ee0Sbellard             ts->temp_allocated = 1;
18457ca4b752SRichard Henderson             tcg_debug_assert(ts->base_type == type);
1846ee17db83SRichard Henderson             tcg_debug_assert(ts->kind == kind);
18472f2e911dSRichard Henderson             return ts;
1848e1c08b00SRichard Henderson         }
1849e8996ee0Sbellard     } else {
1850e1c08b00SRichard Henderson         tcg_debug_assert(kind == TEMP_TB);
1851e1c08b00SRichard Henderson     }
185243eef72fSRichard Henderson 
185343eef72fSRichard Henderson     switch (type) {
185443eef72fSRichard Henderson     case TCG_TYPE_I32:
185543eef72fSRichard Henderson     case TCG_TYPE_V64:
185643eef72fSRichard Henderson     case TCG_TYPE_V128:
185743eef72fSRichard Henderson     case TCG_TYPE_V256:
185843eef72fSRichard Henderson         n = 1;
185943eef72fSRichard Henderson         break;
186043eef72fSRichard Henderson     case TCG_TYPE_I64:
186143eef72fSRichard Henderson         n = 64 / TCG_TARGET_REG_BITS;
186243eef72fSRichard Henderson         break;
186343eef72fSRichard Henderson     case TCG_TYPE_I128:
186443eef72fSRichard Henderson         n = 128 / TCG_TARGET_REG_BITS;
186543eef72fSRichard Henderson         break;
186643eef72fSRichard Henderson     default:
186743eef72fSRichard Henderson         g_assert_not_reached();
186843eef72fSRichard Henderson     }
186943eef72fSRichard Henderson 
18707ca4b752SRichard Henderson     ts = tcg_temp_alloc(s);
187143eef72fSRichard Henderson     ts->base_type = type;
187243eef72fSRichard Henderson     ts->temp_allocated = 1;
187343eef72fSRichard Henderson     ts->kind = kind;
187443eef72fSRichard Henderson 
187543eef72fSRichard Henderson     if (n == 1) {
187643eef72fSRichard Henderson         ts->type = type;
187743eef72fSRichard Henderson     } else {
187843eef72fSRichard Henderson         ts->type = TCG_TYPE_REG;
187943eef72fSRichard Henderson 
1880e1c08b00SRichard Henderson         for (int i = 1; i < n; ++i) {
18817ca4b752SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
18827ca4b752SRichard Henderson 
188343eef72fSRichard Henderson             tcg_debug_assert(ts2 == ts + i);
188443eef72fSRichard Henderson             ts2->base_type = type;
188543eef72fSRichard Henderson             ts2->type = TCG_TYPE_REG;
18867ca4b752SRichard Henderson             ts2->temp_allocated = 1;
188743eef72fSRichard Henderson             ts2->temp_subindex = i;
1888ee17db83SRichard Henderson             ts2->kind = kind;
188943eef72fSRichard Henderson         }
1890c896fe29Sbellard     }
1891085272b3SRichard Henderson     return ts;
1892c896fe29Sbellard }
1893c896fe29Sbellard 
18944643f3e0SRichard Henderson TCGv_i32 tcg_temp_new_i32(void)
18954643f3e0SRichard Henderson {
18964643f3e0SRichard Henderson     return temp_tcgv_i32(tcg_temp_new_internal(TCG_TYPE_I32, TEMP_TB));
18974643f3e0SRichard Henderson }
18984643f3e0SRichard Henderson 
18994643f3e0SRichard Henderson TCGv_i32 tcg_temp_ebb_new_i32(void)
19004643f3e0SRichard Henderson {
19014643f3e0SRichard Henderson     return temp_tcgv_i32(tcg_temp_new_internal(TCG_TYPE_I32, TEMP_EBB));
19024643f3e0SRichard Henderson }
19034643f3e0SRichard Henderson 
19044643f3e0SRichard Henderson TCGv_i64 tcg_temp_new_i64(void)
19054643f3e0SRichard Henderson {
19064643f3e0SRichard Henderson     return temp_tcgv_i64(tcg_temp_new_internal(TCG_TYPE_I64, TEMP_TB));
19074643f3e0SRichard Henderson }
19084643f3e0SRichard Henderson 
19094643f3e0SRichard Henderson TCGv_i64 tcg_temp_ebb_new_i64(void)
19104643f3e0SRichard Henderson {
19114643f3e0SRichard Henderson     return temp_tcgv_i64(tcg_temp_new_internal(TCG_TYPE_I64, TEMP_EBB));
19124643f3e0SRichard Henderson }
19134643f3e0SRichard Henderson 
19144643f3e0SRichard Henderson TCGv_ptr tcg_temp_new_ptr(void)
19154643f3e0SRichard Henderson {
19164643f3e0SRichard Henderson     return temp_tcgv_ptr(tcg_temp_new_internal(TCG_TYPE_PTR, TEMP_TB));
19174643f3e0SRichard Henderson }
19184643f3e0SRichard Henderson 
19194643f3e0SRichard Henderson TCGv_ptr tcg_temp_ebb_new_ptr(void)
19204643f3e0SRichard Henderson {
19214643f3e0SRichard Henderson     return temp_tcgv_ptr(tcg_temp_new_internal(TCG_TYPE_PTR, TEMP_EBB));
19224643f3e0SRichard Henderson }
19234643f3e0SRichard Henderson 
19244643f3e0SRichard Henderson TCGv_i128 tcg_temp_new_i128(void)
19254643f3e0SRichard Henderson {
19264643f3e0SRichard Henderson     return temp_tcgv_i128(tcg_temp_new_internal(TCG_TYPE_I128, TEMP_TB));
19274643f3e0SRichard Henderson }
19284643f3e0SRichard Henderson 
19294643f3e0SRichard Henderson TCGv_i128 tcg_temp_ebb_new_i128(void)
19304643f3e0SRichard Henderson {
19314643f3e0SRichard Henderson     return temp_tcgv_i128(tcg_temp_new_internal(TCG_TYPE_I128, TEMP_EBB));
19324643f3e0SRichard Henderson }
19334643f3e0SRichard Henderson 
1934d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type)
1935d2fd745fSRichard Henderson {
1936d2fd745fSRichard Henderson     TCGTemp *t;
1937d2fd745fSRichard Henderson 
1938d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG
1939d2fd745fSRichard Henderson     switch (type) {
1940d2fd745fSRichard Henderson     case TCG_TYPE_V64:
1941d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v64);
1942d2fd745fSRichard Henderson         break;
1943d2fd745fSRichard Henderson     case TCG_TYPE_V128:
1944d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v128);
1945d2fd745fSRichard Henderson         break;
1946d2fd745fSRichard Henderson     case TCG_TYPE_V256:
1947d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v256);
1948d2fd745fSRichard Henderson         break;
1949d2fd745fSRichard Henderson     default:
1950d2fd745fSRichard Henderson         g_assert_not_reached();
1951d2fd745fSRichard Henderson     }
1952d2fd745fSRichard Henderson #endif
1953d2fd745fSRichard Henderson 
1954bbf989bfSRichard Henderson     t = tcg_temp_new_internal(type, TEMP_EBB);
1955d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1956d2fd745fSRichard Henderson }
1957d2fd745fSRichard Henderson 
1958d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp.  */
1959d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match)
1960d2fd745fSRichard Henderson {
1961d2fd745fSRichard Henderson     TCGTemp *t = tcgv_vec_temp(match);
1962d2fd745fSRichard Henderson 
1963d2fd745fSRichard Henderson     tcg_debug_assert(t->temp_allocated != 0);
1964d2fd745fSRichard Henderson 
1965bbf989bfSRichard Henderson     t = tcg_temp_new_internal(t->base_type, TEMP_EBB);
1966d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1967d2fd745fSRichard Henderson }
1968d2fd745fSRichard Henderson 
19695bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts)
1970c896fe29Sbellard {
1971b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1972c896fe29Sbellard 
1973c7482438SRichard Henderson     switch (ts->kind) {
1974c7482438SRichard Henderson     case TEMP_CONST:
1975f57c6915SRichard Henderson     case TEMP_TB:
19762f2e911dSRichard Henderson         /* Silently ignore free. */
1977c7482438SRichard Henderson         break;
19782f2e911dSRichard Henderson     case TEMP_EBB:
1979eabb7b91SAurelien Jarno         tcg_debug_assert(ts->temp_allocated != 0);
1980e8996ee0Sbellard         ts->temp_allocated = 0;
19812f2e911dSRichard Henderson         set_bit(temp_idx(ts), s->free_temps[ts->base_type].l);
19822f2e911dSRichard Henderson         break;
19832f2e911dSRichard Henderson     default:
19842f2e911dSRichard Henderson         /* It never made sense to free TEMP_FIXED or TEMP_GLOBAL. */
19852f2e911dSRichard Henderson         g_assert_not_reached();
1986e1c08b00SRichard Henderson     }
1987e8996ee0Sbellard }
1988e8996ee0Sbellard 
198958b79713SRichard Henderson void tcg_temp_free_i32(TCGv_i32 arg)
199058b79713SRichard Henderson {
199158b79713SRichard Henderson     tcg_temp_free_internal(tcgv_i32_temp(arg));
199258b79713SRichard Henderson }
199358b79713SRichard Henderson 
199458b79713SRichard Henderson void tcg_temp_free_i64(TCGv_i64 arg)
199558b79713SRichard Henderson {
199658b79713SRichard Henderson     tcg_temp_free_internal(tcgv_i64_temp(arg));
199758b79713SRichard Henderson }
199858b79713SRichard Henderson 
199958b79713SRichard Henderson void tcg_temp_free_i128(TCGv_i128 arg)
200058b79713SRichard Henderson {
200158b79713SRichard Henderson     tcg_temp_free_internal(tcgv_i128_temp(arg));
200258b79713SRichard Henderson }
200358b79713SRichard Henderson 
200458b79713SRichard Henderson void tcg_temp_free_ptr(TCGv_ptr arg)
200558b79713SRichard Henderson {
200658b79713SRichard Henderson     tcg_temp_free_internal(tcgv_ptr_temp(arg));
200758b79713SRichard Henderson }
200858b79713SRichard Henderson 
200958b79713SRichard Henderson void tcg_temp_free_vec(TCGv_vec arg)
201058b79713SRichard Henderson {
201158b79713SRichard Henderson     tcg_temp_free_internal(tcgv_vec_temp(arg));
201258b79713SRichard Henderson }
201358b79713SRichard Henderson 
2014c0522136SRichard Henderson TCGTemp *tcg_constant_internal(TCGType type, int64_t val)
2015c0522136SRichard Henderson {
2016c0522136SRichard Henderson     TCGContext *s = tcg_ctx;
2017c0522136SRichard Henderson     GHashTable *h = s->const_table[type];
2018c0522136SRichard Henderson     TCGTemp *ts;
2019c0522136SRichard Henderson 
2020c0522136SRichard Henderson     if (h == NULL) {
2021c0522136SRichard Henderson         h = g_hash_table_new(g_int64_hash, g_int64_equal);
2022c0522136SRichard Henderson         s->const_table[type] = h;
2023c0522136SRichard Henderson     }
2024c0522136SRichard Henderson 
2025c0522136SRichard Henderson     ts = g_hash_table_lookup(h, &val);
2026c0522136SRichard Henderson     if (ts == NULL) {
2027aef85402SRichard Henderson         int64_t *val_ptr;
2028aef85402SRichard Henderson 
2029c0522136SRichard Henderson         ts = tcg_temp_alloc(s);
2030c0522136SRichard Henderson 
2031c0522136SRichard Henderson         if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
2032c0522136SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
2033c0522136SRichard Henderson 
2034aef85402SRichard Henderson             tcg_debug_assert(ts2 == ts + 1);
2035aef85402SRichard Henderson 
2036c0522136SRichard Henderson             ts->base_type = TCG_TYPE_I64;
2037c0522136SRichard Henderson             ts->type = TCG_TYPE_I32;
2038c0522136SRichard Henderson             ts->kind = TEMP_CONST;
2039c0522136SRichard Henderson             ts->temp_allocated = 1;
2040c0522136SRichard Henderson 
2041c0522136SRichard Henderson             ts2->base_type = TCG_TYPE_I64;
2042c0522136SRichard Henderson             ts2->type = TCG_TYPE_I32;
2043c0522136SRichard Henderson             ts2->kind = TEMP_CONST;
2044c0522136SRichard Henderson             ts2->temp_allocated = 1;
2045fac87bd2SRichard Henderson             ts2->temp_subindex = 1;
2046aef85402SRichard Henderson 
2047aef85402SRichard Henderson             /*
2048aef85402SRichard Henderson              * Retain the full value of the 64-bit constant in the low
2049aef85402SRichard Henderson              * part, so that the hash table works.  Actual uses will
2050aef85402SRichard Henderson              * truncate the value to the low part.
2051aef85402SRichard Henderson              */
2052aef85402SRichard Henderson             ts[HOST_BIG_ENDIAN].val = val;
2053aef85402SRichard Henderson             ts[!HOST_BIG_ENDIAN].val = val >> 32;
2054aef85402SRichard Henderson             val_ptr = &ts[HOST_BIG_ENDIAN].val;
2055c0522136SRichard Henderson         } else {
2056c0522136SRichard Henderson             ts->base_type = type;
2057c0522136SRichard Henderson             ts->type = type;
2058c0522136SRichard Henderson             ts->kind = TEMP_CONST;
2059c0522136SRichard Henderson             ts->temp_allocated = 1;
2060c0522136SRichard Henderson             ts->val = val;
2061aef85402SRichard Henderson             val_ptr = &ts->val;
2062c0522136SRichard Henderson         }
2063aef85402SRichard Henderson         g_hash_table_insert(h, val_ptr, ts);
2064c0522136SRichard Henderson     }
2065c0522136SRichard Henderson 
2066c0522136SRichard Henderson     return ts;
2067c0522136SRichard Henderson }
2068c0522136SRichard Henderson 
206916edaee7SRichard Henderson TCGv_i32 tcg_constant_i32(int32_t val)
207016edaee7SRichard Henderson {
207116edaee7SRichard Henderson     return temp_tcgv_i32(tcg_constant_internal(TCG_TYPE_I32, val));
207216edaee7SRichard Henderson }
207316edaee7SRichard Henderson 
207416edaee7SRichard Henderson TCGv_i64 tcg_constant_i64(int64_t val)
207516edaee7SRichard Henderson {
207616edaee7SRichard Henderson     return temp_tcgv_i64(tcg_constant_internal(TCG_TYPE_I64, val));
207716edaee7SRichard Henderson }
207816edaee7SRichard Henderson 
207916edaee7SRichard Henderson TCGv_ptr tcg_constant_ptr_int(intptr_t val)
208016edaee7SRichard Henderson {
208116edaee7SRichard Henderson     return temp_tcgv_ptr(tcg_constant_internal(TCG_TYPE_PTR, val));
208216edaee7SRichard Henderson }
208316edaee7SRichard Henderson 
2084c0522136SRichard Henderson TCGv_vec tcg_constant_vec(TCGType type, unsigned vece, int64_t val)
2085c0522136SRichard Henderson {
2086c0522136SRichard Henderson     val = dup_const(vece, val);
2087c0522136SRichard Henderson     return temp_tcgv_vec(tcg_constant_internal(type, val));
2088c0522136SRichard Henderson }
2089c0522136SRichard Henderson 
209088d4005bSRichard Henderson TCGv_vec tcg_constant_vec_matching(TCGv_vec match, unsigned vece, int64_t val)
209188d4005bSRichard Henderson {
209288d4005bSRichard Henderson     TCGTemp *t = tcgv_vec_temp(match);
209388d4005bSRichard Henderson 
209488d4005bSRichard Henderson     tcg_debug_assert(t->temp_allocated != 0);
209588d4005bSRichard Henderson     return tcg_constant_vec(t->base_type, vece, val);
209688d4005bSRichard Henderson }
209788d4005bSRichard Henderson 
2098177f648fSRichard Henderson #ifdef CONFIG_DEBUG_TCG
2099177f648fSRichard Henderson size_t temp_idx(TCGTemp *ts)
2100177f648fSRichard Henderson {
2101177f648fSRichard Henderson     ptrdiff_t n = ts - tcg_ctx->temps;
2102177f648fSRichard Henderson     assert(n >= 0 && n < tcg_ctx->nb_temps);
2103177f648fSRichard Henderson     return n;
2104177f648fSRichard Henderson }
2105177f648fSRichard Henderson 
2106177f648fSRichard Henderson TCGTemp *tcgv_i32_temp(TCGv_i32 v)
2107177f648fSRichard Henderson {
2108177f648fSRichard Henderson     uintptr_t o = (uintptr_t)v - offsetof(TCGContext, temps);
2109177f648fSRichard Henderson 
2110177f648fSRichard Henderson     assert(o < sizeof(TCGTemp) * tcg_ctx->nb_temps);
2111177f648fSRichard Henderson     assert(o % sizeof(TCGTemp) == 0);
2112177f648fSRichard Henderson 
2113177f648fSRichard Henderson     return (void *)tcg_ctx + (uintptr_t)v;
2114177f648fSRichard Henderson }
2115177f648fSRichard Henderson #endif /* CONFIG_DEBUG_TCG */
2116177f648fSRichard Henderson 
2117771a5925SRichard Henderson /*
2118771a5925SRichard Henderson  * Return true if OP may appear in the opcode stream with TYPE.
2119771a5925SRichard Henderson  * Test the runtime variable that controls each opcode.
2120771a5925SRichard Henderson  */
2121771a5925SRichard Henderson bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags)
2122be0f34b5SRichard Henderson {
2123f44824ccSRichard Henderson     bool has_type;
2124f44824ccSRichard Henderson 
2125f44824ccSRichard Henderson     switch (type) {
2126f44824ccSRichard Henderson     case TCG_TYPE_I32:
2127f44824ccSRichard Henderson         has_type = true;
2128f44824ccSRichard Henderson         break;
2129f44824ccSRichard Henderson     case TCG_TYPE_I64:
2130f44824ccSRichard Henderson         has_type = TCG_TARGET_REG_BITS == 64;
2131f44824ccSRichard Henderson         break;
2132f44824ccSRichard Henderson     case TCG_TYPE_V64:
2133f44824ccSRichard Henderson         has_type = TCG_TARGET_HAS_v64;
2134f44824ccSRichard Henderson         break;
2135f44824ccSRichard Henderson     case TCG_TYPE_V128:
2136f44824ccSRichard Henderson         has_type = TCG_TARGET_HAS_v128;
2137f44824ccSRichard Henderson         break;
2138f44824ccSRichard Henderson     case TCG_TYPE_V256:
2139f44824ccSRichard Henderson         has_type = TCG_TARGET_HAS_v256;
2140f44824ccSRichard Henderson         break;
2141f44824ccSRichard Henderson     default:
2142f44824ccSRichard Henderson         has_type = false;
2143f44824ccSRichard Henderson         break;
2144f44824ccSRichard Henderson     }
2145d2fd745fSRichard Henderson 
2146be0f34b5SRichard Henderson     switch (op) {
2147be0f34b5SRichard Henderson     case INDEX_op_discard:
2148be0f34b5SRichard Henderson     case INDEX_op_set_label:
2149be0f34b5SRichard Henderson     case INDEX_op_call:
2150be0f34b5SRichard Henderson     case INDEX_op_br:
2151be0f34b5SRichard Henderson     case INDEX_op_mb:
2152be0f34b5SRichard Henderson     case INDEX_op_insn_start:
2153be0f34b5SRichard Henderson     case INDEX_op_exit_tb:
2154be0f34b5SRichard Henderson     case INDEX_op_goto_tb:
2155f4e01e30SRichard Henderson     case INDEX_op_goto_ptr:
2156fecccfccSRichard Henderson     case INDEX_op_qemu_ld_a32_i32:
2157fecccfccSRichard Henderson     case INDEX_op_qemu_ld_a64_i32:
2158fecccfccSRichard Henderson     case INDEX_op_qemu_st_a32_i32:
2159fecccfccSRichard Henderson     case INDEX_op_qemu_st_a64_i32:
2160fecccfccSRichard Henderson     case INDEX_op_qemu_ld_a32_i64:
2161fecccfccSRichard Henderson     case INDEX_op_qemu_ld_a64_i64:
2162fecccfccSRichard Henderson     case INDEX_op_qemu_st_a32_i64:
2163fecccfccSRichard Henderson     case INDEX_op_qemu_st_a64_i64:
2164be0f34b5SRichard Henderson         return true;
2165be0f34b5SRichard Henderson 
2166fecccfccSRichard Henderson     case INDEX_op_qemu_st8_a32_i32:
2167fecccfccSRichard Henderson     case INDEX_op_qemu_st8_a64_i32:
216807ce0b05SRichard Henderson         return TCG_TARGET_HAS_qemu_st8_i32;
216907ce0b05SRichard Henderson 
2170fecccfccSRichard Henderson     case INDEX_op_qemu_ld_a32_i128:
2171fecccfccSRichard Henderson     case INDEX_op_qemu_ld_a64_i128:
2172fecccfccSRichard Henderson     case INDEX_op_qemu_st_a32_i128:
2173fecccfccSRichard Henderson     case INDEX_op_qemu_st_a64_i128:
217412fde9bcSRichard Henderson         return TCG_TARGET_HAS_qemu_ldst_i128;
217512fde9bcSRichard Henderson 
2176be0f34b5SRichard Henderson     case INDEX_op_mov_i32:
2177be0f34b5SRichard Henderson     case INDEX_op_setcond_i32:
2178be0f34b5SRichard Henderson     case INDEX_op_brcond_i32:
21793871be75SRichard Henderson     case INDEX_op_movcond_i32:
2180be0f34b5SRichard Henderson     case INDEX_op_ld8u_i32:
2181be0f34b5SRichard Henderson     case INDEX_op_ld8s_i32:
2182be0f34b5SRichard Henderson     case INDEX_op_ld16u_i32:
2183be0f34b5SRichard Henderson     case INDEX_op_ld16s_i32:
2184be0f34b5SRichard Henderson     case INDEX_op_ld_i32:
2185be0f34b5SRichard Henderson     case INDEX_op_st8_i32:
2186be0f34b5SRichard Henderson     case INDEX_op_st16_i32:
2187be0f34b5SRichard Henderson     case INDEX_op_st_i32:
2188be0f34b5SRichard Henderson     case INDEX_op_add_i32:
2189be0f34b5SRichard Henderson     case INDEX_op_sub_i32:
2190b701f195SRichard Henderson     case INDEX_op_neg_i32:
2191be0f34b5SRichard Henderson     case INDEX_op_mul_i32:
2192be0f34b5SRichard Henderson     case INDEX_op_and_i32:
2193be0f34b5SRichard Henderson     case INDEX_op_or_i32:
2194be0f34b5SRichard Henderson     case INDEX_op_xor_i32:
2195be0f34b5SRichard Henderson     case INDEX_op_shl_i32:
2196be0f34b5SRichard Henderson     case INDEX_op_shr_i32:
2197be0f34b5SRichard Henderson     case INDEX_op_sar_i32:
2198be0f34b5SRichard Henderson         return true;
2199be0f34b5SRichard Henderson 
22003635502dSRichard Henderson     case INDEX_op_negsetcond_i32:
22013635502dSRichard Henderson         return TCG_TARGET_HAS_negsetcond_i32;
2202be0f34b5SRichard Henderson     case INDEX_op_div_i32:
2203be0f34b5SRichard Henderson     case INDEX_op_divu_i32:
2204be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i32;
2205be0f34b5SRichard Henderson     case INDEX_op_rem_i32:
2206be0f34b5SRichard Henderson     case INDEX_op_remu_i32:
2207be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i32;
2208be0f34b5SRichard Henderson     case INDEX_op_div2_i32:
2209be0f34b5SRichard Henderson     case INDEX_op_divu2_i32:
2210be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i32;
2211be0f34b5SRichard Henderson     case INDEX_op_rotl_i32:
2212be0f34b5SRichard Henderson     case INDEX_op_rotr_i32:
2213be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i32;
2214be0f34b5SRichard Henderson     case INDEX_op_deposit_i32:
2215be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i32;
2216be0f34b5SRichard Henderson     case INDEX_op_extract_i32:
2217be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i32;
2218be0f34b5SRichard Henderson     case INDEX_op_sextract_i32:
2219be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i32;
2220fce1296fSRichard Henderson     case INDEX_op_extract2_i32:
2221fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i32;
2222be0f34b5SRichard Henderson     case INDEX_op_add2_i32:
2223be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i32;
2224be0f34b5SRichard Henderson     case INDEX_op_sub2_i32:
2225be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i32;
2226be0f34b5SRichard Henderson     case INDEX_op_mulu2_i32:
2227be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i32;
2228be0f34b5SRichard Henderson     case INDEX_op_muls2_i32:
2229be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i32;
2230be0f34b5SRichard Henderson     case INDEX_op_muluh_i32:
2231be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i32;
2232be0f34b5SRichard Henderson     case INDEX_op_mulsh_i32:
2233be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i32;
2234be0f34b5SRichard Henderson     case INDEX_op_ext8s_i32:
2235be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i32;
2236be0f34b5SRichard Henderson     case INDEX_op_ext16s_i32:
2237be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i32;
2238be0f34b5SRichard Henderson     case INDEX_op_ext8u_i32:
2239be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i32;
2240be0f34b5SRichard Henderson     case INDEX_op_ext16u_i32:
2241be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i32;
2242be0f34b5SRichard Henderson     case INDEX_op_bswap16_i32:
2243be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i32;
2244be0f34b5SRichard Henderson     case INDEX_op_bswap32_i32:
2245be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i32;
2246be0f34b5SRichard Henderson     case INDEX_op_not_i32:
2247be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i32;
2248be0f34b5SRichard Henderson     case INDEX_op_andc_i32:
2249be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i32;
2250be0f34b5SRichard Henderson     case INDEX_op_orc_i32:
2251be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i32;
2252be0f34b5SRichard Henderson     case INDEX_op_eqv_i32:
2253be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i32;
2254be0f34b5SRichard Henderson     case INDEX_op_nand_i32:
2255be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i32;
2256be0f34b5SRichard Henderson     case INDEX_op_nor_i32:
2257be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i32;
2258be0f34b5SRichard Henderson     case INDEX_op_clz_i32:
2259be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i32;
2260be0f34b5SRichard Henderson     case INDEX_op_ctz_i32:
2261be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i32;
2262be0f34b5SRichard Henderson     case INDEX_op_ctpop_i32:
2263be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i32;
2264be0f34b5SRichard Henderson 
2265be0f34b5SRichard Henderson     case INDEX_op_brcond2_i32:
2266be0f34b5SRichard Henderson     case INDEX_op_setcond2_i32:
2267be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 32;
2268be0f34b5SRichard Henderson 
2269be0f34b5SRichard Henderson     case INDEX_op_mov_i64:
2270be0f34b5SRichard Henderson     case INDEX_op_setcond_i64:
2271be0f34b5SRichard Henderson     case INDEX_op_brcond_i64:
22723871be75SRichard Henderson     case INDEX_op_movcond_i64:
2273be0f34b5SRichard Henderson     case INDEX_op_ld8u_i64:
2274be0f34b5SRichard Henderson     case INDEX_op_ld8s_i64:
2275be0f34b5SRichard Henderson     case INDEX_op_ld16u_i64:
2276be0f34b5SRichard Henderson     case INDEX_op_ld16s_i64:
2277be0f34b5SRichard Henderson     case INDEX_op_ld32u_i64:
2278be0f34b5SRichard Henderson     case INDEX_op_ld32s_i64:
2279be0f34b5SRichard Henderson     case INDEX_op_ld_i64:
2280be0f34b5SRichard Henderson     case INDEX_op_st8_i64:
2281be0f34b5SRichard Henderson     case INDEX_op_st16_i64:
2282be0f34b5SRichard Henderson     case INDEX_op_st32_i64:
2283be0f34b5SRichard Henderson     case INDEX_op_st_i64:
2284be0f34b5SRichard Henderson     case INDEX_op_add_i64:
2285be0f34b5SRichard Henderson     case INDEX_op_sub_i64:
2286b701f195SRichard Henderson     case INDEX_op_neg_i64:
2287be0f34b5SRichard Henderson     case INDEX_op_mul_i64:
2288be0f34b5SRichard Henderson     case INDEX_op_and_i64:
2289be0f34b5SRichard Henderson     case INDEX_op_or_i64:
2290be0f34b5SRichard Henderson     case INDEX_op_xor_i64:
2291be0f34b5SRichard Henderson     case INDEX_op_shl_i64:
2292be0f34b5SRichard Henderson     case INDEX_op_shr_i64:
2293be0f34b5SRichard Henderson     case INDEX_op_sar_i64:
2294be0f34b5SRichard Henderson     case INDEX_op_ext_i32_i64:
2295be0f34b5SRichard Henderson     case INDEX_op_extu_i32_i64:
2296be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 64;
2297be0f34b5SRichard Henderson 
22983635502dSRichard Henderson     case INDEX_op_negsetcond_i64:
22993635502dSRichard Henderson         return TCG_TARGET_HAS_negsetcond_i64;
2300be0f34b5SRichard Henderson     case INDEX_op_div_i64:
2301be0f34b5SRichard Henderson     case INDEX_op_divu_i64:
2302be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i64;
2303be0f34b5SRichard Henderson     case INDEX_op_rem_i64:
2304be0f34b5SRichard Henderson     case INDEX_op_remu_i64:
2305be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i64;
2306be0f34b5SRichard Henderson     case INDEX_op_div2_i64:
2307be0f34b5SRichard Henderson     case INDEX_op_divu2_i64:
2308be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i64;
2309be0f34b5SRichard Henderson     case INDEX_op_rotl_i64:
2310be0f34b5SRichard Henderson     case INDEX_op_rotr_i64:
2311be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i64;
2312be0f34b5SRichard Henderson     case INDEX_op_deposit_i64:
2313be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i64;
2314be0f34b5SRichard Henderson     case INDEX_op_extract_i64:
2315be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i64;
2316be0f34b5SRichard Henderson     case INDEX_op_sextract_i64:
2317be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i64;
2318fce1296fSRichard Henderson     case INDEX_op_extract2_i64:
2319fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i64;
2320be0f34b5SRichard Henderson     case INDEX_op_extrl_i64_i32:
2321be0f34b5SRichard Henderson     case INDEX_op_extrh_i64_i32:
232213d885b0SRichard Henderson         return TCG_TARGET_HAS_extr_i64_i32;
2323be0f34b5SRichard Henderson     case INDEX_op_ext8s_i64:
2324be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i64;
2325be0f34b5SRichard Henderson     case INDEX_op_ext16s_i64:
2326be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i64;
2327be0f34b5SRichard Henderson     case INDEX_op_ext32s_i64:
2328be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32s_i64;
2329be0f34b5SRichard Henderson     case INDEX_op_ext8u_i64:
2330be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i64;
2331be0f34b5SRichard Henderson     case INDEX_op_ext16u_i64:
2332be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i64;
2333be0f34b5SRichard Henderson     case INDEX_op_ext32u_i64:
2334be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32u_i64;
2335be0f34b5SRichard Henderson     case INDEX_op_bswap16_i64:
2336be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i64;
2337be0f34b5SRichard Henderson     case INDEX_op_bswap32_i64:
2338be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i64;
2339be0f34b5SRichard Henderson     case INDEX_op_bswap64_i64:
2340be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap64_i64;
2341be0f34b5SRichard Henderson     case INDEX_op_not_i64:
2342be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i64;
2343be0f34b5SRichard Henderson     case INDEX_op_andc_i64:
2344be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i64;
2345be0f34b5SRichard Henderson     case INDEX_op_orc_i64:
2346be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i64;
2347be0f34b5SRichard Henderson     case INDEX_op_eqv_i64:
2348be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i64;
2349be0f34b5SRichard Henderson     case INDEX_op_nand_i64:
2350be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i64;
2351be0f34b5SRichard Henderson     case INDEX_op_nor_i64:
2352be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i64;
2353be0f34b5SRichard Henderson     case INDEX_op_clz_i64:
2354be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i64;
2355be0f34b5SRichard Henderson     case INDEX_op_ctz_i64:
2356be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i64;
2357be0f34b5SRichard Henderson     case INDEX_op_ctpop_i64:
2358be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i64;
2359be0f34b5SRichard Henderson     case INDEX_op_add2_i64:
2360be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i64;
2361be0f34b5SRichard Henderson     case INDEX_op_sub2_i64:
2362be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i64;
2363be0f34b5SRichard Henderson     case INDEX_op_mulu2_i64:
2364be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i64;
2365be0f34b5SRichard Henderson     case INDEX_op_muls2_i64:
2366be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i64;
2367be0f34b5SRichard Henderson     case INDEX_op_muluh_i64:
2368be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i64;
2369be0f34b5SRichard Henderson     case INDEX_op_mulsh_i64:
2370be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i64;
2371be0f34b5SRichard Henderson 
2372d2fd745fSRichard Henderson     case INDEX_op_mov_vec:
2373d2fd745fSRichard Henderson     case INDEX_op_dup_vec:
237437ee55a0SRichard Henderson     case INDEX_op_dupm_vec:
2375d2fd745fSRichard Henderson     case INDEX_op_ld_vec:
2376d2fd745fSRichard Henderson     case INDEX_op_st_vec:
2377d2fd745fSRichard Henderson     case INDEX_op_add_vec:
2378d2fd745fSRichard Henderson     case INDEX_op_sub_vec:
2379d2fd745fSRichard Henderson     case INDEX_op_and_vec:
2380d2fd745fSRichard Henderson     case INDEX_op_or_vec:
2381d2fd745fSRichard Henderson     case INDEX_op_xor_vec:
2382212be173SRichard Henderson     case INDEX_op_cmp_vec:
2383f44824ccSRichard Henderson         return has_type;
2384d2fd745fSRichard Henderson     case INDEX_op_dup2_vec:
2385f44824ccSRichard Henderson         return has_type && TCG_TARGET_REG_BITS == 32;
2386d2fd745fSRichard Henderson     case INDEX_op_not_vec:
2387f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_not_vec;
2388d2fd745fSRichard Henderson     case INDEX_op_neg_vec:
2389f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_neg_vec;
2390bcefc902SRichard Henderson     case INDEX_op_abs_vec:
2391f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_abs_vec;
2392d2fd745fSRichard Henderson     case INDEX_op_andc_vec:
2393f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_andc_vec;
2394d2fd745fSRichard Henderson     case INDEX_op_orc_vec:
2395f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_orc_vec;
2396ed523473SRichard Henderson     case INDEX_op_nand_vec:
2397f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_nand_vec;
2398ed523473SRichard Henderson     case INDEX_op_nor_vec:
2399f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_nor_vec;
2400ed523473SRichard Henderson     case INDEX_op_eqv_vec:
2401f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_eqv_vec;
24023774030aSRichard Henderson     case INDEX_op_mul_vec:
2403f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_mul_vec;
2404d0ec9796SRichard Henderson     case INDEX_op_shli_vec:
2405d0ec9796SRichard Henderson     case INDEX_op_shri_vec:
2406d0ec9796SRichard Henderson     case INDEX_op_sari_vec:
2407f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_shi_vec;
2408d0ec9796SRichard Henderson     case INDEX_op_shls_vec:
2409d0ec9796SRichard Henderson     case INDEX_op_shrs_vec:
2410d0ec9796SRichard Henderson     case INDEX_op_sars_vec:
2411f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_shs_vec;
2412d0ec9796SRichard Henderson     case INDEX_op_shlv_vec:
2413d0ec9796SRichard Henderson     case INDEX_op_shrv_vec:
2414d0ec9796SRichard Henderson     case INDEX_op_sarv_vec:
2415f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_shv_vec;
2416b0f7e744SRichard Henderson     case INDEX_op_rotli_vec:
2417f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_roti_vec;
241823850a74SRichard Henderson     case INDEX_op_rotls_vec:
2419f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_rots_vec;
24205d0ceda9SRichard Henderson     case INDEX_op_rotlv_vec:
24215d0ceda9SRichard Henderson     case INDEX_op_rotrv_vec:
2422f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_rotv_vec;
24238afaf050SRichard Henderson     case INDEX_op_ssadd_vec:
24248afaf050SRichard Henderson     case INDEX_op_usadd_vec:
24258afaf050SRichard Henderson     case INDEX_op_sssub_vec:
24268afaf050SRichard Henderson     case INDEX_op_ussub_vec:
2427f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_sat_vec;
2428dd0a0fcdSRichard Henderson     case INDEX_op_smin_vec:
2429dd0a0fcdSRichard Henderson     case INDEX_op_umin_vec:
2430dd0a0fcdSRichard Henderson     case INDEX_op_smax_vec:
2431dd0a0fcdSRichard Henderson     case INDEX_op_umax_vec:
2432f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_minmax_vec;
243338dc1294SRichard Henderson     case INDEX_op_bitsel_vec:
2434f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_bitsel_vec;
2435f75da298SRichard Henderson     case INDEX_op_cmpsel_vec:
2436f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_cmpsel_vec;
2437d2fd745fSRichard Henderson 
2438db432672SRichard Henderson     default:
2439db432672SRichard Henderson         tcg_debug_assert(op > INDEX_op_last_generic && op < NB_OPS);
2440db432672SRichard Henderson         return true;
2441be0f34b5SRichard Henderson     }
2442be0f34b5SRichard Henderson }
2443be0f34b5SRichard Henderson 
24440e4c6424SRichard Henderson bool tcg_op_deposit_valid(TCGType type, unsigned ofs, unsigned len)
24450e4c6424SRichard Henderson {
24460e4c6424SRichard Henderson     tcg_debug_assert(len > 0);
24470e4c6424SRichard Henderson     switch (type) {
24480e4c6424SRichard Henderson     case TCG_TYPE_I32:
24490e4c6424SRichard Henderson         tcg_debug_assert(ofs < 32);
24500e4c6424SRichard Henderson         tcg_debug_assert(len <= 32);
24510e4c6424SRichard Henderson         tcg_debug_assert(ofs + len <= 32);
24520e4c6424SRichard Henderson         return TCG_TARGET_HAS_deposit_i32 &&
24530e4c6424SRichard Henderson                TCG_TARGET_deposit_i32_valid(ofs, len);
24540e4c6424SRichard Henderson     case TCG_TYPE_I64:
24550e4c6424SRichard Henderson         tcg_debug_assert(ofs < 64);
24560e4c6424SRichard Henderson         tcg_debug_assert(len <= 64);
24570e4c6424SRichard Henderson         tcg_debug_assert(ofs + len <= 64);
24580e4c6424SRichard Henderson         return TCG_TARGET_HAS_deposit_i64 &&
24590e4c6424SRichard Henderson                TCG_TARGET_deposit_i64_valid(ofs, len);
24600e4c6424SRichard Henderson     default:
24610e4c6424SRichard Henderson         g_assert_not_reached();
24620e4c6424SRichard Henderson     }
24630e4c6424SRichard Henderson }
24640e4c6424SRichard Henderson 
246539004a71SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs);
246639004a71SRichard Henderson 
246783a0ad26SRichard Henderson static void tcg_gen_callN(void *func, TCGHelperInfo *info,
246883a0ad26SRichard Henderson                           TCGTemp *ret, TCGTemp **args)
2469c896fe29Sbellard {
247039004a71SRichard Henderson     TCGv_i64 extend_free[MAX_CALL_IARGS];
247139004a71SRichard Henderson     int n_extend = 0;
247275e8b9b7SRichard Henderson     TCGOp *op;
247339004a71SRichard Henderson     int i, n, pi = 0, total_args;
2474afb49896SRichard Henderson 
2475d53106c9SRichard Henderson     if (unlikely(g_once_init_enter(HELPER_INFO_INIT(info)))) {
2476d53106c9SRichard Henderson         init_call_layout(info);
2477d53106c9SRichard Henderson         g_once_init_leave(HELPER_INFO_INIT(info), HELPER_INFO_INIT_VAL(info));
2478d53106c9SRichard Henderson     }
2479d53106c9SRichard Henderson 
248039004a71SRichard Henderson     total_args = info->nr_out + info->nr_in + 2;
248139004a71SRichard Henderson     op = tcg_op_alloc(INDEX_op_call, total_args);
24822bece2c8SRichard Henderson 
248338b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN
248417083f6fSEmilio Cota     /* Flag helpers that may affect guest state */
2485b0748975SRichard Henderson     if (tcg_ctx->plugin_insn && !(info->flags & TCG_CALL_NO_SIDE_EFFECTS)) {
248638b47b19SEmilio G. Cota         tcg_ctx->plugin_insn->calls_helpers = true;
248738b47b19SEmilio G. Cota     }
248838b47b19SEmilio G. Cota #endif
248938b47b19SEmilio G. Cota 
249039004a71SRichard Henderson     TCGOP_CALLO(op) = n = info->nr_out;
249139004a71SRichard Henderson     switch (n) {
249239004a71SRichard Henderson     case 0:
249339004a71SRichard Henderson         tcg_debug_assert(ret == NULL);
249439004a71SRichard Henderson         break;
249539004a71SRichard Henderson     case 1:
249639004a71SRichard Henderson         tcg_debug_assert(ret != NULL);
249739004a71SRichard Henderson         op->args[pi++] = temp_arg(ret);
249839004a71SRichard Henderson         break;
249939004a71SRichard Henderson     case 2:
2500466d3759SRichard Henderson     case 4:
250139004a71SRichard Henderson         tcg_debug_assert(ret != NULL);
2502466d3759SRichard Henderson         tcg_debug_assert(ret->base_type == ret->type + ctz32(n));
250339004a71SRichard Henderson         tcg_debug_assert(ret->temp_subindex == 0);
2504466d3759SRichard Henderson         for (i = 0; i < n; ++i) {
2505466d3759SRichard Henderson             op->args[pi++] = temp_arg(ret + i);
2506466d3759SRichard Henderson         }
250739004a71SRichard Henderson         break;
250839004a71SRichard Henderson     default:
250939004a71SRichard Henderson         g_assert_not_reached();
251039004a71SRichard Henderson     }
25117319d83aSRichard Henderson 
251239004a71SRichard Henderson     TCGOP_CALLI(op) = n = info->nr_in;
251339004a71SRichard Henderson     for (i = 0; i < n; i++) {
251439004a71SRichard Henderson         const TCGCallArgumentLoc *loc = &info->in[i];
251539004a71SRichard Henderson         TCGTemp *ts = args[loc->arg_idx] + loc->tmp_subindex;
251639004a71SRichard Henderson 
251739004a71SRichard Henderson         switch (loc->kind) {
251839004a71SRichard Henderson         case TCG_CALL_ARG_NORMAL:
2519313bdea8SRichard Henderson         case TCG_CALL_ARG_BY_REF:
2520313bdea8SRichard Henderson         case TCG_CALL_ARG_BY_REF_N:
252139004a71SRichard Henderson             op->args[pi++] = temp_arg(ts);
252239004a71SRichard Henderson             break;
252339004a71SRichard Henderson 
252439004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_U:
252539004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_S:
252639004a71SRichard Henderson             {
25275dd48602SRichard Henderson                 TCGv_i64 temp = tcg_temp_ebb_new_i64();
252839004a71SRichard Henderson                 TCGv_i32 orig = temp_tcgv_i32(ts);
252939004a71SRichard Henderson 
253039004a71SRichard Henderson                 if (loc->kind == TCG_CALL_ARG_EXTEND_S) {
253118cf3d07SRichard Henderson                     tcg_gen_ext_i32_i64(temp, orig);
25322bece2c8SRichard Henderson                 } else {
253318cf3d07SRichard Henderson                     tcg_gen_extu_i32_i64(temp, orig);
25342bece2c8SRichard Henderson                 }
253539004a71SRichard Henderson                 op->args[pi++] = tcgv_i64_arg(temp);
253639004a71SRichard Henderson                 extend_free[n_extend++] = temp;
25372bece2c8SRichard Henderson             }
253839004a71SRichard Henderson             break;
25392bece2c8SRichard Henderson 
2540e2a9dd6bSRichard Henderson         default:
2541e2a9dd6bSRichard Henderson             g_assert_not_reached();
2542e2a9dd6bSRichard Henderson         }
2543c896fe29Sbellard     }
254483a0ad26SRichard Henderson     op->args[pi++] = (uintptr_t)func;
25453e92aa34SRichard Henderson     op->args[pi++] = (uintptr_t)info;
254639004a71SRichard Henderson     tcg_debug_assert(pi == total_args);
2547a7812ae4Spbrook 
254807843f75SRichard Henderson     if (tcg_ctx->emit_before_op) {
254907843f75SRichard Henderson         QTAILQ_INSERT_BEFORE(tcg_ctx->emit_before_op, op, link);
255007843f75SRichard Henderson     } else {
255139004a71SRichard Henderson         QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
255207843f75SRichard Henderson     }
25532bece2c8SRichard Henderson 
255439004a71SRichard Henderson     tcg_debug_assert(n_extend < ARRAY_SIZE(extend_free));
255539004a71SRichard Henderson     for (i = 0; i < n_extend; ++i) {
255639004a71SRichard Henderson         tcg_temp_free_i64(extend_free[i]);
2557eb8b0224SRichard Henderson     }
2558a7812ae4Spbrook }
2559c896fe29Sbellard 
256083a0ad26SRichard Henderson void tcg_gen_call0(void *func, TCGHelperInfo *info, TCGTemp *ret)
2561a3a692b8SRichard Henderson {
256283a0ad26SRichard Henderson     tcg_gen_callN(func, info, ret, NULL);
2563a3a692b8SRichard Henderson }
2564a3a692b8SRichard Henderson 
256583a0ad26SRichard Henderson void tcg_gen_call1(void *func, TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1)
2566a3a692b8SRichard Henderson {
256783a0ad26SRichard Henderson     tcg_gen_callN(func, info, ret, &t1);
2568a3a692b8SRichard Henderson }
2569a3a692b8SRichard Henderson 
257083a0ad26SRichard Henderson void tcg_gen_call2(void *func, TCGHelperInfo *info, TCGTemp *ret,
257183a0ad26SRichard Henderson                    TCGTemp *t1, TCGTemp *t2)
2572a3a692b8SRichard Henderson {
2573a3a692b8SRichard Henderson     TCGTemp *args[2] = { t1, t2 };
257483a0ad26SRichard Henderson     tcg_gen_callN(func, info, ret, args);
2575a3a692b8SRichard Henderson }
2576a3a692b8SRichard Henderson 
257783a0ad26SRichard Henderson void tcg_gen_call3(void *func, TCGHelperInfo *info, TCGTemp *ret,
257883a0ad26SRichard Henderson                    TCGTemp *t1, TCGTemp *t2, TCGTemp *t3)
2579a3a692b8SRichard Henderson {
2580a3a692b8SRichard Henderson     TCGTemp *args[3] = { t1, t2, t3 };
258183a0ad26SRichard Henderson     tcg_gen_callN(func, info, ret, args);
2582a3a692b8SRichard Henderson }
2583a3a692b8SRichard Henderson 
258483a0ad26SRichard Henderson void tcg_gen_call4(void *func, TCGHelperInfo *info, TCGTemp *ret,
258583a0ad26SRichard Henderson                    TCGTemp *t1, TCGTemp *t2, TCGTemp *t3, TCGTemp *t4)
2586a3a692b8SRichard Henderson {
2587a3a692b8SRichard Henderson     TCGTemp *args[4] = { t1, t2, t3, t4 };
258883a0ad26SRichard Henderson     tcg_gen_callN(func, info, ret, args);
2589a3a692b8SRichard Henderson }
2590a3a692b8SRichard Henderson 
259183a0ad26SRichard Henderson void tcg_gen_call5(void *func, TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1,
2592a3a692b8SRichard Henderson                    TCGTemp *t2, TCGTemp *t3, TCGTemp *t4, TCGTemp *t5)
2593a3a692b8SRichard Henderson {
2594a3a692b8SRichard Henderson     TCGTemp *args[5] = { t1, t2, t3, t4, t5 };
259583a0ad26SRichard Henderson     tcg_gen_callN(func, info, ret, args);
2596a3a692b8SRichard Henderson }
2597a3a692b8SRichard Henderson 
259883a0ad26SRichard Henderson void tcg_gen_call6(void *func, TCGHelperInfo *info, TCGTemp *ret,
259983a0ad26SRichard Henderson                    TCGTemp *t1, TCGTemp *t2, TCGTemp *t3,
260083a0ad26SRichard Henderson                    TCGTemp *t4, TCGTemp *t5, TCGTemp *t6)
2601a3a692b8SRichard Henderson {
2602a3a692b8SRichard Henderson     TCGTemp *args[6] = { t1, t2, t3, t4, t5, t6 };
260383a0ad26SRichard Henderson     tcg_gen_callN(func, info, ret, args);
2604a3a692b8SRichard Henderson }
2605a3a692b8SRichard Henderson 
260683a0ad26SRichard Henderson void tcg_gen_call7(void *func, TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1,
2607a3a692b8SRichard Henderson                    TCGTemp *t2, TCGTemp *t3, TCGTemp *t4,
2608a3a692b8SRichard Henderson                    TCGTemp *t5, TCGTemp *t6, TCGTemp *t7)
2609a3a692b8SRichard Henderson {
2610a3a692b8SRichard Henderson     TCGTemp *args[7] = { t1, t2, t3, t4, t5, t6, t7 };
261183a0ad26SRichard Henderson     tcg_gen_callN(func, info, ret, args);
2612a3a692b8SRichard Henderson }
2613a3a692b8SRichard Henderson 
26148fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s)
2615c896fe29Sbellard {
2616ac3b8891SRichard Henderson     int i, n;
2617ac3b8891SRichard Henderson 
2618ee17db83SRichard Henderson     for (i = 0, n = s->nb_temps; i < n; i++) {
2619ee17db83SRichard Henderson         TCGTemp *ts = &s->temps[i];
2620ee17db83SRichard Henderson         TCGTempVal val = TEMP_VAL_MEM;
2621ee17db83SRichard Henderson 
2622ee17db83SRichard Henderson         switch (ts->kind) {
2623c0522136SRichard Henderson         case TEMP_CONST:
2624c0522136SRichard Henderson             val = TEMP_VAL_CONST;
2625c0522136SRichard Henderson             break;
2626ee17db83SRichard Henderson         case TEMP_FIXED:
2627ee17db83SRichard Henderson             val = TEMP_VAL_REG;
2628ee17db83SRichard Henderson             break;
2629ee17db83SRichard Henderson         case TEMP_GLOBAL:
2630ee17db83SRichard Henderson             break;
2631c7482438SRichard Henderson         case TEMP_EBB:
2632ee17db83SRichard Henderson             val = TEMP_VAL_DEAD;
2633ee17db83SRichard Henderson             /* fall through */
2634f57c6915SRichard Henderson         case TEMP_TB:
2635e8996ee0Sbellard             ts->mem_allocated = 0;
2636ee17db83SRichard Henderson             break;
2637ee17db83SRichard Henderson         default:
2638ee17db83SRichard Henderson             g_assert_not_reached();
2639ee17db83SRichard Henderson         }
2640ee17db83SRichard Henderson         ts->val_type = val;
2641e8996ee0Sbellard     }
2642f8b2f202SRichard Henderson 
2643f8b2f202SRichard Henderson     memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp));
2644c896fe29Sbellard }
2645c896fe29Sbellard 
2646f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size,
2647f8b2f202SRichard Henderson                                  TCGTemp *ts)
2648c896fe29Sbellard {
26491807f4c4SRichard Henderson     int idx = temp_idx(ts);
2650ac56dd48Spbrook 
2651ee17db83SRichard Henderson     switch (ts->kind) {
2652ee17db83SRichard Henderson     case TEMP_FIXED:
2653ee17db83SRichard Henderson     case TEMP_GLOBAL:
2654ac56dd48Spbrook         pstrcpy(buf, buf_size, ts->name);
2655ee17db83SRichard Henderson         break;
2656f57c6915SRichard Henderson     case TEMP_TB:
2657641d5fbeSbellard         snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
2658ee17db83SRichard Henderson         break;
2659c7482438SRichard Henderson     case TEMP_EBB:
2660ac56dd48Spbrook         snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
2661ee17db83SRichard Henderson         break;
2662c0522136SRichard Henderson     case TEMP_CONST:
2663c0522136SRichard Henderson         switch (ts->type) {
2664c0522136SRichard Henderson         case TCG_TYPE_I32:
2665c0522136SRichard Henderson             snprintf(buf, buf_size, "$0x%x", (int32_t)ts->val);
2666c0522136SRichard Henderson             break;
2667c0522136SRichard Henderson #if TCG_TARGET_REG_BITS > 32
2668c0522136SRichard Henderson         case TCG_TYPE_I64:
2669c0522136SRichard Henderson             snprintf(buf, buf_size, "$0x%" PRIx64, ts->val);
2670c0522136SRichard Henderson             break;
2671c0522136SRichard Henderson #endif
2672c0522136SRichard Henderson         case TCG_TYPE_V64:
2673c0522136SRichard Henderson         case TCG_TYPE_V128:
2674c0522136SRichard Henderson         case TCG_TYPE_V256:
2675c0522136SRichard Henderson             snprintf(buf, buf_size, "v%d$0x%" PRIx64,
2676c0522136SRichard Henderson                      64 << (ts->type - TCG_TYPE_V64), ts->val);
2677c0522136SRichard Henderson             break;
2678c0522136SRichard Henderson         default:
2679c0522136SRichard Henderson             g_assert_not_reached();
2680c0522136SRichard Henderson         }
2681c0522136SRichard Henderson         break;
2682c896fe29Sbellard     }
2683c896fe29Sbellard     return buf;
2684c896fe29Sbellard }
2685c896fe29Sbellard 
268643439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf,
268743439139SRichard Henderson                              int buf_size, TCGArg arg)
2688f8b2f202SRichard Henderson {
268943439139SRichard Henderson     return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg));
2690f8b2f202SRichard Henderson }
2691f8b2f202SRichard Henderson 
2692f48f3edeSblueswir1 static const char * const cond_name[] =
2693f48f3edeSblueswir1 {
26940aed257fSRichard Henderson     [TCG_COND_NEVER] = "never",
26950aed257fSRichard Henderson     [TCG_COND_ALWAYS] = "always",
2696f48f3edeSblueswir1     [TCG_COND_EQ] = "eq",
2697f48f3edeSblueswir1     [TCG_COND_NE] = "ne",
2698f48f3edeSblueswir1     [TCG_COND_LT] = "lt",
2699f48f3edeSblueswir1     [TCG_COND_GE] = "ge",
2700f48f3edeSblueswir1     [TCG_COND_LE] = "le",
2701f48f3edeSblueswir1     [TCG_COND_GT] = "gt",
2702f48f3edeSblueswir1     [TCG_COND_LTU] = "ltu",
2703f48f3edeSblueswir1     [TCG_COND_GEU] = "geu",
2704f48f3edeSblueswir1     [TCG_COND_LEU] = "leu",
2705d48097d0SRichard Henderson     [TCG_COND_GTU] = "gtu",
2706d48097d0SRichard Henderson     [TCG_COND_TSTEQ] = "tsteq",
2707d48097d0SRichard Henderson     [TCG_COND_TSTNE] = "tstne",
2708f48f3edeSblueswir1 };
2709f48f3edeSblueswir1 
271012fde9bcSRichard Henderson static const char * const ldst_name[(MO_BSWAP | MO_SSIZE) + 1] =
2711f713d6adSRichard Henderson {
2712f713d6adSRichard Henderson     [MO_UB]   = "ub",
2713f713d6adSRichard Henderson     [MO_SB]   = "sb",
2714f713d6adSRichard Henderson     [MO_LEUW] = "leuw",
2715f713d6adSRichard Henderson     [MO_LESW] = "lesw",
2716f713d6adSRichard Henderson     [MO_LEUL] = "leul",
2717f713d6adSRichard Henderson     [MO_LESL] = "lesl",
2718fc313c64SFrédéric Pétrot     [MO_LEUQ] = "leq",
2719f713d6adSRichard Henderson     [MO_BEUW] = "beuw",
2720f713d6adSRichard Henderson     [MO_BESW] = "besw",
2721f713d6adSRichard Henderson     [MO_BEUL] = "beul",
2722f713d6adSRichard Henderson     [MO_BESL] = "besl",
2723fc313c64SFrédéric Pétrot     [MO_BEUQ] = "beq",
272412fde9bcSRichard Henderson     [MO_128 + MO_BE] = "beo",
272512fde9bcSRichard Henderson     [MO_128 + MO_LE] = "leo",
2726f713d6adSRichard Henderson };
2727f713d6adSRichard Henderson 
27281f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = {
27291f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "un+",
27301f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "al+",
27311f00b27fSSergey Sorokin     [MO_ALIGN_2 >> MO_ASHIFT]  = "al2+",
27321f00b27fSSergey Sorokin     [MO_ALIGN_4 >> MO_ASHIFT]  = "al4+",
27331f00b27fSSergey Sorokin     [MO_ALIGN_8 >> MO_ASHIFT]  = "al8+",
27341f00b27fSSergey Sorokin     [MO_ALIGN_16 >> MO_ASHIFT] = "al16+",
27351f00b27fSSergey Sorokin     [MO_ALIGN_32 >> MO_ASHIFT] = "al32+",
27361f00b27fSSergey Sorokin     [MO_ALIGN_64 >> MO_ASHIFT] = "al64+",
27371f00b27fSSergey Sorokin };
27381f00b27fSSergey Sorokin 
273937031fefSRichard Henderson static const char * const atom_name[(MO_ATOM_MASK >> MO_ATOM_SHIFT) + 1] = {
274037031fefSRichard Henderson     [MO_ATOM_IFALIGN >> MO_ATOM_SHIFT] = "",
274137031fefSRichard Henderson     [MO_ATOM_IFALIGN_PAIR >> MO_ATOM_SHIFT] = "pair+",
274237031fefSRichard Henderson     [MO_ATOM_WITHIN16 >> MO_ATOM_SHIFT] = "w16+",
274337031fefSRichard Henderson     [MO_ATOM_WITHIN16_PAIR >> MO_ATOM_SHIFT] = "w16p+",
274437031fefSRichard Henderson     [MO_ATOM_SUBALIGN >> MO_ATOM_SHIFT] = "sub+",
274537031fefSRichard Henderson     [MO_ATOM_NONE >> MO_ATOM_SHIFT] = "noat+",
274637031fefSRichard Henderson };
274737031fefSRichard Henderson 
2748587195bdSRichard Henderson static const char bswap_flag_name[][6] = {
2749587195bdSRichard Henderson     [TCG_BSWAP_IZ] = "iz",
2750587195bdSRichard Henderson     [TCG_BSWAP_OZ] = "oz",
2751587195bdSRichard Henderson     [TCG_BSWAP_OS] = "os",
2752587195bdSRichard Henderson     [TCG_BSWAP_IZ | TCG_BSWAP_OZ] = "iz,oz",
2753587195bdSRichard Henderson     [TCG_BSWAP_IZ | TCG_BSWAP_OS] = "iz,os",
2754587195bdSRichard Henderson };
2755587195bdSRichard Henderson 
2756b384c734SRichard Henderson #ifdef CONFIG_PLUGIN
2757b384c734SRichard Henderson static const char * const plugin_from_name[] = {
2758b384c734SRichard Henderson     "from-tb",
2759b384c734SRichard Henderson     "from-insn",
2760b384c734SRichard Henderson     "after-insn",
2761b384c734SRichard Henderson     "after-tb",
2762b384c734SRichard Henderson };
2763b384c734SRichard Henderson #endif
2764b384c734SRichard Henderson 
2765b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d)
2766b016486eSRichard Henderson {
2767b016486eSRichard Henderson     return (d & (d - 1)) == 0;
2768b016486eSRichard Henderson }
2769b016486eSRichard Henderson 
2770b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d)
2771b016486eSRichard Henderson {
2772b016486eSRichard Henderson     if (TCG_TARGET_NB_REGS <= 32) {
2773b016486eSRichard Henderson         return ctz32(d);
2774b016486eSRichard Henderson     } else {
2775b016486eSRichard Henderson         return ctz64(d);
2776b016486eSRichard Henderson     }
2777b016486eSRichard Henderson }
2778b016486eSRichard Henderson 
2779b7a83ff8SRichard Henderson /* Return only the number of characters output -- no error return. */
2780b7a83ff8SRichard Henderson #define ne_fprintf(...) \
2781b7a83ff8SRichard Henderson     ({ int ret_ = fprintf(__VA_ARGS__); ret_ >= 0 ? ret_ : 0; })
2782b7a83ff8SRichard Henderson 
2783b384c734SRichard Henderson void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs)
2784c896fe29Sbellard {
2785c896fe29Sbellard     char buf[128];
2786c45cb8bbSRichard Henderson     TCGOp *op;
2787c896fe29Sbellard 
278815fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
2789c45cb8bbSRichard Henderson         int i, k, nb_oargs, nb_iargs, nb_cargs;
2790c45cb8bbSRichard Henderson         const TCGOpDef *def;
2791c45cb8bbSRichard Henderson         TCGOpcode c;
2792bdfb460eSRichard Henderson         int col = 0;
2793c45cb8bbSRichard Henderson 
2794c45cb8bbSRichard Henderson         c = op->opc;
2795c896fe29Sbellard         def = &tcg_op_defs[c];
2796c45cb8bbSRichard Henderson 
2797765b842aSRichard Henderson         if (c == INDEX_op_insn_start) {
2798b016486eSRichard Henderson             nb_oargs = 0;
2799b7a83ff8SRichard Henderson             col += ne_fprintf(f, "\n ----");
28009aef40edSRichard Henderson 
2801747bd69dSRichard Henderson             for (i = 0, k = s->insn_start_words; i < k; ++i) {
2802c9ad8d27SRichard Henderson                 col += ne_fprintf(f, " %016" PRIx64,
2803c9ad8d27SRichard Henderson                                   tcg_get_insn_start_param(op, i));
2804eeacee4dSBlue Swirl             }
28057e4597d7Sbellard         } else if (c == INDEX_op_call) {
28063e92aa34SRichard Henderson             const TCGHelperInfo *info = tcg_call_info(op);
2807fa52e660SRichard Henderson             void *func = tcg_call_func(op);
28083e92aa34SRichard Henderson 
2809c896fe29Sbellard             /* variable number of arguments */
2810cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
2811cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
2812c896fe29Sbellard             nb_cargs = def->nb_cargs;
2813b03cce8eSbellard 
2814b7a83ff8SRichard Henderson             col += ne_fprintf(f, " %s ", def->name);
28153e92aa34SRichard Henderson 
28163e92aa34SRichard Henderson             /*
28173e92aa34SRichard Henderson              * Print the function name from TCGHelperInfo, if available.
28183e92aa34SRichard Henderson              * Note that plugins have a template function for the info,
28193e92aa34SRichard Henderson              * but the actual function pointer comes from the plugin.
28203e92aa34SRichard Henderson              */
28213e92aa34SRichard Henderson             if (func == info->func) {
2822b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s", info->name);
28233e92aa34SRichard Henderson             } else {
2824b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "plugin(%p)", func);
28253e92aa34SRichard Henderson             }
28263e92aa34SRichard Henderson 
2827b7a83ff8SRichard Henderson             col += ne_fprintf(f, ",$0x%x,$%d", info->flags, nb_oargs);
2828b03cce8eSbellard             for (i = 0; i < nb_oargs; i++) {
2829b7a83ff8SRichard Henderson                 col += ne_fprintf(f, ",%s", tcg_get_arg_str(s, buf, sizeof(buf),
2830efee3746SRichard Henderson                                                             op->args[i]));
2831b03cce8eSbellard             }
2832cf066674SRichard Henderson             for (i = 0; i < nb_iargs; i++) {
2833efee3746SRichard Henderson                 TCGArg arg = op->args[nb_oargs + i];
283439004a71SRichard Henderson                 const char *t = tcg_get_arg_str(s, buf, sizeof(buf), arg);
2835b7a83ff8SRichard Henderson                 col += ne_fprintf(f, ",%s", t);
2836e8996ee0Sbellard             }
2837b03cce8eSbellard         } else {
2838b7a83ff8SRichard Henderson             col += ne_fprintf(f, " %s ", def->name);
2839c45cb8bbSRichard Henderson 
2840c896fe29Sbellard             nb_oargs = def->nb_oargs;
2841c896fe29Sbellard             nb_iargs = def->nb_iargs;
2842c896fe29Sbellard             nb_cargs = def->nb_cargs;
2843c896fe29Sbellard 
2844d2fd745fSRichard Henderson             if (def->flags & TCG_OPF_VECTOR) {
28454d872218SRichard Henderson                 col += ne_fprintf(f, "v%d,e%d,",
28464d872218SRichard Henderson                                   8 * tcg_type_size(TCGOP_TYPE(op)),
2847d2fd745fSRichard Henderson                                   8 << TCGOP_VECE(op));
2848d2fd745fSRichard Henderson             }
2849d2fd745fSRichard Henderson 
2850c896fe29Sbellard             k = 0;
2851c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
2852b7a83ff8SRichard Henderson                 const char *sep =  k ? "," : "";
2853b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s%s", sep,
2854b7a83ff8SRichard Henderson                                   tcg_get_arg_str(s, buf, sizeof(buf),
2855efee3746SRichard Henderson                                                   op->args[k++]));
2856c896fe29Sbellard             }
2857c896fe29Sbellard             for (i = 0; i < nb_iargs; i++) {
2858b7a83ff8SRichard Henderson                 const char *sep =  k ? "," : "";
2859b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s%s", sep,
2860b7a83ff8SRichard Henderson                                   tcg_get_arg_str(s, buf, sizeof(buf),
2861efee3746SRichard Henderson                                                   op->args[k++]));
2862c896fe29Sbellard             }
2863be210acbSRichard Henderson             switch (c) {
2864be210acbSRichard Henderson             case INDEX_op_brcond_i32:
2865ffc5ea09SRichard Henderson             case INDEX_op_setcond_i32:
28663635502dSRichard Henderson             case INDEX_op_negsetcond_i32:
2867ffc5ea09SRichard Henderson             case INDEX_op_movcond_i32:
2868be210acbSRichard Henderson             case INDEX_op_brcond2_i32:
2869be210acbSRichard Henderson             case INDEX_op_setcond2_i32:
2870ffc5ea09SRichard Henderson             case INDEX_op_brcond_i64:
2871be210acbSRichard Henderson             case INDEX_op_setcond_i64:
28723635502dSRichard Henderson             case INDEX_op_negsetcond_i64:
2873ffc5ea09SRichard Henderson             case INDEX_op_movcond_i64:
2874212be173SRichard Henderson             case INDEX_op_cmp_vec:
2875f75da298SRichard Henderson             case INDEX_op_cmpsel_vec:
2876efee3746SRichard Henderson                 if (op->args[k] < ARRAY_SIZE(cond_name)
2877efee3746SRichard Henderson                     && cond_name[op->args[k]]) {
2878b7a83ff8SRichard Henderson                     col += ne_fprintf(f, ",%s", cond_name[op->args[k++]]);
2879eeacee4dSBlue Swirl                 } else {
2880b7a83ff8SRichard Henderson                     col += ne_fprintf(f, ",$0x%" TCG_PRIlx, op->args[k++]);
2881eeacee4dSBlue Swirl                 }
2882f48f3edeSblueswir1                 i = 1;
2883be210acbSRichard Henderson                 break;
2884fecccfccSRichard Henderson             case INDEX_op_qemu_ld_a32_i32:
2885fecccfccSRichard Henderson             case INDEX_op_qemu_ld_a64_i32:
2886fecccfccSRichard Henderson             case INDEX_op_qemu_st_a32_i32:
2887fecccfccSRichard Henderson             case INDEX_op_qemu_st_a64_i32:
2888fecccfccSRichard Henderson             case INDEX_op_qemu_st8_a32_i32:
2889fecccfccSRichard Henderson             case INDEX_op_qemu_st8_a64_i32:
2890fecccfccSRichard Henderson             case INDEX_op_qemu_ld_a32_i64:
2891fecccfccSRichard Henderson             case INDEX_op_qemu_ld_a64_i64:
2892fecccfccSRichard Henderson             case INDEX_op_qemu_st_a32_i64:
2893fecccfccSRichard Henderson             case INDEX_op_qemu_st_a64_i64:
2894fecccfccSRichard Henderson             case INDEX_op_qemu_ld_a32_i128:
2895fecccfccSRichard Henderson             case INDEX_op_qemu_ld_a64_i128:
2896fecccfccSRichard Henderson             case INDEX_op_qemu_st_a32_i128:
2897fecccfccSRichard Henderson             case INDEX_op_qemu_st_a64_i128:
289859227d5dSRichard Henderson                 {
289937031fefSRichard Henderson                     const char *s_al, *s_op, *s_at;
29009002ffcbSRichard Henderson                     MemOpIdx oi = op->args[k++];
29019a239c6eSPhilippe Mathieu-Daudé                     MemOp mop = get_memop(oi);
290259227d5dSRichard Henderson                     unsigned ix = get_mmuidx(oi);
290359227d5dSRichard Henderson 
29049a239c6eSPhilippe Mathieu-Daudé                     s_al = alignment_name[(mop & MO_AMASK) >> MO_ASHIFT];
29059a239c6eSPhilippe Mathieu-Daudé                     s_op = ldst_name[mop & (MO_BSWAP | MO_SSIZE)];
29069a239c6eSPhilippe Mathieu-Daudé                     s_at = atom_name[(mop & MO_ATOM_MASK) >> MO_ATOM_SHIFT];
29079a239c6eSPhilippe Mathieu-Daudé                     mop &= ~(MO_AMASK | MO_BSWAP | MO_SSIZE | MO_ATOM_MASK);
290837031fefSRichard Henderson 
290937031fefSRichard Henderson                     /* If all fields are accounted for, print symbolically. */
29109a239c6eSPhilippe Mathieu-Daudé                     if (!mop && s_al && s_op && s_at) {
291137031fefSRichard Henderson                         col += ne_fprintf(f, ",%s%s%s,%u",
291237031fefSRichard Henderson                                           s_at, s_al, s_op, ix);
291337031fefSRichard Henderson                     } else {
29149a239c6eSPhilippe Mathieu-Daudé                         mop = get_memop(oi);
29159a239c6eSPhilippe Mathieu-Daudé                         col += ne_fprintf(f, ",$0x%x,%u", mop, ix);
2916f713d6adSRichard Henderson                     }
2917f713d6adSRichard Henderson                     i = 1;
291859227d5dSRichard Henderson                 }
2919f713d6adSRichard Henderson                 break;
2920587195bdSRichard Henderson             case INDEX_op_bswap16_i32:
2921587195bdSRichard Henderson             case INDEX_op_bswap16_i64:
2922587195bdSRichard Henderson             case INDEX_op_bswap32_i32:
2923587195bdSRichard Henderson             case INDEX_op_bswap32_i64:
2924587195bdSRichard Henderson             case INDEX_op_bswap64_i64:
2925587195bdSRichard Henderson                 {
2926587195bdSRichard Henderson                     TCGArg flags = op->args[k];
2927587195bdSRichard Henderson                     const char *name = NULL;
2928587195bdSRichard Henderson 
2929587195bdSRichard Henderson                     if (flags < ARRAY_SIZE(bswap_flag_name)) {
2930587195bdSRichard Henderson                         name = bswap_flag_name[flags];
2931587195bdSRichard Henderson                     }
2932587195bdSRichard Henderson                     if (name) {
2933b7a83ff8SRichard Henderson                         col += ne_fprintf(f, ",%s", name);
2934587195bdSRichard Henderson                     } else {
2935b7a83ff8SRichard Henderson                         col += ne_fprintf(f, ",$0x%" TCG_PRIlx, flags);
2936587195bdSRichard Henderson                     }
2937587195bdSRichard Henderson                     i = k = 1;
2938587195bdSRichard Henderson                 }
2939587195bdSRichard Henderson                 break;
2940b384c734SRichard Henderson #ifdef CONFIG_PLUGIN
2941b384c734SRichard Henderson             case INDEX_op_plugin_cb:
2942b384c734SRichard Henderson                 {
2943b384c734SRichard Henderson                     TCGArg from = op->args[k++];
2944b384c734SRichard Henderson                     const char *name = NULL;
2945b384c734SRichard Henderson 
2946b384c734SRichard Henderson                     if (from < ARRAY_SIZE(plugin_from_name)) {
2947b384c734SRichard Henderson                         name = plugin_from_name[from];
2948b384c734SRichard Henderson                     }
2949b384c734SRichard Henderson                     if (name) {
2950b384c734SRichard Henderson                         col += ne_fprintf(f, "%s", name);
2951b384c734SRichard Henderson                     } else {
2952b384c734SRichard Henderson                         col += ne_fprintf(f, "$0x%" TCG_PRIlx, from);
2953b384c734SRichard Henderson                     }
2954b384c734SRichard Henderson                     i = 1;
2955b384c734SRichard Henderson                 }
2956b384c734SRichard Henderson                 break;
2957b384c734SRichard Henderson #endif
2958be210acbSRichard Henderson             default:
2959f48f3edeSblueswir1                 i = 0;
2960be210acbSRichard Henderson                 break;
2961be210acbSRichard Henderson             }
296251e3972cSRichard Henderson             switch (c) {
296351e3972cSRichard Henderson             case INDEX_op_set_label:
296451e3972cSRichard Henderson             case INDEX_op_br:
296551e3972cSRichard Henderson             case INDEX_op_brcond_i32:
296651e3972cSRichard Henderson             case INDEX_op_brcond_i64:
296751e3972cSRichard Henderson             case INDEX_op_brcond2_i32:
2968b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s$L%d", k ? "," : "",
2969efee3746SRichard Henderson                                   arg_label(op->args[k])->id);
297051e3972cSRichard Henderson                 i++, k++;
297151e3972cSRichard Henderson                 break;
29723470867bSRichard Henderson             case INDEX_op_mb:
29733470867bSRichard Henderson                 {
29743470867bSRichard Henderson                     TCGBar membar = op->args[k];
29753470867bSRichard Henderson                     const char *b_op, *m_op;
29763470867bSRichard Henderson 
29773470867bSRichard Henderson                     switch (membar & TCG_BAR_SC) {
29783470867bSRichard Henderson                     case 0:
29793470867bSRichard Henderson                         b_op = "none";
29803470867bSRichard Henderson                         break;
29813470867bSRichard Henderson                     case TCG_BAR_LDAQ:
29823470867bSRichard Henderson                         b_op = "acq";
29833470867bSRichard Henderson                         break;
29843470867bSRichard Henderson                     case TCG_BAR_STRL:
29853470867bSRichard Henderson                         b_op = "rel";
29863470867bSRichard Henderson                         break;
29873470867bSRichard Henderson                     case TCG_BAR_SC:
29883470867bSRichard Henderson                         b_op = "seq";
29893470867bSRichard Henderson                         break;
29903470867bSRichard Henderson                     default:
29913470867bSRichard Henderson                         g_assert_not_reached();
29923470867bSRichard Henderson                     }
29933470867bSRichard Henderson 
29943470867bSRichard Henderson                     switch (membar & TCG_MO_ALL) {
29953470867bSRichard Henderson                     case 0:
29963470867bSRichard Henderson                         m_op = "none";
29973470867bSRichard Henderson                         break;
29983470867bSRichard Henderson                     case TCG_MO_LD_LD:
29993470867bSRichard Henderson                         m_op = "rr";
30003470867bSRichard Henderson                         break;
30013470867bSRichard Henderson                     case TCG_MO_LD_ST:
30023470867bSRichard Henderson                         m_op = "rw";
30033470867bSRichard Henderson                         break;
30043470867bSRichard Henderson                     case TCG_MO_ST_LD:
30053470867bSRichard Henderson                         m_op = "wr";
30063470867bSRichard Henderson                         break;
30073470867bSRichard Henderson                     case TCG_MO_ST_ST:
30083470867bSRichard Henderson                         m_op = "ww";
30093470867bSRichard Henderson                         break;
30103470867bSRichard Henderson                     case TCG_MO_LD_LD | TCG_MO_LD_ST:
30113470867bSRichard Henderson                         m_op = "rr+rw";
30123470867bSRichard Henderson                         break;
30133470867bSRichard Henderson                     case TCG_MO_LD_LD | TCG_MO_ST_LD:
30143470867bSRichard Henderson                         m_op = "rr+wr";
30153470867bSRichard Henderson                         break;
30163470867bSRichard Henderson                     case TCG_MO_LD_LD | TCG_MO_ST_ST:
30173470867bSRichard Henderson                         m_op = "rr+ww";
30183470867bSRichard Henderson                         break;
30193470867bSRichard Henderson                     case TCG_MO_LD_ST | TCG_MO_ST_LD:
30203470867bSRichard Henderson                         m_op = "rw+wr";
30213470867bSRichard Henderson                         break;
30223470867bSRichard Henderson                     case TCG_MO_LD_ST | TCG_MO_ST_ST:
30233470867bSRichard Henderson                         m_op = "rw+ww";
30243470867bSRichard Henderson                         break;
30253470867bSRichard Henderson                     case TCG_MO_ST_LD | TCG_MO_ST_ST:
30263470867bSRichard Henderson                         m_op = "wr+ww";
30273470867bSRichard Henderson                         break;
30283470867bSRichard Henderson                     case TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_MO_ST_LD:
30293470867bSRichard Henderson                         m_op = "rr+rw+wr";
30303470867bSRichard Henderson                         break;
30313470867bSRichard Henderson                     case TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_MO_ST_ST:
30323470867bSRichard Henderson                         m_op = "rr+rw+ww";
30333470867bSRichard Henderson                         break;
30343470867bSRichard Henderson                     case TCG_MO_LD_LD | TCG_MO_ST_LD | TCG_MO_ST_ST:
30353470867bSRichard Henderson                         m_op = "rr+wr+ww";
30363470867bSRichard Henderson                         break;
30373470867bSRichard Henderson                     case TCG_MO_LD_ST | TCG_MO_ST_LD | TCG_MO_ST_ST:
30383470867bSRichard Henderson                         m_op = "rw+wr+ww";
30393470867bSRichard Henderson                         break;
30403470867bSRichard Henderson                     case TCG_MO_ALL:
30413470867bSRichard Henderson                         m_op = "all";
30423470867bSRichard Henderson                         break;
30433470867bSRichard Henderson                     default:
30443470867bSRichard Henderson                         g_assert_not_reached();
30453470867bSRichard Henderson                     }
30463470867bSRichard Henderson 
30473470867bSRichard Henderson                     col += ne_fprintf(f, "%s%s:%s", (k ? "," : ""), b_op, m_op);
30483470867bSRichard Henderson                     i++, k++;
30493470867bSRichard Henderson                 }
30503470867bSRichard Henderson                 break;
305151e3972cSRichard Henderson             default:
305251e3972cSRichard Henderson                 break;
3053eeacee4dSBlue Swirl             }
305451e3972cSRichard Henderson             for (; i < nb_cargs; i++, k++) {
3055b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s$0x%" TCG_PRIlx, k ? "," : "",
3056b7a83ff8SRichard Henderson                                   op->args[k]);
3057bdfb460eSRichard Henderson             }
3058bdfb460eSRichard Henderson         }
3059bdfb460eSRichard Henderson 
30601894f69aSRichard Henderson         if (have_prefs || op->life) {
30611894f69aSRichard Henderson             for (; col < 40; ++col) {
3062b7a83ff8SRichard Henderson                 putc(' ', f);
3063bdfb460eSRichard Henderson             }
30641894f69aSRichard Henderson         }
30651894f69aSRichard Henderson 
30661894f69aSRichard Henderson         if (op->life) {
30671894f69aSRichard Henderson             unsigned life = op->life;
3068bdfb460eSRichard Henderson 
3069bdfb460eSRichard Henderson             if (life & (SYNC_ARG * 3)) {
3070b7a83ff8SRichard Henderson                 ne_fprintf(f, "  sync:");
3071bdfb460eSRichard Henderson                 for (i = 0; i < 2; ++i) {
3072bdfb460eSRichard Henderson                     if (life & (SYNC_ARG << i)) {
3073b7a83ff8SRichard Henderson                         ne_fprintf(f, " %d", i);
3074bdfb460eSRichard Henderson                     }
3075bdfb460eSRichard Henderson                 }
3076bdfb460eSRichard Henderson             }
3077bdfb460eSRichard Henderson             life /= DEAD_ARG;
3078bdfb460eSRichard Henderson             if (life) {
3079b7a83ff8SRichard Henderson                 ne_fprintf(f, "  dead:");
3080bdfb460eSRichard Henderson                 for (i = 0; life; ++i, life >>= 1) {
3081bdfb460eSRichard Henderson                     if (life & 1) {
3082b7a83ff8SRichard Henderson                         ne_fprintf(f, " %d", i);
3083bdfb460eSRichard Henderson                     }
3084bdfb460eSRichard Henderson                 }
3085c896fe29Sbellard             }
3086b03cce8eSbellard         }
30871894f69aSRichard Henderson 
30881894f69aSRichard Henderson         if (have_prefs) {
30891894f69aSRichard Henderson             for (i = 0; i < nb_oargs; ++i) {
309031fd884bSRichard Henderson                 TCGRegSet set = output_pref(op, i);
30911894f69aSRichard Henderson 
30921894f69aSRichard Henderson                 if (i == 0) {
3093b7a83ff8SRichard Henderson                     ne_fprintf(f, "  pref=");
30941894f69aSRichard Henderson                 } else {
3095b7a83ff8SRichard Henderson                     ne_fprintf(f, ",");
30961894f69aSRichard Henderson                 }
30971894f69aSRichard Henderson                 if (set == 0) {
3098b7a83ff8SRichard Henderson                     ne_fprintf(f, "none");
30991894f69aSRichard Henderson                 } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) {
3100b7a83ff8SRichard Henderson                     ne_fprintf(f, "all");
31011894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG
31021894f69aSRichard Henderson                 } else if (tcg_regset_single(set)) {
31031894f69aSRichard Henderson                     TCGReg reg = tcg_regset_first(set);
3104b7a83ff8SRichard Henderson                     ne_fprintf(f, "%s", tcg_target_reg_names[reg]);
31051894f69aSRichard Henderson #endif
31061894f69aSRichard Henderson                 } else if (TCG_TARGET_NB_REGS <= 32) {
3107b7a83ff8SRichard Henderson                     ne_fprintf(f, "0x%x", (uint32_t)set);
31081894f69aSRichard Henderson                 } else {
3109b7a83ff8SRichard Henderson                     ne_fprintf(f, "0x%" PRIx64, (uint64_t)set);
31101894f69aSRichard Henderson                 }
31111894f69aSRichard Henderson             }
31121894f69aSRichard Henderson         }
31131894f69aSRichard Henderson 
3114b7a83ff8SRichard Henderson         putc('\n', f);
3115c896fe29Sbellard     }
3116c896fe29Sbellard }
3117c896fe29Sbellard 
3118c896fe29Sbellard /* we give more priority to constraints with less registers */
31193e80824eSRichard Henderson static int get_constraint_priority(const TCGArgConstraint *arg_ct, int k)
3120c896fe29Sbellard {
31213e80824eSRichard Henderson     int n;
31223e80824eSRichard Henderson 
31233e80824eSRichard Henderson     arg_ct += k;
31243e80824eSRichard Henderson     n = ctpop64(arg_ct->regs);
3125c896fe29Sbellard 
312629f5e925SRichard Henderson     /*
312729f5e925SRichard Henderson      * Sort constraints of a single register first, which includes output
312829f5e925SRichard Henderson      * aliases (which must exactly match the input already allocated).
312929f5e925SRichard Henderson      */
313029f5e925SRichard Henderson     if (n == 1 || arg_ct->oalias) {
313129f5e925SRichard Henderson         return INT_MAX;
3132c896fe29Sbellard     }
313329f5e925SRichard Henderson 
313429f5e925SRichard Henderson     /*
313529f5e925SRichard Henderson      * Sort register pairs next, first then second immediately after.
313629f5e925SRichard Henderson      * Arbitrarily sort multiple pairs by the index of the first reg;
313729f5e925SRichard Henderson      * there shouldn't be many pairs.
313829f5e925SRichard Henderson      */
313929f5e925SRichard Henderson     switch (arg_ct->pair) {
314029f5e925SRichard Henderson     case 1:
314129f5e925SRichard Henderson     case 3:
314229f5e925SRichard Henderson         return (k + 1) * 2;
314329f5e925SRichard Henderson     case 2:
314429f5e925SRichard Henderson         return (arg_ct->pair_index + 1) * 2 - 1;
314529f5e925SRichard Henderson     }
314629f5e925SRichard Henderson 
314729f5e925SRichard Henderson     /* Finally, sort by decreasing register count. */
314829f5e925SRichard Henderson     assert(n > 1);
314929f5e925SRichard Henderson     return -n;
3150c896fe29Sbellard }
3151c896fe29Sbellard 
3152c896fe29Sbellard /* sort from highest priority to lowest */
31533e80824eSRichard Henderson static void sort_constraints(TCGArgConstraint *a, int start, int n)
3154c896fe29Sbellard {
315566792f90SRichard Henderson     int i, j;
3156c896fe29Sbellard 
315766792f90SRichard Henderson     for (i = 0; i < n; i++) {
315866792f90SRichard Henderson         a[start + i].sort_index = start + i;
315966792f90SRichard Henderson     }
316066792f90SRichard Henderson     if (n <= 1) {
3161c896fe29Sbellard         return;
316266792f90SRichard Henderson     }
3163c896fe29Sbellard     for (i = 0; i < n - 1; i++) {
3164c896fe29Sbellard         for (j = i + 1; j < n; j++) {
31653e80824eSRichard Henderson             int p1 = get_constraint_priority(a, a[start + i].sort_index);
31663e80824eSRichard Henderson             int p2 = get_constraint_priority(a, a[start + j].sort_index);
3167c896fe29Sbellard             if (p1 < p2) {
316866792f90SRichard Henderson                 int tmp = a[start + i].sort_index;
316966792f90SRichard Henderson                 a[start + i].sort_index = a[start + j].sort_index;
317066792f90SRichard Henderson                 a[start + j].sort_index = tmp;
3171c896fe29Sbellard             }
3172c896fe29Sbellard         }
3173c896fe29Sbellard     }
3174c896fe29Sbellard }
3175c896fe29Sbellard 
31763e80824eSRichard Henderson static const TCGArgConstraint empty_cts[TCG_MAX_OP_ARGS];
31773e80824eSRichard Henderson static TCGArgConstraint all_cts[ARRAY_SIZE(constraint_sets)][TCG_MAX_OP_ARGS];
31783e80824eSRichard Henderson 
3179501fb3daSRichard Henderson static void process_constraint_sets(void)
3180c896fe29Sbellard {
31813e80824eSRichard Henderson     for (size_t c = 0; c < ARRAY_SIZE(constraint_sets); ++c) {
31823e80824eSRichard Henderson         const TCGConstraintSet *tdefs = &constraint_sets[c];
31833e80824eSRichard Henderson         TCGArgConstraint *args_ct = all_cts[c];
31843e80824eSRichard Henderson         int nb_oargs = tdefs->nb_oargs;
31853e80824eSRichard Henderson         int nb_iargs = tdefs->nb_iargs;
31863e80824eSRichard Henderson         int nb_args = nb_oargs + nb_iargs;
318729f5e925SRichard Henderson         bool saw_alias_pair = false;
3188f69d277eSRichard Henderson 
31893e80824eSRichard Henderson         for (int i = 0; i < nb_args; i++) {
3190f69d277eSRichard Henderson             const char *ct_str = tdefs->args_ct_str[i];
31913e80824eSRichard Henderson             bool input_p = i >= nb_oargs;
31923e80824eSRichard Henderson             int o;
3193f69d277eSRichard Henderson 
319417280ff4SRichard Henderson             switch (*ct_str) {
319517280ff4SRichard Henderson             case '0' ... '9':
31968940ea0dSPhilippe Mathieu-Daudé                 o = *ct_str - '0';
31978940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(input_p);
31983e80824eSRichard Henderson                 tcg_debug_assert(o < nb_oargs);
31993e80824eSRichard Henderson                 tcg_debug_assert(args_ct[o].regs != 0);
32003e80824eSRichard Henderson                 tcg_debug_assert(!args_ct[o].oalias);
32013e80824eSRichard Henderson                 args_ct[i] = args_ct[o];
3202bc2b17e6SRichard Henderson                 /* The output sets oalias.  */
32033e80824eSRichard Henderson                 args_ct[o].oalias = 1;
32043e80824eSRichard Henderson                 args_ct[o].alias_index = i;
3205bc2b17e6SRichard Henderson                 /* The input sets ialias. */
32063e80824eSRichard Henderson                 args_ct[i].ialias = 1;
32073e80824eSRichard Henderson                 args_ct[i].alias_index = o;
32083e80824eSRichard Henderson                 if (args_ct[i].pair) {
320929f5e925SRichard Henderson                     saw_alias_pair = true;
321029f5e925SRichard Henderson                 }
32118940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(ct_str[1] == '\0');
32128940ea0dSPhilippe Mathieu-Daudé                 continue;
32138940ea0dSPhilippe Mathieu-Daudé 
321482790a87SRichard Henderson             case '&':
32158940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(!input_p);
32163e80824eSRichard Henderson                 args_ct[i].newreg = true;
321782790a87SRichard Henderson                 ct_str++;
321882790a87SRichard Henderson                 break;
321929f5e925SRichard Henderson 
322029f5e925SRichard Henderson             case 'p': /* plus */
322129f5e925SRichard Henderson                 /* Allocate to the register after the previous. */
32223e80824eSRichard Henderson                 tcg_debug_assert(i > (input_p ? nb_oargs : 0));
322329f5e925SRichard Henderson                 o = i - 1;
32243e80824eSRichard Henderson                 tcg_debug_assert(!args_ct[o].pair);
32253e80824eSRichard Henderson                 tcg_debug_assert(!args_ct[o].ct);
32263e80824eSRichard Henderson                 args_ct[i] = (TCGArgConstraint){
322729f5e925SRichard Henderson                     .pair = 2,
322829f5e925SRichard Henderson                     .pair_index = o,
32293e80824eSRichard Henderson                     .regs = args_ct[o].regs << 1,
32303e80824eSRichard Henderson                     .newreg = args_ct[o].newreg,
323129f5e925SRichard Henderson                 };
32323e80824eSRichard Henderson                 args_ct[o].pair = 1;
32333e80824eSRichard Henderson                 args_ct[o].pair_index = i;
323429f5e925SRichard Henderson                 tcg_debug_assert(ct_str[1] == '\0');
323529f5e925SRichard Henderson                 continue;
323629f5e925SRichard Henderson 
323729f5e925SRichard Henderson             case 'm': /* minus */
323829f5e925SRichard Henderson                 /* Allocate to the register before the previous. */
32393e80824eSRichard Henderson                 tcg_debug_assert(i > (input_p ? nb_oargs : 0));
324029f5e925SRichard Henderson                 o = i - 1;
32413e80824eSRichard Henderson                 tcg_debug_assert(!args_ct[o].pair);
32423e80824eSRichard Henderson                 tcg_debug_assert(!args_ct[o].ct);
32433e80824eSRichard Henderson                 args_ct[i] = (TCGArgConstraint){
324429f5e925SRichard Henderson                     .pair = 1,
324529f5e925SRichard Henderson                     .pair_index = o,
32463e80824eSRichard Henderson                     .regs = args_ct[o].regs >> 1,
32473e80824eSRichard Henderson                     .newreg = args_ct[o].newreg,
324829f5e925SRichard Henderson                 };
32493e80824eSRichard Henderson                 args_ct[o].pair = 2;
32503e80824eSRichard Henderson                 args_ct[o].pair_index = i;
325129f5e925SRichard Henderson                 tcg_debug_assert(ct_str[1] == '\0');
325229f5e925SRichard Henderson                 continue;
32538940ea0dSPhilippe Mathieu-Daudé             }
32548940ea0dSPhilippe Mathieu-Daudé 
32558940ea0dSPhilippe Mathieu-Daudé             do {
32568940ea0dSPhilippe Mathieu-Daudé                 switch (*ct_str) {
3257c896fe29Sbellard                 case 'i':
32583e80824eSRichard Henderson                     args_ct[i].ct |= TCG_CT_CONST;
3259c896fe29Sbellard                     break;
3260358b4923SRichard Henderson 
3261358b4923SRichard Henderson                 /* Include all of the target-specific constraints. */
3262358b4923SRichard Henderson 
3263358b4923SRichard Henderson #undef CONST
3264358b4923SRichard Henderson #define CONST(CASE, MASK) \
32653e80824eSRichard Henderson     case CASE: args_ct[i].ct |= MASK; break;
3266358b4923SRichard Henderson #define REGS(CASE, MASK) \
32673e80824eSRichard Henderson     case CASE: args_ct[i].regs |= MASK; break;
3268358b4923SRichard Henderson 
3269358b4923SRichard Henderson #include "tcg-target-con-str.h"
3270358b4923SRichard Henderson 
3271358b4923SRichard Henderson #undef REGS
3272358b4923SRichard Henderson #undef CONST
3273c896fe29Sbellard                 default:
32748940ea0dSPhilippe Mathieu-Daudé                 case '0' ... '9':
32758940ea0dSPhilippe Mathieu-Daudé                 case '&':
327629f5e925SRichard Henderson                 case 'p':
327729f5e925SRichard Henderson                 case 'm':
32783e80824eSRichard Henderson                     /* Typo in TCGConstraintSet constraint. */
3279358b4923SRichard Henderson                     g_assert_not_reached();
3280358b4923SRichard Henderson                 }
32818940ea0dSPhilippe Mathieu-Daudé             } while (*++ct_str != '\0');
3282c896fe29Sbellard         }
3283c896fe29Sbellard 
328429f5e925SRichard Henderson         /*
328529f5e925SRichard Henderson          * Fix up output pairs that are aliased with inputs.
328629f5e925SRichard Henderson          * When we created the alias, we copied pair from the output.
328729f5e925SRichard Henderson          * There are three cases:
328829f5e925SRichard Henderson          *    (1a) Pairs of inputs alias pairs of outputs.
328929f5e925SRichard Henderson          *    (1b) One input aliases the first of a pair of outputs.
329029f5e925SRichard Henderson          *    (2)  One input aliases the second of a pair of outputs.
329129f5e925SRichard Henderson          *
329229f5e925SRichard Henderson          * Case 1a is handled by making sure that the pair_index'es are
329329f5e925SRichard Henderson          * properly updated so that they appear the same as a pair of inputs.
329429f5e925SRichard Henderson          *
329529f5e925SRichard Henderson          * Case 1b is handled by setting the pair_index of the input to
329629f5e925SRichard Henderson          * itself, simply so it doesn't point to an unrelated argument.
329729f5e925SRichard Henderson          * Since we don't encounter the "second" during the input allocation
329829f5e925SRichard Henderson          * phase, nothing happens with the second half of the input pair.
329929f5e925SRichard Henderson          *
330029f5e925SRichard Henderson          * Case 2 is handled by setting the second input to pair=3, the
330129f5e925SRichard Henderson          * first output to pair=3, and the pair_index'es to match.
330229f5e925SRichard Henderson          */
330329f5e925SRichard Henderson         if (saw_alias_pair) {
33043e80824eSRichard Henderson             for (int i = nb_oargs; i < nb_args; i++) {
33053e80824eSRichard Henderson                 int o, o2, i2;
33063e80824eSRichard Henderson 
330729f5e925SRichard Henderson                 /*
330829f5e925SRichard Henderson                  * Since [0-9pm] must be alone in the constraint string,
330929f5e925SRichard Henderson                  * the only way they can both be set is if the pair comes
331029f5e925SRichard Henderson                  * from the output alias.
331129f5e925SRichard Henderson                  */
33123e80824eSRichard Henderson                 if (!args_ct[i].ialias) {
331329f5e925SRichard Henderson                     continue;
331429f5e925SRichard Henderson                 }
33153e80824eSRichard Henderson                 switch (args_ct[i].pair) {
331629f5e925SRichard Henderson                 case 0:
331729f5e925SRichard Henderson                     break;
331829f5e925SRichard Henderson                 case 1:
33193e80824eSRichard Henderson                     o = args_ct[i].alias_index;
33203e80824eSRichard Henderson                     o2 = args_ct[o].pair_index;
33213e80824eSRichard Henderson                     tcg_debug_assert(args_ct[o].pair == 1);
33223e80824eSRichard Henderson                     tcg_debug_assert(args_ct[o2].pair == 2);
33233e80824eSRichard Henderson                     if (args_ct[o2].oalias) {
332429f5e925SRichard Henderson                         /* Case 1a */
33253e80824eSRichard Henderson                         i2 = args_ct[o2].alias_index;
33263e80824eSRichard Henderson                         tcg_debug_assert(args_ct[i2].pair == 2);
33273e80824eSRichard Henderson                         args_ct[i2].pair_index = i;
33283e80824eSRichard Henderson                         args_ct[i].pair_index = i2;
332929f5e925SRichard Henderson                     } else {
333029f5e925SRichard Henderson                         /* Case 1b */
33313e80824eSRichard Henderson                         args_ct[i].pair_index = i;
333229f5e925SRichard Henderson                     }
333329f5e925SRichard Henderson                     break;
333429f5e925SRichard Henderson                 case 2:
33353e80824eSRichard Henderson                     o = args_ct[i].alias_index;
33363e80824eSRichard Henderson                     o2 = args_ct[o].pair_index;
33373e80824eSRichard Henderson                     tcg_debug_assert(args_ct[o].pair == 2);
33383e80824eSRichard Henderson                     tcg_debug_assert(args_ct[o2].pair == 1);
33393e80824eSRichard Henderson                     if (args_ct[o2].oalias) {
334029f5e925SRichard Henderson                         /* Case 1a */
33413e80824eSRichard Henderson                         i2 = args_ct[o2].alias_index;
33423e80824eSRichard Henderson                         tcg_debug_assert(args_ct[i2].pair == 1);
33433e80824eSRichard Henderson                         args_ct[i2].pair_index = i;
33443e80824eSRichard Henderson                         args_ct[i].pair_index = i2;
334529f5e925SRichard Henderson                     } else {
334629f5e925SRichard Henderson                         /* Case 2 */
33473e80824eSRichard Henderson                         args_ct[i].pair = 3;
33483e80824eSRichard Henderson                         args_ct[o2].pair = 3;
33493e80824eSRichard Henderson                         args_ct[i].pair_index = o2;
33503e80824eSRichard Henderson                         args_ct[o2].pair_index = i;
335129f5e925SRichard Henderson                     }
335229f5e925SRichard Henderson                     break;
335329f5e925SRichard Henderson                 default:
335429f5e925SRichard Henderson                     g_assert_not_reached();
335529f5e925SRichard Henderson                 }
335629f5e925SRichard Henderson             }
335729f5e925SRichard Henderson         }
335829f5e925SRichard Henderson 
3359c896fe29Sbellard         /* sort the constraints (XXX: this is just an heuristic) */
33603e80824eSRichard Henderson         sort_constraints(args_ct, 0, nb_oargs);
33613e80824eSRichard Henderson         sort_constraints(args_ct, nb_oargs, nb_iargs);
33623e80824eSRichard Henderson     }
3363501fb3daSRichard Henderson }
33643e80824eSRichard Henderson 
3365501fb3daSRichard Henderson static const TCGArgConstraint *opcode_args_ct(const TCGOp *op)
3366501fb3daSRichard Henderson {
3367ed1a653bSRichard Henderson     const TCGOpDef *def = &tcg_op_defs[op->opc];
33683e80824eSRichard Henderson     TCGConstraintSetIndex con_set;
33693e80824eSRichard Henderson 
3370b277cdd2SRichard Henderson #ifdef CONFIG_DEBUG_TCG
3371b277cdd2SRichard Henderson     assert(tcg_op_supported(op->opc, TCGOP_TYPE(op), TCGOP_FLAGS(op)));
3372b277cdd2SRichard Henderson #endif
3373b277cdd2SRichard Henderson 
33743e80824eSRichard Henderson     if (def->flags & TCG_OPF_NOT_PRESENT) {
3375501fb3daSRichard Henderson         return empty_cts;
33763e80824eSRichard Henderson     }
33773e80824eSRichard Henderson 
33786323b363SRichard Henderson     con_set = tcg_target_op_def(op->opc, TCGOP_TYPE(op), TCGOP_FLAGS(op));
33793e80824eSRichard Henderson     tcg_debug_assert(con_set >= 0 && con_set < ARRAY_SIZE(constraint_sets));
33803e80824eSRichard Henderson 
33813e80824eSRichard Henderson     /* The constraint arguments must match TCGOpcode arguments. */
3382501fb3daSRichard Henderson     tcg_debug_assert(constraint_sets[con_set].nb_oargs == def->nb_oargs);
3383501fb3daSRichard Henderson     tcg_debug_assert(constraint_sets[con_set].nb_iargs == def->nb_iargs);
33843e80824eSRichard Henderson 
3385501fb3daSRichard Henderson     return all_cts[con_set];
3386c896fe29Sbellard }
3387c896fe29Sbellard 
3388f85b1fc4SRichard Henderson static void remove_label_use(TCGOp *op, int idx)
3389f85b1fc4SRichard Henderson {
3390f85b1fc4SRichard Henderson     TCGLabel *label = arg_label(op->args[idx]);
3391f85b1fc4SRichard Henderson     TCGLabelUse *use;
3392f85b1fc4SRichard Henderson 
3393f85b1fc4SRichard Henderson     QSIMPLEQ_FOREACH(use, &label->branches, next) {
3394f85b1fc4SRichard Henderson         if (use->op == op) {
3395f85b1fc4SRichard Henderson             QSIMPLEQ_REMOVE(&label->branches, use, TCGLabelUse, next);
3396f85b1fc4SRichard Henderson             return;
3397f85b1fc4SRichard Henderson         }
3398f85b1fc4SRichard Henderson     }
3399f85b1fc4SRichard Henderson     g_assert_not_reached();
3400f85b1fc4SRichard Henderson }
3401f85b1fc4SRichard Henderson 
34020c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op)
34030c627cdcSRichard Henderson {
3404d88a117eSRichard Henderson     switch (op->opc) {
3405d88a117eSRichard Henderson     case INDEX_op_br:
3406f85b1fc4SRichard Henderson         remove_label_use(op, 0);
3407d88a117eSRichard Henderson         break;
3408d88a117eSRichard Henderson     case INDEX_op_brcond_i32:
3409d88a117eSRichard Henderson     case INDEX_op_brcond_i64:
3410f85b1fc4SRichard Henderson         remove_label_use(op, 3);
3411d88a117eSRichard Henderson         break;
3412d88a117eSRichard Henderson     case INDEX_op_brcond2_i32:
3413f85b1fc4SRichard Henderson         remove_label_use(op, 5);
3414d88a117eSRichard Henderson         break;
3415d88a117eSRichard Henderson     default:
3416d88a117eSRichard Henderson         break;
3417d88a117eSRichard Henderson     }
3418d88a117eSRichard Henderson 
341915fa08f8SRichard Henderson     QTAILQ_REMOVE(&s->ops, op, link);
342015fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&s->free_ops, op, link);
3421abebf925SRichard Henderson     s->nb_ops--;
34220c627cdcSRichard Henderson }
34230c627cdcSRichard Henderson 
3424a80cdd31SRichard Henderson void tcg_remove_ops_after(TCGOp *op)
3425a80cdd31SRichard Henderson {
3426a80cdd31SRichard Henderson     TCGContext *s = tcg_ctx;
3427a80cdd31SRichard Henderson 
3428a80cdd31SRichard Henderson     while (true) {
3429a80cdd31SRichard Henderson         TCGOp *last = tcg_last_op();
3430a80cdd31SRichard Henderson         if (last == op) {
3431a80cdd31SRichard Henderson             return;
3432a80cdd31SRichard Henderson         }
3433a80cdd31SRichard Henderson         tcg_op_remove(s, last);
3434a80cdd31SRichard Henderson     }
3435a80cdd31SRichard Henderson }
3436a80cdd31SRichard Henderson 
3437d4478943SPhilippe Mathieu-Daudé static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs)
343815fa08f8SRichard Henderson {
343915fa08f8SRichard Henderson     TCGContext *s = tcg_ctx;
3440cb10bc63SRichard Henderson     TCGOp *op = NULL;
344115fa08f8SRichard Henderson 
3442cb10bc63SRichard Henderson     if (unlikely(!QTAILQ_EMPTY(&s->free_ops))) {
3443cb10bc63SRichard Henderson         QTAILQ_FOREACH(op, &s->free_ops, link) {
3444cb10bc63SRichard Henderson             if (nargs <= op->nargs) {
344515fa08f8SRichard Henderson                 QTAILQ_REMOVE(&s->free_ops, op, link);
3446cb10bc63SRichard Henderson                 nargs = op->nargs;
3447cb10bc63SRichard Henderson                 goto found;
344815fa08f8SRichard Henderson             }
3449cb10bc63SRichard Henderson         }
3450cb10bc63SRichard Henderson     }
3451cb10bc63SRichard Henderson 
3452cb10bc63SRichard Henderson     /* Most opcodes have 3 or 4 operands: reduce fragmentation. */
3453cb10bc63SRichard Henderson     nargs = MAX(4, nargs);
3454cb10bc63SRichard Henderson     op = tcg_malloc(sizeof(TCGOp) + sizeof(TCGArg) * nargs);
3455cb10bc63SRichard Henderson 
3456cb10bc63SRichard Henderson  found:
345715fa08f8SRichard Henderson     memset(op, 0, offsetof(TCGOp, link));
345815fa08f8SRichard Henderson     op->opc = opc;
3459cb10bc63SRichard Henderson     op->nargs = nargs;
346015fa08f8SRichard Henderson 
3461cb10bc63SRichard Henderson     /* Check for bitfield overflow. */
3462cb10bc63SRichard Henderson     tcg_debug_assert(op->nargs == nargs);
3463cb10bc63SRichard Henderson 
3464cb10bc63SRichard Henderson     s->nb_ops++;
346515fa08f8SRichard Henderson     return op;
346615fa08f8SRichard Henderson }
346715fa08f8SRichard Henderson 
3468d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_emit_op(TCGOpcode opc, unsigned nargs)
346915fa08f8SRichard Henderson {
3470d4478943SPhilippe Mathieu-Daudé     TCGOp *op = tcg_op_alloc(opc, nargs);
347107843f75SRichard Henderson 
347207843f75SRichard Henderson     if (tcg_ctx->emit_before_op) {
347307843f75SRichard Henderson         QTAILQ_INSERT_BEFORE(tcg_ctx->emit_before_op, op, link);
347407843f75SRichard Henderson     } else {
347515fa08f8SRichard Henderson         QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
347607843f75SRichard Henderson     }
347715fa08f8SRichard Henderson     return op;
347815fa08f8SRichard Henderson }
347915fa08f8SRichard Henderson 
3480d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op,
3481d4478943SPhilippe Mathieu-Daudé                             TCGOpcode opc, unsigned nargs)
34825a18407fSRichard Henderson {
3483d4478943SPhilippe Mathieu-Daudé     TCGOp *new_op = tcg_op_alloc(opc, nargs);
3484fb744eceSRichard Henderson 
3485fb744eceSRichard Henderson     TCGOP_TYPE(new_op) = TCGOP_TYPE(old_op);
348615fa08f8SRichard Henderson     QTAILQ_INSERT_BEFORE(old_op, new_op, link);
34875a18407fSRichard Henderson     return new_op;
34885a18407fSRichard Henderson }
34895a18407fSRichard Henderson 
3490d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op,
3491d4478943SPhilippe Mathieu-Daudé                            TCGOpcode opc, unsigned nargs)
34925a18407fSRichard Henderson {
3493d4478943SPhilippe Mathieu-Daudé     TCGOp *new_op = tcg_op_alloc(opc, nargs);
3494fb744eceSRichard Henderson 
3495fb744eceSRichard Henderson     TCGOP_TYPE(new_op) = TCGOP_TYPE(old_op);
349615fa08f8SRichard Henderson     QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link);
34975a18407fSRichard Henderson     return new_op;
34985a18407fSRichard Henderson }
34995a18407fSRichard Henderson 
3500968f305eSRichard Henderson static void move_label_uses(TCGLabel *to, TCGLabel *from)
3501968f305eSRichard Henderson {
3502968f305eSRichard Henderson     TCGLabelUse *u;
3503968f305eSRichard Henderson 
3504968f305eSRichard Henderson     QSIMPLEQ_FOREACH(u, &from->branches, next) {
3505968f305eSRichard Henderson         TCGOp *op = u->op;
3506968f305eSRichard Henderson         switch (op->opc) {
3507968f305eSRichard Henderson         case INDEX_op_br:
3508968f305eSRichard Henderson             op->args[0] = label_arg(to);
3509968f305eSRichard Henderson             break;
3510968f305eSRichard Henderson         case INDEX_op_brcond_i32:
3511968f305eSRichard Henderson         case INDEX_op_brcond_i64:
3512968f305eSRichard Henderson             op->args[3] = label_arg(to);
3513968f305eSRichard Henderson             break;
3514968f305eSRichard Henderson         case INDEX_op_brcond2_i32:
3515968f305eSRichard Henderson             op->args[5] = label_arg(to);
3516968f305eSRichard Henderson             break;
3517968f305eSRichard Henderson         default:
3518968f305eSRichard Henderson             g_assert_not_reached();
3519968f305eSRichard Henderson         }
3520968f305eSRichard Henderson     }
3521968f305eSRichard Henderson 
3522968f305eSRichard Henderson     QSIMPLEQ_CONCAT(&to->branches, &from->branches);
3523968f305eSRichard Henderson }
3524968f305eSRichard Henderson 
3525b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code.  */
35269bbee4c0SRichard Henderson static void __attribute__((noinline))
35279bbee4c0SRichard Henderson reachable_code_pass(TCGContext *s)
3528b4fc67c7SRichard Henderson {
35294d89d0bbSRichard Henderson     TCGOp *op, *op_next, *op_prev;
3530b4fc67c7SRichard Henderson     bool dead = false;
3531b4fc67c7SRichard Henderson 
3532b4fc67c7SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
3533b4fc67c7SRichard Henderson         bool remove = dead;
3534b4fc67c7SRichard Henderson         TCGLabel *label;
3535b4fc67c7SRichard Henderson 
3536b4fc67c7SRichard Henderson         switch (op->opc) {
3537b4fc67c7SRichard Henderson         case INDEX_op_set_label:
3538b4fc67c7SRichard Henderson             label = arg_label(op->args[0]);
35394d89d0bbSRichard Henderson 
35404d89d0bbSRichard Henderson             /*
3541968f305eSRichard Henderson              * Note that the first op in the TB is always a load,
3542968f305eSRichard Henderson              * so there is always something before a label.
3543968f305eSRichard Henderson              */
3544968f305eSRichard Henderson             op_prev = QTAILQ_PREV(op, link);
3545968f305eSRichard Henderson 
3546968f305eSRichard Henderson             /*
3547968f305eSRichard Henderson              * If we find two sequential labels, move all branches to
3548968f305eSRichard Henderson              * reference the second label and remove the first label.
3549968f305eSRichard Henderson              * Do this before branch to next optimization, so that the
3550968f305eSRichard Henderson              * middle label is out of the way.
3551968f305eSRichard Henderson              */
3552968f305eSRichard Henderson             if (op_prev->opc == INDEX_op_set_label) {
3553968f305eSRichard Henderson                 move_label_uses(label, arg_label(op_prev->args[0]));
3554968f305eSRichard Henderson                 tcg_op_remove(s, op_prev);
3555968f305eSRichard Henderson                 op_prev = QTAILQ_PREV(op, link);
3556968f305eSRichard Henderson             }
3557968f305eSRichard Henderson 
3558968f305eSRichard Henderson             /*
35594d89d0bbSRichard Henderson              * Optimization can fold conditional branches to unconditional.
35604d89d0bbSRichard Henderson              * If we find a label which is preceded by an unconditional
35614d89d0bbSRichard Henderson              * branch to next, remove the branch.  We couldn't do this when
35624d89d0bbSRichard Henderson              * processing the branch because any dead code between the branch
35634d89d0bbSRichard Henderson              * and label had not yet been removed.
35644d89d0bbSRichard Henderson              */
35654d89d0bbSRichard Henderson             if (op_prev->opc == INDEX_op_br &&
35664d89d0bbSRichard Henderson                 label == arg_label(op_prev->args[0])) {
35674d89d0bbSRichard Henderson                 tcg_op_remove(s, op_prev);
35684d89d0bbSRichard Henderson                 /* Fall through means insns become live again.  */
35694d89d0bbSRichard Henderson                 dead = false;
35704d89d0bbSRichard Henderson             }
35714d89d0bbSRichard Henderson 
3572f85b1fc4SRichard Henderson             if (QSIMPLEQ_EMPTY(&label->branches)) {
3573b4fc67c7SRichard Henderson                 /*
3574b4fc67c7SRichard Henderson                  * While there is an occasional backward branch, virtually
3575b4fc67c7SRichard Henderson                  * all branches generated by the translators are forward.
3576b4fc67c7SRichard Henderson                  * Which means that generally we will have already removed
3577b4fc67c7SRichard Henderson                  * all references to the label that will be, and there is
3578b4fc67c7SRichard Henderson                  * little to be gained by iterating.
3579b4fc67c7SRichard Henderson                  */
3580b4fc67c7SRichard Henderson                 remove = true;
3581b4fc67c7SRichard Henderson             } else {
3582b4fc67c7SRichard Henderson                 /* Once we see a label, insns become live again.  */
3583b4fc67c7SRichard Henderson                 dead = false;
3584b4fc67c7SRichard Henderson                 remove = false;
3585b4fc67c7SRichard Henderson             }
3586b4fc67c7SRichard Henderson             break;
3587b4fc67c7SRichard Henderson 
3588b4fc67c7SRichard Henderson         case INDEX_op_br:
3589b4fc67c7SRichard Henderson         case INDEX_op_exit_tb:
3590b4fc67c7SRichard Henderson         case INDEX_op_goto_ptr:
3591b4fc67c7SRichard Henderson             /* Unconditional branches; everything following is dead.  */
3592b4fc67c7SRichard Henderson             dead = true;
3593b4fc67c7SRichard Henderson             break;
3594b4fc67c7SRichard Henderson 
3595b4fc67c7SRichard Henderson         case INDEX_op_call:
3596b4fc67c7SRichard Henderson             /* Notice noreturn helper calls, raising exceptions.  */
359790163900SRichard Henderson             if (tcg_call_flags(op) & TCG_CALL_NO_RETURN) {
3598b4fc67c7SRichard Henderson                 dead = true;
3599b4fc67c7SRichard Henderson             }
3600b4fc67c7SRichard Henderson             break;
3601b4fc67c7SRichard Henderson 
3602b4fc67c7SRichard Henderson         case INDEX_op_insn_start:
3603b4fc67c7SRichard Henderson             /* Never remove -- we need to keep these for unwind.  */
3604b4fc67c7SRichard Henderson             remove = false;
3605b4fc67c7SRichard Henderson             break;
3606b4fc67c7SRichard Henderson 
3607b4fc67c7SRichard Henderson         default:
3608b4fc67c7SRichard Henderson             break;
3609b4fc67c7SRichard Henderson         }
3610b4fc67c7SRichard Henderson 
3611b4fc67c7SRichard Henderson         if (remove) {
3612b4fc67c7SRichard Henderson             tcg_op_remove(s, op);
3613b4fc67c7SRichard Henderson         }
3614b4fc67c7SRichard Henderson     }
3615b4fc67c7SRichard Henderson }
3616b4fc67c7SRichard Henderson 
3617c70fbf0aSRichard Henderson #define TS_DEAD  1
3618c70fbf0aSRichard Henderson #define TS_MEM   2
3619c70fbf0aSRichard Henderson 
36205a18407fSRichard Henderson #define IS_DEAD_ARG(n)   (arg_life & (DEAD_ARG << (n)))
36215a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n)))
36225a18407fSRichard Henderson 
362325f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp.  */
362425f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts)
362525f49c5fSRichard Henderson {
362625f49c5fSRichard Henderson     return ts->state_ptr;
362725f49c5fSRichard Henderson }
362825f49c5fSRichard Henderson 
362925f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the
363025f49c5fSRichard Henderson  * maximal regset for its type.
363125f49c5fSRichard Henderson  */
363225f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts)
363325f49c5fSRichard Henderson {
363425f49c5fSRichard Henderson     *la_temp_pref(ts)
363525f49c5fSRichard Henderson         = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]);
363625f49c5fSRichard Henderson }
363725f49c5fSRichard Henderson 
36389c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals
36399c43b68dSAurelien Jarno    should be in memory. */
36402616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt)
3641c896fe29Sbellard {
3642b83eabeaSRichard Henderson     int i;
3643b83eabeaSRichard Henderson 
3644b83eabeaSRichard Henderson     for (i = 0; i < ng; ++i) {
3645b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
364625f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
3647b83eabeaSRichard Henderson     }
3648b83eabeaSRichard Henderson     for (i = ng; i < nt; ++i) {
3649b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD;
365025f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
3651b83eabeaSRichard Henderson     }
3652c896fe29Sbellard }
3653c896fe29Sbellard 
36549c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals
36559c43b68dSAurelien Jarno    and local temps should be in memory. */
36562616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt)
3657641d5fbeSbellard {
3658b83eabeaSRichard Henderson     int i;
3659641d5fbeSbellard 
3660ee17db83SRichard Henderson     for (i = 0; i < nt; ++i) {
3661ee17db83SRichard Henderson         TCGTemp *ts = &s->temps[i];
3662ee17db83SRichard Henderson         int state;
3663ee17db83SRichard Henderson 
3664ee17db83SRichard Henderson         switch (ts->kind) {
3665ee17db83SRichard Henderson         case TEMP_FIXED:
3666ee17db83SRichard Henderson         case TEMP_GLOBAL:
3667f57c6915SRichard Henderson         case TEMP_TB:
3668ee17db83SRichard Henderson             state = TS_DEAD | TS_MEM;
3669ee17db83SRichard Henderson             break;
3670c7482438SRichard Henderson         case TEMP_EBB:
3671c0522136SRichard Henderson         case TEMP_CONST:
3672ee17db83SRichard Henderson             state = TS_DEAD;
3673ee17db83SRichard Henderson             break;
3674ee17db83SRichard Henderson         default:
3675ee17db83SRichard Henderson             g_assert_not_reached();
3676c70fbf0aSRichard Henderson         }
3677ee17db83SRichard Henderson         ts->state = state;
3678ee17db83SRichard Henderson         la_reset_pref(ts);
3679641d5fbeSbellard     }
3680641d5fbeSbellard }
3681641d5fbeSbellard 
3682f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory.  */
3683f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng)
3684f65a061cSRichard Henderson {
3685f65a061cSRichard Henderson     int i;
3686f65a061cSRichard Henderson 
3687f65a061cSRichard Henderson     for (i = 0; i < ng; ++i) {
368825f49c5fSRichard Henderson         int state = s->temps[i].state;
368925f49c5fSRichard Henderson         s->temps[i].state = state | TS_MEM;
369025f49c5fSRichard Henderson         if (state == TS_DEAD) {
369125f49c5fSRichard Henderson             /* If the global was previously dead, reset prefs.  */
369225f49c5fSRichard Henderson             la_reset_pref(&s->temps[i]);
369325f49c5fSRichard Henderson         }
3694f65a061cSRichard Henderson     }
3695f65a061cSRichard Henderson }
3696f65a061cSRichard Henderson 
3697b4cb76e6SRichard Henderson /*
3698c7482438SRichard Henderson  * liveness analysis: conditional branch: all temps are dead unless
3699c7482438SRichard Henderson  * explicitly live-across-conditional-branch, globals and local temps
3700c7482438SRichard Henderson  * should be synced.
3701b4cb76e6SRichard Henderson  */
3702b4cb76e6SRichard Henderson static void la_bb_sync(TCGContext *s, int ng, int nt)
3703b4cb76e6SRichard Henderson {
3704b4cb76e6SRichard Henderson     la_global_sync(s, ng);
3705b4cb76e6SRichard Henderson 
3706b4cb76e6SRichard Henderson     for (int i = ng; i < nt; ++i) {
3707c0522136SRichard Henderson         TCGTemp *ts = &s->temps[i];
3708c0522136SRichard Henderson         int state;
3709c0522136SRichard Henderson 
3710c0522136SRichard Henderson         switch (ts->kind) {
3711f57c6915SRichard Henderson         case TEMP_TB:
3712c0522136SRichard Henderson             state = ts->state;
3713c0522136SRichard Henderson             ts->state = state | TS_MEM;
3714b4cb76e6SRichard Henderson             if (state != TS_DEAD) {
3715b4cb76e6SRichard Henderson                 continue;
3716b4cb76e6SRichard Henderson             }
3717c0522136SRichard Henderson             break;
3718c7482438SRichard Henderson         case TEMP_EBB:
3719c0522136SRichard Henderson         case TEMP_CONST:
3720c0522136SRichard Henderson             continue;
3721c0522136SRichard Henderson         default:
3722c0522136SRichard Henderson             g_assert_not_reached();
3723b4cb76e6SRichard Henderson         }
3724b4cb76e6SRichard Henderson         la_reset_pref(&s->temps[i]);
3725b4cb76e6SRichard Henderson     }
3726b4cb76e6SRichard Henderson }
3727b4cb76e6SRichard Henderson 
3728f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill.  */
3729f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng)
3730f65a061cSRichard Henderson {
3731f65a061cSRichard Henderson     int i;
3732f65a061cSRichard Henderson 
3733f65a061cSRichard Henderson     for (i = 0; i < ng; i++) {
3734f65a061cSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
373525f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
373625f49c5fSRichard Henderson     }
373725f49c5fSRichard Henderson }
373825f49c5fSRichard Henderson 
373925f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls.  */
374025f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt)
374125f49c5fSRichard Henderson {
374225f49c5fSRichard Henderson     TCGRegSet mask = ~tcg_target_call_clobber_regs;
374325f49c5fSRichard Henderson     int i;
374425f49c5fSRichard Henderson 
374525f49c5fSRichard Henderson     for (i = 0; i < nt; i++) {
374625f49c5fSRichard Henderson         TCGTemp *ts = &s->temps[i];
374725f49c5fSRichard Henderson         if (!(ts->state & TS_DEAD)) {
374825f49c5fSRichard Henderson             TCGRegSet *pset = la_temp_pref(ts);
374925f49c5fSRichard Henderson             TCGRegSet set = *pset;
375025f49c5fSRichard Henderson 
375125f49c5fSRichard Henderson             set &= mask;
375225f49c5fSRichard Henderson             /* If the combination is not possible, restart.  */
375325f49c5fSRichard Henderson             if (set == 0) {
375425f49c5fSRichard Henderson                 set = tcg_target_available_regs[ts->type] & mask;
375525f49c5fSRichard Henderson             }
375625f49c5fSRichard Henderson             *pset = set;
375725f49c5fSRichard Henderson         }
3758f65a061cSRichard Henderson     }
3759f65a061cSRichard Henderson }
3760f65a061cSRichard Henderson 
3761874b8574SRichard Henderson /*
3762874b8574SRichard Henderson  * Liveness analysis: Verify the lifetime of TEMP_TB, and reduce
3763874b8574SRichard Henderson  * to TEMP_EBB, if possible.
3764874b8574SRichard Henderson  */
3765874b8574SRichard Henderson static void __attribute__((noinline))
3766874b8574SRichard Henderson liveness_pass_0(TCGContext *s)
3767874b8574SRichard Henderson {
3768874b8574SRichard Henderson     void * const multiple_ebb = (void *)(uintptr_t)-1;
3769874b8574SRichard Henderson     int nb_temps = s->nb_temps;
3770874b8574SRichard Henderson     TCGOp *op, *ebb;
3771874b8574SRichard Henderson 
3772874b8574SRichard Henderson     for (int i = s->nb_globals; i < nb_temps; ++i) {
3773874b8574SRichard Henderson         s->temps[i].state_ptr = NULL;
3774874b8574SRichard Henderson     }
3775874b8574SRichard Henderson 
3776874b8574SRichard Henderson     /*
3777874b8574SRichard Henderson      * Represent each EBB by the op at which it begins.  In the case of
3778874b8574SRichard Henderson      * the first EBB, this is the first op, otherwise it is a label.
3779874b8574SRichard Henderson      * Collect the uses of each TEMP_TB: NULL for unused, EBB for use
3780874b8574SRichard Henderson      * within a single EBB, else MULTIPLE_EBB.
3781874b8574SRichard Henderson      */
3782874b8574SRichard Henderson     ebb = QTAILQ_FIRST(&s->ops);
3783874b8574SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
3784874b8574SRichard Henderson         const TCGOpDef *def;
3785874b8574SRichard Henderson         int nb_oargs, nb_iargs;
3786874b8574SRichard Henderson 
3787874b8574SRichard Henderson         switch (op->opc) {
3788874b8574SRichard Henderson         case INDEX_op_set_label:
3789874b8574SRichard Henderson             ebb = op;
3790874b8574SRichard Henderson             continue;
3791874b8574SRichard Henderson         case INDEX_op_discard:
3792874b8574SRichard Henderson             continue;
3793874b8574SRichard Henderson         case INDEX_op_call:
3794874b8574SRichard Henderson             nb_oargs = TCGOP_CALLO(op);
3795874b8574SRichard Henderson             nb_iargs = TCGOP_CALLI(op);
3796874b8574SRichard Henderson             break;
3797874b8574SRichard Henderson         default:
3798874b8574SRichard Henderson             def = &tcg_op_defs[op->opc];
3799874b8574SRichard Henderson             nb_oargs = def->nb_oargs;
3800874b8574SRichard Henderson             nb_iargs = def->nb_iargs;
3801874b8574SRichard Henderson             break;
3802874b8574SRichard Henderson         }
3803874b8574SRichard Henderson 
3804874b8574SRichard Henderson         for (int i = 0; i < nb_oargs + nb_iargs; ++i) {
3805874b8574SRichard Henderson             TCGTemp *ts = arg_temp(op->args[i]);
3806874b8574SRichard Henderson 
3807874b8574SRichard Henderson             if (ts->kind != TEMP_TB) {
3808874b8574SRichard Henderson                 continue;
3809874b8574SRichard Henderson             }
3810874b8574SRichard Henderson             if (ts->state_ptr == NULL) {
3811874b8574SRichard Henderson                 ts->state_ptr = ebb;
3812874b8574SRichard Henderson             } else if (ts->state_ptr != ebb) {
3813874b8574SRichard Henderson                 ts->state_ptr = multiple_ebb;
3814874b8574SRichard Henderson             }
3815874b8574SRichard Henderson         }
3816874b8574SRichard Henderson     }
3817874b8574SRichard Henderson 
3818874b8574SRichard Henderson     /*
3819874b8574SRichard Henderson      * For TEMP_TB that turned out not to be used beyond one EBB,
3820874b8574SRichard Henderson      * reduce the liveness to TEMP_EBB.
3821874b8574SRichard Henderson      */
3822874b8574SRichard Henderson     for (int i = s->nb_globals; i < nb_temps; ++i) {
3823874b8574SRichard Henderson         TCGTemp *ts = &s->temps[i];
3824874b8574SRichard Henderson         if (ts->kind == TEMP_TB && ts->state_ptr != multiple_ebb) {
3825874b8574SRichard Henderson             ts->kind = TEMP_EBB;
3826874b8574SRichard Henderson         }
3827874b8574SRichard Henderson     }
3828874b8574SRichard Henderson }
3829874b8574SRichard Henderson 
3830a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a
3831c896fe29Sbellard    given input arguments is dead. Instructions updating dead
3832c896fe29Sbellard    temporaries are removed. */
38339bbee4c0SRichard Henderson static void __attribute__((noinline))
38349bbee4c0SRichard Henderson liveness_pass_1(TCGContext *s)
3835c896fe29Sbellard {
3836c70fbf0aSRichard Henderson     int nb_globals = s->nb_globals;
38372616c808SRichard Henderson     int nb_temps = s->nb_temps;
383815fa08f8SRichard Henderson     TCGOp *op, *op_prev;
383925f49c5fSRichard Henderson     TCGRegSet *prefs;
384025f49c5fSRichard Henderson     int i;
384125f49c5fSRichard Henderson 
384225f49c5fSRichard Henderson     prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps);
384325f49c5fSRichard Henderson     for (i = 0; i < nb_temps; ++i) {
384425f49c5fSRichard Henderson         s->temps[i].state_ptr = prefs + i;
384525f49c5fSRichard Henderson     }
3846c896fe29Sbellard 
3847ae36a246SRichard Henderson     /* ??? Should be redundant with the exit_tb that ends the TB.  */
38482616c808SRichard Henderson     la_func_end(s, nb_globals, nb_temps);
3849c896fe29Sbellard 
3850eae3eb3eSPaolo Bonzini     QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) {
385125f49c5fSRichard Henderson         int nb_iargs, nb_oargs;
3852c45cb8bbSRichard Henderson         TCGOpcode opc_new, opc_new2;
3853c45cb8bbSRichard Henderson         bool have_opc_new2;
3854a1b3c48dSRichard Henderson         TCGLifeData arg_life = 0;
385525f49c5fSRichard Henderson         TCGTemp *ts;
3856c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
3857c45cb8bbSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
3858501fb3daSRichard Henderson         const TCGArgConstraint *args_ct;
3859c45cb8bbSRichard Henderson 
3860c45cb8bbSRichard Henderson         switch (opc) {
3861c896fe29Sbellard         case INDEX_op_call:
3862c6e113f5Sbellard             {
386339004a71SRichard Henderson                 const TCGHelperInfo *info = tcg_call_info(op);
386439004a71SRichard Henderson                 int call_flags = tcg_call_flags(op);
3865c6e113f5Sbellard 
3866cd9090aaSRichard Henderson                 nb_oargs = TCGOP_CALLO(op);
3867cd9090aaSRichard Henderson                 nb_iargs = TCGOP_CALLI(op);
3868c6e113f5Sbellard 
3869c45cb8bbSRichard Henderson                 /* pure functions can be removed if their result is unused */
387078505279SAurelien Jarno                 if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) {
3871c6e113f5Sbellard                     for (i = 0; i < nb_oargs; i++) {
387225f49c5fSRichard Henderson                         ts = arg_temp(op->args[i]);
387325f49c5fSRichard Henderson                         if (ts->state != TS_DEAD) {
3874c6e113f5Sbellard                             goto do_not_remove_call;
3875c6e113f5Sbellard                         }
38769c43b68dSAurelien Jarno                     }
3877c45cb8bbSRichard Henderson                     goto do_remove;
3878152c35aaSRichard Henderson                 }
3879c6e113f5Sbellard             do_not_remove_call:
3880c896fe29Sbellard 
388125f49c5fSRichard Henderson                 /* Output args are dead.  */
3882c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
388325f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
388425f49c5fSRichard Henderson                     if (ts->state & TS_DEAD) {
3885a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
38866b64b624SAurelien Jarno                     }
388725f49c5fSRichard Henderson                     if (ts->state & TS_MEM) {
3888a1b3c48dSRichard Henderson                         arg_life |= SYNC_ARG << i;
38899c43b68dSAurelien Jarno                     }
389025f49c5fSRichard Henderson                     ts->state = TS_DEAD;
389125f49c5fSRichard Henderson                     la_reset_pref(ts);
3892c896fe29Sbellard                 }
3893c896fe29Sbellard 
389431fd884bSRichard Henderson                 /* Not used -- it will be tcg_target_call_oarg_reg().  */
389531fd884bSRichard Henderson                 memset(op->output_pref, 0, sizeof(op->output_pref));
389631fd884bSRichard Henderson 
389778505279SAurelien Jarno                 if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS |
389878505279SAurelien Jarno                                     TCG_CALL_NO_READ_GLOBALS))) {
3899f65a061cSRichard Henderson                     la_global_kill(s, nb_globals);
3900c70fbf0aSRichard Henderson                 } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) {
3901f65a061cSRichard Henderson                     la_global_sync(s, nb_globals);
3902b9c18f56Saurel32                 }
3903c896fe29Sbellard 
390425f49c5fSRichard Henderson                 /* Record arguments that die in this helper.  */
3905866cb6cbSAurelien Jarno                 for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
390625f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
390739004a71SRichard Henderson                     if (ts->state & TS_DEAD) {
3908a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
3909c896fe29Sbellard                     }
3910c896fe29Sbellard                 }
391125f49c5fSRichard Henderson 
391225f49c5fSRichard Henderson                 /* For all live registers, remove call-clobbered prefs.  */
391325f49c5fSRichard Henderson                 la_cross_call(s, nb_temps);
391425f49c5fSRichard Henderson 
391539004a71SRichard Henderson                 /*
391639004a71SRichard Henderson                  * Input arguments are live for preceding opcodes.
391739004a71SRichard Henderson                  *
391839004a71SRichard Henderson                  * For those arguments that die, and will be allocated in
391939004a71SRichard Henderson                  * registers, clear the register set for that arg, to be
392039004a71SRichard Henderson                  * filled in below.  For args that will be on the stack,
392139004a71SRichard Henderson                  * reset to any available reg.  Process arguments in reverse
392239004a71SRichard Henderson                  * order so that if a temp is used more than once, the stack
392339004a71SRichard Henderson                  * reset to max happens before the register reset to 0.
392425f49c5fSRichard Henderson                  */
392539004a71SRichard Henderson                 for (i = nb_iargs - 1; i >= 0; i--) {
392639004a71SRichard Henderson                     const TCGCallArgumentLoc *loc = &info->in[i];
392739004a71SRichard Henderson                     ts = arg_temp(op->args[nb_oargs + i]);
392839004a71SRichard Henderson 
392939004a71SRichard Henderson                     if (ts->state & TS_DEAD) {
393039004a71SRichard Henderson                         switch (loc->kind) {
393139004a71SRichard Henderson                         case TCG_CALL_ARG_NORMAL:
393239004a71SRichard Henderson                         case TCG_CALL_ARG_EXTEND_U:
393339004a71SRichard Henderson                         case TCG_CALL_ARG_EXTEND_S:
3934338b61e9SRichard Henderson                             if (arg_slot_reg_p(loc->arg_slot)) {
393539004a71SRichard Henderson                                 *la_temp_pref(ts) = 0;
393639004a71SRichard Henderson                                 break;
393739004a71SRichard Henderson                             }
393839004a71SRichard Henderson                             /* fall through */
393939004a71SRichard Henderson                         default:
394039004a71SRichard Henderson                             *la_temp_pref(ts) =
394139004a71SRichard Henderson                                 tcg_target_available_regs[ts->type];
394239004a71SRichard Henderson                             break;
394339004a71SRichard Henderson                         }
394425f49c5fSRichard Henderson                         ts->state &= ~TS_DEAD;
394525f49c5fSRichard Henderson                     }
394625f49c5fSRichard Henderson                 }
394725f49c5fSRichard Henderson 
394839004a71SRichard Henderson                 /*
394939004a71SRichard Henderson                  * For each input argument, add its input register to prefs.
395039004a71SRichard Henderson                  * If a temp is used once, this produces a single set bit;
395139004a71SRichard Henderson                  * if a temp is used multiple times, this produces a set.
395239004a71SRichard Henderson                  */
395339004a71SRichard Henderson                 for (i = 0; i < nb_iargs; i++) {
395439004a71SRichard Henderson                     const TCGCallArgumentLoc *loc = &info->in[i];
395539004a71SRichard Henderson                     ts = arg_temp(op->args[nb_oargs + i]);
395639004a71SRichard Henderson 
395739004a71SRichard Henderson                     switch (loc->kind) {
395839004a71SRichard Henderson                     case TCG_CALL_ARG_NORMAL:
395939004a71SRichard Henderson                     case TCG_CALL_ARG_EXTEND_U:
396039004a71SRichard Henderson                     case TCG_CALL_ARG_EXTEND_S:
3961338b61e9SRichard Henderson                         if (arg_slot_reg_p(loc->arg_slot)) {
396225f49c5fSRichard Henderson                             tcg_regset_set_reg(*la_temp_pref(ts),
396339004a71SRichard Henderson                                 tcg_target_call_iarg_regs[loc->arg_slot]);
396439004a71SRichard Henderson                         }
396539004a71SRichard Henderson                         break;
396639004a71SRichard Henderson                     default:
396739004a71SRichard Henderson                         break;
3968c70fbf0aSRichard Henderson                     }
3969c19f47bfSAurelien Jarno                 }
3970c6e113f5Sbellard             }
3971c896fe29Sbellard             break;
3972765b842aSRichard Henderson         case INDEX_op_insn_start:
3973c896fe29Sbellard             break;
39745ff9d6a4Sbellard         case INDEX_op_discard:
39755ff9d6a4Sbellard             /* mark the temporary as dead */
397625f49c5fSRichard Henderson             ts = arg_temp(op->args[0]);
397725f49c5fSRichard Henderson             ts->state = TS_DEAD;
397825f49c5fSRichard Henderson             la_reset_pref(ts);
39795ff9d6a4Sbellard             break;
39801305c451SRichard Henderson 
39811305c451SRichard Henderson         case INDEX_op_add2_i32:
3982c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i32;
3983f1fae40cSRichard Henderson             goto do_addsub2;
39841305c451SRichard Henderson         case INDEX_op_sub2_i32:
3985c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i32;
3986f1fae40cSRichard Henderson             goto do_addsub2;
3987f1fae40cSRichard Henderson         case INDEX_op_add2_i64:
3988c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i64;
3989f1fae40cSRichard Henderson             goto do_addsub2;
3990f1fae40cSRichard Henderson         case INDEX_op_sub2_i64:
3991c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i64;
3992f1fae40cSRichard Henderson         do_addsub2:
39931305c451SRichard Henderson             nb_iargs = 4;
39941305c451SRichard Henderson             nb_oargs = 2;
39951305c451SRichard Henderson             /* Test if the high part of the operation is dead, but not
39961305c451SRichard Henderson                the low part.  The result can be optimized to a simple
39971305c451SRichard Henderson                add or sub.  This happens often for x86_64 guest when the
39981305c451SRichard Henderson                cpu mode is set to 32 bit.  */
3999b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
4000b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
40011305c451SRichard Henderson                     goto do_remove;
40021305c451SRichard Henderson                 }
4003c45cb8bbSRichard Henderson                 /* Replace the opcode and adjust the args in place,
4004c45cb8bbSRichard Henderson                    leaving 3 unused args at the end.  */
4005c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
4006efee3746SRichard Henderson                 op->args[1] = op->args[2];
4007efee3746SRichard Henderson                 op->args[2] = op->args[4];
40081305c451SRichard Henderson                 /* Fall through and mark the single-word operation live.  */
40091305c451SRichard Henderson                 nb_iargs = 2;
40101305c451SRichard Henderson                 nb_oargs = 1;
40111305c451SRichard Henderson             }
40121305c451SRichard Henderson             goto do_not_remove;
40131305c451SRichard Henderson 
40141414968aSRichard Henderson         case INDEX_op_mulu2_i32:
4015c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
4016c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i32;
4017c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i32;
401803271524SRichard Henderson             goto do_mul2;
4019f1fae40cSRichard Henderson         case INDEX_op_muls2_i32:
4020c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
4021c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i32;
4022c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i32;
4023f1fae40cSRichard Henderson             goto do_mul2;
4024f1fae40cSRichard Henderson         case INDEX_op_mulu2_i64:
4025c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
4026c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i64;
4027c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i64;
402803271524SRichard Henderson             goto do_mul2;
4029f1fae40cSRichard Henderson         case INDEX_op_muls2_i64:
4030c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
4031c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i64;
4032c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i64;
403303271524SRichard Henderson             goto do_mul2;
4034f1fae40cSRichard Henderson         do_mul2:
40351414968aSRichard Henderson             nb_iargs = 2;
40361414968aSRichard Henderson             nb_oargs = 2;
4037b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
4038b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
403903271524SRichard Henderson                     /* Both parts of the operation are dead.  */
40401414968aSRichard Henderson                     goto do_remove;
40411414968aSRichard Henderson                 }
404203271524SRichard Henderson                 /* The high part of the operation is dead; generate the low. */
4043c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
4044efee3746SRichard Henderson                 op->args[1] = op->args[2];
4045efee3746SRichard Henderson                 op->args[2] = op->args[3];
4046b83eabeaSRichard Henderson             } else if (arg_temp(op->args[0])->state == TS_DEAD && have_opc_new2) {
404703271524SRichard Henderson                 /* The low part of the operation is dead; generate the high. */
4048c45cb8bbSRichard Henderson                 op->opc = opc = opc_new2;
4049efee3746SRichard Henderson                 op->args[0] = op->args[1];
4050efee3746SRichard Henderson                 op->args[1] = op->args[2];
4051efee3746SRichard Henderson                 op->args[2] = op->args[3];
405203271524SRichard Henderson             } else {
405303271524SRichard Henderson                 goto do_not_remove;
405403271524SRichard Henderson             }
405503271524SRichard Henderson             /* Mark the single-word operation live.  */
40561414968aSRichard Henderson             nb_oargs = 1;
40571414968aSRichard Henderson             goto do_not_remove;
40581414968aSRichard Henderson 
4059c896fe29Sbellard         default:
40601305c451SRichard Henderson             /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
4061c896fe29Sbellard             nb_iargs = def->nb_iargs;
4062c896fe29Sbellard             nb_oargs = def->nb_oargs;
4063c896fe29Sbellard 
4064c896fe29Sbellard             /* Test if the operation can be removed because all
40655ff9d6a4Sbellard                its outputs are dead. We assume that nb_oargs == 0
40665ff9d6a4Sbellard                implies side effects */
40675ff9d6a4Sbellard             if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
4068c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
4069b83eabeaSRichard Henderson                     if (arg_temp(op->args[i])->state != TS_DEAD) {
4070c896fe29Sbellard                         goto do_not_remove;
4071c896fe29Sbellard                     }
40729c43b68dSAurelien Jarno                 }
4073152c35aaSRichard Henderson                 goto do_remove;
4074152c35aaSRichard Henderson             }
4075152c35aaSRichard Henderson             goto do_not_remove;
4076152c35aaSRichard Henderson 
40771305c451SRichard Henderson         do_remove:
40780c627cdcSRichard Henderson             tcg_op_remove(s, op);
4079152c35aaSRichard Henderson             break;
4080152c35aaSRichard Henderson 
4081c896fe29Sbellard         do_not_remove:
4082c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
408325f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
408425f49c5fSRichard Henderson 
408525f49c5fSRichard Henderson                 /* Remember the preference of the uses that followed.  */
408631fd884bSRichard Henderson                 if (i < ARRAY_SIZE(op->output_pref)) {
408725f49c5fSRichard Henderson                     op->output_pref[i] = *la_temp_pref(ts);
408831fd884bSRichard Henderson                 }
408925f49c5fSRichard Henderson 
409025f49c5fSRichard Henderson                 /* Output args are dead.  */
409125f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
4092a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
40936b64b624SAurelien Jarno                 }
409425f49c5fSRichard Henderson                 if (ts->state & TS_MEM) {
4095a1b3c48dSRichard Henderson                     arg_life |= SYNC_ARG << i;
40969c43b68dSAurelien Jarno                 }
409725f49c5fSRichard Henderson                 ts->state = TS_DEAD;
409825f49c5fSRichard Henderson                 la_reset_pref(ts);
4099c896fe29Sbellard             }
4100c896fe29Sbellard 
410125f49c5fSRichard Henderson             /* If end of basic block, update.  */
4102ae36a246SRichard Henderson             if (def->flags & TCG_OPF_BB_EXIT) {
4103ae36a246SRichard Henderson                 la_func_end(s, nb_globals, nb_temps);
4104b4cb76e6SRichard Henderson             } else if (def->flags & TCG_OPF_COND_BRANCH) {
4105b4cb76e6SRichard Henderson                 la_bb_sync(s, nb_globals, nb_temps);
4106ae36a246SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
41072616c808SRichard Henderson                 la_bb_end(s, nb_globals, nb_temps);
41083d5c5f87SAurelien Jarno             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
4109f65a061cSRichard Henderson                 la_global_sync(s, nb_globals);
411025f49c5fSRichard Henderson                 if (def->flags & TCG_OPF_CALL_CLOBBER) {
411125f49c5fSRichard Henderson                     la_cross_call(s, nb_temps);
411225f49c5fSRichard Henderson                 }
4113c896fe29Sbellard             }
4114c896fe29Sbellard 
411525f49c5fSRichard Henderson             /* Record arguments that die in this opcode.  */
4116866cb6cbSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
411725f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
411825f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
4119a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
4120c896fe29Sbellard                 }
4121c19f47bfSAurelien Jarno             }
412225f49c5fSRichard Henderson 
412325f49c5fSRichard Henderson             /* Input arguments are live for preceding opcodes.  */
4124c19f47bfSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
412525f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
412625f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
412725f49c5fSRichard Henderson                     /* For operands that were dead, initially allow
412825f49c5fSRichard Henderson                        all regs for the type.  */
412925f49c5fSRichard Henderson                     *la_temp_pref(ts) = tcg_target_available_regs[ts->type];
413025f49c5fSRichard Henderson                     ts->state &= ~TS_DEAD;
413125f49c5fSRichard Henderson                 }
413225f49c5fSRichard Henderson             }
413325f49c5fSRichard Henderson 
413425f49c5fSRichard Henderson             /* Incorporate constraints for this operand.  */
413525f49c5fSRichard Henderson             switch (opc) {
413625f49c5fSRichard Henderson             case INDEX_op_mov_i32:
413725f49c5fSRichard Henderson             case INDEX_op_mov_i64:
413825f49c5fSRichard Henderson                 /* Note that these are TCG_OPF_NOT_PRESENT and do not
413925f49c5fSRichard Henderson                    have proper constraints.  That said, special case
414025f49c5fSRichard Henderson                    moves to propagate preferences backward.  */
414125f49c5fSRichard Henderson                 if (IS_DEAD_ARG(1)) {
414225f49c5fSRichard Henderson                     *la_temp_pref(arg_temp(op->args[0]))
414325f49c5fSRichard Henderson                         = *la_temp_pref(arg_temp(op->args[1]));
414425f49c5fSRichard Henderson                 }
414525f49c5fSRichard Henderson                 break;
414625f49c5fSRichard Henderson 
414725f49c5fSRichard Henderson             default:
4148501fb3daSRichard Henderson                 args_ct = opcode_args_ct(op);
414925f49c5fSRichard Henderson                 for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
4150501fb3daSRichard Henderson                     const TCGArgConstraint *ct = &args_ct[i];
415125f49c5fSRichard Henderson                     TCGRegSet set, *pset;
415225f49c5fSRichard Henderson 
415325f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
415425f49c5fSRichard Henderson                     pset = la_temp_pref(ts);
415525f49c5fSRichard Henderson                     set = *pset;
415625f49c5fSRichard Henderson 
41579be0d080SRichard Henderson                     set &= ct->regs;
4158bc2b17e6SRichard Henderson                     if (ct->ialias) {
415931fd884bSRichard Henderson                         set &= output_pref(op, ct->alias_index);
416025f49c5fSRichard Henderson                     }
416125f49c5fSRichard Henderson                     /* If the combination is not possible, restart.  */
416225f49c5fSRichard Henderson                     if (set == 0) {
41639be0d080SRichard Henderson                         set = ct->regs;
416425f49c5fSRichard Henderson                     }
416525f49c5fSRichard Henderson                     *pset = set;
416625f49c5fSRichard Henderson                 }
416725f49c5fSRichard Henderson                 break;
4168c896fe29Sbellard             }
4169c896fe29Sbellard             break;
4170c896fe29Sbellard         }
4171bee158cbSRichard Henderson         op->life = arg_life;
4172c896fe29Sbellard     }
41731ff0a2c5SEvgeny Voevodin }
4174c896fe29Sbellard 
41755a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries.  */
41769bbee4c0SRichard Henderson static bool __attribute__((noinline))
41779bbee4c0SRichard Henderson liveness_pass_2(TCGContext *s)
41785a18407fSRichard Henderson {
41795a18407fSRichard Henderson     int nb_globals = s->nb_globals;
418015fa08f8SRichard Henderson     int nb_temps, i;
41815a18407fSRichard Henderson     bool changes = false;
418215fa08f8SRichard Henderson     TCGOp *op, *op_next;
41835a18407fSRichard Henderson 
41845a18407fSRichard Henderson     /* Create a temporary for each indirect global.  */
41855a18407fSRichard Henderson     for (i = 0; i < nb_globals; ++i) {
41865a18407fSRichard Henderson         TCGTemp *its = &s->temps[i];
41875a18407fSRichard Henderson         if (its->indirect_reg) {
41885a18407fSRichard Henderson             TCGTemp *dts = tcg_temp_alloc(s);
41895a18407fSRichard Henderson             dts->type = its->type;
41905a18407fSRichard Henderson             dts->base_type = its->base_type;
4191e1e64652SRichard Henderson             dts->temp_subindex = its->temp_subindex;
4192c7482438SRichard Henderson             dts->kind = TEMP_EBB;
4193b83eabeaSRichard Henderson             its->state_ptr = dts;
4194b83eabeaSRichard Henderson         } else {
4195b83eabeaSRichard Henderson             its->state_ptr = NULL;
41965a18407fSRichard Henderson         }
4197b83eabeaSRichard Henderson         /* All globals begin dead.  */
4198b83eabeaSRichard Henderson         its->state = TS_DEAD;
41995a18407fSRichard Henderson     }
4200b83eabeaSRichard Henderson     for (nb_temps = s->nb_temps; i < nb_temps; ++i) {
4201b83eabeaSRichard Henderson         TCGTemp *its = &s->temps[i];
4202b83eabeaSRichard Henderson         its->state_ptr = NULL;
4203b83eabeaSRichard Henderson         its->state = TS_DEAD;
4204b83eabeaSRichard Henderson     }
42055a18407fSRichard Henderson 
420615fa08f8SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
42075a18407fSRichard Henderson         TCGOpcode opc = op->opc;
42085a18407fSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
42095a18407fSRichard Henderson         TCGLifeData arg_life = op->life;
42105a18407fSRichard Henderson         int nb_iargs, nb_oargs, call_flags;
4211b83eabeaSRichard Henderson         TCGTemp *arg_ts, *dir_ts;
42125a18407fSRichard Henderson 
42135a18407fSRichard Henderson         if (opc == INDEX_op_call) {
4214cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
4215cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
421690163900SRichard Henderson             call_flags = tcg_call_flags(op);
42175a18407fSRichard Henderson         } else {
42185a18407fSRichard Henderson             nb_iargs = def->nb_iargs;
42195a18407fSRichard Henderson             nb_oargs = def->nb_oargs;
42205a18407fSRichard Henderson 
42215a18407fSRichard Henderson             /* Set flags similar to how calls require.  */
4222b4cb76e6SRichard Henderson             if (def->flags & TCG_OPF_COND_BRANCH) {
4223b4cb76e6SRichard Henderson                 /* Like reading globals: sync_globals */
4224b4cb76e6SRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
4225b4cb76e6SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
42265a18407fSRichard Henderson                 /* Like writing globals: save_globals */
42275a18407fSRichard Henderson                 call_flags = 0;
42285a18407fSRichard Henderson             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
42295a18407fSRichard Henderson                 /* Like reading globals: sync_globals */
42305a18407fSRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
42315a18407fSRichard Henderson             } else {
42325a18407fSRichard Henderson                 /* No effect on globals.  */
42335a18407fSRichard Henderson                 call_flags = (TCG_CALL_NO_READ_GLOBALS |
42345a18407fSRichard Henderson                               TCG_CALL_NO_WRITE_GLOBALS);
42355a18407fSRichard Henderson             }
42365a18407fSRichard Henderson         }
42375a18407fSRichard Henderson 
42385a18407fSRichard Henderson         /* Make sure that input arguments are available.  */
42395a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
4240b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
4241b83eabeaSRichard Henderson             dir_ts = arg_ts->state_ptr;
4242b83eabeaSRichard Henderson             if (dir_ts && arg_ts->state == TS_DEAD) {
4243b83eabeaSRichard Henderson                 TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32
42445a18407fSRichard Henderson                                   ? INDEX_op_ld_i32
42455a18407fSRichard Henderson                                   : INDEX_op_ld_i64);
4246d4478943SPhilippe Mathieu-Daudé                 TCGOp *lop = tcg_op_insert_before(s, op, lopc, 3);
42475a18407fSRichard Henderson 
4248b83eabeaSRichard Henderson                 lop->args[0] = temp_arg(dir_ts);
4249b83eabeaSRichard Henderson                 lop->args[1] = temp_arg(arg_ts->mem_base);
4250b83eabeaSRichard Henderson                 lop->args[2] = arg_ts->mem_offset;
42515a18407fSRichard Henderson 
42525a18407fSRichard Henderson                 /* Loaded, but synced with memory.  */
4253b83eabeaSRichard Henderson                 arg_ts->state = TS_MEM;
42545a18407fSRichard Henderson             }
42555a18407fSRichard Henderson         }
42565a18407fSRichard Henderson 
42575a18407fSRichard Henderson         /* Perform input replacement, and mark inputs that became dead.
42585a18407fSRichard Henderson            No action is required except keeping temp_state up to date
42595a18407fSRichard Henderson            so that we reload when needed.  */
42605a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
4261b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
4262b83eabeaSRichard Henderson             dir_ts = arg_ts->state_ptr;
4263b83eabeaSRichard Henderson             if (dir_ts) {
4264b83eabeaSRichard Henderson                 op->args[i] = temp_arg(dir_ts);
42655a18407fSRichard Henderson                 changes = true;
42665a18407fSRichard Henderson                 if (IS_DEAD_ARG(i)) {
4267b83eabeaSRichard Henderson                     arg_ts->state = TS_DEAD;
42685a18407fSRichard Henderson                 }
42695a18407fSRichard Henderson             }
42705a18407fSRichard Henderson         }
42715a18407fSRichard Henderson 
42725a18407fSRichard Henderson         /* Liveness analysis should ensure that the following are
42735a18407fSRichard Henderson            all correct, for call sites and basic block end points.  */
42745a18407fSRichard Henderson         if (call_flags & TCG_CALL_NO_READ_GLOBALS) {
42755a18407fSRichard Henderson             /* Nothing to do */
42765a18407fSRichard Henderson         } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) {
42775a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
42785a18407fSRichard Henderson                 /* Liveness should see that globals are synced back,
42795a18407fSRichard Henderson                    that is, either TS_DEAD or TS_MEM.  */
4280b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
4281b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
4282b83eabeaSRichard Henderson                                  || arg_ts->state != 0);
42835a18407fSRichard Henderson             }
42845a18407fSRichard Henderson         } else {
42855a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
42865a18407fSRichard Henderson                 /* Liveness should see that globals are saved back,
42875a18407fSRichard Henderson                    that is, TS_DEAD, waiting to be reloaded.  */
4288b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
4289b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
4290b83eabeaSRichard Henderson                                  || arg_ts->state == TS_DEAD);
42915a18407fSRichard Henderson             }
42925a18407fSRichard Henderson         }
42935a18407fSRichard Henderson 
42945a18407fSRichard Henderson         /* Outputs become available.  */
429561f15c48SRichard Henderson         if (opc == INDEX_op_mov_i32 || opc == INDEX_op_mov_i64) {
429661f15c48SRichard Henderson             arg_ts = arg_temp(op->args[0]);
429761f15c48SRichard Henderson             dir_ts = arg_ts->state_ptr;
429861f15c48SRichard Henderson             if (dir_ts) {
429961f15c48SRichard Henderson                 op->args[0] = temp_arg(dir_ts);
430061f15c48SRichard Henderson                 changes = true;
430161f15c48SRichard Henderson 
430261f15c48SRichard Henderson                 /* The output is now live and modified.  */
430361f15c48SRichard Henderson                 arg_ts->state = 0;
430461f15c48SRichard Henderson 
430561f15c48SRichard Henderson                 if (NEED_SYNC_ARG(0)) {
430661f15c48SRichard Henderson                     TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
430761f15c48SRichard Henderson                                       ? INDEX_op_st_i32
430861f15c48SRichard Henderson                                       : INDEX_op_st_i64);
4309d4478943SPhilippe Mathieu-Daudé                     TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3);
431061f15c48SRichard Henderson                     TCGTemp *out_ts = dir_ts;
431161f15c48SRichard Henderson 
431261f15c48SRichard Henderson                     if (IS_DEAD_ARG(0)) {
431361f15c48SRichard Henderson                         out_ts = arg_temp(op->args[1]);
431461f15c48SRichard Henderson                         arg_ts->state = TS_DEAD;
431561f15c48SRichard Henderson                         tcg_op_remove(s, op);
431661f15c48SRichard Henderson                     } else {
431761f15c48SRichard Henderson                         arg_ts->state = TS_MEM;
431861f15c48SRichard Henderson                     }
431961f15c48SRichard Henderson 
432061f15c48SRichard Henderson                     sop->args[0] = temp_arg(out_ts);
432161f15c48SRichard Henderson                     sop->args[1] = temp_arg(arg_ts->mem_base);
432261f15c48SRichard Henderson                     sop->args[2] = arg_ts->mem_offset;
432361f15c48SRichard Henderson                 } else {
432461f15c48SRichard Henderson                     tcg_debug_assert(!IS_DEAD_ARG(0));
432561f15c48SRichard Henderson                 }
432661f15c48SRichard Henderson             }
432761f15c48SRichard Henderson         } else {
43285a18407fSRichard Henderson             for (i = 0; i < nb_oargs; i++) {
4329b83eabeaSRichard Henderson                 arg_ts = arg_temp(op->args[i]);
4330b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
4331b83eabeaSRichard Henderson                 if (!dir_ts) {
43325a18407fSRichard Henderson                     continue;
43335a18407fSRichard Henderson                 }
4334b83eabeaSRichard Henderson                 op->args[i] = temp_arg(dir_ts);
43355a18407fSRichard Henderson                 changes = true;
43365a18407fSRichard Henderson 
43375a18407fSRichard Henderson                 /* The output is now live and modified.  */
4338b83eabeaSRichard Henderson                 arg_ts->state = 0;
43395a18407fSRichard Henderson 
43405a18407fSRichard Henderson                 /* Sync outputs upon their last write.  */
43415a18407fSRichard Henderson                 if (NEED_SYNC_ARG(i)) {
4342b83eabeaSRichard Henderson                     TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
43435a18407fSRichard Henderson                                       ? INDEX_op_st_i32
43445a18407fSRichard Henderson                                       : INDEX_op_st_i64);
4345d4478943SPhilippe Mathieu-Daudé                     TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3);
43465a18407fSRichard Henderson 
4347b83eabeaSRichard Henderson                     sop->args[0] = temp_arg(dir_ts);
4348b83eabeaSRichard Henderson                     sop->args[1] = temp_arg(arg_ts->mem_base);
4349b83eabeaSRichard Henderson                     sop->args[2] = arg_ts->mem_offset;
43505a18407fSRichard Henderson 
4351b83eabeaSRichard Henderson                     arg_ts->state = TS_MEM;
43525a18407fSRichard Henderson                 }
43535a18407fSRichard Henderson                 /* Drop outputs that are dead.  */
43545a18407fSRichard Henderson                 if (IS_DEAD_ARG(i)) {
4355b83eabeaSRichard Henderson                     arg_ts->state = TS_DEAD;
43565a18407fSRichard Henderson                 }
43575a18407fSRichard Henderson             }
43585a18407fSRichard Henderson         }
435961f15c48SRichard Henderson     }
43605a18407fSRichard Henderson 
43615a18407fSRichard Henderson     return changes;
43625a18407fSRichard Henderson }
43635a18407fSRichard Henderson 
43642272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts)
4365c896fe29Sbellard {
436631c96417SRichard Henderson     intptr_t off;
4367273eb50cSRichard Henderson     int size, align;
4368c1c09194SRichard Henderson 
4369273eb50cSRichard Henderson     /* When allocating an object, look at the full type. */
4370273eb50cSRichard Henderson     size = tcg_type_size(ts->base_type);
4371273eb50cSRichard Henderson     switch (ts->base_type) {
4372c1c09194SRichard Henderson     case TCG_TYPE_I32:
437331c96417SRichard Henderson         align = 4;
4374c1c09194SRichard Henderson         break;
4375c1c09194SRichard Henderson     case TCG_TYPE_I64:
4376c1c09194SRichard Henderson     case TCG_TYPE_V64:
437731c96417SRichard Henderson         align = 8;
4378c1c09194SRichard Henderson         break;
437943eef72fSRichard Henderson     case TCG_TYPE_I128:
4380c1c09194SRichard Henderson     case TCG_TYPE_V128:
4381c1c09194SRichard Henderson     case TCG_TYPE_V256:
438243eef72fSRichard Henderson         /*
438343eef72fSRichard Henderson          * Note that we do not require aligned storage for V256,
438443eef72fSRichard Henderson          * and that we provide alignment for I128 to match V128,
438543eef72fSRichard Henderson          * even if that's above what the host ABI requires.
438643eef72fSRichard Henderson          */
438731c96417SRichard Henderson         align = 16;
4388c1c09194SRichard Henderson         break;
4389c1c09194SRichard Henderson     default:
4390c1c09194SRichard Henderson         g_assert_not_reached();
4391b591dc59SBlue Swirl     }
4392c1c09194SRichard Henderson 
4393b9537d59SRichard Henderson     /*
4394b9537d59SRichard Henderson      * Assume the stack is sufficiently aligned.
4395b9537d59SRichard Henderson      * This affects e.g. ARM NEON, where we have 8 byte stack alignment
4396b9537d59SRichard Henderson      * and do not require 16 byte vector alignment.  This seems slightly
4397b9537d59SRichard Henderson      * easier than fully parameterizing the above switch statement.
4398b9537d59SRichard Henderson      */
4399b9537d59SRichard Henderson     align = MIN(TCG_TARGET_STACK_ALIGN, align);
4400c1c09194SRichard Henderson     off = ROUND_UP(s->current_frame_offset, align);
4401732d5897SRichard Henderson 
4402732d5897SRichard Henderson     /* If we've exhausted the stack frame, restart with a smaller TB. */
4403732d5897SRichard Henderson     if (off + size > s->frame_end) {
4404732d5897SRichard Henderson         tcg_raise_tb_overflow(s);
4405732d5897SRichard Henderson     }
4406c1c09194SRichard Henderson     s->current_frame_offset = off + size;
44079defd1bdSRichard Henderson #if defined(__sparc__)
4408273eb50cSRichard Henderson     off += TCG_TARGET_STACK_BIAS;
44099defd1bdSRichard Henderson #endif
4410273eb50cSRichard Henderson 
4411273eb50cSRichard Henderson     /* If the object was subdivided, assign memory to all the parts. */
4412273eb50cSRichard Henderson     if (ts->base_type != ts->type) {
4413273eb50cSRichard Henderson         int part_size = tcg_type_size(ts->type);
4414273eb50cSRichard Henderson         int part_count = size / part_size;
4415273eb50cSRichard Henderson 
4416273eb50cSRichard Henderson         /*
4417273eb50cSRichard Henderson          * Each part is allocated sequentially in tcg_temp_new_internal.
4418273eb50cSRichard Henderson          * Jump back to the first part by subtracting the current index.
4419273eb50cSRichard Henderson          */
4420273eb50cSRichard Henderson         ts -= ts->temp_subindex;
4421273eb50cSRichard Henderson         for (int i = 0; i < part_count; ++i) {
4422273eb50cSRichard Henderson             ts[i].mem_offset = off + i * part_size;
4423273eb50cSRichard Henderson             ts[i].mem_base = s->frame_temp;
4424273eb50cSRichard Henderson             ts[i].mem_allocated = 1;
4425273eb50cSRichard Henderson         }
4426273eb50cSRichard Henderson     } else {
4427273eb50cSRichard Henderson         ts->mem_offset = off;
4428b3a62939SRichard Henderson         ts->mem_base = s->frame_temp;
4429c896fe29Sbellard         ts->mem_allocated = 1;
4430c896fe29Sbellard     }
4431273eb50cSRichard Henderson }
4432c896fe29Sbellard 
4433098859f1SRichard Henderson /* Assign @reg to @ts, and update reg_to_temp[]. */
4434098859f1SRichard Henderson static void set_temp_val_reg(TCGContext *s, TCGTemp *ts, TCGReg reg)
4435098859f1SRichard Henderson {
4436098859f1SRichard Henderson     if (ts->val_type == TEMP_VAL_REG) {
4437098859f1SRichard Henderson         TCGReg old = ts->reg;
4438098859f1SRichard Henderson         tcg_debug_assert(s->reg_to_temp[old] == ts);
4439098859f1SRichard Henderson         if (old == reg) {
4440098859f1SRichard Henderson             return;
4441098859f1SRichard Henderson         }
4442098859f1SRichard Henderson         s->reg_to_temp[old] = NULL;
4443098859f1SRichard Henderson     }
4444098859f1SRichard Henderson     tcg_debug_assert(s->reg_to_temp[reg] == NULL);
4445098859f1SRichard Henderson     s->reg_to_temp[reg] = ts;
4446098859f1SRichard Henderson     ts->val_type = TEMP_VAL_REG;
4447098859f1SRichard Henderson     ts->reg = reg;
4448098859f1SRichard Henderson }
4449098859f1SRichard Henderson 
4450098859f1SRichard Henderson /* Assign a non-register value type to @ts, and update reg_to_temp[]. */
4451098859f1SRichard Henderson static void set_temp_val_nonreg(TCGContext *s, TCGTemp *ts, TCGTempVal type)
4452098859f1SRichard Henderson {
4453098859f1SRichard Henderson     tcg_debug_assert(type != TEMP_VAL_REG);
4454098859f1SRichard Henderson     if (ts->val_type == TEMP_VAL_REG) {
4455098859f1SRichard Henderson         TCGReg reg = ts->reg;
4456098859f1SRichard Henderson         tcg_debug_assert(s->reg_to_temp[reg] == ts);
4457098859f1SRichard Henderson         s->reg_to_temp[reg] = NULL;
4458098859f1SRichard Henderson     }
4459098859f1SRichard Henderson     ts->val_type = type;
4460098859f1SRichard Henderson }
4461098859f1SRichard Henderson 
4462b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet);
4463b3915dbbSRichard Henderson 
446459d7c14eSRichard Henderson /* Mark a temporary as free or dead.  If 'free_or_dead' is negative,
446559d7c14eSRichard Henderson    mark it free; otherwise mark it dead.  */
446659d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead)
4467c896fe29Sbellard {
4468c0522136SRichard Henderson     TCGTempVal new_type;
4469c0522136SRichard Henderson 
4470c0522136SRichard Henderson     switch (ts->kind) {
4471c0522136SRichard Henderson     case TEMP_FIXED:
447259d7c14eSRichard Henderson         return;
4473c0522136SRichard Henderson     case TEMP_GLOBAL:
4474f57c6915SRichard Henderson     case TEMP_TB:
4475c0522136SRichard Henderson         new_type = TEMP_VAL_MEM;
4476c0522136SRichard Henderson         break;
4477c7482438SRichard Henderson     case TEMP_EBB:
4478c0522136SRichard Henderson         new_type = free_or_dead < 0 ? TEMP_VAL_MEM : TEMP_VAL_DEAD;
4479c0522136SRichard Henderson         break;
4480c0522136SRichard Henderson     case TEMP_CONST:
4481c0522136SRichard Henderson         new_type = TEMP_VAL_CONST;
4482c0522136SRichard Henderson         break;
4483c0522136SRichard Henderson     default:
4484c0522136SRichard Henderson         g_assert_not_reached();
448559d7c14eSRichard Henderson     }
4486098859f1SRichard Henderson     set_temp_val_nonreg(s, ts, new_type);
448759d7c14eSRichard Henderson }
4488c896fe29Sbellard 
448959d7c14eSRichard Henderson /* Mark a temporary as dead.  */
449059d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts)
449159d7c14eSRichard Henderson {
449259d7c14eSRichard Henderson     temp_free_or_dead(s, ts, 1);
449359d7c14eSRichard Henderson }
449459d7c14eSRichard Henderson 
449559d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary
449659d7c14eSRichard Henderson    registers needs to be allocated to store a constant.  If 'free_or_dead'
449759d7c14eSRichard Henderson    is non-zero, subsequently release the temporary; if it is positive, the
449859d7c14eSRichard Henderson    temp is dead; if it is negative, the temp is free.  */
449998b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs,
450098b4e186SRichard Henderson                       TCGRegSet preferred_regs, int free_or_dead)
450159d7c14eSRichard Henderson {
4502c0522136SRichard Henderson     if (!temp_readonly(ts) && !ts->mem_coherent) {
45037f6ceedfSAurelien Jarno         if (!ts->mem_allocated) {
45042272e4a7SRichard Henderson             temp_allocate_frame(s, ts);
450559d7c14eSRichard Henderson         }
450659d7c14eSRichard Henderson         switch (ts->val_type) {
450759d7c14eSRichard Henderson         case TEMP_VAL_CONST:
450859d7c14eSRichard Henderson             /* If we're going to free the temp immediately, then we won't
450959d7c14eSRichard Henderson                require it later in a register, so attempt to store the
451059d7c14eSRichard Henderson                constant to memory directly.  */
451159d7c14eSRichard Henderson             if (free_or_dead
451259d7c14eSRichard Henderson                 && tcg_out_sti(s, ts->type, ts->val,
451359d7c14eSRichard Henderson                                ts->mem_base->reg, ts->mem_offset)) {
451459d7c14eSRichard Henderson                 break;
451559d7c14eSRichard Henderson             }
451659d7c14eSRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
451798b4e186SRichard Henderson                       allocated_regs, preferred_regs);
451859d7c14eSRichard Henderson             /* fallthrough */
451959d7c14eSRichard Henderson 
452059d7c14eSRichard Henderson         case TEMP_VAL_REG:
452159d7c14eSRichard Henderson             tcg_out_st(s, ts->type, ts->reg,
452259d7c14eSRichard Henderson                        ts->mem_base->reg, ts->mem_offset);
452359d7c14eSRichard Henderson             break;
452459d7c14eSRichard Henderson 
452559d7c14eSRichard Henderson         case TEMP_VAL_MEM:
452659d7c14eSRichard Henderson             break;
452759d7c14eSRichard Henderson 
452859d7c14eSRichard Henderson         case TEMP_VAL_DEAD:
452959d7c14eSRichard Henderson         default:
4530732e89f4SRichard Henderson             g_assert_not_reached();
4531c896fe29Sbellard         }
45327f6ceedfSAurelien Jarno         ts->mem_coherent = 1;
45337f6ceedfSAurelien Jarno     }
453459d7c14eSRichard Henderson     if (free_or_dead) {
453559d7c14eSRichard Henderson         temp_free_or_dead(s, ts, free_or_dead);
453659d7c14eSRichard Henderson     }
453759d7c14eSRichard Henderson }
45387f6ceedfSAurelien Jarno 
45397f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */
4540b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs)
45417f6ceedfSAurelien Jarno {
4542f8b2f202SRichard Henderson     TCGTemp *ts = s->reg_to_temp[reg];
4543f8b2f202SRichard Henderson     if (ts != NULL) {
454498b4e186SRichard Henderson         temp_sync(s, ts, allocated_regs, 0, -1);
4545c896fe29Sbellard     }
4546c896fe29Sbellard }
4547c896fe29Sbellard 
4548b016486eSRichard Henderson /**
4549b016486eSRichard Henderson  * tcg_reg_alloc:
4550b016486eSRichard Henderson  * @required_regs: Set of registers in which we must allocate.
4551b016486eSRichard Henderson  * @allocated_regs: Set of registers which must be avoided.
4552b016486eSRichard Henderson  * @preferred_regs: Set of registers we should prefer.
4553b016486eSRichard Henderson  * @rev: True if we search the registers in "indirect" order.
4554b016486eSRichard Henderson  *
4555b016486eSRichard Henderson  * The allocated register must be in @required_regs & ~@allocated_regs,
4556b016486eSRichard Henderson  * but if we can put it in @preferred_regs we may save a move later.
4557b016486eSRichard Henderson  */
4558b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs,
4559b016486eSRichard Henderson                             TCGRegSet allocated_regs,
4560b016486eSRichard Henderson                             TCGRegSet preferred_regs, bool rev)
4561c896fe29Sbellard {
4562b016486eSRichard Henderson     int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
4563b016486eSRichard Henderson     TCGRegSet reg_ct[2];
456491478cefSRichard Henderson     const int *order;
4565c896fe29Sbellard 
4566b016486eSRichard Henderson     reg_ct[1] = required_regs & ~allocated_regs;
4567b016486eSRichard Henderson     tcg_debug_assert(reg_ct[1] != 0);
4568b016486eSRichard Henderson     reg_ct[0] = reg_ct[1] & preferred_regs;
4569b016486eSRichard Henderson 
4570b016486eSRichard Henderson     /* Skip the preferred_regs option if it cannot be satisfied,
4571b016486eSRichard Henderson        or if the preference made no difference.  */
4572b016486eSRichard Henderson     f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1];
4573b016486eSRichard Henderson 
457491478cefSRichard Henderson     order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
4575c896fe29Sbellard 
4576b016486eSRichard Henderson     /* Try free registers, preferences first.  */
4577b016486eSRichard Henderson     for (j = f; j < 2; j++) {
4578b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
4579b016486eSRichard Henderson 
4580b016486eSRichard Henderson         if (tcg_regset_single(set)) {
4581b016486eSRichard Henderson             /* One register in the set.  */
4582b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
4583b016486eSRichard Henderson             if (s->reg_to_temp[reg] == NULL) {
4584c896fe29Sbellard                 return reg;
4585c896fe29Sbellard             }
4586b016486eSRichard Henderson         } else {
458791478cefSRichard Henderson             for (i = 0; i < n; i++) {
4588b016486eSRichard Henderson                 TCGReg reg = order[i];
4589b016486eSRichard Henderson                 if (s->reg_to_temp[reg] == NULL &&
4590b016486eSRichard Henderson                     tcg_regset_test_reg(set, reg)) {
4591b016486eSRichard Henderson                     return reg;
4592b016486eSRichard Henderson                 }
4593b016486eSRichard Henderson             }
4594b016486eSRichard Henderson         }
4595b016486eSRichard Henderson     }
4596b016486eSRichard Henderson 
4597b016486eSRichard Henderson     /* We must spill something.  */
4598b016486eSRichard Henderson     for (j = f; j < 2; j++) {
4599b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
4600b016486eSRichard Henderson 
4601b016486eSRichard Henderson         if (tcg_regset_single(set)) {
4602b016486eSRichard Henderson             /* One register in the set.  */
4603b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
4604b3915dbbSRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
4605c896fe29Sbellard             return reg;
4606b016486eSRichard Henderson         } else {
4607b016486eSRichard Henderson             for (i = 0; i < n; i++) {
4608b016486eSRichard Henderson                 TCGReg reg = order[i];
4609b016486eSRichard Henderson                 if (tcg_regset_test_reg(set, reg)) {
4610b016486eSRichard Henderson                     tcg_reg_free(s, reg, allocated_regs);
4611b016486eSRichard Henderson                     return reg;
4612b016486eSRichard Henderson                 }
4613b016486eSRichard Henderson             }
4614c896fe29Sbellard         }
4615c896fe29Sbellard     }
4616c896fe29Sbellard 
4617732e89f4SRichard Henderson     g_assert_not_reached();
4618c896fe29Sbellard }
4619c896fe29Sbellard 
462029f5e925SRichard Henderson static TCGReg tcg_reg_alloc_pair(TCGContext *s, TCGRegSet required_regs,
462129f5e925SRichard Henderson                                  TCGRegSet allocated_regs,
462229f5e925SRichard Henderson                                  TCGRegSet preferred_regs, bool rev)
462329f5e925SRichard Henderson {
462429f5e925SRichard Henderson     int i, j, k, fmin, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
462529f5e925SRichard Henderson     TCGRegSet reg_ct[2];
462629f5e925SRichard Henderson     const int *order;
462729f5e925SRichard Henderson 
462829f5e925SRichard Henderson     /* Ensure that if I is not in allocated_regs, I+1 is not either. */
462929f5e925SRichard Henderson     reg_ct[1] = required_regs & ~(allocated_regs | (allocated_regs >> 1));
463029f5e925SRichard Henderson     tcg_debug_assert(reg_ct[1] != 0);
463129f5e925SRichard Henderson     reg_ct[0] = reg_ct[1] & preferred_regs;
463229f5e925SRichard Henderson 
463329f5e925SRichard Henderson     order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
463429f5e925SRichard Henderson 
463529f5e925SRichard Henderson     /*
463629f5e925SRichard Henderson      * Skip the preferred_regs option if it cannot be satisfied,
463729f5e925SRichard Henderson      * or if the preference made no difference.
463829f5e925SRichard Henderson      */
463929f5e925SRichard Henderson     k = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1];
464029f5e925SRichard Henderson 
464129f5e925SRichard Henderson     /*
464229f5e925SRichard Henderson      * Minimize the number of flushes by looking for 2 free registers first,
464329f5e925SRichard Henderson      * then a single flush, then two flushes.
464429f5e925SRichard Henderson      */
464529f5e925SRichard Henderson     for (fmin = 2; fmin >= 0; fmin--) {
464629f5e925SRichard Henderson         for (j = k; j < 2; j++) {
464729f5e925SRichard Henderson             TCGRegSet set = reg_ct[j];
464829f5e925SRichard Henderson 
464929f5e925SRichard Henderson             for (i = 0; i < n; i++) {
465029f5e925SRichard Henderson                 TCGReg reg = order[i];
465129f5e925SRichard Henderson 
465229f5e925SRichard Henderson                 if (tcg_regset_test_reg(set, reg)) {
465329f5e925SRichard Henderson                     int f = !s->reg_to_temp[reg] + !s->reg_to_temp[reg + 1];
465429f5e925SRichard Henderson                     if (f >= fmin) {
465529f5e925SRichard Henderson                         tcg_reg_free(s, reg, allocated_regs);
465629f5e925SRichard Henderson                         tcg_reg_free(s, reg + 1, allocated_regs);
465729f5e925SRichard Henderson                         return reg;
465829f5e925SRichard Henderson                     }
465929f5e925SRichard Henderson                 }
466029f5e925SRichard Henderson             }
466129f5e925SRichard Henderson         }
466229f5e925SRichard Henderson     }
4663732e89f4SRichard Henderson     g_assert_not_reached();
466429f5e925SRichard Henderson }
466529f5e925SRichard Henderson 
466640ae5c62SRichard Henderson /* Make sure the temporary is in a register.  If needed, allocate the register
466740ae5c62SRichard Henderson    from DESIRED while avoiding ALLOCATED.  */
466840ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs,
4669b722452aSRichard Henderson                       TCGRegSet allocated_regs, TCGRegSet preferred_regs)
467040ae5c62SRichard Henderson {
467140ae5c62SRichard Henderson     TCGReg reg;
467240ae5c62SRichard Henderson 
467340ae5c62SRichard Henderson     switch (ts->val_type) {
467440ae5c62SRichard Henderson     case TEMP_VAL_REG:
467540ae5c62SRichard Henderson         return;
467640ae5c62SRichard Henderson     case TEMP_VAL_CONST:
4677b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
4678b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
46790a6a8bc8SRichard Henderson         if (ts->type <= TCG_TYPE_I64) {
468040ae5c62SRichard Henderson             tcg_out_movi(s, ts->type, reg, ts->val);
46810a6a8bc8SRichard Henderson         } else {
46824e186175SRichard Henderson             uint64_t val = ts->val;
46834e186175SRichard Henderson             MemOp vece = MO_64;
46844e186175SRichard Henderson 
46854e186175SRichard Henderson             /*
46864e186175SRichard Henderson              * Find the minimal vector element that matches the constant.
46874e186175SRichard Henderson              * The targets will, in general, have to do this search anyway,
46884e186175SRichard Henderson              * do this generically.
46894e186175SRichard Henderson              */
46904e186175SRichard Henderson             if (val == dup_const(MO_8, val)) {
46914e186175SRichard Henderson                 vece = MO_8;
46924e186175SRichard Henderson             } else if (val == dup_const(MO_16, val)) {
46934e186175SRichard Henderson                 vece = MO_16;
46940b4286ddSRichard Henderson             } else if (val == dup_const(MO_32, val)) {
46954e186175SRichard Henderson                 vece = MO_32;
46964e186175SRichard Henderson             }
46974e186175SRichard Henderson 
46984e186175SRichard Henderson             tcg_out_dupi_vec(s, ts->type, vece, reg, ts->val);
46990a6a8bc8SRichard Henderson         }
470040ae5c62SRichard Henderson         ts->mem_coherent = 0;
470140ae5c62SRichard Henderson         break;
470240ae5c62SRichard Henderson     case TEMP_VAL_MEM:
4703b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
4704b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
470540ae5c62SRichard Henderson         tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset);
470640ae5c62SRichard Henderson         ts->mem_coherent = 1;
470740ae5c62SRichard Henderson         break;
470840ae5c62SRichard Henderson     case TEMP_VAL_DEAD:
470940ae5c62SRichard Henderson     default:
4710732e89f4SRichard Henderson         g_assert_not_reached();
471140ae5c62SRichard Henderson     }
4712098859f1SRichard Henderson     set_temp_val_reg(s, ts, reg);
471340ae5c62SRichard Henderson }
471440ae5c62SRichard Henderson 
471559d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a
4716e8996ee0Sbellard    temporary registers needs to be allocated to store a constant.  */
471759d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs)
47181ad80729SAurelien Jarno {
47192c0366f0SAurelien Jarno     /* The liveness analysis already ensures that globals are back
4720eabb7b91SAurelien Jarno        in memory. Keep an tcg_debug_assert for safety. */
4721e01fa97dSRichard Henderson     tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || temp_readonly(ts));
47221ad80729SAurelien Jarno }
47231ad80729SAurelien Jarno 
47249814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be
4725641d5fbeSbellard    modified be the following code. 'allocated_regs' is used in case a
4726641d5fbeSbellard    temporary registers needs to be allocated to store a constant. */
4727641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
4728641d5fbeSbellard {
4729ac3b8891SRichard Henderson     int i, n;
4730641d5fbeSbellard 
4731ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
4732b13eb728SRichard Henderson         temp_save(s, &s->temps[i], allocated_regs);
4733641d5fbeSbellard     }
4734e5097dc8Sbellard }
4735e5097dc8Sbellard 
47363d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be
47373d5c5f87SAurelien Jarno    read by the following code. 'allocated_regs' is used in case a
47383d5c5f87SAurelien Jarno    temporary registers needs to be allocated to store a constant. */
47393d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs)
47403d5c5f87SAurelien Jarno {
4741ac3b8891SRichard Henderson     int i, n;
47423d5c5f87SAurelien Jarno 
4743ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
474412b9b11aSRichard Henderson         TCGTemp *ts = &s->temps[i];
474512b9b11aSRichard Henderson         tcg_debug_assert(ts->val_type != TEMP_VAL_REG
4746ee17db83SRichard Henderson                          || ts->kind == TEMP_FIXED
474712b9b11aSRichard Henderson                          || ts->mem_coherent);
47483d5c5f87SAurelien Jarno     }
47493d5c5f87SAurelien Jarno }
47503d5c5f87SAurelien Jarno 
4751e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and
4752e8996ee0Sbellard    all globals are stored at their canonical location. */
4753e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
4754e5097dc8Sbellard {
4755e5097dc8Sbellard     int i;
4756e5097dc8Sbellard 
4757c896fe29Sbellard     for (i = s->nb_globals; i < s->nb_temps; i++) {
4758b13eb728SRichard Henderson         TCGTemp *ts = &s->temps[i];
4759c0522136SRichard Henderson 
4760c0522136SRichard Henderson         switch (ts->kind) {
4761f57c6915SRichard Henderson         case TEMP_TB:
4762b13eb728SRichard Henderson             temp_save(s, ts, allocated_regs);
4763c0522136SRichard Henderson             break;
4764c7482438SRichard Henderson         case TEMP_EBB:
47652c0366f0SAurelien Jarno             /* The liveness analysis already ensures that temps are dead.
4766eabb7b91SAurelien Jarno                Keep an tcg_debug_assert for safety. */
4767eabb7b91SAurelien Jarno             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
4768c0522136SRichard Henderson             break;
4769c0522136SRichard Henderson         case TEMP_CONST:
4770c0522136SRichard Henderson             /* Similarly, we should have freed any allocated register. */
4771c0522136SRichard Henderson             tcg_debug_assert(ts->val_type == TEMP_VAL_CONST);
4772c0522136SRichard Henderson             break;
4773c0522136SRichard Henderson         default:
4774c0522136SRichard Henderson             g_assert_not_reached();
4775c896fe29Sbellard         }
4776641d5fbeSbellard     }
4777e8996ee0Sbellard 
4778e8996ee0Sbellard     save_globals(s, allocated_regs);
4779c896fe29Sbellard }
4780c896fe29Sbellard 
4781bab1671fSRichard Henderson /*
4782c7482438SRichard Henderson  * At a conditional branch, we assume all temporaries are dead unless
4783c7482438SRichard Henderson  * explicitly live-across-conditional-branch; all globals and local
4784c7482438SRichard Henderson  * temps are synced to their location.
4785b4cb76e6SRichard Henderson  */
4786b4cb76e6SRichard Henderson static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs)
4787b4cb76e6SRichard Henderson {
4788b4cb76e6SRichard Henderson     sync_globals(s, allocated_regs);
4789b4cb76e6SRichard Henderson 
4790b4cb76e6SRichard Henderson     for (int i = s->nb_globals; i < s->nb_temps; i++) {
4791b4cb76e6SRichard Henderson         TCGTemp *ts = &s->temps[i];
4792b4cb76e6SRichard Henderson         /*
4793b4cb76e6SRichard Henderson          * The liveness analysis already ensures that temps are dead.
4794b4cb76e6SRichard Henderson          * Keep tcg_debug_asserts for safety.
4795b4cb76e6SRichard Henderson          */
4796c0522136SRichard Henderson         switch (ts->kind) {
4797f57c6915SRichard Henderson         case TEMP_TB:
4798b4cb76e6SRichard Henderson             tcg_debug_assert(ts->val_type != TEMP_VAL_REG || ts->mem_coherent);
4799c0522136SRichard Henderson             break;
4800c7482438SRichard Henderson         case TEMP_EBB:
4801c0522136SRichard Henderson         case TEMP_CONST:
4802c0522136SRichard Henderson             break;
4803c0522136SRichard Henderson         default:
4804c0522136SRichard Henderson             g_assert_not_reached();
4805b4cb76e6SRichard Henderson         }
4806b4cb76e6SRichard Henderson     }
4807b4cb76e6SRichard Henderson }
4808b4cb76e6SRichard Henderson 
4809b4cb76e6SRichard Henderson /*
4810c58f4c97SRichard Henderson  * Specialized code generation for INDEX_op_mov_* with a constant.
4811bab1671fSRichard Henderson  */
48120fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots,
4813ba87719cSRichard Henderson                                   tcg_target_ulong val, TCGLifeData arg_life,
4814ba87719cSRichard Henderson                                   TCGRegSet preferred_regs)
4815e8996ee0Sbellard {
4816d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
4817e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
481859d7c14eSRichard Henderson 
481959d7c14eSRichard Henderson     /* The movi is not explicitly generated here.  */
4820098859f1SRichard Henderson     set_temp_val_nonreg(s, ots, TEMP_VAL_CONST);
4821e8996ee0Sbellard     ots->val = val;
482259d7c14eSRichard Henderson     ots->mem_coherent = 0;
4823ec7a869dSAurelien Jarno     if (NEED_SYNC_ARG(0)) {
4824ba87719cSRichard Henderson         temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0));
482559d7c14eSRichard Henderson     } else if (IS_DEAD_ARG(0)) {
4826f8bf00f1SRichard Henderson         temp_dead(s, ots);
48274c4e1ab2SAurelien Jarno     }
4828e8996ee0Sbellard }
4829e8996ee0Sbellard 
4830bab1671fSRichard Henderson /*
4831bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_mov_*.
4832bab1671fSRichard Henderson  */
4833dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op)
4834c896fe29Sbellard {
4835dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
483669e3706dSRichard Henderson     TCGRegSet allocated_regs, preferred_regs;
4837c896fe29Sbellard     TCGTemp *ts, *ots;
4838450445d5SRichard Henderson     TCGType otype, itype;
4839098859f1SRichard Henderson     TCGReg oreg, ireg;
4840c896fe29Sbellard 
4841d21369f5SRichard Henderson     allocated_regs = s->reserved_regs;
484231fd884bSRichard Henderson     preferred_regs = output_pref(op, 0);
484343439139SRichard Henderson     ots = arg_temp(op->args[0]);
484443439139SRichard Henderson     ts = arg_temp(op->args[1]);
4845450445d5SRichard Henderson 
4846d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
4847e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
4848d63e3b6eSRichard Henderson 
4849450445d5SRichard Henderson     /* Note that otype != itype for no-op truncation.  */
4850450445d5SRichard Henderson     otype = ots->type;
4851450445d5SRichard Henderson     itype = ts->type;
4852c896fe29Sbellard 
48530fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_CONST) {
48540fe4fca4SPaolo Bonzini         /* propagate constant or generate sti */
48550fe4fca4SPaolo Bonzini         tcg_target_ulong val = ts->val;
48560fe4fca4SPaolo Bonzini         if (IS_DEAD_ARG(1)) {
48570fe4fca4SPaolo Bonzini             temp_dead(s, ts);
48580fe4fca4SPaolo Bonzini         }
485969e3706dSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs);
48600fe4fca4SPaolo Bonzini         return;
48610fe4fca4SPaolo Bonzini     }
48620fe4fca4SPaolo Bonzini 
48630fe4fca4SPaolo Bonzini     /* If the source value is in memory we're going to be forced
48640fe4fca4SPaolo Bonzini        to have it in a register in order to perform the copy.  Copy
48650fe4fca4SPaolo Bonzini        the SOURCE value into its own register first, that way we
48660fe4fca4SPaolo Bonzini        don't have to reload SOURCE the next time it is used. */
48670fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_MEM) {
486869e3706dSRichard Henderson         temp_load(s, ts, tcg_target_available_regs[itype],
486969e3706dSRichard Henderson                   allocated_regs, preferred_regs);
4870c29c1d7eSAurelien Jarno     }
48710fe4fca4SPaolo Bonzini     tcg_debug_assert(ts->val_type == TEMP_VAL_REG);
4872098859f1SRichard Henderson     ireg = ts->reg;
4873098859f1SRichard Henderson 
4874d63e3b6eSRichard Henderson     if (IS_DEAD_ARG(0)) {
4875c29c1d7eSAurelien Jarno         /* mov to a non-saved dead register makes no sense (even with
4876c29c1d7eSAurelien Jarno            liveness analysis disabled). */
4877eabb7b91SAurelien Jarno         tcg_debug_assert(NEED_SYNC_ARG(0));
4878c29c1d7eSAurelien Jarno         if (!ots->mem_allocated) {
48792272e4a7SRichard Henderson             temp_allocate_frame(s, ots);
4880c29c1d7eSAurelien Jarno         }
4881098859f1SRichard Henderson         tcg_out_st(s, otype, ireg, ots->mem_base->reg, ots->mem_offset);
4882c29c1d7eSAurelien Jarno         if (IS_DEAD_ARG(1)) {
4883f8bf00f1SRichard Henderson             temp_dead(s, ts);
4884c29c1d7eSAurelien Jarno         }
4885f8bf00f1SRichard Henderson         temp_dead(s, ots);
4886098859f1SRichard Henderson         return;
4887098859f1SRichard Henderson     }
4888098859f1SRichard Henderson 
4889ee17db83SRichard Henderson     if (IS_DEAD_ARG(1) && ts->kind != TEMP_FIXED) {
4890098859f1SRichard Henderson         /*
4891098859f1SRichard Henderson          * The mov can be suppressed.  Kill input first, so that it
4892098859f1SRichard Henderson          * is unlinked from reg_to_temp, then set the output to the
4893098859f1SRichard Henderson          * reg that we saved from the input.
4894098859f1SRichard Henderson          */
4895f8bf00f1SRichard Henderson         temp_dead(s, ts);
4896098859f1SRichard Henderson         oreg = ireg;
4897c29c1d7eSAurelien Jarno     } else {
4898098859f1SRichard Henderson         if (ots->val_type == TEMP_VAL_REG) {
4899098859f1SRichard Henderson             oreg = ots->reg;
4900098859f1SRichard Henderson         } else {
4901098859f1SRichard Henderson             /* Make sure to not spill the input register during allocation. */
4902098859f1SRichard Henderson             oreg = tcg_reg_alloc(s, tcg_target_available_regs[otype],
4903098859f1SRichard Henderson                                  allocated_regs | ((TCGRegSet)1 << ireg),
4904098859f1SRichard Henderson                                  preferred_regs, ots->indirect_base);
4905c29c1d7eSAurelien Jarno         }
4906098859f1SRichard Henderson         if (!tcg_out_mov(s, otype, oreg, ireg)) {
4907240c08d0SRichard Henderson             /*
4908240c08d0SRichard Henderson              * Cross register class move not supported.
4909240c08d0SRichard Henderson              * Store the source register into the destination slot
4910240c08d0SRichard Henderson              * and leave the destination temp as TEMP_VAL_MEM.
4911240c08d0SRichard Henderson              */
4912e01fa97dSRichard Henderson             assert(!temp_readonly(ots));
4913240c08d0SRichard Henderson             if (!ts->mem_allocated) {
4914240c08d0SRichard Henderson                 temp_allocate_frame(s, ots);
4915240c08d0SRichard Henderson             }
4916098859f1SRichard Henderson             tcg_out_st(s, ts->type, ireg, ots->mem_base->reg, ots->mem_offset);
4917098859f1SRichard Henderson             set_temp_val_nonreg(s, ts, TEMP_VAL_MEM);
4918240c08d0SRichard Henderson             ots->mem_coherent = 1;
4919240c08d0SRichard Henderson             return;
492078113e83SRichard Henderson         }
4921c29c1d7eSAurelien Jarno     }
4922098859f1SRichard Henderson     set_temp_val_reg(s, ots, oreg);
4923c896fe29Sbellard     ots->mem_coherent = 0;
4924098859f1SRichard Henderson 
4925ec7a869dSAurelien Jarno     if (NEED_SYNC_ARG(0)) {
492698b4e186SRichard Henderson         temp_sync(s, ots, allocated_regs, 0, 0);
4927c29c1d7eSAurelien Jarno     }
4928ec7a869dSAurelien Jarno }
4929c896fe29Sbellard 
4930bab1671fSRichard Henderson /*
4931bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_dup_vec.
4932bab1671fSRichard Henderson  */
4933bab1671fSRichard Henderson static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op)
4934bab1671fSRichard Henderson {
4935bab1671fSRichard Henderson     const TCGLifeData arg_life = op->life;
4936bab1671fSRichard Henderson     TCGRegSet dup_out_regs, dup_in_regs;
4937501fb3daSRichard Henderson     const TCGArgConstraint *dup_args_ct;
4938bab1671fSRichard Henderson     TCGTemp *its, *ots;
4939bab1671fSRichard Henderson     TCGType itype, vtype;
4940bab1671fSRichard Henderson     unsigned vece;
494131c96417SRichard Henderson     int lowpart_ofs;
4942bab1671fSRichard Henderson     bool ok;
4943bab1671fSRichard Henderson 
4944bab1671fSRichard Henderson     ots = arg_temp(op->args[0]);
4945bab1671fSRichard Henderson     its = arg_temp(op->args[1]);
4946bab1671fSRichard Henderson 
4947bab1671fSRichard Henderson     /* ENV should not be modified.  */
4948e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
4949bab1671fSRichard Henderson 
4950bab1671fSRichard Henderson     itype = its->type;
4951bab1671fSRichard Henderson     vece = TCGOP_VECE(op);
49524d872218SRichard Henderson     vtype = TCGOP_TYPE(op);
4953bab1671fSRichard Henderson 
4954bab1671fSRichard Henderson     if (its->val_type == TEMP_VAL_CONST) {
4955bab1671fSRichard Henderson         /* Propagate constant via movi -> dupi.  */
4956bab1671fSRichard Henderson         tcg_target_ulong val = its->val;
4957bab1671fSRichard Henderson         if (IS_DEAD_ARG(1)) {
4958bab1671fSRichard Henderson             temp_dead(s, its);
4959bab1671fSRichard Henderson         }
496031fd884bSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, output_pref(op, 0));
4961bab1671fSRichard Henderson         return;
4962bab1671fSRichard Henderson     }
4963bab1671fSRichard Henderson 
4964501fb3daSRichard Henderson     dup_args_ct = opcode_args_ct(op);
4965501fb3daSRichard Henderson     dup_out_regs = dup_args_ct[0].regs;
4966501fb3daSRichard Henderson     dup_in_regs = dup_args_ct[1].regs;
4967bab1671fSRichard Henderson 
4968bab1671fSRichard Henderson     /* Allocate the output register now.  */
4969bab1671fSRichard Henderson     if (ots->val_type != TEMP_VAL_REG) {
4970bab1671fSRichard Henderson         TCGRegSet allocated_regs = s->reserved_regs;
4971098859f1SRichard Henderson         TCGReg oreg;
4972bab1671fSRichard Henderson 
4973bab1671fSRichard Henderson         if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) {
4974bab1671fSRichard Henderson             /* Make sure to not spill the input register. */
4975bab1671fSRichard Henderson             tcg_regset_set_reg(allocated_regs, its->reg);
4976bab1671fSRichard Henderson         }
4977098859f1SRichard Henderson         oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
497831fd884bSRichard Henderson                              output_pref(op, 0), ots->indirect_base);
4979098859f1SRichard Henderson         set_temp_val_reg(s, ots, oreg);
4980bab1671fSRichard Henderson     }
4981bab1671fSRichard Henderson 
4982bab1671fSRichard Henderson     switch (its->val_type) {
4983bab1671fSRichard Henderson     case TEMP_VAL_REG:
4984bab1671fSRichard Henderson         /*
4985bab1671fSRichard Henderson          * The dup constriaints must be broad, covering all possible VECE.
4986bab1671fSRichard Henderson          * However, tcg_op_dup_vec() gets to see the VECE and we allow it
4987bab1671fSRichard Henderson          * to fail, indicating that extra moves are required for that case.
4988bab1671fSRichard Henderson          */
4989bab1671fSRichard Henderson         if (tcg_regset_test_reg(dup_in_regs, its->reg)) {
4990bab1671fSRichard Henderson             if (tcg_out_dup_vec(s, vtype, vece, ots->reg, its->reg)) {
4991bab1671fSRichard Henderson                 goto done;
4992bab1671fSRichard Henderson             }
4993bab1671fSRichard Henderson             /* Try again from memory or a vector input register.  */
4994bab1671fSRichard Henderson         }
4995bab1671fSRichard Henderson         if (!its->mem_coherent) {
4996bab1671fSRichard Henderson             /*
4997bab1671fSRichard Henderson              * The input register is not synced, and so an extra store
4998bab1671fSRichard Henderson              * would be required to use memory.  Attempt an integer-vector
4999bab1671fSRichard Henderson              * register move first.  We do not have a TCGRegSet for this.
5000bab1671fSRichard Henderson              */
5001bab1671fSRichard Henderson             if (tcg_out_mov(s, itype, ots->reg, its->reg)) {
5002bab1671fSRichard Henderson                 break;
5003bab1671fSRichard Henderson             }
5004bab1671fSRichard Henderson             /* Sync the temp back to its slot and load from there.  */
5005bab1671fSRichard Henderson             temp_sync(s, its, s->reserved_regs, 0, 0);
5006bab1671fSRichard Henderson         }
5007bab1671fSRichard Henderson         /* fall through */
5008bab1671fSRichard Henderson 
5009bab1671fSRichard Henderson     case TEMP_VAL_MEM:
501031c96417SRichard Henderson         lowpart_ofs = 0;
501131c96417SRichard Henderson         if (HOST_BIG_ENDIAN) {
501231c96417SRichard Henderson             lowpart_ofs = tcg_type_size(itype) - (1 << vece);
501331c96417SRichard Henderson         }
5014d6ecb4a9SRichard Henderson         if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg,
501531c96417SRichard Henderson                              its->mem_offset + lowpart_ofs)) {
5016d6ecb4a9SRichard Henderson             goto done;
5017d6ecb4a9SRichard Henderson         }
5018098859f1SRichard Henderson         /* Load the input into the destination vector register. */
5019bab1671fSRichard Henderson         tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset);
5020bab1671fSRichard Henderson         break;
5021bab1671fSRichard Henderson 
5022bab1671fSRichard Henderson     default:
5023bab1671fSRichard Henderson         g_assert_not_reached();
5024bab1671fSRichard Henderson     }
5025bab1671fSRichard Henderson 
5026bab1671fSRichard Henderson     /* We now have a vector input register, so dup must succeed. */
5027bab1671fSRichard Henderson     ok = tcg_out_dup_vec(s, vtype, vece, ots->reg, ots->reg);
5028bab1671fSRichard Henderson     tcg_debug_assert(ok);
5029bab1671fSRichard Henderson 
5030bab1671fSRichard Henderson  done:
503136f5539cSRichard Henderson     ots->mem_coherent = 0;
5032bab1671fSRichard Henderson     if (IS_DEAD_ARG(1)) {
5033bab1671fSRichard Henderson         temp_dead(s, its);
5034bab1671fSRichard Henderson     }
5035bab1671fSRichard Henderson     if (NEED_SYNC_ARG(0)) {
5036bab1671fSRichard Henderson         temp_sync(s, ots, s->reserved_regs, 0, 0);
5037bab1671fSRichard Henderson     }
5038bab1671fSRichard Henderson     if (IS_DEAD_ARG(0)) {
5039bab1671fSRichard Henderson         temp_dead(s, ots);
5040bab1671fSRichard Henderson     }
5041bab1671fSRichard Henderson }
5042bab1671fSRichard Henderson 
5043dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op)
5044c896fe29Sbellard {
5045dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
5046dd186292SRichard Henderson     const TCGOpDef * const def = &tcg_op_defs[op->opc];
504782790a87SRichard Henderson     TCGRegSet i_allocated_regs;
504882790a87SRichard Henderson     TCGRegSet o_allocated_regs;
5049b6638662SRichard Henderson     int i, k, nb_iargs, nb_oargs;
5050b6638662SRichard Henderson     TCGReg reg;
5051c896fe29Sbellard     TCGArg arg;
5052501fb3daSRichard Henderson     const TCGArgConstraint *args_ct;
5053c896fe29Sbellard     const TCGArgConstraint *arg_ct;
5054c896fe29Sbellard     TCGTemp *ts;
5055c896fe29Sbellard     TCGArg new_args[TCG_MAX_OP_ARGS];
5056c896fe29Sbellard     int const_args[TCG_MAX_OP_ARGS];
505721e9a8aeSRichard Henderson     TCGCond op_cond;
5058c896fe29Sbellard 
5059c896fe29Sbellard     nb_oargs = def->nb_oargs;
5060c896fe29Sbellard     nb_iargs = def->nb_iargs;
5061c896fe29Sbellard 
5062c896fe29Sbellard     /* copy constants */
5063c896fe29Sbellard     memcpy(new_args + nb_oargs + nb_iargs,
5064dd186292SRichard Henderson            op->args + nb_oargs + nb_iargs,
5065c896fe29Sbellard            sizeof(TCGArg) * def->nb_cargs);
5066c896fe29Sbellard 
5067d21369f5SRichard Henderson     i_allocated_regs = s->reserved_regs;
5068d21369f5SRichard Henderson     o_allocated_regs = s->reserved_regs;
506982790a87SRichard Henderson 
507021e9a8aeSRichard Henderson     switch (op->opc) {
507121e9a8aeSRichard Henderson     case INDEX_op_brcond_i32:
507221e9a8aeSRichard Henderson     case INDEX_op_brcond_i64:
507321e9a8aeSRichard Henderson         op_cond = op->args[2];
507421e9a8aeSRichard Henderson         break;
507521e9a8aeSRichard Henderson     case INDEX_op_setcond_i32:
507621e9a8aeSRichard Henderson     case INDEX_op_setcond_i64:
507721e9a8aeSRichard Henderson     case INDEX_op_negsetcond_i32:
507821e9a8aeSRichard Henderson     case INDEX_op_negsetcond_i64:
507921e9a8aeSRichard Henderson     case INDEX_op_cmp_vec:
508021e9a8aeSRichard Henderson         op_cond = op->args[3];
508121e9a8aeSRichard Henderson         break;
508221e9a8aeSRichard Henderson     case INDEX_op_brcond2_i32:
508321e9a8aeSRichard Henderson         op_cond = op->args[4];
508421e9a8aeSRichard Henderson         break;
508521e9a8aeSRichard Henderson     case INDEX_op_movcond_i32:
508621e9a8aeSRichard Henderson     case INDEX_op_movcond_i64:
508721e9a8aeSRichard Henderson     case INDEX_op_setcond2_i32:
508821e9a8aeSRichard Henderson     case INDEX_op_cmpsel_vec:
508921e9a8aeSRichard Henderson         op_cond = op->args[5];
509021e9a8aeSRichard Henderson         break;
509121e9a8aeSRichard Henderson     default:
509221e9a8aeSRichard Henderson         /* No condition within opcode. */
509321e9a8aeSRichard Henderson         op_cond = TCG_COND_ALWAYS;
509421e9a8aeSRichard Henderson         break;
509521e9a8aeSRichard Henderson     }
509621e9a8aeSRichard Henderson 
5097501fb3daSRichard Henderson     args_ct = opcode_args_ct(op);
5098501fb3daSRichard Henderson 
5099c896fe29Sbellard     /* satisfy input constraints */
5100c896fe29Sbellard     for (k = 0; k < nb_iargs; k++) {
510129f5e925SRichard Henderson         TCGRegSet i_preferred_regs, i_required_regs;
510229f5e925SRichard Henderson         bool allocate_new_reg, copyto_new_reg;
510329f5e925SRichard Henderson         TCGTemp *ts2;
510429f5e925SRichard Henderson         int i1, i2;
5105d62816f2SRichard Henderson 
5106501fb3daSRichard Henderson         i = args_ct[nb_oargs + k].sort_index;
5107dd186292SRichard Henderson         arg = op->args[i];
5108501fb3daSRichard Henderson         arg_ct = &args_ct[i];
510943439139SRichard Henderson         ts = arg_temp(arg);
511040ae5c62SRichard Henderson 
511140ae5c62SRichard Henderson         if (ts->val_type == TEMP_VAL_CONST
511221e9a8aeSRichard Henderson             && tcg_target_const_match(ts->val, arg_ct->ct, ts->type,
511321e9a8aeSRichard Henderson                                       op_cond, TCGOP_VECE(op))) {
5114c896fe29Sbellard             /* constant is OK for instruction */
5115c896fe29Sbellard             const_args[i] = 1;
5116c896fe29Sbellard             new_args[i] = ts->val;
5117d62816f2SRichard Henderson             continue;
5118c896fe29Sbellard         }
511940ae5c62SRichard Henderson 
51201c1824dcSRichard Henderson         reg = ts->reg;
51211c1824dcSRichard Henderson         i_preferred_regs = 0;
512229f5e925SRichard Henderson         i_required_regs = arg_ct->regs;
51231c1824dcSRichard Henderson         allocate_new_reg = false;
512429f5e925SRichard Henderson         copyto_new_reg = false;
51251c1824dcSRichard Henderson 
512629f5e925SRichard Henderson         switch (arg_ct->pair) {
512729f5e925SRichard Henderson         case 0: /* not paired */
5128bc2b17e6SRichard Henderson             if (arg_ct->ialias) {
512931fd884bSRichard Henderson                 i_preferred_regs = output_pref(op, arg_ct->alias_index);
5130c0522136SRichard Henderson 
5131c0522136SRichard Henderson                 /*
5132c0522136SRichard Henderson                  * If the input is readonly, then it cannot also be an
5133c0522136SRichard Henderson                  * output and aliased to itself.  If the input is not
5134c0522136SRichard Henderson                  * dead after the instruction, we must allocate a new
5135c0522136SRichard Henderson                  * register and move it.
5136c0522136SRichard Henderson                  */
513722d2e535SIlya Leoshkevich                 if (temp_readonly(ts) || !IS_DEAD_ARG(i)
5138501fb3daSRichard Henderson                     || args_ct[arg_ct->alias_index].newreg) {
51391c1824dcSRichard Henderson                     allocate_new_reg = true;
51401c1824dcSRichard Henderson                 } else if (ts->val_type == TEMP_VAL_REG) {
5141c0522136SRichard Henderson                     /*
51421c1824dcSRichard Henderson                      * Check if the current register has already been
51431c1824dcSRichard Henderson                      * allocated for another input.
5144c0522136SRichard Henderson                      */
514529f5e925SRichard Henderson                     allocate_new_reg =
514629f5e925SRichard Henderson                         tcg_regset_test_reg(i_allocated_regs, reg);
51477e1df267SAurelien Jarno                 }
51487e1df267SAurelien Jarno             }
51491c1824dcSRichard Henderson             if (!allocate_new_reg) {
515029f5e925SRichard Henderson                 temp_load(s, ts, i_required_regs, i_allocated_regs,
515129f5e925SRichard Henderson                           i_preferred_regs);
5152c896fe29Sbellard                 reg = ts->reg;
515329f5e925SRichard Henderson                 allocate_new_reg = !tcg_regset_test_reg(i_required_regs, reg);
51541c1824dcSRichard Henderson             }
51551c1824dcSRichard Henderson             if (allocate_new_reg) {
5156c0522136SRichard Henderson                 /*
5157c0522136SRichard Henderson                  * Allocate a new register matching the constraint
5158c0522136SRichard Henderson                  * and move the temporary register into it.
5159c0522136SRichard Henderson                  */
5160d62816f2SRichard Henderson                 temp_load(s, ts, tcg_target_available_regs[ts->type],
5161d62816f2SRichard Henderson                           i_allocated_regs, 0);
516229f5e925SRichard Henderson                 reg = tcg_reg_alloc(s, i_required_regs, i_allocated_regs,
51631c1824dcSRichard Henderson                                     i_preferred_regs, ts->indirect_base);
516429f5e925SRichard Henderson                 copyto_new_reg = true;
516529f5e925SRichard Henderson             }
516629f5e925SRichard Henderson             break;
516729f5e925SRichard Henderson 
516829f5e925SRichard Henderson         case 1:
516929f5e925SRichard Henderson             /* First of an input pair; if i1 == i2, the second is an output. */
517029f5e925SRichard Henderson             i1 = i;
517129f5e925SRichard Henderson             i2 = arg_ct->pair_index;
517229f5e925SRichard Henderson             ts2 = i1 != i2 ? arg_temp(op->args[i2]) : NULL;
517329f5e925SRichard Henderson 
517429f5e925SRichard Henderson             /*
517529f5e925SRichard Henderson              * It is easier to default to allocating a new pair
517629f5e925SRichard Henderson              * and to identify a few cases where it's not required.
517729f5e925SRichard Henderson              */
517829f5e925SRichard Henderson             if (arg_ct->ialias) {
517931fd884bSRichard Henderson                 i_preferred_regs = output_pref(op, arg_ct->alias_index);
518029f5e925SRichard Henderson                 if (IS_DEAD_ARG(i1) &&
518129f5e925SRichard Henderson                     IS_DEAD_ARG(i2) &&
518229f5e925SRichard Henderson                     !temp_readonly(ts) &&
518329f5e925SRichard Henderson                     ts->val_type == TEMP_VAL_REG &&
518429f5e925SRichard Henderson                     ts->reg < TCG_TARGET_NB_REGS - 1 &&
518529f5e925SRichard Henderson                     tcg_regset_test_reg(i_required_regs, reg) &&
518629f5e925SRichard Henderson                     !tcg_regset_test_reg(i_allocated_regs, reg) &&
518729f5e925SRichard Henderson                     !tcg_regset_test_reg(i_allocated_regs, reg + 1) &&
518829f5e925SRichard Henderson                     (ts2
518929f5e925SRichard Henderson                      ? ts2->val_type == TEMP_VAL_REG &&
519029f5e925SRichard Henderson                        ts2->reg == reg + 1 &&
519129f5e925SRichard Henderson                        !temp_readonly(ts2)
519229f5e925SRichard Henderson                      : s->reg_to_temp[reg + 1] == NULL)) {
519329f5e925SRichard Henderson                     break;
519429f5e925SRichard Henderson                 }
519529f5e925SRichard Henderson             } else {
519629f5e925SRichard Henderson                 /* Without aliasing, the pair must also be an input. */
519729f5e925SRichard Henderson                 tcg_debug_assert(ts2);
519829f5e925SRichard Henderson                 if (ts->val_type == TEMP_VAL_REG &&
519929f5e925SRichard Henderson                     ts2->val_type == TEMP_VAL_REG &&
520029f5e925SRichard Henderson                     ts2->reg == reg + 1 &&
520129f5e925SRichard Henderson                     tcg_regset_test_reg(i_required_regs, reg)) {
520229f5e925SRichard Henderson                     break;
520329f5e925SRichard Henderson                 }
520429f5e925SRichard Henderson             }
520529f5e925SRichard Henderson             reg = tcg_reg_alloc_pair(s, i_required_regs, i_allocated_regs,
520629f5e925SRichard Henderson                                      0, ts->indirect_base);
520729f5e925SRichard Henderson             goto do_pair;
520829f5e925SRichard Henderson 
520929f5e925SRichard Henderson         case 2: /* pair second */
521029f5e925SRichard Henderson             reg = new_args[arg_ct->pair_index] + 1;
521129f5e925SRichard Henderson             goto do_pair;
521229f5e925SRichard Henderson 
521329f5e925SRichard Henderson         case 3: /* ialias with second output, no first input */
521429f5e925SRichard Henderson             tcg_debug_assert(arg_ct->ialias);
521531fd884bSRichard Henderson             i_preferred_regs = output_pref(op, arg_ct->alias_index);
521629f5e925SRichard Henderson 
521729f5e925SRichard Henderson             if (IS_DEAD_ARG(i) &&
521829f5e925SRichard Henderson                 !temp_readonly(ts) &&
521929f5e925SRichard Henderson                 ts->val_type == TEMP_VAL_REG &&
522029f5e925SRichard Henderson                 reg > 0 &&
522129f5e925SRichard Henderson                 s->reg_to_temp[reg - 1] == NULL &&
522229f5e925SRichard Henderson                 tcg_regset_test_reg(i_required_regs, reg) &&
522329f5e925SRichard Henderson                 !tcg_regset_test_reg(i_allocated_regs, reg) &&
522429f5e925SRichard Henderson                 !tcg_regset_test_reg(i_allocated_regs, reg - 1)) {
522529f5e925SRichard Henderson                 tcg_regset_set_reg(i_allocated_regs, reg - 1);
522629f5e925SRichard Henderson                 break;
522729f5e925SRichard Henderson             }
522829f5e925SRichard Henderson             reg = tcg_reg_alloc_pair(s, i_required_regs >> 1,
522929f5e925SRichard Henderson                                      i_allocated_regs, 0,
523029f5e925SRichard Henderson                                      ts->indirect_base);
523129f5e925SRichard Henderson             tcg_regset_set_reg(i_allocated_regs, reg);
523229f5e925SRichard Henderson             reg += 1;
523329f5e925SRichard Henderson             goto do_pair;
523429f5e925SRichard Henderson 
523529f5e925SRichard Henderson         do_pair:
523629f5e925SRichard Henderson             /*
523729f5e925SRichard Henderson              * If an aliased input is not dead after the instruction,
523829f5e925SRichard Henderson              * we must allocate a new register and move it.
523929f5e925SRichard Henderson              */
524029f5e925SRichard Henderson             if (arg_ct->ialias && (!IS_DEAD_ARG(i) || temp_readonly(ts))) {
524129f5e925SRichard Henderson                 TCGRegSet t_allocated_regs = i_allocated_regs;
524229f5e925SRichard Henderson 
524329f5e925SRichard Henderson                 /*
524429f5e925SRichard Henderson                  * Because of the alias, and the continued life, make sure
524529f5e925SRichard Henderson                  * that the temp is somewhere *other* than the reg pair,
524629f5e925SRichard Henderson                  * and we get a copy in reg.
524729f5e925SRichard Henderson                  */
524829f5e925SRichard Henderson                 tcg_regset_set_reg(t_allocated_regs, reg);
524929f5e925SRichard Henderson                 tcg_regset_set_reg(t_allocated_regs, reg + 1);
525029f5e925SRichard Henderson                 if (ts->val_type == TEMP_VAL_REG && ts->reg == reg) {
525129f5e925SRichard Henderson                     /* If ts was already in reg, copy it somewhere else. */
525229f5e925SRichard Henderson                     TCGReg nr;
525329f5e925SRichard Henderson                     bool ok;
525429f5e925SRichard Henderson 
525529f5e925SRichard Henderson                     tcg_debug_assert(ts->kind != TEMP_FIXED);
525629f5e925SRichard Henderson                     nr = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
525729f5e925SRichard Henderson                                        t_allocated_regs, 0, ts->indirect_base);
525829f5e925SRichard Henderson                     ok = tcg_out_mov(s, ts->type, nr, reg);
525929f5e925SRichard Henderson                     tcg_debug_assert(ok);
526029f5e925SRichard Henderson 
526129f5e925SRichard Henderson                     set_temp_val_reg(s, ts, nr);
526229f5e925SRichard Henderson                 } else {
526329f5e925SRichard Henderson                     temp_load(s, ts, tcg_target_available_regs[ts->type],
526429f5e925SRichard Henderson                               t_allocated_regs, 0);
526529f5e925SRichard Henderson                     copyto_new_reg = true;
526629f5e925SRichard Henderson                 }
526729f5e925SRichard Henderson             } else {
526829f5e925SRichard Henderson                 /* Preferably allocate to reg, otherwise copy. */
526929f5e925SRichard Henderson                 i_required_regs = (TCGRegSet)1 << reg;
527029f5e925SRichard Henderson                 temp_load(s, ts, i_required_regs, i_allocated_regs,
527129f5e925SRichard Henderson                           i_preferred_regs);
527229f5e925SRichard Henderson                 copyto_new_reg = ts->reg != reg;
527329f5e925SRichard Henderson             }
527429f5e925SRichard Henderson             break;
527529f5e925SRichard Henderson 
527629f5e925SRichard Henderson         default:
527729f5e925SRichard Henderson             g_assert_not_reached();
527829f5e925SRichard Henderson         }
527929f5e925SRichard Henderson 
528029f5e925SRichard Henderson         if (copyto_new_reg) {
528178113e83SRichard Henderson             if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
5282240c08d0SRichard Henderson                 /*
5283240c08d0SRichard Henderson                  * Cross register class move not supported.  Sync the
5284240c08d0SRichard Henderson                  * temp back to its slot and load from there.
5285240c08d0SRichard Henderson                  */
5286240c08d0SRichard Henderson                 temp_sync(s, ts, i_allocated_regs, 0, 0);
5287240c08d0SRichard Henderson                 tcg_out_ld(s, ts->type, reg,
5288240c08d0SRichard Henderson                            ts->mem_base->reg, ts->mem_offset);
528978113e83SRichard Henderson             }
5290c896fe29Sbellard         }
5291c896fe29Sbellard         new_args[i] = reg;
5292c896fe29Sbellard         const_args[i] = 0;
529382790a87SRichard Henderson         tcg_regset_set_reg(i_allocated_regs, reg);
5294c896fe29Sbellard     }
5295c896fe29Sbellard 
5296c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
5297866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
5298866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
529943439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
5300c896fe29Sbellard         }
5301c896fe29Sbellard     }
5302c896fe29Sbellard 
5303b4cb76e6SRichard Henderson     if (def->flags & TCG_OPF_COND_BRANCH) {
5304b4cb76e6SRichard Henderson         tcg_reg_alloc_cbranch(s, i_allocated_regs);
5305b4cb76e6SRichard Henderson     } else if (def->flags & TCG_OPF_BB_END) {
530682790a87SRichard Henderson         tcg_reg_alloc_bb_end(s, i_allocated_regs);
5307a52ad07eSAurelien Jarno     } else {
5308c896fe29Sbellard         if (def->flags & TCG_OPF_CALL_CLOBBER) {
5309b03cce8eSbellard             /* XXX: permit generic clobber register list ? */
5310c8074023SRichard Henderson             for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
5311c8074023SRichard Henderson                 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
531282790a87SRichard Henderson                     tcg_reg_free(s, i, i_allocated_regs);
5313c896fe29Sbellard                 }
5314c896fe29Sbellard             }
53153d5c5f87SAurelien Jarno         }
53163d5c5f87SAurelien Jarno         if (def->flags & TCG_OPF_SIDE_EFFECTS) {
53173d5c5f87SAurelien Jarno             /* sync globals if the op has side effects and might trigger
53183d5c5f87SAurelien Jarno                an exception. */
531982790a87SRichard Henderson             sync_globals(s, i_allocated_regs);
5320c896fe29Sbellard         }
5321c896fe29Sbellard 
5322c896fe29Sbellard         /* satisfy the output constraints */
5323c896fe29Sbellard         for (k = 0; k < nb_oargs; k++) {
5324501fb3daSRichard Henderson             i = args_ct[k].sort_index;
5325dd186292SRichard Henderson             arg = op->args[i];
5326501fb3daSRichard Henderson             arg_ct = &args_ct[i];
532743439139SRichard Henderson             ts = arg_temp(arg);
5328d63e3b6eSRichard Henderson 
5329d63e3b6eSRichard Henderson             /* ENV should not be modified.  */
5330e01fa97dSRichard Henderson             tcg_debug_assert(!temp_readonly(ts));
5331d63e3b6eSRichard Henderson 
533229f5e925SRichard Henderson             switch (arg_ct->pair) {
533329f5e925SRichard Henderson             case 0: /* not paired */
5334bc2b17e6SRichard Henderson                 if (arg_ct->oalias && !const_args[arg_ct->alias_index]) {
53355ff9d6a4Sbellard                     reg = new_args[arg_ct->alias_index];
5336bc2b17e6SRichard Henderson                 } else if (arg_ct->newreg) {
53379be0d080SRichard Henderson                     reg = tcg_reg_alloc(s, arg_ct->regs,
533882790a87SRichard Henderson                                         i_allocated_regs | o_allocated_regs,
533931fd884bSRichard Henderson                                         output_pref(op, k), ts->indirect_base);
5340c896fe29Sbellard                 } else {
53419be0d080SRichard Henderson                     reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs,
534231fd884bSRichard Henderson                                         output_pref(op, k), ts->indirect_base);
5343c896fe29Sbellard                 }
534429f5e925SRichard Henderson                 break;
534529f5e925SRichard Henderson 
534629f5e925SRichard Henderson             case 1: /* first of pair */
534729f5e925SRichard Henderson                 if (arg_ct->oalias) {
534829f5e925SRichard Henderson                     reg = new_args[arg_ct->alias_index];
5349ca5bed07SRichard Henderson                 } else if (arg_ct->newreg) {
5350ca5bed07SRichard Henderson                     reg = tcg_reg_alloc_pair(s, arg_ct->regs,
5351ca5bed07SRichard Henderson                                              i_allocated_regs | o_allocated_regs,
5352ca5bed07SRichard Henderson                                              output_pref(op, k),
5353ca5bed07SRichard Henderson                                              ts->indirect_base);
5354ca5bed07SRichard Henderson                 } else {
535529f5e925SRichard Henderson                     reg = tcg_reg_alloc_pair(s, arg_ct->regs, o_allocated_regs,
5356ca5bed07SRichard Henderson                                              output_pref(op, k),
5357ca5bed07SRichard Henderson                                              ts->indirect_base);
5358ca5bed07SRichard Henderson                 }
535929f5e925SRichard Henderson                 break;
536029f5e925SRichard Henderson 
536129f5e925SRichard Henderson             case 2: /* second of pair */
536229f5e925SRichard Henderson                 if (arg_ct->oalias) {
536329f5e925SRichard Henderson                     reg = new_args[arg_ct->alias_index];
536429f5e925SRichard Henderson                 } else {
536529f5e925SRichard Henderson                     reg = new_args[arg_ct->pair_index] + 1;
536629f5e925SRichard Henderson                 }
536729f5e925SRichard Henderson                 break;
536829f5e925SRichard Henderson 
536929f5e925SRichard Henderson             case 3: /* first of pair, aliasing with a second input */
537029f5e925SRichard Henderson                 tcg_debug_assert(!arg_ct->newreg);
537129f5e925SRichard Henderson                 reg = new_args[arg_ct->pair_index] - 1;
537229f5e925SRichard Henderson                 break;
537329f5e925SRichard Henderson 
537429f5e925SRichard Henderson             default:
537529f5e925SRichard Henderson                 g_assert_not_reached();
537629f5e925SRichard Henderson             }
537782790a87SRichard Henderson             tcg_regset_set_reg(o_allocated_regs, reg);
5378098859f1SRichard Henderson             set_temp_val_reg(s, ts, reg);
5379c896fe29Sbellard             ts->mem_coherent = 0;
5380c896fe29Sbellard             new_args[i] = reg;
5381c896fe29Sbellard         }
5382e8996ee0Sbellard     }
5383c896fe29Sbellard 
5384c896fe29Sbellard     /* emit instruction */
5385678155b2SRichard Henderson     switch (op->opc) {
5386678155b2SRichard Henderson     case INDEX_op_ext8s_i32:
5387678155b2SRichard Henderson         tcg_out_ext8s(s, TCG_TYPE_I32, new_args[0], new_args[1]);
5388678155b2SRichard Henderson         break;
5389678155b2SRichard Henderson     case INDEX_op_ext8s_i64:
5390678155b2SRichard Henderson         tcg_out_ext8s(s, TCG_TYPE_I64, new_args[0], new_args[1]);
5391678155b2SRichard Henderson         break;
5392d0e66c89SRichard Henderson     case INDEX_op_ext8u_i32:
5393d0e66c89SRichard Henderson     case INDEX_op_ext8u_i64:
5394d0e66c89SRichard Henderson         tcg_out_ext8u(s, new_args[0], new_args[1]);
5395d0e66c89SRichard Henderson         break;
5396753e42eaSRichard Henderson     case INDEX_op_ext16s_i32:
5397753e42eaSRichard Henderson         tcg_out_ext16s(s, TCG_TYPE_I32, new_args[0], new_args[1]);
5398753e42eaSRichard Henderson         break;
5399753e42eaSRichard Henderson     case INDEX_op_ext16s_i64:
5400753e42eaSRichard Henderson         tcg_out_ext16s(s, TCG_TYPE_I64, new_args[0], new_args[1]);
5401753e42eaSRichard Henderson         break;
5402379afdffSRichard Henderson     case INDEX_op_ext16u_i32:
5403379afdffSRichard Henderson     case INDEX_op_ext16u_i64:
5404379afdffSRichard Henderson         tcg_out_ext16u(s, new_args[0], new_args[1]);
5405379afdffSRichard Henderson         break;
540652bf3398SRichard Henderson     case INDEX_op_ext32s_i64:
540752bf3398SRichard Henderson         tcg_out_ext32s(s, new_args[0], new_args[1]);
540852bf3398SRichard Henderson         break;
54099ecf5f61SRichard Henderson     case INDEX_op_ext32u_i64:
54109ecf5f61SRichard Henderson         tcg_out_ext32u(s, new_args[0], new_args[1]);
54119ecf5f61SRichard Henderson         break;
54129c6aa274SRichard Henderson     case INDEX_op_ext_i32_i64:
54139c6aa274SRichard Henderson         tcg_out_exts_i32_i64(s, new_args[0], new_args[1]);
54149c6aa274SRichard Henderson         break;
5415b9bfe000SRichard Henderson     case INDEX_op_extu_i32_i64:
5416b9bfe000SRichard Henderson         tcg_out_extu_i32_i64(s, new_args[0], new_args[1]);
5417b9bfe000SRichard Henderson         break;
5418b8b94ac6SRichard Henderson     case INDEX_op_extrl_i64_i32:
5419b8b94ac6SRichard Henderson         tcg_out_extrl_i64_i32(s, new_args[0], new_args[1]);
5420b8b94ac6SRichard Henderson         break;
5421678155b2SRichard Henderson     default:
5422d2fd745fSRichard Henderson         if (def->flags & TCG_OPF_VECTOR) {
54234d872218SRichard Henderson             tcg_out_vec_op(s, op->opc, TCGOP_TYPE(op) - TCG_TYPE_V64,
54244d872218SRichard Henderson                            TCGOP_VECE(op), new_args, const_args);
5425d2fd745fSRichard Henderson         } else {
5426*4e350091SRichard Henderson             tcg_out_op(s, op->opc, TCGOP_TYPE(op), new_args, const_args);
5427d2fd745fSRichard Henderson         }
5428678155b2SRichard Henderson         break;
5429678155b2SRichard Henderson     }
5430c896fe29Sbellard 
5431c896fe29Sbellard     /* move the outputs in the correct register if needed */
5432c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
543343439139SRichard Henderson         ts = arg_temp(op->args[i]);
5434d63e3b6eSRichard Henderson 
5435d63e3b6eSRichard Henderson         /* ENV should not be modified.  */
5436e01fa97dSRichard Henderson         tcg_debug_assert(!temp_readonly(ts));
5437d63e3b6eSRichard Henderson 
5438ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
543998b4e186SRichard Henderson             temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i));
544059d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
5441f8bf00f1SRichard Henderson             temp_dead(s, ts);
5442ec7a869dSAurelien Jarno         }
5443c896fe29Sbellard     }
5444c896fe29Sbellard }
5445c896fe29Sbellard 
5446efe86b21SRichard Henderson static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op)
5447efe86b21SRichard Henderson {
5448efe86b21SRichard Henderson     const TCGLifeData arg_life = op->life;
5449efe86b21SRichard Henderson     TCGTemp *ots, *itsl, *itsh;
54504d872218SRichard Henderson     TCGType vtype = TCGOP_TYPE(op);
5451efe86b21SRichard Henderson 
5452efe86b21SRichard Henderson     /* This opcode is only valid for 32-bit hosts, for 64-bit elements. */
5453efe86b21SRichard Henderson     tcg_debug_assert(TCG_TARGET_REG_BITS == 32);
5454efe86b21SRichard Henderson     tcg_debug_assert(TCGOP_VECE(op) == MO_64);
5455efe86b21SRichard Henderson 
5456efe86b21SRichard Henderson     ots = arg_temp(op->args[0]);
5457efe86b21SRichard Henderson     itsl = arg_temp(op->args[1]);
5458efe86b21SRichard Henderson     itsh = arg_temp(op->args[2]);
5459efe86b21SRichard Henderson 
5460efe86b21SRichard Henderson     /* ENV should not be modified.  */
5461efe86b21SRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
5462efe86b21SRichard Henderson 
5463efe86b21SRichard Henderson     /* Allocate the output register now.  */
5464efe86b21SRichard Henderson     if (ots->val_type != TEMP_VAL_REG) {
5465efe86b21SRichard Henderson         TCGRegSet allocated_regs = s->reserved_regs;
5466501fb3daSRichard Henderson         TCGRegSet dup_out_regs = opcode_args_ct(op)[0].regs;
5467098859f1SRichard Henderson         TCGReg oreg;
5468efe86b21SRichard Henderson 
5469efe86b21SRichard Henderson         /* Make sure to not spill the input registers. */
5470efe86b21SRichard Henderson         if (!IS_DEAD_ARG(1) && itsl->val_type == TEMP_VAL_REG) {
5471efe86b21SRichard Henderson             tcg_regset_set_reg(allocated_regs, itsl->reg);
5472efe86b21SRichard Henderson         }
5473efe86b21SRichard Henderson         if (!IS_DEAD_ARG(2) && itsh->val_type == TEMP_VAL_REG) {
5474efe86b21SRichard Henderson             tcg_regset_set_reg(allocated_regs, itsh->reg);
5475efe86b21SRichard Henderson         }
5476efe86b21SRichard Henderson 
5477098859f1SRichard Henderson         oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
547831fd884bSRichard Henderson                              output_pref(op, 0), ots->indirect_base);
5479098859f1SRichard Henderson         set_temp_val_reg(s, ots, oreg);
5480efe86b21SRichard Henderson     }
5481efe86b21SRichard Henderson 
5482efe86b21SRichard Henderson     /* Promote dup2 of immediates to dupi_vec. */
5483efe86b21SRichard Henderson     if (itsl->val_type == TEMP_VAL_CONST && itsh->val_type == TEMP_VAL_CONST) {
5484efe86b21SRichard Henderson         uint64_t val = deposit64(itsl->val, 32, 32, itsh->val);
5485efe86b21SRichard Henderson         MemOp vece = MO_64;
5486efe86b21SRichard Henderson 
5487efe86b21SRichard Henderson         if (val == dup_const(MO_8, val)) {
5488efe86b21SRichard Henderson             vece = MO_8;
5489efe86b21SRichard Henderson         } else if (val == dup_const(MO_16, val)) {
5490efe86b21SRichard Henderson             vece = MO_16;
5491efe86b21SRichard Henderson         } else if (val == dup_const(MO_32, val)) {
5492efe86b21SRichard Henderson             vece = MO_32;
5493efe86b21SRichard Henderson         }
5494efe86b21SRichard Henderson 
5495efe86b21SRichard Henderson         tcg_out_dupi_vec(s, vtype, vece, ots->reg, val);
5496efe86b21SRichard Henderson         goto done;
5497efe86b21SRichard Henderson     }
5498efe86b21SRichard Henderson 
5499efe86b21SRichard Henderson     /* If the two inputs form one 64-bit value, try dupm_vec. */
5500aef85402SRichard Henderson     if (itsl->temp_subindex == HOST_BIG_ENDIAN &&
5501aef85402SRichard Henderson         itsh->temp_subindex == !HOST_BIG_ENDIAN &&
5502aef85402SRichard Henderson         itsl == itsh + (HOST_BIG_ENDIAN ? 1 : -1)) {
5503aef85402SRichard Henderson         TCGTemp *its = itsl - HOST_BIG_ENDIAN;
5504aef85402SRichard Henderson 
5505aef85402SRichard Henderson         temp_sync(s, its + 0, s->reserved_regs, 0, 0);
5506aef85402SRichard Henderson         temp_sync(s, its + 1, s->reserved_regs, 0, 0);
5507aef85402SRichard Henderson 
5508efe86b21SRichard Henderson         if (tcg_out_dupm_vec(s, vtype, MO_64, ots->reg,
5509efe86b21SRichard Henderson                              its->mem_base->reg, its->mem_offset)) {
5510efe86b21SRichard Henderson             goto done;
5511efe86b21SRichard Henderson         }
5512efe86b21SRichard Henderson     }
5513efe86b21SRichard Henderson 
5514efe86b21SRichard Henderson     /* Fall back to generic expansion. */
5515efe86b21SRichard Henderson     return false;
5516efe86b21SRichard Henderson 
5517efe86b21SRichard Henderson  done:
551836f5539cSRichard Henderson     ots->mem_coherent = 0;
5519efe86b21SRichard Henderson     if (IS_DEAD_ARG(1)) {
5520efe86b21SRichard Henderson         temp_dead(s, itsl);
5521efe86b21SRichard Henderson     }
5522efe86b21SRichard Henderson     if (IS_DEAD_ARG(2)) {
5523efe86b21SRichard Henderson         temp_dead(s, itsh);
5524efe86b21SRichard Henderson     }
5525efe86b21SRichard Henderson     if (NEED_SYNC_ARG(0)) {
5526efe86b21SRichard Henderson         temp_sync(s, ots, s->reserved_regs, 0, IS_DEAD_ARG(0));
5527efe86b21SRichard Henderson     } else if (IS_DEAD_ARG(0)) {
5528efe86b21SRichard Henderson         temp_dead(s, ots);
5529efe86b21SRichard Henderson     }
5530efe86b21SRichard Henderson     return true;
5531efe86b21SRichard Henderson }
5532efe86b21SRichard Henderson 
553339004a71SRichard Henderson static void load_arg_reg(TCGContext *s, TCGReg reg, TCGTemp *ts,
553439004a71SRichard Henderson                          TCGRegSet allocated_regs)
5535c896fe29Sbellard {
5536c896fe29Sbellard     if (ts->val_type == TEMP_VAL_REG) {
5537c896fe29Sbellard         if (ts->reg != reg) {
55384250da10SRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
553978113e83SRichard Henderson             if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
5540240c08d0SRichard Henderson                 /*
5541240c08d0SRichard Henderson                  * Cross register class move not supported.  Sync the
5542240c08d0SRichard Henderson                  * temp back to its slot and load from there.
5543240c08d0SRichard Henderson                  */
5544240c08d0SRichard Henderson                 temp_sync(s, ts, allocated_regs, 0, 0);
5545240c08d0SRichard Henderson                 tcg_out_ld(s, ts->type, reg,
5546240c08d0SRichard Henderson                            ts->mem_base->reg, ts->mem_offset);
554778113e83SRichard Henderson             }
5548c896fe29Sbellard         }
5549c896fe29Sbellard     } else {
5550ccb1bb66SRichard Henderson         TCGRegSet arg_set = 0;
555140ae5c62SRichard Henderson 
55524250da10SRichard Henderson         tcg_reg_free(s, reg, allocated_regs);
555340ae5c62SRichard Henderson         tcg_regset_set_reg(arg_set, reg);
5554b722452aSRichard Henderson         temp_load(s, ts, arg_set, allocated_regs, 0);
5555c896fe29Sbellard     }
555639004a71SRichard Henderson }
555740ae5c62SRichard Henderson 
5558d78e4a4fSRichard Henderson static void load_arg_stk(TCGContext *s, unsigned arg_slot, TCGTemp *ts,
555939004a71SRichard Henderson                          TCGRegSet allocated_regs)
556039004a71SRichard Henderson {
556139004a71SRichard Henderson     /*
556239004a71SRichard Henderson      * When the destination is on the stack, load up the temp and store.
556339004a71SRichard Henderson      * If there are many call-saved registers, the temp might live to
556439004a71SRichard Henderson      * see another use; otherwise it'll be discarded.
556539004a71SRichard Henderson      */
556639004a71SRichard Henderson     temp_load(s, ts, tcg_target_available_regs[ts->type], allocated_regs, 0);
556739004a71SRichard Henderson     tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK,
5568d78e4a4fSRichard Henderson                arg_slot_stk_ofs(arg_slot));
556939004a71SRichard Henderson }
557039004a71SRichard Henderson 
557139004a71SRichard Henderson static void load_arg_normal(TCGContext *s, const TCGCallArgumentLoc *l,
557239004a71SRichard Henderson                             TCGTemp *ts, TCGRegSet *allocated_regs)
557339004a71SRichard Henderson {
5574338b61e9SRichard Henderson     if (arg_slot_reg_p(l->arg_slot)) {
557539004a71SRichard Henderson         TCGReg reg = tcg_target_call_iarg_regs[l->arg_slot];
557639004a71SRichard Henderson         load_arg_reg(s, reg, ts, *allocated_regs);
557739004a71SRichard Henderson         tcg_regset_set_reg(*allocated_regs, reg);
557839004a71SRichard Henderson     } else {
5579d78e4a4fSRichard Henderson         load_arg_stk(s, l->arg_slot, ts, *allocated_regs);
5580c896fe29Sbellard     }
558139cf05d3Sbellard }
5582c896fe29Sbellard 
5583d78e4a4fSRichard Henderson static void load_arg_ref(TCGContext *s, unsigned arg_slot, TCGReg ref_base,
5584313bdea8SRichard Henderson                          intptr_t ref_off, TCGRegSet *allocated_regs)
5585313bdea8SRichard Henderson {
5586313bdea8SRichard Henderson     TCGReg reg;
5587313bdea8SRichard Henderson 
5588d78e4a4fSRichard Henderson     if (arg_slot_reg_p(arg_slot)) {
5589313bdea8SRichard Henderson         reg = tcg_target_call_iarg_regs[arg_slot];
5590313bdea8SRichard Henderson         tcg_reg_free(s, reg, *allocated_regs);
5591313bdea8SRichard Henderson         tcg_out_addi_ptr(s, reg, ref_base, ref_off);
5592313bdea8SRichard Henderson         tcg_regset_set_reg(*allocated_regs, reg);
5593313bdea8SRichard Henderson     } else {
5594313bdea8SRichard Henderson         reg = tcg_reg_alloc(s, tcg_target_available_regs[TCG_TYPE_PTR],
5595313bdea8SRichard Henderson                             *allocated_regs, 0, false);
5596313bdea8SRichard Henderson         tcg_out_addi_ptr(s, reg, ref_base, ref_off);
5597313bdea8SRichard Henderson         tcg_out_st(s, TCG_TYPE_PTR, reg, TCG_REG_CALL_STACK,
5598d78e4a4fSRichard Henderson                    arg_slot_stk_ofs(arg_slot));
5599313bdea8SRichard Henderson     }
5600313bdea8SRichard Henderson }
5601313bdea8SRichard Henderson 
560239004a71SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op)
560339004a71SRichard Henderson {
560439004a71SRichard Henderson     const int nb_oargs = TCGOP_CALLO(op);
560539004a71SRichard Henderson     const int nb_iargs = TCGOP_CALLI(op);
560639004a71SRichard Henderson     const TCGLifeData arg_life = op->life;
560739004a71SRichard Henderson     const TCGHelperInfo *info = tcg_call_info(op);
560839004a71SRichard Henderson     TCGRegSet allocated_regs = s->reserved_regs;
560939004a71SRichard Henderson     int i;
561039004a71SRichard Henderson 
561139004a71SRichard Henderson     /*
561239004a71SRichard Henderson      * Move inputs into place in reverse order,
561339004a71SRichard Henderson      * so that we place stacked arguments first.
561439004a71SRichard Henderson      */
561539004a71SRichard Henderson     for (i = nb_iargs - 1; i >= 0; --i) {
561639004a71SRichard Henderson         const TCGCallArgumentLoc *loc = &info->in[i];
561739004a71SRichard Henderson         TCGTemp *ts = arg_temp(op->args[nb_oargs + i]);
561839004a71SRichard Henderson 
561939004a71SRichard Henderson         switch (loc->kind) {
562039004a71SRichard Henderson         case TCG_CALL_ARG_NORMAL:
562139004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_U:
562239004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_S:
562339004a71SRichard Henderson             load_arg_normal(s, loc, ts, &allocated_regs);
562439004a71SRichard Henderson             break;
5625313bdea8SRichard Henderson         case TCG_CALL_ARG_BY_REF:
5626313bdea8SRichard Henderson             load_arg_stk(s, loc->ref_slot, ts, allocated_regs);
5627313bdea8SRichard Henderson             load_arg_ref(s, loc->arg_slot, TCG_REG_CALL_STACK,
5628d78e4a4fSRichard Henderson                          arg_slot_stk_ofs(loc->ref_slot),
5629313bdea8SRichard Henderson                          &allocated_regs);
5630313bdea8SRichard Henderson             break;
5631313bdea8SRichard Henderson         case TCG_CALL_ARG_BY_REF_N:
5632313bdea8SRichard Henderson             load_arg_stk(s, loc->ref_slot, ts, allocated_regs);
5633313bdea8SRichard Henderson             break;
563439004a71SRichard Henderson         default:
563539004a71SRichard Henderson             g_assert_not_reached();
563639004a71SRichard Henderson         }
563739004a71SRichard Henderson     }
563839004a71SRichard Henderson 
563939004a71SRichard Henderson     /* Mark dead temporaries and free the associated registers.  */
5640866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
5641866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
564243439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
5643c896fe29Sbellard         }
5644c896fe29Sbellard     }
5645c896fe29Sbellard 
564639004a71SRichard Henderson     /* Clobber call registers.  */
5647c8074023SRichard Henderson     for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
5648c8074023SRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
5649b3915dbbSRichard Henderson             tcg_reg_free(s, i, allocated_regs);
5650c896fe29Sbellard         }
5651c896fe29Sbellard     }
5652c896fe29Sbellard 
565339004a71SRichard Henderson     /*
565439004a71SRichard Henderson      * Save globals if they might be written by the helper,
565539004a71SRichard Henderson      * sync them if they might be read.
565639004a71SRichard Henderson      */
565739004a71SRichard Henderson     if (info->flags & TCG_CALL_NO_READ_GLOBALS) {
565878505279SAurelien Jarno         /* Nothing to do */
565939004a71SRichard Henderson     } else if (info->flags & TCG_CALL_NO_WRITE_GLOBALS) {
566078505279SAurelien Jarno         sync_globals(s, allocated_regs);
566178505279SAurelien Jarno     } else {
5662e8996ee0Sbellard         save_globals(s, allocated_regs);
5663b9c18f56Saurel32     }
5664c896fe29Sbellard 
5665313bdea8SRichard Henderson     /*
5666313bdea8SRichard Henderson      * If the ABI passes a pointer to the returned struct as the first
5667313bdea8SRichard Henderson      * argument, load that now.  Pass a pointer to the output home slot.
5668313bdea8SRichard Henderson      */
5669313bdea8SRichard Henderson     if (info->out_kind == TCG_CALL_RET_BY_REF) {
5670313bdea8SRichard Henderson         TCGTemp *ts = arg_temp(op->args[0]);
5671313bdea8SRichard Henderson 
5672313bdea8SRichard Henderson         if (!ts->mem_allocated) {
5673313bdea8SRichard Henderson             temp_allocate_frame(s, ts);
5674313bdea8SRichard Henderson         }
5675313bdea8SRichard Henderson         load_arg_ref(s, 0, ts->mem_base->reg, ts->mem_offset, &allocated_regs);
5676313bdea8SRichard Henderson     }
5677313bdea8SRichard Henderson 
5678cee44b03SRichard Henderson     tcg_out_call(s, tcg_call_func(op), info);
5679c896fe29Sbellard 
568039004a71SRichard Henderson     /* Assign output registers and emit moves if needed.  */
568139004a71SRichard Henderson     switch (info->out_kind) {
568239004a71SRichard Henderson     case TCG_CALL_RET_NORMAL:
5683c896fe29Sbellard         for (i = 0; i < nb_oargs; i++) {
568439004a71SRichard Henderson             TCGTemp *ts = arg_temp(op->args[i]);
56855e3d0c19SRichard Henderson             TCGReg reg = tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, i);
5686d63e3b6eSRichard Henderson 
5687d63e3b6eSRichard Henderson             /* ENV should not be modified.  */
5688e01fa97dSRichard Henderson             tcg_debug_assert(!temp_readonly(ts));
5689d63e3b6eSRichard Henderson 
5690098859f1SRichard Henderson             set_temp_val_reg(s, ts, reg);
5691c896fe29Sbellard             ts->mem_coherent = 0;
569239004a71SRichard Henderson         }
569339004a71SRichard Henderson         break;
5694313bdea8SRichard Henderson 
5695c6556aa0SRichard Henderson     case TCG_CALL_RET_BY_VEC:
5696c6556aa0SRichard Henderson         {
5697c6556aa0SRichard Henderson             TCGTemp *ts = arg_temp(op->args[0]);
5698c6556aa0SRichard Henderson 
5699c6556aa0SRichard Henderson             tcg_debug_assert(ts->base_type == TCG_TYPE_I128);
5700c6556aa0SRichard Henderson             tcg_debug_assert(ts->temp_subindex == 0);
5701c6556aa0SRichard Henderson             if (!ts->mem_allocated) {
5702c6556aa0SRichard Henderson                 temp_allocate_frame(s, ts);
5703c6556aa0SRichard Henderson             }
5704c6556aa0SRichard Henderson             tcg_out_st(s, TCG_TYPE_V128,
5705c6556aa0SRichard Henderson                        tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0),
5706c6556aa0SRichard Henderson                        ts->mem_base->reg, ts->mem_offset);
5707c6556aa0SRichard Henderson         }
5708c6556aa0SRichard Henderson         /* fall through to mark all parts in memory */
5709c6556aa0SRichard Henderson 
5710313bdea8SRichard Henderson     case TCG_CALL_RET_BY_REF:
5711313bdea8SRichard Henderson         /* The callee has performed a write through the reference. */
5712313bdea8SRichard Henderson         for (i = 0; i < nb_oargs; i++) {
5713313bdea8SRichard Henderson             TCGTemp *ts = arg_temp(op->args[i]);
5714313bdea8SRichard Henderson             ts->val_type = TEMP_VAL_MEM;
5715313bdea8SRichard Henderson         }
5716313bdea8SRichard Henderson         break;
5717313bdea8SRichard Henderson 
571839004a71SRichard Henderson     default:
571939004a71SRichard Henderson         g_assert_not_reached();
572039004a71SRichard Henderson     }
572139004a71SRichard Henderson 
572239004a71SRichard Henderson     /* Flush or discard output registers as needed. */
572339004a71SRichard Henderson     for (i = 0; i < nb_oargs; i++) {
572439004a71SRichard Henderson         TCGTemp *ts = arg_temp(op->args[i]);
5725ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
572639004a71SRichard Henderson             temp_sync(s, ts, s->reserved_regs, 0, IS_DEAD_ARG(i));
572759d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
5728f8bf00f1SRichard Henderson             temp_dead(s, ts);
5729c896fe29Sbellard         }
5730c896fe29Sbellard     }
57318c11ad25SAurelien Jarno }
5732c896fe29Sbellard 
5733e63b8a29SRichard Henderson /**
5734e63b8a29SRichard Henderson  * atom_and_align_for_opc:
5735e63b8a29SRichard Henderson  * @s: tcg context
5736e63b8a29SRichard Henderson  * @opc: memory operation code
5737e63b8a29SRichard Henderson  * @host_atom: MO_ATOM_{IFALIGN,WITHIN16,SUBALIGN} for host operations
5738e63b8a29SRichard Henderson  * @allow_two_ops: true if we are prepared to issue two operations
5739e63b8a29SRichard Henderson  *
5740e63b8a29SRichard Henderson  * Return the alignment and atomicity to use for the inline fast path
5741e63b8a29SRichard Henderson  * for the given memory operation.  The alignment may be larger than
5742e63b8a29SRichard Henderson  * that specified in @opc, and the correct alignment will be diagnosed
5743e63b8a29SRichard Henderson  * by the slow path helper.
5744e63b8a29SRichard Henderson  *
5745e63b8a29SRichard Henderson  * If @allow_two_ops, the host is prepared to test for 2x alignment,
5746e63b8a29SRichard Henderson  * and issue two loads or stores for subalignment.
5747e63b8a29SRichard Henderson  */
5748e63b8a29SRichard Henderson static TCGAtomAlign atom_and_align_for_opc(TCGContext *s, MemOp opc,
5749e63b8a29SRichard Henderson                                            MemOp host_atom, bool allow_two_ops)
5750e63b8a29SRichard Henderson {
5751c5809eeeSRichard Henderson     MemOp align = memop_alignment_bits(opc);
5752e63b8a29SRichard Henderson     MemOp size = opc & MO_SIZE;
5753e63b8a29SRichard Henderson     MemOp half = size ? size - 1 : 0;
5754cbb14556SRichard Henderson     MemOp atom = opc & MO_ATOM_MASK;
5755e63b8a29SRichard Henderson     MemOp atmax;
5756e63b8a29SRichard Henderson 
5757e63b8a29SRichard Henderson     switch (atom) {
5758e63b8a29SRichard Henderson     case MO_ATOM_NONE:
5759e63b8a29SRichard Henderson         /* The operation requires no specific atomicity. */
5760e63b8a29SRichard Henderson         atmax = MO_8;
5761e63b8a29SRichard Henderson         break;
5762e63b8a29SRichard Henderson 
5763e63b8a29SRichard Henderson     case MO_ATOM_IFALIGN:
5764e63b8a29SRichard Henderson         atmax = size;
5765e63b8a29SRichard Henderson         break;
5766e63b8a29SRichard Henderson 
5767e63b8a29SRichard Henderson     case MO_ATOM_IFALIGN_PAIR:
5768e63b8a29SRichard Henderson         atmax = half;
5769e63b8a29SRichard Henderson         break;
5770e63b8a29SRichard Henderson 
5771e63b8a29SRichard Henderson     case MO_ATOM_WITHIN16:
5772e63b8a29SRichard Henderson         atmax = size;
5773e63b8a29SRichard Henderson         if (size == MO_128) {
5774e63b8a29SRichard Henderson             /* Misalignment implies !within16, and therefore no atomicity. */
5775e63b8a29SRichard Henderson         } else if (host_atom != MO_ATOM_WITHIN16) {
5776e63b8a29SRichard Henderson             /* The host does not implement within16, so require alignment. */
5777e63b8a29SRichard Henderson             align = MAX(align, size);
5778e63b8a29SRichard Henderson         }
5779e63b8a29SRichard Henderson         break;
5780e63b8a29SRichard Henderson 
5781e63b8a29SRichard Henderson     case MO_ATOM_WITHIN16_PAIR:
5782e63b8a29SRichard Henderson         atmax = size;
5783e63b8a29SRichard Henderson         /*
5784e63b8a29SRichard Henderson          * Misalignment implies !within16, and therefore half atomicity.
5785e63b8a29SRichard Henderson          * Any host prepared for two operations can implement this with
5786e63b8a29SRichard Henderson          * half alignment.
5787e63b8a29SRichard Henderson          */
5788e63b8a29SRichard Henderson         if (host_atom != MO_ATOM_WITHIN16 && allow_two_ops) {
5789e63b8a29SRichard Henderson             align = MAX(align, half);
5790e63b8a29SRichard Henderson         }
5791e63b8a29SRichard Henderson         break;
5792e63b8a29SRichard Henderson 
5793e63b8a29SRichard Henderson     case MO_ATOM_SUBALIGN:
5794e63b8a29SRichard Henderson         atmax = size;
5795e63b8a29SRichard Henderson         if (host_atom != MO_ATOM_SUBALIGN) {
5796e63b8a29SRichard Henderson             /* If unaligned but not odd, there are subobjects up to half. */
5797e63b8a29SRichard Henderson             if (allow_two_ops) {
5798e63b8a29SRichard Henderson                 align = MAX(align, half);
5799e63b8a29SRichard Henderson             } else {
5800e63b8a29SRichard Henderson                 align = MAX(align, size);
5801e63b8a29SRichard Henderson             }
5802e63b8a29SRichard Henderson         }
5803e63b8a29SRichard Henderson         break;
5804e63b8a29SRichard Henderson 
5805e63b8a29SRichard Henderson     default:
5806e63b8a29SRichard Henderson         g_assert_not_reached();
5807e63b8a29SRichard Henderson     }
5808e63b8a29SRichard Henderson 
5809e63b8a29SRichard Henderson     return (TCGAtomAlign){ .atom = atmax, .align = align };
5810e63b8a29SRichard Henderson }
5811e63b8a29SRichard Henderson 
58128429a1caSRichard Henderson /*
58138429a1caSRichard Henderson  * Similarly for qemu_ld/st slow path helpers.
58148429a1caSRichard Henderson  * We must re-implement tcg_gen_callN and tcg_reg_alloc_call simultaneously,
58158429a1caSRichard Henderson  * using only the provided backend tcg_out_* functions.
58168429a1caSRichard Henderson  */
58178429a1caSRichard Henderson 
58188429a1caSRichard Henderson static int tcg_out_helper_stk_ofs(TCGType type, unsigned slot)
58198429a1caSRichard Henderson {
58208429a1caSRichard Henderson     int ofs = arg_slot_stk_ofs(slot);
58218429a1caSRichard Henderson 
58228429a1caSRichard Henderson     /*
58238429a1caSRichard Henderson      * Each stack slot is TCG_TARGET_LONG_BITS.  If the host does not
58248429a1caSRichard Henderson      * require extension to uint64_t, adjust the address for uint32_t.
58258429a1caSRichard Henderson      */
58268429a1caSRichard Henderson     if (HOST_BIG_ENDIAN &&
58278429a1caSRichard Henderson         TCG_TARGET_REG_BITS == 64 &&
58288429a1caSRichard Henderson         type == TCG_TYPE_I32) {
58298429a1caSRichard Henderson         ofs += 4;
58308429a1caSRichard Henderson     }
58318429a1caSRichard Henderson     return ofs;
58328429a1caSRichard Henderson }
58338429a1caSRichard Henderson 
58348d314041SRichard Henderson static void tcg_out_helper_load_slots(TCGContext *s,
58358429a1caSRichard Henderson                                       unsigned nmov, TCGMovExtend *mov,
58362462e30eSRichard Henderson                                       const TCGLdstHelperParam *parm)
58378429a1caSRichard Henderson {
58388d314041SRichard Henderson     unsigned i;
58392462e30eSRichard Henderson     TCGReg dst3;
58402462e30eSRichard Henderson 
58418d314041SRichard Henderson     /*
58428d314041SRichard Henderson      * Start from the end, storing to the stack first.
58438d314041SRichard Henderson      * This frees those registers, so we need not consider overlap.
58448d314041SRichard Henderson      */
58458d314041SRichard Henderson     for (i = nmov; i-- > 0; ) {
58468d314041SRichard Henderson         unsigned slot = mov[i].dst;
58478d314041SRichard Henderson 
58488d314041SRichard Henderson         if (arg_slot_reg_p(slot)) {
58498d314041SRichard Henderson             goto found_reg;
58508d314041SRichard Henderson         }
58518d314041SRichard Henderson 
58528d314041SRichard Henderson         TCGReg src = mov[i].src;
58538d314041SRichard Henderson         TCGType dst_type = mov[i].dst_type;
58548d314041SRichard Henderson         MemOp dst_mo = dst_type == TCG_TYPE_I32 ? MO_32 : MO_64;
58558d314041SRichard Henderson 
58568d314041SRichard Henderson         /* The argument is going onto the stack; extend into scratch. */
58578d314041SRichard Henderson         if ((mov[i].src_ext & MO_SIZE) != dst_mo) {
58588d314041SRichard Henderson             tcg_debug_assert(parm->ntmp != 0);
58598d314041SRichard Henderson             mov[i].dst = src = parm->tmp[0];
58608d314041SRichard Henderson             tcg_out_movext1(s, &mov[i]);
58618d314041SRichard Henderson         }
58628d314041SRichard Henderson 
58638d314041SRichard Henderson         tcg_out_st(s, dst_type, src, TCG_REG_CALL_STACK,
58648d314041SRichard Henderson                    tcg_out_helper_stk_ofs(dst_type, slot));
58658d314041SRichard Henderson     }
58668d314041SRichard Henderson     return;
58678d314041SRichard Henderson 
58688d314041SRichard Henderson  found_reg:
58698d314041SRichard Henderson     /*
58708d314041SRichard Henderson      * The remaining arguments are in registers.
58718d314041SRichard Henderson      * Convert slot numbers to argument registers.
58728d314041SRichard Henderson      */
58738d314041SRichard Henderson     nmov = i + 1;
58748d314041SRichard Henderson     for (i = 0; i < nmov; ++i) {
58758d314041SRichard Henderson         mov[i].dst = tcg_target_call_iarg_regs[mov[i].dst];
58768d314041SRichard Henderson     }
58778d314041SRichard Henderson 
58788429a1caSRichard Henderson     switch (nmov) {
58792462e30eSRichard Henderson     case 4:
58808429a1caSRichard Henderson         /* The backend must have provided enough temps for the worst case. */
58812462e30eSRichard Henderson         tcg_debug_assert(parm->ntmp >= 2);
58828429a1caSRichard Henderson 
58832462e30eSRichard Henderson         dst3 = mov[3].dst;
58842462e30eSRichard Henderson         for (unsigned j = 0; j < 3; ++j) {
58852462e30eSRichard Henderson             if (dst3 == mov[j].src) {
58868429a1caSRichard Henderson                 /*
58872462e30eSRichard Henderson                  * Conflict. Copy the source to a temporary, perform the
58882462e30eSRichard Henderson                  * remaining moves, then the extension from our scratch
58892462e30eSRichard Henderson                  * on the way out.
58908429a1caSRichard Henderson                  */
58912462e30eSRichard Henderson                 TCGReg scratch = parm->tmp[1];
58928429a1caSRichard Henderson 
58932462e30eSRichard Henderson                 tcg_out_mov(s, mov[3].src_type, scratch, mov[3].src);
58942462e30eSRichard Henderson                 tcg_out_movext3(s, mov, mov + 1, mov + 2, parm->tmp[0]);
58952462e30eSRichard Henderson                 tcg_out_movext1_new_src(s, &mov[3], scratch);
58962462e30eSRichard Henderson                 break;
58978429a1caSRichard Henderson             }
58988429a1caSRichard Henderson         }
58998429a1caSRichard Henderson 
59008429a1caSRichard Henderson         /* No conflicts: perform this move and continue. */
59012462e30eSRichard Henderson         tcg_out_movext1(s, &mov[3]);
59022462e30eSRichard Henderson         /* fall through */
59038429a1caSRichard Henderson 
59042462e30eSRichard Henderson     case 3:
59052462e30eSRichard Henderson         tcg_out_movext3(s, mov, mov + 1, mov + 2,
59062462e30eSRichard Henderson                         parm->ntmp ? parm->tmp[0] : -1);
59072462e30eSRichard Henderson         break;
59088429a1caSRichard Henderson     case 2:
59092462e30eSRichard Henderson         tcg_out_movext2(s, mov, mov + 1,
59102462e30eSRichard Henderson                         parm->ntmp ? parm->tmp[0] : -1);
59112462e30eSRichard Henderson         break;
59128429a1caSRichard Henderson     case 1:
59138429a1caSRichard Henderson         tcg_out_movext1(s, mov);
59142462e30eSRichard Henderson         break;
59152462e30eSRichard Henderson     default:
59168429a1caSRichard Henderson         g_assert_not_reached();
59178429a1caSRichard Henderson     }
59188429a1caSRichard Henderson }
59198429a1caSRichard Henderson 
59208429a1caSRichard Henderson static void tcg_out_helper_load_imm(TCGContext *s, unsigned slot,
59218429a1caSRichard Henderson                                     TCGType type, tcg_target_long imm,
59228429a1caSRichard Henderson                                     const TCGLdstHelperParam *parm)
59238429a1caSRichard Henderson {
59248429a1caSRichard Henderson     if (arg_slot_reg_p(slot)) {
59258429a1caSRichard Henderson         tcg_out_movi(s, type, tcg_target_call_iarg_regs[slot], imm);
59268429a1caSRichard Henderson     } else {
59278429a1caSRichard Henderson         int ofs = tcg_out_helper_stk_ofs(type, slot);
59288429a1caSRichard Henderson         if (!tcg_out_sti(s, type, imm, TCG_REG_CALL_STACK, ofs)) {
59298429a1caSRichard Henderson             tcg_debug_assert(parm->ntmp != 0);
59308429a1caSRichard Henderson             tcg_out_movi(s, type, parm->tmp[0], imm);
59318429a1caSRichard Henderson             tcg_out_st(s, type, parm->tmp[0], TCG_REG_CALL_STACK, ofs);
59328429a1caSRichard Henderson         }
59338429a1caSRichard Henderson     }
59348429a1caSRichard Henderson }
59358429a1caSRichard Henderson 
59368429a1caSRichard Henderson static void tcg_out_helper_load_common_args(TCGContext *s,
59378429a1caSRichard Henderson                                             const TCGLabelQemuLdst *ldst,
59388429a1caSRichard Henderson                                             const TCGLdstHelperParam *parm,
59398429a1caSRichard Henderson                                             const TCGHelperInfo *info,
59408429a1caSRichard Henderson                                             unsigned next_arg)
59418429a1caSRichard Henderson {
59428429a1caSRichard Henderson     TCGMovExtend ptr_mov = {
59438429a1caSRichard Henderson         .dst_type = TCG_TYPE_PTR,
59448429a1caSRichard Henderson         .src_type = TCG_TYPE_PTR,
59458429a1caSRichard Henderson         .src_ext = sizeof(void *) == 4 ? MO_32 : MO_64
59468429a1caSRichard Henderson     };
59478429a1caSRichard Henderson     const TCGCallArgumentLoc *loc = &info->in[0];
59488429a1caSRichard Henderson     TCGType type;
59498429a1caSRichard Henderson     unsigned slot;
59508429a1caSRichard Henderson     tcg_target_ulong imm;
59518429a1caSRichard Henderson 
59528429a1caSRichard Henderson     /*
59538429a1caSRichard Henderson      * Handle env, which is always first.
59548429a1caSRichard Henderson      */
59558429a1caSRichard Henderson     ptr_mov.dst = loc->arg_slot;
59568429a1caSRichard Henderson     ptr_mov.src = TCG_AREG0;
59578429a1caSRichard Henderson     tcg_out_helper_load_slots(s, 1, &ptr_mov, parm);
59588429a1caSRichard Henderson 
59598429a1caSRichard Henderson     /*
59608429a1caSRichard Henderson      * Handle oi.
59618429a1caSRichard Henderson      */
59628429a1caSRichard Henderson     imm = ldst->oi;
59638429a1caSRichard Henderson     loc = &info->in[next_arg];
59648429a1caSRichard Henderson     type = TCG_TYPE_I32;
59658429a1caSRichard Henderson     switch (loc->kind) {
59668429a1caSRichard Henderson     case TCG_CALL_ARG_NORMAL:
59678429a1caSRichard Henderson         break;
59688429a1caSRichard Henderson     case TCG_CALL_ARG_EXTEND_U:
59698429a1caSRichard Henderson     case TCG_CALL_ARG_EXTEND_S:
59708429a1caSRichard Henderson         /* No extension required for MemOpIdx. */
59718429a1caSRichard Henderson         tcg_debug_assert(imm <= INT32_MAX);
59728429a1caSRichard Henderson         type = TCG_TYPE_REG;
59738429a1caSRichard Henderson         break;
59748429a1caSRichard Henderson     default:
59758429a1caSRichard Henderson         g_assert_not_reached();
59768429a1caSRichard Henderson     }
59778429a1caSRichard Henderson     tcg_out_helper_load_imm(s, loc->arg_slot, type, imm, parm);
59788429a1caSRichard Henderson     next_arg++;
59798429a1caSRichard Henderson 
59808429a1caSRichard Henderson     /*
59818429a1caSRichard Henderson      * Handle ra.
59828429a1caSRichard Henderson      */
59838429a1caSRichard Henderson     loc = &info->in[next_arg];
59848429a1caSRichard Henderson     slot = loc->arg_slot;
59858429a1caSRichard Henderson     if (parm->ra_gen) {
59868429a1caSRichard Henderson         int arg_reg = -1;
59878429a1caSRichard Henderson         TCGReg ra_reg;
59888429a1caSRichard Henderson 
59898429a1caSRichard Henderson         if (arg_slot_reg_p(slot)) {
59908429a1caSRichard Henderson             arg_reg = tcg_target_call_iarg_regs[slot];
59918429a1caSRichard Henderson         }
59928429a1caSRichard Henderson         ra_reg = parm->ra_gen(s, ldst, arg_reg);
59938429a1caSRichard Henderson 
59948429a1caSRichard Henderson         ptr_mov.dst = slot;
59958429a1caSRichard Henderson         ptr_mov.src = ra_reg;
59968429a1caSRichard Henderson         tcg_out_helper_load_slots(s, 1, &ptr_mov, parm);
59978429a1caSRichard Henderson     } else {
59988429a1caSRichard Henderson         imm = (uintptr_t)ldst->raddr;
59998429a1caSRichard Henderson         tcg_out_helper_load_imm(s, slot, TCG_TYPE_PTR, imm, parm);
60008429a1caSRichard Henderson     }
60018429a1caSRichard Henderson }
60028429a1caSRichard Henderson 
60038429a1caSRichard Henderson static unsigned tcg_out_helper_add_mov(TCGMovExtend *mov,
60048429a1caSRichard Henderson                                        const TCGCallArgumentLoc *loc,
60058429a1caSRichard Henderson                                        TCGType dst_type, TCGType src_type,
60068429a1caSRichard Henderson                                        TCGReg lo, TCGReg hi)
60078429a1caSRichard Henderson {
6008ebebea53SRichard Henderson     MemOp reg_mo;
6009ebebea53SRichard Henderson 
60108429a1caSRichard Henderson     if (dst_type <= TCG_TYPE_REG) {
60118429a1caSRichard Henderson         MemOp src_ext;
60128429a1caSRichard Henderson 
60138429a1caSRichard Henderson         switch (loc->kind) {
60148429a1caSRichard Henderson         case TCG_CALL_ARG_NORMAL:
60158429a1caSRichard Henderson             src_ext = src_type == TCG_TYPE_I32 ? MO_32 : MO_64;
60168429a1caSRichard Henderson             break;
60178429a1caSRichard Henderson         case TCG_CALL_ARG_EXTEND_U:
60188429a1caSRichard Henderson             dst_type = TCG_TYPE_REG;
60198429a1caSRichard Henderson             src_ext = MO_UL;
60208429a1caSRichard Henderson             break;
60218429a1caSRichard Henderson         case TCG_CALL_ARG_EXTEND_S:
60228429a1caSRichard Henderson             dst_type = TCG_TYPE_REG;
60238429a1caSRichard Henderson             src_ext = MO_SL;
60248429a1caSRichard Henderson             break;
60258429a1caSRichard Henderson         default:
60268429a1caSRichard Henderson             g_assert_not_reached();
60278429a1caSRichard Henderson         }
60288429a1caSRichard Henderson 
60298429a1caSRichard Henderson         mov[0].dst = loc->arg_slot;
60308429a1caSRichard Henderson         mov[0].dst_type = dst_type;
60318429a1caSRichard Henderson         mov[0].src = lo;
60328429a1caSRichard Henderson         mov[0].src_type = src_type;
60338429a1caSRichard Henderson         mov[0].src_ext = src_ext;
60348429a1caSRichard Henderson         return 1;
60358429a1caSRichard Henderson     }
60368429a1caSRichard Henderson 
6037ebebea53SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
6038ebebea53SRichard Henderson         assert(dst_type == TCG_TYPE_I64);
6039ebebea53SRichard Henderson         reg_mo = MO_32;
6040ebebea53SRichard Henderson     } else {
6041ebebea53SRichard Henderson         assert(dst_type == TCG_TYPE_I128);
6042ebebea53SRichard Henderson         reg_mo = MO_64;
6043ebebea53SRichard Henderson     }
60448429a1caSRichard Henderson 
60458429a1caSRichard Henderson     mov[0].dst = loc[HOST_BIG_ENDIAN].arg_slot;
60468429a1caSRichard Henderson     mov[0].src = lo;
6047ebebea53SRichard Henderson     mov[0].dst_type = TCG_TYPE_REG;
6048ebebea53SRichard Henderson     mov[0].src_type = TCG_TYPE_REG;
6049ebebea53SRichard Henderson     mov[0].src_ext = reg_mo;
60508429a1caSRichard Henderson 
60518429a1caSRichard Henderson     mov[1].dst = loc[!HOST_BIG_ENDIAN].arg_slot;
60528429a1caSRichard Henderson     mov[1].src = hi;
6053ebebea53SRichard Henderson     mov[1].dst_type = TCG_TYPE_REG;
6054ebebea53SRichard Henderson     mov[1].src_type = TCG_TYPE_REG;
6055ebebea53SRichard Henderson     mov[1].src_ext = reg_mo;
60568429a1caSRichard Henderson 
60578429a1caSRichard Henderson     return 2;
60588429a1caSRichard Henderson }
60598429a1caSRichard Henderson 
60608429a1caSRichard Henderson static void tcg_out_ld_helper_args(TCGContext *s, const TCGLabelQemuLdst *ldst,
60618429a1caSRichard Henderson                                    const TCGLdstHelperParam *parm)
60628429a1caSRichard Henderson {
60638429a1caSRichard Henderson     const TCGHelperInfo *info;
60648429a1caSRichard Henderson     const TCGCallArgumentLoc *loc;
60658429a1caSRichard Henderson     TCGMovExtend mov[2];
60668429a1caSRichard Henderson     unsigned next_arg, nmov;
60678429a1caSRichard Henderson     MemOp mop = get_memop(ldst->oi);
60688429a1caSRichard Henderson 
60698429a1caSRichard Henderson     switch (mop & MO_SIZE) {
60708429a1caSRichard Henderson     case MO_8:
60718429a1caSRichard Henderson     case MO_16:
60728429a1caSRichard Henderson     case MO_32:
60738429a1caSRichard Henderson         info = &info_helper_ld32_mmu;
60748429a1caSRichard Henderson         break;
60758429a1caSRichard Henderson     case MO_64:
60768429a1caSRichard Henderson         info = &info_helper_ld64_mmu;
60778429a1caSRichard Henderson         break;
6078ebebea53SRichard Henderson     case MO_128:
6079ebebea53SRichard Henderson         info = &info_helper_ld128_mmu;
6080ebebea53SRichard Henderson         break;
60818429a1caSRichard Henderson     default:
60828429a1caSRichard Henderson         g_assert_not_reached();
60838429a1caSRichard Henderson     }
60848429a1caSRichard Henderson 
60858429a1caSRichard Henderson     /* Defer env argument. */
60868429a1caSRichard Henderson     next_arg = 1;
60878429a1caSRichard Henderson 
60888429a1caSRichard Henderson     loc = &info->in[next_arg];
6089c31e5fa4SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && s->addr_type == TCG_TYPE_I32) {
609024e46e6cSRichard Henderson         /*
609124e46e6cSRichard Henderson          * 32-bit host with 32-bit guest: zero-extend the guest address
609224e46e6cSRichard Henderson          * to 64-bits for the helper by storing the low part, then
609324e46e6cSRichard Henderson          * load a zero for the high part.
609424e46e6cSRichard Henderson          */
609524e46e6cSRichard Henderson         tcg_out_helper_add_mov(mov, loc + HOST_BIG_ENDIAN,
609624e46e6cSRichard Henderson                                TCG_TYPE_I32, TCG_TYPE_I32,
609724e46e6cSRichard Henderson                                ldst->addrlo_reg, -1);
609824e46e6cSRichard Henderson         tcg_out_helper_load_slots(s, 1, mov, parm);
609924e46e6cSRichard Henderson 
610024e46e6cSRichard Henderson         tcg_out_helper_load_imm(s, loc[!HOST_BIG_ENDIAN].arg_slot,
610124e46e6cSRichard Henderson                                 TCG_TYPE_I32, 0, parm);
610224e46e6cSRichard Henderson         next_arg += 2;
6103c31e5fa4SRichard Henderson     } else {
6104c31e5fa4SRichard Henderson         nmov = tcg_out_helper_add_mov(mov, loc, TCG_TYPE_I64, s->addr_type,
6105c31e5fa4SRichard Henderson                                       ldst->addrlo_reg, ldst->addrhi_reg);
6106c31e5fa4SRichard Henderson         tcg_out_helper_load_slots(s, nmov, mov, parm);
6107c31e5fa4SRichard Henderson         next_arg += nmov;
610824e46e6cSRichard Henderson     }
61098429a1caSRichard Henderson 
6110ebebea53SRichard Henderson     switch (info->out_kind) {
6111ebebea53SRichard Henderson     case TCG_CALL_RET_NORMAL:
6112ebebea53SRichard Henderson     case TCG_CALL_RET_BY_VEC:
6113ebebea53SRichard Henderson         break;
6114ebebea53SRichard Henderson     case TCG_CALL_RET_BY_REF:
6115ebebea53SRichard Henderson         /*
6116ebebea53SRichard Henderson          * The return reference is in the first argument slot.
6117ebebea53SRichard Henderson          * We need memory in which to return: re-use the top of stack.
6118ebebea53SRichard Henderson          */
6119ebebea53SRichard Henderson         {
6120ebebea53SRichard Henderson             int ofs_slot0 = TCG_TARGET_CALL_STACK_OFFSET;
6121ebebea53SRichard Henderson 
6122ebebea53SRichard Henderson             if (arg_slot_reg_p(0)) {
6123ebebea53SRichard Henderson                 tcg_out_addi_ptr(s, tcg_target_call_iarg_regs[0],
6124ebebea53SRichard Henderson                                  TCG_REG_CALL_STACK, ofs_slot0);
6125ebebea53SRichard Henderson             } else {
6126ebebea53SRichard Henderson                 tcg_debug_assert(parm->ntmp != 0);
6127ebebea53SRichard Henderson                 tcg_out_addi_ptr(s, parm->tmp[0],
6128ebebea53SRichard Henderson                                  TCG_REG_CALL_STACK, ofs_slot0);
6129ebebea53SRichard Henderson                 tcg_out_st(s, TCG_TYPE_PTR, parm->tmp[0],
6130ebebea53SRichard Henderson                            TCG_REG_CALL_STACK, ofs_slot0);
6131ebebea53SRichard Henderson             }
6132ebebea53SRichard Henderson         }
6133ebebea53SRichard Henderson         break;
6134ebebea53SRichard Henderson     default:
6135ebebea53SRichard Henderson         g_assert_not_reached();
6136ebebea53SRichard Henderson     }
61378429a1caSRichard Henderson 
61388429a1caSRichard Henderson     tcg_out_helper_load_common_args(s, ldst, parm, info, next_arg);
61398429a1caSRichard Henderson }
61408429a1caSRichard Henderson 
61418429a1caSRichard Henderson static void tcg_out_ld_helper_ret(TCGContext *s, const TCGLabelQemuLdst *ldst,
61428429a1caSRichard Henderson                                   bool load_sign,
61438429a1caSRichard Henderson                                   const TCGLdstHelperParam *parm)
61448429a1caSRichard Henderson {
61458429a1caSRichard Henderson     MemOp mop = get_memop(ldst->oi);
6146ebebea53SRichard Henderson     TCGMovExtend mov[2];
6147ebebea53SRichard Henderson     int ofs_slot0;
61488429a1caSRichard Henderson 
6149ebebea53SRichard Henderson     switch (ldst->type) {
6150ebebea53SRichard Henderson     case TCG_TYPE_I64:
6151ebebea53SRichard Henderson         if (TCG_TARGET_REG_BITS == 32) {
6152ebebea53SRichard Henderson             break;
6153ebebea53SRichard Henderson         }
6154ebebea53SRichard Henderson         /* fall through */
6155ebebea53SRichard Henderson 
6156ebebea53SRichard Henderson     case TCG_TYPE_I32:
61578429a1caSRichard Henderson         mov[0].dst = ldst->datalo_reg;
61588429a1caSRichard Henderson         mov[0].src = tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, 0);
61598429a1caSRichard Henderson         mov[0].dst_type = ldst->type;
61608429a1caSRichard Henderson         mov[0].src_type = TCG_TYPE_REG;
61618429a1caSRichard Henderson 
61628429a1caSRichard Henderson         /*
61638429a1caSRichard Henderson          * If load_sign, then we allowed the helper to perform the
61648429a1caSRichard Henderson          * appropriate sign extension to tcg_target_ulong, and all
61658429a1caSRichard Henderson          * we need now is a plain move.
61668429a1caSRichard Henderson          *
61678429a1caSRichard Henderson          * If they do not, then we expect the relevant extension
61688429a1caSRichard Henderson          * instruction to be no more expensive than a move, and
61698429a1caSRichard Henderson          * we thus save the icache etc by only using one of two
61708429a1caSRichard Henderson          * helper functions.
61718429a1caSRichard Henderson          */
61728429a1caSRichard Henderson         if (load_sign || !(mop & MO_SIGN)) {
61738429a1caSRichard Henderson             if (TCG_TARGET_REG_BITS == 32 || ldst->type == TCG_TYPE_I32) {
61748429a1caSRichard Henderson                 mov[0].src_ext = MO_32;
61758429a1caSRichard Henderson             } else {
61768429a1caSRichard Henderson                 mov[0].src_ext = MO_64;
61778429a1caSRichard Henderson             }
61788429a1caSRichard Henderson         } else {
61798429a1caSRichard Henderson             mov[0].src_ext = mop & MO_SSIZE;
61808429a1caSRichard Henderson         }
61818429a1caSRichard Henderson         tcg_out_movext1(s, mov);
6182ebebea53SRichard Henderson         return;
6183ebebea53SRichard Henderson 
6184ebebea53SRichard Henderson     case TCG_TYPE_I128:
6185ebebea53SRichard Henderson         tcg_debug_assert(TCG_TARGET_REG_BITS == 64);
6186ebebea53SRichard Henderson         ofs_slot0 = TCG_TARGET_CALL_STACK_OFFSET;
6187ebebea53SRichard Henderson         switch (TCG_TARGET_CALL_RET_I128) {
6188ebebea53SRichard Henderson         case TCG_CALL_RET_NORMAL:
6189ebebea53SRichard Henderson             break;
6190ebebea53SRichard Henderson         case TCG_CALL_RET_BY_VEC:
6191ebebea53SRichard Henderson             tcg_out_st(s, TCG_TYPE_V128,
6192ebebea53SRichard Henderson                        tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0),
6193ebebea53SRichard Henderson                        TCG_REG_CALL_STACK, ofs_slot0);
6194ebebea53SRichard Henderson             /* fall through */
6195ebebea53SRichard Henderson         case TCG_CALL_RET_BY_REF:
6196ebebea53SRichard Henderson             tcg_out_ld(s, TCG_TYPE_I64, ldst->datalo_reg,
6197ebebea53SRichard Henderson                        TCG_REG_CALL_STACK, ofs_slot0 + 8 * HOST_BIG_ENDIAN);
6198ebebea53SRichard Henderson             tcg_out_ld(s, TCG_TYPE_I64, ldst->datahi_reg,
6199ebebea53SRichard Henderson                        TCG_REG_CALL_STACK, ofs_slot0 + 8 * !HOST_BIG_ENDIAN);
6200ebebea53SRichard Henderson             return;
6201ebebea53SRichard Henderson         default:
6202ebebea53SRichard Henderson             g_assert_not_reached();
6203ebebea53SRichard Henderson         }
6204ebebea53SRichard Henderson         break;
6205ebebea53SRichard Henderson 
6206ebebea53SRichard Henderson     default:
6207ebebea53SRichard Henderson         g_assert_not_reached();
6208ebebea53SRichard Henderson     }
62098429a1caSRichard Henderson 
62108429a1caSRichard Henderson     mov[0].dst = ldst->datalo_reg;
62118429a1caSRichard Henderson     mov[0].src =
62128429a1caSRichard Henderson         tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, HOST_BIG_ENDIAN);
6213723d3a27SRichard Henderson     mov[0].dst_type = TCG_TYPE_REG;
6214723d3a27SRichard Henderson     mov[0].src_type = TCG_TYPE_REG;
6215ebebea53SRichard Henderson     mov[0].src_ext = TCG_TARGET_REG_BITS == 32 ? MO_32 : MO_64;
62168429a1caSRichard Henderson 
62178429a1caSRichard Henderson     mov[1].dst = ldst->datahi_reg;
62188429a1caSRichard Henderson     mov[1].src =
62198429a1caSRichard Henderson         tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, !HOST_BIG_ENDIAN);
62208429a1caSRichard Henderson     mov[1].dst_type = TCG_TYPE_REG;
62218429a1caSRichard Henderson     mov[1].src_type = TCG_TYPE_REG;
6222ebebea53SRichard Henderson     mov[1].src_ext = TCG_TARGET_REG_BITS == 32 ? MO_32 : MO_64;
62238429a1caSRichard Henderson 
62248429a1caSRichard Henderson     tcg_out_movext2(s, mov, mov + 1, parm->ntmp ? parm->tmp[0] : -1);
62258429a1caSRichard Henderson }
62268429a1caSRichard Henderson 
62278429a1caSRichard Henderson static void tcg_out_st_helper_args(TCGContext *s, const TCGLabelQemuLdst *ldst,
62288429a1caSRichard Henderson                                    const TCGLdstHelperParam *parm)
62298429a1caSRichard Henderson {
62308429a1caSRichard Henderson     const TCGHelperInfo *info;
62318429a1caSRichard Henderson     const TCGCallArgumentLoc *loc;
62328429a1caSRichard Henderson     TCGMovExtend mov[4];
62338429a1caSRichard Henderson     TCGType data_type;
62348429a1caSRichard Henderson     unsigned next_arg, nmov, n;
62358429a1caSRichard Henderson     MemOp mop = get_memop(ldst->oi);
62368429a1caSRichard Henderson 
62378429a1caSRichard Henderson     switch (mop & MO_SIZE) {
62388429a1caSRichard Henderson     case MO_8:
62398429a1caSRichard Henderson     case MO_16:
62408429a1caSRichard Henderson     case MO_32:
62418429a1caSRichard Henderson         info = &info_helper_st32_mmu;
62428429a1caSRichard Henderson         data_type = TCG_TYPE_I32;
62438429a1caSRichard Henderson         break;
62448429a1caSRichard Henderson     case MO_64:
62458429a1caSRichard Henderson         info = &info_helper_st64_mmu;
62468429a1caSRichard Henderson         data_type = TCG_TYPE_I64;
62478429a1caSRichard Henderson         break;
6248ebebea53SRichard Henderson     case MO_128:
6249ebebea53SRichard Henderson         info = &info_helper_st128_mmu;
6250ebebea53SRichard Henderson         data_type = TCG_TYPE_I128;
6251ebebea53SRichard Henderson         break;
62528429a1caSRichard Henderson     default:
62538429a1caSRichard Henderson         g_assert_not_reached();
62548429a1caSRichard Henderson     }
62558429a1caSRichard Henderson 
62568429a1caSRichard Henderson     /* Defer env argument. */
62578429a1caSRichard Henderson     next_arg = 1;
62588429a1caSRichard Henderson     nmov = 0;
62598429a1caSRichard Henderson 
62608429a1caSRichard Henderson     /* Handle addr argument. */
62618429a1caSRichard Henderson     loc = &info->in[next_arg];
6262c31e5fa4SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && s->addr_type == TCG_TYPE_I32) {
626324e46e6cSRichard Henderson         /*
626424e46e6cSRichard Henderson          * 32-bit host with 32-bit guest: zero-extend the guest address
626524e46e6cSRichard Henderson          * to 64-bits for the helper by storing the low part.  Later,
626624e46e6cSRichard Henderson          * after we have processed the register inputs, we will load a
626724e46e6cSRichard Henderson          * zero for the high part.
626824e46e6cSRichard Henderson          */
626924e46e6cSRichard Henderson         tcg_out_helper_add_mov(mov, loc + HOST_BIG_ENDIAN,
627024e46e6cSRichard Henderson                                TCG_TYPE_I32, TCG_TYPE_I32,
627124e46e6cSRichard Henderson                                ldst->addrlo_reg, -1);
627224e46e6cSRichard Henderson         next_arg += 2;
627324e46e6cSRichard Henderson         nmov += 1;
6274c31e5fa4SRichard Henderson     } else {
6275c31e5fa4SRichard Henderson         n = tcg_out_helper_add_mov(mov, loc, TCG_TYPE_I64, s->addr_type,
6276c31e5fa4SRichard Henderson                                    ldst->addrlo_reg, ldst->addrhi_reg);
6277c31e5fa4SRichard Henderson         next_arg += n;
6278c31e5fa4SRichard Henderson         nmov += n;
627924e46e6cSRichard Henderson     }
62808429a1caSRichard Henderson 
62818429a1caSRichard Henderson     /* Handle data argument. */
62828429a1caSRichard Henderson     loc = &info->in[next_arg];
6283ebebea53SRichard Henderson     switch (loc->kind) {
6284ebebea53SRichard Henderson     case TCG_CALL_ARG_NORMAL:
6285ebebea53SRichard Henderson     case TCG_CALL_ARG_EXTEND_U:
6286ebebea53SRichard Henderson     case TCG_CALL_ARG_EXTEND_S:
62878429a1caSRichard Henderson         n = tcg_out_helper_add_mov(mov + nmov, loc, data_type, ldst->type,
62888429a1caSRichard Henderson                                    ldst->datalo_reg, ldst->datahi_reg);
62898429a1caSRichard Henderson         next_arg += n;
62908429a1caSRichard Henderson         nmov += n;
6291ebebea53SRichard Henderson         tcg_out_helper_load_slots(s, nmov, mov, parm);
6292ebebea53SRichard Henderson         break;
6293ebebea53SRichard Henderson 
6294ebebea53SRichard Henderson     case TCG_CALL_ARG_BY_REF:
6295ebebea53SRichard Henderson         tcg_debug_assert(TCG_TARGET_REG_BITS == 64);
6296ebebea53SRichard Henderson         tcg_debug_assert(data_type == TCG_TYPE_I128);
6297ebebea53SRichard Henderson         tcg_out_st(s, TCG_TYPE_I64,
6298ebebea53SRichard Henderson                    HOST_BIG_ENDIAN ? ldst->datahi_reg : ldst->datalo_reg,
6299ebebea53SRichard Henderson                    TCG_REG_CALL_STACK, arg_slot_stk_ofs(loc[0].ref_slot));
6300ebebea53SRichard Henderson         tcg_out_st(s, TCG_TYPE_I64,
6301ebebea53SRichard Henderson                    HOST_BIG_ENDIAN ? ldst->datalo_reg : ldst->datahi_reg,
6302ebebea53SRichard Henderson                    TCG_REG_CALL_STACK, arg_slot_stk_ofs(loc[1].ref_slot));
63038429a1caSRichard Henderson 
63048429a1caSRichard Henderson         tcg_out_helper_load_slots(s, nmov, mov, parm);
6305ebebea53SRichard Henderson 
6306ebebea53SRichard Henderson         if (arg_slot_reg_p(loc->arg_slot)) {
6307ebebea53SRichard Henderson             tcg_out_addi_ptr(s, tcg_target_call_iarg_regs[loc->arg_slot],
6308ebebea53SRichard Henderson                              TCG_REG_CALL_STACK,
6309ebebea53SRichard Henderson                              arg_slot_stk_ofs(loc->ref_slot));
6310ebebea53SRichard Henderson         } else {
6311ebebea53SRichard Henderson             tcg_debug_assert(parm->ntmp != 0);
6312ebebea53SRichard Henderson             tcg_out_addi_ptr(s, parm->tmp[0], TCG_REG_CALL_STACK,
6313ebebea53SRichard Henderson                              arg_slot_stk_ofs(loc->ref_slot));
6314ebebea53SRichard Henderson             tcg_out_st(s, TCG_TYPE_PTR, parm->tmp[0],
6315ebebea53SRichard Henderson                        TCG_REG_CALL_STACK, arg_slot_stk_ofs(loc->arg_slot));
6316ebebea53SRichard Henderson         }
6317ebebea53SRichard Henderson         next_arg += 2;
6318ebebea53SRichard Henderson         break;
6319ebebea53SRichard Henderson 
6320ebebea53SRichard Henderson     default:
6321ebebea53SRichard Henderson         g_assert_not_reached();
6322ebebea53SRichard Henderson     }
6323ebebea53SRichard Henderson 
6324c31e5fa4SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && s->addr_type == TCG_TYPE_I32) {
6325c31e5fa4SRichard Henderson         /* Zero extend the address by loading a zero for the high part. */
632624e46e6cSRichard Henderson         loc = &info->in[1 + !HOST_BIG_ENDIAN];
632724e46e6cSRichard Henderson         tcg_out_helper_load_imm(s, loc->arg_slot, TCG_TYPE_I32, 0, parm);
632824e46e6cSRichard Henderson     }
632924e46e6cSRichard Henderson 
63308429a1caSRichard Henderson     tcg_out_helper_load_common_args(s, ldst, parm, info, next_arg);
63318429a1caSRichard Henderson }
63328429a1caSRichard Henderson 
633376cef4b2SRichard Henderson int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start)
6334c896fe29Sbellard {
6335747bd69dSRichard Henderson     int i, start_words, num_insns;
633615fa08f8SRichard Henderson     TCGOp *op;
6337c896fe29Sbellard 
6338d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)
6339fbf59aadSRichard Henderson                  && qemu_log_in_addr_range(pc_start))) {
6340c60f599bSRichard Henderson         FILE *logfile = qemu_log_trylock();
634178b54858SRichard Henderson         if (logfile) {
634278b54858SRichard Henderson             fprintf(logfile, "OP:\n");
6343b7a83ff8SRichard Henderson             tcg_dump_ops(s, logfile, false);
634478b54858SRichard Henderson             fprintf(logfile, "\n");
6345fc59d2d8SRobert Foley             qemu_log_unlock(logfile);
6346c896fe29Sbellard         }
634778b54858SRichard Henderson     }
6348c896fe29Sbellard 
6349bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG
6350bef16ab4SRichard Henderson     /* Ensure all labels referenced have been emitted.  */
6351bef16ab4SRichard Henderson     {
6352bef16ab4SRichard Henderson         TCGLabel *l;
6353bef16ab4SRichard Henderson         bool error = false;
6354bef16ab4SRichard Henderson 
6355bef16ab4SRichard Henderson         QSIMPLEQ_FOREACH(l, &s->labels, next) {
6356f85b1fc4SRichard Henderson             if (unlikely(!l->present) && !QSIMPLEQ_EMPTY(&l->branches)) {
6357bef16ab4SRichard Henderson                 qemu_log_mask(CPU_LOG_TB_OP,
6358bef16ab4SRichard Henderson                               "$L%d referenced but not present.\n", l->id);
6359bef16ab4SRichard Henderson                 error = true;
6360bef16ab4SRichard Henderson             }
6361bef16ab4SRichard Henderson         }
6362bef16ab4SRichard Henderson         assert(!error);
6363bef16ab4SRichard Henderson     }
6364bef16ab4SRichard Henderson #endif
6365bef16ab4SRichard Henderson 
636604e006abSRichard Henderson     /* Do not reuse any EBB that may be allocated within the TB. */
636704e006abSRichard Henderson     tcg_temp_ebb_reset_freed(s);
636804e006abSRichard Henderson 
6369c45cb8bbSRichard Henderson     tcg_optimize(s);
63708f2e8c07SKirill Batuzov 
6371b4fc67c7SRichard Henderson     reachable_code_pass(s);
6372874b8574SRichard Henderson     liveness_pass_0(s);
6373b83eabeaSRichard Henderson     liveness_pass_1(s);
63745a18407fSRichard Henderson 
63755a18407fSRichard Henderson     if (s->nb_indirects > 0) {
63765a18407fSRichard Henderson         if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND)
6377fbf59aadSRichard Henderson                      && qemu_log_in_addr_range(pc_start))) {
6378c60f599bSRichard Henderson             FILE *logfile = qemu_log_trylock();
637978b54858SRichard Henderson             if (logfile) {
638078b54858SRichard Henderson                 fprintf(logfile, "OP before indirect lowering:\n");
6381b7a83ff8SRichard Henderson                 tcg_dump_ops(s, logfile, false);
638278b54858SRichard Henderson                 fprintf(logfile, "\n");
6383fc59d2d8SRobert Foley                 qemu_log_unlock(logfile);
63845a18407fSRichard Henderson             }
638578b54858SRichard Henderson         }
6386645e3a81SRichard Henderson 
63875a18407fSRichard Henderson         /* Replace indirect temps with direct temps.  */
6388b83eabeaSRichard Henderson         if (liveness_pass_2(s)) {
63895a18407fSRichard Henderson             /* If changes were made, re-run liveness.  */
6390b83eabeaSRichard Henderson             liveness_pass_1(s);
63915a18407fSRichard Henderson         }
63925a18407fSRichard Henderson     }
6393c5cc28ffSAurelien Jarno 
6394d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT)
6395fbf59aadSRichard Henderson                  && qemu_log_in_addr_range(pc_start))) {
6396c60f599bSRichard Henderson         FILE *logfile = qemu_log_trylock();
639778b54858SRichard Henderson         if (logfile) {
639878b54858SRichard Henderson             fprintf(logfile, "OP after optimization and liveness analysis:\n");
6399b7a83ff8SRichard Henderson             tcg_dump_ops(s, logfile, true);
640078b54858SRichard Henderson             fprintf(logfile, "\n");
6401fc59d2d8SRobert Foley             qemu_log_unlock(logfile);
6402c896fe29Sbellard         }
640378b54858SRichard Henderson     }
6404c896fe29Sbellard 
640535abb009SRichard Henderson     /* Initialize goto_tb jump offsets. */
64063a50f424SRichard Henderson     tb->jmp_reset_offset[0] = TB_JMP_OFFSET_INVALID;
64073a50f424SRichard Henderson     tb->jmp_reset_offset[1] = TB_JMP_OFFSET_INVALID;
64089da6079bSRichard Henderson     tb->jmp_insn_offset[0] = TB_JMP_OFFSET_INVALID;
64099da6079bSRichard Henderson     tb->jmp_insn_offset[1] = TB_JMP_OFFSET_INVALID;
641035abb009SRichard Henderson 
6411c896fe29Sbellard     tcg_reg_alloc_start(s);
6412c896fe29Sbellard 
6413db0c51a3SRichard Henderson     /*
6414db0c51a3SRichard Henderson      * Reset the buffer pointers when restarting after overflow.
6415db0c51a3SRichard Henderson      * TODO: Move this into translate-all.c with the rest of the
6416db0c51a3SRichard Henderson      * buffer management.  Having only this done here is confusing.
6417db0c51a3SRichard Henderson      */
6418db0c51a3SRichard Henderson     s->code_buf = tcg_splitwx_to_rw(tb->tc.ptr);
6419db0c51a3SRichard Henderson     s->code_ptr = s->code_buf;
6420a7cfd751SRichard Henderson     s->data_gen_ptr = NULL;
6421c896fe29Sbellard 
64226001f772SLaurent Vivier     QSIMPLEQ_INIT(&s->ldst_labels);
642357a26946SRichard Henderson     s->pool_labels = NULL;
64249ecefc84SRichard Henderson 
6425747bd69dSRichard Henderson     start_words = s->insn_start_words;
6426747bd69dSRichard Henderson     s->gen_insn_data =
6427747bd69dSRichard Henderson         tcg_malloc(sizeof(uint64_t) * s->gen_tb->icount * start_words);
6428747bd69dSRichard Henderson 
64299358fbbfSRichard Henderson     tcg_out_tb_start(s);
64309358fbbfSRichard Henderson 
6431fca8a500SRichard Henderson     num_insns = -1;
643215fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
6433c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
6434b3db8758Sblueswir1 
6435c896fe29Sbellard         switch (opc) {
6436c896fe29Sbellard         case INDEX_op_mov_i32:
6437c896fe29Sbellard         case INDEX_op_mov_i64:
6438d2fd745fSRichard Henderson         case INDEX_op_mov_vec:
6439dd186292SRichard Henderson             tcg_reg_alloc_mov(s, op);
6440c896fe29Sbellard             break;
6441bab1671fSRichard Henderson         case INDEX_op_dup_vec:
6442bab1671fSRichard Henderson             tcg_reg_alloc_dup(s, op);
6443bab1671fSRichard Henderson             break;
6444765b842aSRichard Henderson         case INDEX_op_insn_start:
6445fca8a500SRichard Henderson             if (num_insns >= 0) {
64469f754620SRichard Henderson                 size_t off = tcg_current_code_size(s);
64479f754620SRichard Henderson                 s->gen_insn_end_off[num_insns] = off;
64489f754620SRichard Henderson                 /* Assert that we do not overflow our stored offset.  */
64499f754620SRichard Henderson                 assert(s->gen_insn_end_off[num_insns] == off);
6450fca8a500SRichard Henderson             }
6451fca8a500SRichard Henderson             num_insns++;
6452747bd69dSRichard Henderson             for (i = 0; i < start_words; ++i) {
6453747bd69dSRichard Henderson                 s->gen_insn_data[num_insns * start_words + i] =
6454c9ad8d27SRichard Henderson                     tcg_get_insn_start_param(op, i);
6455bad729e2SRichard Henderson             }
6456c896fe29Sbellard             break;
64575ff9d6a4Sbellard         case INDEX_op_discard:
645843439139SRichard Henderson             temp_dead(s, arg_temp(op->args[0]));
64595ff9d6a4Sbellard             break;
6460c896fe29Sbellard         case INDEX_op_set_label:
6461e8996ee0Sbellard             tcg_reg_alloc_bb_end(s, s->reserved_regs);
646292ab8e7dSRichard Henderson             tcg_out_label(s, arg_label(op->args[0]));
6463c896fe29Sbellard             break;
6464c896fe29Sbellard         case INDEX_op_call:
6465dd186292SRichard Henderson             tcg_reg_alloc_call(s, op);
6466c45cb8bbSRichard Henderson             break;
6467b55a8d9dSRichard Henderson         case INDEX_op_exit_tb:
6468b55a8d9dSRichard Henderson             tcg_out_exit_tb(s, op->args[0]);
6469b55a8d9dSRichard Henderson             break;
6470cf7d6b8eSRichard Henderson         case INDEX_op_goto_tb:
6471cf7d6b8eSRichard Henderson             tcg_out_goto_tb(s, op->args[0]);
6472cf7d6b8eSRichard Henderson             break;
6473efe86b21SRichard Henderson         case INDEX_op_dup2_vec:
6474efe86b21SRichard Henderson             if (tcg_reg_alloc_dup2(s, op)) {
6475efe86b21SRichard Henderson                 break;
6476efe86b21SRichard Henderson             }
6477efe86b21SRichard Henderson             /* fall through */
6478c896fe29Sbellard         default:
647925c4d9ccSRichard Henderson             /* Sanity check that we've not introduced any unhandled opcodes. */
6480771a5925SRichard Henderson             tcg_debug_assert(tcg_op_supported(opc, TCGOP_TYPE(op),
6481771a5925SRichard Henderson                                               TCGOP_FLAGS(op)));
6482c896fe29Sbellard             /* Note: in order to speed up the code, it would be much
6483c896fe29Sbellard                faster to have specialized register allocator functions for
6484c896fe29Sbellard                some common argument patterns */
6485dd186292SRichard Henderson             tcg_reg_alloc_op(s, op);
6486c896fe29Sbellard             break;
6487c896fe29Sbellard         }
6488b125f9dcSRichard Henderson         /* Test for (pending) buffer overflow.  The assumption is that any
6489b125f9dcSRichard Henderson            one operation beginning below the high water mark cannot overrun
6490b125f9dcSRichard Henderson            the buffer completely.  Thus we can test for overflow after
6491b125f9dcSRichard Henderson            generating code without having to check during generation.  */
6492644da9b3SJohn Clarke         if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) {
6493b125f9dcSRichard Henderson             return -1;
6494b125f9dcSRichard Henderson         }
64956e6c4efeSRichard Henderson         /* Test for TB overflow, as seen by gen_insn_end_off.  */
64966e6c4efeSRichard Henderson         if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) {
64976e6c4efeSRichard Henderson             return -2;
64986e6c4efeSRichard Henderson         }
6499c896fe29Sbellard     }
6500747bd69dSRichard Henderson     tcg_debug_assert(num_insns + 1 == s->gen_tb->icount);
6501fca8a500SRichard Henderson     s->gen_insn_end_off[num_insns] = tcg_current_code_size(s);
6502c45cb8bbSRichard Henderson 
6503b76f0d8cSYeongkyoon Lee     /* Generate TB finalization at the end of block */
6504aeee05f5SRichard Henderson     i = tcg_out_ldst_finalize(s);
6505aeee05f5SRichard Henderson     if (i < 0) {
6506aeee05f5SRichard Henderson         return i;
650723dceda6SRichard Henderson     }
65081768987bSRichard Henderson     i = tcg_out_pool_finalize(s);
65091768987bSRichard Henderson     if (i < 0) {
65101768987bSRichard Henderson         return i;
651157a26946SRichard Henderson     }
65127ecd02a0SRichard Henderson     if (!tcg_resolve_relocs(s)) {
65137ecd02a0SRichard Henderson         return -2;
65147ecd02a0SRichard Henderson     }
6515c896fe29Sbellard 
6516df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
6517c896fe29Sbellard     /* flush instruction cache */
6518db0c51a3SRichard Henderson     flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf),
6519db0c51a3SRichard Henderson                         (uintptr_t)s->code_buf,
65201da8de39SRichard Henderson                         tcg_ptr_byte_diff(s->code_ptr, s->code_buf));
6521df5d2b16SRichard Henderson #endif
65222aeabc08SStefan Weil 
65231813e175SRichard Henderson     return tcg_current_code_size(s);
6524c896fe29Sbellard }
6525c896fe29Sbellard 
6526813da627SRichard Henderson #ifdef ELF_HOST_MACHINE
65275872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things:
65285872bbf2SRichard Henderson 
65295872bbf2SRichard Henderson    (1) Define ELF_HOST_MACHINE to indicate both what value to
65305872bbf2SRichard Henderson        put into the ELF image and to indicate support for the feature.
65315872bbf2SRichard Henderson 
65325872bbf2SRichard Henderson    (2) Define tcg_register_jit.  This should create a buffer containing
65335872bbf2SRichard Henderson        the contents of a .debug_frame section that describes the post-
65345872bbf2SRichard Henderson        prologue unwind info for the tcg machine.
65355872bbf2SRichard Henderson 
65365872bbf2SRichard Henderson    (3) Call tcg_register_jit_int, with the constructed .debug_frame.
65375872bbf2SRichard Henderson */
6538813da627SRichard Henderson 
6539813da627SRichard Henderson /* Begin GDB interface.  THE FOLLOWING MUST MATCH GDB DOCS.  */
6540813da627SRichard Henderson typedef enum {
6541813da627SRichard Henderson     JIT_NOACTION = 0,
6542813da627SRichard Henderson     JIT_REGISTER_FN,
6543813da627SRichard Henderson     JIT_UNREGISTER_FN
6544813da627SRichard Henderson } jit_actions_t;
6545813da627SRichard Henderson 
6546813da627SRichard Henderson struct jit_code_entry {
6547813da627SRichard Henderson     struct jit_code_entry *next_entry;
6548813da627SRichard Henderson     struct jit_code_entry *prev_entry;
6549813da627SRichard Henderson     const void *symfile_addr;
6550813da627SRichard Henderson     uint64_t symfile_size;
6551813da627SRichard Henderson };
6552813da627SRichard Henderson 
6553813da627SRichard Henderson struct jit_descriptor {
6554813da627SRichard Henderson     uint32_t version;
6555813da627SRichard Henderson     uint32_t action_flag;
6556813da627SRichard Henderson     struct jit_code_entry *relevant_entry;
6557813da627SRichard Henderson     struct jit_code_entry *first_entry;
6558813da627SRichard Henderson };
6559813da627SRichard Henderson 
6560813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline));
6561813da627SRichard Henderson void __jit_debug_register_code(void)
6562813da627SRichard Henderson {
6563813da627SRichard Henderson     asm("");
6564813da627SRichard Henderson }
6565813da627SRichard Henderson 
6566813da627SRichard Henderson /* Must statically initialize the version, because GDB may check
6567813da627SRichard Henderson    the version before we can set it.  */
6568813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
6569813da627SRichard Henderson 
6570813da627SRichard Henderson /* End GDB interface.  */
6571813da627SRichard Henderson 
6572813da627SRichard Henderson static int find_string(const char *strtab, const char *str)
6573813da627SRichard Henderson {
6574813da627SRichard Henderson     const char *p = strtab + 1;
6575813da627SRichard Henderson 
6576813da627SRichard Henderson     while (1) {
6577813da627SRichard Henderson         if (strcmp(p, str) == 0) {
6578813da627SRichard Henderson             return p - strtab;
6579813da627SRichard Henderson         }
6580813da627SRichard Henderson         p += strlen(p) + 1;
6581813da627SRichard Henderson     }
6582813da627SRichard Henderson }
6583813da627SRichard Henderson 
6584755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf_ptr, size_t buf_size,
65852c90784aSRichard Henderson                                  const void *debug_frame,
65862c90784aSRichard Henderson                                  size_t debug_frame_size)
6587813da627SRichard Henderson {
65885872bbf2SRichard Henderson     struct __attribute__((packed)) DebugInfo {
65895872bbf2SRichard Henderson         uint32_t  len;
65905872bbf2SRichard Henderson         uint16_t  version;
65915872bbf2SRichard Henderson         uint32_t  abbrev;
65925872bbf2SRichard Henderson         uint8_t   ptr_size;
65935872bbf2SRichard Henderson         uint8_t   cu_die;
65945872bbf2SRichard Henderson         uint16_t  cu_lang;
65955872bbf2SRichard Henderson         uintptr_t cu_low_pc;
65965872bbf2SRichard Henderson         uintptr_t cu_high_pc;
65975872bbf2SRichard Henderson         uint8_t   fn_die;
65985872bbf2SRichard Henderson         char      fn_name[16];
65995872bbf2SRichard Henderson         uintptr_t fn_low_pc;
66005872bbf2SRichard Henderson         uintptr_t fn_high_pc;
66015872bbf2SRichard Henderson         uint8_t   cu_eoc;
66025872bbf2SRichard Henderson     };
6603813da627SRichard Henderson 
6604813da627SRichard Henderson     struct ElfImage {
6605813da627SRichard Henderson         ElfW(Ehdr) ehdr;
6606813da627SRichard Henderson         ElfW(Phdr) phdr;
66075872bbf2SRichard Henderson         ElfW(Shdr) shdr[7];
66085872bbf2SRichard Henderson         ElfW(Sym)  sym[2];
66095872bbf2SRichard Henderson         struct DebugInfo di;
66105872bbf2SRichard Henderson         uint8_t    da[24];
66115872bbf2SRichard Henderson         char       str[80];
66125872bbf2SRichard Henderson     };
66135872bbf2SRichard Henderson 
66145872bbf2SRichard Henderson     struct ElfImage *img;
66155872bbf2SRichard Henderson 
66165872bbf2SRichard Henderson     static const struct ElfImage img_template = {
66175872bbf2SRichard Henderson         .ehdr = {
66185872bbf2SRichard Henderson             .e_ident[EI_MAG0] = ELFMAG0,
66195872bbf2SRichard Henderson             .e_ident[EI_MAG1] = ELFMAG1,
66205872bbf2SRichard Henderson             .e_ident[EI_MAG2] = ELFMAG2,
66215872bbf2SRichard Henderson             .e_ident[EI_MAG3] = ELFMAG3,
66225872bbf2SRichard Henderson             .e_ident[EI_CLASS] = ELF_CLASS,
66235872bbf2SRichard Henderson             .e_ident[EI_DATA] = ELF_DATA,
66245872bbf2SRichard Henderson             .e_ident[EI_VERSION] = EV_CURRENT,
66255872bbf2SRichard Henderson             .e_type = ET_EXEC,
66265872bbf2SRichard Henderson             .e_machine = ELF_HOST_MACHINE,
66275872bbf2SRichard Henderson             .e_version = EV_CURRENT,
66285872bbf2SRichard Henderson             .e_phoff = offsetof(struct ElfImage, phdr),
66295872bbf2SRichard Henderson             .e_shoff = offsetof(struct ElfImage, shdr),
66305872bbf2SRichard Henderson             .e_ehsize = sizeof(ElfW(Shdr)),
66315872bbf2SRichard Henderson             .e_phentsize = sizeof(ElfW(Phdr)),
66325872bbf2SRichard Henderson             .e_phnum = 1,
66335872bbf2SRichard Henderson             .e_shentsize = sizeof(ElfW(Shdr)),
66345872bbf2SRichard Henderson             .e_shnum = ARRAY_SIZE(img->shdr),
66355872bbf2SRichard Henderson             .e_shstrndx = ARRAY_SIZE(img->shdr) - 1,
6636abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS
6637abbb3eaeSRichard Henderson             .e_flags = ELF_HOST_FLAGS,
6638abbb3eaeSRichard Henderson #endif
6639abbb3eaeSRichard Henderson #ifdef ELF_OSABI
6640abbb3eaeSRichard Henderson             .e_ident[EI_OSABI] = ELF_OSABI,
6641abbb3eaeSRichard Henderson #endif
66425872bbf2SRichard Henderson         },
66435872bbf2SRichard Henderson         .phdr = {
66445872bbf2SRichard Henderson             .p_type = PT_LOAD,
66455872bbf2SRichard Henderson             .p_flags = PF_X,
66465872bbf2SRichard Henderson         },
66475872bbf2SRichard Henderson         .shdr = {
66485872bbf2SRichard Henderson             [0] = { .sh_type = SHT_NULL },
66495872bbf2SRichard Henderson             /* Trick: The contents of code_gen_buffer are not present in
66505872bbf2SRichard Henderson                this fake ELF file; that got allocated elsewhere.  Therefore
66515872bbf2SRichard Henderson                we mark .text as SHT_NOBITS (similar to .bss) so that readers
66525872bbf2SRichard Henderson                will not look for contents.  We can record any address.  */
66535872bbf2SRichard Henderson             [1] = { /* .text */
66545872bbf2SRichard Henderson                 .sh_type = SHT_NOBITS,
66555872bbf2SRichard Henderson                 .sh_flags = SHF_EXECINSTR | SHF_ALLOC,
66565872bbf2SRichard Henderson             },
66575872bbf2SRichard Henderson             [2] = { /* .debug_info */
66585872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
66595872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, di),
66605872bbf2SRichard Henderson                 .sh_size = sizeof(struct DebugInfo),
66615872bbf2SRichard Henderson             },
66625872bbf2SRichard Henderson             [3] = { /* .debug_abbrev */
66635872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
66645872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, da),
66655872bbf2SRichard Henderson                 .sh_size = sizeof(img->da),
66665872bbf2SRichard Henderson             },
66675872bbf2SRichard Henderson             [4] = { /* .debug_frame */
66685872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
66695872bbf2SRichard Henderson                 .sh_offset = sizeof(struct ElfImage),
66705872bbf2SRichard Henderson             },
66715872bbf2SRichard Henderson             [5] = { /* .symtab */
66725872bbf2SRichard Henderson                 .sh_type = SHT_SYMTAB,
66735872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, sym),
66745872bbf2SRichard Henderson                 .sh_size = sizeof(img->sym),
66755872bbf2SRichard Henderson                 .sh_info = 1,
66765872bbf2SRichard Henderson                 .sh_link = ARRAY_SIZE(img->shdr) - 1,
66775872bbf2SRichard Henderson                 .sh_entsize = sizeof(ElfW(Sym)),
66785872bbf2SRichard Henderson             },
66795872bbf2SRichard Henderson             [6] = { /* .strtab */
66805872bbf2SRichard Henderson                 .sh_type = SHT_STRTAB,
66815872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, str),
66825872bbf2SRichard Henderson                 .sh_size = sizeof(img->str),
66835872bbf2SRichard Henderson             }
66845872bbf2SRichard Henderson         },
66855872bbf2SRichard Henderson         .sym = {
66865872bbf2SRichard Henderson             [1] = { /* code_gen_buffer */
66875872bbf2SRichard Henderson                 .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC),
66885872bbf2SRichard Henderson                 .st_shndx = 1,
66895872bbf2SRichard Henderson             }
66905872bbf2SRichard Henderson         },
66915872bbf2SRichard Henderson         .di = {
66925872bbf2SRichard Henderson             .len = sizeof(struct DebugInfo) - 4,
66935872bbf2SRichard Henderson             .version = 2,
66945872bbf2SRichard Henderson             .ptr_size = sizeof(void *),
66955872bbf2SRichard Henderson             .cu_die = 1,
66965872bbf2SRichard Henderson             .cu_lang = 0x8001,  /* DW_LANG_Mips_Assembler */
66975872bbf2SRichard Henderson             .fn_die = 2,
66985872bbf2SRichard Henderson             .fn_name = "code_gen_buffer"
66995872bbf2SRichard Henderson         },
67005872bbf2SRichard Henderson         .da = {
67015872bbf2SRichard Henderson             1,          /* abbrev number (the cu) */
67025872bbf2SRichard Henderson             0x11, 1,    /* DW_TAG_compile_unit, has children */
67035872bbf2SRichard Henderson             0x13, 0x5,  /* DW_AT_language, DW_FORM_data2 */
67045872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
67055872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
67065872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
67075872bbf2SRichard Henderson             2,          /* abbrev number (the fn) */
67085872bbf2SRichard Henderson             0x2e, 0,    /* DW_TAG_subprogram, no children */
67095872bbf2SRichard Henderson             0x3, 0x8,   /* DW_AT_name, DW_FORM_string */
67105872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
67115872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
67125872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
67135872bbf2SRichard Henderson             0           /* no more abbrev */
67145872bbf2SRichard Henderson         },
67155872bbf2SRichard Henderson         .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0"
67165872bbf2SRichard Henderson                ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer",
6717813da627SRichard Henderson     };
6718813da627SRichard Henderson 
6719813da627SRichard Henderson     /* We only need a single jit entry; statically allocate it.  */
6720813da627SRichard Henderson     static struct jit_code_entry one_entry;
6721813da627SRichard Henderson 
67225872bbf2SRichard Henderson     uintptr_t buf = (uintptr_t)buf_ptr;
6723813da627SRichard Henderson     size_t img_size = sizeof(struct ElfImage) + debug_frame_size;
67242c90784aSRichard Henderson     DebugFrameHeader *dfh;
6725813da627SRichard Henderson 
67265872bbf2SRichard Henderson     img = g_malloc(img_size);
67275872bbf2SRichard Henderson     *img = img_template;
6728813da627SRichard Henderson 
67295872bbf2SRichard Henderson     img->phdr.p_vaddr = buf;
67305872bbf2SRichard Henderson     img->phdr.p_paddr = buf;
67315872bbf2SRichard Henderson     img->phdr.p_memsz = buf_size;
6732813da627SRichard Henderson 
67335872bbf2SRichard Henderson     img->shdr[1].sh_name = find_string(img->str, ".text");
67345872bbf2SRichard Henderson     img->shdr[1].sh_addr = buf;
67355872bbf2SRichard Henderson     img->shdr[1].sh_size = buf_size;
6736813da627SRichard Henderson 
67375872bbf2SRichard Henderson     img->shdr[2].sh_name = find_string(img->str, ".debug_info");
67385872bbf2SRichard Henderson     img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev");
67395872bbf2SRichard Henderson 
67405872bbf2SRichard Henderson     img->shdr[4].sh_name = find_string(img->str, ".debug_frame");
67415872bbf2SRichard Henderson     img->shdr[4].sh_size = debug_frame_size;
67425872bbf2SRichard Henderson 
67435872bbf2SRichard Henderson     img->shdr[5].sh_name = find_string(img->str, ".symtab");
67445872bbf2SRichard Henderson     img->shdr[6].sh_name = find_string(img->str, ".strtab");
67455872bbf2SRichard Henderson 
67465872bbf2SRichard Henderson     img->sym[1].st_name = find_string(img->str, "code_gen_buffer");
67475872bbf2SRichard Henderson     img->sym[1].st_value = buf;
67485872bbf2SRichard Henderson     img->sym[1].st_size = buf_size;
67495872bbf2SRichard Henderson 
67505872bbf2SRichard Henderson     img->di.cu_low_pc = buf;
675145aba097SRichard Henderson     img->di.cu_high_pc = buf + buf_size;
67525872bbf2SRichard Henderson     img->di.fn_low_pc = buf;
675345aba097SRichard Henderson     img->di.fn_high_pc = buf + buf_size;
6754813da627SRichard Henderson 
67552c90784aSRichard Henderson     dfh = (DebugFrameHeader *)(img + 1);
67562c90784aSRichard Henderson     memcpy(dfh, debug_frame, debug_frame_size);
67572c90784aSRichard Henderson     dfh->fde.func_start = buf;
67582c90784aSRichard Henderson     dfh->fde.func_len = buf_size;
67592c90784aSRichard Henderson 
6760813da627SRichard Henderson #ifdef DEBUG_JIT
6761813da627SRichard Henderson     /* Enable this block to be able to debug the ELF image file creation.
6762813da627SRichard Henderson        One can use readelf, objdump, or other inspection utilities.  */
6763813da627SRichard Henderson     {
6764eb6b2edfSBin Meng         g_autofree char *jit = g_strdup_printf("%s/qemu.jit", g_get_tmp_dir());
6765eb6b2edfSBin Meng         FILE *f = fopen(jit, "w+b");
6766813da627SRichard Henderson         if (f) {
67675872bbf2SRichard Henderson             if (fwrite(img, img_size, 1, f) != img_size) {
6768813da627SRichard Henderson                 /* Avoid stupid unused return value warning for fwrite.  */
6769813da627SRichard Henderson             }
6770813da627SRichard Henderson             fclose(f);
6771813da627SRichard Henderson         }
6772813da627SRichard Henderson     }
6773813da627SRichard Henderson #endif
6774813da627SRichard Henderson 
6775813da627SRichard Henderson     one_entry.symfile_addr = img;
6776813da627SRichard Henderson     one_entry.symfile_size = img_size;
6777813da627SRichard Henderson 
6778813da627SRichard Henderson     __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
6779813da627SRichard Henderson     __jit_debug_descriptor.relevant_entry = &one_entry;
6780813da627SRichard Henderson     __jit_debug_descriptor.first_entry = &one_entry;
6781813da627SRichard Henderson     __jit_debug_register_code();
6782813da627SRichard Henderson }
6783813da627SRichard Henderson #else
67845872bbf2SRichard Henderson /* No support for the feature.  Provide the entry point expected by exec.c,
67855872bbf2SRichard Henderson    and implement the internal function we declared earlier.  */
6786813da627SRichard Henderson 
6787755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size,
67882c90784aSRichard Henderson                                  const void *debug_frame,
67892c90784aSRichard Henderson                                  size_t debug_frame_size)
6790813da627SRichard Henderson {
6791813da627SRichard Henderson }
6792813da627SRichard Henderson 
6793755bf9e5SRichard Henderson void tcg_register_jit(const void *buf, size_t buf_size)
6794813da627SRichard Henderson {
6795813da627SRichard Henderson }
6796813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */
6797db432672SRichard Henderson 
6798db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec
6799db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...)
6800db432672SRichard Henderson {
6801db432672SRichard Henderson     g_assert_not_reached();
6802db432672SRichard Henderson }
6803db432672SRichard Henderson #endif
6804