xref: /qemu/tcg/tcg.c (revision c742824dd8df3283098d5339291d49e65e515751)
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 */
1030cd38379SRichard Henderson     TCGReg addr_reg;        /* reg index for guest virtual addr */
1042528f771SRichard Henderson     TCGReg datalo_reg;      /* reg index for low word to be loaded or stored */
1052528f771SRichard Henderson     TCGReg datahi_reg;      /* reg index for high word to be loaded or stored */
1062528f771SRichard Henderson     const tcg_insn_unit *raddr;   /* addr of the next IR of qemu_ld/st IR */
1072528f771SRichard Henderson     tcg_insn_unit *label_ptr[2]; /* label pointers to be updated */
1082528f771SRichard Henderson     QSIMPLEQ_ENTRY(TCGLabelQemuLdst) next;
109a417ef83SRichard Henderson };
1102528f771SRichard Henderson 
111755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size,
1122c90784aSRichard Henderson                                  const void *debug_frame,
1132c90784aSRichard Henderson                                  size_t debug_frame_size)
114813da627SRichard Henderson     __attribute__((unused));
115813da627SRichard Henderson 
116139c1837SPaolo Bonzini /* Forward declarations for functions declared and used in tcg-target.c.inc. */
1179358fbbfSRichard Henderson static void tcg_out_tb_start(TCGContext *s);
1182a534affSRichard Henderson static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
119a05b5b9bSRichard Henderson                        intptr_t arg2);
12078113e83SRichard Henderson static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
121c0ad3001SStefan Weil static void tcg_out_movi(TCGContext *s, TCGType type,
1222a534affSRichard Henderson                          TCGReg ret, tcg_target_long arg);
123678155b2SRichard Henderson static void tcg_out_ext8s(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
124753e42eaSRichard Henderson static void tcg_out_ext16s(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
125d0e66c89SRichard Henderson static void tcg_out_ext8u(TCGContext *s, TCGReg ret, TCGReg arg);
126379afdffSRichard Henderson static void tcg_out_ext16u(TCGContext *s, TCGReg ret, TCGReg arg);
12752bf3398SRichard Henderson static void tcg_out_ext32s(TCGContext *s, TCGReg ret, TCGReg arg);
1289ecf5f61SRichard Henderson static void tcg_out_ext32u(TCGContext *s, TCGReg ret, TCGReg arg);
1299c6aa274SRichard Henderson static void tcg_out_exts_i32_i64(TCGContext *s, TCGReg ret, TCGReg arg);
130b9bfe000SRichard Henderson static void tcg_out_extu_i32_i64(TCGContext *s, TCGReg ret, TCGReg arg);
131b8b94ac6SRichard Henderson static void tcg_out_extrl_i64_i32(TCGContext *s, TCGReg ret, TCGReg arg);
132313bdea8SRichard Henderson static void tcg_out_addi_ptr(TCGContext *s, TCGReg, TCGReg, tcg_target_long);
133129f1f9eSRichard Henderson static bool tcg_out_xchg(TCGContext *s, TCGType type, TCGReg r1, TCGReg r2);
134b55a8d9dSRichard Henderson static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg);
135cf7d6b8eSRichard Henderson static void tcg_out_goto_tb(TCGContext *s, int which);
1364e350091SRichard Henderson static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type,
1375e8892dbSMiroslav Rezanina                        const TCGArg args[TCG_MAX_OP_ARGS],
1385e8892dbSMiroslav Rezanina                        const int const_args[TCG_MAX_OP_ARGS]);
139d2fd745fSRichard Henderson #if TCG_TARGET_MAYBE_vec
140e7632cfaSRichard Henderson static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
141e7632cfaSRichard Henderson                             TCGReg dst, TCGReg src);
142d6ecb4a9SRichard Henderson static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
143d6ecb4a9SRichard Henderson                              TCGReg dst, TCGReg base, intptr_t offset);
1444e186175SRichard Henderson static void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece,
1454e186175SRichard Henderson                              TCGReg dst, int64_t arg);
1465e8892dbSMiroslav Rezanina static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
1475e8892dbSMiroslav Rezanina                            unsigned vecl, unsigned vece,
1485e8892dbSMiroslav Rezanina                            const TCGArg args[TCG_MAX_OP_ARGS],
1495e8892dbSMiroslav Rezanina                            const int const_args[TCG_MAX_OP_ARGS]);
150d2fd745fSRichard Henderson #else
151e7632cfaSRichard Henderson static inline bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
152e7632cfaSRichard Henderson                                    TCGReg dst, TCGReg src)
153e7632cfaSRichard Henderson {
154e7632cfaSRichard Henderson     g_assert_not_reached();
155e7632cfaSRichard Henderson }
156d6ecb4a9SRichard Henderson static inline bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
157d6ecb4a9SRichard Henderson                                     TCGReg dst, TCGReg base, intptr_t offset)
158d6ecb4a9SRichard Henderson {
159d6ecb4a9SRichard Henderson     g_assert_not_reached();
160d6ecb4a9SRichard Henderson }
1614e186175SRichard Henderson static inline void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece,
1624e186175SRichard Henderson                                     TCGReg dst, int64_t arg)
163e7632cfaSRichard Henderson {
164e7632cfaSRichard Henderson     g_assert_not_reached();
165e7632cfaSRichard Henderson }
1665e8892dbSMiroslav Rezanina static inline void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
1675e8892dbSMiroslav Rezanina                                   unsigned vecl, unsigned vece,
1685e8892dbSMiroslav Rezanina                                   const TCGArg args[TCG_MAX_OP_ARGS],
1695e8892dbSMiroslav Rezanina                                   const int const_args[TCG_MAX_OP_ARGS])
170d2fd745fSRichard Henderson {
171d2fd745fSRichard Henderson     g_assert_not_reached();
172d2fd745fSRichard Henderson }
1737d3e705aSRichard Henderson int tcg_can_emit_vec_op(TCGOpcode o, TCGType t, unsigned ve)
1747d3e705aSRichard Henderson {
1757d3e705aSRichard Henderson     return 0;
1767d3e705aSRichard Henderson }
177d2fd745fSRichard Henderson #endif
1782a534affSRichard Henderson static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
179a05b5b9bSRichard Henderson                        intptr_t arg2);
18059d7c14eSRichard Henderson static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
18159d7c14eSRichard Henderson                         TCGReg base, intptr_t ofs);
1827b7d8b2dSRichard Henderson static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target,
183cee44b03SRichard Henderson                          const TCGHelperInfo *info);
1845e3d0c19SRichard Henderson static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot);
18521e9a8aeSRichard Henderson static bool tcg_target_const_match(int64_t val, int ct,
18621e9a8aeSRichard Henderson                                    TCGType type, TCGCond cond, int vece);
187c896fe29Sbellard 
18823088ca0SRichard Henderson #ifndef CONFIG_USER_ONLY
18923088ca0SRichard Henderson #define guest_base  ({ qemu_build_not_reached(); (uintptr_t)0; })
19023088ca0SRichard Henderson #endif
19123088ca0SRichard Henderson 
1928429a1caSRichard Henderson typedef struct TCGLdstHelperParam {
1938429a1caSRichard Henderson     TCGReg (*ra_gen)(TCGContext *s, const TCGLabelQemuLdst *l, int arg_reg);
1948429a1caSRichard Henderson     unsigned ntmp;
1958429a1caSRichard Henderson     int tmp[3];
1968429a1caSRichard Henderson } TCGLdstHelperParam;
1978429a1caSRichard Henderson 
1988429a1caSRichard Henderson static void tcg_out_ld_helper_args(TCGContext *s, const TCGLabelQemuLdst *l,
1998429a1caSRichard Henderson                                    const TCGLdstHelperParam *p)
2008429a1caSRichard Henderson     __attribute__((unused));
2018429a1caSRichard Henderson static void tcg_out_ld_helper_ret(TCGContext *s, const TCGLabelQemuLdst *l,
2028429a1caSRichard Henderson                                   bool load_sign, const TCGLdstHelperParam *p)
2038429a1caSRichard Henderson     __attribute__((unused));
2048429a1caSRichard Henderson static void tcg_out_st_helper_args(TCGContext *s, const TCGLabelQemuLdst *l,
2058429a1caSRichard Henderson                                    const TCGLdstHelperParam *p)
2068429a1caSRichard Henderson     __attribute__((unused));
2078429a1caSRichard Henderson 
208de95016dSRichard Henderson static void * const qemu_ld_helpers[MO_SSIZE + 1] __attribute__((unused)) = {
2090cadc1edSRichard Henderson     [MO_UB] = helper_ldub_mmu,
2100cadc1edSRichard Henderson     [MO_SB] = helper_ldsb_mmu,
2110cadc1edSRichard Henderson     [MO_UW] = helper_lduw_mmu,
2120cadc1edSRichard Henderson     [MO_SW] = helper_ldsw_mmu,
2130cadc1edSRichard Henderson     [MO_UL] = helper_ldul_mmu,
2140cadc1edSRichard Henderson     [MO_UQ] = helper_ldq_mmu,
2150cadc1edSRichard Henderson #if TCG_TARGET_REG_BITS == 64
2160cadc1edSRichard Henderson     [MO_SL] = helper_ldsl_mmu,
217ebebea53SRichard Henderson     [MO_128] = helper_ld16_mmu,
2180cadc1edSRichard Henderson #endif
2190cadc1edSRichard Henderson };
2200cadc1edSRichard Henderson 
221de95016dSRichard Henderson static void * const qemu_st_helpers[MO_SIZE + 1] __attribute__((unused)) = {
2220cadc1edSRichard Henderson     [MO_8]  = helper_stb_mmu,
2230cadc1edSRichard Henderson     [MO_16] = helper_stw_mmu,
2240cadc1edSRichard Henderson     [MO_32] = helper_stl_mmu,
2250cadc1edSRichard Henderson     [MO_64] = helper_stq_mmu,
226ebebea53SRichard Henderson #if TCG_TARGET_REG_BITS == 64
227ebebea53SRichard Henderson     [MO_128] = helper_st16_mmu,
228ebebea53SRichard Henderson #endif
2290cadc1edSRichard Henderson };
2300cadc1edSRichard Henderson 
231e63b8a29SRichard Henderson typedef struct {
232e63b8a29SRichard Henderson     MemOp atom;   /* lg2 bits of atomicity required */
233e63b8a29SRichard Henderson     MemOp align;  /* lg2 bits of alignment to use */
234e63b8a29SRichard Henderson } TCGAtomAlign;
235e63b8a29SRichard Henderson 
236e63b8a29SRichard Henderson static TCGAtomAlign atom_and_align_for_opc(TCGContext *s, MemOp opc,
237e63b8a29SRichard Henderson                                            MemOp host_atom, bool allow_two_ops)
238e63b8a29SRichard Henderson     __attribute__((unused));
239e63b8a29SRichard Henderson 
240397cabaaSRichard Henderson #ifdef CONFIG_USER_ONLY
241397cabaaSRichard Henderson bool tcg_use_softmmu;
242397cabaaSRichard Henderson #endif
243397cabaaSRichard Henderson 
24442eb6dfcSRichard Henderson TCGContext tcg_init_ctx;
24542eb6dfcSRichard Henderson __thread TCGContext *tcg_ctx;
24642eb6dfcSRichard Henderson 
2475ff7258cSRichard Henderson TCGContext **tcg_ctxs;
2480e2d61cfSRichard Henderson unsigned int tcg_cur_ctxs;
2490e2d61cfSRichard Henderson unsigned int tcg_max_ctxs;
250ad75a51eSRichard Henderson TCGv_env tcg_env;
251c8bc1168SRichard Henderson const void *tcg_code_gen_epilogue;
252db0c51a3SRichard Henderson uintptr_t tcg_splitwx_diff;
253df2cce29SEmilio G. Cota 
254b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
255b91ccb31SRichard Henderson tcg_prologue_fn *tcg_qemu_tb_exec;
256b91ccb31SRichard Henderson #endif
257b91ccb31SRichard Henderson 
258d2fd745fSRichard Henderson static TCGRegSet tcg_target_available_regs[TCG_TYPE_COUNT];
259b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs;
260c896fe29Sbellard 
2611813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1
2624196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v)
263c896fe29Sbellard {
264c896fe29Sbellard     *s->code_ptr++ = v;
265c896fe29Sbellard }
266c896fe29Sbellard 
2674196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p,
2684196dca6SPeter Maydell                                                       uint8_t v)
2695c53bb81SPeter Maydell {
2701813e175SRichard Henderson     *p = v;
2715c53bb81SPeter Maydell }
2721813e175SRichard Henderson #endif
2735c53bb81SPeter Maydell 
2741813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2
2754196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v)
276c896fe29Sbellard {
2771813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
2781813e175SRichard Henderson         *s->code_ptr++ = v;
2791813e175SRichard Henderson     } else {
2801813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2814387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2821813e175SRichard Henderson         s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE);
2831813e175SRichard Henderson     }
284c896fe29Sbellard }
285c896fe29Sbellard 
2864196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p,
2874196dca6SPeter Maydell                                                        uint16_t v)
2885c53bb81SPeter Maydell {
2891813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
2901813e175SRichard Henderson         *p = v;
2911813e175SRichard Henderson     } else {
2925c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2935c53bb81SPeter Maydell     }
2941813e175SRichard Henderson }
2951813e175SRichard Henderson #endif
2965c53bb81SPeter Maydell 
2971813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4
2984196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v)
299c896fe29Sbellard {
3001813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
3011813e175SRichard Henderson         *s->code_ptr++ = v;
3021813e175SRichard Henderson     } else {
3031813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
3044387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
3051813e175SRichard Henderson         s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE);
3061813e175SRichard Henderson     }
307c896fe29Sbellard }
308c896fe29Sbellard 
3094196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p,
3104196dca6SPeter Maydell                                                        uint32_t v)
3115c53bb81SPeter Maydell {
3121813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
3131813e175SRichard Henderson         *p = v;
3141813e175SRichard Henderson     } else {
3155c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
3165c53bb81SPeter Maydell     }
3171813e175SRichard Henderson }
3181813e175SRichard Henderson #endif
3195c53bb81SPeter Maydell 
3201813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 8
3214196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v)
322ac26eb69SRichard Henderson {
3231813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
3241813e175SRichard Henderson         *s->code_ptr++ = v;
3251813e175SRichard Henderson     } else {
3261813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
3274387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
3281813e175SRichard Henderson         s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE);
3291813e175SRichard Henderson     }
330ac26eb69SRichard Henderson }
331ac26eb69SRichard Henderson 
3324196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p,
3334196dca6SPeter Maydell                                                        uint64_t v)
3345c53bb81SPeter Maydell {
3351813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
3361813e175SRichard Henderson         *p = v;
3371813e175SRichard Henderson     } else {
3385c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
3395c53bb81SPeter Maydell     }
3401813e175SRichard Henderson }
3411813e175SRichard Henderson #endif
3425c53bb81SPeter Maydell 
343c896fe29Sbellard /* label relocation processing */
344c896fe29Sbellard 
3451813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
346bec16311SRichard Henderson                           TCGLabel *l, intptr_t addend)
347c896fe29Sbellard {
3487ecd02a0SRichard Henderson     TCGRelocation *r = tcg_malloc(sizeof(TCGRelocation));
349c896fe29Sbellard 
350c896fe29Sbellard     r->type = type;
351c896fe29Sbellard     r->ptr = code_ptr;
352c896fe29Sbellard     r->addend = addend;
3537ecd02a0SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next);
354c896fe29Sbellard }
355c896fe29Sbellard 
35692ab8e7dSRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l)
357c896fe29Sbellard {
358eabb7b91SAurelien Jarno     tcg_debug_assert(!l->has_value);
359c896fe29Sbellard     l->has_value = 1;
36092ab8e7dSRichard Henderson     l->u.value_ptr = tcg_splitwx_to_rx(s->code_ptr);
361c896fe29Sbellard }
362c896fe29Sbellard 
36342a268c2SRichard Henderson TCGLabel *gen_new_label(void)
364c896fe29Sbellard {
365b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
36651e3972cSRichard Henderson     TCGLabel *l = tcg_malloc(sizeof(TCGLabel));
367c896fe29Sbellard 
3687ecd02a0SRichard Henderson     memset(l, 0, sizeof(TCGLabel));
3697ecd02a0SRichard Henderson     l->id = s->nb_labels++;
370f85b1fc4SRichard Henderson     QSIMPLEQ_INIT(&l->branches);
3717ecd02a0SRichard Henderson     QSIMPLEQ_INIT(&l->relocs);
3727ecd02a0SRichard Henderson 
373bef16ab4SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&s->labels, l, next);
37442a268c2SRichard Henderson 
37542a268c2SRichard Henderson     return l;
376c896fe29Sbellard }
377c896fe29Sbellard 
3787ecd02a0SRichard Henderson static bool tcg_resolve_relocs(TCGContext *s)
3797ecd02a0SRichard Henderson {
3807ecd02a0SRichard Henderson     TCGLabel *l;
3817ecd02a0SRichard Henderson 
3827ecd02a0SRichard Henderson     QSIMPLEQ_FOREACH(l, &s->labels, next) {
3837ecd02a0SRichard Henderson         TCGRelocation *r;
3847ecd02a0SRichard Henderson         uintptr_t value = l->u.value;
3857ecd02a0SRichard Henderson 
3867ecd02a0SRichard Henderson         QSIMPLEQ_FOREACH(r, &l->relocs, next) {
3877ecd02a0SRichard Henderson             if (!patch_reloc(r->ptr, r->type, value, r->addend)) {
3887ecd02a0SRichard Henderson                 return false;
3897ecd02a0SRichard Henderson             }
3907ecd02a0SRichard Henderson         }
3917ecd02a0SRichard Henderson     }
3927ecd02a0SRichard Henderson     return true;
3937ecd02a0SRichard Henderson }
3947ecd02a0SRichard Henderson 
3959f754620SRichard Henderson static void set_jmp_reset_offset(TCGContext *s, int which)
3969f754620SRichard Henderson {
397f14bed3fSRichard Henderson     /*
398f14bed3fSRichard Henderson      * We will check for overflow at the end of the opcode loop in
399f14bed3fSRichard Henderson      * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX.
400f14bed3fSRichard Henderson      */
401b7e4afbdSRichard Henderson     s->gen_tb->jmp_reset_offset[which] = tcg_current_code_size(s);
4029f754620SRichard Henderson }
4039f754620SRichard Henderson 
404b52a2c03SRichard Henderson static void G_GNUC_UNUSED set_jmp_insn_offset(TCGContext *s, int which)
405b52a2c03SRichard Henderson {
406b52a2c03SRichard Henderson     /*
407b52a2c03SRichard Henderson      * We will check for overflow at the end of the opcode loop in
408b52a2c03SRichard Henderson      * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX.
409b52a2c03SRichard Henderson      */
4109da6079bSRichard Henderson     s->gen_tb->jmp_insn_offset[which] = tcg_current_code_size(s);
411b52a2c03SRichard Henderson }
412b52a2c03SRichard Henderson 
413becc452aSRichard Henderson static uintptr_t G_GNUC_UNUSED get_jmp_target_addr(TCGContext *s, int which)
414becc452aSRichard Henderson {
415becc452aSRichard Henderson     /*
416becc452aSRichard Henderson      * Return the read-execute version of the pointer, for the benefit
417becc452aSRichard Henderson      * of any pc-relative addressing mode.
418becc452aSRichard Henderson      */
4199da6079bSRichard Henderson     return (uintptr_t)tcg_splitwx_to_rx(&s->gen_tb->jmp_target_addr[which]);
420becc452aSRichard Henderson }
421becc452aSRichard Henderson 
422397cabaaSRichard Henderson static int __attribute__((unused))
423397cabaaSRichard Henderson tlb_mask_table_ofs(TCGContext *s, int which)
424d0a9bb5eSRichard Henderson {
4257857ee11SRichard Henderson     return (offsetof(CPUNegativeOffsetState, tlb.f[which]) -
4267857ee11SRichard Henderson             sizeof(CPUNegativeOffsetState));
427d0a9bb5eSRichard Henderson }
428d0a9bb5eSRichard Henderson 
429db6b7d0cSRichard Henderson /* Signal overflow, starting over with fewer guest insns. */
4308905770bSMarc-André Lureau static G_NORETURN
4318905770bSMarc-André Lureau void tcg_raise_tb_overflow(TCGContext *s)
432db6b7d0cSRichard Henderson {
433db6b7d0cSRichard Henderson     siglongjmp(s->jmp_trans, -2);
434db6b7d0cSRichard Henderson }
435db6b7d0cSRichard Henderson 
4368429a1caSRichard Henderson /*
4378429a1caSRichard Henderson  * Used by tcg_out_movext{1,2} to hold the arguments for tcg_out_movext.
4388429a1caSRichard Henderson  * By the time we arrive at tcg_out_movext1, @dst is always a TCGReg.
4398429a1caSRichard Henderson  *
4408429a1caSRichard Henderson  * However, tcg_out_helper_load_slots reuses this field to hold an
4418429a1caSRichard Henderson  * argument slot number (which may designate a argument register or an
4428429a1caSRichard Henderson  * argument stack slot), converting to TCGReg once all arguments that
4438429a1caSRichard Henderson  * are destined for the stack are processed.
4448429a1caSRichard Henderson  */
445129f1f9eSRichard Henderson typedef struct TCGMovExtend {
4468429a1caSRichard Henderson     unsigned dst;
447129f1f9eSRichard Henderson     TCGReg src;
448129f1f9eSRichard Henderson     TCGType dst_type;
449129f1f9eSRichard Henderson     TCGType src_type;
450129f1f9eSRichard Henderson     MemOp src_ext;
451129f1f9eSRichard Henderson } TCGMovExtend;
452129f1f9eSRichard Henderson 
453b3dfd5fcSRichard Henderson /**
454b3dfd5fcSRichard Henderson  * tcg_out_movext -- move and extend
455b3dfd5fcSRichard Henderson  * @s: tcg context
456b3dfd5fcSRichard Henderson  * @dst_type: integral type for destination
457b3dfd5fcSRichard Henderson  * @dst: destination register
458b3dfd5fcSRichard Henderson  * @src_type: integral type for source
459b3dfd5fcSRichard Henderson  * @src_ext: extension to apply to source
460b3dfd5fcSRichard Henderson  * @src: source register
461b3dfd5fcSRichard Henderson  *
462b3dfd5fcSRichard Henderson  * Move or extend @src into @dst, depending on @src_ext and the types.
463b3dfd5fcSRichard Henderson  */
464129f1f9eSRichard Henderson static void tcg_out_movext(TCGContext *s, TCGType dst_type, TCGReg dst,
465b3dfd5fcSRichard Henderson                            TCGType src_type, MemOp src_ext, TCGReg src)
466b3dfd5fcSRichard Henderson {
467b3dfd5fcSRichard Henderson     switch (src_ext) {
468b3dfd5fcSRichard Henderson     case MO_UB:
469b3dfd5fcSRichard Henderson         tcg_out_ext8u(s, dst, src);
470b3dfd5fcSRichard Henderson         break;
471b3dfd5fcSRichard Henderson     case MO_SB:
472b3dfd5fcSRichard Henderson         tcg_out_ext8s(s, dst_type, dst, src);
473b3dfd5fcSRichard Henderson         break;
474b3dfd5fcSRichard Henderson     case MO_UW:
475b3dfd5fcSRichard Henderson         tcg_out_ext16u(s, dst, src);
476b3dfd5fcSRichard Henderson         break;
477b3dfd5fcSRichard Henderson     case MO_SW:
478b3dfd5fcSRichard Henderson         tcg_out_ext16s(s, dst_type, dst, src);
479b3dfd5fcSRichard Henderson         break;
480b3dfd5fcSRichard Henderson     case MO_UL:
481b3dfd5fcSRichard Henderson     case MO_SL:
482b3dfd5fcSRichard Henderson         if (dst_type == TCG_TYPE_I32) {
483b3dfd5fcSRichard Henderson             if (src_type == TCG_TYPE_I32) {
484b3dfd5fcSRichard Henderson                 tcg_out_mov(s, TCG_TYPE_I32, dst, src);
485b3dfd5fcSRichard Henderson             } else {
486b3dfd5fcSRichard Henderson                 tcg_out_extrl_i64_i32(s, dst, src);
487b3dfd5fcSRichard Henderson             }
488b3dfd5fcSRichard Henderson         } else if (src_type == TCG_TYPE_I32) {
489b3dfd5fcSRichard Henderson             if (src_ext & MO_SIGN) {
490b3dfd5fcSRichard Henderson                 tcg_out_exts_i32_i64(s, dst, src);
491b3dfd5fcSRichard Henderson             } else {
492b3dfd5fcSRichard Henderson                 tcg_out_extu_i32_i64(s, dst, src);
493b3dfd5fcSRichard Henderson             }
494b3dfd5fcSRichard Henderson         } else {
495b3dfd5fcSRichard Henderson             if (src_ext & MO_SIGN) {
496b3dfd5fcSRichard Henderson                 tcg_out_ext32s(s, dst, src);
497b3dfd5fcSRichard Henderson             } else {
498b3dfd5fcSRichard Henderson                 tcg_out_ext32u(s, dst, src);
499b3dfd5fcSRichard Henderson             }
500b3dfd5fcSRichard Henderson         }
501b3dfd5fcSRichard Henderson         break;
502b3dfd5fcSRichard Henderson     case MO_UQ:
503b3dfd5fcSRichard Henderson         tcg_debug_assert(TCG_TARGET_REG_BITS == 64);
504b3dfd5fcSRichard Henderson         if (dst_type == TCG_TYPE_I32) {
505b3dfd5fcSRichard Henderson             tcg_out_extrl_i64_i32(s, dst, src);
506b3dfd5fcSRichard Henderson         } else {
507b3dfd5fcSRichard Henderson             tcg_out_mov(s, TCG_TYPE_I64, dst, src);
508b3dfd5fcSRichard Henderson         }
509b3dfd5fcSRichard Henderson         break;
510b3dfd5fcSRichard Henderson     default:
511b3dfd5fcSRichard Henderson         g_assert_not_reached();
512b3dfd5fcSRichard Henderson     }
513b3dfd5fcSRichard Henderson }
514b3dfd5fcSRichard Henderson 
515129f1f9eSRichard Henderson /* Minor variations on a theme, using a structure. */
516129f1f9eSRichard Henderson static void tcg_out_movext1_new_src(TCGContext *s, const TCGMovExtend *i,
517129f1f9eSRichard Henderson                                     TCGReg src)
518129f1f9eSRichard Henderson {
519129f1f9eSRichard Henderson     tcg_out_movext(s, i->dst_type, i->dst, i->src_type, i->src_ext, src);
520129f1f9eSRichard Henderson }
521129f1f9eSRichard Henderson 
522129f1f9eSRichard Henderson static void tcg_out_movext1(TCGContext *s, const TCGMovExtend *i)
523129f1f9eSRichard Henderson {
524129f1f9eSRichard Henderson     tcg_out_movext1_new_src(s, i, i->src);
525129f1f9eSRichard Henderson }
526129f1f9eSRichard Henderson 
527129f1f9eSRichard Henderson /**
528129f1f9eSRichard Henderson  * tcg_out_movext2 -- move and extend two pair
529129f1f9eSRichard Henderson  * @s: tcg context
530129f1f9eSRichard Henderson  * @i1: first move description
531129f1f9eSRichard Henderson  * @i2: second move description
532129f1f9eSRichard Henderson  * @scratch: temporary register, or -1 for none
533129f1f9eSRichard Henderson  *
534129f1f9eSRichard Henderson  * As tcg_out_movext, for both @i1 and @i2, caring for overlap
535129f1f9eSRichard Henderson  * between the sources and destinations.
536129f1f9eSRichard Henderson  */
537129f1f9eSRichard Henderson 
5388429a1caSRichard Henderson static void tcg_out_movext2(TCGContext *s, const TCGMovExtend *i1,
539129f1f9eSRichard Henderson                             const TCGMovExtend *i2, int scratch)
540129f1f9eSRichard Henderson {
541129f1f9eSRichard Henderson     TCGReg src1 = i1->src;
542129f1f9eSRichard Henderson     TCGReg src2 = i2->src;
543129f1f9eSRichard Henderson 
544129f1f9eSRichard Henderson     if (i1->dst != src2) {
545129f1f9eSRichard Henderson         tcg_out_movext1(s, i1);
546129f1f9eSRichard Henderson         tcg_out_movext1(s, i2);
547129f1f9eSRichard Henderson         return;
548129f1f9eSRichard Henderson     }
549129f1f9eSRichard Henderson     if (i2->dst == src1) {
550129f1f9eSRichard Henderson         TCGType src1_type = i1->src_type;
551129f1f9eSRichard Henderson         TCGType src2_type = i2->src_type;
552129f1f9eSRichard Henderson 
553129f1f9eSRichard Henderson         if (tcg_out_xchg(s, MAX(src1_type, src2_type), src1, src2)) {
554129f1f9eSRichard Henderson             /* The data is now in the correct registers, now extend. */
555129f1f9eSRichard Henderson             src1 = i2->src;
556129f1f9eSRichard Henderson             src2 = i1->src;
557129f1f9eSRichard Henderson         } else {
558129f1f9eSRichard Henderson             tcg_debug_assert(scratch >= 0);
559129f1f9eSRichard Henderson             tcg_out_mov(s, src1_type, scratch, src1);
560129f1f9eSRichard Henderson             src1 = scratch;
561129f1f9eSRichard Henderson         }
562129f1f9eSRichard Henderson     }
563129f1f9eSRichard Henderson     tcg_out_movext1_new_src(s, i2, src2);
564129f1f9eSRichard Henderson     tcg_out_movext1_new_src(s, i1, src1);
565129f1f9eSRichard Henderson }
566129f1f9eSRichard Henderson 
5672462e30eSRichard Henderson /**
5682462e30eSRichard Henderson  * tcg_out_movext3 -- move and extend three pair
5692462e30eSRichard Henderson  * @s: tcg context
5702462e30eSRichard Henderson  * @i1: first move description
5712462e30eSRichard Henderson  * @i2: second move description
5722462e30eSRichard Henderson  * @i3: third move description
5732462e30eSRichard Henderson  * @scratch: temporary register, or -1 for none
5742462e30eSRichard Henderson  *
5752462e30eSRichard Henderson  * As tcg_out_movext, for all of @i1, @i2 and @i3, caring for overlap
5762462e30eSRichard Henderson  * between the sources and destinations.
5772462e30eSRichard Henderson  */
5782462e30eSRichard Henderson 
5792462e30eSRichard Henderson static void tcg_out_movext3(TCGContext *s, const TCGMovExtend *i1,
5802462e30eSRichard Henderson                             const TCGMovExtend *i2, const TCGMovExtend *i3,
5812462e30eSRichard Henderson                             int scratch)
5822462e30eSRichard Henderson {
5832462e30eSRichard Henderson     TCGReg src1 = i1->src;
5842462e30eSRichard Henderson     TCGReg src2 = i2->src;
5852462e30eSRichard Henderson     TCGReg src3 = i3->src;
5862462e30eSRichard Henderson 
5872462e30eSRichard Henderson     if (i1->dst != src2 && i1->dst != src3) {
5882462e30eSRichard Henderson         tcg_out_movext1(s, i1);
5892462e30eSRichard Henderson         tcg_out_movext2(s, i2, i3, scratch);
5902462e30eSRichard Henderson         return;
5912462e30eSRichard Henderson     }
5922462e30eSRichard Henderson     if (i2->dst != src1 && i2->dst != src3) {
5932462e30eSRichard Henderson         tcg_out_movext1(s, i2);
5942462e30eSRichard Henderson         tcg_out_movext2(s, i1, i3, scratch);
5952462e30eSRichard Henderson         return;
5962462e30eSRichard Henderson     }
5972462e30eSRichard Henderson     if (i3->dst != src1 && i3->dst != src2) {
5982462e30eSRichard Henderson         tcg_out_movext1(s, i3);
5992462e30eSRichard Henderson         tcg_out_movext2(s, i1, i2, scratch);
6002462e30eSRichard Henderson         return;
6012462e30eSRichard Henderson     }
6022462e30eSRichard Henderson 
6032462e30eSRichard Henderson     /*
6042462e30eSRichard Henderson      * There is a cycle.  Since there are only 3 nodes, the cycle is
6052462e30eSRichard Henderson      * either "clockwise" or "anti-clockwise", and can be solved with
6062462e30eSRichard Henderson      * a single scratch or two xchg.
6072462e30eSRichard Henderson      */
6082462e30eSRichard Henderson     if (i1->dst == src2 && i2->dst == src3 && i3->dst == src1) {
6092462e30eSRichard Henderson         /* "Clockwise" */
6102462e30eSRichard Henderson         if (tcg_out_xchg(s, MAX(i1->src_type, i2->src_type), src1, src2)) {
6112462e30eSRichard Henderson             tcg_out_xchg(s, MAX(i2->src_type, i3->src_type), src2, src3);
6122462e30eSRichard Henderson             /* The data is now in the correct registers, now extend. */
6132462e30eSRichard Henderson             tcg_out_movext1_new_src(s, i1, i1->dst);
6142462e30eSRichard Henderson             tcg_out_movext1_new_src(s, i2, i2->dst);
6152462e30eSRichard Henderson             tcg_out_movext1_new_src(s, i3, i3->dst);
6162462e30eSRichard Henderson         } else {
6172462e30eSRichard Henderson             tcg_debug_assert(scratch >= 0);
6182462e30eSRichard Henderson             tcg_out_mov(s, i1->src_type, scratch, src1);
6192462e30eSRichard Henderson             tcg_out_movext1(s, i3);
6202462e30eSRichard Henderson             tcg_out_movext1(s, i2);
6212462e30eSRichard Henderson             tcg_out_movext1_new_src(s, i1, scratch);
6222462e30eSRichard Henderson         }
6232462e30eSRichard Henderson     } else if (i1->dst == src3 && i2->dst == src1 && i3->dst == src2) {
6242462e30eSRichard Henderson         /* "Anti-clockwise" */
6252462e30eSRichard Henderson         if (tcg_out_xchg(s, MAX(i2->src_type, i3->src_type), src2, src3)) {
6262462e30eSRichard Henderson             tcg_out_xchg(s, MAX(i1->src_type, i2->src_type), src1, src2);
6272462e30eSRichard Henderson             /* The data is now in the correct registers, now extend. */
6282462e30eSRichard Henderson             tcg_out_movext1_new_src(s, i1, i1->dst);
6292462e30eSRichard Henderson             tcg_out_movext1_new_src(s, i2, i2->dst);
6302462e30eSRichard Henderson             tcg_out_movext1_new_src(s, i3, i3->dst);
6312462e30eSRichard Henderson         } else {
6322462e30eSRichard Henderson             tcg_debug_assert(scratch >= 0);
6332462e30eSRichard Henderson             tcg_out_mov(s, i1->src_type, scratch, src1);
6342462e30eSRichard Henderson             tcg_out_movext1(s, i2);
6352462e30eSRichard Henderson             tcg_out_movext1(s, i3);
6362462e30eSRichard Henderson             tcg_out_movext1_new_src(s, i1, scratch);
6372462e30eSRichard Henderson         }
6382462e30eSRichard Henderson     } else {
6392462e30eSRichard Henderson         g_assert_not_reached();
6402462e30eSRichard Henderson     }
6412462e30eSRichard Henderson }
6422462e30eSRichard Henderson 
643a417ef83SRichard Henderson /*
644a417ef83SRichard Henderson  * Allocate a new TCGLabelQemuLdst entry.
645a417ef83SRichard Henderson  */
646a417ef83SRichard Henderson 
647a417ef83SRichard Henderson __attribute__((unused))
648a417ef83SRichard Henderson static TCGLabelQemuLdst *new_ldst_label(TCGContext *s)
649a417ef83SRichard Henderson {
650a417ef83SRichard Henderson     TCGLabelQemuLdst *l = tcg_malloc(sizeof(*l));
651a417ef83SRichard Henderson 
652a417ef83SRichard Henderson     memset(l, 0, sizeof(*l));
653a417ef83SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&s->ldst_labels, l, next);
654a417ef83SRichard Henderson 
655a417ef83SRichard Henderson     return l;
656a417ef83SRichard Henderson }
657a417ef83SRichard Henderson 
658a417ef83SRichard Henderson /*
659a417ef83SRichard Henderson  * Allocate new constant pool entries.
660a417ef83SRichard Henderson  */
661a417ef83SRichard Henderson 
662a417ef83SRichard Henderson typedef struct TCGLabelPoolData {
663a417ef83SRichard Henderson     struct TCGLabelPoolData *next;
664a417ef83SRichard Henderson     tcg_insn_unit *label;
665a417ef83SRichard Henderson     intptr_t addend;
666a417ef83SRichard Henderson     int rtype;
667a417ef83SRichard Henderson     unsigned nlong;
668a417ef83SRichard Henderson     tcg_target_ulong data[];
669a417ef83SRichard Henderson } TCGLabelPoolData;
670a417ef83SRichard Henderson 
671a417ef83SRichard Henderson static TCGLabelPoolData *new_pool_alloc(TCGContext *s, int nlong, int rtype,
672a417ef83SRichard Henderson                                         tcg_insn_unit *label, intptr_t addend)
673a417ef83SRichard Henderson {
674a417ef83SRichard Henderson     TCGLabelPoolData *n = tcg_malloc(sizeof(TCGLabelPoolData)
675a417ef83SRichard Henderson                                      + sizeof(tcg_target_ulong) * nlong);
676a417ef83SRichard Henderson 
677a417ef83SRichard Henderson     n->label = label;
678a417ef83SRichard Henderson     n->addend = addend;
679a417ef83SRichard Henderson     n->rtype = rtype;
680a417ef83SRichard Henderson     n->nlong = nlong;
681a417ef83SRichard Henderson     return n;
682a417ef83SRichard Henderson }
683a417ef83SRichard Henderson 
684a417ef83SRichard Henderson static void new_pool_insert(TCGContext *s, TCGLabelPoolData *n)
685a417ef83SRichard Henderson {
686a417ef83SRichard Henderson     TCGLabelPoolData *i, **pp;
687a417ef83SRichard Henderson     int nlong = n->nlong;
688a417ef83SRichard Henderson 
689a417ef83SRichard Henderson     /* Insertion sort on the pool.  */
690a417ef83SRichard Henderson     for (pp = &s->pool_labels; (i = *pp) != NULL; pp = &i->next) {
691a417ef83SRichard Henderson         if (nlong > i->nlong) {
692a417ef83SRichard Henderson             break;
693a417ef83SRichard Henderson         }
694a417ef83SRichard Henderson         if (nlong < i->nlong) {
695a417ef83SRichard Henderson             continue;
696a417ef83SRichard Henderson         }
697a417ef83SRichard Henderson         if (memcmp(n->data, i->data, sizeof(tcg_target_ulong) * nlong) >= 0) {
698a417ef83SRichard Henderson             break;
699a417ef83SRichard Henderson         }
700a417ef83SRichard Henderson     }
701a417ef83SRichard Henderson     n->next = *pp;
702a417ef83SRichard Henderson     *pp = n;
703a417ef83SRichard Henderson }
704a417ef83SRichard Henderson 
705a417ef83SRichard Henderson /* The "usual" for generic integer code.  */
706a417ef83SRichard Henderson __attribute__((unused))
707a417ef83SRichard Henderson static void new_pool_label(TCGContext *s, tcg_target_ulong d, int rtype,
708a417ef83SRichard Henderson                            tcg_insn_unit *label, intptr_t addend)
709a417ef83SRichard Henderson {
710a417ef83SRichard Henderson     TCGLabelPoolData *n = new_pool_alloc(s, 1, rtype, label, addend);
711a417ef83SRichard Henderson     n->data[0] = d;
712a417ef83SRichard Henderson     new_pool_insert(s, n);
713a417ef83SRichard Henderson }
714a417ef83SRichard Henderson 
715a417ef83SRichard Henderson /* For v64 or v128, depending on the host.  */
716a417ef83SRichard Henderson __attribute__((unused))
717a417ef83SRichard Henderson static void new_pool_l2(TCGContext *s, int rtype, tcg_insn_unit *label,
718a417ef83SRichard Henderson                         intptr_t addend, tcg_target_ulong d0,
719a417ef83SRichard Henderson                         tcg_target_ulong d1)
720a417ef83SRichard Henderson {
721a417ef83SRichard Henderson     TCGLabelPoolData *n = new_pool_alloc(s, 2, rtype, label, addend);
722a417ef83SRichard Henderson     n->data[0] = d0;
723a417ef83SRichard Henderson     n->data[1] = d1;
724a417ef83SRichard Henderson     new_pool_insert(s, n);
725a417ef83SRichard Henderson }
726a417ef83SRichard Henderson 
727a417ef83SRichard Henderson /* For v128 or v256, depending on the host.  */
728a417ef83SRichard Henderson __attribute__((unused))
729a417ef83SRichard Henderson static void new_pool_l4(TCGContext *s, int rtype, tcg_insn_unit *label,
730a417ef83SRichard Henderson                         intptr_t addend, tcg_target_ulong d0,
731a417ef83SRichard Henderson                         tcg_target_ulong d1, tcg_target_ulong d2,
732a417ef83SRichard Henderson                         tcg_target_ulong d3)
733a417ef83SRichard Henderson {
734a417ef83SRichard Henderson     TCGLabelPoolData *n = new_pool_alloc(s, 4, rtype, label, addend);
735a417ef83SRichard Henderson     n->data[0] = d0;
736a417ef83SRichard Henderson     n->data[1] = d1;
737a417ef83SRichard Henderson     n->data[2] = d2;
738a417ef83SRichard Henderson     n->data[3] = d3;
739a417ef83SRichard Henderson     new_pool_insert(s, n);
740a417ef83SRichard Henderson }
741a417ef83SRichard Henderson 
742a417ef83SRichard Henderson /* For v256, for 32-bit host.  */
743a417ef83SRichard Henderson __attribute__((unused))
744a417ef83SRichard Henderson static void new_pool_l8(TCGContext *s, int rtype, tcg_insn_unit *label,
745a417ef83SRichard Henderson                         intptr_t addend, tcg_target_ulong d0,
746a417ef83SRichard Henderson                         tcg_target_ulong d1, tcg_target_ulong d2,
747a417ef83SRichard Henderson                         tcg_target_ulong d3, tcg_target_ulong d4,
748a417ef83SRichard Henderson                         tcg_target_ulong d5, tcg_target_ulong d6,
749a417ef83SRichard Henderson                         tcg_target_ulong d7)
750a417ef83SRichard Henderson {
751a417ef83SRichard Henderson     TCGLabelPoolData *n = new_pool_alloc(s, 8, rtype, label, addend);
752a417ef83SRichard Henderson     n->data[0] = d0;
753a417ef83SRichard Henderson     n->data[1] = d1;
754a417ef83SRichard Henderson     n->data[2] = d2;
755a417ef83SRichard Henderson     n->data[3] = d3;
756a417ef83SRichard Henderson     n->data[4] = d4;
757a417ef83SRichard Henderson     n->data[5] = d5;
758a417ef83SRichard Henderson     n->data[6] = d6;
759a417ef83SRichard Henderson     n->data[7] = d7;
760a417ef83SRichard Henderson     new_pool_insert(s, n);
761a417ef83SRichard Henderson }
762a417ef83SRichard Henderson 
763a417ef83SRichard Henderson /*
764a417ef83SRichard Henderson  * Generate TB finalization at the end of block
765a417ef83SRichard Henderson  */
766a417ef83SRichard Henderson 
767a417ef83SRichard Henderson static int tcg_out_ldst_finalize(TCGContext *s)
768a417ef83SRichard Henderson {
769a417ef83SRichard Henderson     TCGLabelQemuLdst *lb;
770a417ef83SRichard Henderson 
771a417ef83SRichard Henderson     /* qemu_ld/st slow paths */
772a417ef83SRichard Henderson     QSIMPLEQ_FOREACH(lb, &s->ldst_labels, next) {
773a417ef83SRichard Henderson         if (lb->is_ld
774a417ef83SRichard Henderson             ? !tcg_out_qemu_ld_slow_path(s, lb)
775a417ef83SRichard Henderson             : !tcg_out_qemu_st_slow_path(s, lb)) {
776a417ef83SRichard Henderson             return -2;
777a417ef83SRichard Henderson         }
778a417ef83SRichard Henderson 
779a417ef83SRichard Henderson         /*
780a417ef83SRichard Henderson          * Test for (pending) buffer overflow.  The assumption is that any
781a417ef83SRichard Henderson          * one operation beginning below the high water mark cannot overrun
782a417ef83SRichard Henderson          * the buffer completely.  Thus we can test for overflow after
783a417ef83SRichard Henderson          * generating code without having to check during generation.
784a417ef83SRichard Henderson          */
785a417ef83SRichard Henderson         if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) {
786a417ef83SRichard Henderson             return -1;
787a417ef83SRichard Henderson         }
788a417ef83SRichard Henderson     }
789a417ef83SRichard Henderson     return 0;
790a417ef83SRichard Henderson }
791a417ef83SRichard Henderson 
792a417ef83SRichard Henderson static int tcg_out_pool_finalize(TCGContext *s)
793a417ef83SRichard Henderson {
794a417ef83SRichard Henderson     TCGLabelPoolData *p = s->pool_labels;
795a417ef83SRichard Henderson     TCGLabelPoolData *l = NULL;
796a417ef83SRichard Henderson     void *a;
797a417ef83SRichard Henderson 
798a417ef83SRichard Henderson     if (p == NULL) {
799a417ef83SRichard Henderson         return 0;
800a417ef83SRichard Henderson     }
801a417ef83SRichard Henderson 
802a417ef83SRichard Henderson     /*
803a417ef83SRichard Henderson      * ??? Round up to qemu_icache_linesize, but then do not round
804a417ef83SRichard Henderson      * again when allocating the next TranslationBlock structure.
805a417ef83SRichard Henderson      */
806a417ef83SRichard Henderson     a = (void *)ROUND_UP((uintptr_t)s->code_ptr,
807a417ef83SRichard Henderson                          sizeof(tcg_target_ulong) * p->nlong);
808a417ef83SRichard Henderson     tcg_out_nop_fill(s->code_ptr, (tcg_insn_unit *)a - s->code_ptr);
809a417ef83SRichard Henderson     s->data_gen_ptr = a;
810a417ef83SRichard Henderson 
811a417ef83SRichard Henderson     for (; p != NULL; p = p->next) {
812a417ef83SRichard Henderson         size_t size = sizeof(tcg_target_ulong) * p->nlong;
813a417ef83SRichard Henderson         uintptr_t value;
814a417ef83SRichard Henderson 
815a417ef83SRichard Henderson         if (!l || l->nlong != p->nlong || memcmp(l->data, p->data, size)) {
816a417ef83SRichard Henderson             if (unlikely(a > s->code_gen_highwater)) {
817a417ef83SRichard Henderson                 return -1;
818a417ef83SRichard Henderson             }
819a417ef83SRichard Henderson             memcpy(a, p->data, size);
820a417ef83SRichard Henderson             a += size;
821a417ef83SRichard Henderson             l = p;
822a417ef83SRichard Henderson         }
823a417ef83SRichard Henderson 
824a417ef83SRichard Henderson         value = (uintptr_t)tcg_splitwx_to_rx(a) - size;
825a417ef83SRichard Henderson         if (!patch_reloc(p->label, p->rtype, value, p->addend)) {
826a417ef83SRichard Henderson             return -2;
827a417ef83SRichard Henderson         }
828a417ef83SRichard Henderson     }
829a417ef83SRichard Henderson 
830a417ef83SRichard Henderson     s->code_ptr = a;
831a417ef83SRichard Henderson     return 0;
832a417ef83SRichard Henderson }
833a417ef83SRichard Henderson 
8344c22e840SRichard Henderson #define C_PFX1(P, A)                    P##A
8354c22e840SRichard Henderson #define C_PFX2(P, A, B)                 P##A##_##B
8364c22e840SRichard Henderson #define C_PFX3(P, A, B, C)              P##A##_##B##_##C
8374c22e840SRichard Henderson #define C_PFX4(P, A, B, C, D)           P##A##_##B##_##C##_##D
8384c22e840SRichard Henderson #define C_PFX5(P, A, B, C, D, E)        P##A##_##B##_##C##_##D##_##E
8394c22e840SRichard Henderson #define C_PFX6(P, A, B, C, D, E, F)     P##A##_##B##_##C##_##D##_##E##_##F
8404c22e840SRichard Henderson 
8414c22e840SRichard Henderson /* Define an enumeration for the various combinations. */
8424c22e840SRichard Henderson 
8434c22e840SRichard Henderson #define C_O0_I1(I1)                     C_PFX1(c_o0_i1_, I1),
8444c22e840SRichard Henderson #define C_O0_I2(I1, I2)                 C_PFX2(c_o0_i2_, I1, I2),
8454c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3)             C_PFX3(c_o0_i3_, I1, I2, I3),
8464c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4)         C_PFX4(c_o0_i4_, I1, I2, I3, I4),
8474c22e840SRichard Henderson 
8484c22e840SRichard Henderson #define C_O1_I1(O1, I1)                 C_PFX2(c_o1_i1_, O1, I1),
8494c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2)             C_PFX3(c_o1_i2_, O1, I1, I2),
8504c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3)         C_PFX4(c_o1_i3_, O1, I1, I2, I3),
8514c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4)     C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4),
8524c22e840SRichard Henderson 
8534c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2)             C_PFX3(c_n1_i2_, O1, I1, I2),
854ca5bed07SRichard Henderson #define C_N1O1_I1(O1, O2, I1)           C_PFX3(c_n1o1_i1_, O1, O2, I1),
855fa645b48SRichard Henderson #define C_N2_I1(O1, O2, I1)             C_PFX3(c_n2_i1_, O1, O2, I1),
8564c22e840SRichard Henderson 
8574c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1)             C_PFX3(c_o2_i1_, O1, O2, I1),
8584c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2)         C_PFX4(c_o2_i2_, O1, O2, I1, I2),
8594c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3)     C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3),
8604c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4),
86122d2e535SIlya Leoshkevich #define C_N1_O1_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_n1_o1_i4_, O1, O2, I1, I2, I3, I4),
8624c22e840SRichard Henderson 
8634c22e840SRichard Henderson typedef enum {
8645500bd9eSRichard Henderson     C_Dynamic = -2,
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 
9585500bd9eSRichard Henderson /*
9595500bd9eSRichard Henderson  * TCGOutOp is the base class for a set of structures that describe how
9605500bd9eSRichard Henderson  * to generate code for a given TCGOpcode.
9615500bd9eSRichard Henderson  *
9625500bd9eSRichard Henderson  * @static_constraint:
9635500bd9eSRichard Henderson  *   C_NotImplemented: The TCGOpcode is not supported by the backend.
9645500bd9eSRichard Henderson  *   C_Dynamic:        Use @dynamic_constraint to select a constraint set
9655500bd9eSRichard Henderson  *                     based on any of @type, @flags, or host isa.
9665500bd9eSRichard Henderson  *   Otherwise:        The register allocation constrains for the TCGOpcode.
9675500bd9eSRichard Henderson  *
9685500bd9eSRichard Henderson  * Subclasses of TCGOutOp will define a set of output routines that may
9695500bd9eSRichard Henderson  * be used.  Such routines will often be selected by the set of registers
9705500bd9eSRichard Henderson  * and constants that come out of register allocation.  The set of
9715500bd9eSRichard Henderson  * routines that are provided will guide the set of constraints that are
9725500bd9eSRichard Henderson  * legal.  In particular, assume that tcg_optimize() has done its job in
9735500bd9eSRichard Henderson  * swapping commutative operands and folding operations for which all
9745500bd9eSRichard Henderson  * operands are constant.
9755500bd9eSRichard Henderson  */
9765500bd9eSRichard Henderson typedef struct TCGOutOp {
9775500bd9eSRichard Henderson     TCGConstraintSetIndex static_constraint;
9785500bd9eSRichard Henderson     TCGConstraintSetIndex (*dynamic_constraint)(TCGType type, unsigned flags);
9795500bd9eSRichard Henderson } TCGOutOp;
9805500bd9eSRichard Henderson 
981662cdbcfSRichard Henderson typedef struct TCGOutOpBinary {
982662cdbcfSRichard Henderson     TCGOutOp base;
983662cdbcfSRichard Henderson     void (*out_rrr)(TCGContext *s, TCGType type,
984662cdbcfSRichard Henderson                     TCGReg a0, TCGReg a1, TCGReg a2);
985662cdbcfSRichard Henderson     void (*out_rri)(TCGContext *s, TCGType type,
986662cdbcfSRichard Henderson                     TCGReg a0, TCGReg a1, tcg_target_long a2);
987662cdbcfSRichard Henderson } TCGOutOpBinary;
988662cdbcfSRichard Henderson 
989e126a91cSRichard Henderson typedef struct TCGOutOpUnary {
990e126a91cSRichard Henderson     TCGOutOp base;
991e126a91cSRichard Henderson     void (*out_rr)(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1);
992e126a91cSRichard Henderson } TCGOutOpUnary;
993e126a91cSRichard Henderson 
9943f057e24SRichard Henderson typedef struct TCGOutOpSubtract {
9953f057e24SRichard Henderson     TCGOutOp base;
9963f057e24SRichard Henderson     void (*out_rrr)(TCGContext *s, TCGType type,
9973f057e24SRichard Henderson                     TCGReg a0, TCGReg a1, TCGReg a2);
9983f057e24SRichard Henderson     void (*out_rir)(TCGContext *s, TCGType type,
9993f057e24SRichard Henderson                     TCGReg a0, tcg_target_long a1, TCGReg a2);
10003f057e24SRichard Henderson } TCGOutOpSubtract;
10013f057e24SRichard Henderson 
1002139c1837SPaolo Bonzini #include "tcg-target.c.inc"
1003c896fe29Sbellard 
10047857ee11SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
10057857ee11SRichard Henderson /* Validate CPUTLBDescFast placement. */
10067857ee11SRichard Henderson QEMU_BUILD_BUG_ON((int)(offsetof(CPUNegativeOffsetState, tlb.f[0]) -
10077857ee11SRichard Henderson                         sizeof(CPUNegativeOffsetState))
10087857ee11SRichard Henderson                   < MIN_TLB_MASK_TABLE_OFS);
10097857ee11SRichard Henderson #endif
10107857ee11SRichard Henderson 
1011662cdbcfSRichard Henderson /*
1012662cdbcfSRichard Henderson  * Register V as the TCGOutOp for O.
1013662cdbcfSRichard Henderson  * This verifies that V is of type T, otherwise give a nice compiler error.
1014662cdbcfSRichard Henderson  * This prevents trivial mistakes within each arch/tcg-target.c.inc.
1015662cdbcfSRichard Henderson  */
1016662cdbcfSRichard Henderson #define OUTOP(O, T, V)  [O] = _Generic(V, T: &V.base)
1017662cdbcfSRichard Henderson 
10185500bd9eSRichard Henderson /* Register allocation descriptions for every TCGOpcode. */
10195500bd9eSRichard Henderson static const TCGOutOp * const all_outop[NB_OPS] = {
102079602f63SRichard Henderson     OUTOP(INDEX_op_add, TCGOutOpBinary, outop_add),
1021c3b920b3SRichard Henderson     OUTOP(INDEX_op_and, TCGOutOpBinary, outop_and),
102246f96bffSRichard Henderson     OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc),
10235c0968a7SRichard Henderson     OUTOP(INDEX_op_eqv, TCGOutOpBinary, outop_eqv),
1024d2c3ecadSRichard Henderson     OUTOP(INDEX_op_mul, TCGOutOpBinary, outop_mul),
1025*c742824dSRichard Henderson     OUTOP(INDEX_op_mulsh, TCGOutOpBinary, outop_mulsh),
1026aa28c9efSRichard Henderson     OUTOP(INDEX_op_muluh, TCGOutOpBinary, outop_muluh),
102759379a45SRichard Henderson     OUTOP(INDEX_op_nand, TCGOutOpBinary, outop_nand),
102869713587SRichard Henderson     OUTOP(INDEX_op_neg, TCGOutOpUnary, outop_neg),
10293a8c4e9eSRichard Henderson     OUTOP(INDEX_op_nor, TCGOutOpBinary, outop_nor),
10305c62d377SRichard Henderson     OUTOP(INDEX_op_not, TCGOutOpUnary, outop_not),
103149bd7514SRichard Henderson     OUTOP(INDEX_op_or, TCGOutOpBinary, outop_or),
10326aba25ebSRichard Henderson     OUTOP(INDEX_op_orc, TCGOutOpBinary, outop_orc),
103360f34f55SRichard Henderson     OUTOP(INDEX_op_sub, TCGOutOpSubtract, outop_sub),
1034fffd3dc9SRichard Henderson     OUTOP(INDEX_op_xor, TCGOutOpBinary, outop_xor),
10355500bd9eSRichard Henderson };
10365500bd9eSRichard Henderson 
1037662cdbcfSRichard Henderson #undef OUTOP
1038662cdbcfSRichard Henderson 
1039e8feb96fSEmilio G. Cota /*
10403468b59eSEmilio G. Cota  * All TCG threads except the parent (i.e. the one that called tcg_context_init
10413468b59eSEmilio G. Cota  * and registered the target's TCG globals) must register with this function
10423468b59eSEmilio G. Cota  * before initiating translation.
10433468b59eSEmilio G. Cota  *
10443468b59eSEmilio G. Cota  * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation
10453468b59eSEmilio G. Cota  * of tcg_region_init() for the reasoning behind this.
10463468b59eSEmilio G. Cota  *
10477893e42dSPhilippe Mathieu-Daudé  * In system-mode each caller registers its context in tcg_ctxs[]. Note that in
10487893e42dSPhilippe Mathieu-Daudé  * system-mode tcg_ctxs[] does not track tcg_ctx_init, since the initial context
10493468b59eSEmilio G. Cota  * is not used anymore for translation once this function is called.
10503468b59eSEmilio G. Cota  *
10517893e42dSPhilippe Mathieu-Daudé  * Not tracking tcg_init_ctx in tcg_ctxs[] in system-mode keeps code that
10527893e42dSPhilippe Mathieu-Daudé  * iterates over the array (e.g. tcg_code_size() the same for both system/user
10537893e42dSPhilippe Mathieu-Daudé  * modes.
10543468b59eSEmilio G. Cota  */
10553468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
10563468b59eSEmilio G. Cota void tcg_register_thread(void)
10573468b59eSEmilio G. Cota {
10583468b59eSEmilio G. Cota     tcg_ctx = &tcg_init_ctx;
10593468b59eSEmilio G. Cota }
10603468b59eSEmilio G. Cota #else
10613468b59eSEmilio G. Cota void tcg_register_thread(void)
10623468b59eSEmilio G. Cota {
10633468b59eSEmilio G. Cota     TCGContext *s = g_malloc(sizeof(*s));
10643468b59eSEmilio G. Cota     unsigned int i, n;
10653468b59eSEmilio G. Cota 
10663468b59eSEmilio G. Cota     *s = tcg_init_ctx;
10673468b59eSEmilio G. Cota 
10683468b59eSEmilio G. Cota     /* Relink mem_base.  */
10693468b59eSEmilio G. Cota     for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) {
10703468b59eSEmilio G. Cota         if (tcg_init_ctx.temps[i].mem_base) {
10713468b59eSEmilio G. Cota             ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps;
10723468b59eSEmilio G. Cota             tcg_debug_assert(b >= 0 && b < n);
10733468b59eSEmilio G. Cota             s->temps[i].mem_base = &s->temps[b];
10743468b59eSEmilio G. Cota         }
10753468b59eSEmilio G. Cota     }
10763468b59eSEmilio G. Cota 
10773468b59eSEmilio G. Cota     /* Claim an entry in tcg_ctxs */
10780e2d61cfSRichard Henderson     n = qatomic_fetch_inc(&tcg_cur_ctxs);
10790e2d61cfSRichard Henderson     g_assert(n < tcg_max_ctxs);
1080d73415a3SStefan Hajnoczi     qatomic_set(&tcg_ctxs[n], s);
10813468b59eSEmilio G. Cota 
108238b47b19SEmilio G. Cota     if (n > 0) {
1083bf042e8eSRichard Henderson         tcg_region_initial_alloc(s);
108438b47b19SEmilio G. Cota     }
108538b47b19SEmilio G. Cota 
10863468b59eSEmilio G. Cota     tcg_ctx = s;
10873468b59eSEmilio G. Cota }
10883468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */
10893468b59eSEmilio G. Cota 
1090c896fe29Sbellard /* pool based memory allocation */
1091c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size)
1092c896fe29Sbellard {
1093c896fe29Sbellard     TCGPool *p;
1094c896fe29Sbellard     int pool_size;
1095c896fe29Sbellard 
1096c896fe29Sbellard     if (size > TCG_POOL_CHUNK_SIZE) {
1097c896fe29Sbellard         /* big malloc: insert a new pool (XXX: could optimize) */
10987267c094SAnthony Liguori         p = g_malloc(sizeof(TCGPool) + size);
1099c896fe29Sbellard         p->size = size;
11004055299eSKirill Batuzov         p->next = s->pool_first_large;
11014055299eSKirill Batuzov         s->pool_first_large = p;
11024055299eSKirill Batuzov         return p->data;
1103c896fe29Sbellard     } else {
1104c896fe29Sbellard         p = s->pool_current;
1105c896fe29Sbellard         if (!p) {
1106c896fe29Sbellard             p = s->pool_first;
1107c896fe29Sbellard             if (!p)
1108c896fe29Sbellard                 goto new_pool;
1109c896fe29Sbellard         } else {
1110c896fe29Sbellard             if (!p->next) {
1111c896fe29Sbellard             new_pool:
1112c896fe29Sbellard                 pool_size = TCG_POOL_CHUNK_SIZE;
11137267c094SAnthony Liguori                 p = g_malloc(sizeof(TCGPool) + pool_size);
1114c896fe29Sbellard                 p->size = pool_size;
1115c896fe29Sbellard                 p->next = NULL;
1116a813e36fSRichard Henderson                 if (s->pool_current) {
1117c896fe29Sbellard                     s->pool_current->next = p;
1118a813e36fSRichard Henderson                 } else {
1119c896fe29Sbellard                     s->pool_first = p;
1120a813e36fSRichard Henderson                 }
1121c896fe29Sbellard             } else {
1122c896fe29Sbellard                 p = p->next;
1123c896fe29Sbellard             }
1124c896fe29Sbellard         }
1125c896fe29Sbellard     }
1126c896fe29Sbellard     s->pool_current = p;
1127c896fe29Sbellard     s->pool_cur = p->data + size;
1128c896fe29Sbellard     s->pool_end = p->data + p->size;
1129c896fe29Sbellard     return p->data;
1130c896fe29Sbellard }
1131c896fe29Sbellard 
1132c896fe29Sbellard void tcg_pool_reset(TCGContext *s)
1133c896fe29Sbellard {
11344055299eSKirill Batuzov     TCGPool *p, *t;
11354055299eSKirill Batuzov     for (p = s->pool_first_large; p; p = t) {
11364055299eSKirill Batuzov         t = p->next;
11374055299eSKirill Batuzov         g_free(p);
11384055299eSKirill Batuzov     }
11394055299eSKirill Batuzov     s->pool_first_large = NULL;
1140c896fe29Sbellard     s->pool_cur = s->pool_end = NULL;
1141c896fe29Sbellard     s->pool_current = NULL;
1142c896fe29Sbellard }
1143c896fe29Sbellard 
11448429a1caSRichard Henderson /*
11458429a1caSRichard Henderson  * Create TCGHelperInfo structures for "tcg/tcg-ldst.h" functions,
11468429a1caSRichard Henderson  * akin to what "exec/helper-tcg.h" does with DEF_HELPER_FLAGS_N.
11478429a1caSRichard Henderson  * We only use these for layout in tcg_out_ld_helper_ret and
11488429a1caSRichard Henderson  * tcg_out_st_helper_args, and share them between several of
11498429a1caSRichard Henderson  * the helpers, with the end result that it's easier to build manually.
11508429a1caSRichard Henderson  */
11518429a1caSRichard Henderson 
11528429a1caSRichard Henderson #if TCG_TARGET_REG_BITS == 32
11538429a1caSRichard Henderson # define dh_typecode_ttl  dh_typecode_i32
11548429a1caSRichard Henderson #else
11558429a1caSRichard Henderson # define dh_typecode_ttl  dh_typecode_i64
11568429a1caSRichard Henderson #endif
11578429a1caSRichard Henderson 
11588429a1caSRichard Henderson static TCGHelperInfo info_helper_ld32_mmu = {
11598429a1caSRichard Henderson     .flags = TCG_CALL_NO_WG,
11608429a1caSRichard Henderson     .typemask = dh_typemask(ttl, 0)  /* return tcg_target_ulong */
11618429a1caSRichard Henderson               | dh_typemask(env, 1)
116224e46e6cSRichard Henderson               | dh_typemask(i64, 2)  /* uint64_t addr */
11638429a1caSRichard Henderson               | dh_typemask(i32, 3)  /* unsigned oi */
11648429a1caSRichard Henderson               | dh_typemask(ptr, 4)  /* uintptr_t ra */
11658429a1caSRichard Henderson };
11668429a1caSRichard Henderson 
11678429a1caSRichard Henderson static TCGHelperInfo info_helper_ld64_mmu = {
11688429a1caSRichard Henderson     .flags = TCG_CALL_NO_WG,
11698429a1caSRichard Henderson     .typemask = dh_typemask(i64, 0)  /* return uint64_t */
11708429a1caSRichard Henderson               | dh_typemask(env, 1)
117124e46e6cSRichard Henderson               | dh_typemask(i64, 2)  /* uint64_t addr */
11728429a1caSRichard Henderson               | dh_typemask(i32, 3)  /* unsigned oi */
11738429a1caSRichard Henderson               | dh_typemask(ptr, 4)  /* uintptr_t ra */
11748429a1caSRichard Henderson };
11758429a1caSRichard Henderson 
1176ebebea53SRichard Henderson static TCGHelperInfo info_helper_ld128_mmu = {
1177ebebea53SRichard Henderson     .flags = TCG_CALL_NO_WG,
1178ebebea53SRichard Henderson     .typemask = dh_typemask(i128, 0) /* return Int128 */
1179ebebea53SRichard Henderson               | dh_typemask(env, 1)
118024e46e6cSRichard Henderson               | dh_typemask(i64, 2)  /* uint64_t addr */
1181ebebea53SRichard Henderson               | dh_typemask(i32, 3)  /* unsigned oi */
1182ebebea53SRichard Henderson               | dh_typemask(ptr, 4)  /* uintptr_t ra */
1183ebebea53SRichard Henderson };
1184ebebea53SRichard Henderson 
11858429a1caSRichard Henderson static TCGHelperInfo info_helper_st32_mmu = {
11868429a1caSRichard Henderson     .flags = TCG_CALL_NO_WG,
11878429a1caSRichard Henderson     .typemask = dh_typemask(void, 0)
11888429a1caSRichard Henderson               | dh_typemask(env, 1)
118924e46e6cSRichard Henderson               | dh_typemask(i64, 2)  /* uint64_t addr */
11908429a1caSRichard Henderson               | dh_typemask(i32, 3)  /* uint32_t data */
11918429a1caSRichard Henderson               | dh_typemask(i32, 4)  /* unsigned oi */
11928429a1caSRichard Henderson               | dh_typemask(ptr, 5)  /* uintptr_t ra */
11938429a1caSRichard Henderson };
11948429a1caSRichard Henderson 
11958429a1caSRichard Henderson static TCGHelperInfo info_helper_st64_mmu = {
11968429a1caSRichard Henderson     .flags = TCG_CALL_NO_WG,
11978429a1caSRichard Henderson     .typemask = dh_typemask(void, 0)
11988429a1caSRichard Henderson               | dh_typemask(env, 1)
119924e46e6cSRichard Henderson               | dh_typemask(i64, 2)  /* uint64_t addr */
12008429a1caSRichard Henderson               | dh_typemask(i64, 3)  /* uint64_t data */
12018429a1caSRichard Henderson               | dh_typemask(i32, 4)  /* unsigned oi */
12028429a1caSRichard Henderson               | dh_typemask(ptr, 5)  /* uintptr_t ra */
12038429a1caSRichard Henderson };
12048429a1caSRichard Henderson 
1205ebebea53SRichard Henderson static TCGHelperInfo info_helper_st128_mmu = {
1206ebebea53SRichard Henderson     .flags = TCG_CALL_NO_WG,
1207ebebea53SRichard Henderson     .typemask = dh_typemask(void, 0)
1208ebebea53SRichard Henderson               | dh_typemask(env, 1)
120924e46e6cSRichard Henderson               | dh_typemask(i64, 2)  /* uint64_t addr */
1210ebebea53SRichard Henderson               | dh_typemask(i128, 3) /* Int128 data */
1211ebebea53SRichard Henderson               | dh_typemask(i32, 4)  /* unsigned oi */
1212ebebea53SRichard Henderson               | dh_typemask(ptr, 5)  /* uintptr_t ra */
1213ebebea53SRichard Henderson };
1214ebebea53SRichard Henderson 
121522f15579SRichard Henderson #ifdef CONFIG_TCG_INTERPRETER
1216c6ef8c7bSPhilippe Mathieu-Daudé static ffi_type *typecode_to_ffi(int argmask)
1217c6ef8c7bSPhilippe Mathieu-Daudé {
1218e9709e17SRichard Henderson     /*
1219e9709e17SRichard Henderson      * libffi does not support __int128_t, so we have forced Int128
1220e9709e17SRichard Henderson      * to use the structure definition instead of the builtin type.
1221e9709e17SRichard Henderson      */
1222e9709e17SRichard Henderson     static ffi_type *ffi_type_i128_elements[3] = {
1223e9709e17SRichard Henderson         &ffi_type_uint64,
1224e9709e17SRichard Henderson         &ffi_type_uint64,
1225e9709e17SRichard Henderson         NULL
1226e9709e17SRichard Henderson     };
1227e9709e17SRichard Henderson     static ffi_type ffi_type_i128 = {
1228e9709e17SRichard Henderson         .size = 16,
1229e9709e17SRichard Henderson         .alignment = __alignof__(Int128),
1230e9709e17SRichard Henderson         .type = FFI_TYPE_STRUCT,
1231e9709e17SRichard Henderson         .elements = ffi_type_i128_elements,
1232e9709e17SRichard Henderson     };
1233e9709e17SRichard Henderson 
1234c6ef8c7bSPhilippe Mathieu-Daudé     switch (argmask) {
1235c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_void:
1236c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_void;
1237c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_i32:
1238c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_uint32;
1239c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_s32:
1240c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_sint32;
1241c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_i64:
1242c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_uint64;
1243c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_s64:
1244c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_sint64;
1245c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_ptr:
1246c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_pointer;
1247e9709e17SRichard Henderson     case dh_typecode_i128:
1248e9709e17SRichard Henderson         return &ffi_type_i128;
1249c6ef8c7bSPhilippe Mathieu-Daudé     }
1250c6ef8c7bSPhilippe Mathieu-Daudé     g_assert_not_reached();
1251c6ef8c7bSPhilippe Mathieu-Daudé }
12520c22e176SPhilippe Mathieu-Daudé 
1253d53106c9SRichard Henderson static ffi_cif *init_ffi_layout(TCGHelperInfo *info)
12540c22e176SPhilippe Mathieu-Daudé {
1255f9c4bb80SRichard Henderson     unsigned typemask = info->typemask;
12560c22e176SPhilippe Mathieu-Daudé     struct {
12570c22e176SPhilippe Mathieu-Daudé         ffi_cif cif;
12580c22e176SPhilippe Mathieu-Daudé         ffi_type *args[];
12590c22e176SPhilippe Mathieu-Daudé     } *ca;
12600c22e176SPhilippe Mathieu-Daudé     ffi_status status;
12610c22e176SPhilippe Mathieu-Daudé     int nargs;
12620c22e176SPhilippe Mathieu-Daudé 
12630c22e176SPhilippe Mathieu-Daudé     /* Ignoring the return type, find the last non-zero field. */
12640c22e176SPhilippe Mathieu-Daudé     nargs = 32 - clz32(typemask >> 3);
12650c22e176SPhilippe Mathieu-Daudé     nargs = DIV_ROUND_UP(nargs, 3);
1266e9709e17SRichard Henderson     assert(nargs <= MAX_CALL_IARGS);
12670c22e176SPhilippe Mathieu-Daudé 
12680c22e176SPhilippe Mathieu-Daudé     ca = g_malloc0(sizeof(*ca) + nargs * sizeof(ffi_type *));
12690c22e176SPhilippe Mathieu-Daudé     ca->cif.rtype = typecode_to_ffi(typemask & 7);
12700c22e176SPhilippe Mathieu-Daudé     ca->cif.nargs = nargs;
12710c22e176SPhilippe Mathieu-Daudé 
12720c22e176SPhilippe Mathieu-Daudé     if (nargs != 0) {
12730c22e176SPhilippe Mathieu-Daudé         ca->cif.arg_types = ca->args;
12740c22e176SPhilippe Mathieu-Daudé         for (int j = 0; j < nargs; ++j) {
12750c22e176SPhilippe Mathieu-Daudé             int typecode = extract32(typemask, (j + 1) * 3, 3);
12760c22e176SPhilippe Mathieu-Daudé             ca->args[j] = typecode_to_ffi(typecode);
12770c22e176SPhilippe Mathieu-Daudé         }
12780c22e176SPhilippe Mathieu-Daudé     }
12790c22e176SPhilippe Mathieu-Daudé 
12800c22e176SPhilippe Mathieu-Daudé     status = ffi_prep_cif(&ca->cif, FFI_DEFAULT_ABI, nargs,
12810c22e176SPhilippe Mathieu-Daudé                           ca->cif.rtype, ca->cif.arg_types);
12820c22e176SPhilippe Mathieu-Daudé     assert(status == FFI_OK);
12830c22e176SPhilippe Mathieu-Daudé 
1284d53106c9SRichard Henderson     return &ca->cif;
12850c22e176SPhilippe Mathieu-Daudé }
1286f9c4bb80SRichard Henderson 
1287d53106c9SRichard Henderson #define HELPER_INFO_INIT(I)      (&(I)->cif)
1288d53106c9SRichard Henderson #define HELPER_INFO_INIT_VAL(I)  init_ffi_layout(I)
1289d53106c9SRichard Henderson #else
1290d53106c9SRichard Henderson #define HELPER_INFO_INIT(I)      (&(I)->init)
1291d53106c9SRichard Henderson #define HELPER_INFO_INIT_VAL(I)  1
12920c22e176SPhilippe Mathieu-Daudé #endif /* CONFIG_TCG_INTERPRETER */
129322f15579SRichard Henderson 
1294338b61e9SRichard Henderson static inline bool arg_slot_reg_p(unsigned arg_slot)
1295338b61e9SRichard Henderson {
1296338b61e9SRichard Henderson     /*
1297338b61e9SRichard Henderson      * Split the sizeof away from the comparison to avoid Werror from
1298338b61e9SRichard Henderson      * "unsigned < 0 is always false", when iarg_regs is empty.
1299338b61e9SRichard Henderson      */
1300338b61e9SRichard Henderson     unsigned nreg = ARRAY_SIZE(tcg_target_call_iarg_regs);
1301338b61e9SRichard Henderson     return arg_slot < nreg;
1302338b61e9SRichard Henderson }
1303338b61e9SRichard Henderson 
1304d78e4a4fSRichard Henderson static inline int arg_slot_stk_ofs(unsigned arg_slot)
1305d78e4a4fSRichard Henderson {
1306d78e4a4fSRichard Henderson     unsigned max = TCG_STATIC_CALL_ARGS_SIZE / sizeof(tcg_target_long);
1307d78e4a4fSRichard Henderson     unsigned stk_slot = arg_slot - ARRAY_SIZE(tcg_target_call_iarg_regs);
1308d78e4a4fSRichard Henderson 
1309d78e4a4fSRichard Henderson     tcg_debug_assert(stk_slot < max);
1310d78e4a4fSRichard Henderson     return TCG_TARGET_CALL_STACK_OFFSET + stk_slot * sizeof(tcg_target_long);
1311d78e4a4fSRichard Henderson }
1312d78e4a4fSRichard Henderson 
131339004a71SRichard Henderson typedef struct TCGCumulativeArgs {
131439004a71SRichard Henderson     int arg_idx;                /* tcg_gen_callN args[] */
131539004a71SRichard Henderson     int info_in_idx;            /* TCGHelperInfo in[] */
131639004a71SRichard Henderson     int arg_slot;               /* regs+stack slot */
131739004a71SRichard Henderson     int ref_slot;               /* stack slots for references */
131839004a71SRichard Henderson } TCGCumulativeArgs;
131939004a71SRichard Henderson 
132039004a71SRichard Henderson static void layout_arg_even(TCGCumulativeArgs *cum)
132139004a71SRichard Henderson {
132239004a71SRichard Henderson     cum->arg_slot += cum->arg_slot & 1;
132339004a71SRichard Henderson }
132439004a71SRichard Henderson 
132539004a71SRichard Henderson static void layout_arg_1(TCGCumulativeArgs *cum, TCGHelperInfo *info,
132639004a71SRichard Henderson                          TCGCallArgumentKind kind)
132739004a71SRichard Henderson {
132839004a71SRichard Henderson     TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx];
132939004a71SRichard Henderson 
133039004a71SRichard Henderson     *loc = (TCGCallArgumentLoc){
133139004a71SRichard Henderson         .kind = kind,
133239004a71SRichard Henderson         .arg_idx = cum->arg_idx,
133339004a71SRichard Henderson         .arg_slot = cum->arg_slot,
133439004a71SRichard Henderson     };
133539004a71SRichard Henderson     cum->info_in_idx++;
133639004a71SRichard Henderson     cum->arg_slot++;
133739004a71SRichard Henderson }
133839004a71SRichard Henderson 
133939004a71SRichard Henderson static void layout_arg_normal_n(TCGCumulativeArgs *cum,
134039004a71SRichard Henderson                                 TCGHelperInfo *info, int n)
134139004a71SRichard Henderson {
134239004a71SRichard Henderson     TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx];
134339004a71SRichard Henderson 
134439004a71SRichard Henderson     for (int i = 0; i < n; ++i) {
134539004a71SRichard Henderson         /* Layout all using the same arg_idx, adjusting the subindex. */
134639004a71SRichard Henderson         loc[i] = (TCGCallArgumentLoc){
134739004a71SRichard Henderson             .kind = TCG_CALL_ARG_NORMAL,
134839004a71SRichard Henderson             .arg_idx = cum->arg_idx,
134939004a71SRichard Henderson             .tmp_subindex = i,
135039004a71SRichard Henderson             .arg_slot = cum->arg_slot + i,
135139004a71SRichard Henderson         };
135239004a71SRichard Henderson     }
135339004a71SRichard Henderson     cum->info_in_idx += n;
135439004a71SRichard Henderson     cum->arg_slot += n;
135539004a71SRichard Henderson }
135639004a71SRichard Henderson 
1357313bdea8SRichard Henderson static void layout_arg_by_ref(TCGCumulativeArgs *cum, TCGHelperInfo *info)
1358313bdea8SRichard Henderson {
1359313bdea8SRichard Henderson     TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx];
1360313bdea8SRichard Henderson     int n = 128 / TCG_TARGET_REG_BITS;
1361313bdea8SRichard Henderson 
1362313bdea8SRichard Henderson     /* The first subindex carries the pointer. */
1363313bdea8SRichard Henderson     layout_arg_1(cum, info, TCG_CALL_ARG_BY_REF);
1364313bdea8SRichard Henderson 
1365313bdea8SRichard Henderson     /*
1366313bdea8SRichard Henderson      * The callee is allowed to clobber memory associated with
1367313bdea8SRichard Henderson      * structure pass by-reference.  Therefore we must make copies.
1368313bdea8SRichard Henderson      * Allocate space from "ref_slot", which will be adjusted to
1369313bdea8SRichard Henderson      * follow the parameters on the stack.
1370313bdea8SRichard Henderson      */
1371313bdea8SRichard Henderson     loc[0].ref_slot = cum->ref_slot;
1372313bdea8SRichard Henderson 
1373313bdea8SRichard Henderson     /*
1374313bdea8SRichard Henderson      * Subsequent words also go into the reference slot, but
1375313bdea8SRichard Henderson      * do not accumulate into the regular arguments.
1376313bdea8SRichard Henderson      */
1377313bdea8SRichard Henderson     for (int i = 1; i < n; ++i) {
1378313bdea8SRichard Henderson         loc[i] = (TCGCallArgumentLoc){
1379313bdea8SRichard Henderson             .kind = TCG_CALL_ARG_BY_REF_N,
1380313bdea8SRichard Henderson             .arg_idx = cum->arg_idx,
1381313bdea8SRichard Henderson             .tmp_subindex = i,
1382313bdea8SRichard Henderson             .ref_slot = cum->ref_slot + i,
1383313bdea8SRichard Henderson         };
1384313bdea8SRichard Henderson     }
1385e18ed26cSRichard Henderson     cum->info_in_idx += n - 1;  /* i=0 accounted for in layout_arg_1 */
1386313bdea8SRichard Henderson     cum->ref_slot += n;
1387313bdea8SRichard Henderson }
1388313bdea8SRichard Henderson 
138939004a71SRichard Henderson static void init_call_layout(TCGHelperInfo *info)
139039004a71SRichard Henderson {
139139004a71SRichard Henderson     int max_reg_slots = ARRAY_SIZE(tcg_target_call_iarg_regs);
139239004a71SRichard Henderson     int max_stk_slots = TCG_STATIC_CALL_ARGS_SIZE / sizeof(tcg_target_long);
139339004a71SRichard Henderson     unsigned typemask = info->typemask;
139439004a71SRichard Henderson     unsigned typecode;
139539004a71SRichard Henderson     TCGCumulativeArgs cum = { };
139639004a71SRichard Henderson 
139739004a71SRichard Henderson     /*
139839004a71SRichard Henderson      * Parse and place any function return value.
139939004a71SRichard Henderson      */
140039004a71SRichard Henderson     typecode = typemask & 7;
140139004a71SRichard Henderson     switch (typecode) {
140239004a71SRichard Henderson     case dh_typecode_void:
140339004a71SRichard Henderson         info->nr_out = 0;
140439004a71SRichard Henderson         break;
140539004a71SRichard Henderson     case dh_typecode_i32:
140639004a71SRichard Henderson     case dh_typecode_s32:
140739004a71SRichard Henderson     case dh_typecode_ptr:
140839004a71SRichard Henderson         info->nr_out = 1;
140939004a71SRichard Henderson         info->out_kind = TCG_CALL_RET_NORMAL;
141039004a71SRichard Henderson         break;
141139004a71SRichard Henderson     case dh_typecode_i64:
141239004a71SRichard Henderson     case dh_typecode_s64:
141339004a71SRichard Henderson         info->nr_out = 64 / TCG_TARGET_REG_BITS;
141439004a71SRichard Henderson         info->out_kind = TCG_CALL_RET_NORMAL;
14155e3d0c19SRichard Henderson         /* Query the last register now to trigger any assert early. */
14165e3d0c19SRichard Henderson         tcg_target_call_oarg_reg(info->out_kind, info->nr_out - 1);
1417466d3759SRichard Henderson         break;
1418466d3759SRichard Henderson     case dh_typecode_i128:
1419466d3759SRichard Henderson         info->nr_out = 128 / TCG_TARGET_REG_BITS;
14205427a9a7SRichard Henderson         info->out_kind = TCG_TARGET_CALL_RET_I128;
14215427a9a7SRichard Henderson         switch (TCG_TARGET_CALL_RET_I128) {
1422466d3759SRichard Henderson         case TCG_CALL_RET_NORMAL:
14235e3d0c19SRichard Henderson             /* Query the last register now to trigger any assert early. */
14245e3d0c19SRichard Henderson             tcg_target_call_oarg_reg(info->out_kind, info->nr_out - 1);
1425466d3759SRichard Henderson             break;
1426c6556aa0SRichard Henderson         case TCG_CALL_RET_BY_VEC:
1427c6556aa0SRichard Henderson             /* Query the single register now to trigger any assert early. */
1428c6556aa0SRichard Henderson             tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0);
1429c6556aa0SRichard Henderson             break;
1430313bdea8SRichard Henderson         case TCG_CALL_RET_BY_REF:
1431313bdea8SRichard Henderson             /*
1432313bdea8SRichard Henderson              * Allocate the first argument to the output.
1433313bdea8SRichard Henderson              * We don't need to store this anywhere, just make it
1434313bdea8SRichard Henderson              * unavailable for use in the input loop below.
1435313bdea8SRichard Henderson              */
1436313bdea8SRichard Henderson             cum.arg_slot = 1;
1437313bdea8SRichard Henderson             break;
1438466d3759SRichard Henderson         default:
1439466d3759SRichard Henderson             qemu_build_not_reached();
1440466d3759SRichard Henderson         }
144139004a71SRichard Henderson         break;
144239004a71SRichard Henderson     default:
144339004a71SRichard Henderson         g_assert_not_reached();
144439004a71SRichard Henderson     }
144539004a71SRichard Henderson 
144639004a71SRichard Henderson     /*
144739004a71SRichard Henderson      * Parse and place function arguments.
144839004a71SRichard Henderson      */
144939004a71SRichard Henderson     for (typemask >>= 3; typemask; typemask >>= 3, cum.arg_idx++) {
145039004a71SRichard Henderson         TCGCallArgumentKind kind;
145139004a71SRichard Henderson         TCGType type;
145239004a71SRichard Henderson 
145339004a71SRichard Henderson         typecode = typemask & 7;
145439004a71SRichard Henderson         switch (typecode) {
145539004a71SRichard Henderson         case dh_typecode_i32:
145639004a71SRichard Henderson         case dh_typecode_s32:
145739004a71SRichard Henderson             type = TCG_TYPE_I32;
145839004a71SRichard Henderson             break;
145939004a71SRichard Henderson         case dh_typecode_i64:
146039004a71SRichard Henderson         case dh_typecode_s64:
146139004a71SRichard Henderson             type = TCG_TYPE_I64;
146239004a71SRichard Henderson             break;
146339004a71SRichard Henderson         case dh_typecode_ptr:
146439004a71SRichard Henderson             type = TCG_TYPE_PTR;
146539004a71SRichard Henderson             break;
1466466d3759SRichard Henderson         case dh_typecode_i128:
1467466d3759SRichard Henderson             type = TCG_TYPE_I128;
1468466d3759SRichard Henderson             break;
146939004a71SRichard Henderson         default:
147039004a71SRichard Henderson             g_assert_not_reached();
147139004a71SRichard Henderson         }
147239004a71SRichard Henderson 
147339004a71SRichard Henderson         switch (type) {
147439004a71SRichard Henderson         case TCG_TYPE_I32:
147539004a71SRichard Henderson             switch (TCG_TARGET_CALL_ARG_I32) {
147639004a71SRichard Henderson             case TCG_CALL_ARG_EVEN:
147739004a71SRichard Henderson                 layout_arg_even(&cum);
147839004a71SRichard Henderson                 /* fall through */
147939004a71SRichard Henderson             case TCG_CALL_ARG_NORMAL:
148039004a71SRichard Henderson                 layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL);
148139004a71SRichard Henderson                 break;
148239004a71SRichard Henderson             case TCG_CALL_ARG_EXTEND:
148339004a71SRichard Henderson                 kind = TCG_CALL_ARG_EXTEND_U + (typecode & 1);
148439004a71SRichard Henderson                 layout_arg_1(&cum, info, kind);
148539004a71SRichard Henderson                 break;
148639004a71SRichard Henderson             default:
148739004a71SRichard Henderson                 qemu_build_not_reached();
148839004a71SRichard Henderson             }
148939004a71SRichard Henderson             break;
149039004a71SRichard Henderson 
149139004a71SRichard Henderson         case TCG_TYPE_I64:
149239004a71SRichard Henderson             switch (TCG_TARGET_CALL_ARG_I64) {
149339004a71SRichard Henderson             case TCG_CALL_ARG_EVEN:
149439004a71SRichard Henderson                 layout_arg_even(&cum);
149539004a71SRichard Henderson                 /* fall through */
149639004a71SRichard Henderson             case TCG_CALL_ARG_NORMAL:
149739004a71SRichard Henderson                 if (TCG_TARGET_REG_BITS == 32) {
149839004a71SRichard Henderson                     layout_arg_normal_n(&cum, info, 2);
149939004a71SRichard Henderson                 } else {
150039004a71SRichard Henderson                     layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL);
150139004a71SRichard Henderson                 }
150239004a71SRichard Henderson                 break;
150339004a71SRichard Henderson             default:
150439004a71SRichard Henderson                 qemu_build_not_reached();
150539004a71SRichard Henderson             }
150639004a71SRichard Henderson             break;
150739004a71SRichard Henderson 
1508466d3759SRichard Henderson         case TCG_TYPE_I128:
15095427a9a7SRichard Henderson             switch (TCG_TARGET_CALL_ARG_I128) {
1510466d3759SRichard Henderson             case TCG_CALL_ARG_EVEN:
1511466d3759SRichard Henderson                 layout_arg_even(&cum);
1512466d3759SRichard Henderson                 /* fall through */
1513466d3759SRichard Henderson             case TCG_CALL_ARG_NORMAL:
1514466d3759SRichard Henderson                 layout_arg_normal_n(&cum, info, 128 / TCG_TARGET_REG_BITS);
1515466d3759SRichard Henderson                 break;
1516313bdea8SRichard Henderson             case TCG_CALL_ARG_BY_REF:
1517313bdea8SRichard Henderson                 layout_arg_by_ref(&cum, info);
1518313bdea8SRichard Henderson                 break;
1519466d3759SRichard Henderson             default:
1520466d3759SRichard Henderson                 qemu_build_not_reached();
1521466d3759SRichard Henderson             }
1522466d3759SRichard Henderson             break;
1523466d3759SRichard Henderson 
152439004a71SRichard Henderson         default:
152539004a71SRichard Henderson             g_assert_not_reached();
152639004a71SRichard Henderson         }
152739004a71SRichard Henderson     }
152839004a71SRichard Henderson     info->nr_in = cum.info_in_idx;
152939004a71SRichard Henderson 
153039004a71SRichard Henderson     /* Validate that we didn't overrun the input array. */
153139004a71SRichard Henderson     assert(cum.info_in_idx <= ARRAY_SIZE(info->in));
153239004a71SRichard Henderson     /* Validate the backend has enough argument space. */
153339004a71SRichard Henderson     assert(cum.arg_slot <= max_reg_slots + max_stk_slots);
1534313bdea8SRichard Henderson 
1535313bdea8SRichard Henderson     /*
1536313bdea8SRichard Henderson      * Relocate the "ref_slot" area to the end of the parameters.
1537313bdea8SRichard Henderson      * Minimizing this stack offset helps code size for x86,
1538313bdea8SRichard Henderson      * which has a signed 8-bit offset encoding.
1539313bdea8SRichard Henderson      */
1540313bdea8SRichard Henderson     if (cum.ref_slot != 0) {
1541313bdea8SRichard Henderson         int ref_base = 0;
1542313bdea8SRichard Henderson 
1543313bdea8SRichard Henderson         if (cum.arg_slot > max_reg_slots) {
1544313bdea8SRichard Henderson             int align = __alignof(Int128) / sizeof(tcg_target_long);
1545313bdea8SRichard Henderson 
1546313bdea8SRichard Henderson             ref_base = cum.arg_slot - max_reg_slots;
1547313bdea8SRichard Henderson             if (align > 1) {
1548313bdea8SRichard Henderson                 ref_base = ROUND_UP(ref_base, align);
1549313bdea8SRichard Henderson             }
1550313bdea8SRichard Henderson         }
1551313bdea8SRichard Henderson         assert(ref_base + cum.ref_slot <= max_stk_slots);
1552d78e4a4fSRichard Henderson         ref_base += max_reg_slots;
1553313bdea8SRichard Henderson 
1554313bdea8SRichard Henderson         if (ref_base != 0) {
1555313bdea8SRichard Henderson             for (int i = cum.info_in_idx - 1; i >= 0; --i) {
1556313bdea8SRichard Henderson                 TCGCallArgumentLoc *loc = &info->in[i];
1557313bdea8SRichard Henderson                 switch (loc->kind) {
1558313bdea8SRichard Henderson                 case TCG_CALL_ARG_BY_REF:
1559313bdea8SRichard Henderson                 case TCG_CALL_ARG_BY_REF_N:
1560313bdea8SRichard Henderson                     loc->ref_slot += ref_base;
1561313bdea8SRichard Henderson                     break;
1562313bdea8SRichard Henderson                 default:
1563313bdea8SRichard Henderson                     break;
1564313bdea8SRichard Henderson                 }
1565313bdea8SRichard Henderson             }
1566313bdea8SRichard Henderson         }
1567313bdea8SRichard Henderson     }
156839004a71SRichard Henderson }
156939004a71SRichard Henderson 
157091478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)];
1571501fb3daSRichard Henderson static void process_constraint_sets(void);
15721c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
15731c2adb95SRichard Henderson                                             TCGReg reg, const char *name);
157491478cefSRichard Henderson 
1575a9d107faSRichard Henderson static void tcg_context_init(unsigned max_threads)
1576c896fe29Sbellard {
1577a76aabd3SRichard Henderson     TCGContext *s = &tcg_init_ctx;
15783e80824eSRichard Henderson     int n, i;
15791c2adb95SRichard Henderson     TCGTemp *ts;
1580c896fe29Sbellard 
1581c896fe29Sbellard     memset(s, 0, sizeof(*s));
1582c896fe29Sbellard     s->nb_globals = 0;
1583c896fe29Sbellard 
15848429a1caSRichard Henderson     init_call_layout(&info_helper_ld32_mmu);
15858429a1caSRichard Henderson     init_call_layout(&info_helper_ld64_mmu);
1586ebebea53SRichard Henderson     init_call_layout(&info_helper_ld128_mmu);
15878429a1caSRichard Henderson     init_call_layout(&info_helper_st32_mmu);
15888429a1caSRichard Henderson     init_call_layout(&info_helper_st64_mmu);
1589ebebea53SRichard Henderson     init_call_layout(&info_helper_st128_mmu);
15908429a1caSRichard Henderson 
1591c896fe29Sbellard     tcg_target_init(s);
1592501fb3daSRichard Henderson     process_constraint_sets();
159391478cefSRichard Henderson 
159491478cefSRichard Henderson     /* Reverse the order of the saved registers, assuming they're all at
159591478cefSRichard Henderson        the start of tcg_target_reg_alloc_order.  */
159691478cefSRichard Henderson     for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) {
159791478cefSRichard Henderson         int r = tcg_target_reg_alloc_order[n];
159891478cefSRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) {
159991478cefSRichard Henderson             break;
160091478cefSRichard Henderson         }
160191478cefSRichard Henderson     }
160291478cefSRichard Henderson     for (i = 0; i < n; ++i) {
160391478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i];
160491478cefSRichard Henderson     }
160591478cefSRichard Henderson     for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) {
160691478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i];
160791478cefSRichard Henderson     }
1608b1311c4aSEmilio G. Cota 
1609b1311c4aSEmilio G. Cota     tcg_ctx = s;
16103468b59eSEmilio G. Cota     /*
16113468b59eSEmilio G. Cota      * In user-mode we simply share the init context among threads, since we
16123468b59eSEmilio G. Cota      * use a single region. See the documentation tcg_region_init() for the
16133468b59eSEmilio G. Cota      * reasoning behind this.
1614a9d107faSRichard Henderson      * In system-mode we will have at most max_threads TCG threads.
16153468b59eSEmilio G. Cota      */
16163468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
1617df2cce29SEmilio G. Cota     tcg_ctxs = &tcg_ctx;
16180e2d61cfSRichard Henderson     tcg_cur_ctxs = 1;
16190e2d61cfSRichard Henderson     tcg_max_ctxs = 1;
16203468b59eSEmilio G. Cota #else
1621a9d107faSRichard Henderson     tcg_max_ctxs = max_threads;
1622a9d107faSRichard Henderson     tcg_ctxs = g_new0(TCGContext *, max_threads);
16233468b59eSEmilio G. Cota #endif
16241c2adb95SRichard Henderson 
16251c2adb95SRichard Henderson     tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0));
16261c2adb95SRichard Henderson     ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env");
1627ad75a51eSRichard Henderson     tcg_env = temp_tcgv_ptr(ts);
16289002ec79SRichard Henderson }
1629b03cce8eSbellard 
1630a9d107faSRichard Henderson void tcg_init(size_t tb_size, int splitwx, unsigned max_threads)
1631a76aabd3SRichard Henderson {
1632a9d107faSRichard Henderson     tcg_context_init(max_threads);
1633a9d107faSRichard Henderson     tcg_region_init(tb_size, splitwx, max_threads);
1634a76aabd3SRichard Henderson }
1635a76aabd3SRichard Henderson 
16366e3b2bfdSEmilio G. Cota /*
16376e3b2bfdSEmilio G. Cota  * Allocate TBs right before their corresponding translated code, making
16386e3b2bfdSEmilio G. Cota  * sure that TBs and code are on different cache lines.
16396e3b2bfdSEmilio G. Cota  */
16406e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s)
16416e3b2bfdSEmilio G. Cota {
16426e3b2bfdSEmilio G. Cota     uintptr_t align = qemu_icache_linesize;
16436e3b2bfdSEmilio G. Cota     TranslationBlock *tb;
16446e3b2bfdSEmilio G. Cota     void *next;
16456e3b2bfdSEmilio G. Cota 
1646e8feb96fSEmilio G. Cota  retry:
16476e3b2bfdSEmilio G. Cota     tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align);
16486e3b2bfdSEmilio G. Cota     next = (void *)ROUND_UP((uintptr_t)(tb + 1), align);
16496e3b2bfdSEmilio G. Cota 
16506e3b2bfdSEmilio G. Cota     if (unlikely(next > s->code_gen_highwater)) {
1651e8feb96fSEmilio G. Cota         if (tcg_region_alloc(s)) {
16526e3b2bfdSEmilio G. Cota             return NULL;
16536e3b2bfdSEmilio G. Cota         }
1654e8feb96fSEmilio G. Cota         goto retry;
1655e8feb96fSEmilio G. Cota     }
1656d73415a3SStefan Hajnoczi     qatomic_set(&s->code_gen_ptr, next);
16576e3b2bfdSEmilio G. Cota     return tb;
16586e3b2bfdSEmilio G. Cota }
16596e3b2bfdSEmilio G. Cota 
1660935f75aeSRichard Henderson void tcg_prologue_init(void)
16619002ec79SRichard Henderson {
1662935f75aeSRichard Henderson     TCGContext *s = tcg_ctx;
1663b0a0794aSRichard Henderson     size_t prologue_size;
16648163b749SRichard Henderson 
1665b0a0794aSRichard Henderson     s->code_ptr = s->code_gen_ptr;
1666b0a0794aSRichard Henderson     s->code_buf = s->code_gen_ptr;
16675b38ee31SRichard Henderson     s->data_gen_ptr = NULL;
1668b91ccb31SRichard Henderson 
1669b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
1670b0a0794aSRichard Henderson     tcg_qemu_tb_exec = (tcg_prologue_fn *)tcg_splitwx_to_rx(s->code_ptr);
1671b91ccb31SRichard Henderson #endif
16728163b749SRichard Henderson 
16735b38ee31SRichard Henderson     s->pool_labels = NULL;
16745b38ee31SRichard Henderson 
1675653b87ebSRoman Bolshakov     qemu_thread_jit_write();
16768163b749SRichard Henderson     /* Generate the prologue.  */
1677b03cce8eSbellard     tcg_target_qemu_prologue(s);
16785b38ee31SRichard Henderson 
16795b38ee31SRichard Henderson     /* Allow the prologue to put e.g. guest_base into a pool entry.  */
16805b38ee31SRichard Henderson     {
16811768987bSRichard Henderson         int result = tcg_out_pool_finalize(s);
16821768987bSRichard Henderson         tcg_debug_assert(result == 0);
16835b38ee31SRichard Henderson     }
16845b38ee31SRichard Henderson 
1685b0a0794aSRichard Henderson     prologue_size = tcg_current_code_size(s);
16865584e2dbSIlya Leoshkevich     perf_report_prologue(s->code_gen_ptr, prologue_size);
1687b0a0794aSRichard Henderson 
1688df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
1689b0a0794aSRichard Henderson     flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf),
1690b0a0794aSRichard Henderson                         (uintptr_t)s->code_buf, prologue_size);
1691df5d2b16SRichard Henderson #endif
16928163b749SRichard Henderson 
1693d6b64b2bSRichard Henderson     if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) {
1694c60f599bSRichard Henderson         FILE *logfile = qemu_log_trylock();
169578b54858SRichard Henderson         if (logfile) {
169678b54858SRichard Henderson             fprintf(logfile, "PROLOGUE: [size=%zu]\n", prologue_size);
16975b38ee31SRichard Henderson             if (s->data_gen_ptr) {
1698b0a0794aSRichard Henderson                 size_t code_size = s->data_gen_ptr - s->code_gen_ptr;
16995b38ee31SRichard Henderson                 size_t data_size = prologue_size - code_size;
17005b38ee31SRichard Henderson                 size_t i;
17015b38ee31SRichard Henderson 
170278b54858SRichard Henderson                 disas(logfile, s->code_gen_ptr, code_size);
17035b38ee31SRichard Henderson 
17045b38ee31SRichard Henderson                 for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) {
17055b38ee31SRichard Henderson                     if (sizeof(tcg_target_ulong) == 8) {
170678b54858SRichard Henderson                         fprintf(logfile,
170778b54858SRichard Henderson                                 "0x%08" PRIxPTR ":  .quad  0x%016" PRIx64 "\n",
17085b38ee31SRichard Henderson                                 (uintptr_t)s->data_gen_ptr + i,
17095b38ee31SRichard Henderson                                 *(uint64_t *)(s->data_gen_ptr + i));
17105b38ee31SRichard Henderson                     } else {
171178b54858SRichard Henderson                         fprintf(logfile,
171278b54858SRichard Henderson                                 "0x%08" PRIxPTR ":  .long  0x%08x\n",
17135b38ee31SRichard Henderson                                 (uintptr_t)s->data_gen_ptr + i,
17145b38ee31SRichard Henderson                                 *(uint32_t *)(s->data_gen_ptr + i));
17155b38ee31SRichard Henderson                     }
17165b38ee31SRichard Henderson                 }
17175b38ee31SRichard Henderson             } else {
171878b54858SRichard Henderson                 disas(logfile, s->code_gen_ptr, prologue_size);
17195b38ee31SRichard Henderson             }
172078b54858SRichard Henderson             fprintf(logfile, "\n");
1721fc59d2d8SRobert Foley             qemu_log_unlock(logfile);
1722d6b64b2bSRichard Henderson         }
172378b54858SRichard Henderson     }
1724cedbcb01SEmilio G. Cota 
17256eea0434SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
17266eea0434SRichard Henderson     /*
17276eea0434SRichard Henderson      * Assert that goto_ptr is implemented completely, setting an epilogue.
17286eea0434SRichard Henderson      * For tci, we use NULL as the signal to return from the interpreter,
17296eea0434SRichard Henderson      * so skip this check.
17306eea0434SRichard Henderson      */
17318b5c2b62SRichard Henderson     tcg_debug_assert(tcg_code_gen_epilogue != NULL);
17326eea0434SRichard Henderson #endif
1733d1c74ab3SRichard Henderson 
1734d1c74ab3SRichard Henderson     tcg_region_prologue_set(s);
1735c896fe29Sbellard }
1736c896fe29Sbellard 
1737c896fe29Sbellard void tcg_func_start(TCGContext *s)
1738c896fe29Sbellard {
1739c896fe29Sbellard     tcg_pool_reset(s);
1740c896fe29Sbellard     s->nb_temps = s->nb_globals;
17410ec9eabcSRichard Henderson 
17420ec9eabcSRichard Henderson     /* No temps have been previously allocated for size or locality.  */
174304e006abSRichard Henderson     tcg_temp_ebb_reset_freed(s);
17440ec9eabcSRichard Henderson 
1745c0522136SRichard Henderson     /* No constant temps have been previously allocated. */
1746c0522136SRichard Henderson     for (int i = 0; i < TCG_TYPE_COUNT; ++i) {
1747c0522136SRichard Henderson         if (s->const_table[i]) {
1748c0522136SRichard Henderson             g_hash_table_remove_all(s->const_table[i]);
1749c0522136SRichard Henderson         }
1750c0522136SRichard Henderson     }
1751c0522136SRichard Henderson 
1752abebf925SRichard Henderson     s->nb_ops = 0;
1753c896fe29Sbellard     s->nb_labels = 0;
1754c896fe29Sbellard     s->current_frame_offset = s->frame_start;
1755c896fe29Sbellard 
17560a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG
17570a209d4bSRichard Henderson     s->goto_tb_issue_mask = 0;
17580a209d4bSRichard Henderson #endif
17590a209d4bSRichard Henderson 
176015fa08f8SRichard Henderson     QTAILQ_INIT(&s->ops);
176115fa08f8SRichard Henderson     QTAILQ_INIT(&s->free_ops);
176207843f75SRichard Henderson     s->emit_before_op = NULL;
1763bef16ab4SRichard Henderson     QSIMPLEQ_INIT(&s->labels);
17644baf3978SRichard Henderson 
1765a0ecb8e4SRichard Henderson     tcg_debug_assert(s->addr_type <= TCG_TYPE_REG);
1766747bd69dSRichard Henderson     tcg_debug_assert(s->insn_start_words > 0);
1767c896fe29Sbellard }
1768c896fe29Sbellard 
1769ae30e866SRichard Henderson static TCGTemp *tcg_temp_alloc(TCGContext *s)
17707ca4b752SRichard Henderson {
17717ca4b752SRichard Henderson     int n = s->nb_temps++;
1772ae30e866SRichard Henderson 
1773ae30e866SRichard Henderson     if (n >= TCG_MAX_TEMPS) {
1774db6b7d0cSRichard Henderson         tcg_raise_tb_overflow(s);
1775ae30e866SRichard Henderson     }
17767ca4b752SRichard Henderson     return memset(&s->temps[n], 0, sizeof(TCGTemp));
17777ca4b752SRichard Henderson }
17787ca4b752SRichard Henderson 
1779ae30e866SRichard Henderson static TCGTemp *tcg_global_alloc(TCGContext *s)
17807ca4b752SRichard Henderson {
1781fa477d25SRichard Henderson     TCGTemp *ts;
1782fa477d25SRichard Henderson 
17837ca4b752SRichard Henderson     tcg_debug_assert(s->nb_globals == s->nb_temps);
1784ae30e866SRichard Henderson     tcg_debug_assert(s->nb_globals < TCG_MAX_TEMPS);
17857ca4b752SRichard Henderson     s->nb_globals++;
1786fa477d25SRichard Henderson     ts = tcg_temp_alloc(s);
1787ee17db83SRichard Henderson     ts->kind = TEMP_GLOBAL;
1788fa477d25SRichard Henderson 
1789fa477d25SRichard Henderson     return ts;
1790c896fe29Sbellard }
1791c896fe29Sbellard 
1792085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
1793b6638662SRichard Henderson                                             TCGReg reg, const char *name)
1794c896fe29Sbellard {
1795c896fe29Sbellard     TCGTemp *ts;
1796c896fe29Sbellard 
17971a057554SRichard Henderson     tcg_debug_assert(TCG_TARGET_REG_BITS == 64 || type == TCG_TYPE_I32);
17987ca4b752SRichard Henderson 
17997ca4b752SRichard Henderson     ts = tcg_global_alloc(s);
1800c896fe29Sbellard     ts->base_type = type;
1801c896fe29Sbellard     ts->type = type;
1802ee17db83SRichard Henderson     ts->kind = TEMP_FIXED;
1803c896fe29Sbellard     ts->reg = reg;
1804c896fe29Sbellard     ts->name = name;
1805c896fe29Sbellard     tcg_regset_set_reg(s->reserved_regs, reg);
18067ca4b752SRichard Henderson 
1807085272b3SRichard Henderson     return ts;
1808a7812ae4Spbrook }
1809a7812ae4Spbrook 
1810b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size)
1811a7812ae4Spbrook {
1812b3a62939SRichard Henderson     s->frame_start = start;
1813b3a62939SRichard Henderson     s->frame_end = start + size;
1814085272b3SRichard Henderson     s->frame_temp
1815085272b3SRichard Henderson         = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame");
1816b3a62939SRichard Henderson }
1817a7812ae4Spbrook 
18184643f3e0SRichard Henderson static TCGTemp *tcg_global_mem_new_internal(TCGv_ptr base, intptr_t offset,
18194643f3e0SRichard Henderson                                             const char *name, TCGType type)
1820c896fe29Sbellard {
1821b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1822dc41aa7dSRichard Henderson     TCGTemp *base_ts = tcgv_ptr_temp(base);
18237ca4b752SRichard Henderson     TCGTemp *ts = tcg_global_alloc(s);
1824aef85402SRichard Henderson     int indirect_reg = 0;
1825c896fe29Sbellard 
1826c0522136SRichard Henderson     switch (base_ts->kind) {
1827c0522136SRichard Henderson     case TEMP_FIXED:
1828c0522136SRichard Henderson         break;
1829c0522136SRichard Henderson     case TEMP_GLOBAL:
18305a18407fSRichard Henderson         /* We do not support double-indirect registers.  */
18315a18407fSRichard Henderson         tcg_debug_assert(!base_ts->indirect_reg);
1832b3915dbbSRichard Henderson         base_ts->indirect_base = 1;
18335a18407fSRichard Henderson         s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64
18345a18407fSRichard Henderson                             ? 2 : 1);
18355a18407fSRichard Henderson         indirect_reg = 1;
1836c0522136SRichard Henderson         break;
1837c0522136SRichard Henderson     default:
1838c0522136SRichard Henderson         g_assert_not_reached();
1839b3915dbbSRichard Henderson     }
1840b3915dbbSRichard Henderson 
18417ca4b752SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
18427ca4b752SRichard Henderson         TCGTemp *ts2 = tcg_global_alloc(s);
1843c896fe29Sbellard         char buf[64];
18447ca4b752SRichard Henderson 
18457ca4b752SRichard Henderson         ts->base_type = TCG_TYPE_I64;
1846c896fe29Sbellard         ts->type = TCG_TYPE_I32;
1847b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1848c896fe29Sbellard         ts->mem_allocated = 1;
1849b3a62939SRichard Henderson         ts->mem_base = base_ts;
1850aef85402SRichard Henderson         ts->mem_offset = offset;
1851c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1852c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_0");
1853c896fe29Sbellard         ts->name = strdup(buf);
1854c896fe29Sbellard 
18557ca4b752SRichard Henderson         tcg_debug_assert(ts2 == ts + 1);
18567ca4b752SRichard Henderson         ts2->base_type = TCG_TYPE_I64;
18577ca4b752SRichard Henderson         ts2->type = TCG_TYPE_I32;
1858b3915dbbSRichard Henderson         ts2->indirect_reg = indirect_reg;
18597ca4b752SRichard Henderson         ts2->mem_allocated = 1;
18607ca4b752SRichard Henderson         ts2->mem_base = base_ts;
1861aef85402SRichard Henderson         ts2->mem_offset = offset + 4;
1862fac87bd2SRichard Henderson         ts2->temp_subindex = 1;
1863c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1864c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_1");
1865120c1084SRichard Henderson         ts2->name = strdup(buf);
18667ca4b752SRichard Henderson     } else {
1867c896fe29Sbellard         ts->base_type = type;
1868c896fe29Sbellard         ts->type = type;
1869b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1870c896fe29Sbellard         ts->mem_allocated = 1;
1871b3a62939SRichard Henderson         ts->mem_base = base_ts;
1872c896fe29Sbellard         ts->mem_offset = offset;
1873c896fe29Sbellard         ts->name = name;
1874c896fe29Sbellard     }
1875085272b3SRichard Henderson     return ts;
1876c896fe29Sbellard }
1877c896fe29Sbellard 
18784643f3e0SRichard Henderson TCGv_i32 tcg_global_mem_new_i32(TCGv_ptr reg, intptr_t off, const char *name)
18794643f3e0SRichard Henderson {
18804643f3e0SRichard Henderson     TCGTemp *ts = tcg_global_mem_new_internal(reg, off, name, TCG_TYPE_I32);
18814643f3e0SRichard Henderson     return temp_tcgv_i32(ts);
18824643f3e0SRichard Henderson }
18834643f3e0SRichard Henderson 
18844643f3e0SRichard Henderson TCGv_i64 tcg_global_mem_new_i64(TCGv_ptr reg, intptr_t off, const char *name)
18854643f3e0SRichard Henderson {
18864643f3e0SRichard Henderson     TCGTemp *ts = tcg_global_mem_new_internal(reg, off, name, TCG_TYPE_I64);
18874643f3e0SRichard Henderson     return temp_tcgv_i64(ts);
18884643f3e0SRichard Henderson }
18894643f3e0SRichard Henderson 
18904643f3e0SRichard Henderson TCGv_ptr tcg_global_mem_new_ptr(TCGv_ptr reg, intptr_t off, const char *name)
18914643f3e0SRichard Henderson {
18924643f3e0SRichard Henderson     TCGTemp *ts = tcg_global_mem_new_internal(reg, off, name, TCG_TYPE_PTR);
18934643f3e0SRichard Henderson     return temp_tcgv_ptr(ts);
18944643f3e0SRichard Henderson }
18954643f3e0SRichard Henderson 
1896fb04ab7dSRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, TCGTempKind kind)
1897c896fe29Sbellard {
1898b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1899c896fe29Sbellard     TCGTemp *ts;
1900e1c08b00SRichard Henderson     int n;
1901c896fe29Sbellard 
1902e1c08b00SRichard Henderson     if (kind == TEMP_EBB) {
1903e1c08b00SRichard Henderson         int idx = find_first_bit(s->free_temps[type].l, TCG_MAX_TEMPS);
1904e1c08b00SRichard Henderson 
19050ec9eabcSRichard Henderson         if (idx < TCG_MAX_TEMPS) {
19060ec9eabcSRichard Henderson             /* There is already an available temp with the right type.  */
1907e1c08b00SRichard Henderson             clear_bit(idx, s->free_temps[type].l);
19080ec9eabcSRichard Henderson 
1909e8996ee0Sbellard             ts = &s->temps[idx];
1910e8996ee0Sbellard             ts->temp_allocated = 1;
19117ca4b752SRichard Henderson             tcg_debug_assert(ts->base_type == type);
1912ee17db83SRichard Henderson             tcg_debug_assert(ts->kind == kind);
19132f2e911dSRichard Henderson             return ts;
1914e1c08b00SRichard Henderson         }
1915e8996ee0Sbellard     } else {
1916e1c08b00SRichard Henderson         tcg_debug_assert(kind == TEMP_TB);
1917e1c08b00SRichard Henderson     }
191843eef72fSRichard Henderson 
191943eef72fSRichard Henderson     switch (type) {
192043eef72fSRichard Henderson     case TCG_TYPE_I32:
192143eef72fSRichard Henderson     case TCG_TYPE_V64:
192243eef72fSRichard Henderson     case TCG_TYPE_V128:
192343eef72fSRichard Henderson     case TCG_TYPE_V256:
192443eef72fSRichard Henderson         n = 1;
192543eef72fSRichard Henderson         break;
192643eef72fSRichard Henderson     case TCG_TYPE_I64:
192743eef72fSRichard Henderson         n = 64 / TCG_TARGET_REG_BITS;
192843eef72fSRichard Henderson         break;
192943eef72fSRichard Henderson     case TCG_TYPE_I128:
193043eef72fSRichard Henderson         n = 128 / TCG_TARGET_REG_BITS;
193143eef72fSRichard Henderson         break;
193243eef72fSRichard Henderson     default:
193343eef72fSRichard Henderson         g_assert_not_reached();
193443eef72fSRichard Henderson     }
193543eef72fSRichard Henderson 
19367ca4b752SRichard Henderson     ts = tcg_temp_alloc(s);
193743eef72fSRichard Henderson     ts->base_type = type;
193843eef72fSRichard Henderson     ts->temp_allocated = 1;
193943eef72fSRichard Henderson     ts->kind = kind;
194043eef72fSRichard Henderson 
194143eef72fSRichard Henderson     if (n == 1) {
194243eef72fSRichard Henderson         ts->type = type;
194343eef72fSRichard Henderson     } else {
194443eef72fSRichard Henderson         ts->type = TCG_TYPE_REG;
194543eef72fSRichard Henderson 
1946e1c08b00SRichard Henderson         for (int i = 1; i < n; ++i) {
19477ca4b752SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
19487ca4b752SRichard Henderson 
194943eef72fSRichard Henderson             tcg_debug_assert(ts2 == ts + i);
195043eef72fSRichard Henderson             ts2->base_type = type;
195143eef72fSRichard Henderson             ts2->type = TCG_TYPE_REG;
19527ca4b752SRichard Henderson             ts2->temp_allocated = 1;
195343eef72fSRichard Henderson             ts2->temp_subindex = i;
1954ee17db83SRichard Henderson             ts2->kind = kind;
195543eef72fSRichard Henderson         }
1956c896fe29Sbellard     }
1957085272b3SRichard Henderson     return ts;
1958c896fe29Sbellard }
1959c896fe29Sbellard 
19604643f3e0SRichard Henderson TCGv_i32 tcg_temp_new_i32(void)
19614643f3e0SRichard Henderson {
19624643f3e0SRichard Henderson     return temp_tcgv_i32(tcg_temp_new_internal(TCG_TYPE_I32, TEMP_TB));
19634643f3e0SRichard Henderson }
19644643f3e0SRichard Henderson 
19654643f3e0SRichard Henderson TCGv_i32 tcg_temp_ebb_new_i32(void)
19664643f3e0SRichard Henderson {
19674643f3e0SRichard Henderson     return temp_tcgv_i32(tcg_temp_new_internal(TCG_TYPE_I32, TEMP_EBB));
19684643f3e0SRichard Henderson }
19694643f3e0SRichard Henderson 
19704643f3e0SRichard Henderson TCGv_i64 tcg_temp_new_i64(void)
19714643f3e0SRichard Henderson {
19724643f3e0SRichard Henderson     return temp_tcgv_i64(tcg_temp_new_internal(TCG_TYPE_I64, TEMP_TB));
19734643f3e0SRichard Henderson }
19744643f3e0SRichard Henderson 
19754643f3e0SRichard Henderson TCGv_i64 tcg_temp_ebb_new_i64(void)
19764643f3e0SRichard Henderson {
19774643f3e0SRichard Henderson     return temp_tcgv_i64(tcg_temp_new_internal(TCG_TYPE_I64, TEMP_EBB));
19784643f3e0SRichard Henderson }
19794643f3e0SRichard Henderson 
19804643f3e0SRichard Henderson TCGv_ptr tcg_temp_new_ptr(void)
19814643f3e0SRichard Henderson {
19824643f3e0SRichard Henderson     return temp_tcgv_ptr(tcg_temp_new_internal(TCG_TYPE_PTR, TEMP_TB));
19834643f3e0SRichard Henderson }
19844643f3e0SRichard Henderson 
19854643f3e0SRichard Henderson TCGv_ptr tcg_temp_ebb_new_ptr(void)
19864643f3e0SRichard Henderson {
19874643f3e0SRichard Henderson     return temp_tcgv_ptr(tcg_temp_new_internal(TCG_TYPE_PTR, TEMP_EBB));
19884643f3e0SRichard Henderson }
19894643f3e0SRichard Henderson 
19904643f3e0SRichard Henderson TCGv_i128 tcg_temp_new_i128(void)
19914643f3e0SRichard Henderson {
19924643f3e0SRichard Henderson     return temp_tcgv_i128(tcg_temp_new_internal(TCG_TYPE_I128, TEMP_TB));
19934643f3e0SRichard Henderson }
19944643f3e0SRichard Henderson 
19954643f3e0SRichard Henderson TCGv_i128 tcg_temp_ebb_new_i128(void)
19964643f3e0SRichard Henderson {
19974643f3e0SRichard Henderson     return temp_tcgv_i128(tcg_temp_new_internal(TCG_TYPE_I128, TEMP_EBB));
19984643f3e0SRichard Henderson }
19994643f3e0SRichard Henderson 
2000d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type)
2001d2fd745fSRichard Henderson {
2002d2fd745fSRichard Henderson     TCGTemp *t;
2003d2fd745fSRichard Henderson 
2004d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG
2005d2fd745fSRichard Henderson     switch (type) {
2006d2fd745fSRichard Henderson     case TCG_TYPE_V64:
2007d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v64);
2008d2fd745fSRichard Henderson         break;
2009d2fd745fSRichard Henderson     case TCG_TYPE_V128:
2010d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v128);
2011d2fd745fSRichard Henderson         break;
2012d2fd745fSRichard Henderson     case TCG_TYPE_V256:
2013d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v256);
2014d2fd745fSRichard Henderson         break;
2015d2fd745fSRichard Henderson     default:
2016d2fd745fSRichard Henderson         g_assert_not_reached();
2017d2fd745fSRichard Henderson     }
2018d2fd745fSRichard Henderson #endif
2019d2fd745fSRichard Henderson 
2020bbf989bfSRichard Henderson     t = tcg_temp_new_internal(type, TEMP_EBB);
2021d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
2022d2fd745fSRichard Henderson }
2023d2fd745fSRichard Henderson 
2024d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp.  */
2025d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match)
2026d2fd745fSRichard Henderson {
2027d2fd745fSRichard Henderson     TCGTemp *t = tcgv_vec_temp(match);
2028d2fd745fSRichard Henderson 
2029d2fd745fSRichard Henderson     tcg_debug_assert(t->temp_allocated != 0);
2030d2fd745fSRichard Henderson 
2031bbf989bfSRichard Henderson     t = tcg_temp_new_internal(t->base_type, TEMP_EBB);
2032d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
2033d2fd745fSRichard Henderson }
2034d2fd745fSRichard Henderson 
20355bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts)
2036c896fe29Sbellard {
2037b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
2038c896fe29Sbellard 
2039c7482438SRichard Henderson     switch (ts->kind) {
2040c7482438SRichard Henderson     case TEMP_CONST:
2041f57c6915SRichard Henderson     case TEMP_TB:
20422f2e911dSRichard Henderson         /* Silently ignore free. */
2043c7482438SRichard Henderson         break;
20442f2e911dSRichard Henderson     case TEMP_EBB:
2045eabb7b91SAurelien Jarno         tcg_debug_assert(ts->temp_allocated != 0);
2046e8996ee0Sbellard         ts->temp_allocated = 0;
20472f2e911dSRichard Henderson         set_bit(temp_idx(ts), s->free_temps[ts->base_type].l);
20482f2e911dSRichard Henderson         break;
20492f2e911dSRichard Henderson     default:
20502f2e911dSRichard Henderson         /* It never made sense to free TEMP_FIXED or TEMP_GLOBAL. */
20512f2e911dSRichard Henderson         g_assert_not_reached();
2052e1c08b00SRichard Henderson     }
2053e8996ee0Sbellard }
2054e8996ee0Sbellard 
205558b79713SRichard Henderson void tcg_temp_free_i32(TCGv_i32 arg)
205658b79713SRichard Henderson {
205758b79713SRichard Henderson     tcg_temp_free_internal(tcgv_i32_temp(arg));
205858b79713SRichard Henderson }
205958b79713SRichard Henderson 
206058b79713SRichard Henderson void tcg_temp_free_i64(TCGv_i64 arg)
206158b79713SRichard Henderson {
206258b79713SRichard Henderson     tcg_temp_free_internal(tcgv_i64_temp(arg));
206358b79713SRichard Henderson }
206458b79713SRichard Henderson 
206558b79713SRichard Henderson void tcg_temp_free_i128(TCGv_i128 arg)
206658b79713SRichard Henderson {
206758b79713SRichard Henderson     tcg_temp_free_internal(tcgv_i128_temp(arg));
206858b79713SRichard Henderson }
206958b79713SRichard Henderson 
207058b79713SRichard Henderson void tcg_temp_free_ptr(TCGv_ptr arg)
207158b79713SRichard Henderson {
207258b79713SRichard Henderson     tcg_temp_free_internal(tcgv_ptr_temp(arg));
207358b79713SRichard Henderson }
207458b79713SRichard Henderson 
207558b79713SRichard Henderson void tcg_temp_free_vec(TCGv_vec arg)
207658b79713SRichard Henderson {
207758b79713SRichard Henderson     tcg_temp_free_internal(tcgv_vec_temp(arg));
207858b79713SRichard Henderson }
207958b79713SRichard Henderson 
2080c0522136SRichard Henderson TCGTemp *tcg_constant_internal(TCGType type, int64_t val)
2081c0522136SRichard Henderson {
2082c0522136SRichard Henderson     TCGContext *s = tcg_ctx;
2083c0522136SRichard Henderson     GHashTable *h = s->const_table[type];
2084c0522136SRichard Henderson     TCGTemp *ts;
2085c0522136SRichard Henderson 
2086c0522136SRichard Henderson     if (h == NULL) {
2087c0522136SRichard Henderson         h = g_hash_table_new(g_int64_hash, g_int64_equal);
2088c0522136SRichard Henderson         s->const_table[type] = h;
2089c0522136SRichard Henderson     }
2090c0522136SRichard Henderson 
2091c0522136SRichard Henderson     ts = g_hash_table_lookup(h, &val);
2092c0522136SRichard Henderson     if (ts == NULL) {
2093aef85402SRichard Henderson         int64_t *val_ptr;
2094aef85402SRichard Henderson 
2095c0522136SRichard Henderson         ts = tcg_temp_alloc(s);
2096c0522136SRichard Henderson 
2097c0522136SRichard Henderson         if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
2098c0522136SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
2099c0522136SRichard Henderson 
2100aef85402SRichard Henderson             tcg_debug_assert(ts2 == ts + 1);
2101aef85402SRichard Henderson 
2102c0522136SRichard Henderson             ts->base_type = TCG_TYPE_I64;
2103c0522136SRichard Henderson             ts->type = TCG_TYPE_I32;
2104c0522136SRichard Henderson             ts->kind = TEMP_CONST;
2105c0522136SRichard Henderson             ts->temp_allocated = 1;
2106c0522136SRichard Henderson 
2107c0522136SRichard Henderson             ts2->base_type = TCG_TYPE_I64;
2108c0522136SRichard Henderson             ts2->type = TCG_TYPE_I32;
2109c0522136SRichard Henderson             ts2->kind = TEMP_CONST;
2110c0522136SRichard Henderson             ts2->temp_allocated = 1;
2111fac87bd2SRichard Henderson             ts2->temp_subindex = 1;
2112aef85402SRichard Henderson 
2113aef85402SRichard Henderson             /*
2114aef85402SRichard Henderson              * Retain the full value of the 64-bit constant in the low
2115aef85402SRichard Henderson              * part, so that the hash table works.  Actual uses will
2116aef85402SRichard Henderson              * truncate the value to the low part.
2117aef85402SRichard Henderson              */
2118aef85402SRichard Henderson             ts[HOST_BIG_ENDIAN].val = val;
2119aef85402SRichard Henderson             ts[!HOST_BIG_ENDIAN].val = val >> 32;
2120aef85402SRichard Henderson             val_ptr = &ts[HOST_BIG_ENDIAN].val;
2121c0522136SRichard Henderson         } else {
2122c0522136SRichard Henderson             ts->base_type = type;
2123c0522136SRichard Henderson             ts->type = type;
2124c0522136SRichard Henderson             ts->kind = TEMP_CONST;
2125c0522136SRichard Henderson             ts->temp_allocated = 1;
2126c0522136SRichard Henderson             ts->val = val;
2127aef85402SRichard Henderson             val_ptr = &ts->val;
2128c0522136SRichard Henderson         }
2129aef85402SRichard Henderson         g_hash_table_insert(h, val_ptr, ts);
2130c0522136SRichard Henderson     }
2131c0522136SRichard Henderson 
2132c0522136SRichard Henderson     return ts;
2133c0522136SRichard Henderson }
2134c0522136SRichard Henderson 
213516edaee7SRichard Henderson TCGv_i32 tcg_constant_i32(int32_t val)
213616edaee7SRichard Henderson {
213716edaee7SRichard Henderson     return temp_tcgv_i32(tcg_constant_internal(TCG_TYPE_I32, val));
213816edaee7SRichard Henderson }
213916edaee7SRichard Henderson 
214016edaee7SRichard Henderson TCGv_i64 tcg_constant_i64(int64_t val)
214116edaee7SRichard Henderson {
214216edaee7SRichard Henderson     return temp_tcgv_i64(tcg_constant_internal(TCG_TYPE_I64, val));
214316edaee7SRichard Henderson }
214416edaee7SRichard Henderson 
214516edaee7SRichard Henderson TCGv_ptr tcg_constant_ptr_int(intptr_t val)
214616edaee7SRichard Henderson {
214716edaee7SRichard Henderson     return temp_tcgv_ptr(tcg_constant_internal(TCG_TYPE_PTR, val));
214816edaee7SRichard Henderson }
214916edaee7SRichard Henderson 
2150c0522136SRichard Henderson TCGv_vec tcg_constant_vec(TCGType type, unsigned vece, int64_t val)
2151c0522136SRichard Henderson {
2152c0522136SRichard Henderson     val = dup_const(vece, val);
2153c0522136SRichard Henderson     return temp_tcgv_vec(tcg_constant_internal(type, val));
2154c0522136SRichard Henderson }
2155c0522136SRichard Henderson 
215688d4005bSRichard Henderson TCGv_vec tcg_constant_vec_matching(TCGv_vec match, unsigned vece, int64_t val)
215788d4005bSRichard Henderson {
215888d4005bSRichard Henderson     TCGTemp *t = tcgv_vec_temp(match);
215988d4005bSRichard Henderson 
216088d4005bSRichard Henderson     tcg_debug_assert(t->temp_allocated != 0);
216188d4005bSRichard Henderson     return tcg_constant_vec(t->base_type, vece, val);
216288d4005bSRichard Henderson }
216388d4005bSRichard Henderson 
2164177f648fSRichard Henderson #ifdef CONFIG_DEBUG_TCG
2165177f648fSRichard Henderson size_t temp_idx(TCGTemp *ts)
2166177f648fSRichard Henderson {
2167177f648fSRichard Henderson     ptrdiff_t n = ts - tcg_ctx->temps;
2168177f648fSRichard Henderson     assert(n >= 0 && n < tcg_ctx->nb_temps);
2169177f648fSRichard Henderson     return n;
2170177f648fSRichard Henderson }
2171177f648fSRichard Henderson 
2172177f648fSRichard Henderson TCGTemp *tcgv_i32_temp(TCGv_i32 v)
2173177f648fSRichard Henderson {
2174177f648fSRichard Henderson     uintptr_t o = (uintptr_t)v - offsetof(TCGContext, temps);
2175177f648fSRichard Henderson 
2176177f648fSRichard Henderson     assert(o < sizeof(TCGTemp) * tcg_ctx->nb_temps);
2177177f648fSRichard Henderson     assert(o % sizeof(TCGTemp) == 0);
2178177f648fSRichard Henderson 
2179177f648fSRichard Henderson     return (void *)tcg_ctx + (uintptr_t)v;
2180177f648fSRichard Henderson }
2181177f648fSRichard Henderson #endif /* CONFIG_DEBUG_TCG */
2182177f648fSRichard Henderson 
2183771a5925SRichard Henderson /*
2184771a5925SRichard Henderson  * Return true if OP may appear in the opcode stream with TYPE.
2185771a5925SRichard Henderson  * Test the runtime variable that controls each opcode.
2186771a5925SRichard Henderson  */
2187771a5925SRichard Henderson bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags)
2188be0f34b5SRichard Henderson {
2189f44824ccSRichard Henderson     bool has_type;
2190f44824ccSRichard Henderson 
2191f44824ccSRichard Henderson     switch (type) {
2192f44824ccSRichard Henderson     case TCG_TYPE_I32:
2193f44824ccSRichard Henderson         has_type = true;
2194f44824ccSRichard Henderson         break;
2195f44824ccSRichard Henderson     case TCG_TYPE_I64:
2196f44824ccSRichard Henderson         has_type = TCG_TARGET_REG_BITS == 64;
2197f44824ccSRichard Henderson         break;
2198f44824ccSRichard Henderson     case TCG_TYPE_V64:
2199f44824ccSRichard Henderson         has_type = TCG_TARGET_HAS_v64;
2200f44824ccSRichard Henderson         break;
2201f44824ccSRichard Henderson     case TCG_TYPE_V128:
2202f44824ccSRichard Henderson         has_type = TCG_TARGET_HAS_v128;
2203f44824ccSRichard Henderson         break;
2204f44824ccSRichard Henderson     case TCG_TYPE_V256:
2205f44824ccSRichard Henderson         has_type = TCG_TARGET_HAS_v256;
2206f44824ccSRichard Henderson         break;
2207f44824ccSRichard Henderson     default:
2208f44824ccSRichard Henderson         has_type = false;
2209f44824ccSRichard Henderson         break;
2210f44824ccSRichard Henderson     }
2211d2fd745fSRichard Henderson 
2212be0f34b5SRichard Henderson     switch (op) {
2213be0f34b5SRichard Henderson     case INDEX_op_discard:
2214be0f34b5SRichard Henderson     case INDEX_op_set_label:
2215be0f34b5SRichard Henderson     case INDEX_op_call:
2216be0f34b5SRichard Henderson     case INDEX_op_br:
2217be0f34b5SRichard Henderson     case INDEX_op_mb:
2218be0f34b5SRichard Henderson     case INDEX_op_insn_start:
2219be0f34b5SRichard Henderson     case INDEX_op_exit_tb:
2220be0f34b5SRichard Henderson     case INDEX_op_goto_tb:
2221f4e01e30SRichard Henderson     case INDEX_op_goto_ptr:
222250b7a197SRichard Henderson     case INDEX_op_qemu_ld_i32:
222350b7a197SRichard Henderson     case INDEX_op_qemu_st_i32:
222450b7a197SRichard Henderson     case INDEX_op_qemu_ld_i64:
222550b7a197SRichard Henderson     case INDEX_op_qemu_st_i64:
2226be0f34b5SRichard Henderson         return true;
2227be0f34b5SRichard Henderson 
222850b7a197SRichard Henderson     case INDEX_op_qemu_st8_i32:
222907ce0b05SRichard Henderson         return TCG_TARGET_HAS_qemu_st8_i32;
223007ce0b05SRichard Henderson 
223150b7a197SRichard Henderson     case INDEX_op_qemu_ld_i128:
223250b7a197SRichard Henderson     case INDEX_op_qemu_st_i128:
223312fde9bcSRichard Henderson         return TCG_TARGET_HAS_qemu_ldst_i128;
223412fde9bcSRichard Henderson 
223579602f63SRichard Henderson     case INDEX_op_add:
2236c3b920b3SRichard Henderson     case INDEX_op_and:
2237b5701261SRichard Henderson     case INDEX_op_mov:
223849bd7514SRichard Henderson     case INDEX_op_or:
2239fffd3dc9SRichard Henderson     case INDEX_op_xor:
2240b5701261SRichard Henderson         return has_type;
2241b5701261SRichard Henderson 
2242be0f34b5SRichard Henderson     case INDEX_op_setcond_i32:
2243be0f34b5SRichard Henderson     case INDEX_op_brcond_i32:
22443871be75SRichard Henderson     case INDEX_op_movcond_i32:
2245be0f34b5SRichard Henderson     case INDEX_op_ld8u_i32:
2246be0f34b5SRichard Henderson     case INDEX_op_ld8s_i32:
2247be0f34b5SRichard Henderson     case INDEX_op_ld16u_i32:
2248be0f34b5SRichard Henderson     case INDEX_op_ld16s_i32:
2249be0f34b5SRichard Henderson     case INDEX_op_ld_i32:
2250be0f34b5SRichard Henderson     case INDEX_op_st8_i32:
2251be0f34b5SRichard Henderson     case INDEX_op_st16_i32:
2252be0f34b5SRichard Henderson     case INDEX_op_st_i32:
2253be0f34b5SRichard Henderson     case INDEX_op_shl_i32:
2254be0f34b5SRichard Henderson     case INDEX_op_shr_i32:
2255be0f34b5SRichard Henderson     case INDEX_op_sar_i32:
2256c334de11SRichard Henderson     case INDEX_op_extract_i32:
2257c334de11SRichard Henderson     case INDEX_op_sextract_i32:
22586482e9d2SRichard Henderson     case INDEX_op_deposit_i32:
2259be0f34b5SRichard Henderson         return true;
2260be0f34b5SRichard Henderson 
22613635502dSRichard Henderson     case INDEX_op_negsetcond_i32:
22623635502dSRichard Henderson         return TCG_TARGET_HAS_negsetcond_i32;
2263be0f34b5SRichard Henderson     case INDEX_op_div_i32:
2264be0f34b5SRichard Henderson     case INDEX_op_divu_i32:
2265be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i32;
2266be0f34b5SRichard Henderson     case INDEX_op_rem_i32:
2267be0f34b5SRichard Henderson     case INDEX_op_remu_i32:
2268be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i32;
2269be0f34b5SRichard Henderson     case INDEX_op_div2_i32:
2270be0f34b5SRichard Henderson     case INDEX_op_divu2_i32:
2271be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i32;
2272be0f34b5SRichard Henderson     case INDEX_op_rotl_i32:
2273be0f34b5SRichard Henderson     case INDEX_op_rotr_i32:
2274be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i32;
2275fce1296fSRichard Henderson     case INDEX_op_extract2_i32:
2276fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i32;
2277be0f34b5SRichard Henderson     case INDEX_op_add2_i32:
2278be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i32;
2279be0f34b5SRichard Henderson     case INDEX_op_sub2_i32:
2280be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i32;
2281be0f34b5SRichard Henderson     case INDEX_op_mulu2_i32:
2282be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i32;
2283be0f34b5SRichard Henderson     case INDEX_op_muls2_i32:
2284be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i32;
2285be0f34b5SRichard Henderson     case INDEX_op_bswap16_i32:
2286be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i32;
2287be0f34b5SRichard Henderson     case INDEX_op_bswap32_i32:
2288be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i32;
2289be0f34b5SRichard Henderson     case INDEX_op_clz_i32:
2290be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i32;
2291be0f34b5SRichard Henderson     case INDEX_op_ctz_i32:
2292be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i32;
2293be0f34b5SRichard Henderson     case INDEX_op_ctpop_i32:
2294be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i32;
2295be0f34b5SRichard Henderson 
2296be0f34b5SRichard Henderson     case INDEX_op_brcond2_i32:
2297be0f34b5SRichard Henderson     case INDEX_op_setcond2_i32:
2298be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 32;
2299be0f34b5SRichard Henderson 
2300be0f34b5SRichard Henderson     case INDEX_op_setcond_i64:
2301be0f34b5SRichard Henderson     case INDEX_op_brcond_i64:
23023871be75SRichard Henderson     case INDEX_op_movcond_i64:
2303be0f34b5SRichard Henderson     case INDEX_op_ld8u_i64:
2304be0f34b5SRichard Henderson     case INDEX_op_ld8s_i64:
2305be0f34b5SRichard Henderson     case INDEX_op_ld16u_i64:
2306be0f34b5SRichard Henderson     case INDEX_op_ld16s_i64:
2307be0f34b5SRichard Henderson     case INDEX_op_ld32u_i64:
2308be0f34b5SRichard Henderson     case INDEX_op_ld32s_i64:
2309be0f34b5SRichard Henderson     case INDEX_op_ld_i64:
2310be0f34b5SRichard Henderson     case INDEX_op_st8_i64:
2311be0f34b5SRichard Henderson     case INDEX_op_st16_i64:
2312be0f34b5SRichard Henderson     case INDEX_op_st32_i64:
2313be0f34b5SRichard Henderson     case INDEX_op_st_i64:
2314be0f34b5SRichard Henderson     case INDEX_op_shl_i64:
2315be0f34b5SRichard Henderson     case INDEX_op_shr_i64:
2316be0f34b5SRichard Henderson     case INDEX_op_sar_i64:
2317be0f34b5SRichard Henderson     case INDEX_op_ext_i32_i64:
2318be0f34b5SRichard Henderson     case INDEX_op_extu_i32_i64:
2319c334de11SRichard Henderson     case INDEX_op_extract_i64:
2320c334de11SRichard Henderson     case INDEX_op_sextract_i64:
23216482e9d2SRichard Henderson     case INDEX_op_deposit_i64:
2322be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 64;
2323be0f34b5SRichard Henderson 
23243635502dSRichard Henderson     case INDEX_op_negsetcond_i64:
23253635502dSRichard Henderson         return TCG_TARGET_HAS_negsetcond_i64;
2326be0f34b5SRichard Henderson     case INDEX_op_div_i64:
2327be0f34b5SRichard Henderson     case INDEX_op_divu_i64:
2328be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i64;
2329be0f34b5SRichard Henderson     case INDEX_op_rem_i64:
2330be0f34b5SRichard Henderson     case INDEX_op_remu_i64:
2331be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i64;
2332be0f34b5SRichard Henderson     case INDEX_op_div2_i64:
2333be0f34b5SRichard Henderson     case INDEX_op_divu2_i64:
2334be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i64;
2335be0f34b5SRichard Henderson     case INDEX_op_rotl_i64:
2336be0f34b5SRichard Henderson     case INDEX_op_rotr_i64:
2337be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i64;
2338fce1296fSRichard Henderson     case INDEX_op_extract2_i64:
2339fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i64;
2340be0f34b5SRichard Henderson     case INDEX_op_extrl_i64_i32:
2341be0f34b5SRichard Henderson     case INDEX_op_extrh_i64_i32:
234213d885b0SRichard Henderson         return TCG_TARGET_HAS_extr_i64_i32;
2343be0f34b5SRichard Henderson     case INDEX_op_bswap16_i64:
2344be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i64;
2345be0f34b5SRichard Henderson     case INDEX_op_bswap32_i64:
2346be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i64;
2347be0f34b5SRichard Henderson     case INDEX_op_bswap64_i64:
2348be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap64_i64;
2349be0f34b5SRichard Henderson     case INDEX_op_clz_i64:
2350be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i64;
2351be0f34b5SRichard Henderson     case INDEX_op_ctz_i64:
2352be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i64;
2353be0f34b5SRichard Henderson     case INDEX_op_ctpop_i64:
2354be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i64;
2355be0f34b5SRichard Henderson     case INDEX_op_add2_i64:
2356be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i64;
2357be0f34b5SRichard Henderson     case INDEX_op_sub2_i64:
2358be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i64;
2359be0f34b5SRichard Henderson     case INDEX_op_mulu2_i64:
2360be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i64;
2361be0f34b5SRichard Henderson     case INDEX_op_muls2_i64:
2362be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i64;
2363be0f34b5SRichard Henderson 
2364d2fd745fSRichard Henderson     case INDEX_op_mov_vec:
2365d2fd745fSRichard Henderson     case INDEX_op_dup_vec:
236637ee55a0SRichard Henderson     case INDEX_op_dupm_vec:
2367d2fd745fSRichard Henderson     case INDEX_op_ld_vec:
2368d2fd745fSRichard Henderson     case INDEX_op_st_vec:
2369d2fd745fSRichard Henderson     case INDEX_op_add_vec:
2370d2fd745fSRichard Henderson     case INDEX_op_sub_vec:
2371d2fd745fSRichard Henderson     case INDEX_op_and_vec:
2372d2fd745fSRichard Henderson     case INDEX_op_or_vec:
2373d2fd745fSRichard Henderson     case INDEX_op_xor_vec:
2374212be173SRichard Henderson     case INDEX_op_cmp_vec:
2375f44824ccSRichard Henderson         return has_type;
2376d2fd745fSRichard Henderson     case INDEX_op_dup2_vec:
2377f44824ccSRichard Henderson         return has_type && TCG_TARGET_REG_BITS == 32;
2378d2fd745fSRichard Henderson     case INDEX_op_not_vec:
2379f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_not_vec;
2380d2fd745fSRichard Henderson     case INDEX_op_neg_vec:
2381f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_neg_vec;
2382bcefc902SRichard Henderson     case INDEX_op_abs_vec:
2383f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_abs_vec;
2384d2fd745fSRichard Henderson     case INDEX_op_andc_vec:
2385f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_andc_vec;
2386d2fd745fSRichard Henderson     case INDEX_op_orc_vec:
2387f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_orc_vec;
2388ed523473SRichard Henderson     case INDEX_op_nand_vec:
2389f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_nand_vec;
2390ed523473SRichard Henderson     case INDEX_op_nor_vec:
2391f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_nor_vec;
2392ed523473SRichard Henderson     case INDEX_op_eqv_vec:
2393f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_eqv_vec;
23943774030aSRichard Henderson     case INDEX_op_mul_vec:
2395f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_mul_vec;
2396d0ec9796SRichard Henderson     case INDEX_op_shli_vec:
2397d0ec9796SRichard Henderson     case INDEX_op_shri_vec:
2398d0ec9796SRichard Henderson     case INDEX_op_sari_vec:
2399f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_shi_vec;
2400d0ec9796SRichard Henderson     case INDEX_op_shls_vec:
2401d0ec9796SRichard Henderson     case INDEX_op_shrs_vec:
2402d0ec9796SRichard Henderson     case INDEX_op_sars_vec:
2403f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_shs_vec;
2404d0ec9796SRichard Henderson     case INDEX_op_shlv_vec:
2405d0ec9796SRichard Henderson     case INDEX_op_shrv_vec:
2406d0ec9796SRichard Henderson     case INDEX_op_sarv_vec:
2407f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_shv_vec;
2408b0f7e744SRichard Henderson     case INDEX_op_rotli_vec:
2409f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_roti_vec;
241023850a74SRichard Henderson     case INDEX_op_rotls_vec:
2411f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_rots_vec;
24125d0ceda9SRichard Henderson     case INDEX_op_rotlv_vec:
24135d0ceda9SRichard Henderson     case INDEX_op_rotrv_vec:
2414f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_rotv_vec;
24158afaf050SRichard Henderson     case INDEX_op_ssadd_vec:
24168afaf050SRichard Henderson     case INDEX_op_usadd_vec:
24178afaf050SRichard Henderson     case INDEX_op_sssub_vec:
24188afaf050SRichard Henderson     case INDEX_op_ussub_vec:
2419f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_sat_vec;
2420dd0a0fcdSRichard Henderson     case INDEX_op_smin_vec:
2421dd0a0fcdSRichard Henderson     case INDEX_op_umin_vec:
2422dd0a0fcdSRichard Henderson     case INDEX_op_smax_vec:
2423dd0a0fcdSRichard Henderson     case INDEX_op_umax_vec:
2424f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_minmax_vec;
242538dc1294SRichard Henderson     case INDEX_op_bitsel_vec:
2426f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_bitsel_vec;
2427f75da298SRichard Henderson     case INDEX_op_cmpsel_vec:
2428f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_cmpsel_vec;
2429d2fd745fSRichard Henderson 
2430db432672SRichard Henderson     default:
24315500bd9eSRichard Henderson         if (op < INDEX_op_last_generic) {
24325500bd9eSRichard Henderson             const TCGOutOp *outop;
24335500bd9eSRichard Henderson             TCGConstraintSetIndex con_set;
24345500bd9eSRichard Henderson 
24355500bd9eSRichard Henderson             if (!has_type) {
24365500bd9eSRichard Henderson                 return false;
24375500bd9eSRichard Henderson             }
24385500bd9eSRichard Henderson 
24395500bd9eSRichard Henderson             outop = all_outop[op];
24405500bd9eSRichard Henderson             tcg_debug_assert(outop != NULL);
24415500bd9eSRichard Henderson 
24425500bd9eSRichard Henderson             con_set = outop->static_constraint;
24435500bd9eSRichard Henderson             if (con_set == C_Dynamic) {
24445500bd9eSRichard Henderson                 con_set = outop->dynamic_constraint(type, flags);
24455500bd9eSRichard Henderson             }
24465500bd9eSRichard Henderson             if (con_set >= 0) {
2447db432672SRichard Henderson                 return true;
2448be0f34b5SRichard Henderson             }
24495500bd9eSRichard Henderson             tcg_debug_assert(con_set == C_NotImplemented);
24505500bd9eSRichard Henderson             return false;
24515500bd9eSRichard Henderson         }
24525500bd9eSRichard Henderson         tcg_debug_assert(op < NB_OPS);
24535500bd9eSRichard Henderson         return true;
24545500bd9eSRichard Henderson 
24555500bd9eSRichard Henderson     case INDEX_op_last_generic:
24565500bd9eSRichard Henderson         g_assert_not_reached();
24575500bd9eSRichard Henderson     }
2458be0f34b5SRichard Henderson }
2459be0f34b5SRichard Henderson 
24600e4c6424SRichard Henderson bool tcg_op_deposit_valid(TCGType type, unsigned ofs, unsigned len)
24610e4c6424SRichard Henderson {
24626482e9d2SRichard Henderson     unsigned width;
24636482e9d2SRichard Henderson 
24646482e9d2SRichard Henderson     tcg_debug_assert(type == TCG_TYPE_I32 || type == TCG_TYPE_I64);
24656482e9d2SRichard Henderson     width = (type == TCG_TYPE_I32 ? 32 : 64);
24666482e9d2SRichard Henderson 
24676482e9d2SRichard Henderson     tcg_debug_assert(ofs < width);
24680e4c6424SRichard Henderson     tcg_debug_assert(len > 0);
24696482e9d2SRichard Henderson     tcg_debug_assert(len <= width - ofs);
24706482e9d2SRichard Henderson 
24716482e9d2SRichard Henderson     return TCG_TARGET_deposit_valid(type, ofs, len);
24720e4c6424SRichard Henderson }
24730e4c6424SRichard Henderson 
247439004a71SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs);
247539004a71SRichard Henderson 
247683a0ad26SRichard Henderson static void tcg_gen_callN(void *func, TCGHelperInfo *info,
247783a0ad26SRichard Henderson                           TCGTemp *ret, TCGTemp **args)
2478c896fe29Sbellard {
247939004a71SRichard Henderson     TCGv_i64 extend_free[MAX_CALL_IARGS];
248039004a71SRichard Henderson     int n_extend = 0;
248175e8b9b7SRichard Henderson     TCGOp *op;
248239004a71SRichard Henderson     int i, n, pi = 0, total_args;
2483afb49896SRichard Henderson 
2484d53106c9SRichard Henderson     if (unlikely(g_once_init_enter(HELPER_INFO_INIT(info)))) {
2485d53106c9SRichard Henderson         init_call_layout(info);
2486d53106c9SRichard Henderson         g_once_init_leave(HELPER_INFO_INIT(info), HELPER_INFO_INIT_VAL(info));
2487d53106c9SRichard Henderson     }
2488d53106c9SRichard Henderson 
248939004a71SRichard Henderson     total_args = info->nr_out + info->nr_in + 2;
249039004a71SRichard Henderson     op = tcg_op_alloc(INDEX_op_call, total_args);
24912bece2c8SRichard Henderson 
249238b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN
249317083f6fSEmilio Cota     /* Flag helpers that may affect guest state */
2494b0748975SRichard Henderson     if (tcg_ctx->plugin_insn && !(info->flags & TCG_CALL_NO_SIDE_EFFECTS)) {
249538b47b19SEmilio G. Cota         tcg_ctx->plugin_insn->calls_helpers = true;
249638b47b19SEmilio G. Cota     }
249738b47b19SEmilio G. Cota #endif
249838b47b19SEmilio G. Cota 
249939004a71SRichard Henderson     TCGOP_CALLO(op) = n = info->nr_out;
250039004a71SRichard Henderson     switch (n) {
250139004a71SRichard Henderson     case 0:
250239004a71SRichard Henderson         tcg_debug_assert(ret == NULL);
250339004a71SRichard Henderson         break;
250439004a71SRichard Henderson     case 1:
250539004a71SRichard Henderson         tcg_debug_assert(ret != NULL);
250639004a71SRichard Henderson         op->args[pi++] = temp_arg(ret);
250739004a71SRichard Henderson         break;
250839004a71SRichard Henderson     case 2:
2509466d3759SRichard Henderson     case 4:
251039004a71SRichard Henderson         tcg_debug_assert(ret != NULL);
2511466d3759SRichard Henderson         tcg_debug_assert(ret->base_type == ret->type + ctz32(n));
251239004a71SRichard Henderson         tcg_debug_assert(ret->temp_subindex == 0);
2513466d3759SRichard Henderson         for (i = 0; i < n; ++i) {
2514466d3759SRichard Henderson             op->args[pi++] = temp_arg(ret + i);
2515466d3759SRichard Henderson         }
251639004a71SRichard Henderson         break;
251739004a71SRichard Henderson     default:
251839004a71SRichard Henderson         g_assert_not_reached();
251939004a71SRichard Henderson     }
25207319d83aSRichard Henderson 
252139004a71SRichard Henderson     TCGOP_CALLI(op) = n = info->nr_in;
252239004a71SRichard Henderson     for (i = 0; i < n; i++) {
252339004a71SRichard Henderson         const TCGCallArgumentLoc *loc = &info->in[i];
252439004a71SRichard Henderson         TCGTemp *ts = args[loc->arg_idx] + loc->tmp_subindex;
252539004a71SRichard Henderson 
252639004a71SRichard Henderson         switch (loc->kind) {
252739004a71SRichard Henderson         case TCG_CALL_ARG_NORMAL:
2528313bdea8SRichard Henderson         case TCG_CALL_ARG_BY_REF:
2529313bdea8SRichard Henderson         case TCG_CALL_ARG_BY_REF_N:
253039004a71SRichard Henderson             op->args[pi++] = temp_arg(ts);
253139004a71SRichard Henderson             break;
253239004a71SRichard Henderson 
253339004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_U:
253439004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_S:
253539004a71SRichard Henderson             {
25365dd48602SRichard Henderson                 TCGv_i64 temp = tcg_temp_ebb_new_i64();
253739004a71SRichard Henderson                 TCGv_i32 orig = temp_tcgv_i32(ts);
253839004a71SRichard Henderson 
253939004a71SRichard Henderson                 if (loc->kind == TCG_CALL_ARG_EXTEND_S) {
254018cf3d07SRichard Henderson                     tcg_gen_ext_i32_i64(temp, orig);
25412bece2c8SRichard Henderson                 } else {
254218cf3d07SRichard Henderson                     tcg_gen_extu_i32_i64(temp, orig);
25432bece2c8SRichard Henderson                 }
254439004a71SRichard Henderson                 op->args[pi++] = tcgv_i64_arg(temp);
254539004a71SRichard Henderson                 extend_free[n_extend++] = temp;
25462bece2c8SRichard Henderson             }
254739004a71SRichard Henderson             break;
25482bece2c8SRichard Henderson 
2549e2a9dd6bSRichard Henderson         default:
2550e2a9dd6bSRichard Henderson             g_assert_not_reached();
2551e2a9dd6bSRichard Henderson         }
2552c896fe29Sbellard     }
255383a0ad26SRichard Henderson     op->args[pi++] = (uintptr_t)func;
25543e92aa34SRichard Henderson     op->args[pi++] = (uintptr_t)info;
255539004a71SRichard Henderson     tcg_debug_assert(pi == total_args);
2556a7812ae4Spbrook 
255707843f75SRichard Henderson     if (tcg_ctx->emit_before_op) {
255807843f75SRichard Henderson         QTAILQ_INSERT_BEFORE(tcg_ctx->emit_before_op, op, link);
255907843f75SRichard Henderson     } else {
256039004a71SRichard Henderson         QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
256107843f75SRichard Henderson     }
25622bece2c8SRichard Henderson 
256339004a71SRichard Henderson     tcg_debug_assert(n_extend < ARRAY_SIZE(extend_free));
256439004a71SRichard Henderson     for (i = 0; i < n_extend; ++i) {
256539004a71SRichard Henderson         tcg_temp_free_i64(extend_free[i]);
2566eb8b0224SRichard Henderson     }
2567a7812ae4Spbrook }
2568c896fe29Sbellard 
256983a0ad26SRichard Henderson void tcg_gen_call0(void *func, TCGHelperInfo *info, TCGTemp *ret)
2570a3a692b8SRichard Henderson {
257183a0ad26SRichard Henderson     tcg_gen_callN(func, info, ret, NULL);
2572a3a692b8SRichard Henderson }
2573a3a692b8SRichard Henderson 
257483a0ad26SRichard Henderson void tcg_gen_call1(void *func, TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1)
2575a3a692b8SRichard Henderson {
257683a0ad26SRichard Henderson     tcg_gen_callN(func, info, ret, &t1);
2577a3a692b8SRichard Henderson }
2578a3a692b8SRichard Henderson 
257983a0ad26SRichard Henderson void tcg_gen_call2(void *func, TCGHelperInfo *info, TCGTemp *ret,
258083a0ad26SRichard Henderson                    TCGTemp *t1, TCGTemp *t2)
2581a3a692b8SRichard Henderson {
2582a3a692b8SRichard Henderson     TCGTemp *args[2] = { t1, t2 };
258383a0ad26SRichard Henderson     tcg_gen_callN(func, info, ret, args);
2584a3a692b8SRichard Henderson }
2585a3a692b8SRichard Henderson 
258683a0ad26SRichard Henderson void tcg_gen_call3(void *func, TCGHelperInfo *info, TCGTemp *ret,
258783a0ad26SRichard Henderson                    TCGTemp *t1, TCGTemp *t2, TCGTemp *t3)
2588a3a692b8SRichard Henderson {
2589a3a692b8SRichard Henderson     TCGTemp *args[3] = { t1, t2, t3 };
259083a0ad26SRichard Henderson     tcg_gen_callN(func, info, ret, args);
2591a3a692b8SRichard Henderson }
2592a3a692b8SRichard Henderson 
259383a0ad26SRichard Henderson void tcg_gen_call4(void *func, TCGHelperInfo *info, TCGTemp *ret,
259483a0ad26SRichard Henderson                    TCGTemp *t1, TCGTemp *t2, TCGTemp *t3, TCGTemp *t4)
2595a3a692b8SRichard Henderson {
2596a3a692b8SRichard Henderson     TCGTemp *args[4] = { t1, t2, t3, t4 };
259783a0ad26SRichard Henderson     tcg_gen_callN(func, info, ret, args);
2598a3a692b8SRichard Henderson }
2599a3a692b8SRichard Henderson 
260083a0ad26SRichard Henderson void tcg_gen_call5(void *func, TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1,
2601a3a692b8SRichard Henderson                    TCGTemp *t2, TCGTemp *t3, TCGTemp *t4, TCGTemp *t5)
2602a3a692b8SRichard Henderson {
2603a3a692b8SRichard Henderson     TCGTemp *args[5] = { t1, t2, t3, t4, t5 };
260483a0ad26SRichard Henderson     tcg_gen_callN(func, info, ret, args);
2605a3a692b8SRichard Henderson }
2606a3a692b8SRichard Henderson 
260783a0ad26SRichard Henderson void tcg_gen_call6(void *func, TCGHelperInfo *info, TCGTemp *ret,
260883a0ad26SRichard Henderson                    TCGTemp *t1, TCGTemp *t2, TCGTemp *t3,
260983a0ad26SRichard Henderson                    TCGTemp *t4, TCGTemp *t5, TCGTemp *t6)
2610a3a692b8SRichard Henderson {
2611a3a692b8SRichard Henderson     TCGTemp *args[6] = { t1, t2, t3, t4, t5, t6 };
261283a0ad26SRichard Henderson     tcg_gen_callN(func, info, ret, args);
2613a3a692b8SRichard Henderson }
2614a3a692b8SRichard Henderson 
261583a0ad26SRichard Henderson void tcg_gen_call7(void *func, TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1,
2616a3a692b8SRichard Henderson                    TCGTemp *t2, TCGTemp *t3, TCGTemp *t4,
2617a3a692b8SRichard Henderson                    TCGTemp *t5, TCGTemp *t6, TCGTemp *t7)
2618a3a692b8SRichard Henderson {
2619a3a692b8SRichard Henderson     TCGTemp *args[7] = { t1, t2, t3, t4, t5, t6, t7 };
262083a0ad26SRichard Henderson     tcg_gen_callN(func, info, ret, args);
2621a3a692b8SRichard Henderson }
2622a3a692b8SRichard Henderson 
26238fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s)
2624c896fe29Sbellard {
2625ac3b8891SRichard Henderson     int i, n;
2626ac3b8891SRichard Henderson 
2627ee17db83SRichard Henderson     for (i = 0, n = s->nb_temps; i < n; i++) {
2628ee17db83SRichard Henderson         TCGTemp *ts = &s->temps[i];
2629ee17db83SRichard Henderson         TCGTempVal val = TEMP_VAL_MEM;
2630ee17db83SRichard Henderson 
2631ee17db83SRichard Henderson         switch (ts->kind) {
2632c0522136SRichard Henderson         case TEMP_CONST:
2633c0522136SRichard Henderson             val = TEMP_VAL_CONST;
2634c0522136SRichard Henderson             break;
2635ee17db83SRichard Henderson         case TEMP_FIXED:
2636ee17db83SRichard Henderson             val = TEMP_VAL_REG;
2637ee17db83SRichard Henderson             break;
2638ee17db83SRichard Henderson         case TEMP_GLOBAL:
2639ee17db83SRichard Henderson             break;
2640c7482438SRichard Henderson         case TEMP_EBB:
2641ee17db83SRichard Henderson             val = TEMP_VAL_DEAD;
2642ee17db83SRichard Henderson             /* fall through */
2643f57c6915SRichard Henderson         case TEMP_TB:
2644e8996ee0Sbellard             ts->mem_allocated = 0;
2645ee17db83SRichard Henderson             break;
2646ee17db83SRichard Henderson         default:
2647ee17db83SRichard Henderson             g_assert_not_reached();
2648ee17db83SRichard Henderson         }
2649ee17db83SRichard Henderson         ts->val_type = val;
2650e8996ee0Sbellard     }
2651f8b2f202SRichard Henderson 
2652f8b2f202SRichard Henderson     memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp));
2653c896fe29Sbellard }
2654c896fe29Sbellard 
2655f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size,
2656f8b2f202SRichard Henderson                                  TCGTemp *ts)
2657c896fe29Sbellard {
26581807f4c4SRichard Henderson     int idx = temp_idx(ts);
2659ac56dd48Spbrook 
2660ee17db83SRichard Henderson     switch (ts->kind) {
2661ee17db83SRichard Henderson     case TEMP_FIXED:
2662ee17db83SRichard Henderson     case TEMP_GLOBAL:
2663ac56dd48Spbrook         pstrcpy(buf, buf_size, ts->name);
2664ee17db83SRichard Henderson         break;
2665f57c6915SRichard Henderson     case TEMP_TB:
2666641d5fbeSbellard         snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
2667ee17db83SRichard Henderson         break;
2668c7482438SRichard Henderson     case TEMP_EBB:
2669ac56dd48Spbrook         snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
2670ee17db83SRichard Henderson         break;
2671c0522136SRichard Henderson     case TEMP_CONST:
2672c0522136SRichard Henderson         switch (ts->type) {
2673c0522136SRichard Henderson         case TCG_TYPE_I32:
2674c0522136SRichard Henderson             snprintf(buf, buf_size, "$0x%x", (int32_t)ts->val);
2675c0522136SRichard Henderson             break;
2676c0522136SRichard Henderson #if TCG_TARGET_REG_BITS > 32
2677c0522136SRichard Henderson         case TCG_TYPE_I64:
2678c0522136SRichard Henderson             snprintf(buf, buf_size, "$0x%" PRIx64, ts->val);
2679c0522136SRichard Henderson             break;
2680c0522136SRichard Henderson #endif
2681c0522136SRichard Henderson         case TCG_TYPE_V64:
2682c0522136SRichard Henderson         case TCG_TYPE_V128:
2683c0522136SRichard Henderson         case TCG_TYPE_V256:
2684c0522136SRichard Henderson             snprintf(buf, buf_size, "v%d$0x%" PRIx64,
2685c0522136SRichard Henderson                      64 << (ts->type - TCG_TYPE_V64), ts->val);
2686c0522136SRichard Henderson             break;
2687c0522136SRichard Henderson         default:
2688c0522136SRichard Henderson             g_assert_not_reached();
2689c0522136SRichard Henderson         }
2690c0522136SRichard Henderson         break;
2691c896fe29Sbellard     }
2692c896fe29Sbellard     return buf;
2693c896fe29Sbellard }
2694c896fe29Sbellard 
269543439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf,
269643439139SRichard Henderson                              int buf_size, TCGArg arg)
2697f8b2f202SRichard Henderson {
269843439139SRichard Henderson     return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg));
2699f8b2f202SRichard Henderson }
2700f8b2f202SRichard Henderson 
2701f48f3edeSblueswir1 static const char * const cond_name[] =
2702f48f3edeSblueswir1 {
27030aed257fSRichard Henderson     [TCG_COND_NEVER] = "never",
27040aed257fSRichard Henderson     [TCG_COND_ALWAYS] = "always",
2705f48f3edeSblueswir1     [TCG_COND_EQ] = "eq",
2706f48f3edeSblueswir1     [TCG_COND_NE] = "ne",
2707f48f3edeSblueswir1     [TCG_COND_LT] = "lt",
2708f48f3edeSblueswir1     [TCG_COND_GE] = "ge",
2709f48f3edeSblueswir1     [TCG_COND_LE] = "le",
2710f48f3edeSblueswir1     [TCG_COND_GT] = "gt",
2711f48f3edeSblueswir1     [TCG_COND_LTU] = "ltu",
2712f48f3edeSblueswir1     [TCG_COND_GEU] = "geu",
2713f48f3edeSblueswir1     [TCG_COND_LEU] = "leu",
2714d48097d0SRichard Henderson     [TCG_COND_GTU] = "gtu",
2715d48097d0SRichard Henderson     [TCG_COND_TSTEQ] = "tsteq",
2716d48097d0SRichard Henderson     [TCG_COND_TSTNE] = "tstne",
2717f48f3edeSblueswir1 };
2718f48f3edeSblueswir1 
271912fde9bcSRichard Henderson static const char * const ldst_name[(MO_BSWAP | MO_SSIZE) + 1] =
2720f713d6adSRichard Henderson {
2721f713d6adSRichard Henderson     [MO_UB]   = "ub",
2722f713d6adSRichard Henderson     [MO_SB]   = "sb",
2723f713d6adSRichard Henderson     [MO_LEUW] = "leuw",
2724f713d6adSRichard Henderson     [MO_LESW] = "lesw",
2725f713d6adSRichard Henderson     [MO_LEUL] = "leul",
2726f713d6adSRichard Henderson     [MO_LESL] = "lesl",
2727fc313c64SFrédéric Pétrot     [MO_LEUQ] = "leq",
2728f713d6adSRichard Henderson     [MO_BEUW] = "beuw",
2729f713d6adSRichard Henderson     [MO_BESW] = "besw",
2730f713d6adSRichard Henderson     [MO_BEUL] = "beul",
2731f713d6adSRichard Henderson     [MO_BESL] = "besl",
2732fc313c64SFrédéric Pétrot     [MO_BEUQ] = "beq",
273312fde9bcSRichard Henderson     [MO_128 + MO_BE] = "beo",
273412fde9bcSRichard Henderson     [MO_128 + MO_LE] = "leo",
2735f713d6adSRichard Henderson };
2736f713d6adSRichard Henderson 
27371f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = {
27381f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "un+",
27391f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "al+",
27401f00b27fSSergey Sorokin     [MO_ALIGN_2 >> MO_ASHIFT]  = "al2+",
27411f00b27fSSergey Sorokin     [MO_ALIGN_4 >> MO_ASHIFT]  = "al4+",
27421f00b27fSSergey Sorokin     [MO_ALIGN_8 >> MO_ASHIFT]  = "al8+",
27431f00b27fSSergey Sorokin     [MO_ALIGN_16 >> MO_ASHIFT] = "al16+",
27441f00b27fSSergey Sorokin     [MO_ALIGN_32 >> MO_ASHIFT] = "al32+",
27451f00b27fSSergey Sorokin     [MO_ALIGN_64 >> MO_ASHIFT] = "al64+",
27461f00b27fSSergey Sorokin };
27471f00b27fSSergey Sorokin 
274837031fefSRichard Henderson static const char * const atom_name[(MO_ATOM_MASK >> MO_ATOM_SHIFT) + 1] = {
274937031fefSRichard Henderson     [MO_ATOM_IFALIGN >> MO_ATOM_SHIFT] = "",
275037031fefSRichard Henderson     [MO_ATOM_IFALIGN_PAIR >> MO_ATOM_SHIFT] = "pair+",
275137031fefSRichard Henderson     [MO_ATOM_WITHIN16 >> MO_ATOM_SHIFT] = "w16+",
275237031fefSRichard Henderson     [MO_ATOM_WITHIN16_PAIR >> MO_ATOM_SHIFT] = "w16p+",
275337031fefSRichard Henderson     [MO_ATOM_SUBALIGN >> MO_ATOM_SHIFT] = "sub+",
275437031fefSRichard Henderson     [MO_ATOM_NONE >> MO_ATOM_SHIFT] = "noat+",
275537031fefSRichard Henderson };
275637031fefSRichard Henderson 
2757587195bdSRichard Henderson static const char bswap_flag_name[][6] = {
2758587195bdSRichard Henderson     [TCG_BSWAP_IZ] = "iz",
2759587195bdSRichard Henderson     [TCG_BSWAP_OZ] = "oz",
2760587195bdSRichard Henderson     [TCG_BSWAP_OS] = "os",
2761587195bdSRichard Henderson     [TCG_BSWAP_IZ | TCG_BSWAP_OZ] = "iz,oz",
2762587195bdSRichard Henderson     [TCG_BSWAP_IZ | TCG_BSWAP_OS] = "iz,os",
2763587195bdSRichard Henderson };
2764587195bdSRichard Henderson 
2765b384c734SRichard Henderson #ifdef CONFIG_PLUGIN
2766b384c734SRichard Henderson static const char * const plugin_from_name[] = {
2767b384c734SRichard Henderson     "from-tb",
2768b384c734SRichard Henderson     "from-insn",
2769b384c734SRichard Henderson     "after-insn",
2770b384c734SRichard Henderson     "after-tb",
2771b384c734SRichard Henderson };
2772b384c734SRichard Henderson #endif
2773b384c734SRichard Henderson 
2774b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d)
2775b016486eSRichard Henderson {
2776b016486eSRichard Henderson     return (d & (d - 1)) == 0;
2777b016486eSRichard Henderson }
2778b016486eSRichard Henderson 
2779b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d)
2780b016486eSRichard Henderson {
2781b016486eSRichard Henderson     if (TCG_TARGET_NB_REGS <= 32) {
2782b016486eSRichard Henderson         return ctz32(d);
2783b016486eSRichard Henderson     } else {
2784b016486eSRichard Henderson         return ctz64(d);
2785b016486eSRichard Henderson     }
2786b016486eSRichard Henderson }
2787b016486eSRichard Henderson 
2788b7a83ff8SRichard Henderson /* Return only the number of characters output -- no error return. */
2789b7a83ff8SRichard Henderson #define ne_fprintf(...) \
2790b7a83ff8SRichard Henderson     ({ int ret_ = fprintf(__VA_ARGS__); ret_ >= 0 ? ret_ : 0; })
2791b7a83ff8SRichard Henderson 
2792b384c734SRichard Henderson void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs)
2793c896fe29Sbellard {
2794c896fe29Sbellard     char buf[128];
2795c45cb8bbSRichard Henderson     TCGOp *op;
2796c896fe29Sbellard 
279715fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
2798c45cb8bbSRichard Henderson         int i, k, nb_oargs, nb_iargs, nb_cargs;
2799c45cb8bbSRichard Henderson         const TCGOpDef *def;
2800c45cb8bbSRichard Henderson         TCGOpcode c;
2801bdfb460eSRichard Henderson         int col = 0;
2802c45cb8bbSRichard Henderson 
2803c45cb8bbSRichard Henderson         c = op->opc;
2804c896fe29Sbellard         def = &tcg_op_defs[c];
2805c45cb8bbSRichard Henderson 
2806765b842aSRichard Henderson         if (c == INDEX_op_insn_start) {
2807b016486eSRichard Henderson             nb_oargs = 0;
2808b7a83ff8SRichard Henderson             col += ne_fprintf(f, "\n ----");
28099aef40edSRichard Henderson 
2810747bd69dSRichard Henderson             for (i = 0, k = s->insn_start_words; i < k; ++i) {
2811c9ad8d27SRichard Henderson                 col += ne_fprintf(f, " %016" PRIx64,
2812c9ad8d27SRichard Henderson                                   tcg_get_insn_start_param(op, i));
2813eeacee4dSBlue Swirl             }
28147e4597d7Sbellard         } else if (c == INDEX_op_call) {
28153e92aa34SRichard Henderson             const TCGHelperInfo *info = tcg_call_info(op);
2816fa52e660SRichard Henderson             void *func = tcg_call_func(op);
28173e92aa34SRichard Henderson 
2818c896fe29Sbellard             /* variable number of arguments */
2819cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
2820cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
2821c896fe29Sbellard             nb_cargs = def->nb_cargs;
2822b03cce8eSbellard 
2823b7a83ff8SRichard Henderson             col += ne_fprintf(f, " %s ", def->name);
28243e92aa34SRichard Henderson 
28253e92aa34SRichard Henderson             /*
28263e92aa34SRichard Henderson              * Print the function name from TCGHelperInfo, if available.
28273e92aa34SRichard Henderson              * Note that plugins have a template function for the info,
28283e92aa34SRichard Henderson              * but the actual function pointer comes from the plugin.
28293e92aa34SRichard Henderson              */
28303e92aa34SRichard Henderson             if (func == info->func) {
2831b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s", info->name);
28323e92aa34SRichard Henderson             } else {
2833b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "plugin(%p)", func);
28343e92aa34SRichard Henderson             }
28353e92aa34SRichard Henderson 
2836b7a83ff8SRichard Henderson             col += ne_fprintf(f, ",$0x%x,$%d", info->flags, nb_oargs);
2837b03cce8eSbellard             for (i = 0; i < nb_oargs; i++) {
2838b7a83ff8SRichard Henderson                 col += ne_fprintf(f, ",%s", tcg_get_arg_str(s, buf, sizeof(buf),
2839efee3746SRichard Henderson                                                             op->args[i]));
2840b03cce8eSbellard             }
2841cf066674SRichard Henderson             for (i = 0; i < nb_iargs; i++) {
2842efee3746SRichard Henderson                 TCGArg arg = op->args[nb_oargs + i];
284339004a71SRichard Henderson                 const char *t = tcg_get_arg_str(s, buf, sizeof(buf), arg);
2844b7a83ff8SRichard Henderson                 col += ne_fprintf(f, ",%s", t);
2845e8996ee0Sbellard             }
2846b03cce8eSbellard         } else {
2847b5701261SRichard Henderson             if (def->flags & TCG_OPF_INT) {
2848b5701261SRichard Henderson                 col += ne_fprintf(f, " %s_i%d ",
2849b5701261SRichard Henderson                                   def->name,
2850b5701261SRichard Henderson                                   8 * tcg_type_size(TCGOP_TYPE(op)));
2851b5701261SRichard Henderson             } else if (def->flags & TCG_OPF_VECTOR) {
2852b5701261SRichard Henderson                 col += ne_fprintf(f, "%s v%d,e%d,",
2853b5701261SRichard Henderson                                   def->name,
2854b5701261SRichard Henderson                                   8 * tcg_type_size(TCGOP_TYPE(op)),
2855b5701261SRichard Henderson                                   8 << TCGOP_VECE(op));
2856b5701261SRichard Henderson             } else {
2857b7a83ff8SRichard Henderson                 col += ne_fprintf(f, " %s ", def->name);
2858b5701261SRichard Henderson             }
2859c45cb8bbSRichard Henderson 
2860c896fe29Sbellard             nb_oargs = def->nb_oargs;
2861c896fe29Sbellard             nb_iargs = def->nb_iargs;
2862c896fe29Sbellard             nb_cargs = def->nb_cargs;
2863c896fe29Sbellard 
2864c896fe29Sbellard             k = 0;
2865c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
2866b7a83ff8SRichard Henderson                 const char *sep =  k ? "," : "";
2867b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s%s", sep,
2868b7a83ff8SRichard Henderson                                   tcg_get_arg_str(s, buf, sizeof(buf),
2869efee3746SRichard Henderson                                                   op->args[k++]));
2870c896fe29Sbellard             }
2871c896fe29Sbellard             for (i = 0; i < nb_iargs; i++) {
2872b7a83ff8SRichard Henderson                 const char *sep =  k ? "," : "";
2873b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s%s", sep,
2874b7a83ff8SRichard Henderson                                   tcg_get_arg_str(s, buf, sizeof(buf),
2875efee3746SRichard Henderson                                                   op->args[k++]));
2876c896fe29Sbellard             }
2877be210acbSRichard Henderson             switch (c) {
2878be210acbSRichard Henderson             case INDEX_op_brcond_i32:
2879ffc5ea09SRichard Henderson             case INDEX_op_setcond_i32:
28803635502dSRichard Henderson             case INDEX_op_negsetcond_i32:
2881ffc5ea09SRichard Henderson             case INDEX_op_movcond_i32:
2882be210acbSRichard Henderson             case INDEX_op_brcond2_i32:
2883be210acbSRichard Henderson             case INDEX_op_setcond2_i32:
2884ffc5ea09SRichard Henderson             case INDEX_op_brcond_i64:
2885be210acbSRichard Henderson             case INDEX_op_setcond_i64:
28863635502dSRichard Henderson             case INDEX_op_negsetcond_i64:
2887ffc5ea09SRichard Henderson             case INDEX_op_movcond_i64:
2888212be173SRichard Henderson             case INDEX_op_cmp_vec:
2889f75da298SRichard Henderson             case INDEX_op_cmpsel_vec:
2890efee3746SRichard Henderson                 if (op->args[k] < ARRAY_SIZE(cond_name)
2891efee3746SRichard Henderson                     && cond_name[op->args[k]]) {
2892b7a83ff8SRichard Henderson                     col += ne_fprintf(f, ",%s", cond_name[op->args[k++]]);
2893eeacee4dSBlue Swirl                 } else {
2894b7a83ff8SRichard Henderson                     col += ne_fprintf(f, ",$0x%" TCG_PRIlx, op->args[k++]);
2895eeacee4dSBlue Swirl                 }
2896f48f3edeSblueswir1                 i = 1;
2897be210acbSRichard Henderson                 break;
289850b7a197SRichard Henderson             case INDEX_op_qemu_ld_i32:
289950b7a197SRichard Henderson             case INDEX_op_qemu_st_i32:
290050b7a197SRichard Henderson             case INDEX_op_qemu_st8_i32:
290150b7a197SRichard Henderson             case INDEX_op_qemu_ld_i64:
290250b7a197SRichard Henderson             case INDEX_op_qemu_st_i64:
290350b7a197SRichard Henderson             case INDEX_op_qemu_ld_i128:
290450b7a197SRichard Henderson             case INDEX_op_qemu_st_i128:
290559227d5dSRichard Henderson                 {
290637031fefSRichard Henderson                     const char *s_al, *s_op, *s_at;
29079002ffcbSRichard Henderson                     MemOpIdx oi = op->args[k++];
29089a239c6eSPhilippe Mathieu-Daudé                     MemOp mop = get_memop(oi);
290959227d5dSRichard Henderson                     unsigned ix = get_mmuidx(oi);
291059227d5dSRichard Henderson 
29119a239c6eSPhilippe Mathieu-Daudé                     s_al = alignment_name[(mop & MO_AMASK) >> MO_ASHIFT];
29129a239c6eSPhilippe Mathieu-Daudé                     s_op = ldst_name[mop & (MO_BSWAP | MO_SSIZE)];
29139a239c6eSPhilippe Mathieu-Daudé                     s_at = atom_name[(mop & MO_ATOM_MASK) >> MO_ATOM_SHIFT];
29149a239c6eSPhilippe Mathieu-Daudé                     mop &= ~(MO_AMASK | MO_BSWAP | MO_SSIZE | MO_ATOM_MASK);
291537031fefSRichard Henderson 
291637031fefSRichard Henderson                     /* If all fields are accounted for, print symbolically. */
29179a239c6eSPhilippe Mathieu-Daudé                     if (!mop && s_al && s_op && s_at) {
291837031fefSRichard Henderson                         col += ne_fprintf(f, ",%s%s%s,%u",
291937031fefSRichard Henderson                                           s_at, s_al, s_op, ix);
292037031fefSRichard Henderson                     } else {
29219a239c6eSPhilippe Mathieu-Daudé                         mop = get_memop(oi);
29229a239c6eSPhilippe Mathieu-Daudé                         col += ne_fprintf(f, ",$0x%x,%u", mop, ix);
2923f713d6adSRichard Henderson                     }
2924f713d6adSRichard Henderson                     i = 1;
292559227d5dSRichard Henderson                 }
2926f713d6adSRichard Henderson                 break;
2927587195bdSRichard Henderson             case INDEX_op_bswap16_i32:
2928587195bdSRichard Henderson             case INDEX_op_bswap16_i64:
2929587195bdSRichard Henderson             case INDEX_op_bswap32_i32:
2930587195bdSRichard Henderson             case INDEX_op_bswap32_i64:
2931587195bdSRichard Henderson             case INDEX_op_bswap64_i64:
2932587195bdSRichard Henderson                 {
2933587195bdSRichard Henderson                     TCGArg flags = op->args[k];
2934587195bdSRichard Henderson                     const char *name = NULL;
2935587195bdSRichard Henderson 
2936587195bdSRichard Henderson                     if (flags < ARRAY_SIZE(bswap_flag_name)) {
2937587195bdSRichard Henderson                         name = bswap_flag_name[flags];
2938587195bdSRichard Henderson                     }
2939587195bdSRichard Henderson                     if (name) {
2940b7a83ff8SRichard Henderson                         col += ne_fprintf(f, ",%s", name);
2941587195bdSRichard Henderson                     } else {
2942b7a83ff8SRichard Henderson                         col += ne_fprintf(f, ",$0x%" TCG_PRIlx, flags);
2943587195bdSRichard Henderson                     }
2944587195bdSRichard Henderson                     i = k = 1;
2945587195bdSRichard Henderson                 }
2946587195bdSRichard Henderson                 break;
2947b384c734SRichard Henderson #ifdef CONFIG_PLUGIN
2948b384c734SRichard Henderson             case INDEX_op_plugin_cb:
2949b384c734SRichard Henderson                 {
2950b384c734SRichard Henderson                     TCGArg from = op->args[k++];
2951b384c734SRichard Henderson                     const char *name = NULL;
2952b384c734SRichard Henderson 
2953b384c734SRichard Henderson                     if (from < ARRAY_SIZE(plugin_from_name)) {
2954b384c734SRichard Henderson                         name = plugin_from_name[from];
2955b384c734SRichard Henderson                     }
2956b384c734SRichard Henderson                     if (name) {
2957b384c734SRichard Henderson                         col += ne_fprintf(f, "%s", name);
2958b384c734SRichard Henderson                     } else {
2959b384c734SRichard Henderson                         col += ne_fprintf(f, "$0x%" TCG_PRIlx, from);
2960b384c734SRichard Henderson                     }
2961b384c734SRichard Henderson                     i = 1;
2962b384c734SRichard Henderson                 }
2963b384c734SRichard Henderson                 break;
2964b384c734SRichard Henderson #endif
2965be210acbSRichard Henderson             default:
2966f48f3edeSblueswir1                 i = 0;
2967be210acbSRichard Henderson                 break;
2968be210acbSRichard Henderson             }
296951e3972cSRichard Henderson             switch (c) {
297051e3972cSRichard Henderson             case INDEX_op_set_label:
297151e3972cSRichard Henderson             case INDEX_op_br:
297251e3972cSRichard Henderson             case INDEX_op_brcond_i32:
297351e3972cSRichard Henderson             case INDEX_op_brcond_i64:
297451e3972cSRichard Henderson             case INDEX_op_brcond2_i32:
2975b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s$L%d", k ? "," : "",
2976efee3746SRichard Henderson                                   arg_label(op->args[k])->id);
297751e3972cSRichard Henderson                 i++, k++;
297851e3972cSRichard Henderson                 break;
29793470867bSRichard Henderson             case INDEX_op_mb:
29803470867bSRichard Henderson                 {
29813470867bSRichard Henderson                     TCGBar membar = op->args[k];
29823470867bSRichard Henderson                     const char *b_op, *m_op;
29833470867bSRichard Henderson 
29843470867bSRichard Henderson                     switch (membar & TCG_BAR_SC) {
29853470867bSRichard Henderson                     case 0:
29863470867bSRichard Henderson                         b_op = "none";
29873470867bSRichard Henderson                         break;
29883470867bSRichard Henderson                     case TCG_BAR_LDAQ:
29893470867bSRichard Henderson                         b_op = "acq";
29903470867bSRichard Henderson                         break;
29913470867bSRichard Henderson                     case TCG_BAR_STRL:
29923470867bSRichard Henderson                         b_op = "rel";
29933470867bSRichard Henderson                         break;
29943470867bSRichard Henderson                     case TCG_BAR_SC:
29953470867bSRichard Henderson                         b_op = "seq";
29963470867bSRichard Henderson                         break;
29973470867bSRichard Henderson                     default:
29983470867bSRichard Henderson                         g_assert_not_reached();
29993470867bSRichard Henderson                     }
30003470867bSRichard Henderson 
30013470867bSRichard Henderson                     switch (membar & TCG_MO_ALL) {
30023470867bSRichard Henderson                     case 0:
30033470867bSRichard Henderson                         m_op = "none";
30043470867bSRichard Henderson                         break;
30053470867bSRichard Henderson                     case TCG_MO_LD_LD:
30063470867bSRichard Henderson                         m_op = "rr";
30073470867bSRichard Henderson                         break;
30083470867bSRichard Henderson                     case TCG_MO_LD_ST:
30093470867bSRichard Henderson                         m_op = "rw";
30103470867bSRichard Henderson                         break;
30113470867bSRichard Henderson                     case TCG_MO_ST_LD:
30123470867bSRichard Henderson                         m_op = "wr";
30133470867bSRichard Henderson                         break;
30143470867bSRichard Henderson                     case TCG_MO_ST_ST:
30153470867bSRichard Henderson                         m_op = "ww";
30163470867bSRichard Henderson                         break;
30173470867bSRichard Henderson                     case TCG_MO_LD_LD | TCG_MO_LD_ST:
30183470867bSRichard Henderson                         m_op = "rr+rw";
30193470867bSRichard Henderson                         break;
30203470867bSRichard Henderson                     case TCG_MO_LD_LD | TCG_MO_ST_LD:
30213470867bSRichard Henderson                         m_op = "rr+wr";
30223470867bSRichard Henderson                         break;
30233470867bSRichard Henderson                     case TCG_MO_LD_LD | TCG_MO_ST_ST:
30243470867bSRichard Henderson                         m_op = "rr+ww";
30253470867bSRichard Henderson                         break;
30263470867bSRichard Henderson                     case TCG_MO_LD_ST | TCG_MO_ST_LD:
30273470867bSRichard Henderson                         m_op = "rw+wr";
30283470867bSRichard Henderson                         break;
30293470867bSRichard Henderson                     case TCG_MO_LD_ST | TCG_MO_ST_ST:
30303470867bSRichard Henderson                         m_op = "rw+ww";
30313470867bSRichard Henderson                         break;
30323470867bSRichard Henderson                     case TCG_MO_ST_LD | TCG_MO_ST_ST:
30333470867bSRichard Henderson                         m_op = "wr+ww";
30343470867bSRichard Henderson                         break;
30353470867bSRichard Henderson                     case TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_MO_ST_LD:
30363470867bSRichard Henderson                         m_op = "rr+rw+wr";
30373470867bSRichard Henderson                         break;
30383470867bSRichard Henderson                     case TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_MO_ST_ST:
30393470867bSRichard Henderson                         m_op = "rr+rw+ww";
30403470867bSRichard Henderson                         break;
30413470867bSRichard Henderson                     case TCG_MO_LD_LD | TCG_MO_ST_LD | TCG_MO_ST_ST:
30423470867bSRichard Henderson                         m_op = "rr+wr+ww";
30433470867bSRichard Henderson                         break;
30443470867bSRichard Henderson                     case TCG_MO_LD_ST | TCG_MO_ST_LD | TCG_MO_ST_ST:
30453470867bSRichard Henderson                         m_op = "rw+wr+ww";
30463470867bSRichard Henderson                         break;
30473470867bSRichard Henderson                     case TCG_MO_ALL:
30483470867bSRichard Henderson                         m_op = "all";
30493470867bSRichard Henderson                         break;
30503470867bSRichard Henderson                     default:
30513470867bSRichard Henderson                         g_assert_not_reached();
30523470867bSRichard Henderson                     }
30533470867bSRichard Henderson 
30543470867bSRichard Henderson                     col += ne_fprintf(f, "%s%s:%s", (k ? "," : ""), b_op, m_op);
30553470867bSRichard Henderson                     i++, k++;
30563470867bSRichard Henderson                 }
30573470867bSRichard Henderson                 break;
305851e3972cSRichard Henderson             default:
305951e3972cSRichard Henderson                 break;
3060eeacee4dSBlue Swirl             }
306151e3972cSRichard Henderson             for (; i < nb_cargs; i++, k++) {
3062b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s$0x%" TCG_PRIlx, k ? "," : "",
3063b7a83ff8SRichard Henderson                                   op->args[k]);
3064bdfb460eSRichard Henderson             }
3065bdfb460eSRichard Henderson         }
3066bdfb460eSRichard Henderson 
30671894f69aSRichard Henderson         if (have_prefs || op->life) {
30681894f69aSRichard Henderson             for (; col < 40; ++col) {
3069b7a83ff8SRichard Henderson                 putc(' ', f);
3070bdfb460eSRichard Henderson             }
30711894f69aSRichard Henderson         }
30721894f69aSRichard Henderson 
30731894f69aSRichard Henderson         if (op->life) {
30741894f69aSRichard Henderson             unsigned life = op->life;
3075bdfb460eSRichard Henderson 
3076bdfb460eSRichard Henderson             if (life & (SYNC_ARG * 3)) {
3077b7a83ff8SRichard Henderson                 ne_fprintf(f, "  sync:");
3078bdfb460eSRichard Henderson                 for (i = 0; i < 2; ++i) {
3079bdfb460eSRichard Henderson                     if (life & (SYNC_ARG << i)) {
3080b7a83ff8SRichard Henderson                         ne_fprintf(f, " %d", i);
3081bdfb460eSRichard Henderson                     }
3082bdfb460eSRichard Henderson                 }
3083bdfb460eSRichard Henderson             }
3084bdfb460eSRichard Henderson             life /= DEAD_ARG;
3085bdfb460eSRichard Henderson             if (life) {
3086b7a83ff8SRichard Henderson                 ne_fprintf(f, "  dead:");
3087bdfb460eSRichard Henderson                 for (i = 0; life; ++i, life >>= 1) {
3088bdfb460eSRichard Henderson                     if (life & 1) {
3089b7a83ff8SRichard Henderson                         ne_fprintf(f, " %d", i);
3090bdfb460eSRichard Henderson                     }
3091bdfb460eSRichard Henderson                 }
3092c896fe29Sbellard             }
3093b03cce8eSbellard         }
30941894f69aSRichard Henderson 
30951894f69aSRichard Henderson         if (have_prefs) {
30961894f69aSRichard Henderson             for (i = 0; i < nb_oargs; ++i) {
309731fd884bSRichard Henderson                 TCGRegSet set = output_pref(op, i);
30981894f69aSRichard Henderson 
30991894f69aSRichard Henderson                 if (i == 0) {
3100b7a83ff8SRichard Henderson                     ne_fprintf(f, "  pref=");
31011894f69aSRichard Henderson                 } else {
3102b7a83ff8SRichard Henderson                     ne_fprintf(f, ",");
31031894f69aSRichard Henderson                 }
31041894f69aSRichard Henderson                 if (set == 0) {
3105b7a83ff8SRichard Henderson                     ne_fprintf(f, "none");
31061894f69aSRichard Henderson                 } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) {
3107b7a83ff8SRichard Henderson                     ne_fprintf(f, "all");
31081894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG
31091894f69aSRichard Henderson                 } else if (tcg_regset_single(set)) {
31101894f69aSRichard Henderson                     TCGReg reg = tcg_regset_first(set);
3111b7a83ff8SRichard Henderson                     ne_fprintf(f, "%s", tcg_target_reg_names[reg]);
31121894f69aSRichard Henderson #endif
31131894f69aSRichard Henderson                 } else if (TCG_TARGET_NB_REGS <= 32) {
3114b7a83ff8SRichard Henderson                     ne_fprintf(f, "0x%x", (uint32_t)set);
31151894f69aSRichard Henderson                 } else {
3116b7a83ff8SRichard Henderson                     ne_fprintf(f, "0x%" PRIx64, (uint64_t)set);
31171894f69aSRichard Henderson                 }
31181894f69aSRichard Henderson             }
31191894f69aSRichard Henderson         }
31201894f69aSRichard Henderson 
3121b7a83ff8SRichard Henderson         putc('\n', f);
3122c896fe29Sbellard     }
3123c896fe29Sbellard }
3124c896fe29Sbellard 
3125c896fe29Sbellard /* we give more priority to constraints with less registers */
31263e80824eSRichard Henderson static int get_constraint_priority(const TCGArgConstraint *arg_ct, int k)
3127c896fe29Sbellard {
31283e80824eSRichard Henderson     int n;
31293e80824eSRichard Henderson 
31303e80824eSRichard Henderson     arg_ct += k;
31313e80824eSRichard Henderson     n = ctpop64(arg_ct->regs);
3132c896fe29Sbellard 
313329f5e925SRichard Henderson     /*
313429f5e925SRichard Henderson      * Sort constraints of a single register first, which includes output
313529f5e925SRichard Henderson      * aliases (which must exactly match the input already allocated).
313629f5e925SRichard Henderson      */
313729f5e925SRichard Henderson     if (n == 1 || arg_ct->oalias) {
313829f5e925SRichard Henderson         return INT_MAX;
3139c896fe29Sbellard     }
314029f5e925SRichard Henderson 
314129f5e925SRichard Henderson     /*
314229f5e925SRichard Henderson      * Sort register pairs next, first then second immediately after.
314329f5e925SRichard Henderson      * Arbitrarily sort multiple pairs by the index of the first reg;
314429f5e925SRichard Henderson      * there shouldn't be many pairs.
314529f5e925SRichard Henderson      */
314629f5e925SRichard Henderson     switch (arg_ct->pair) {
314729f5e925SRichard Henderson     case 1:
314829f5e925SRichard Henderson     case 3:
314929f5e925SRichard Henderson         return (k + 1) * 2;
315029f5e925SRichard Henderson     case 2:
315129f5e925SRichard Henderson         return (arg_ct->pair_index + 1) * 2 - 1;
315229f5e925SRichard Henderson     }
315329f5e925SRichard Henderson 
315429f5e925SRichard Henderson     /* Finally, sort by decreasing register count. */
315529f5e925SRichard Henderson     assert(n > 1);
315629f5e925SRichard Henderson     return -n;
3157c896fe29Sbellard }
3158c896fe29Sbellard 
3159c896fe29Sbellard /* sort from highest priority to lowest */
31603e80824eSRichard Henderson static void sort_constraints(TCGArgConstraint *a, int start, int n)
3161c896fe29Sbellard {
316266792f90SRichard Henderson     int i, j;
3163c896fe29Sbellard 
316466792f90SRichard Henderson     for (i = 0; i < n; i++) {
316566792f90SRichard Henderson         a[start + i].sort_index = start + i;
316666792f90SRichard Henderson     }
316766792f90SRichard Henderson     if (n <= 1) {
3168c896fe29Sbellard         return;
316966792f90SRichard Henderson     }
3170c896fe29Sbellard     for (i = 0; i < n - 1; i++) {
3171c896fe29Sbellard         for (j = i + 1; j < n; j++) {
31723e80824eSRichard Henderson             int p1 = get_constraint_priority(a, a[start + i].sort_index);
31733e80824eSRichard Henderson             int p2 = get_constraint_priority(a, a[start + j].sort_index);
3174c896fe29Sbellard             if (p1 < p2) {
317566792f90SRichard Henderson                 int tmp = a[start + i].sort_index;
317666792f90SRichard Henderson                 a[start + i].sort_index = a[start + j].sort_index;
317766792f90SRichard Henderson                 a[start + j].sort_index = tmp;
3178c896fe29Sbellard             }
3179c896fe29Sbellard         }
3180c896fe29Sbellard     }
3181c896fe29Sbellard }
3182c896fe29Sbellard 
31833e80824eSRichard Henderson static const TCGArgConstraint empty_cts[TCG_MAX_OP_ARGS];
31843e80824eSRichard Henderson static TCGArgConstraint all_cts[ARRAY_SIZE(constraint_sets)][TCG_MAX_OP_ARGS];
31853e80824eSRichard Henderson 
3186501fb3daSRichard Henderson static void process_constraint_sets(void)
3187c896fe29Sbellard {
31883e80824eSRichard Henderson     for (size_t c = 0; c < ARRAY_SIZE(constraint_sets); ++c) {
31893e80824eSRichard Henderson         const TCGConstraintSet *tdefs = &constraint_sets[c];
31903e80824eSRichard Henderson         TCGArgConstraint *args_ct = all_cts[c];
31913e80824eSRichard Henderson         int nb_oargs = tdefs->nb_oargs;
31923e80824eSRichard Henderson         int nb_iargs = tdefs->nb_iargs;
31933e80824eSRichard Henderson         int nb_args = nb_oargs + nb_iargs;
319429f5e925SRichard Henderson         bool saw_alias_pair = false;
3195f69d277eSRichard Henderson 
31963e80824eSRichard Henderson         for (int i = 0; i < nb_args; i++) {
3197f69d277eSRichard Henderson             const char *ct_str = tdefs->args_ct_str[i];
31983e80824eSRichard Henderson             bool input_p = i >= nb_oargs;
31993e80824eSRichard Henderson             int o;
3200f69d277eSRichard Henderson 
320117280ff4SRichard Henderson             switch (*ct_str) {
320217280ff4SRichard Henderson             case '0' ... '9':
32038940ea0dSPhilippe Mathieu-Daudé                 o = *ct_str - '0';
32048940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(input_p);
32053e80824eSRichard Henderson                 tcg_debug_assert(o < nb_oargs);
32063e80824eSRichard Henderson                 tcg_debug_assert(args_ct[o].regs != 0);
32073e80824eSRichard Henderson                 tcg_debug_assert(!args_ct[o].oalias);
32083e80824eSRichard Henderson                 args_ct[i] = args_ct[o];
3209bc2b17e6SRichard Henderson                 /* The output sets oalias.  */
32103e80824eSRichard Henderson                 args_ct[o].oalias = 1;
32113e80824eSRichard Henderson                 args_ct[o].alias_index = i;
3212bc2b17e6SRichard Henderson                 /* The input sets ialias. */
32133e80824eSRichard Henderson                 args_ct[i].ialias = 1;
32143e80824eSRichard Henderson                 args_ct[i].alias_index = o;
32153e80824eSRichard Henderson                 if (args_ct[i].pair) {
321629f5e925SRichard Henderson                     saw_alias_pair = true;
321729f5e925SRichard Henderson                 }
32188940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(ct_str[1] == '\0');
32198940ea0dSPhilippe Mathieu-Daudé                 continue;
32208940ea0dSPhilippe Mathieu-Daudé 
322182790a87SRichard Henderson             case '&':
32228940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(!input_p);
32233e80824eSRichard Henderson                 args_ct[i].newreg = true;
322482790a87SRichard Henderson                 ct_str++;
322582790a87SRichard Henderson                 break;
322629f5e925SRichard Henderson 
322729f5e925SRichard Henderson             case 'p': /* plus */
322829f5e925SRichard Henderson                 /* Allocate to the register after the previous. */
32293e80824eSRichard Henderson                 tcg_debug_assert(i > (input_p ? nb_oargs : 0));
323029f5e925SRichard Henderson                 o = i - 1;
32313e80824eSRichard Henderson                 tcg_debug_assert(!args_ct[o].pair);
32323e80824eSRichard Henderson                 tcg_debug_assert(!args_ct[o].ct);
32333e80824eSRichard Henderson                 args_ct[i] = (TCGArgConstraint){
323429f5e925SRichard Henderson                     .pair = 2,
323529f5e925SRichard Henderson                     .pair_index = o,
32363e80824eSRichard Henderson                     .regs = args_ct[o].regs << 1,
32373e80824eSRichard Henderson                     .newreg = args_ct[o].newreg,
323829f5e925SRichard Henderson                 };
32393e80824eSRichard Henderson                 args_ct[o].pair = 1;
32403e80824eSRichard Henderson                 args_ct[o].pair_index = i;
324129f5e925SRichard Henderson                 tcg_debug_assert(ct_str[1] == '\0');
324229f5e925SRichard Henderson                 continue;
324329f5e925SRichard Henderson 
324429f5e925SRichard Henderson             case 'm': /* minus */
324529f5e925SRichard Henderson                 /* Allocate to the register before the previous. */
32463e80824eSRichard Henderson                 tcg_debug_assert(i > (input_p ? nb_oargs : 0));
324729f5e925SRichard Henderson                 o = i - 1;
32483e80824eSRichard Henderson                 tcg_debug_assert(!args_ct[o].pair);
32493e80824eSRichard Henderson                 tcg_debug_assert(!args_ct[o].ct);
32503e80824eSRichard Henderson                 args_ct[i] = (TCGArgConstraint){
325129f5e925SRichard Henderson                     .pair = 1,
325229f5e925SRichard Henderson                     .pair_index = o,
32533e80824eSRichard Henderson                     .regs = args_ct[o].regs >> 1,
32543e80824eSRichard Henderson                     .newreg = args_ct[o].newreg,
325529f5e925SRichard Henderson                 };
32563e80824eSRichard Henderson                 args_ct[o].pair = 2;
32573e80824eSRichard Henderson                 args_ct[o].pair_index = i;
325829f5e925SRichard Henderson                 tcg_debug_assert(ct_str[1] == '\0');
325929f5e925SRichard Henderson                 continue;
32608940ea0dSPhilippe Mathieu-Daudé             }
32618940ea0dSPhilippe Mathieu-Daudé 
32628940ea0dSPhilippe Mathieu-Daudé             do {
32638940ea0dSPhilippe Mathieu-Daudé                 switch (*ct_str) {
3264c896fe29Sbellard                 case 'i':
32653e80824eSRichard Henderson                     args_ct[i].ct |= TCG_CT_CONST;
3266c896fe29Sbellard                     break;
32676b8abd24SRichard Henderson #ifdef TCG_REG_ZERO
32686b8abd24SRichard Henderson                 case 'z':
32696b8abd24SRichard Henderson                     args_ct[i].ct |= TCG_CT_REG_ZERO;
32706b8abd24SRichard Henderson                     break;
32716b8abd24SRichard Henderson #endif
3272358b4923SRichard Henderson 
3273358b4923SRichard Henderson                 /* Include all of the target-specific constraints. */
3274358b4923SRichard Henderson 
3275358b4923SRichard Henderson #undef CONST
3276358b4923SRichard Henderson #define CONST(CASE, MASK) \
32773e80824eSRichard Henderson     case CASE: args_ct[i].ct |= MASK; break;
3278358b4923SRichard Henderson #define REGS(CASE, MASK) \
32793e80824eSRichard Henderson     case CASE: args_ct[i].regs |= MASK; break;
3280358b4923SRichard Henderson 
3281358b4923SRichard Henderson #include "tcg-target-con-str.h"
3282358b4923SRichard Henderson 
3283358b4923SRichard Henderson #undef REGS
3284358b4923SRichard Henderson #undef CONST
3285c896fe29Sbellard                 default:
32868940ea0dSPhilippe Mathieu-Daudé                 case '0' ... '9':
32878940ea0dSPhilippe Mathieu-Daudé                 case '&':
328829f5e925SRichard Henderson                 case 'p':
328929f5e925SRichard Henderson                 case 'm':
32903e80824eSRichard Henderson                     /* Typo in TCGConstraintSet constraint. */
3291358b4923SRichard Henderson                     g_assert_not_reached();
3292358b4923SRichard Henderson                 }
32938940ea0dSPhilippe Mathieu-Daudé             } while (*++ct_str != '\0');
3294c896fe29Sbellard         }
3295c896fe29Sbellard 
329629f5e925SRichard Henderson         /*
329729f5e925SRichard Henderson          * Fix up output pairs that are aliased with inputs.
329829f5e925SRichard Henderson          * When we created the alias, we copied pair from the output.
329929f5e925SRichard Henderson          * There are three cases:
330029f5e925SRichard Henderson          *    (1a) Pairs of inputs alias pairs of outputs.
330129f5e925SRichard Henderson          *    (1b) One input aliases the first of a pair of outputs.
330229f5e925SRichard Henderson          *    (2)  One input aliases the second of a pair of outputs.
330329f5e925SRichard Henderson          *
330429f5e925SRichard Henderson          * Case 1a is handled by making sure that the pair_index'es are
330529f5e925SRichard Henderson          * properly updated so that they appear the same as a pair of inputs.
330629f5e925SRichard Henderson          *
330729f5e925SRichard Henderson          * Case 1b is handled by setting the pair_index of the input to
330829f5e925SRichard Henderson          * itself, simply so it doesn't point to an unrelated argument.
330929f5e925SRichard Henderson          * Since we don't encounter the "second" during the input allocation
331029f5e925SRichard Henderson          * phase, nothing happens with the second half of the input pair.
331129f5e925SRichard Henderson          *
331229f5e925SRichard Henderson          * Case 2 is handled by setting the second input to pair=3, the
331329f5e925SRichard Henderson          * first output to pair=3, and the pair_index'es to match.
331429f5e925SRichard Henderson          */
331529f5e925SRichard Henderson         if (saw_alias_pair) {
33163e80824eSRichard Henderson             for (int i = nb_oargs; i < nb_args; i++) {
33173e80824eSRichard Henderson                 int o, o2, i2;
33183e80824eSRichard Henderson 
331929f5e925SRichard Henderson                 /*
332029f5e925SRichard Henderson                  * Since [0-9pm] must be alone in the constraint string,
332129f5e925SRichard Henderson                  * the only way they can both be set is if the pair comes
332229f5e925SRichard Henderson                  * from the output alias.
332329f5e925SRichard Henderson                  */
33243e80824eSRichard Henderson                 if (!args_ct[i].ialias) {
332529f5e925SRichard Henderson                     continue;
332629f5e925SRichard Henderson                 }
33273e80824eSRichard Henderson                 switch (args_ct[i].pair) {
332829f5e925SRichard Henderson                 case 0:
332929f5e925SRichard Henderson                     break;
333029f5e925SRichard Henderson                 case 1:
33313e80824eSRichard Henderson                     o = args_ct[i].alias_index;
33323e80824eSRichard Henderson                     o2 = args_ct[o].pair_index;
33333e80824eSRichard Henderson                     tcg_debug_assert(args_ct[o].pair == 1);
33343e80824eSRichard Henderson                     tcg_debug_assert(args_ct[o2].pair == 2);
33353e80824eSRichard Henderson                     if (args_ct[o2].oalias) {
333629f5e925SRichard Henderson                         /* Case 1a */
33373e80824eSRichard Henderson                         i2 = args_ct[o2].alias_index;
33383e80824eSRichard Henderson                         tcg_debug_assert(args_ct[i2].pair == 2);
33393e80824eSRichard Henderson                         args_ct[i2].pair_index = i;
33403e80824eSRichard Henderson                         args_ct[i].pair_index = i2;
334129f5e925SRichard Henderson                     } else {
334229f5e925SRichard Henderson                         /* Case 1b */
33433e80824eSRichard Henderson                         args_ct[i].pair_index = i;
334429f5e925SRichard Henderson                     }
334529f5e925SRichard Henderson                     break;
334629f5e925SRichard Henderson                 case 2:
33473e80824eSRichard Henderson                     o = args_ct[i].alias_index;
33483e80824eSRichard Henderson                     o2 = args_ct[o].pair_index;
33493e80824eSRichard Henderson                     tcg_debug_assert(args_ct[o].pair == 2);
33503e80824eSRichard Henderson                     tcg_debug_assert(args_ct[o2].pair == 1);
33513e80824eSRichard Henderson                     if (args_ct[o2].oalias) {
335229f5e925SRichard Henderson                         /* Case 1a */
33533e80824eSRichard Henderson                         i2 = args_ct[o2].alias_index;
33543e80824eSRichard Henderson                         tcg_debug_assert(args_ct[i2].pair == 1);
33553e80824eSRichard Henderson                         args_ct[i2].pair_index = i;
33563e80824eSRichard Henderson                         args_ct[i].pair_index = i2;
335729f5e925SRichard Henderson                     } else {
335829f5e925SRichard Henderson                         /* Case 2 */
33593e80824eSRichard Henderson                         args_ct[i].pair = 3;
33603e80824eSRichard Henderson                         args_ct[o2].pair = 3;
33613e80824eSRichard Henderson                         args_ct[i].pair_index = o2;
33623e80824eSRichard Henderson                         args_ct[o2].pair_index = i;
336329f5e925SRichard Henderson                     }
336429f5e925SRichard Henderson                     break;
336529f5e925SRichard Henderson                 default:
336629f5e925SRichard Henderson                     g_assert_not_reached();
336729f5e925SRichard Henderson                 }
336829f5e925SRichard Henderson             }
336929f5e925SRichard Henderson         }
337029f5e925SRichard Henderson 
3371c896fe29Sbellard         /* sort the constraints (XXX: this is just an heuristic) */
33723e80824eSRichard Henderson         sort_constraints(args_ct, 0, nb_oargs);
33733e80824eSRichard Henderson         sort_constraints(args_ct, nb_oargs, nb_iargs);
33743e80824eSRichard Henderson     }
3375501fb3daSRichard Henderson }
33763e80824eSRichard Henderson 
3377501fb3daSRichard Henderson static const TCGArgConstraint *opcode_args_ct(const TCGOp *op)
3378501fb3daSRichard Henderson {
33795500bd9eSRichard Henderson     TCGOpcode opc = op->opc;
33805500bd9eSRichard Henderson     TCGType type = TCGOP_TYPE(op);
33815500bd9eSRichard Henderson     unsigned flags = TCGOP_FLAGS(op);
33825500bd9eSRichard Henderson     const TCGOpDef *def = &tcg_op_defs[opc];
33835500bd9eSRichard Henderson     const TCGOutOp *outop = all_outop[opc];
33843e80824eSRichard Henderson     TCGConstraintSetIndex con_set;
33853e80824eSRichard Henderson 
33863e80824eSRichard Henderson     if (def->flags & TCG_OPF_NOT_PRESENT) {
3387501fb3daSRichard Henderson         return empty_cts;
33883e80824eSRichard Henderson     }
33893e80824eSRichard Henderson 
33905500bd9eSRichard Henderson     if (outop) {
33915500bd9eSRichard Henderson         con_set = outop->static_constraint;
33925500bd9eSRichard Henderson         if (con_set == C_Dynamic) {
33935500bd9eSRichard Henderson             con_set = outop->dynamic_constraint(type, flags);
33945500bd9eSRichard Henderson         }
33955500bd9eSRichard Henderson     } else {
33965500bd9eSRichard Henderson         con_set = tcg_target_op_def(opc, type, flags);
33975500bd9eSRichard Henderson     }
33985500bd9eSRichard Henderson     tcg_debug_assert(con_set >= 0);
33995500bd9eSRichard Henderson     tcg_debug_assert(con_set < ARRAY_SIZE(constraint_sets));
34003e80824eSRichard Henderson 
34013e80824eSRichard Henderson     /* The constraint arguments must match TCGOpcode arguments. */
3402501fb3daSRichard Henderson     tcg_debug_assert(constraint_sets[con_set].nb_oargs == def->nb_oargs);
3403501fb3daSRichard Henderson     tcg_debug_assert(constraint_sets[con_set].nb_iargs == def->nb_iargs);
34043e80824eSRichard Henderson 
3405501fb3daSRichard Henderson     return all_cts[con_set];
3406c896fe29Sbellard }
3407c896fe29Sbellard 
3408f85b1fc4SRichard Henderson static void remove_label_use(TCGOp *op, int idx)
3409f85b1fc4SRichard Henderson {
3410f85b1fc4SRichard Henderson     TCGLabel *label = arg_label(op->args[idx]);
3411f85b1fc4SRichard Henderson     TCGLabelUse *use;
3412f85b1fc4SRichard Henderson 
3413f85b1fc4SRichard Henderson     QSIMPLEQ_FOREACH(use, &label->branches, next) {
3414f85b1fc4SRichard Henderson         if (use->op == op) {
3415f85b1fc4SRichard Henderson             QSIMPLEQ_REMOVE(&label->branches, use, TCGLabelUse, next);
3416f85b1fc4SRichard Henderson             return;
3417f85b1fc4SRichard Henderson         }
3418f85b1fc4SRichard Henderson     }
3419f85b1fc4SRichard Henderson     g_assert_not_reached();
3420f85b1fc4SRichard Henderson }
3421f85b1fc4SRichard Henderson 
34220c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op)
34230c627cdcSRichard Henderson {
3424d88a117eSRichard Henderson     switch (op->opc) {
3425d88a117eSRichard Henderson     case INDEX_op_br:
3426f85b1fc4SRichard Henderson         remove_label_use(op, 0);
3427d88a117eSRichard Henderson         break;
3428d88a117eSRichard Henderson     case INDEX_op_brcond_i32:
3429d88a117eSRichard Henderson     case INDEX_op_brcond_i64:
3430f85b1fc4SRichard Henderson         remove_label_use(op, 3);
3431d88a117eSRichard Henderson         break;
3432d88a117eSRichard Henderson     case INDEX_op_brcond2_i32:
3433f85b1fc4SRichard Henderson         remove_label_use(op, 5);
3434d88a117eSRichard Henderson         break;
3435d88a117eSRichard Henderson     default:
3436d88a117eSRichard Henderson         break;
3437d88a117eSRichard Henderson     }
3438d88a117eSRichard Henderson 
343915fa08f8SRichard Henderson     QTAILQ_REMOVE(&s->ops, op, link);
344015fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&s->free_ops, op, link);
3441abebf925SRichard Henderson     s->nb_ops--;
34420c627cdcSRichard Henderson }
34430c627cdcSRichard Henderson 
3444a80cdd31SRichard Henderson void tcg_remove_ops_after(TCGOp *op)
3445a80cdd31SRichard Henderson {
3446a80cdd31SRichard Henderson     TCGContext *s = tcg_ctx;
3447a80cdd31SRichard Henderson 
3448a80cdd31SRichard Henderson     while (true) {
3449a80cdd31SRichard Henderson         TCGOp *last = tcg_last_op();
3450a80cdd31SRichard Henderson         if (last == op) {
3451a80cdd31SRichard Henderson             return;
3452a80cdd31SRichard Henderson         }
3453a80cdd31SRichard Henderson         tcg_op_remove(s, last);
3454a80cdd31SRichard Henderson     }
3455a80cdd31SRichard Henderson }
3456a80cdd31SRichard Henderson 
3457d4478943SPhilippe Mathieu-Daudé static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs)
345815fa08f8SRichard Henderson {
345915fa08f8SRichard Henderson     TCGContext *s = tcg_ctx;
3460cb10bc63SRichard Henderson     TCGOp *op = NULL;
346115fa08f8SRichard Henderson 
3462cb10bc63SRichard Henderson     if (unlikely(!QTAILQ_EMPTY(&s->free_ops))) {
3463cb10bc63SRichard Henderson         QTAILQ_FOREACH(op, &s->free_ops, link) {
3464cb10bc63SRichard Henderson             if (nargs <= op->nargs) {
346515fa08f8SRichard Henderson                 QTAILQ_REMOVE(&s->free_ops, op, link);
3466cb10bc63SRichard Henderson                 nargs = op->nargs;
3467cb10bc63SRichard Henderson                 goto found;
346815fa08f8SRichard Henderson             }
3469cb10bc63SRichard Henderson         }
3470cb10bc63SRichard Henderson     }
3471cb10bc63SRichard Henderson 
3472cb10bc63SRichard Henderson     /* Most opcodes have 3 or 4 operands: reduce fragmentation. */
3473cb10bc63SRichard Henderson     nargs = MAX(4, nargs);
3474cb10bc63SRichard Henderson     op = tcg_malloc(sizeof(TCGOp) + sizeof(TCGArg) * nargs);
3475cb10bc63SRichard Henderson 
3476cb10bc63SRichard Henderson  found:
347715fa08f8SRichard Henderson     memset(op, 0, offsetof(TCGOp, link));
347815fa08f8SRichard Henderson     op->opc = opc;
3479cb10bc63SRichard Henderson     op->nargs = nargs;
348015fa08f8SRichard Henderson 
3481cb10bc63SRichard Henderson     /* Check for bitfield overflow. */
3482cb10bc63SRichard Henderson     tcg_debug_assert(op->nargs == nargs);
3483cb10bc63SRichard Henderson 
3484cb10bc63SRichard Henderson     s->nb_ops++;
348515fa08f8SRichard Henderson     return op;
348615fa08f8SRichard Henderson }
348715fa08f8SRichard Henderson 
3488d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_emit_op(TCGOpcode opc, unsigned nargs)
348915fa08f8SRichard Henderson {
3490d4478943SPhilippe Mathieu-Daudé     TCGOp *op = tcg_op_alloc(opc, nargs);
349107843f75SRichard Henderson 
349207843f75SRichard Henderson     if (tcg_ctx->emit_before_op) {
349307843f75SRichard Henderson         QTAILQ_INSERT_BEFORE(tcg_ctx->emit_before_op, op, link);
349407843f75SRichard Henderson     } else {
349515fa08f8SRichard Henderson         QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
349607843f75SRichard Henderson     }
349715fa08f8SRichard Henderson     return op;
349815fa08f8SRichard Henderson }
349915fa08f8SRichard Henderson 
3500d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op,
3501cf5c9f69SRichard Henderson                             TCGOpcode opc, TCGType type, unsigned nargs)
35025a18407fSRichard Henderson {
3503d4478943SPhilippe Mathieu-Daudé     TCGOp *new_op = tcg_op_alloc(opc, nargs);
3504fb744eceSRichard Henderson 
3505cf5c9f69SRichard Henderson     TCGOP_TYPE(new_op) = type;
350615fa08f8SRichard Henderson     QTAILQ_INSERT_BEFORE(old_op, new_op, link);
35075a18407fSRichard Henderson     return new_op;
35085a18407fSRichard Henderson }
35095a18407fSRichard Henderson 
3510d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op,
3511cf5c9f69SRichard Henderson                            TCGOpcode opc, TCGType type, unsigned nargs)
35125a18407fSRichard Henderson {
3513d4478943SPhilippe Mathieu-Daudé     TCGOp *new_op = tcg_op_alloc(opc, nargs);
3514fb744eceSRichard Henderson 
3515cf5c9f69SRichard Henderson     TCGOP_TYPE(new_op) = type;
351615fa08f8SRichard Henderson     QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link);
35175a18407fSRichard Henderson     return new_op;
35185a18407fSRichard Henderson }
35195a18407fSRichard Henderson 
3520968f305eSRichard Henderson static void move_label_uses(TCGLabel *to, TCGLabel *from)
3521968f305eSRichard Henderson {
3522968f305eSRichard Henderson     TCGLabelUse *u;
3523968f305eSRichard Henderson 
3524968f305eSRichard Henderson     QSIMPLEQ_FOREACH(u, &from->branches, next) {
3525968f305eSRichard Henderson         TCGOp *op = u->op;
3526968f305eSRichard Henderson         switch (op->opc) {
3527968f305eSRichard Henderson         case INDEX_op_br:
3528968f305eSRichard Henderson             op->args[0] = label_arg(to);
3529968f305eSRichard Henderson             break;
3530968f305eSRichard Henderson         case INDEX_op_brcond_i32:
3531968f305eSRichard Henderson         case INDEX_op_brcond_i64:
3532968f305eSRichard Henderson             op->args[3] = label_arg(to);
3533968f305eSRichard Henderson             break;
3534968f305eSRichard Henderson         case INDEX_op_brcond2_i32:
3535968f305eSRichard Henderson             op->args[5] = label_arg(to);
3536968f305eSRichard Henderson             break;
3537968f305eSRichard Henderson         default:
3538968f305eSRichard Henderson             g_assert_not_reached();
3539968f305eSRichard Henderson         }
3540968f305eSRichard Henderson     }
3541968f305eSRichard Henderson 
3542968f305eSRichard Henderson     QSIMPLEQ_CONCAT(&to->branches, &from->branches);
3543968f305eSRichard Henderson }
3544968f305eSRichard Henderson 
3545b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code.  */
35469bbee4c0SRichard Henderson static void __attribute__((noinline))
35479bbee4c0SRichard Henderson reachable_code_pass(TCGContext *s)
3548b4fc67c7SRichard Henderson {
35494d89d0bbSRichard Henderson     TCGOp *op, *op_next, *op_prev;
3550b4fc67c7SRichard Henderson     bool dead = false;
3551b4fc67c7SRichard Henderson 
3552b4fc67c7SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
3553b4fc67c7SRichard Henderson         bool remove = dead;
3554b4fc67c7SRichard Henderson         TCGLabel *label;
3555b4fc67c7SRichard Henderson 
3556b4fc67c7SRichard Henderson         switch (op->opc) {
3557b4fc67c7SRichard Henderson         case INDEX_op_set_label:
3558b4fc67c7SRichard Henderson             label = arg_label(op->args[0]);
35594d89d0bbSRichard Henderson 
35604d89d0bbSRichard Henderson             /*
3561968f305eSRichard Henderson              * Note that the first op in the TB is always a load,
3562968f305eSRichard Henderson              * so there is always something before a label.
3563968f305eSRichard Henderson              */
3564968f305eSRichard Henderson             op_prev = QTAILQ_PREV(op, link);
3565968f305eSRichard Henderson 
3566968f305eSRichard Henderson             /*
3567968f305eSRichard Henderson              * If we find two sequential labels, move all branches to
3568968f305eSRichard Henderson              * reference the second label and remove the first label.
3569968f305eSRichard Henderson              * Do this before branch to next optimization, so that the
3570968f305eSRichard Henderson              * middle label is out of the way.
3571968f305eSRichard Henderson              */
3572968f305eSRichard Henderson             if (op_prev->opc == INDEX_op_set_label) {
3573968f305eSRichard Henderson                 move_label_uses(label, arg_label(op_prev->args[0]));
3574968f305eSRichard Henderson                 tcg_op_remove(s, op_prev);
3575968f305eSRichard Henderson                 op_prev = QTAILQ_PREV(op, link);
3576968f305eSRichard Henderson             }
3577968f305eSRichard Henderson 
3578968f305eSRichard Henderson             /*
35794d89d0bbSRichard Henderson              * Optimization can fold conditional branches to unconditional.
35804d89d0bbSRichard Henderson              * If we find a label which is preceded by an unconditional
35814d89d0bbSRichard Henderson              * branch to next, remove the branch.  We couldn't do this when
35824d89d0bbSRichard Henderson              * processing the branch because any dead code between the branch
35834d89d0bbSRichard Henderson              * and label had not yet been removed.
35844d89d0bbSRichard Henderson              */
35854d89d0bbSRichard Henderson             if (op_prev->opc == INDEX_op_br &&
35864d89d0bbSRichard Henderson                 label == arg_label(op_prev->args[0])) {
35874d89d0bbSRichard Henderson                 tcg_op_remove(s, op_prev);
35884d89d0bbSRichard Henderson                 /* Fall through means insns become live again.  */
35894d89d0bbSRichard Henderson                 dead = false;
35904d89d0bbSRichard Henderson             }
35914d89d0bbSRichard Henderson 
3592f85b1fc4SRichard Henderson             if (QSIMPLEQ_EMPTY(&label->branches)) {
3593b4fc67c7SRichard Henderson                 /*
3594b4fc67c7SRichard Henderson                  * While there is an occasional backward branch, virtually
3595b4fc67c7SRichard Henderson                  * all branches generated by the translators are forward.
3596b4fc67c7SRichard Henderson                  * Which means that generally we will have already removed
3597b4fc67c7SRichard Henderson                  * all references to the label that will be, and there is
3598b4fc67c7SRichard Henderson                  * little to be gained by iterating.
3599b4fc67c7SRichard Henderson                  */
3600b4fc67c7SRichard Henderson                 remove = true;
3601b4fc67c7SRichard Henderson             } else {
3602b4fc67c7SRichard Henderson                 /* Once we see a label, insns become live again.  */
3603b4fc67c7SRichard Henderson                 dead = false;
3604b4fc67c7SRichard Henderson                 remove = false;
3605b4fc67c7SRichard Henderson             }
3606b4fc67c7SRichard Henderson             break;
3607b4fc67c7SRichard Henderson 
3608b4fc67c7SRichard Henderson         case INDEX_op_br:
3609b4fc67c7SRichard Henderson         case INDEX_op_exit_tb:
3610b4fc67c7SRichard Henderson         case INDEX_op_goto_ptr:
3611b4fc67c7SRichard Henderson             /* Unconditional branches; everything following is dead.  */
3612b4fc67c7SRichard Henderson             dead = true;
3613b4fc67c7SRichard Henderson             break;
3614b4fc67c7SRichard Henderson 
3615b4fc67c7SRichard Henderson         case INDEX_op_call:
3616b4fc67c7SRichard Henderson             /* Notice noreturn helper calls, raising exceptions.  */
361790163900SRichard Henderson             if (tcg_call_flags(op) & TCG_CALL_NO_RETURN) {
3618b4fc67c7SRichard Henderson                 dead = true;
3619b4fc67c7SRichard Henderson             }
3620b4fc67c7SRichard Henderson             break;
3621b4fc67c7SRichard Henderson 
3622b4fc67c7SRichard Henderson         case INDEX_op_insn_start:
3623b4fc67c7SRichard Henderson             /* Never remove -- we need to keep these for unwind.  */
3624b4fc67c7SRichard Henderson             remove = false;
3625b4fc67c7SRichard Henderson             break;
3626b4fc67c7SRichard Henderson 
3627b4fc67c7SRichard Henderson         default:
3628b4fc67c7SRichard Henderson             break;
3629b4fc67c7SRichard Henderson         }
3630b4fc67c7SRichard Henderson 
3631b4fc67c7SRichard Henderson         if (remove) {
3632b4fc67c7SRichard Henderson             tcg_op_remove(s, op);
3633b4fc67c7SRichard Henderson         }
3634b4fc67c7SRichard Henderson     }
3635b4fc67c7SRichard Henderson }
3636b4fc67c7SRichard Henderson 
3637c70fbf0aSRichard Henderson #define TS_DEAD  1
3638c70fbf0aSRichard Henderson #define TS_MEM   2
3639c70fbf0aSRichard Henderson 
36405a18407fSRichard Henderson #define IS_DEAD_ARG(n)   (arg_life & (DEAD_ARG << (n)))
36415a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n)))
36425a18407fSRichard Henderson 
364325f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp.  */
364425f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts)
364525f49c5fSRichard Henderson {
364625f49c5fSRichard Henderson     return ts->state_ptr;
364725f49c5fSRichard Henderson }
364825f49c5fSRichard Henderson 
364925f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the
365025f49c5fSRichard Henderson  * maximal regset for its type.
365125f49c5fSRichard Henderson  */
365225f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts)
365325f49c5fSRichard Henderson {
365425f49c5fSRichard Henderson     *la_temp_pref(ts)
365525f49c5fSRichard Henderson         = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]);
365625f49c5fSRichard Henderson }
365725f49c5fSRichard Henderson 
36589c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals
36599c43b68dSAurelien Jarno    should be in memory. */
36602616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt)
3661c896fe29Sbellard {
3662b83eabeaSRichard Henderson     int i;
3663b83eabeaSRichard Henderson 
3664b83eabeaSRichard Henderson     for (i = 0; i < ng; ++i) {
3665b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
366625f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
3667b83eabeaSRichard Henderson     }
3668b83eabeaSRichard Henderson     for (i = ng; i < nt; ++i) {
3669b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD;
367025f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
3671b83eabeaSRichard Henderson     }
3672c896fe29Sbellard }
3673c896fe29Sbellard 
36749c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals
36759c43b68dSAurelien Jarno    and local temps should be in memory. */
36762616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt)
3677641d5fbeSbellard {
3678b83eabeaSRichard Henderson     int i;
3679641d5fbeSbellard 
3680ee17db83SRichard Henderson     for (i = 0; i < nt; ++i) {
3681ee17db83SRichard Henderson         TCGTemp *ts = &s->temps[i];
3682ee17db83SRichard Henderson         int state;
3683ee17db83SRichard Henderson 
3684ee17db83SRichard Henderson         switch (ts->kind) {
3685ee17db83SRichard Henderson         case TEMP_FIXED:
3686ee17db83SRichard Henderson         case TEMP_GLOBAL:
3687f57c6915SRichard Henderson         case TEMP_TB:
3688ee17db83SRichard Henderson             state = TS_DEAD | TS_MEM;
3689ee17db83SRichard Henderson             break;
3690c7482438SRichard Henderson         case TEMP_EBB:
3691c0522136SRichard Henderson         case TEMP_CONST:
3692ee17db83SRichard Henderson             state = TS_DEAD;
3693ee17db83SRichard Henderson             break;
3694ee17db83SRichard Henderson         default:
3695ee17db83SRichard Henderson             g_assert_not_reached();
3696c70fbf0aSRichard Henderson         }
3697ee17db83SRichard Henderson         ts->state = state;
3698ee17db83SRichard Henderson         la_reset_pref(ts);
3699641d5fbeSbellard     }
3700641d5fbeSbellard }
3701641d5fbeSbellard 
3702f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory.  */
3703f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng)
3704f65a061cSRichard Henderson {
3705f65a061cSRichard Henderson     int i;
3706f65a061cSRichard Henderson 
3707f65a061cSRichard Henderson     for (i = 0; i < ng; ++i) {
370825f49c5fSRichard Henderson         int state = s->temps[i].state;
370925f49c5fSRichard Henderson         s->temps[i].state = state | TS_MEM;
371025f49c5fSRichard Henderson         if (state == TS_DEAD) {
371125f49c5fSRichard Henderson             /* If the global was previously dead, reset prefs.  */
371225f49c5fSRichard Henderson             la_reset_pref(&s->temps[i]);
371325f49c5fSRichard Henderson         }
3714f65a061cSRichard Henderson     }
3715f65a061cSRichard Henderson }
3716f65a061cSRichard Henderson 
3717b4cb76e6SRichard Henderson /*
3718c7482438SRichard Henderson  * liveness analysis: conditional branch: all temps are dead unless
3719c7482438SRichard Henderson  * explicitly live-across-conditional-branch, globals and local temps
3720c7482438SRichard Henderson  * should be synced.
3721b4cb76e6SRichard Henderson  */
3722b4cb76e6SRichard Henderson static void la_bb_sync(TCGContext *s, int ng, int nt)
3723b4cb76e6SRichard Henderson {
3724b4cb76e6SRichard Henderson     la_global_sync(s, ng);
3725b4cb76e6SRichard Henderson 
3726b4cb76e6SRichard Henderson     for (int i = ng; i < nt; ++i) {
3727c0522136SRichard Henderson         TCGTemp *ts = &s->temps[i];
3728c0522136SRichard Henderson         int state;
3729c0522136SRichard Henderson 
3730c0522136SRichard Henderson         switch (ts->kind) {
3731f57c6915SRichard Henderson         case TEMP_TB:
3732c0522136SRichard Henderson             state = ts->state;
3733c0522136SRichard Henderson             ts->state = state | TS_MEM;
3734b4cb76e6SRichard Henderson             if (state != TS_DEAD) {
3735b4cb76e6SRichard Henderson                 continue;
3736b4cb76e6SRichard Henderson             }
3737c0522136SRichard Henderson             break;
3738c7482438SRichard Henderson         case TEMP_EBB:
3739c0522136SRichard Henderson         case TEMP_CONST:
3740c0522136SRichard Henderson             continue;
3741c0522136SRichard Henderson         default:
3742c0522136SRichard Henderson             g_assert_not_reached();
3743b4cb76e6SRichard Henderson         }
3744b4cb76e6SRichard Henderson         la_reset_pref(&s->temps[i]);
3745b4cb76e6SRichard Henderson     }
3746b4cb76e6SRichard Henderson }
3747b4cb76e6SRichard Henderson 
3748f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill.  */
3749f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng)
3750f65a061cSRichard Henderson {
3751f65a061cSRichard Henderson     int i;
3752f65a061cSRichard Henderson 
3753f65a061cSRichard Henderson     for (i = 0; i < ng; i++) {
3754f65a061cSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
375525f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
375625f49c5fSRichard Henderson     }
375725f49c5fSRichard Henderson }
375825f49c5fSRichard Henderson 
375925f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls.  */
376025f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt)
376125f49c5fSRichard Henderson {
376225f49c5fSRichard Henderson     TCGRegSet mask = ~tcg_target_call_clobber_regs;
376325f49c5fSRichard Henderson     int i;
376425f49c5fSRichard Henderson 
376525f49c5fSRichard Henderson     for (i = 0; i < nt; i++) {
376625f49c5fSRichard Henderson         TCGTemp *ts = &s->temps[i];
376725f49c5fSRichard Henderson         if (!(ts->state & TS_DEAD)) {
376825f49c5fSRichard Henderson             TCGRegSet *pset = la_temp_pref(ts);
376925f49c5fSRichard Henderson             TCGRegSet set = *pset;
377025f49c5fSRichard Henderson 
377125f49c5fSRichard Henderson             set &= mask;
377225f49c5fSRichard Henderson             /* If the combination is not possible, restart.  */
377325f49c5fSRichard Henderson             if (set == 0) {
377425f49c5fSRichard Henderson                 set = tcg_target_available_regs[ts->type] & mask;
377525f49c5fSRichard Henderson             }
377625f49c5fSRichard Henderson             *pset = set;
377725f49c5fSRichard Henderson         }
3778f65a061cSRichard Henderson     }
3779f65a061cSRichard Henderson }
3780f65a061cSRichard Henderson 
3781874b8574SRichard Henderson /*
3782874b8574SRichard Henderson  * Liveness analysis: Verify the lifetime of TEMP_TB, and reduce
3783874b8574SRichard Henderson  * to TEMP_EBB, if possible.
3784874b8574SRichard Henderson  */
3785874b8574SRichard Henderson static void __attribute__((noinline))
3786874b8574SRichard Henderson liveness_pass_0(TCGContext *s)
3787874b8574SRichard Henderson {
3788874b8574SRichard Henderson     void * const multiple_ebb = (void *)(uintptr_t)-1;
3789874b8574SRichard Henderson     int nb_temps = s->nb_temps;
3790874b8574SRichard Henderson     TCGOp *op, *ebb;
3791874b8574SRichard Henderson 
3792874b8574SRichard Henderson     for (int i = s->nb_globals; i < nb_temps; ++i) {
3793874b8574SRichard Henderson         s->temps[i].state_ptr = NULL;
3794874b8574SRichard Henderson     }
3795874b8574SRichard Henderson 
3796874b8574SRichard Henderson     /*
3797874b8574SRichard Henderson      * Represent each EBB by the op at which it begins.  In the case of
3798874b8574SRichard Henderson      * the first EBB, this is the first op, otherwise it is a label.
3799874b8574SRichard Henderson      * Collect the uses of each TEMP_TB: NULL for unused, EBB for use
3800874b8574SRichard Henderson      * within a single EBB, else MULTIPLE_EBB.
3801874b8574SRichard Henderson      */
3802874b8574SRichard Henderson     ebb = QTAILQ_FIRST(&s->ops);
3803874b8574SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
3804874b8574SRichard Henderson         const TCGOpDef *def;
3805874b8574SRichard Henderson         int nb_oargs, nb_iargs;
3806874b8574SRichard Henderson 
3807874b8574SRichard Henderson         switch (op->opc) {
3808874b8574SRichard Henderson         case INDEX_op_set_label:
3809874b8574SRichard Henderson             ebb = op;
3810874b8574SRichard Henderson             continue;
3811874b8574SRichard Henderson         case INDEX_op_discard:
3812874b8574SRichard Henderson             continue;
3813874b8574SRichard Henderson         case INDEX_op_call:
3814874b8574SRichard Henderson             nb_oargs = TCGOP_CALLO(op);
3815874b8574SRichard Henderson             nb_iargs = TCGOP_CALLI(op);
3816874b8574SRichard Henderson             break;
3817874b8574SRichard Henderson         default:
3818874b8574SRichard Henderson             def = &tcg_op_defs[op->opc];
3819874b8574SRichard Henderson             nb_oargs = def->nb_oargs;
3820874b8574SRichard Henderson             nb_iargs = def->nb_iargs;
3821874b8574SRichard Henderson             break;
3822874b8574SRichard Henderson         }
3823874b8574SRichard Henderson 
3824874b8574SRichard Henderson         for (int i = 0; i < nb_oargs + nb_iargs; ++i) {
3825874b8574SRichard Henderson             TCGTemp *ts = arg_temp(op->args[i]);
3826874b8574SRichard Henderson 
3827874b8574SRichard Henderson             if (ts->kind != TEMP_TB) {
3828874b8574SRichard Henderson                 continue;
3829874b8574SRichard Henderson             }
3830874b8574SRichard Henderson             if (ts->state_ptr == NULL) {
3831874b8574SRichard Henderson                 ts->state_ptr = ebb;
3832874b8574SRichard Henderson             } else if (ts->state_ptr != ebb) {
3833874b8574SRichard Henderson                 ts->state_ptr = multiple_ebb;
3834874b8574SRichard Henderson             }
3835874b8574SRichard Henderson         }
3836874b8574SRichard Henderson     }
3837874b8574SRichard Henderson 
3838874b8574SRichard Henderson     /*
3839874b8574SRichard Henderson      * For TEMP_TB that turned out not to be used beyond one EBB,
3840874b8574SRichard Henderson      * reduce the liveness to TEMP_EBB.
3841874b8574SRichard Henderson      */
3842874b8574SRichard Henderson     for (int i = s->nb_globals; i < nb_temps; ++i) {
3843874b8574SRichard Henderson         TCGTemp *ts = &s->temps[i];
3844874b8574SRichard Henderson         if (ts->kind == TEMP_TB && ts->state_ptr != multiple_ebb) {
3845874b8574SRichard Henderson             ts->kind = TEMP_EBB;
3846874b8574SRichard Henderson         }
3847874b8574SRichard Henderson     }
3848874b8574SRichard Henderson }
3849874b8574SRichard Henderson 
3850a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a
3851c896fe29Sbellard    given input arguments is dead. Instructions updating dead
3852c896fe29Sbellard    temporaries are removed. */
38539bbee4c0SRichard Henderson static void __attribute__((noinline))
38549bbee4c0SRichard Henderson liveness_pass_1(TCGContext *s)
3855c896fe29Sbellard {
3856c70fbf0aSRichard Henderson     int nb_globals = s->nb_globals;
38572616c808SRichard Henderson     int nb_temps = s->nb_temps;
385815fa08f8SRichard Henderson     TCGOp *op, *op_prev;
385925f49c5fSRichard Henderson     TCGRegSet *prefs;
386025f49c5fSRichard Henderson     int i;
386125f49c5fSRichard Henderson 
386225f49c5fSRichard Henderson     prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps);
386325f49c5fSRichard Henderson     for (i = 0; i < nb_temps; ++i) {
386425f49c5fSRichard Henderson         s->temps[i].state_ptr = prefs + i;
386525f49c5fSRichard Henderson     }
3866c896fe29Sbellard 
3867ae36a246SRichard Henderson     /* ??? Should be redundant with the exit_tb that ends the TB.  */
38682616c808SRichard Henderson     la_func_end(s, nb_globals, nb_temps);
3869c896fe29Sbellard 
3870eae3eb3eSPaolo Bonzini     QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) {
387125f49c5fSRichard Henderson         int nb_iargs, nb_oargs;
3872c45cb8bbSRichard Henderson         TCGOpcode opc_new, opc_new2;
3873a1b3c48dSRichard Henderson         TCGLifeData arg_life = 0;
387425f49c5fSRichard Henderson         TCGTemp *ts;
3875c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
3876c45cb8bbSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
3877501fb3daSRichard Henderson         const TCGArgConstraint *args_ct;
3878c45cb8bbSRichard Henderson 
3879c45cb8bbSRichard Henderson         switch (opc) {
3880c896fe29Sbellard         case INDEX_op_call:
3881c6e113f5Sbellard             {
388239004a71SRichard Henderson                 const TCGHelperInfo *info = tcg_call_info(op);
388339004a71SRichard Henderson                 int call_flags = tcg_call_flags(op);
3884c6e113f5Sbellard 
3885cd9090aaSRichard Henderson                 nb_oargs = TCGOP_CALLO(op);
3886cd9090aaSRichard Henderson                 nb_iargs = TCGOP_CALLI(op);
3887c6e113f5Sbellard 
3888c45cb8bbSRichard Henderson                 /* pure functions can be removed if their result is unused */
388978505279SAurelien Jarno                 if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) {
3890c6e113f5Sbellard                     for (i = 0; i < nb_oargs; i++) {
389125f49c5fSRichard Henderson                         ts = arg_temp(op->args[i]);
389225f49c5fSRichard Henderson                         if (ts->state != TS_DEAD) {
3893c6e113f5Sbellard                             goto do_not_remove_call;
3894c6e113f5Sbellard                         }
38959c43b68dSAurelien Jarno                     }
3896c45cb8bbSRichard Henderson                     goto do_remove;
3897152c35aaSRichard Henderson                 }
3898c6e113f5Sbellard             do_not_remove_call:
3899c896fe29Sbellard 
390025f49c5fSRichard Henderson                 /* Output args are dead.  */
3901c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
390225f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
390325f49c5fSRichard Henderson                     if (ts->state & TS_DEAD) {
3904a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
39056b64b624SAurelien Jarno                     }
390625f49c5fSRichard Henderson                     if (ts->state & TS_MEM) {
3907a1b3c48dSRichard Henderson                         arg_life |= SYNC_ARG << i;
39089c43b68dSAurelien Jarno                     }
390925f49c5fSRichard Henderson                     ts->state = TS_DEAD;
391025f49c5fSRichard Henderson                     la_reset_pref(ts);
3911c896fe29Sbellard                 }
3912c896fe29Sbellard 
391331fd884bSRichard Henderson                 /* Not used -- it will be tcg_target_call_oarg_reg().  */
391431fd884bSRichard Henderson                 memset(op->output_pref, 0, sizeof(op->output_pref));
391531fd884bSRichard Henderson 
391678505279SAurelien Jarno                 if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS |
391778505279SAurelien Jarno                                     TCG_CALL_NO_READ_GLOBALS))) {
3918f65a061cSRichard Henderson                     la_global_kill(s, nb_globals);
3919c70fbf0aSRichard Henderson                 } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) {
3920f65a061cSRichard Henderson                     la_global_sync(s, nb_globals);
3921b9c18f56Saurel32                 }
3922c896fe29Sbellard 
392325f49c5fSRichard Henderson                 /* Record arguments that die in this helper.  */
3924866cb6cbSAurelien Jarno                 for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
392525f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
392639004a71SRichard Henderson                     if (ts->state & TS_DEAD) {
3927a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
3928c896fe29Sbellard                     }
3929c896fe29Sbellard                 }
393025f49c5fSRichard Henderson 
393125f49c5fSRichard Henderson                 /* For all live registers, remove call-clobbered prefs.  */
393225f49c5fSRichard Henderson                 la_cross_call(s, nb_temps);
393325f49c5fSRichard Henderson 
393439004a71SRichard Henderson                 /*
393539004a71SRichard Henderson                  * Input arguments are live for preceding opcodes.
393639004a71SRichard Henderson                  *
393739004a71SRichard Henderson                  * For those arguments that die, and will be allocated in
393839004a71SRichard Henderson                  * registers, clear the register set for that arg, to be
393939004a71SRichard Henderson                  * filled in below.  For args that will be on the stack,
394039004a71SRichard Henderson                  * reset to any available reg.  Process arguments in reverse
394139004a71SRichard Henderson                  * order so that if a temp is used more than once, the stack
394239004a71SRichard Henderson                  * reset to max happens before the register reset to 0.
394325f49c5fSRichard Henderson                  */
394439004a71SRichard Henderson                 for (i = nb_iargs - 1; i >= 0; i--) {
394539004a71SRichard Henderson                     const TCGCallArgumentLoc *loc = &info->in[i];
394639004a71SRichard Henderson                     ts = arg_temp(op->args[nb_oargs + i]);
394739004a71SRichard Henderson 
394839004a71SRichard Henderson                     if (ts->state & TS_DEAD) {
394939004a71SRichard Henderson                         switch (loc->kind) {
395039004a71SRichard Henderson                         case TCG_CALL_ARG_NORMAL:
395139004a71SRichard Henderson                         case TCG_CALL_ARG_EXTEND_U:
395239004a71SRichard Henderson                         case TCG_CALL_ARG_EXTEND_S:
3953338b61e9SRichard Henderson                             if (arg_slot_reg_p(loc->arg_slot)) {
395439004a71SRichard Henderson                                 *la_temp_pref(ts) = 0;
395539004a71SRichard Henderson                                 break;
395639004a71SRichard Henderson                             }
395739004a71SRichard Henderson                             /* fall through */
395839004a71SRichard Henderson                         default:
395939004a71SRichard Henderson                             *la_temp_pref(ts) =
396039004a71SRichard Henderson                                 tcg_target_available_regs[ts->type];
396139004a71SRichard Henderson                             break;
396239004a71SRichard Henderson                         }
396325f49c5fSRichard Henderson                         ts->state &= ~TS_DEAD;
396425f49c5fSRichard Henderson                     }
396525f49c5fSRichard Henderson                 }
396625f49c5fSRichard Henderson 
396739004a71SRichard Henderson                 /*
396839004a71SRichard Henderson                  * For each input argument, add its input register to prefs.
396939004a71SRichard Henderson                  * If a temp is used once, this produces a single set bit;
397039004a71SRichard Henderson                  * if a temp is used multiple times, this produces a set.
397139004a71SRichard Henderson                  */
397239004a71SRichard Henderson                 for (i = 0; i < nb_iargs; i++) {
397339004a71SRichard Henderson                     const TCGCallArgumentLoc *loc = &info->in[i];
397439004a71SRichard Henderson                     ts = arg_temp(op->args[nb_oargs + i]);
397539004a71SRichard Henderson 
397639004a71SRichard Henderson                     switch (loc->kind) {
397739004a71SRichard Henderson                     case TCG_CALL_ARG_NORMAL:
397839004a71SRichard Henderson                     case TCG_CALL_ARG_EXTEND_U:
397939004a71SRichard Henderson                     case TCG_CALL_ARG_EXTEND_S:
3980338b61e9SRichard Henderson                         if (arg_slot_reg_p(loc->arg_slot)) {
398125f49c5fSRichard Henderson                             tcg_regset_set_reg(*la_temp_pref(ts),
398239004a71SRichard Henderson                                 tcg_target_call_iarg_regs[loc->arg_slot]);
398339004a71SRichard Henderson                         }
398439004a71SRichard Henderson                         break;
398539004a71SRichard Henderson                     default:
398639004a71SRichard Henderson                         break;
3987c70fbf0aSRichard Henderson                     }
3988c19f47bfSAurelien Jarno                 }
3989c6e113f5Sbellard             }
3990c896fe29Sbellard             break;
3991765b842aSRichard Henderson         case INDEX_op_insn_start:
3992c896fe29Sbellard             break;
39935ff9d6a4Sbellard         case INDEX_op_discard:
39945ff9d6a4Sbellard             /* mark the temporary as dead */
399525f49c5fSRichard Henderson             ts = arg_temp(op->args[0]);
399625f49c5fSRichard Henderson             ts->state = TS_DEAD;
399725f49c5fSRichard Henderson             la_reset_pref(ts);
39985ff9d6a4Sbellard             break;
39991305c451SRichard Henderson 
40001305c451SRichard Henderson         case INDEX_op_add2_i32:
400179602f63SRichard Henderson         case INDEX_op_add2_i64:
400279602f63SRichard Henderson             opc_new = INDEX_op_add;
4003f1fae40cSRichard Henderson             goto do_addsub2;
40041305c451SRichard Henderson         case INDEX_op_sub2_i32:
4005f1fae40cSRichard Henderson         case INDEX_op_sub2_i64:
400660f34f55SRichard Henderson             opc_new = INDEX_op_sub;
4007f1fae40cSRichard Henderson         do_addsub2:
40081305c451SRichard Henderson             nb_iargs = 4;
40091305c451SRichard Henderson             nb_oargs = 2;
40101305c451SRichard Henderson             /* Test if the high part of the operation is dead, but not
40111305c451SRichard Henderson                the low part.  The result can be optimized to a simple
40121305c451SRichard Henderson                add or sub.  This happens often for x86_64 guest when the
40131305c451SRichard Henderson                cpu mode is set to 32 bit.  */
4014b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
4015b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
40161305c451SRichard Henderson                     goto do_remove;
40171305c451SRichard Henderson                 }
4018c45cb8bbSRichard Henderson                 /* Replace the opcode and adjust the args in place,
4019c45cb8bbSRichard Henderson                    leaving 3 unused args at the end.  */
4020c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
4021efee3746SRichard Henderson                 op->args[1] = op->args[2];
4022efee3746SRichard Henderson                 op->args[2] = op->args[4];
40231305c451SRichard Henderson                 /* Fall through and mark the single-word operation live.  */
40241305c451SRichard Henderson                 nb_iargs = 2;
40251305c451SRichard Henderson                 nb_oargs = 1;
40261305c451SRichard Henderson             }
40271305c451SRichard Henderson             goto do_not_remove;
40281305c451SRichard Henderson 
4029f1fae40cSRichard Henderson         case INDEX_op_muls2_i32:
4030*c742824dSRichard Henderson         case INDEX_op_muls2_i64:
4031d2c3ecadSRichard Henderson             opc_new = INDEX_op_mul;
4032*c742824dSRichard Henderson             opc_new2 = INDEX_op_mulsh;
4033f1fae40cSRichard Henderson             goto do_mul2;
4034aa28c9efSRichard Henderson         case INDEX_op_mulu2_i32:
4035f1fae40cSRichard Henderson         case INDEX_op_mulu2_i64:
4036d2c3ecadSRichard Henderson             opc_new = INDEX_op_mul;
4037aa28c9efSRichard Henderson             opc_new2 = INDEX_op_muluh;
4038f1fae40cSRichard Henderson         do_mul2:
40391414968aSRichard Henderson             nb_iargs = 2;
40401414968aSRichard Henderson             nb_oargs = 2;
4041b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
4042b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
404303271524SRichard Henderson                     /* Both parts of the operation are dead.  */
40441414968aSRichard Henderson                     goto do_remove;
40451414968aSRichard Henderson                 }
404603271524SRichard Henderson                 /* The high part of the operation is dead; generate the low. */
4047c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
4048efee3746SRichard Henderson                 op->args[1] = op->args[2];
4049efee3746SRichard Henderson                 op->args[2] = op->args[3];
4050937246f2SRichard Henderson             } else if (arg_temp(op->args[0])->state == TS_DEAD &&
4051937246f2SRichard Henderson                        tcg_op_supported(opc_new2, TCGOP_TYPE(op), 0)) {
405203271524SRichard Henderson                 /* The low part of the operation is dead; generate the high. */
4053c45cb8bbSRichard Henderson                 op->opc = opc = opc_new2;
4054efee3746SRichard Henderson                 op->args[0] = op->args[1];
4055efee3746SRichard Henderson                 op->args[1] = op->args[2];
4056efee3746SRichard Henderson                 op->args[2] = op->args[3];
405703271524SRichard Henderson             } else {
405803271524SRichard Henderson                 goto do_not_remove;
405903271524SRichard Henderson             }
406003271524SRichard Henderson             /* Mark the single-word operation live.  */
40611414968aSRichard Henderson             nb_oargs = 1;
40621414968aSRichard Henderson             goto do_not_remove;
40631414968aSRichard Henderson 
4064c896fe29Sbellard         default:
40651305c451SRichard Henderson             /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
4066c896fe29Sbellard             nb_iargs = def->nb_iargs;
4067c896fe29Sbellard             nb_oargs = def->nb_oargs;
4068c896fe29Sbellard 
4069c896fe29Sbellard             /* Test if the operation can be removed because all
40705ff9d6a4Sbellard                its outputs are dead. We assume that nb_oargs == 0
40715ff9d6a4Sbellard                implies side effects */
40725ff9d6a4Sbellard             if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
4073c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
4074b83eabeaSRichard Henderson                     if (arg_temp(op->args[i])->state != TS_DEAD) {
4075c896fe29Sbellard                         goto do_not_remove;
4076c896fe29Sbellard                     }
40779c43b68dSAurelien Jarno                 }
4078152c35aaSRichard Henderson                 goto do_remove;
4079152c35aaSRichard Henderson             }
4080152c35aaSRichard Henderson             goto do_not_remove;
4081152c35aaSRichard Henderson 
40821305c451SRichard Henderson         do_remove:
40830c627cdcSRichard Henderson             tcg_op_remove(s, op);
4084152c35aaSRichard Henderson             break;
4085152c35aaSRichard Henderson 
4086c896fe29Sbellard         do_not_remove:
4087c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
408825f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
408925f49c5fSRichard Henderson 
409025f49c5fSRichard Henderson                 /* Remember the preference of the uses that followed.  */
409131fd884bSRichard Henderson                 if (i < ARRAY_SIZE(op->output_pref)) {
409225f49c5fSRichard Henderson                     op->output_pref[i] = *la_temp_pref(ts);
409331fd884bSRichard Henderson                 }
409425f49c5fSRichard Henderson 
409525f49c5fSRichard Henderson                 /* Output args are dead.  */
409625f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
4097a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
40986b64b624SAurelien Jarno                 }
409925f49c5fSRichard Henderson                 if (ts->state & TS_MEM) {
4100a1b3c48dSRichard Henderson                     arg_life |= SYNC_ARG << i;
41019c43b68dSAurelien Jarno                 }
410225f49c5fSRichard Henderson                 ts->state = TS_DEAD;
410325f49c5fSRichard Henderson                 la_reset_pref(ts);
4104c896fe29Sbellard             }
4105c896fe29Sbellard 
410625f49c5fSRichard Henderson             /* If end of basic block, update.  */
4107ae36a246SRichard Henderson             if (def->flags & TCG_OPF_BB_EXIT) {
4108ae36a246SRichard Henderson                 la_func_end(s, nb_globals, nb_temps);
4109b4cb76e6SRichard Henderson             } else if (def->flags & TCG_OPF_COND_BRANCH) {
4110b4cb76e6SRichard Henderson                 la_bb_sync(s, nb_globals, nb_temps);
4111ae36a246SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
41122616c808SRichard Henderson                 la_bb_end(s, nb_globals, nb_temps);
41133d5c5f87SAurelien Jarno             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
4114f65a061cSRichard Henderson                 la_global_sync(s, nb_globals);
411525f49c5fSRichard Henderson                 if (def->flags & TCG_OPF_CALL_CLOBBER) {
411625f49c5fSRichard Henderson                     la_cross_call(s, nb_temps);
411725f49c5fSRichard Henderson                 }
4118c896fe29Sbellard             }
4119c896fe29Sbellard 
412025f49c5fSRichard Henderson             /* Record arguments that die in this opcode.  */
4121866cb6cbSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
412225f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
412325f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
4124a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
4125c896fe29Sbellard                 }
4126c19f47bfSAurelien Jarno             }
412725f49c5fSRichard Henderson 
412825f49c5fSRichard Henderson             /* Input arguments are live for preceding opcodes.  */
4129c19f47bfSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
413025f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
413125f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
413225f49c5fSRichard Henderson                     /* For operands that were dead, initially allow
413325f49c5fSRichard Henderson                        all regs for the type.  */
413425f49c5fSRichard Henderson                     *la_temp_pref(ts) = tcg_target_available_regs[ts->type];
413525f49c5fSRichard Henderson                     ts->state &= ~TS_DEAD;
413625f49c5fSRichard Henderson                 }
413725f49c5fSRichard Henderson             }
413825f49c5fSRichard Henderson 
413925f49c5fSRichard Henderson             /* Incorporate constraints for this operand.  */
414025f49c5fSRichard Henderson             switch (opc) {
4141b5701261SRichard Henderson             case INDEX_op_mov:
414225f49c5fSRichard Henderson                 /* Note that these are TCG_OPF_NOT_PRESENT and do not
414325f49c5fSRichard Henderson                    have proper constraints.  That said, special case
414425f49c5fSRichard Henderson                    moves to propagate preferences backward.  */
414525f49c5fSRichard Henderson                 if (IS_DEAD_ARG(1)) {
414625f49c5fSRichard Henderson                     *la_temp_pref(arg_temp(op->args[0]))
414725f49c5fSRichard Henderson                         = *la_temp_pref(arg_temp(op->args[1]));
414825f49c5fSRichard Henderson                 }
414925f49c5fSRichard Henderson                 break;
415025f49c5fSRichard Henderson 
415125f49c5fSRichard Henderson             default:
4152501fb3daSRichard Henderson                 args_ct = opcode_args_ct(op);
415325f49c5fSRichard Henderson                 for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
4154501fb3daSRichard Henderson                     const TCGArgConstraint *ct = &args_ct[i];
415525f49c5fSRichard Henderson                     TCGRegSet set, *pset;
415625f49c5fSRichard Henderson 
415725f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
415825f49c5fSRichard Henderson                     pset = la_temp_pref(ts);
415925f49c5fSRichard Henderson                     set = *pset;
416025f49c5fSRichard Henderson 
41619be0d080SRichard Henderson                     set &= ct->regs;
4162bc2b17e6SRichard Henderson                     if (ct->ialias) {
416331fd884bSRichard Henderson                         set &= output_pref(op, ct->alias_index);
416425f49c5fSRichard Henderson                     }
416525f49c5fSRichard Henderson                     /* If the combination is not possible, restart.  */
416625f49c5fSRichard Henderson                     if (set == 0) {
41679be0d080SRichard Henderson                         set = ct->regs;
416825f49c5fSRichard Henderson                     }
416925f49c5fSRichard Henderson                     *pset = set;
417025f49c5fSRichard Henderson                 }
417125f49c5fSRichard Henderson                 break;
4172c896fe29Sbellard             }
4173c896fe29Sbellard             break;
4174c896fe29Sbellard         }
4175bee158cbSRichard Henderson         op->life = arg_life;
4176c896fe29Sbellard     }
41771ff0a2c5SEvgeny Voevodin }
4178c896fe29Sbellard 
41795a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries.  */
41809bbee4c0SRichard Henderson static bool __attribute__((noinline))
41819bbee4c0SRichard Henderson liveness_pass_2(TCGContext *s)
41825a18407fSRichard Henderson {
41835a18407fSRichard Henderson     int nb_globals = s->nb_globals;
418415fa08f8SRichard Henderson     int nb_temps, i;
41855a18407fSRichard Henderson     bool changes = false;
418615fa08f8SRichard Henderson     TCGOp *op, *op_next;
41875a18407fSRichard Henderson 
41885a18407fSRichard Henderson     /* Create a temporary for each indirect global.  */
41895a18407fSRichard Henderson     for (i = 0; i < nb_globals; ++i) {
41905a18407fSRichard Henderson         TCGTemp *its = &s->temps[i];
41915a18407fSRichard Henderson         if (its->indirect_reg) {
41925a18407fSRichard Henderson             TCGTemp *dts = tcg_temp_alloc(s);
41935a18407fSRichard Henderson             dts->type = its->type;
41945a18407fSRichard Henderson             dts->base_type = its->base_type;
4195e1e64652SRichard Henderson             dts->temp_subindex = its->temp_subindex;
4196c7482438SRichard Henderson             dts->kind = TEMP_EBB;
4197b83eabeaSRichard Henderson             its->state_ptr = dts;
4198b83eabeaSRichard Henderson         } else {
4199b83eabeaSRichard Henderson             its->state_ptr = NULL;
42005a18407fSRichard Henderson         }
4201b83eabeaSRichard Henderson         /* All globals begin dead.  */
4202b83eabeaSRichard Henderson         its->state = TS_DEAD;
42035a18407fSRichard Henderson     }
4204b83eabeaSRichard Henderson     for (nb_temps = s->nb_temps; i < nb_temps; ++i) {
4205b83eabeaSRichard Henderson         TCGTemp *its = &s->temps[i];
4206b83eabeaSRichard Henderson         its->state_ptr = NULL;
4207b83eabeaSRichard Henderson         its->state = TS_DEAD;
4208b83eabeaSRichard Henderson     }
42095a18407fSRichard Henderson 
421015fa08f8SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
42115a18407fSRichard Henderson         TCGOpcode opc = op->opc;
42125a18407fSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
42135a18407fSRichard Henderson         TCGLifeData arg_life = op->life;
42145a18407fSRichard Henderson         int nb_iargs, nb_oargs, call_flags;
4215b83eabeaSRichard Henderson         TCGTemp *arg_ts, *dir_ts;
42165a18407fSRichard Henderson 
42175a18407fSRichard Henderson         if (opc == INDEX_op_call) {
4218cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
4219cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
422090163900SRichard Henderson             call_flags = tcg_call_flags(op);
42215a18407fSRichard Henderson         } else {
42225a18407fSRichard Henderson             nb_iargs = def->nb_iargs;
42235a18407fSRichard Henderson             nb_oargs = def->nb_oargs;
42245a18407fSRichard Henderson 
42255a18407fSRichard Henderson             /* Set flags similar to how calls require.  */
4226b4cb76e6SRichard Henderson             if (def->flags & TCG_OPF_COND_BRANCH) {
4227b4cb76e6SRichard Henderson                 /* Like reading globals: sync_globals */
4228b4cb76e6SRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
4229b4cb76e6SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
42305a18407fSRichard Henderson                 /* Like writing globals: save_globals */
42315a18407fSRichard Henderson                 call_flags = 0;
42325a18407fSRichard Henderson             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
42335a18407fSRichard Henderson                 /* Like reading globals: sync_globals */
42345a18407fSRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
42355a18407fSRichard Henderson             } else {
42365a18407fSRichard Henderson                 /* No effect on globals.  */
42375a18407fSRichard Henderson                 call_flags = (TCG_CALL_NO_READ_GLOBALS |
42385a18407fSRichard Henderson                               TCG_CALL_NO_WRITE_GLOBALS);
42395a18407fSRichard Henderson             }
42405a18407fSRichard Henderson         }
42415a18407fSRichard Henderson 
42425a18407fSRichard Henderson         /* Make sure that input arguments are available.  */
42435a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
4244b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
4245b83eabeaSRichard Henderson             dir_ts = arg_ts->state_ptr;
4246b83eabeaSRichard Henderson             if (dir_ts && arg_ts->state == TS_DEAD) {
4247b83eabeaSRichard Henderson                 TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32
42485a18407fSRichard Henderson                                   ? INDEX_op_ld_i32
42495a18407fSRichard Henderson                                   : INDEX_op_ld_i64);
4250cf5c9f69SRichard Henderson                 TCGOp *lop = tcg_op_insert_before(s, op, lopc,
4251cf5c9f69SRichard Henderson                                                   arg_ts->type, 3);
42525a18407fSRichard Henderson 
4253b83eabeaSRichard Henderson                 lop->args[0] = temp_arg(dir_ts);
4254b83eabeaSRichard Henderson                 lop->args[1] = temp_arg(arg_ts->mem_base);
4255b83eabeaSRichard Henderson                 lop->args[2] = arg_ts->mem_offset;
42565a18407fSRichard Henderson 
42575a18407fSRichard Henderson                 /* Loaded, but synced with memory.  */
4258b83eabeaSRichard Henderson                 arg_ts->state = TS_MEM;
42595a18407fSRichard Henderson             }
42605a18407fSRichard Henderson         }
42615a18407fSRichard Henderson 
42625a18407fSRichard Henderson         /* Perform input replacement, and mark inputs that became dead.
42635a18407fSRichard Henderson            No action is required except keeping temp_state up to date
42645a18407fSRichard Henderson            so that we reload when needed.  */
42655a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
4266b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
4267b83eabeaSRichard Henderson             dir_ts = arg_ts->state_ptr;
4268b83eabeaSRichard Henderson             if (dir_ts) {
4269b83eabeaSRichard Henderson                 op->args[i] = temp_arg(dir_ts);
42705a18407fSRichard Henderson                 changes = true;
42715a18407fSRichard Henderson                 if (IS_DEAD_ARG(i)) {
4272b83eabeaSRichard Henderson                     arg_ts->state = TS_DEAD;
42735a18407fSRichard Henderson                 }
42745a18407fSRichard Henderson             }
42755a18407fSRichard Henderson         }
42765a18407fSRichard Henderson 
42775a18407fSRichard Henderson         /* Liveness analysis should ensure that the following are
42785a18407fSRichard Henderson            all correct, for call sites and basic block end points.  */
42795a18407fSRichard Henderson         if (call_flags & TCG_CALL_NO_READ_GLOBALS) {
42805a18407fSRichard Henderson             /* Nothing to do */
42815a18407fSRichard Henderson         } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) {
42825a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
42835a18407fSRichard Henderson                 /* Liveness should see that globals are synced back,
42845a18407fSRichard Henderson                    that is, either TS_DEAD or TS_MEM.  */
4285b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
4286b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
4287b83eabeaSRichard Henderson                                  || arg_ts->state != 0);
42885a18407fSRichard Henderson             }
42895a18407fSRichard Henderson         } else {
42905a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
42915a18407fSRichard Henderson                 /* Liveness should see that globals are saved back,
42925a18407fSRichard Henderson                    that is, TS_DEAD, waiting to be reloaded.  */
4293b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
4294b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
4295b83eabeaSRichard Henderson                                  || arg_ts->state == TS_DEAD);
42965a18407fSRichard Henderson             }
42975a18407fSRichard Henderson         }
42985a18407fSRichard Henderson 
42995a18407fSRichard Henderson         /* Outputs become available.  */
4300b5701261SRichard Henderson         if (opc == INDEX_op_mov) {
430161f15c48SRichard Henderson             arg_ts = arg_temp(op->args[0]);
430261f15c48SRichard Henderson             dir_ts = arg_ts->state_ptr;
430361f15c48SRichard Henderson             if (dir_ts) {
430461f15c48SRichard Henderson                 op->args[0] = temp_arg(dir_ts);
430561f15c48SRichard Henderson                 changes = true;
430661f15c48SRichard Henderson 
430761f15c48SRichard Henderson                 /* The output is now live and modified.  */
430861f15c48SRichard Henderson                 arg_ts->state = 0;
430961f15c48SRichard Henderson 
431061f15c48SRichard Henderson                 if (NEED_SYNC_ARG(0)) {
431161f15c48SRichard Henderson                     TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
431261f15c48SRichard Henderson                                       ? INDEX_op_st_i32
431361f15c48SRichard Henderson                                       : INDEX_op_st_i64);
4314cf5c9f69SRichard Henderson                     TCGOp *sop = tcg_op_insert_after(s, op, sopc,
4315cf5c9f69SRichard Henderson                                                      arg_ts->type, 3);
431661f15c48SRichard Henderson                     TCGTemp *out_ts = dir_ts;
431761f15c48SRichard Henderson 
431861f15c48SRichard Henderson                     if (IS_DEAD_ARG(0)) {
431961f15c48SRichard Henderson                         out_ts = arg_temp(op->args[1]);
432061f15c48SRichard Henderson                         arg_ts->state = TS_DEAD;
432161f15c48SRichard Henderson                         tcg_op_remove(s, op);
432261f15c48SRichard Henderson                     } else {
432361f15c48SRichard Henderson                         arg_ts->state = TS_MEM;
432461f15c48SRichard Henderson                     }
432561f15c48SRichard Henderson 
432661f15c48SRichard Henderson                     sop->args[0] = temp_arg(out_ts);
432761f15c48SRichard Henderson                     sop->args[1] = temp_arg(arg_ts->mem_base);
432861f15c48SRichard Henderson                     sop->args[2] = arg_ts->mem_offset;
432961f15c48SRichard Henderson                 } else {
433061f15c48SRichard Henderson                     tcg_debug_assert(!IS_DEAD_ARG(0));
433161f15c48SRichard Henderson                 }
433261f15c48SRichard Henderson             }
433361f15c48SRichard Henderson         } else {
43345a18407fSRichard Henderson             for (i = 0; i < nb_oargs; i++) {
4335b83eabeaSRichard Henderson                 arg_ts = arg_temp(op->args[i]);
4336b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
4337b83eabeaSRichard Henderson                 if (!dir_ts) {
43385a18407fSRichard Henderson                     continue;
43395a18407fSRichard Henderson                 }
4340b83eabeaSRichard Henderson                 op->args[i] = temp_arg(dir_ts);
43415a18407fSRichard Henderson                 changes = true;
43425a18407fSRichard Henderson 
43435a18407fSRichard Henderson                 /* The output is now live and modified.  */
4344b83eabeaSRichard Henderson                 arg_ts->state = 0;
43455a18407fSRichard Henderson 
43465a18407fSRichard Henderson                 /* Sync outputs upon their last write.  */
43475a18407fSRichard Henderson                 if (NEED_SYNC_ARG(i)) {
4348b83eabeaSRichard Henderson                     TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
43495a18407fSRichard Henderson                                       ? INDEX_op_st_i32
43505a18407fSRichard Henderson                                       : INDEX_op_st_i64);
4351cf5c9f69SRichard Henderson                     TCGOp *sop = tcg_op_insert_after(s, op, sopc,
4352cf5c9f69SRichard Henderson                                                      arg_ts->type, 3);
43535a18407fSRichard Henderson 
4354b83eabeaSRichard Henderson                     sop->args[0] = temp_arg(dir_ts);
4355b83eabeaSRichard Henderson                     sop->args[1] = temp_arg(arg_ts->mem_base);
4356b83eabeaSRichard Henderson                     sop->args[2] = arg_ts->mem_offset;
43575a18407fSRichard Henderson 
4358b83eabeaSRichard Henderson                     arg_ts->state = TS_MEM;
43595a18407fSRichard Henderson                 }
43605a18407fSRichard Henderson                 /* Drop outputs that are dead.  */
43615a18407fSRichard Henderson                 if (IS_DEAD_ARG(i)) {
4362b83eabeaSRichard Henderson                     arg_ts->state = TS_DEAD;
43635a18407fSRichard Henderson                 }
43645a18407fSRichard Henderson             }
43655a18407fSRichard Henderson         }
436661f15c48SRichard Henderson     }
43675a18407fSRichard Henderson 
43685a18407fSRichard Henderson     return changes;
43695a18407fSRichard Henderson }
43705a18407fSRichard Henderson 
43712272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts)
4372c896fe29Sbellard {
437331c96417SRichard Henderson     intptr_t off;
4374273eb50cSRichard Henderson     int size, align;
4375c1c09194SRichard Henderson 
4376273eb50cSRichard Henderson     /* When allocating an object, look at the full type. */
4377273eb50cSRichard Henderson     size = tcg_type_size(ts->base_type);
4378273eb50cSRichard Henderson     switch (ts->base_type) {
4379c1c09194SRichard Henderson     case TCG_TYPE_I32:
438031c96417SRichard Henderson         align = 4;
4381c1c09194SRichard Henderson         break;
4382c1c09194SRichard Henderson     case TCG_TYPE_I64:
4383c1c09194SRichard Henderson     case TCG_TYPE_V64:
438431c96417SRichard Henderson         align = 8;
4385c1c09194SRichard Henderson         break;
438643eef72fSRichard Henderson     case TCG_TYPE_I128:
4387c1c09194SRichard Henderson     case TCG_TYPE_V128:
4388c1c09194SRichard Henderson     case TCG_TYPE_V256:
438943eef72fSRichard Henderson         /*
439043eef72fSRichard Henderson          * Note that we do not require aligned storage for V256,
439143eef72fSRichard Henderson          * and that we provide alignment for I128 to match V128,
439243eef72fSRichard Henderson          * even if that's above what the host ABI requires.
439343eef72fSRichard Henderson          */
439431c96417SRichard Henderson         align = 16;
4395c1c09194SRichard Henderson         break;
4396c1c09194SRichard Henderson     default:
4397c1c09194SRichard Henderson         g_assert_not_reached();
4398b591dc59SBlue Swirl     }
4399c1c09194SRichard Henderson 
4400b9537d59SRichard Henderson     /*
4401b9537d59SRichard Henderson      * Assume the stack is sufficiently aligned.
4402b9537d59SRichard Henderson      * This affects e.g. ARM NEON, where we have 8 byte stack alignment
4403b9537d59SRichard Henderson      * and do not require 16 byte vector alignment.  This seems slightly
4404b9537d59SRichard Henderson      * easier than fully parameterizing the above switch statement.
4405b9537d59SRichard Henderson      */
4406b9537d59SRichard Henderson     align = MIN(TCG_TARGET_STACK_ALIGN, align);
4407c1c09194SRichard Henderson     off = ROUND_UP(s->current_frame_offset, align);
4408732d5897SRichard Henderson 
4409732d5897SRichard Henderson     /* If we've exhausted the stack frame, restart with a smaller TB. */
4410732d5897SRichard Henderson     if (off + size > s->frame_end) {
4411732d5897SRichard Henderson         tcg_raise_tb_overflow(s);
4412732d5897SRichard Henderson     }
4413c1c09194SRichard Henderson     s->current_frame_offset = off + size;
44149defd1bdSRichard Henderson #if defined(__sparc__)
4415273eb50cSRichard Henderson     off += TCG_TARGET_STACK_BIAS;
44169defd1bdSRichard Henderson #endif
4417273eb50cSRichard Henderson 
4418273eb50cSRichard Henderson     /* If the object was subdivided, assign memory to all the parts. */
4419273eb50cSRichard Henderson     if (ts->base_type != ts->type) {
4420273eb50cSRichard Henderson         int part_size = tcg_type_size(ts->type);
4421273eb50cSRichard Henderson         int part_count = size / part_size;
4422273eb50cSRichard Henderson 
4423273eb50cSRichard Henderson         /*
4424273eb50cSRichard Henderson          * Each part is allocated sequentially in tcg_temp_new_internal.
4425273eb50cSRichard Henderson          * Jump back to the first part by subtracting the current index.
4426273eb50cSRichard Henderson          */
4427273eb50cSRichard Henderson         ts -= ts->temp_subindex;
4428273eb50cSRichard Henderson         for (int i = 0; i < part_count; ++i) {
4429273eb50cSRichard Henderson             ts[i].mem_offset = off + i * part_size;
4430273eb50cSRichard Henderson             ts[i].mem_base = s->frame_temp;
4431273eb50cSRichard Henderson             ts[i].mem_allocated = 1;
4432273eb50cSRichard Henderson         }
4433273eb50cSRichard Henderson     } else {
4434273eb50cSRichard Henderson         ts->mem_offset = off;
4435b3a62939SRichard Henderson         ts->mem_base = s->frame_temp;
4436c896fe29Sbellard         ts->mem_allocated = 1;
4437c896fe29Sbellard     }
4438273eb50cSRichard Henderson }
4439c896fe29Sbellard 
4440098859f1SRichard Henderson /* Assign @reg to @ts, and update reg_to_temp[]. */
4441098859f1SRichard Henderson static void set_temp_val_reg(TCGContext *s, TCGTemp *ts, TCGReg reg)
4442098859f1SRichard Henderson {
4443098859f1SRichard Henderson     if (ts->val_type == TEMP_VAL_REG) {
4444098859f1SRichard Henderson         TCGReg old = ts->reg;
4445098859f1SRichard Henderson         tcg_debug_assert(s->reg_to_temp[old] == ts);
4446098859f1SRichard Henderson         if (old == reg) {
4447098859f1SRichard Henderson             return;
4448098859f1SRichard Henderson         }
4449098859f1SRichard Henderson         s->reg_to_temp[old] = NULL;
4450098859f1SRichard Henderson     }
4451098859f1SRichard Henderson     tcg_debug_assert(s->reg_to_temp[reg] == NULL);
4452098859f1SRichard Henderson     s->reg_to_temp[reg] = ts;
4453098859f1SRichard Henderson     ts->val_type = TEMP_VAL_REG;
4454098859f1SRichard Henderson     ts->reg = reg;
4455098859f1SRichard Henderson }
4456098859f1SRichard Henderson 
4457098859f1SRichard Henderson /* Assign a non-register value type to @ts, and update reg_to_temp[]. */
4458098859f1SRichard Henderson static void set_temp_val_nonreg(TCGContext *s, TCGTemp *ts, TCGTempVal type)
4459098859f1SRichard Henderson {
4460098859f1SRichard Henderson     tcg_debug_assert(type != TEMP_VAL_REG);
4461098859f1SRichard Henderson     if (ts->val_type == TEMP_VAL_REG) {
4462098859f1SRichard Henderson         TCGReg reg = ts->reg;
4463098859f1SRichard Henderson         tcg_debug_assert(s->reg_to_temp[reg] == ts);
4464098859f1SRichard Henderson         s->reg_to_temp[reg] = NULL;
4465098859f1SRichard Henderson     }
4466098859f1SRichard Henderson     ts->val_type = type;
4467098859f1SRichard Henderson }
4468098859f1SRichard Henderson 
4469b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet);
4470b3915dbbSRichard Henderson 
447159d7c14eSRichard Henderson /* Mark a temporary as free or dead.  If 'free_or_dead' is negative,
447259d7c14eSRichard Henderson    mark it free; otherwise mark it dead.  */
447359d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead)
4474c896fe29Sbellard {
4475c0522136SRichard Henderson     TCGTempVal new_type;
4476c0522136SRichard Henderson 
4477c0522136SRichard Henderson     switch (ts->kind) {
4478c0522136SRichard Henderson     case TEMP_FIXED:
447959d7c14eSRichard Henderson         return;
4480c0522136SRichard Henderson     case TEMP_GLOBAL:
4481f57c6915SRichard Henderson     case TEMP_TB:
4482c0522136SRichard Henderson         new_type = TEMP_VAL_MEM;
4483c0522136SRichard Henderson         break;
4484c7482438SRichard Henderson     case TEMP_EBB:
4485c0522136SRichard Henderson         new_type = free_or_dead < 0 ? TEMP_VAL_MEM : TEMP_VAL_DEAD;
4486c0522136SRichard Henderson         break;
4487c0522136SRichard Henderson     case TEMP_CONST:
4488c0522136SRichard Henderson         new_type = TEMP_VAL_CONST;
4489c0522136SRichard Henderson         break;
4490c0522136SRichard Henderson     default:
4491c0522136SRichard Henderson         g_assert_not_reached();
449259d7c14eSRichard Henderson     }
4493098859f1SRichard Henderson     set_temp_val_nonreg(s, ts, new_type);
449459d7c14eSRichard Henderson }
4495c896fe29Sbellard 
449659d7c14eSRichard Henderson /* Mark a temporary as dead.  */
449759d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts)
449859d7c14eSRichard Henderson {
449959d7c14eSRichard Henderson     temp_free_or_dead(s, ts, 1);
450059d7c14eSRichard Henderson }
450159d7c14eSRichard Henderson 
450259d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary
450359d7c14eSRichard Henderson    registers needs to be allocated to store a constant.  If 'free_or_dead'
450459d7c14eSRichard Henderson    is non-zero, subsequently release the temporary; if it is positive, the
450559d7c14eSRichard Henderson    temp is dead; if it is negative, the temp is free.  */
450698b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs,
450798b4e186SRichard Henderson                       TCGRegSet preferred_regs, int free_or_dead)
450859d7c14eSRichard Henderson {
4509c0522136SRichard Henderson     if (!temp_readonly(ts) && !ts->mem_coherent) {
45107f6ceedfSAurelien Jarno         if (!ts->mem_allocated) {
45112272e4a7SRichard Henderson             temp_allocate_frame(s, ts);
451259d7c14eSRichard Henderson         }
451359d7c14eSRichard Henderson         switch (ts->val_type) {
451459d7c14eSRichard Henderson         case TEMP_VAL_CONST:
451559d7c14eSRichard Henderson             /* If we're going to free the temp immediately, then we won't
451659d7c14eSRichard Henderson                require it later in a register, so attempt to store the
451759d7c14eSRichard Henderson                constant to memory directly.  */
451859d7c14eSRichard Henderson             if (free_or_dead
451959d7c14eSRichard Henderson                 && tcg_out_sti(s, ts->type, ts->val,
452059d7c14eSRichard Henderson                                ts->mem_base->reg, ts->mem_offset)) {
452159d7c14eSRichard Henderson                 break;
452259d7c14eSRichard Henderson             }
452359d7c14eSRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
452498b4e186SRichard Henderson                       allocated_regs, preferred_regs);
452559d7c14eSRichard Henderson             /* fallthrough */
452659d7c14eSRichard Henderson 
452759d7c14eSRichard Henderson         case TEMP_VAL_REG:
452859d7c14eSRichard Henderson             tcg_out_st(s, ts->type, ts->reg,
452959d7c14eSRichard Henderson                        ts->mem_base->reg, ts->mem_offset);
453059d7c14eSRichard Henderson             break;
453159d7c14eSRichard Henderson 
453259d7c14eSRichard Henderson         case TEMP_VAL_MEM:
453359d7c14eSRichard Henderson             break;
453459d7c14eSRichard Henderson 
453559d7c14eSRichard Henderson         case TEMP_VAL_DEAD:
453659d7c14eSRichard Henderson         default:
4537732e89f4SRichard Henderson             g_assert_not_reached();
4538c896fe29Sbellard         }
45397f6ceedfSAurelien Jarno         ts->mem_coherent = 1;
45407f6ceedfSAurelien Jarno     }
454159d7c14eSRichard Henderson     if (free_or_dead) {
454259d7c14eSRichard Henderson         temp_free_or_dead(s, ts, free_or_dead);
454359d7c14eSRichard Henderson     }
454459d7c14eSRichard Henderson }
45457f6ceedfSAurelien Jarno 
45467f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */
4547b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs)
45487f6ceedfSAurelien Jarno {
4549f8b2f202SRichard Henderson     TCGTemp *ts = s->reg_to_temp[reg];
4550f8b2f202SRichard Henderson     if (ts != NULL) {
455198b4e186SRichard Henderson         temp_sync(s, ts, allocated_regs, 0, -1);
4552c896fe29Sbellard     }
4553c896fe29Sbellard }
4554c896fe29Sbellard 
4555b016486eSRichard Henderson /**
4556b016486eSRichard Henderson  * tcg_reg_alloc:
4557b016486eSRichard Henderson  * @required_regs: Set of registers in which we must allocate.
4558b016486eSRichard Henderson  * @allocated_regs: Set of registers which must be avoided.
4559b016486eSRichard Henderson  * @preferred_regs: Set of registers we should prefer.
4560b016486eSRichard Henderson  * @rev: True if we search the registers in "indirect" order.
4561b016486eSRichard Henderson  *
4562b016486eSRichard Henderson  * The allocated register must be in @required_regs & ~@allocated_regs,
4563b016486eSRichard Henderson  * but if we can put it in @preferred_regs we may save a move later.
4564b016486eSRichard Henderson  */
4565b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs,
4566b016486eSRichard Henderson                             TCGRegSet allocated_regs,
4567b016486eSRichard Henderson                             TCGRegSet preferred_regs, bool rev)
4568c896fe29Sbellard {
4569b016486eSRichard Henderson     int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
4570b016486eSRichard Henderson     TCGRegSet reg_ct[2];
457191478cefSRichard Henderson     const int *order;
4572c896fe29Sbellard 
4573b016486eSRichard Henderson     reg_ct[1] = required_regs & ~allocated_regs;
4574b016486eSRichard Henderson     tcg_debug_assert(reg_ct[1] != 0);
4575b016486eSRichard Henderson     reg_ct[0] = reg_ct[1] & preferred_regs;
4576b016486eSRichard Henderson 
4577b016486eSRichard Henderson     /* Skip the preferred_regs option if it cannot be satisfied,
4578b016486eSRichard Henderson        or if the preference made no difference.  */
4579b016486eSRichard Henderson     f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1];
4580b016486eSRichard Henderson 
458191478cefSRichard Henderson     order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
4582c896fe29Sbellard 
4583b016486eSRichard Henderson     /* Try free registers, preferences first.  */
4584b016486eSRichard Henderson     for (j = f; j < 2; j++) {
4585b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
4586b016486eSRichard Henderson 
4587b016486eSRichard Henderson         if (tcg_regset_single(set)) {
4588b016486eSRichard Henderson             /* One register in the set.  */
4589b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
4590b016486eSRichard Henderson             if (s->reg_to_temp[reg] == NULL) {
4591c896fe29Sbellard                 return reg;
4592c896fe29Sbellard             }
4593b016486eSRichard Henderson         } else {
459491478cefSRichard Henderson             for (i = 0; i < n; i++) {
4595b016486eSRichard Henderson                 TCGReg reg = order[i];
4596b016486eSRichard Henderson                 if (s->reg_to_temp[reg] == NULL &&
4597b016486eSRichard Henderson                     tcg_regset_test_reg(set, reg)) {
4598b016486eSRichard Henderson                     return reg;
4599b016486eSRichard Henderson                 }
4600b016486eSRichard Henderson             }
4601b016486eSRichard Henderson         }
4602b016486eSRichard Henderson     }
4603b016486eSRichard Henderson 
4604b016486eSRichard Henderson     /* We must spill something.  */
4605b016486eSRichard Henderson     for (j = f; j < 2; j++) {
4606b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
4607b016486eSRichard Henderson 
4608b016486eSRichard Henderson         if (tcg_regset_single(set)) {
4609b016486eSRichard Henderson             /* One register in the set.  */
4610b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
4611b3915dbbSRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
4612c896fe29Sbellard             return reg;
4613b016486eSRichard Henderson         } else {
4614b016486eSRichard Henderson             for (i = 0; i < n; i++) {
4615b016486eSRichard Henderson                 TCGReg reg = order[i];
4616b016486eSRichard Henderson                 if (tcg_regset_test_reg(set, reg)) {
4617b016486eSRichard Henderson                     tcg_reg_free(s, reg, allocated_regs);
4618b016486eSRichard Henderson                     return reg;
4619b016486eSRichard Henderson                 }
4620b016486eSRichard Henderson             }
4621c896fe29Sbellard         }
4622c896fe29Sbellard     }
4623c896fe29Sbellard 
4624732e89f4SRichard Henderson     g_assert_not_reached();
4625c896fe29Sbellard }
4626c896fe29Sbellard 
462729f5e925SRichard Henderson static TCGReg tcg_reg_alloc_pair(TCGContext *s, TCGRegSet required_regs,
462829f5e925SRichard Henderson                                  TCGRegSet allocated_regs,
462929f5e925SRichard Henderson                                  TCGRegSet preferred_regs, bool rev)
463029f5e925SRichard Henderson {
463129f5e925SRichard Henderson     int i, j, k, fmin, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
463229f5e925SRichard Henderson     TCGRegSet reg_ct[2];
463329f5e925SRichard Henderson     const int *order;
463429f5e925SRichard Henderson 
463529f5e925SRichard Henderson     /* Ensure that if I is not in allocated_regs, I+1 is not either. */
463629f5e925SRichard Henderson     reg_ct[1] = required_regs & ~(allocated_regs | (allocated_regs >> 1));
463729f5e925SRichard Henderson     tcg_debug_assert(reg_ct[1] != 0);
463829f5e925SRichard Henderson     reg_ct[0] = reg_ct[1] & preferred_regs;
463929f5e925SRichard Henderson 
464029f5e925SRichard Henderson     order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
464129f5e925SRichard Henderson 
464229f5e925SRichard Henderson     /*
464329f5e925SRichard Henderson      * Skip the preferred_regs option if it cannot be satisfied,
464429f5e925SRichard Henderson      * or if the preference made no difference.
464529f5e925SRichard Henderson      */
464629f5e925SRichard Henderson     k = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1];
464729f5e925SRichard Henderson 
464829f5e925SRichard Henderson     /*
464929f5e925SRichard Henderson      * Minimize the number of flushes by looking for 2 free registers first,
465029f5e925SRichard Henderson      * then a single flush, then two flushes.
465129f5e925SRichard Henderson      */
465229f5e925SRichard Henderson     for (fmin = 2; fmin >= 0; fmin--) {
465329f5e925SRichard Henderson         for (j = k; j < 2; j++) {
465429f5e925SRichard Henderson             TCGRegSet set = reg_ct[j];
465529f5e925SRichard Henderson 
465629f5e925SRichard Henderson             for (i = 0; i < n; i++) {
465729f5e925SRichard Henderson                 TCGReg reg = order[i];
465829f5e925SRichard Henderson 
465929f5e925SRichard Henderson                 if (tcg_regset_test_reg(set, reg)) {
466029f5e925SRichard Henderson                     int f = !s->reg_to_temp[reg] + !s->reg_to_temp[reg + 1];
466129f5e925SRichard Henderson                     if (f >= fmin) {
466229f5e925SRichard Henderson                         tcg_reg_free(s, reg, allocated_regs);
466329f5e925SRichard Henderson                         tcg_reg_free(s, reg + 1, allocated_regs);
466429f5e925SRichard Henderson                         return reg;
466529f5e925SRichard Henderson                     }
466629f5e925SRichard Henderson                 }
466729f5e925SRichard Henderson             }
466829f5e925SRichard Henderson         }
466929f5e925SRichard Henderson     }
4670732e89f4SRichard Henderson     g_assert_not_reached();
467129f5e925SRichard Henderson }
467229f5e925SRichard Henderson 
467340ae5c62SRichard Henderson /* Make sure the temporary is in a register.  If needed, allocate the register
467440ae5c62SRichard Henderson    from DESIRED while avoiding ALLOCATED.  */
467540ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs,
4676b722452aSRichard Henderson                       TCGRegSet allocated_regs, TCGRegSet preferred_regs)
467740ae5c62SRichard Henderson {
467840ae5c62SRichard Henderson     TCGReg reg;
467940ae5c62SRichard Henderson 
468040ae5c62SRichard Henderson     switch (ts->val_type) {
468140ae5c62SRichard Henderson     case TEMP_VAL_REG:
468240ae5c62SRichard Henderson         return;
468340ae5c62SRichard Henderson     case TEMP_VAL_CONST:
4684b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
4685b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
46860a6a8bc8SRichard Henderson         if (ts->type <= TCG_TYPE_I64) {
468740ae5c62SRichard Henderson             tcg_out_movi(s, ts->type, reg, ts->val);
46880a6a8bc8SRichard Henderson         } else {
46894e186175SRichard Henderson             uint64_t val = ts->val;
46904e186175SRichard Henderson             MemOp vece = MO_64;
46914e186175SRichard Henderson 
46924e186175SRichard Henderson             /*
46934e186175SRichard Henderson              * Find the minimal vector element that matches the constant.
46944e186175SRichard Henderson              * The targets will, in general, have to do this search anyway,
46954e186175SRichard Henderson              * do this generically.
46964e186175SRichard Henderson              */
46974e186175SRichard Henderson             if (val == dup_const(MO_8, val)) {
46984e186175SRichard Henderson                 vece = MO_8;
46994e186175SRichard Henderson             } else if (val == dup_const(MO_16, val)) {
47004e186175SRichard Henderson                 vece = MO_16;
47010b4286ddSRichard Henderson             } else if (val == dup_const(MO_32, val)) {
47024e186175SRichard Henderson                 vece = MO_32;
47034e186175SRichard Henderson             }
47044e186175SRichard Henderson 
47054e186175SRichard Henderson             tcg_out_dupi_vec(s, ts->type, vece, reg, ts->val);
47060a6a8bc8SRichard Henderson         }
470740ae5c62SRichard Henderson         ts->mem_coherent = 0;
470840ae5c62SRichard Henderson         break;
470940ae5c62SRichard Henderson     case TEMP_VAL_MEM:
4710e139bc4bSPhilippe Mathieu-Daudé         if (!ts->mem_allocated) {
4711e139bc4bSPhilippe Mathieu-Daudé             temp_allocate_frame(s, ts);
4712e139bc4bSPhilippe Mathieu-Daudé         }
4713b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
4714b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
471540ae5c62SRichard Henderson         tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset);
471640ae5c62SRichard Henderson         ts->mem_coherent = 1;
471740ae5c62SRichard Henderson         break;
471840ae5c62SRichard Henderson     case TEMP_VAL_DEAD:
471940ae5c62SRichard Henderson     default:
4720732e89f4SRichard Henderson         g_assert_not_reached();
472140ae5c62SRichard Henderson     }
4722098859f1SRichard Henderson     set_temp_val_reg(s, ts, reg);
472340ae5c62SRichard Henderson }
472440ae5c62SRichard Henderson 
472559d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a
4726e8996ee0Sbellard    temporary registers needs to be allocated to store a constant.  */
472759d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs)
47281ad80729SAurelien Jarno {
47292c0366f0SAurelien Jarno     /* The liveness analysis already ensures that globals are back
4730eabb7b91SAurelien Jarno        in memory. Keep an tcg_debug_assert for safety. */
4731e01fa97dSRichard Henderson     tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || temp_readonly(ts));
47321ad80729SAurelien Jarno }
47331ad80729SAurelien Jarno 
47349814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be
4735641d5fbeSbellard    modified be the following code. 'allocated_regs' is used in case a
4736641d5fbeSbellard    temporary registers needs to be allocated to store a constant. */
4737641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
4738641d5fbeSbellard {
4739ac3b8891SRichard Henderson     int i, n;
4740641d5fbeSbellard 
4741ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
4742b13eb728SRichard Henderson         temp_save(s, &s->temps[i], allocated_regs);
4743641d5fbeSbellard     }
4744e5097dc8Sbellard }
4745e5097dc8Sbellard 
47463d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be
47473d5c5f87SAurelien Jarno    read by the following code. 'allocated_regs' is used in case a
47483d5c5f87SAurelien Jarno    temporary registers needs to be allocated to store a constant. */
47493d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs)
47503d5c5f87SAurelien Jarno {
4751ac3b8891SRichard Henderson     int i, n;
47523d5c5f87SAurelien Jarno 
4753ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
475412b9b11aSRichard Henderson         TCGTemp *ts = &s->temps[i];
475512b9b11aSRichard Henderson         tcg_debug_assert(ts->val_type != TEMP_VAL_REG
4756ee17db83SRichard Henderson                          || ts->kind == TEMP_FIXED
475712b9b11aSRichard Henderson                          || ts->mem_coherent);
47583d5c5f87SAurelien Jarno     }
47593d5c5f87SAurelien Jarno }
47603d5c5f87SAurelien Jarno 
4761e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and
4762e8996ee0Sbellard    all globals are stored at their canonical location. */
4763e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
4764e5097dc8Sbellard {
4765e5097dc8Sbellard     int i;
4766e5097dc8Sbellard 
4767c896fe29Sbellard     for (i = s->nb_globals; i < s->nb_temps; i++) {
4768b13eb728SRichard Henderson         TCGTemp *ts = &s->temps[i];
4769c0522136SRichard Henderson 
4770c0522136SRichard Henderson         switch (ts->kind) {
4771f57c6915SRichard Henderson         case TEMP_TB:
4772b13eb728SRichard Henderson             temp_save(s, ts, allocated_regs);
4773c0522136SRichard Henderson             break;
4774c7482438SRichard Henderson         case TEMP_EBB:
47752c0366f0SAurelien Jarno             /* The liveness analysis already ensures that temps are dead.
4776eabb7b91SAurelien Jarno                Keep an tcg_debug_assert for safety. */
4777eabb7b91SAurelien Jarno             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
4778c0522136SRichard Henderson             break;
4779c0522136SRichard Henderson         case TEMP_CONST:
4780c0522136SRichard Henderson             /* Similarly, we should have freed any allocated register. */
4781c0522136SRichard Henderson             tcg_debug_assert(ts->val_type == TEMP_VAL_CONST);
4782c0522136SRichard Henderson             break;
4783c0522136SRichard Henderson         default:
4784c0522136SRichard Henderson             g_assert_not_reached();
4785c896fe29Sbellard         }
4786641d5fbeSbellard     }
4787e8996ee0Sbellard 
4788e8996ee0Sbellard     save_globals(s, allocated_regs);
4789c896fe29Sbellard }
4790c896fe29Sbellard 
4791bab1671fSRichard Henderson /*
4792c7482438SRichard Henderson  * At a conditional branch, we assume all temporaries are dead unless
4793c7482438SRichard Henderson  * explicitly live-across-conditional-branch; all globals and local
4794c7482438SRichard Henderson  * temps are synced to their location.
4795b4cb76e6SRichard Henderson  */
4796b4cb76e6SRichard Henderson static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs)
4797b4cb76e6SRichard Henderson {
4798b4cb76e6SRichard Henderson     sync_globals(s, allocated_regs);
4799b4cb76e6SRichard Henderson 
4800b4cb76e6SRichard Henderson     for (int i = s->nb_globals; i < s->nb_temps; i++) {
4801b4cb76e6SRichard Henderson         TCGTemp *ts = &s->temps[i];
4802b4cb76e6SRichard Henderson         /*
4803b4cb76e6SRichard Henderson          * The liveness analysis already ensures that temps are dead.
4804b4cb76e6SRichard Henderson          * Keep tcg_debug_asserts for safety.
4805b4cb76e6SRichard Henderson          */
4806c0522136SRichard Henderson         switch (ts->kind) {
4807f57c6915SRichard Henderson         case TEMP_TB:
4808b4cb76e6SRichard Henderson             tcg_debug_assert(ts->val_type != TEMP_VAL_REG || ts->mem_coherent);
4809c0522136SRichard Henderson             break;
4810c7482438SRichard Henderson         case TEMP_EBB:
4811c0522136SRichard Henderson         case TEMP_CONST:
4812c0522136SRichard Henderson             break;
4813c0522136SRichard Henderson         default:
4814c0522136SRichard Henderson             g_assert_not_reached();
4815b4cb76e6SRichard Henderson         }
4816b4cb76e6SRichard Henderson     }
4817b4cb76e6SRichard Henderson }
4818b4cb76e6SRichard Henderson 
4819b4cb76e6SRichard Henderson /*
4820c58f4c97SRichard Henderson  * Specialized code generation for INDEX_op_mov_* with a constant.
4821bab1671fSRichard Henderson  */
48220fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots,
4823ba87719cSRichard Henderson                                   tcg_target_ulong val, TCGLifeData arg_life,
4824ba87719cSRichard Henderson                                   TCGRegSet preferred_regs)
4825e8996ee0Sbellard {
4826d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
4827e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
482859d7c14eSRichard Henderson 
482959d7c14eSRichard Henderson     /* The movi is not explicitly generated here.  */
4830098859f1SRichard Henderson     set_temp_val_nonreg(s, ots, TEMP_VAL_CONST);
4831e8996ee0Sbellard     ots->val = val;
483259d7c14eSRichard Henderson     ots->mem_coherent = 0;
4833ec7a869dSAurelien Jarno     if (NEED_SYNC_ARG(0)) {
4834ba87719cSRichard Henderson         temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0));
483559d7c14eSRichard Henderson     } else if (IS_DEAD_ARG(0)) {
4836f8bf00f1SRichard Henderson         temp_dead(s, ots);
48374c4e1ab2SAurelien Jarno     }
4838e8996ee0Sbellard }
4839e8996ee0Sbellard 
4840bab1671fSRichard Henderson /*
4841bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_mov_*.
4842bab1671fSRichard Henderson  */
4843dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op)
4844c896fe29Sbellard {
4845dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
484669e3706dSRichard Henderson     TCGRegSet allocated_regs, preferred_regs;
4847c896fe29Sbellard     TCGTemp *ts, *ots;
4848450445d5SRichard Henderson     TCGType otype, itype;
4849098859f1SRichard Henderson     TCGReg oreg, ireg;
4850c896fe29Sbellard 
4851d21369f5SRichard Henderson     allocated_regs = s->reserved_regs;
485231fd884bSRichard Henderson     preferred_regs = output_pref(op, 0);
485343439139SRichard Henderson     ots = arg_temp(op->args[0]);
485443439139SRichard Henderson     ts = arg_temp(op->args[1]);
4855450445d5SRichard Henderson 
4856d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
4857e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
4858d63e3b6eSRichard Henderson 
4859450445d5SRichard Henderson     /* Note that otype != itype for no-op truncation.  */
4860450445d5SRichard Henderson     otype = ots->type;
4861450445d5SRichard Henderson     itype = ts->type;
4862c896fe29Sbellard 
48630fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_CONST) {
48640fe4fca4SPaolo Bonzini         /* propagate constant or generate sti */
48650fe4fca4SPaolo Bonzini         tcg_target_ulong val = ts->val;
48660fe4fca4SPaolo Bonzini         if (IS_DEAD_ARG(1)) {
48670fe4fca4SPaolo Bonzini             temp_dead(s, ts);
48680fe4fca4SPaolo Bonzini         }
486969e3706dSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs);
48700fe4fca4SPaolo Bonzini         return;
48710fe4fca4SPaolo Bonzini     }
48720fe4fca4SPaolo Bonzini 
48730fe4fca4SPaolo Bonzini     /* If the source value is in memory we're going to be forced
48740fe4fca4SPaolo Bonzini        to have it in a register in order to perform the copy.  Copy
48750fe4fca4SPaolo Bonzini        the SOURCE value into its own register first, that way we
48760fe4fca4SPaolo Bonzini        don't have to reload SOURCE the next time it is used. */
48770fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_MEM) {
487869e3706dSRichard Henderson         temp_load(s, ts, tcg_target_available_regs[itype],
487969e3706dSRichard Henderson                   allocated_regs, preferred_regs);
4880c29c1d7eSAurelien Jarno     }
48810fe4fca4SPaolo Bonzini     tcg_debug_assert(ts->val_type == TEMP_VAL_REG);
4882098859f1SRichard Henderson     ireg = ts->reg;
4883098859f1SRichard Henderson 
4884d63e3b6eSRichard Henderson     if (IS_DEAD_ARG(0)) {
4885c29c1d7eSAurelien Jarno         /* mov to a non-saved dead register makes no sense (even with
4886c29c1d7eSAurelien Jarno            liveness analysis disabled). */
4887eabb7b91SAurelien Jarno         tcg_debug_assert(NEED_SYNC_ARG(0));
4888c29c1d7eSAurelien Jarno         if (!ots->mem_allocated) {
48892272e4a7SRichard Henderson             temp_allocate_frame(s, ots);
4890c29c1d7eSAurelien Jarno         }
4891098859f1SRichard Henderson         tcg_out_st(s, otype, ireg, ots->mem_base->reg, ots->mem_offset);
4892c29c1d7eSAurelien Jarno         if (IS_DEAD_ARG(1)) {
4893f8bf00f1SRichard Henderson             temp_dead(s, ts);
4894c29c1d7eSAurelien Jarno         }
4895f8bf00f1SRichard Henderson         temp_dead(s, ots);
4896098859f1SRichard Henderson         return;
4897098859f1SRichard Henderson     }
4898098859f1SRichard Henderson 
4899ee17db83SRichard Henderson     if (IS_DEAD_ARG(1) && ts->kind != TEMP_FIXED) {
4900098859f1SRichard Henderson         /*
4901098859f1SRichard Henderson          * The mov can be suppressed.  Kill input first, so that it
4902098859f1SRichard Henderson          * is unlinked from reg_to_temp, then set the output to the
4903098859f1SRichard Henderson          * reg that we saved from the input.
4904098859f1SRichard Henderson          */
4905f8bf00f1SRichard Henderson         temp_dead(s, ts);
4906098859f1SRichard Henderson         oreg = ireg;
4907c29c1d7eSAurelien Jarno     } else {
4908098859f1SRichard Henderson         if (ots->val_type == TEMP_VAL_REG) {
4909098859f1SRichard Henderson             oreg = ots->reg;
4910098859f1SRichard Henderson         } else {
4911098859f1SRichard Henderson             /* Make sure to not spill the input register during allocation. */
4912098859f1SRichard Henderson             oreg = tcg_reg_alloc(s, tcg_target_available_regs[otype],
4913098859f1SRichard Henderson                                  allocated_regs | ((TCGRegSet)1 << ireg),
4914098859f1SRichard Henderson                                  preferred_regs, ots->indirect_base);
4915c29c1d7eSAurelien Jarno         }
4916098859f1SRichard Henderson         if (!tcg_out_mov(s, otype, oreg, ireg)) {
4917240c08d0SRichard Henderson             /*
4918240c08d0SRichard Henderson              * Cross register class move not supported.
4919240c08d0SRichard Henderson              * Store the source register into the destination slot
4920240c08d0SRichard Henderson              * and leave the destination temp as TEMP_VAL_MEM.
4921240c08d0SRichard Henderson              */
4922e01fa97dSRichard Henderson             assert(!temp_readonly(ots));
4923240c08d0SRichard Henderson             if (!ts->mem_allocated) {
4924240c08d0SRichard Henderson                 temp_allocate_frame(s, ots);
4925240c08d0SRichard Henderson             }
4926098859f1SRichard Henderson             tcg_out_st(s, ts->type, ireg, ots->mem_base->reg, ots->mem_offset);
4927098859f1SRichard Henderson             set_temp_val_nonreg(s, ts, TEMP_VAL_MEM);
4928240c08d0SRichard Henderson             ots->mem_coherent = 1;
4929240c08d0SRichard Henderson             return;
493078113e83SRichard Henderson         }
4931c29c1d7eSAurelien Jarno     }
4932098859f1SRichard Henderson     set_temp_val_reg(s, ots, oreg);
4933c896fe29Sbellard     ots->mem_coherent = 0;
4934098859f1SRichard Henderson 
4935ec7a869dSAurelien Jarno     if (NEED_SYNC_ARG(0)) {
493698b4e186SRichard Henderson         temp_sync(s, ots, allocated_regs, 0, 0);
4937c29c1d7eSAurelien Jarno     }
4938ec7a869dSAurelien Jarno }
4939c896fe29Sbellard 
4940bab1671fSRichard Henderson /*
4941bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_dup_vec.
4942bab1671fSRichard Henderson  */
4943bab1671fSRichard Henderson static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op)
4944bab1671fSRichard Henderson {
4945bab1671fSRichard Henderson     const TCGLifeData arg_life = op->life;
4946bab1671fSRichard Henderson     TCGRegSet dup_out_regs, dup_in_regs;
4947501fb3daSRichard Henderson     const TCGArgConstraint *dup_args_ct;
4948bab1671fSRichard Henderson     TCGTemp *its, *ots;
4949bab1671fSRichard Henderson     TCGType itype, vtype;
4950bab1671fSRichard Henderson     unsigned vece;
495131c96417SRichard Henderson     int lowpart_ofs;
4952bab1671fSRichard Henderson     bool ok;
4953bab1671fSRichard Henderson 
4954bab1671fSRichard Henderson     ots = arg_temp(op->args[0]);
4955bab1671fSRichard Henderson     its = arg_temp(op->args[1]);
4956bab1671fSRichard Henderson 
4957bab1671fSRichard Henderson     /* ENV should not be modified.  */
4958e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
4959bab1671fSRichard Henderson 
4960bab1671fSRichard Henderson     itype = its->type;
4961bab1671fSRichard Henderson     vece = TCGOP_VECE(op);
49624d872218SRichard Henderson     vtype = TCGOP_TYPE(op);
4963bab1671fSRichard Henderson 
4964bab1671fSRichard Henderson     if (its->val_type == TEMP_VAL_CONST) {
4965bab1671fSRichard Henderson         /* Propagate constant via movi -> dupi.  */
4966bab1671fSRichard Henderson         tcg_target_ulong val = its->val;
4967bab1671fSRichard Henderson         if (IS_DEAD_ARG(1)) {
4968bab1671fSRichard Henderson             temp_dead(s, its);
4969bab1671fSRichard Henderson         }
497031fd884bSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, output_pref(op, 0));
4971bab1671fSRichard Henderson         return;
4972bab1671fSRichard Henderson     }
4973bab1671fSRichard Henderson 
4974501fb3daSRichard Henderson     dup_args_ct = opcode_args_ct(op);
4975501fb3daSRichard Henderson     dup_out_regs = dup_args_ct[0].regs;
4976501fb3daSRichard Henderson     dup_in_regs = dup_args_ct[1].regs;
4977bab1671fSRichard Henderson 
4978bab1671fSRichard Henderson     /* Allocate the output register now.  */
4979bab1671fSRichard Henderson     if (ots->val_type != TEMP_VAL_REG) {
4980bab1671fSRichard Henderson         TCGRegSet allocated_regs = s->reserved_regs;
4981098859f1SRichard Henderson         TCGReg oreg;
4982bab1671fSRichard Henderson 
4983bab1671fSRichard Henderson         if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) {
4984bab1671fSRichard Henderson             /* Make sure to not spill the input register. */
4985bab1671fSRichard Henderson             tcg_regset_set_reg(allocated_regs, its->reg);
4986bab1671fSRichard Henderson         }
4987098859f1SRichard Henderson         oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
498831fd884bSRichard Henderson                              output_pref(op, 0), ots->indirect_base);
4989098859f1SRichard Henderson         set_temp_val_reg(s, ots, oreg);
4990bab1671fSRichard Henderson     }
4991bab1671fSRichard Henderson 
4992bab1671fSRichard Henderson     switch (its->val_type) {
4993bab1671fSRichard Henderson     case TEMP_VAL_REG:
4994bab1671fSRichard Henderson         /*
4995bab1671fSRichard Henderson          * The dup constriaints must be broad, covering all possible VECE.
4996bab1671fSRichard Henderson          * However, tcg_op_dup_vec() gets to see the VECE and we allow it
4997bab1671fSRichard Henderson          * to fail, indicating that extra moves are required for that case.
4998bab1671fSRichard Henderson          */
4999bab1671fSRichard Henderson         if (tcg_regset_test_reg(dup_in_regs, its->reg)) {
5000bab1671fSRichard Henderson             if (tcg_out_dup_vec(s, vtype, vece, ots->reg, its->reg)) {
5001bab1671fSRichard Henderson                 goto done;
5002bab1671fSRichard Henderson             }
5003bab1671fSRichard Henderson             /* Try again from memory or a vector input register.  */
5004bab1671fSRichard Henderson         }
5005bab1671fSRichard Henderson         if (!its->mem_coherent) {
5006bab1671fSRichard Henderson             /*
5007bab1671fSRichard Henderson              * The input register is not synced, and so an extra store
5008bab1671fSRichard Henderson              * would be required to use memory.  Attempt an integer-vector
5009bab1671fSRichard Henderson              * register move first.  We do not have a TCGRegSet for this.
5010bab1671fSRichard Henderson              */
5011bab1671fSRichard Henderson             if (tcg_out_mov(s, itype, ots->reg, its->reg)) {
5012bab1671fSRichard Henderson                 break;
5013bab1671fSRichard Henderson             }
5014bab1671fSRichard Henderson             /* Sync the temp back to its slot and load from there.  */
5015bab1671fSRichard Henderson             temp_sync(s, its, s->reserved_regs, 0, 0);
5016bab1671fSRichard Henderson         }
5017bab1671fSRichard Henderson         /* fall through */
5018bab1671fSRichard Henderson 
5019bab1671fSRichard Henderson     case TEMP_VAL_MEM:
502031c96417SRichard Henderson         lowpart_ofs = 0;
502131c96417SRichard Henderson         if (HOST_BIG_ENDIAN) {
502231c96417SRichard Henderson             lowpart_ofs = tcg_type_size(itype) - (1 << vece);
502331c96417SRichard Henderson         }
5024d6ecb4a9SRichard Henderson         if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg,
502531c96417SRichard Henderson                              its->mem_offset + lowpart_ofs)) {
5026d6ecb4a9SRichard Henderson             goto done;
5027d6ecb4a9SRichard Henderson         }
5028098859f1SRichard Henderson         /* Load the input into the destination vector register. */
5029bab1671fSRichard Henderson         tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset);
5030bab1671fSRichard Henderson         break;
5031bab1671fSRichard Henderson 
5032bab1671fSRichard Henderson     default:
5033bab1671fSRichard Henderson         g_assert_not_reached();
5034bab1671fSRichard Henderson     }
5035bab1671fSRichard Henderson 
5036bab1671fSRichard Henderson     /* We now have a vector input register, so dup must succeed. */
5037bab1671fSRichard Henderson     ok = tcg_out_dup_vec(s, vtype, vece, ots->reg, ots->reg);
5038bab1671fSRichard Henderson     tcg_debug_assert(ok);
5039bab1671fSRichard Henderson 
5040bab1671fSRichard Henderson  done:
504136f5539cSRichard Henderson     ots->mem_coherent = 0;
5042bab1671fSRichard Henderson     if (IS_DEAD_ARG(1)) {
5043bab1671fSRichard Henderson         temp_dead(s, its);
5044bab1671fSRichard Henderson     }
5045bab1671fSRichard Henderson     if (NEED_SYNC_ARG(0)) {
5046bab1671fSRichard Henderson         temp_sync(s, ots, s->reserved_regs, 0, 0);
5047bab1671fSRichard Henderson     }
5048bab1671fSRichard Henderson     if (IS_DEAD_ARG(0)) {
5049bab1671fSRichard Henderson         temp_dead(s, ots);
5050bab1671fSRichard Henderson     }
5051bab1671fSRichard Henderson }
5052bab1671fSRichard Henderson 
5053dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op)
5054c896fe29Sbellard {
5055dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
5056dd186292SRichard Henderson     const TCGOpDef * const def = &tcg_op_defs[op->opc];
505782790a87SRichard Henderson     TCGRegSet i_allocated_regs;
505882790a87SRichard Henderson     TCGRegSet o_allocated_regs;
5059b6638662SRichard Henderson     int i, k, nb_iargs, nb_oargs;
5060b6638662SRichard Henderson     TCGReg reg;
5061c896fe29Sbellard     TCGArg arg;
5062501fb3daSRichard Henderson     const TCGArgConstraint *args_ct;
5063c896fe29Sbellard     const TCGArgConstraint *arg_ct;
5064c896fe29Sbellard     TCGTemp *ts;
5065c896fe29Sbellard     TCGArg new_args[TCG_MAX_OP_ARGS];
5066c896fe29Sbellard     int const_args[TCG_MAX_OP_ARGS];
506721e9a8aeSRichard Henderson     TCGCond op_cond;
5068c896fe29Sbellard 
5069c896fe29Sbellard     nb_oargs = def->nb_oargs;
5070c896fe29Sbellard     nb_iargs = def->nb_iargs;
5071c896fe29Sbellard 
5072c896fe29Sbellard     /* copy constants */
5073c896fe29Sbellard     memcpy(new_args + nb_oargs + nb_iargs,
5074dd186292SRichard Henderson            op->args + nb_oargs + nb_iargs,
5075c896fe29Sbellard            sizeof(TCGArg) * def->nb_cargs);
5076c896fe29Sbellard 
5077d21369f5SRichard Henderson     i_allocated_regs = s->reserved_regs;
5078d21369f5SRichard Henderson     o_allocated_regs = s->reserved_regs;
507982790a87SRichard Henderson 
508021e9a8aeSRichard Henderson     switch (op->opc) {
508121e9a8aeSRichard Henderson     case INDEX_op_brcond_i32:
508221e9a8aeSRichard Henderson     case INDEX_op_brcond_i64:
508321e9a8aeSRichard Henderson         op_cond = op->args[2];
508421e9a8aeSRichard Henderson         break;
508521e9a8aeSRichard Henderson     case INDEX_op_setcond_i32:
508621e9a8aeSRichard Henderson     case INDEX_op_setcond_i64:
508721e9a8aeSRichard Henderson     case INDEX_op_negsetcond_i32:
508821e9a8aeSRichard Henderson     case INDEX_op_negsetcond_i64:
508921e9a8aeSRichard Henderson     case INDEX_op_cmp_vec:
509021e9a8aeSRichard Henderson         op_cond = op->args[3];
509121e9a8aeSRichard Henderson         break;
509221e9a8aeSRichard Henderson     case INDEX_op_brcond2_i32:
509321e9a8aeSRichard Henderson         op_cond = op->args[4];
509421e9a8aeSRichard Henderson         break;
509521e9a8aeSRichard Henderson     case INDEX_op_movcond_i32:
509621e9a8aeSRichard Henderson     case INDEX_op_movcond_i64:
509721e9a8aeSRichard Henderson     case INDEX_op_setcond2_i32:
509821e9a8aeSRichard Henderson     case INDEX_op_cmpsel_vec:
509921e9a8aeSRichard Henderson         op_cond = op->args[5];
510021e9a8aeSRichard Henderson         break;
510121e9a8aeSRichard Henderson     default:
510221e9a8aeSRichard Henderson         /* No condition within opcode. */
510321e9a8aeSRichard Henderson         op_cond = TCG_COND_ALWAYS;
510421e9a8aeSRichard Henderson         break;
510521e9a8aeSRichard Henderson     }
510621e9a8aeSRichard Henderson 
5107501fb3daSRichard Henderson     args_ct = opcode_args_ct(op);
5108501fb3daSRichard Henderson 
5109c896fe29Sbellard     /* satisfy input constraints */
5110c896fe29Sbellard     for (k = 0; k < nb_iargs; k++) {
511129f5e925SRichard Henderson         TCGRegSet i_preferred_regs, i_required_regs;
511229f5e925SRichard Henderson         bool allocate_new_reg, copyto_new_reg;
511329f5e925SRichard Henderson         TCGTemp *ts2;
511429f5e925SRichard Henderson         int i1, i2;
5115d62816f2SRichard Henderson 
5116501fb3daSRichard Henderson         i = args_ct[nb_oargs + k].sort_index;
5117dd186292SRichard Henderson         arg = op->args[i];
5118501fb3daSRichard Henderson         arg_ct = &args_ct[i];
511943439139SRichard Henderson         ts = arg_temp(arg);
512040ae5c62SRichard Henderson 
51216b8abd24SRichard Henderson         if (ts->val_type == TEMP_VAL_CONST) {
51226b8abd24SRichard Henderson #ifdef TCG_REG_ZERO
51236b8abd24SRichard Henderson             if (ts->val == 0 && (arg_ct->ct & TCG_CT_REG_ZERO)) {
51246b8abd24SRichard Henderson                 /* Hardware zero register: indicate register via non-const. */
51256b8abd24SRichard Henderson                 const_args[i] = 0;
51266b8abd24SRichard Henderson                 new_args[i] = TCG_REG_ZERO;
51276b8abd24SRichard Henderson                 continue;
51286b8abd24SRichard Henderson             }
51296b8abd24SRichard Henderson #endif
51306b8abd24SRichard Henderson 
51316b8abd24SRichard Henderson             if (tcg_target_const_match(ts->val, arg_ct->ct, ts->type,
513221e9a8aeSRichard Henderson                                        op_cond, TCGOP_VECE(op))) {
5133c896fe29Sbellard                 /* constant is OK for instruction */
5134c896fe29Sbellard                 const_args[i] = 1;
5135c896fe29Sbellard                 new_args[i] = ts->val;
5136d62816f2SRichard Henderson                 continue;
5137c896fe29Sbellard             }
51386b8abd24SRichard Henderson         }
513940ae5c62SRichard Henderson 
51401c1824dcSRichard Henderson         reg = ts->reg;
51411c1824dcSRichard Henderson         i_preferred_regs = 0;
514229f5e925SRichard Henderson         i_required_regs = arg_ct->regs;
51431c1824dcSRichard Henderson         allocate_new_reg = false;
514429f5e925SRichard Henderson         copyto_new_reg = false;
51451c1824dcSRichard Henderson 
514629f5e925SRichard Henderson         switch (arg_ct->pair) {
514729f5e925SRichard Henderson         case 0: /* not paired */
5148bc2b17e6SRichard Henderson             if (arg_ct->ialias) {
514931fd884bSRichard Henderson                 i_preferred_regs = output_pref(op, arg_ct->alias_index);
5150c0522136SRichard Henderson 
5151c0522136SRichard Henderson                 /*
5152c0522136SRichard Henderson                  * If the input is readonly, then it cannot also be an
5153c0522136SRichard Henderson                  * output and aliased to itself.  If the input is not
5154c0522136SRichard Henderson                  * dead after the instruction, we must allocate a new
5155c0522136SRichard Henderson                  * register and move it.
5156c0522136SRichard Henderson                  */
515722d2e535SIlya Leoshkevich                 if (temp_readonly(ts) || !IS_DEAD_ARG(i)
5158501fb3daSRichard Henderson                     || args_ct[arg_ct->alias_index].newreg) {
51591c1824dcSRichard Henderson                     allocate_new_reg = true;
51601c1824dcSRichard Henderson                 } else if (ts->val_type == TEMP_VAL_REG) {
5161c0522136SRichard Henderson                     /*
51621c1824dcSRichard Henderson                      * Check if the current register has already been
51631c1824dcSRichard Henderson                      * allocated for another input.
5164c0522136SRichard Henderson                      */
516529f5e925SRichard Henderson                     allocate_new_reg =
516629f5e925SRichard Henderson                         tcg_regset_test_reg(i_allocated_regs, reg);
51677e1df267SAurelien Jarno                 }
51687e1df267SAurelien Jarno             }
51691c1824dcSRichard Henderson             if (!allocate_new_reg) {
517029f5e925SRichard Henderson                 temp_load(s, ts, i_required_regs, i_allocated_regs,
517129f5e925SRichard Henderson                           i_preferred_regs);
5172c896fe29Sbellard                 reg = ts->reg;
517329f5e925SRichard Henderson                 allocate_new_reg = !tcg_regset_test_reg(i_required_regs, reg);
51741c1824dcSRichard Henderson             }
51751c1824dcSRichard Henderson             if (allocate_new_reg) {
5176c0522136SRichard Henderson                 /*
5177c0522136SRichard Henderson                  * Allocate a new register matching the constraint
5178c0522136SRichard Henderson                  * and move the temporary register into it.
5179c0522136SRichard Henderson                  */
5180d62816f2SRichard Henderson                 temp_load(s, ts, tcg_target_available_regs[ts->type],
5181d62816f2SRichard Henderson                           i_allocated_regs, 0);
518229f5e925SRichard Henderson                 reg = tcg_reg_alloc(s, i_required_regs, i_allocated_regs,
51831c1824dcSRichard Henderson                                     i_preferred_regs, ts->indirect_base);
518429f5e925SRichard Henderson                 copyto_new_reg = true;
518529f5e925SRichard Henderson             }
518629f5e925SRichard Henderson             break;
518729f5e925SRichard Henderson 
518829f5e925SRichard Henderson         case 1:
518929f5e925SRichard Henderson             /* First of an input pair; if i1 == i2, the second is an output. */
519029f5e925SRichard Henderson             i1 = i;
519129f5e925SRichard Henderson             i2 = arg_ct->pair_index;
519229f5e925SRichard Henderson             ts2 = i1 != i2 ? arg_temp(op->args[i2]) : NULL;
519329f5e925SRichard Henderson 
519429f5e925SRichard Henderson             /*
519529f5e925SRichard Henderson              * It is easier to default to allocating a new pair
519629f5e925SRichard Henderson              * and to identify a few cases where it's not required.
519729f5e925SRichard Henderson              */
519829f5e925SRichard Henderson             if (arg_ct->ialias) {
519931fd884bSRichard Henderson                 i_preferred_regs = output_pref(op, arg_ct->alias_index);
520029f5e925SRichard Henderson                 if (IS_DEAD_ARG(i1) &&
520129f5e925SRichard Henderson                     IS_DEAD_ARG(i2) &&
520229f5e925SRichard Henderson                     !temp_readonly(ts) &&
520329f5e925SRichard Henderson                     ts->val_type == TEMP_VAL_REG &&
520429f5e925SRichard Henderson                     ts->reg < TCG_TARGET_NB_REGS - 1 &&
520529f5e925SRichard Henderson                     tcg_regset_test_reg(i_required_regs, reg) &&
520629f5e925SRichard Henderson                     !tcg_regset_test_reg(i_allocated_regs, reg) &&
520729f5e925SRichard Henderson                     !tcg_regset_test_reg(i_allocated_regs, reg + 1) &&
520829f5e925SRichard Henderson                     (ts2
520929f5e925SRichard Henderson                      ? ts2->val_type == TEMP_VAL_REG &&
521029f5e925SRichard Henderson                        ts2->reg == reg + 1 &&
521129f5e925SRichard Henderson                        !temp_readonly(ts2)
521229f5e925SRichard Henderson                      : s->reg_to_temp[reg + 1] == NULL)) {
521329f5e925SRichard Henderson                     break;
521429f5e925SRichard Henderson                 }
521529f5e925SRichard Henderson             } else {
521629f5e925SRichard Henderson                 /* Without aliasing, the pair must also be an input. */
521729f5e925SRichard Henderson                 tcg_debug_assert(ts2);
521829f5e925SRichard Henderson                 if (ts->val_type == TEMP_VAL_REG &&
521929f5e925SRichard Henderson                     ts2->val_type == TEMP_VAL_REG &&
522029f5e925SRichard Henderson                     ts2->reg == reg + 1 &&
522129f5e925SRichard Henderson                     tcg_regset_test_reg(i_required_regs, reg)) {
522229f5e925SRichard Henderson                     break;
522329f5e925SRichard Henderson                 }
522429f5e925SRichard Henderson             }
522529f5e925SRichard Henderson             reg = tcg_reg_alloc_pair(s, i_required_regs, i_allocated_regs,
522629f5e925SRichard Henderson                                      0, ts->indirect_base);
522729f5e925SRichard Henderson             goto do_pair;
522829f5e925SRichard Henderson 
522929f5e925SRichard Henderson         case 2: /* pair second */
523029f5e925SRichard Henderson             reg = new_args[arg_ct->pair_index] + 1;
523129f5e925SRichard Henderson             goto do_pair;
523229f5e925SRichard Henderson 
523329f5e925SRichard Henderson         case 3: /* ialias with second output, no first input */
523429f5e925SRichard Henderson             tcg_debug_assert(arg_ct->ialias);
523531fd884bSRichard Henderson             i_preferred_regs = output_pref(op, arg_ct->alias_index);
523629f5e925SRichard Henderson 
523729f5e925SRichard Henderson             if (IS_DEAD_ARG(i) &&
523829f5e925SRichard Henderson                 !temp_readonly(ts) &&
523929f5e925SRichard Henderson                 ts->val_type == TEMP_VAL_REG &&
524029f5e925SRichard Henderson                 reg > 0 &&
524129f5e925SRichard Henderson                 s->reg_to_temp[reg - 1] == NULL &&
524229f5e925SRichard Henderson                 tcg_regset_test_reg(i_required_regs, reg) &&
524329f5e925SRichard Henderson                 !tcg_regset_test_reg(i_allocated_regs, reg) &&
524429f5e925SRichard Henderson                 !tcg_regset_test_reg(i_allocated_regs, reg - 1)) {
524529f5e925SRichard Henderson                 tcg_regset_set_reg(i_allocated_regs, reg - 1);
524629f5e925SRichard Henderson                 break;
524729f5e925SRichard Henderson             }
524829f5e925SRichard Henderson             reg = tcg_reg_alloc_pair(s, i_required_regs >> 1,
524929f5e925SRichard Henderson                                      i_allocated_regs, 0,
525029f5e925SRichard Henderson                                      ts->indirect_base);
525129f5e925SRichard Henderson             tcg_regset_set_reg(i_allocated_regs, reg);
525229f5e925SRichard Henderson             reg += 1;
525329f5e925SRichard Henderson             goto do_pair;
525429f5e925SRichard Henderson 
525529f5e925SRichard Henderson         do_pair:
525629f5e925SRichard Henderson             /*
525729f5e925SRichard Henderson              * If an aliased input is not dead after the instruction,
525829f5e925SRichard Henderson              * we must allocate a new register and move it.
525929f5e925SRichard Henderson              */
526029f5e925SRichard Henderson             if (arg_ct->ialias && (!IS_DEAD_ARG(i) || temp_readonly(ts))) {
526129f5e925SRichard Henderson                 TCGRegSet t_allocated_regs = i_allocated_regs;
526229f5e925SRichard Henderson 
526329f5e925SRichard Henderson                 /*
526429f5e925SRichard Henderson                  * Because of the alias, and the continued life, make sure
526529f5e925SRichard Henderson                  * that the temp is somewhere *other* than the reg pair,
526629f5e925SRichard Henderson                  * and we get a copy in reg.
526729f5e925SRichard Henderson                  */
526829f5e925SRichard Henderson                 tcg_regset_set_reg(t_allocated_regs, reg);
526929f5e925SRichard Henderson                 tcg_regset_set_reg(t_allocated_regs, reg + 1);
527029f5e925SRichard Henderson                 if (ts->val_type == TEMP_VAL_REG && ts->reg == reg) {
527129f5e925SRichard Henderson                     /* If ts was already in reg, copy it somewhere else. */
527229f5e925SRichard Henderson                     TCGReg nr;
527329f5e925SRichard Henderson                     bool ok;
527429f5e925SRichard Henderson 
527529f5e925SRichard Henderson                     tcg_debug_assert(ts->kind != TEMP_FIXED);
527629f5e925SRichard Henderson                     nr = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
527729f5e925SRichard Henderson                                        t_allocated_regs, 0, ts->indirect_base);
527829f5e925SRichard Henderson                     ok = tcg_out_mov(s, ts->type, nr, reg);
527929f5e925SRichard Henderson                     tcg_debug_assert(ok);
528029f5e925SRichard Henderson 
528129f5e925SRichard Henderson                     set_temp_val_reg(s, ts, nr);
528229f5e925SRichard Henderson                 } else {
528329f5e925SRichard Henderson                     temp_load(s, ts, tcg_target_available_regs[ts->type],
528429f5e925SRichard Henderson                               t_allocated_regs, 0);
528529f5e925SRichard Henderson                     copyto_new_reg = true;
528629f5e925SRichard Henderson                 }
528729f5e925SRichard Henderson             } else {
528829f5e925SRichard Henderson                 /* Preferably allocate to reg, otherwise copy. */
528929f5e925SRichard Henderson                 i_required_regs = (TCGRegSet)1 << reg;
529029f5e925SRichard Henderson                 temp_load(s, ts, i_required_regs, i_allocated_regs,
529129f5e925SRichard Henderson                           i_preferred_regs);
529229f5e925SRichard Henderson                 copyto_new_reg = ts->reg != reg;
529329f5e925SRichard Henderson             }
529429f5e925SRichard Henderson             break;
529529f5e925SRichard Henderson 
529629f5e925SRichard Henderson         default:
529729f5e925SRichard Henderson             g_assert_not_reached();
529829f5e925SRichard Henderson         }
529929f5e925SRichard Henderson 
530029f5e925SRichard Henderson         if (copyto_new_reg) {
530178113e83SRichard Henderson             if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
5302240c08d0SRichard Henderson                 /*
5303240c08d0SRichard Henderson                  * Cross register class move not supported.  Sync the
5304240c08d0SRichard Henderson                  * temp back to its slot and load from there.
5305240c08d0SRichard Henderson                  */
5306240c08d0SRichard Henderson                 temp_sync(s, ts, i_allocated_regs, 0, 0);
5307240c08d0SRichard Henderson                 tcg_out_ld(s, ts->type, reg,
5308240c08d0SRichard Henderson                            ts->mem_base->reg, ts->mem_offset);
530978113e83SRichard Henderson             }
5310c896fe29Sbellard         }
5311c896fe29Sbellard         new_args[i] = reg;
5312c896fe29Sbellard         const_args[i] = 0;
531382790a87SRichard Henderson         tcg_regset_set_reg(i_allocated_regs, reg);
5314c896fe29Sbellard     }
5315c896fe29Sbellard 
5316c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
5317866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
5318866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
531943439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
5320c896fe29Sbellard         }
5321c896fe29Sbellard     }
5322c896fe29Sbellard 
5323b4cb76e6SRichard Henderson     if (def->flags & TCG_OPF_COND_BRANCH) {
5324b4cb76e6SRichard Henderson         tcg_reg_alloc_cbranch(s, i_allocated_regs);
5325b4cb76e6SRichard Henderson     } else if (def->flags & TCG_OPF_BB_END) {
532682790a87SRichard Henderson         tcg_reg_alloc_bb_end(s, i_allocated_regs);
5327a52ad07eSAurelien Jarno     } else {
5328c896fe29Sbellard         if (def->flags & TCG_OPF_CALL_CLOBBER) {
5329b03cce8eSbellard             /* XXX: permit generic clobber register list ? */
5330c8074023SRichard Henderson             for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
5331c8074023SRichard Henderson                 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
533282790a87SRichard Henderson                     tcg_reg_free(s, i, i_allocated_regs);
5333c896fe29Sbellard                 }
5334c896fe29Sbellard             }
53353d5c5f87SAurelien Jarno         }
53363d5c5f87SAurelien Jarno         if (def->flags & TCG_OPF_SIDE_EFFECTS) {
53373d5c5f87SAurelien Jarno             /* sync globals if the op has side effects and might trigger
53383d5c5f87SAurelien Jarno                an exception. */
533982790a87SRichard Henderson             sync_globals(s, i_allocated_regs);
5340c896fe29Sbellard         }
5341c896fe29Sbellard 
5342c896fe29Sbellard         /* satisfy the output constraints */
5343c896fe29Sbellard         for (k = 0; k < nb_oargs; k++) {
5344501fb3daSRichard Henderson             i = args_ct[k].sort_index;
5345dd186292SRichard Henderson             arg = op->args[i];
5346501fb3daSRichard Henderson             arg_ct = &args_ct[i];
534743439139SRichard Henderson             ts = arg_temp(arg);
5348d63e3b6eSRichard Henderson 
5349d63e3b6eSRichard Henderson             /* ENV should not be modified.  */
5350e01fa97dSRichard Henderson             tcg_debug_assert(!temp_readonly(ts));
5351d63e3b6eSRichard Henderson 
535229f5e925SRichard Henderson             switch (arg_ct->pair) {
535329f5e925SRichard Henderson             case 0: /* not paired */
5354bc2b17e6SRichard Henderson                 if (arg_ct->oalias && !const_args[arg_ct->alias_index]) {
53555ff9d6a4Sbellard                     reg = new_args[arg_ct->alias_index];
5356bc2b17e6SRichard Henderson                 } else if (arg_ct->newreg) {
53579be0d080SRichard Henderson                     reg = tcg_reg_alloc(s, arg_ct->regs,
535882790a87SRichard Henderson                                         i_allocated_regs | o_allocated_regs,
535931fd884bSRichard Henderson                                         output_pref(op, k), ts->indirect_base);
5360c896fe29Sbellard                 } else {
53619be0d080SRichard Henderson                     reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs,
536231fd884bSRichard Henderson                                         output_pref(op, k), ts->indirect_base);
5363c896fe29Sbellard                 }
536429f5e925SRichard Henderson                 break;
536529f5e925SRichard Henderson 
536629f5e925SRichard Henderson             case 1: /* first of pair */
536729f5e925SRichard Henderson                 if (arg_ct->oalias) {
536829f5e925SRichard Henderson                     reg = new_args[arg_ct->alias_index];
5369ca5bed07SRichard Henderson                 } else if (arg_ct->newreg) {
5370ca5bed07SRichard Henderson                     reg = tcg_reg_alloc_pair(s, arg_ct->regs,
5371ca5bed07SRichard Henderson                                              i_allocated_regs | o_allocated_regs,
5372ca5bed07SRichard Henderson                                              output_pref(op, k),
5373ca5bed07SRichard Henderson                                              ts->indirect_base);
5374ca5bed07SRichard Henderson                 } else {
537529f5e925SRichard Henderson                     reg = tcg_reg_alloc_pair(s, arg_ct->regs, o_allocated_regs,
5376ca5bed07SRichard Henderson                                              output_pref(op, k),
5377ca5bed07SRichard Henderson                                              ts->indirect_base);
5378ca5bed07SRichard Henderson                 }
537929f5e925SRichard Henderson                 break;
538029f5e925SRichard Henderson 
538129f5e925SRichard Henderson             case 2: /* second of pair */
538229f5e925SRichard Henderson                 if (arg_ct->oalias) {
538329f5e925SRichard Henderson                     reg = new_args[arg_ct->alias_index];
538429f5e925SRichard Henderson                 } else {
538529f5e925SRichard Henderson                     reg = new_args[arg_ct->pair_index] + 1;
538629f5e925SRichard Henderson                 }
538729f5e925SRichard Henderson                 break;
538829f5e925SRichard Henderson 
538929f5e925SRichard Henderson             case 3: /* first of pair, aliasing with a second input */
539029f5e925SRichard Henderson                 tcg_debug_assert(!arg_ct->newreg);
539129f5e925SRichard Henderson                 reg = new_args[arg_ct->pair_index] - 1;
539229f5e925SRichard Henderson                 break;
539329f5e925SRichard Henderson 
539429f5e925SRichard Henderson             default:
539529f5e925SRichard Henderson                 g_assert_not_reached();
539629f5e925SRichard Henderson             }
539782790a87SRichard Henderson             tcg_regset_set_reg(o_allocated_regs, reg);
5398098859f1SRichard Henderson             set_temp_val_reg(s, ts, reg);
5399c896fe29Sbellard             ts->mem_coherent = 0;
5400c896fe29Sbellard             new_args[i] = reg;
5401c896fe29Sbellard         }
5402e8996ee0Sbellard     }
5403c896fe29Sbellard 
5404c896fe29Sbellard     /* emit instruction */
5405662cdbcfSRichard Henderson     TCGType type = TCGOP_TYPE(op);
5406678155b2SRichard Henderson     switch (op->opc) {
54079c6aa274SRichard Henderson     case INDEX_op_ext_i32_i64:
54089c6aa274SRichard Henderson         tcg_out_exts_i32_i64(s, new_args[0], new_args[1]);
54099c6aa274SRichard Henderson         break;
5410b9bfe000SRichard Henderson     case INDEX_op_extu_i32_i64:
5411b9bfe000SRichard Henderson         tcg_out_extu_i32_i64(s, new_args[0], new_args[1]);
5412b9bfe000SRichard Henderson         break;
5413b8b94ac6SRichard Henderson     case INDEX_op_extrl_i64_i32:
5414b8b94ac6SRichard Henderson         tcg_out_extrl_i64_i32(s, new_args[0], new_args[1]);
5415b8b94ac6SRichard Henderson         break;
5416662cdbcfSRichard Henderson 
541779602f63SRichard Henderson     case INDEX_op_add:
5418c3b920b3SRichard Henderson     case INDEX_op_and:
541946f96bffSRichard Henderson     case INDEX_op_andc:
54205c0968a7SRichard Henderson     case INDEX_op_eqv:
5421d2c3ecadSRichard Henderson     case INDEX_op_mul:
5422*c742824dSRichard Henderson     case INDEX_op_mulsh:
5423aa28c9efSRichard Henderson     case INDEX_op_muluh:
542459379a45SRichard Henderson     case INDEX_op_nand:
54253a8c4e9eSRichard Henderson     case INDEX_op_nor:
542649bd7514SRichard Henderson     case INDEX_op_or:
54276aba25ebSRichard Henderson     case INDEX_op_orc:
5428fffd3dc9SRichard Henderson     case INDEX_op_xor:
5429662cdbcfSRichard Henderson         {
5430662cdbcfSRichard Henderson             const TCGOutOpBinary *out =
5431662cdbcfSRichard Henderson                 container_of(all_outop[op->opc], TCGOutOpBinary, base);
5432662cdbcfSRichard Henderson 
5433662cdbcfSRichard Henderson             /* Constants should never appear in the first source operand. */
5434662cdbcfSRichard Henderson             tcg_debug_assert(!const_args[1]);
5435662cdbcfSRichard Henderson             if (const_args[2]) {
5436662cdbcfSRichard Henderson                 out->out_rri(s, type, new_args[0], new_args[1], new_args[2]);
5437662cdbcfSRichard Henderson             } else {
5438662cdbcfSRichard Henderson                 out->out_rrr(s, type, new_args[0], new_args[1], new_args[2]);
5439662cdbcfSRichard Henderson             }
5440662cdbcfSRichard Henderson         }
5441662cdbcfSRichard Henderson         break;
5442662cdbcfSRichard Henderson 
544360f34f55SRichard Henderson     case INDEX_op_sub:
54443f057e24SRichard Henderson         {
54453f057e24SRichard Henderson             const TCGOutOpSubtract *out = &outop_sub;
54463f057e24SRichard Henderson 
54473f057e24SRichard Henderson             /*
54483f057e24SRichard Henderson              * Constants should never appear in the second source operand.
54493f057e24SRichard Henderson              * These are folded to add with negative constant.
54503f057e24SRichard Henderson              */
54513f057e24SRichard Henderson             tcg_debug_assert(!const_args[2]);
54523f057e24SRichard Henderson             if (const_args[1]) {
54533f057e24SRichard Henderson                 out->out_rir(s, type, new_args[0], new_args[1], new_args[2]);
54543f057e24SRichard Henderson             } else {
54553f057e24SRichard Henderson                 out->out_rrr(s, type, new_args[0], new_args[1], new_args[2]);
54563f057e24SRichard Henderson             }
54573f057e24SRichard Henderson         }
54583f057e24SRichard Henderson         break;
54593f057e24SRichard Henderson 
546069713587SRichard Henderson     case INDEX_op_neg:
54615c62d377SRichard Henderson     case INDEX_op_not:
5462e126a91cSRichard Henderson         {
5463e126a91cSRichard Henderson             const TCGOutOpUnary *out =
5464e126a91cSRichard Henderson                 container_of(all_outop[op->opc], TCGOutOpUnary, base);
5465e126a91cSRichard Henderson 
5466e126a91cSRichard Henderson             /* Constants should have been folded. */
5467e126a91cSRichard Henderson             tcg_debug_assert(!const_args[1]);
5468e126a91cSRichard Henderson             out->out_rr(s, type, new_args[0], new_args[1]);
5469e126a91cSRichard Henderson         }
5470e126a91cSRichard Henderson         break;
5471e126a91cSRichard Henderson 
5472678155b2SRichard Henderson     default:
5473d2fd745fSRichard Henderson         if (def->flags & TCG_OPF_VECTOR) {
5474662cdbcfSRichard Henderson             tcg_out_vec_op(s, op->opc, type - TCG_TYPE_V64,
54754d872218SRichard Henderson                            TCGOP_VECE(op), new_args, const_args);
5476d2fd745fSRichard Henderson         } else {
5477662cdbcfSRichard Henderson             tcg_out_op(s, op->opc, type, new_args, const_args);
5478d2fd745fSRichard Henderson         }
5479678155b2SRichard Henderson         break;
5480678155b2SRichard Henderson     }
5481c896fe29Sbellard 
5482c896fe29Sbellard     /* move the outputs in the correct register if needed */
5483c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
548443439139SRichard Henderson         ts = arg_temp(op->args[i]);
5485d63e3b6eSRichard Henderson 
5486d63e3b6eSRichard Henderson         /* ENV should not be modified.  */
5487e01fa97dSRichard Henderson         tcg_debug_assert(!temp_readonly(ts));
5488d63e3b6eSRichard Henderson 
5489ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
549098b4e186SRichard Henderson             temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i));
549159d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
5492f8bf00f1SRichard Henderson             temp_dead(s, ts);
5493ec7a869dSAurelien Jarno         }
5494c896fe29Sbellard     }
5495c896fe29Sbellard }
5496c896fe29Sbellard 
5497efe86b21SRichard Henderson static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op)
5498efe86b21SRichard Henderson {
5499efe86b21SRichard Henderson     const TCGLifeData arg_life = op->life;
5500efe86b21SRichard Henderson     TCGTemp *ots, *itsl, *itsh;
55014d872218SRichard Henderson     TCGType vtype = TCGOP_TYPE(op);
5502efe86b21SRichard Henderson 
5503efe86b21SRichard Henderson     /* This opcode is only valid for 32-bit hosts, for 64-bit elements. */
5504efe86b21SRichard Henderson     tcg_debug_assert(TCG_TARGET_REG_BITS == 32);
5505efe86b21SRichard Henderson     tcg_debug_assert(TCGOP_VECE(op) == MO_64);
5506efe86b21SRichard Henderson 
5507efe86b21SRichard Henderson     ots = arg_temp(op->args[0]);
5508efe86b21SRichard Henderson     itsl = arg_temp(op->args[1]);
5509efe86b21SRichard Henderson     itsh = arg_temp(op->args[2]);
5510efe86b21SRichard Henderson 
5511efe86b21SRichard Henderson     /* ENV should not be modified.  */
5512efe86b21SRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
5513efe86b21SRichard Henderson 
5514efe86b21SRichard Henderson     /* Allocate the output register now.  */
5515efe86b21SRichard Henderson     if (ots->val_type != TEMP_VAL_REG) {
5516efe86b21SRichard Henderson         TCGRegSet allocated_regs = s->reserved_regs;
5517501fb3daSRichard Henderson         TCGRegSet dup_out_regs = opcode_args_ct(op)[0].regs;
5518098859f1SRichard Henderson         TCGReg oreg;
5519efe86b21SRichard Henderson 
5520efe86b21SRichard Henderson         /* Make sure to not spill the input registers. */
5521efe86b21SRichard Henderson         if (!IS_DEAD_ARG(1) && itsl->val_type == TEMP_VAL_REG) {
5522efe86b21SRichard Henderson             tcg_regset_set_reg(allocated_regs, itsl->reg);
5523efe86b21SRichard Henderson         }
5524efe86b21SRichard Henderson         if (!IS_DEAD_ARG(2) && itsh->val_type == TEMP_VAL_REG) {
5525efe86b21SRichard Henderson             tcg_regset_set_reg(allocated_regs, itsh->reg);
5526efe86b21SRichard Henderson         }
5527efe86b21SRichard Henderson 
5528098859f1SRichard Henderson         oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
552931fd884bSRichard Henderson                              output_pref(op, 0), ots->indirect_base);
5530098859f1SRichard Henderson         set_temp_val_reg(s, ots, oreg);
5531efe86b21SRichard Henderson     }
5532efe86b21SRichard Henderson 
5533efe86b21SRichard Henderson     /* Promote dup2 of immediates to dupi_vec. */
5534efe86b21SRichard Henderson     if (itsl->val_type == TEMP_VAL_CONST && itsh->val_type == TEMP_VAL_CONST) {
5535efe86b21SRichard Henderson         uint64_t val = deposit64(itsl->val, 32, 32, itsh->val);
5536efe86b21SRichard Henderson         MemOp vece = MO_64;
5537efe86b21SRichard Henderson 
5538efe86b21SRichard Henderson         if (val == dup_const(MO_8, val)) {
5539efe86b21SRichard Henderson             vece = MO_8;
5540efe86b21SRichard Henderson         } else if (val == dup_const(MO_16, val)) {
5541efe86b21SRichard Henderson             vece = MO_16;
5542efe86b21SRichard Henderson         } else if (val == dup_const(MO_32, val)) {
5543efe86b21SRichard Henderson             vece = MO_32;
5544efe86b21SRichard Henderson         }
5545efe86b21SRichard Henderson 
5546efe86b21SRichard Henderson         tcg_out_dupi_vec(s, vtype, vece, ots->reg, val);
5547efe86b21SRichard Henderson         goto done;
5548efe86b21SRichard Henderson     }
5549efe86b21SRichard Henderson 
5550efe86b21SRichard Henderson     /* If the two inputs form one 64-bit value, try dupm_vec. */
5551aef85402SRichard Henderson     if (itsl->temp_subindex == HOST_BIG_ENDIAN &&
5552aef85402SRichard Henderson         itsh->temp_subindex == !HOST_BIG_ENDIAN &&
5553aef85402SRichard Henderson         itsl == itsh + (HOST_BIG_ENDIAN ? 1 : -1)) {
5554aef85402SRichard Henderson         TCGTemp *its = itsl - HOST_BIG_ENDIAN;
5555aef85402SRichard Henderson 
5556aef85402SRichard Henderson         temp_sync(s, its + 0, s->reserved_regs, 0, 0);
5557aef85402SRichard Henderson         temp_sync(s, its + 1, s->reserved_regs, 0, 0);
5558aef85402SRichard Henderson 
5559efe86b21SRichard Henderson         if (tcg_out_dupm_vec(s, vtype, MO_64, ots->reg,
5560efe86b21SRichard Henderson                              its->mem_base->reg, its->mem_offset)) {
5561efe86b21SRichard Henderson             goto done;
5562efe86b21SRichard Henderson         }
5563efe86b21SRichard Henderson     }
5564efe86b21SRichard Henderson 
5565efe86b21SRichard Henderson     /* Fall back to generic expansion. */
5566efe86b21SRichard Henderson     return false;
5567efe86b21SRichard Henderson 
5568efe86b21SRichard Henderson  done:
556936f5539cSRichard Henderson     ots->mem_coherent = 0;
5570efe86b21SRichard Henderson     if (IS_DEAD_ARG(1)) {
5571efe86b21SRichard Henderson         temp_dead(s, itsl);
5572efe86b21SRichard Henderson     }
5573efe86b21SRichard Henderson     if (IS_DEAD_ARG(2)) {
5574efe86b21SRichard Henderson         temp_dead(s, itsh);
5575efe86b21SRichard Henderson     }
5576efe86b21SRichard Henderson     if (NEED_SYNC_ARG(0)) {
5577efe86b21SRichard Henderson         temp_sync(s, ots, s->reserved_regs, 0, IS_DEAD_ARG(0));
5578efe86b21SRichard Henderson     } else if (IS_DEAD_ARG(0)) {
5579efe86b21SRichard Henderson         temp_dead(s, ots);
5580efe86b21SRichard Henderson     }
5581efe86b21SRichard Henderson     return true;
5582efe86b21SRichard Henderson }
5583efe86b21SRichard Henderson 
558439004a71SRichard Henderson static void load_arg_reg(TCGContext *s, TCGReg reg, TCGTemp *ts,
558539004a71SRichard Henderson                          TCGRegSet allocated_regs)
5586c896fe29Sbellard {
5587c896fe29Sbellard     if (ts->val_type == TEMP_VAL_REG) {
5588c896fe29Sbellard         if (ts->reg != reg) {
55894250da10SRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
559078113e83SRichard Henderson             if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
5591240c08d0SRichard Henderson                 /*
5592240c08d0SRichard Henderson                  * Cross register class move not supported.  Sync the
5593240c08d0SRichard Henderson                  * temp back to its slot and load from there.
5594240c08d0SRichard Henderson                  */
5595240c08d0SRichard Henderson                 temp_sync(s, ts, allocated_regs, 0, 0);
5596240c08d0SRichard Henderson                 tcg_out_ld(s, ts->type, reg,
5597240c08d0SRichard Henderson                            ts->mem_base->reg, ts->mem_offset);
559878113e83SRichard Henderson             }
5599c896fe29Sbellard         }
5600c896fe29Sbellard     } else {
5601ccb1bb66SRichard Henderson         TCGRegSet arg_set = 0;
560240ae5c62SRichard Henderson 
56034250da10SRichard Henderson         tcg_reg_free(s, reg, allocated_regs);
560440ae5c62SRichard Henderson         tcg_regset_set_reg(arg_set, reg);
5605b722452aSRichard Henderson         temp_load(s, ts, arg_set, allocated_regs, 0);
5606c896fe29Sbellard     }
560739004a71SRichard Henderson }
560840ae5c62SRichard Henderson 
5609d78e4a4fSRichard Henderson static void load_arg_stk(TCGContext *s, unsigned arg_slot, TCGTemp *ts,
561039004a71SRichard Henderson                          TCGRegSet allocated_regs)
561139004a71SRichard Henderson {
561239004a71SRichard Henderson     /*
561339004a71SRichard Henderson      * When the destination is on the stack, load up the temp and store.
561439004a71SRichard Henderson      * If there are many call-saved registers, the temp might live to
561539004a71SRichard Henderson      * see another use; otherwise it'll be discarded.
561639004a71SRichard Henderson      */
561739004a71SRichard Henderson     temp_load(s, ts, tcg_target_available_regs[ts->type], allocated_regs, 0);
561839004a71SRichard Henderson     tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK,
5619d78e4a4fSRichard Henderson                arg_slot_stk_ofs(arg_slot));
562039004a71SRichard Henderson }
562139004a71SRichard Henderson 
562239004a71SRichard Henderson static void load_arg_normal(TCGContext *s, const TCGCallArgumentLoc *l,
562339004a71SRichard Henderson                             TCGTemp *ts, TCGRegSet *allocated_regs)
562439004a71SRichard Henderson {
5625338b61e9SRichard Henderson     if (arg_slot_reg_p(l->arg_slot)) {
562639004a71SRichard Henderson         TCGReg reg = tcg_target_call_iarg_regs[l->arg_slot];
562739004a71SRichard Henderson         load_arg_reg(s, reg, ts, *allocated_regs);
562839004a71SRichard Henderson         tcg_regset_set_reg(*allocated_regs, reg);
562939004a71SRichard Henderson     } else {
5630d78e4a4fSRichard Henderson         load_arg_stk(s, l->arg_slot, ts, *allocated_regs);
5631c896fe29Sbellard     }
563239cf05d3Sbellard }
5633c896fe29Sbellard 
5634d78e4a4fSRichard Henderson static void load_arg_ref(TCGContext *s, unsigned arg_slot, TCGReg ref_base,
5635313bdea8SRichard Henderson                          intptr_t ref_off, TCGRegSet *allocated_regs)
5636313bdea8SRichard Henderson {
5637313bdea8SRichard Henderson     TCGReg reg;
5638313bdea8SRichard Henderson 
5639d78e4a4fSRichard Henderson     if (arg_slot_reg_p(arg_slot)) {
5640313bdea8SRichard Henderson         reg = tcg_target_call_iarg_regs[arg_slot];
5641313bdea8SRichard Henderson         tcg_reg_free(s, reg, *allocated_regs);
5642313bdea8SRichard Henderson         tcg_out_addi_ptr(s, reg, ref_base, ref_off);
5643313bdea8SRichard Henderson         tcg_regset_set_reg(*allocated_regs, reg);
5644313bdea8SRichard Henderson     } else {
5645313bdea8SRichard Henderson         reg = tcg_reg_alloc(s, tcg_target_available_regs[TCG_TYPE_PTR],
5646313bdea8SRichard Henderson                             *allocated_regs, 0, false);
5647313bdea8SRichard Henderson         tcg_out_addi_ptr(s, reg, ref_base, ref_off);
5648313bdea8SRichard Henderson         tcg_out_st(s, TCG_TYPE_PTR, reg, TCG_REG_CALL_STACK,
5649d78e4a4fSRichard Henderson                    arg_slot_stk_ofs(arg_slot));
5650313bdea8SRichard Henderson     }
5651313bdea8SRichard Henderson }
5652313bdea8SRichard Henderson 
565339004a71SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op)
565439004a71SRichard Henderson {
565539004a71SRichard Henderson     const int nb_oargs = TCGOP_CALLO(op);
565639004a71SRichard Henderson     const int nb_iargs = TCGOP_CALLI(op);
565739004a71SRichard Henderson     const TCGLifeData arg_life = op->life;
565839004a71SRichard Henderson     const TCGHelperInfo *info = tcg_call_info(op);
565939004a71SRichard Henderson     TCGRegSet allocated_regs = s->reserved_regs;
566039004a71SRichard Henderson     int i;
566139004a71SRichard Henderson 
566239004a71SRichard Henderson     /*
566339004a71SRichard Henderson      * Move inputs into place in reverse order,
566439004a71SRichard Henderson      * so that we place stacked arguments first.
566539004a71SRichard Henderson      */
566639004a71SRichard Henderson     for (i = nb_iargs - 1; i >= 0; --i) {
566739004a71SRichard Henderson         const TCGCallArgumentLoc *loc = &info->in[i];
566839004a71SRichard Henderson         TCGTemp *ts = arg_temp(op->args[nb_oargs + i]);
566939004a71SRichard Henderson 
567039004a71SRichard Henderson         switch (loc->kind) {
567139004a71SRichard Henderson         case TCG_CALL_ARG_NORMAL:
567239004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_U:
567339004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_S:
567439004a71SRichard Henderson             load_arg_normal(s, loc, ts, &allocated_regs);
567539004a71SRichard Henderson             break;
5676313bdea8SRichard Henderson         case TCG_CALL_ARG_BY_REF:
5677313bdea8SRichard Henderson             load_arg_stk(s, loc->ref_slot, ts, allocated_regs);
5678313bdea8SRichard Henderson             load_arg_ref(s, loc->arg_slot, TCG_REG_CALL_STACK,
5679d78e4a4fSRichard Henderson                          arg_slot_stk_ofs(loc->ref_slot),
5680313bdea8SRichard Henderson                          &allocated_regs);
5681313bdea8SRichard Henderson             break;
5682313bdea8SRichard Henderson         case TCG_CALL_ARG_BY_REF_N:
5683313bdea8SRichard Henderson             load_arg_stk(s, loc->ref_slot, ts, allocated_regs);
5684313bdea8SRichard Henderson             break;
568539004a71SRichard Henderson         default:
568639004a71SRichard Henderson             g_assert_not_reached();
568739004a71SRichard Henderson         }
568839004a71SRichard Henderson     }
568939004a71SRichard Henderson 
569039004a71SRichard Henderson     /* Mark dead temporaries and free the associated registers.  */
5691866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
5692866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
569343439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
5694c896fe29Sbellard         }
5695c896fe29Sbellard     }
5696c896fe29Sbellard 
569739004a71SRichard Henderson     /* Clobber call registers.  */
5698c8074023SRichard Henderson     for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
5699c8074023SRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
5700b3915dbbSRichard Henderson             tcg_reg_free(s, i, allocated_regs);
5701c896fe29Sbellard         }
5702c896fe29Sbellard     }
5703c896fe29Sbellard 
570439004a71SRichard Henderson     /*
570539004a71SRichard Henderson      * Save globals if they might be written by the helper,
570639004a71SRichard Henderson      * sync them if they might be read.
570739004a71SRichard Henderson      */
570839004a71SRichard Henderson     if (info->flags & TCG_CALL_NO_READ_GLOBALS) {
570978505279SAurelien Jarno         /* Nothing to do */
571039004a71SRichard Henderson     } else if (info->flags & TCG_CALL_NO_WRITE_GLOBALS) {
571178505279SAurelien Jarno         sync_globals(s, allocated_regs);
571278505279SAurelien Jarno     } else {
5713e8996ee0Sbellard         save_globals(s, allocated_regs);
5714b9c18f56Saurel32     }
5715c896fe29Sbellard 
5716313bdea8SRichard Henderson     /*
5717313bdea8SRichard Henderson      * If the ABI passes a pointer to the returned struct as the first
5718313bdea8SRichard Henderson      * argument, load that now.  Pass a pointer to the output home slot.
5719313bdea8SRichard Henderson      */
5720313bdea8SRichard Henderson     if (info->out_kind == TCG_CALL_RET_BY_REF) {
5721313bdea8SRichard Henderson         TCGTemp *ts = arg_temp(op->args[0]);
5722313bdea8SRichard Henderson 
5723313bdea8SRichard Henderson         if (!ts->mem_allocated) {
5724313bdea8SRichard Henderson             temp_allocate_frame(s, ts);
5725313bdea8SRichard Henderson         }
5726313bdea8SRichard Henderson         load_arg_ref(s, 0, ts->mem_base->reg, ts->mem_offset, &allocated_regs);
5727313bdea8SRichard Henderson     }
5728313bdea8SRichard Henderson 
5729cee44b03SRichard Henderson     tcg_out_call(s, tcg_call_func(op), info);
5730c896fe29Sbellard 
573139004a71SRichard Henderson     /* Assign output registers and emit moves if needed.  */
573239004a71SRichard Henderson     switch (info->out_kind) {
573339004a71SRichard Henderson     case TCG_CALL_RET_NORMAL:
5734c896fe29Sbellard         for (i = 0; i < nb_oargs; i++) {
573539004a71SRichard Henderson             TCGTemp *ts = arg_temp(op->args[i]);
57365e3d0c19SRichard Henderson             TCGReg reg = tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, i);
5737d63e3b6eSRichard Henderson 
5738d63e3b6eSRichard Henderson             /* ENV should not be modified.  */
5739e01fa97dSRichard Henderson             tcg_debug_assert(!temp_readonly(ts));
5740d63e3b6eSRichard Henderson 
5741098859f1SRichard Henderson             set_temp_val_reg(s, ts, reg);
5742c896fe29Sbellard             ts->mem_coherent = 0;
574339004a71SRichard Henderson         }
574439004a71SRichard Henderson         break;
5745313bdea8SRichard Henderson 
5746c6556aa0SRichard Henderson     case TCG_CALL_RET_BY_VEC:
5747c6556aa0SRichard Henderson         {
5748c6556aa0SRichard Henderson             TCGTemp *ts = arg_temp(op->args[0]);
5749c6556aa0SRichard Henderson 
5750c6556aa0SRichard Henderson             tcg_debug_assert(ts->base_type == TCG_TYPE_I128);
5751c6556aa0SRichard Henderson             tcg_debug_assert(ts->temp_subindex == 0);
5752c6556aa0SRichard Henderson             if (!ts->mem_allocated) {
5753c6556aa0SRichard Henderson                 temp_allocate_frame(s, ts);
5754c6556aa0SRichard Henderson             }
5755c6556aa0SRichard Henderson             tcg_out_st(s, TCG_TYPE_V128,
5756c6556aa0SRichard Henderson                        tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0),
5757c6556aa0SRichard Henderson                        ts->mem_base->reg, ts->mem_offset);
5758c6556aa0SRichard Henderson         }
5759c6556aa0SRichard Henderson         /* fall through to mark all parts in memory */
5760c6556aa0SRichard Henderson 
5761313bdea8SRichard Henderson     case TCG_CALL_RET_BY_REF:
5762313bdea8SRichard Henderson         /* The callee has performed a write through the reference. */
5763313bdea8SRichard Henderson         for (i = 0; i < nb_oargs; i++) {
5764313bdea8SRichard Henderson             TCGTemp *ts = arg_temp(op->args[i]);
5765313bdea8SRichard Henderson             ts->val_type = TEMP_VAL_MEM;
5766313bdea8SRichard Henderson         }
5767313bdea8SRichard Henderson         break;
5768313bdea8SRichard Henderson 
576939004a71SRichard Henderson     default:
577039004a71SRichard Henderson         g_assert_not_reached();
577139004a71SRichard Henderson     }
577239004a71SRichard Henderson 
577339004a71SRichard Henderson     /* Flush or discard output registers as needed. */
577439004a71SRichard Henderson     for (i = 0; i < nb_oargs; i++) {
577539004a71SRichard Henderson         TCGTemp *ts = arg_temp(op->args[i]);
5776ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
577739004a71SRichard Henderson             temp_sync(s, ts, s->reserved_regs, 0, IS_DEAD_ARG(i));
577859d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
5779f8bf00f1SRichard Henderson             temp_dead(s, ts);
5780c896fe29Sbellard         }
5781c896fe29Sbellard     }
57828c11ad25SAurelien Jarno }
5783c896fe29Sbellard 
5784e63b8a29SRichard Henderson /**
5785e63b8a29SRichard Henderson  * atom_and_align_for_opc:
5786e63b8a29SRichard Henderson  * @s: tcg context
5787e63b8a29SRichard Henderson  * @opc: memory operation code
5788e63b8a29SRichard Henderson  * @host_atom: MO_ATOM_{IFALIGN,WITHIN16,SUBALIGN} for host operations
5789e63b8a29SRichard Henderson  * @allow_two_ops: true if we are prepared to issue two operations
5790e63b8a29SRichard Henderson  *
5791e63b8a29SRichard Henderson  * Return the alignment and atomicity to use for the inline fast path
5792e63b8a29SRichard Henderson  * for the given memory operation.  The alignment may be larger than
5793e63b8a29SRichard Henderson  * that specified in @opc, and the correct alignment will be diagnosed
5794e63b8a29SRichard Henderson  * by the slow path helper.
5795e63b8a29SRichard Henderson  *
5796e63b8a29SRichard Henderson  * If @allow_two_ops, the host is prepared to test for 2x alignment,
5797e63b8a29SRichard Henderson  * and issue two loads or stores for subalignment.
5798e63b8a29SRichard Henderson  */
5799e63b8a29SRichard Henderson static TCGAtomAlign atom_and_align_for_opc(TCGContext *s, MemOp opc,
5800e63b8a29SRichard Henderson                                            MemOp host_atom, bool allow_two_ops)
5801e63b8a29SRichard Henderson {
5802c5809eeeSRichard Henderson     MemOp align = memop_alignment_bits(opc);
5803e63b8a29SRichard Henderson     MemOp size = opc & MO_SIZE;
5804e63b8a29SRichard Henderson     MemOp half = size ? size - 1 : 0;
5805cbb14556SRichard Henderson     MemOp atom = opc & MO_ATOM_MASK;
5806e63b8a29SRichard Henderson     MemOp atmax;
5807e63b8a29SRichard Henderson 
5808e63b8a29SRichard Henderson     switch (atom) {
5809e63b8a29SRichard Henderson     case MO_ATOM_NONE:
5810e63b8a29SRichard Henderson         /* The operation requires no specific atomicity. */
5811e63b8a29SRichard Henderson         atmax = MO_8;
5812e63b8a29SRichard Henderson         break;
5813e63b8a29SRichard Henderson 
5814e63b8a29SRichard Henderson     case MO_ATOM_IFALIGN:
5815e63b8a29SRichard Henderson         atmax = size;
5816e63b8a29SRichard Henderson         break;
5817e63b8a29SRichard Henderson 
5818e63b8a29SRichard Henderson     case MO_ATOM_IFALIGN_PAIR:
5819e63b8a29SRichard Henderson         atmax = half;
5820e63b8a29SRichard Henderson         break;
5821e63b8a29SRichard Henderson 
5822e63b8a29SRichard Henderson     case MO_ATOM_WITHIN16:
5823e63b8a29SRichard Henderson         atmax = size;
5824e63b8a29SRichard Henderson         if (size == MO_128) {
5825e63b8a29SRichard Henderson             /* Misalignment implies !within16, and therefore no atomicity. */
5826e63b8a29SRichard Henderson         } else if (host_atom != MO_ATOM_WITHIN16) {
5827e63b8a29SRichard Henderson             /* The host does not implement within16, so require alignment. */
5828e63b8a29SRichard Henderson             align = MAX(align, size);
5829e63b8a29SRichard Henderson         }
5830e63b8a29SRichard Henderson         break;
5831e63b8a29SRichard Henderson 
5832e63b8a29SRichard Henderson     case MO_ATOM_WITHIN16_PAIR:
5833e63b8a29SRichard Henderson         atmax = size;
5834e63b8a29SRichard Henderson         /*
5835e63b8a29SRichard Henderson          * Misalignment implies !within16, and therefore half atomicity.
5836e63b8a29SRichard Henderson          * Any host prepared for two operations can implement this with
5837e63b8a29SRichard Henderson          * half alignment.
5838e63b8a29SRichard Henderson          */
5839e63b8a29SRichard Henderson         if (host_atom != MO_ATOM_WITHIN16 && allow_two_ops) {
5840e63b8a29SRichard Henderson             align = MAX(align, half);
5841e63b8a29SRichard Henderson         }
5842e63b8a29SRichard Henderson         break;
5843e63b8a29SRichard Henderson 
5844e63b8a29SRichard Henderson     case MO_ATOM_SUBALIGN:
5845e63b8a29SRichard Henderson         atmax = size;
5846e63b8a29SRichard Henderson         if (host_atom != MO_ATOM_SUBALIGN) {
5847e63b8a29SRichard Henderson             /* If unaligned but not odd, there are subobjects up to half. */
5848e63b8a29SRichard Henderson             if (allow_two_ops) {
5849e63b8a29SRichard Henderson                 align = MAX(align, half);
5850e63b8a29SRichard Henderson             } else {
5851e63b8a29SRichard Henderson                 align = MAX(align, size);
5852e63b8a29SRichard Henderson             }
5853e63b8a29SRichard Henderson         }
5854e63b8a29SRichard Henderson         break;
5855e63b8a29SRichard Henderson 
5856e63b8a29SRichard Henderson     default:
5857e63b8a29SRichard Henderson         g_assert_not_reached();
5858e63b8a29SRichard Henderson     }
5859e63b8a29SRichard Henderson 
5860e63b8a29SRichard Henderson     return (TCGAtomAlign){ .atom = atmax, .align = align };
5861e63b8a29SRichard Henderson }
5862e63b8a29SRichard Henderson 
58638429a1caSRichard Henderson /*
58648429a1caSRichard Henderson  * Similarly for qemu_ld/st slow path helpers.
58658429a1caSRichard Henderson  * We must re-implement tcg_gen_callN and tcg_reg_alloc_call simultaneously,
58668429a1caSRichard Henderson  * using only the provided backend tcg_out_* functions.
58678429a1caSRichard Henderson  */
58688429a1caSRichard Henderson 
58698429a1caSRichard Henderson static int tcg_out_helper_stk_ofs(TCGType type, unsigned slot)
58708429a1caSRichard Henderson {
58718429a1caSRichard Henderson     int ofs = arg_slot_stk_ofs(slot);
58728429a1caSRichard Henderson 
58738429a1caSRichard Henderson     /*
58748429a1caSRichard Henderson      * Each stack slot is TCG_TARGET_LONG_BITS.  If the host does not
58758429a1caSRichard Henderson      * require extension to uint64_t, adjust the address for uint32_t.
58768429a1caSRichard Henderson      */
58778429a1caSRichard Henderson     if (HOST_BIG_ENDIAN &&
58788429a1caSRichard Henderson         TCG_TARGET_REG_BITS == 64 &&
58798429a1caSRichard Henderson         type == TCG_TYPE_I32) {
58808429a1caSRichard Henderson         ofs += 4;
58818429a1caSRichard Henderson     }
58828429a1caSRichard Henderson     return ofs;
58838429a1caSRichard Henderson }
58848429a1caSRichard Henderson 
58858d314041SRichard Henderson static void tcg_out_helper_load_slots(TCGContext *s,
58868429a1caSRichard Henderson                                       unsigned nmov, TCGMovExtend *mov,
58872462e30eSRichard Henderson                                       const TCGLdstHelperParam *parm)
58888429a1caSRichard Henderson {
58898d314041SRichard Henderson     unsigned i;
58902462e30eSRichard Henderson     TCGReg dst3;
58912462e30eSRichard Henderson 
58928d314041SRichard Henderson     /*
58938d314041SRichard Henderson      * Start from the end, storing to the stack first.
58948d314041SRichard Henderson      * This frees those registers, so we need not consider overlap.
58958d314041SRichard Henderson      */
58968d314041SRichard Henderson     for (i = nmov; i-- > 0; ) {
58978d314041SRichard Henderson         unsigned slot = mov[i].dst;
58988d314041SRichard Henderson 
58998d314041SRichard Henderson         if (arg_slot_reg_p(slot)) {
59008d314041SRichard Henderson             goto found_reg;
59018d314041SRichard Henderson         }
59028d314041SRichard Henderson 
59038d314041SRichard Henderson         TCGReg src = mov[i].src;
59048d314041SRichard Henderson         TCGType dst_type = mov[i].dst_type;
59058d314041SRichard Henderson         MemOp dst_mo = dst_type == TCG_TYPE_I32 ? MO_32 : MO_64;
59068d314041SRichard Henderson 
59078d314041SRichard Henderson         /* The argument is going onto the stack; extend into scratch. */
59088d314041SRichard Henderson         if ((mov[i].src_ext & MO_SIZE) != dst_mo) {
59098d314041SRichard Henderson             tcg_debug_assert(parm->ntmp != 0);
59108d314041SRichard Henderson             mov[i].dst = src = parm->tmp[0];
59118d314041SRichard Henderson             tcg_out_movext1(s, &mov[i]);
59128d314041SRichard Henderson         }
59138d314041SRichard Henderson 
59148d314041SRichard Henderson         tcg_out_st(s, dst_type, src, TCG_REG_CALL_STACK,
59158d314041SRichard Henderson                    tcg_out_helper_stk_ofs(dst_type, slot));
59168d314041SRichard Henderson     }
59178d314041SRichard Henderson     return;
59188d314041SRichard Henderson 
59198d314041SRichard Henderson  found_reg:
59208d314041SRichard Henderson     /*
59218d314041SRichard Henderson      * The remaining arguments are in registers.
59228d314041SRichard Henderson      * Convert slot numbers to argument registers.
59238d314041SRichard Henderson      */
59248d314041SRichard Henderson     nmov = i + 1;
59258d314041SRichard Henderson     for (i = 0; i < nmov; ++i) {
59268d314041SRichard Henderson         mov[i].dst = tcg_target_call_iarg_regs[mov[i].dst];
59278d314041SRichard Henderson     }
59288d314041SRichard Henderson 
59298429a1caSRichard Henderson     switch (nmov) {
59302462e30eSRichard Henderson     case 4:
59318429a1caSRichard Henderson         /* The backend must have provided enough temps for the worst case. */
59322462e30eSRichard Henderson         tcg_debug_assert(parm->ntmp >= 2);
59338429a1caSRichard Henderson 
59342462e30eSRichard Henderson         dst3 = mov[3].dst;
59352462e30eSRichard Henderson         for (unsigned j = 0; j < 3; ++j) {
59362462e30eSRichard Henderson             if (dst3 == mov[j].src) {
59378429a1caSRichard Henderson                 /*
59382462e30eSRichard Henderson                  * Conflict. Copy the source to a temporary, perform the
59392462e30eSRichard Henderson                  * remaining moves, then the extension from our scratch
59402462e30eSRichard Henderson                  * on the way out.
59418429a1caSRichard Henderson                  */
59422462e30eSRichard Henderson                 TCGReg scratch = parm->tmp[1];
59438429a1caSRichard Henderson 
59442462e30eSRichard Henderson                 tcg_out_mov(s, mov[3].src_type, scratch, mov[3].src);
59452462e30eSRichard Henderson                 tcg_out_movext3(s, mov, mov + 1, mov + 2, parm->tmp[0]);
59462462e30eSRichard Henderson                 tcg_out_movext1_new_src(s, &mov[3], scratch);
59472462e30eSRichard Henderson                 break;
59488429a1caSRichard Henderson             }
59498429a1caSRichard Henderson         }
59508429a1caSRichard Henderson 
59518429a1caSRichard Henderson         /* No conflicts: perform this move and continue. */
59522462e30eSRichard Henderson         tcg_out_movext1(s, &mov[3]);
59532462e30eSRichard Henderson         /* fall through */
59548429a1caSRichard Henderson 
59552462e30eSRichard Henderson     case 3:
59562462e30eSRichard Henderson         tcg_out_movext3(s, mov, mov + 1, mov + 2,
59572462e30eSRichard Henderson                         parm->ntmp ? parm->tmp[0] : -1);
59582462e30eSRichard Henderson         break;
59598429a1caSRichard Henderson     case 2:
59602462e30eSRichard Henderson         tcg_out_movext2(s, mov, mov + 1,
59612462e30eSRichard Henderson                         parm->ntmp ? parm->tmp[0] : -1);
59622462e30eSRichard Henderson         break;
59638429a1caSRichard Henderson     case 1:
59648429a1caSRichard Henderson         tcg_out_movext1(s, mov);
59652462e30eSRichard Henderson         break;
59662462e30eSRichard Henderson     default:
59678429a1caSRichard Henderson         g_assert_not_reached();
59688429a1caSRichard Henderson     }
59698429a1caSRichard Henderson }
59708429a1caSRichard Henderson 
59718429a1caSRichard Henderson static void tcg_out_helper_load_imm(TCGContext *s, unsigned slot,
59728429a1caSRichard Henderson                                     TCGType type, tcg_target_long imm,
59738429a1caSRichard Henderson                                     const TCGLdstHelperParam *parm)
59748429a1caSRichard Henderson {
59758429a1caSRichard Henderson     if (arg_slot_reg_p(slot)) {
59768429a1caSRichard Henderson         tcg_out_movi(s, type, tcg_target_call_iarg_regs[slot], imm);
59778429a1caSRichard Henderson     } else {
59788429a1caSRichard Henderson         int ofs = tcg_out_helper_stk_ofs(type, slot);
59798429a1caSRichard Henderson         if (!tcg_out_sti(s, type, imm, TCG_REG_CALL_STACK, ofs)) {
59808429a1caSRichard Henderson             tcg_debug_assert(parm->ntmp != 0);
59818429a1caSRichard Henderson             tcg_out_movi(s, type, parm->tmp[0], imm);
59828429a1caSRichard Henderson             tcg_out_st(s, type, parm->tmp[0], TCG_REG_CALL_STACK, ofs);
59838429a1caSRichard Henderson         }
59848429a1caSRichard Henderson     }
59858429a1caSRichard Henderson }
59868429a1caSRichard Henderson 
59878429a1caSRichard Henderson static void tcg_out_helper_load_common_args(TCGContext *s,
59888429a1caSRichard Henderson                                             const TCGLabelQemuLdst *ldst,
59898429a1caSRichard Henderson                                             const TCGLdstHelperParam *parm,
59908429a1caSRichard Henderson                                             const TCGHelperInfo *info,
59918429a1caSRichard Henderson                                             unsigned next_arg)
59928429a1caSRichard Henderson {
59938429a1caSRichard Henderson     TCGMovExtend ptr_mov = {
59948429a1caSRichard Henderson         .dst_type = TCG_TYPE_PTR,
59958429a1caSRichard Henderson         .src_type = TCG_TYPE_PTR,
59968429a1caSRichard Henderson         .src_ext = sizeof(void *) == 4 ? MO_32 : MO_64
59978429a1caSRichard Henderson     };
59988429a1caSRichard Henderson     const TCGCallArgumentLoc *loc = &info->in[0];
59998429a1caSRichard Henderson     TCGType type;
60008429a1caSRichard Henderson     unsigned slot;
60018429a1caSRichard Henderson     tcg_target_ulong imm;
60028429a1caSRichard Henderson 
60038429a1caSRichard Henderson     /*
60048429a1caSRichard Henderson      * Handle env, which is always first.
60058429a1caSRichard Henderson      */
60068429a1caSRichard Henderson     ptr_mov.dst = loc->arg_slot;
60078429a1caSRichard Henderson     ptr_mov.src = TCG_AREG0;
60088429a1caSRichard Henderson     tcg_out_helper_load_slots(s, 1, &ptr_mov, parm);
60098429a1caSRichard Henderson 
60108429a1caSRichard Henderson     /*
60118429a1caSRichard Henderson      * Handle oi.
60128429a1caSRichard Henderson      */
60138429a1caSRichard Henderson     imm = ldst->oi;
60148429a1caSRichard Henderson     loc = &info->in[next_arg];
60158429a1caSRichard Henderson     type = TCG_TYPE_I32;
60168429a1caSRichard Henderson     switch (loc->kind) {
60178429a1caSRichard Henderson     case TCG_CALL_ARG_NORMAL:
60188429a1caSRichard Henderson         break;
60198429a1caSRichard Henderson     case TCG_CALL_ARG_EXTEND_U:
60208429a1caSRichard Henderson     case TCG_CALL_ARG_EXTEND_S:
60218429a1caSRichard Henderson         /* No extension required for MemOpIdx. */
60228429a1caSRichard Henderson         tcg_debug_assert(imm <= INT32_MAX);
60238429a1caSRichard Henderson         type = TCG_TYPE_REG;
60248429a1caSRichard Henderson         break;
60258429a1caSRichard Henderson     default:
60268429a1caSRichard Henderson         g_assert_not_reached();
60278429a1caSRichard Henderson     }
60288429a1caSRichard Henderson     tcg_out_helper_load_imm(s, loc->arg_slot, type, imm, parm);
60298429a1caSRichard Henderson     next_arg++;
60308429a1caSRichard Henderson 
60318429a1caSRichard Henderson     /*
60328429a1caSRichard Henderson      * Handle ra.
60338429a1caSRichard Henderson      */
60348429a1caSRichard Henderson     loc = &info->in[next_arg];
60358429a1caSRichard Henderson     slot = loc->arg_slot;
60368429a1caSRichard Henderson     if (parm->ra_gen) {
60378429a1caSRichard Henderson         int arg_reg = -1;
60388429a1caSRichard Henderson         TCGReg ra_reg;
60398429a1caSRichard Henderson 
60408429a1caSRichard Henderson         if (arg_slot_reg_p(slot)) {
60418429a1caSRichard Henderson             arg_reg = tcg_target_call_iarg_regs[slot];
60428429a1caSRichard Henderson         }
60438429a1caSRichard Henderson         ra_reg = parm->ra_gen(s, ldst, arg_reg);
60448429a1caSRichard Henderson 
60458429a1caSRichard Henderson         ptr_mov.dst = slot;
60468429a1caSRichard Henderson         ptr_mov.src = ra_reg;
60478429a1caSRichard Henderson         tcg_out_helper_load_slots(s, 1, &ptr_mov, parm);
60488429a1caSRichard Henderson     } else {
60498429a1caSRichard Henderson         imm = (uintptr_t)ldst->raddr;
60508429a1caSRichard Henderson         tcg_out_helper_load_imm(s, slot, TCG_TYPE_PTR, imm, parm);
60518429a1caSRichard Henderson     }
60528429a1caSRichard Henderson }
60538429a1caSRichard Henderson 
60548429a1caSRichard Henderson static unsigned tcg_out_helper_add_mov(TCGMovExtend *mov,
60558429a1caSRichard Henderson                                        const TCGCallArgumentLoc *loc,
60568429a1caSRichard Henderson                                        TCGType dst_type, TCGType src_type,
60578429a1caSRichard Henderson                                        TCGReg lo, TCGReg hi)
60588429a1caSRichard Henderson {
6059ebebea53SRichard Henderson     MemOp reg_mo;
6060ebebea53SRichard Henderson 
60618429a1caSRichard Henderson     if (dst_type <= TCG_TYPE_REG) {
60628429a1caSRichard Henderson         MemOp src_ext;
60638429a1caSRichard Henderson 
60648429a1caSRichard Henderson         switch (loc->kind) {
60658429a1caSRichard Henderson         case TCG_CALL_ARG_NORMAL:
60668429a1caSRichard Henderson             src_ext = src_type == TCG_TYPE_I32 ? MO_32 : MO_64;
60678429a1caSRichard Henderson             break;
60688429a1caSRichard Henderson         case TCG_CALL_ARG_EXTEND_U:
60698429a1caSRichard Henderson             dst_type = TCG_TYPE_REG;
60708429a1caSRichard Henderson             src_ext = MO_UL;
60718429a1caSRichard Henderson             break;
60728429a1caSRichard Henderson         case TCG_CALL_ARG_EXTEND_S:
60738429a1caSRichard Henderson             dst_type = TCG_TYPE_REG;
60748429a1caSRichard Henderson             src_ext = MO_SL;
60758429a1caSRichard Henderson             break;
60768429a1caSRichard Henderson         default:
60778429a1caSRichard Henderson             g_assert_not_reached();
60788429a1caSRichard Henderson         }
60798429a1caSRichard Henderson 
60808429a1caSRichard Henderson         mov[0].dst = loc->arg_slot;
60818429a1caSRichard Henderson         mov[0].dst_type = dst_type;
60828429a1caSRichard Henderson         mov[0].src = lo;
60838429a1caSRichard Henderson         mov[0].src_type = src_type;
60848429a1caSRichard Henderson         mov[0].src_ext = src_ext;
60858429a1caSRichard Henderson         return 1;
60868429a1caSRichard Henderson     }
60878429a1caSRichard Henderson 
6088ebebea53SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
6089ebebea53SRichard Henderson         assert(dst_type == TCG_TYPE_I64);
6090ebebea53SRichard Henderson         reg_mo = MO_32;
6091ebebea53SRichard Henderson     } else {
6092ebebea53SRichard Henderson         assert(dst_type == TCG_TYPE_I128);
6093ebebea53SRichard Henderson         reg_mo = MO_64;
6094ebebea53SRichard Henderson     }
60958429a1caSRichard Henderson 
60968429a1caSRichard Henderson     mov[0].dst = loc[HOST_BIG_ENDIAN].arg_slot;
60978429a1caSRichard Henderson     mov[0].src = lo;
6098ebebea53SRichard Henderson     mov[0].dst_type = TCG_TYPE_REG;
6099ebebea53SRichard Henderson     mov[0].src_type = TCG_TYPE_REG;
6100ebebea53SRichard Henderson     mov[0].src_ext = reg_mo;
61018429a1caSRichard Henderson 
61028429a1caSRichard Henderson     mov[1].dst = loc[!HOST_BIG_ENDIAN].arg_slot;
61038429a1caSRichard Henderson     mov[1].src = hi;
6104ebebea53SRichard Henderson     mov[1].dst_type = TCG_TYPE_REG;
6105ebebea53SRichard Henderson     mov[1].src_type = TCG_TYPE_REG;
6106ebebea53SRichard Henderson     mov[1].src_ext = reg_mo;
61078429a1caSRichard Henderson 
61088429a1caSRichard Henderson     return 2;
61098429a1caSRichard Henderson }
61108429a1caSRichard Henderson 
61118429a1caSRichard Henderson static void tcg_out_ld_helper_args(TCGContext *s, const TCGLabelQemuLdst *ldst,
61128429a1caSRichard Henderson                                    const TCGLdstHelperParam *parm)
61138429a1caSRichard Henderson {
61148429a1caSRichard Henderson     const TCGHelperInfo *info;
61158429a1caSRichard Henderson     const TCGCallArgumentLoc *loc;
61168429a1caSRichard Henderson     TCGMovExtend mov[2];
61178429a1caSRichard Henderson     unsigned next_arg, nmov;
61188429a1caSRichard Henderson     MemOp mop = get_memop(ldst->oi);
61198429a1caSRichard Henderson 
61208429a1caSRichard Henderson     switch (mop & MO_SIZE) {
61218429a1caSRichard Henderson     case MO_8:
61228429a1caSRichard Henderson     case MO_16:
61238429a1caSRichard Henderson     case MO_32:
61248429a1caSRichard Henderson         info = &info_helper_ld32_mmu;
61258429a1caSRichard Henderson         break;
61268429a1caSRichard Henderson     case MO_64:
61278429a1caSRichard Henderson         info = &info_helper_ld64_mmu;
61288429a1caSRichard Henderson         break;
6129ebebea53SRichard Henderson     case MO_128:
6130ebebea53SRichard Henderson         info = &info_helper_ld128_mmu;
6131ebebea53SRichard Henderson         break;
61328429a1caSRichard Henderson     default:
61338429a1caSRichard Henderson         g_assert_not_reached();
61348429a1caSRichard Henderson     }
61358429a1caSRichard Henderson 
61368429a1caSRichard Henderson     /* Defer env argument. */
61378429a1caSRichard Henderson     next_arg = 1;
61388429a1caSRichard Henderson 
61398429a1caSRichard Henderson     loc = &info->in[next_arg];
6140c31e5fa4SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && s->addr_type == TCG_TYPE_I32) {
614124e46e6cSRichard Henderson         /*
614224e46e6cSRichard Henderson          * 32-bit host with 32-bit guest: zero-extend the guest address
614324e46e6cSRichard Henderson          * to 64-bits for the helper by storing the low part, then
614424e46e6cSRichard Henderson          * load a zero for the high part.
614524e46e6cSRichard Henderson          */
614624e46e6cSRichard Henderson         tcg_out_helper_add_mov(mov, loc + HOST_BIG_ENDIAN,
614724e46e6cSRichard Henderson                                TCG_TYPE_I32, TCG_TYPE_I32,
61480cd38379SRichard Henderson                                ldst->addr_reg, -1);
614924e46e6cSRichard Henderson         tcg_out_helper_load_slots(s, 1, mov, parm);
615024e46e6cSRichard Henderson 
615124e46e6cSRichard Henderson         tcg_out_helper_load_imm(s, loc[!HOST_BIG_ENDIAN].arg_slot,
615224e46e6cSRichard Henderson                                 TCG_TYPE_I32, 0, parm);
615324e46e6cSRichard Henderson         next_arg += 2;
6154c31e5fa4SRichard Henderson     } else {
6155c31e5fa4SRichard Henderson         nmov = tcg_out_helper_add_mov(mov, loc, TCG_TYPE_I64, s->addr_type,
61560cd38379SRichard Henderson                                       ldst->addr_reg, -1);
6157c31e5fa4SRichard Henderson         tcg_out_helper_load_slots(s, nmov, mov, parm);
6158c31e5fa4SRichard Henderson         next_arg += nmov;
615924e46e6cSRichard Henderson     }
61608429a1caSRichard Henderson 
6161ebebea53SRichard Henderson     switch (info->out_kind) {
6162ebebea53SRichard Henderson     case TCG_CALL_RET_NORMAL:
6163ebebea53SRichard Henderson     case TCG_CALL_RET_BY_VEC:
6164ebebea53SRichard Henderson         break;
6165ebebea53SRichard Henderson     case TCG_CALL_RET_BY_REF:
6166ebebea53SRichard Henderson         /*
6167ebebea53SRichard Henderson          * The return reference is in the first argument slot.
6168ebebea53SRichard Henderson          * We need memory in which to return: re-use the top of stack.
6169ebebea53SRichard Henderson          */
6170ebebea53SRichard Henderson         {
6171ebebea53SRichard Henderson             int ofs_slot0 = TCG_TARGET_CALL_STACK_OFFSET;
6172ebebea53SRichard Henderson 
6173ebebea53SRichard Henderson             if (arg_slot_reg_p(0)) {
6174ebebea53SRichard Henderson                 tcg_out_addi_ptr(s, tcg_target_call_iarg_regs[0],
6175ebebea53SRichard Henderson                                  TCG_REG_CALL_STACK, ofs_slot0);
6176ebebea53SRichard Henderson             } else {
6177ebebea53SRichard Henderson                 tcg_debug_assert(parm->ntmp != 0);
6178ebebea53SRichard Henderson                 tcg_out_addi_ptr(s, parm->tmp[0],
6179ebebea53SRichard Henderson                                  TCG_REG_CALL_STACK, ofs_slot0);
6180ebebea53SRichard Henderson                 tcg_out_st(s, TCG_TYPE_PTR, parm->tmp[0],
6181ebebea53SRichard Henderson                            TCG_REG_CALL_STACK, ofs_slot0);
6182ebebea53SRichard Henderson             }
6183ebebea53SRichard Henderson         }
6184ebebea53SRichard Henderson         break;
6185ebebea53SRichard Henderson     default:
6186ebebea53SRichard Henderson         g_assert_not_reached();
6187ebebea53SRichard Henderson     }
61888429a1caSRichard Henderson 
61898429a1caSRichard Henderson     tcg_out_helper_load_common_args(s, ldst, parm, info, next_arg);
61908429a1caSRichard Henderson }
61918429a1caSRichard Henderson 
61928429a1caSRichard Henderson static void tcg_out_ld_helper_ret(TCGContext *s, const TCGLabelQemuLdst *ldst,
61938429a1caSRichard Henderson                                   bool load_sign,
61948429a1caSRichard Henderson                                   const TCGLdstHelperParam *parm)
61958429a1caSRichard Henderson {
61968429a1caSRichard Henderson     MemOp mop = get_memop(ldst->oi);
6197ebebea53SRichard Henderson     TCGMovExtend mov[2];
6198ebebea53SRichard Henderson     int ofs_slot0;
61998429a1caSRichard Henderson 
6200ebebea53SRichard Henderson     switch (ldst->type) {
6201ebebea53SRichard Henderson     case TCG_TYPE_I64:
6202ebebea53SRichard Henderson         if (TCG_TARGET_REG_BITS == 32) {
6203ebebea53SRichard Henderson             break;
6204ebebea53SRichard Henderson         }
6205ebebea53SRichard Henderson         /* fall through */
6206ebebea53SRichard Henderson 
6207ebebea53SRichard Henderson     case TCG_TYPE_I32:
62088429a1caSRichard Henderson         mov[0].dst = ldst->datalo_reg;
62098429a1caSRichard Henderson         mov[0].src = tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, 0);
62108429a1caSRichard Henderson         mov[0].dst_type = ldst->type;
62118429a1caSRichard Henderson         mov[0].src_type = TCG_TYPE_REG;
62128429a1caSRichard Henderson 
62138429a1caSRichard Henderson         /*
62148429a1caSRichard Henderson          * If load_sign, then we allowed the helper to perform the
62158429a1caSRichard Henderson          * appropriate sign extension to tcg_target_ulong, and all
62168429a1caSRichard Henderson          * we need now is a plain move.
62178429a1caSRichard Henderson          *
62188429a1caSRichard Henderson          * If they do not, then we expect the relevant extension
62198429a1caSRichard Henderson          * instruction to be no more expensive than a move, and
62208429a1caSRichard Henderson          * we thus save the icache etc by only using one of two
62218429a1caSRichard Henderson          * helper functions.
62228429a1caSRichard Henderson          */
62238429a1caSRichard Henderson         if (load_sign || !(mop & MO_SIGN)) {
62248429a1caSRichard Henderson             if (TCG_TARGET_REG_BITS == 32 || ldst->type == TCG_TYPE_I32) {
62258429a1caSRichard Henderson                 mov[0].src_ext = MO_32;
62268429a1caSRichard Henderson             } else {
62278429a1caSRichard Henderson                 mov[0].src_ext = MO_64;
62288429a1caSRichard Henderson             }
62298429a1caSRichard Henderson         } else {
62308429a1caSRichard Henderson             mov[0].src_ext = mop & MO_SSIZE;
62318429a1caSRichard Henderson         }
62328429a1caSRichard Henderson         tcg_out_movext1(s, mov);
6233ebebea53SRichard Henderson         return;
6234ebebea53SRichard Henderson 
6235ebebea53SRichard Henderson     case TCG_TYPE_I128:
6236ebebea53SRichard Henderson         tcg_debug_assert(TCG_TARGET_REG_BITS == 64);
6237ebebea53SRichard Henderson         ofs_slot0 = TCG_TARGET_CALL_STACK_OFFSET;
6238ebebea53SRichard Henderson         switch (TCG_TARGET_CALL_RET_I128) {
6239ebebea53SRichard Henderson         case TCG_CALL_RET_NORMAL:
6240ebebea53SRichard Henderson             break;
6241ebebea53SRichard Henderson         case TCG_CALL_RET_BY_VEC:
6242ebebea53SRichard Henderson             tcg_out_st(s, TCG_TYPE_V128,
6243ebebea53SRichard Henderson                        tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0),
6244ebebea53SRichard Henderson                        TCG_REG_CALL_STACK, ofs_slot0);
6245ebebea53SRichard Henderson             /* fall through */
6246ebebea53SRichard Henderson         case TCG_CALL_RET_BY_REF:
6247ebebea53SRichard Henderson             tcg_out_ld(s, TCG_TYPE_I64, ldst->datalo_reg,
6248ebebea53SRichard Henderson                        TCG_REG_CALL_STACK, ofs_slot0 + 8 * HOST_BIG_ENDIAN);
6249ebebea53SRichard Henderson             tcg_out_ld(s, TCG_TYPE_I64, ldst->datahi_reg,
6250ebebea53SRichard Henderson                        TCG_REG_CALL_STACK, ofs_slot0 + 8 * !HOST_BIG_ENDIAN);
6251ebebea53SRichard Henderson             return;
6252ebebea53SRichard Henderson         default:
6253ebebea53SRichard Henderson             g_assert_not_reached();
6254ebebea53SRichard Henderson         }
6255ebebea53SRichard Henderson         break;
6256ebebea53SRichard Henderson 
6257ebebea53SRichard Henderson     default:
6258ebebea53SRichard Henderson         g_assert_not_reached();
6259ebebea53SRichard Henderson     }
62608429a1caSRichard Henderson 
62618429a1caSRichard Henderson     mov[0].dst = ldst->datalo_reg;
62628429a1caSRichard Henderson     mov[0].src =
62638429a1caSRichard Henderson         tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, HOST_BIG_ENDIAN);
6264723d3a27SRichard Henderson     mov[0].dst_type = TCG_TYPE_REG;
6265723d3a27SRichard Henderson     mov[0].src_type = TCG_TYPE_REG;
6266ebebea53SRichard Henderson     mov[0].src_ext = TCG_TARGET_REG_BITS == 32 ? MO_32 : MO_64;
62678429a1caSRichard Henderson 
62688429a1caSRichard Henderson     mov[1].dst = ldst->datahi_reg;
62698429a1caSRichard Henderson     mov[1].src =
62708429a1caSRichard Henderson         tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, !HOST_BIG_ENDIAN);
62718429a1caSRichard Henderson     mov[1].dst_type = TCG_TYPE_REG;
62728429a1caSRichard Henderson     mov[1].src_type = TCG_TYPE_REG;
6273ebebea53SRichard Henderson     mov[1].src_ext = TCG_TARGET_REG_BITS == 32 ? MO_32 : MO_64;
62748429a1caSRichard Henderson 
62758429a1caSRichard Henderson     tcg_out_movext2(s, mov, mov + 1, parm->ntmp ? parm->tmp[0] : -1);
62768429a1caSRichard Henderson }
62778429a1caSRichard Henderson 
62788429a1caSRichard Henderson static void tcg_out_st_helper_args(TCGContext *s, const TCGLabelQemuLdst *ldst,
62798429a1caSRichard Henderson                                    const TCGLdstHelperParam *parm)
62808429a1caSRichard Henderson {
62818429a1caSRichard Henderson     const TCGHelperInfo *info;
62828429a1caSRichard Henderson     const TCGCallArgumentLoc *loc;
62838429a1caSRichard Henderson     TCGMovExtend mov[4];
62848429a1caSRichard Henderson     TCGType data_type;
62858429a1caSRichard Henderson     unsigned next_arg, nmov, n;
62868429a1caSRichard Henderson     MemOp mop = get_memop(ldst->oi);
62878429a1caSRichard Henderson 
62888429a1caSRichard Henderson     switch (mop & MO_SIZE) {
62898429a1caSRichard Henderson     case MO_8:
62908429a1caSRichard Henderson     case MO_16:
62918429a1caSRichard Henderson     case MO_32:
62928429a1caSRichard Henderson         info = &info_helper_st32_mmu;
62938429a1caSRichard Henderson         data_type = TCG_TYPE_I32;
62948429a1caSRichard Henderson         break;
62958429a1caSRichard Henderson     case MO_64:
62968429a1caSRichard Henderson         info = &info_helper_st64_mmu;
62978429a1caSRichard Henderson         data_type = TCG_TYPE_I64;
62988429a1caSRichard Henderson         break;
6299ebebea53SRichard Henderson     case MO_128:
6300ebebea53SRichard Henderson         info = &info_helper_st128_mmu;
6301ebebea53SRichard Henderson         data_type = TCG_TYPE_I128;
6302ebebea53SRichard Henderson         break;
63038429a1caSRichard Henderson     default:
63048429a1caSRichard Henderson         g_assert_not_reached();
63058429a1caSRichard Henderson     }
63068429a1caSRichard Henderson 
63078429a1caSRichard Henderson     /* Defer env argument. */
63088429a1caSRichard Henderson     next_arg = 1;
63098429a1caSRichard Henderson     nmov = 0;
63108429a1caSRichard Henderson 
63118429a1caSRichard Henderson     /* Handle addr argument. */
63128429a1caSRichard Henderson     loc = &info->in[next_arg];
63130cd38379SRichard Henderson     tcg_debug_assert(s->addr_type <= TCG_TYPE_REG);
63140cd38379SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
631524e46e6cSRichard Henderson         /*
63160cd38379SRichard Henderson          * 32-bit host (and thus 32-bit guest): zero-extend the guest address
631724e46e6cSRichard Henderson          * to 64-bits for the helper by storing the low part.  Later,
631824e46e6cSRichard Henderson          * after we have processed the register inputs, we will load a
631924e46e6cSRichard Henderson          * zero for the high part.
632024e46e6cSRichard Henderson          */
632124e46e6cSRichard Henderson         tcg_out_helper_add_mov(mov, loc + HOST_BIG_ENDIAN,
632224e46e6cSRichard Henderson                                TCG_TYPE_I32, TCG_TYPE_I32,
63230cd38379SRichard Henderson                                ldst->addr_reg, -1);
632424e46e6cSRichard Henderson         next_arg += 2;
632524e46e6cSRichard Henderson         nmov += 1;
6326c31e5fa4SRichard Henderson     } else {
6327c31e5fa4SRichard Henderson         n = tcg_out_helper_add_mov(mov, loc, TCG_TYPE_I64, s->addr_type,
63280cd38379SRichard Henderson                                    ldst->addr_reg, -1);
6329c31e5fa4SRichard Henderson         next_arg += n;
6330c31e5fa4SRichard Henderson         nmov += n;
633124e46e6cSRichard Henderson     }
63328429a1caSRichard Henderson 
63338429a1caSRichard Henderson     /* Handle data argument. */
63348429a1caSRichard Henderson     loc = &info->in[next_arg];
6335ebebea53SRichard Henderson     switch (loc->kind) {
6336ebebea53SRichard Henderson     case TCG_CALL_ARG_NORMAL:
6337ebebea53SRichard Henderson     case TCG_CALL_ARG_EXTEND_U:
6338ebebea53SRichard Henderson     case TCG_CALL_ARG_EXTEND_S:
63398429a1caSRichard Henderson         n = tcg_out_helper_add_mov(mov + nmov, loc, data_type, ldst->type,
63408429a1caSRichard Henderson                                    ldst->datalo_reg, ldst->datahi_reg);
63418429a1caSRichard Henderson         next_arg += n;
63428429a1caSRichard Henderson         nmov += n;
6343ebebea53SRichard Henderson         tcg_out_helper_load_slots(s, nmov, mov, parm);
6344ebebea53SRichard Henderson         break;
6345ebebea53SRichard Henderson 
6346ebebea53SRichard Henderson     case TCG_CALL_ARG_BY_REF:
6347ebebea53SRichard Henderson         tcg_debug_assert(TCG_TARGET_REG_BITS == 64);
6348ebebea53SRichard Henderson         tcg_debug_assert(data_type == TCG_TYPE_I128);
6349ebebea53SRichard Henderson         tcg_out_st(s, TCG_TYPE_I64,
6350ebebea53SRichard Henderson                    HOST_BIG_ENDIAN ? ldst->datahi_reg : ldst->datalo_reg,
6351ebebea53SRichard Henderson                    TCG_REG_CALL_STACK, arg_slot_stk_ofs(loc[0].ref_slot));
6352ebebea53SRichard Henderson         tcg_out_st(s, TCG_TYPE_I64,
6353ebebea53SRichard Henderson                    HOST_BIG_ENDIAN ? ldst->datalo_reg : ldst->datahi_reg,
6354ebebea53SRichard Henderson                    TCG_REG_CALL_STACK, arg_slot_stk_ofs(loc[1].ref_slot));
63558429a1caSRichard Henderson 
63568429a1caSRichard Henderson         tcg_out_helper_load_slots(s, nmov, mov, parm);
6357ebebea53SRichard Henderson 
6358ebebea53SRichard Henderson         if (arg_slot_reg_p(loc->arg_slot)) {
6359ebebea53SRichard Henderson             tcg_out_addi_ptr(s, tcg_target_call_iarg_regs[loc->arg_slot],
6360ebebea53SRichard Henderson                              TCG_REG_CALL_STACK,
6361ebebea53SRichard Henderson                              arg_slot_stk_ofs(loc->ref_slot));
6362ebebea53SRichard Henderson         } else {
6363ebebea53SRichard Henderson             tcg_debug_assert(parm->ntmp != 0);
6364ebebea53SRichard Henderson             tcg_out_addi_ptr(s, parm->tmp[0], TCG_REG_CALL_STACK,
6365ebebea53SRichard Henderson                              arg_slot_stk_ofs(loc->ref_slot));
6366ebebea53SRichard Henderson             tcg_out_st(s, TCG_TYPE_PTR, parm->tmp[0],
6367ebebea53SRichard Henderson                        TCG_REG_CALL_STACK, arg_slot_stk_ofs(loc->arg_slot));
6368ebebea53SRichard Henderson         }
6369ebebea53SRichard Henderson         next_arg += 2;
6370ebebea53SRichard Henderson         break;
6371ebebea53SRichard Henderson 
6372ebebea53SRichard Henderson     default:
6373ebebea53SRichard Henderson         g_assert_not_reached();
6374ebebea53SRichard Henderson     }
6375ebebea53SRichard Henderson 
63760cd38379SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
6377c31e5fa4SRichard Henderson         /* Zero extend the address by loading a zero for the high part. */
637824e46e6cSRichard Henderson         loc = &info->in[1 + !HOST_BIG_ENDIAN];
637924e46e6cSRichard Henderson         tcg_out_helper_load_imm(s, loc->arg_slot, TCG_TYPE_I32, 0, parm);
638024e46e6cSRichard Henderson     }
638124e46e6cSRichard Henderson 
63828429a1caSRichard Henderson     tcg_out_helper_load_common_args(s, ldst, parm, info, next_arg);
63838429a1caSRichard Henderson }
63848429a1caSRichard Henderson 
638576cef4b2SRichard Henderson int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start)
6386c896fe29Sbellard {
6387747bd69dSRichard Henderson     int i, start_words, num_insns;
638815fa08f8SRichard Henderson     TCGOp *op;
6389c896fe29Sbellard 
6390d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)
6391fbf59aadSRichard Henderson                  && qemu_log_in_addr_range(pc_start))) {
6392c60f599bSRichard Henderson         FILE *logfile = qemu_log_trylock();
639378b54858SRichard Henderson         if (logfile) {
639478b54858SRichard Henderson             fprintf(logfile, "OP:\n");
6395b7a83ff8SRichard Henderson             tcg_dump_ops(s, logfile, false);
639678b54858SRichard Henderson             fprintf(logfile, "\n");
6397fc59d2d8SRobert Foley             qemu_log_unlock(logfile);
6398c896fe29Sbellard         }
639978b54858SRichard Henderson     }
6400c896fe29Sbellard 
6401bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG
6402bef16ab4SRichard Henderson     /* Ensure all labels referenced have been emitted.  */
6403bef16ab4SRichard Henderson     {
6404bef16ab4SRichard Henderson         TCGLabel *l;
6405bef16ab4SRichard Henderson         bool error = false;
6406bef16ab4SRichard Henderson 
6407bef16ab4SRichard Henderson         QSIMPLEQ_FOREACH(l, &s->labels, next) {
6408f85b1fc4SRichard Henderson             if (unlikely(!l->present) && !QSIMPLEQ_EMPTY(&l->branches)) {
6409bef16ab4SRichard Henderson                 qemu_log_mask(CPU_LOG_TB_OP,
6410bef16ab4SRichard Henderson                               "$L%d referenced but not present.\n", l->id);
6411bef16ab4SRichard Henderson                 error = true;
6412bef16ab4SRichard Henderson             }
6413bef16ab4SRichard Henderson         }
6414bef16ab4SRichard Henderson         assert(!error);
6415bef16ab4SRichard Henderson     }
6416bef16ab4SRichard Henderson #endif
6417bef16ab4SRichard Henderson 
641804e006abSRichard Henderson     /* Do not reuse any EBB that may be allocated within the TB. */
641904e006abSRichard Henderson     tcg_temp_ebb_reset_freed(s);
642004e006abSRichard Henderson 
6421c45cb8bbSRichard Henderson     tcg_optimize(s);
64228f2e8c07SKirill Batuzov 
6423b4fc67c7SRichard Henderson     reachable_code_pass(s);
6424874b8574SRichard Henderson     liveness_pass_0(s);
6425b83eabeaSRichard Henderson     liveness_pass_1(s);
64265a18407fSRichard Henderson 
64275a18407fSRichard Henderson     if (s->nb_indirects > 0) {
64285a18407fSRichard Henderson         if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND)
6429fbf59aadSRichard Henderson                      && qemu_log_in_addr_range(pc_start))) {
6430c60f599bSRichard Henderson             FILE *logfile = qemu_log_trylock();
643178b54858SRichard Henderson             if (logfile) {
643278b54858SRichard Henderson                 fprintf(logfile, "OP before indirect lowering:\n");
6433b7a83ff8SRichard Henderson                 tcg_dump_ops(s, logfile, false);
643478b54858SRichard Henderson                 fprintf(logfile, "\n");
6435fc59d2d8SRobert Foley                 qemu_log_unlock(logfile);
64365a18407fSRichard Henderson             }
643778b54858SRichard Henderson         }
6438645e3a81SRichard Henderson 
64395a18407fSRichard Henderson         /* Replace indirect temps with direct temps.  */
6440b83eabeaSRichard Henderson         if (liveness_pass_2(s)) {
64415a18407fSRichard Henderson             /* If changes were made, re-run liveness.  */
6442b83eabeaSRichard Henderson             liveness_pass_1(s);
64435a18407fSRichard Henderson         }
64445a18407fSRichard Henderson     }
6445c5cc28ffSAurelien Jarno 
6446d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT)
6447fbf59aadSRichard Henderson                  && qemu_log_in_addr_range(pc_start))) {
6448c60f599bSRichard Henderson         FILE *logfile = qemu_log_trylock();
644978b54858SRichard Henderson         if (logfile) {
645078b54858SRichard Henderson             fprintf(logfile, "OP after optimization and liveness analysis:\n");
6451b7a83ff8SRichard Henderson             tcg_dump_ops(s, logfile, true);
645278b54858SRichard Henderson             fprintf(logfile, "\n");
6453fc59d2d8SRobert Foley             qemu_log_unlock(logfile);
6454c896fe29Sbellard         }
645578b54858SRichard Henderson     }
6456c896fe29Sbellard 
645735abb009SRichard Henderson     /* Initialize goto_tb jump offsets. */
64583a50f424SRichard Henderson     tb->jmp_reset_offset[0] = TB_JMP_OFFSET_INVALID;
64593a50f424SRichard Henderson     tb->jmp_reset_offset[1] = TB_JMP_OFFSET_INVALID;
64609da6079bSRichard Henderson     tb->jmp_insn_offset[0] = TB_JMP_OFFSET_INVALID;
64619da6079bSRichard Henderson     tb->jmp_insn_offset[1] = TB_JMP_OFFSET_INVALID;
646235abb009SRichard Henderson 
6463c896fe29Sbellard     tcg_reg_alloc_start(s);
6464c896fe29Sbellard 
6465db0c51a3SRichard Henderson     /*
6466db0c51a3SRichard Henderson      * Reset the buffer pointers when restarting after overflow.
6467db0c51a3SRichard Henderson      * TODO: Move this into translate-all.c with the rest of the
6468db0c51a3SRichard Henderson      * buffer management.  Having only this done here is confusing.
6469db0c51a3SRichard Henderson      */
6470db0c51a3SRichard Henderson     s->code_buf = tcg_splitwx_to_rw(tb->tc.ptr);
6471db0c51a3SRichard Henderson     s->code_ptr = s->code_buf;
6472a7cfd751SRichard Henderson     s->data_gen_ptr = NULL;
6473c896fe29Sbellard 
64746001f772SLaurent Vivier     QSIMPLEQ_INIT(&s->ldst_labels);
647557a26946SRichard Henderson     s->pool_labels = NULL;
64769ecefc84SRichard Henderson 
6477747bd69dSRichard Henderson     start_words = s->insn_start_words;
6478747bd69dSRichard Henderson     s->gen_insn_data =
6479747bd69dSRichard Henderson         tcg_malloc(sizeof(uint64_t) * s->gen_tb->icount * start_words);
6480747bd69dSRichard Henderson 
64819358fbbfSRichard Henderson     tcg_out_tb_start(s);
64829358fbbfSRichard Henderson 
6483fca8a500SRichard Henderson     num_insns = -1;
648415fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
6485c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
6486b3db8758Sblueswir1 
6487c896fe29Sbellard         switch (opc) {
6488b5701261SRichard Henderson         case INDEX_op_mov:
6489d2fd745fSRichard Henderson         case INDEX_op_mov_vec:
6490dd186292SRichard Henderson             tcg_reg_alloc_mov(s, op);
6491c896fe29Sbellard             break;
6492bab1671fSRichard Henderson         case INDEX_op_dup_vec:
6493bab1671fSRichard Henderson             tcg_reg_alloc_dup(s, op);
6494bab1671fSRichard Henderson             break;
6495765b842aSRichard Henderson         case INDEX_op_insn_start:
6496fca8a500SRichard Henderson             if (num_insns >= 0) {
64979f754620SRichard Henderson                 size_t off = tcg_current_code_size(s);
64989f754620SRichard Henderson                 s->gen_insn_end_off[num_insns] = off;
64999f754620SRichard Henderson                 /* Assert that we do not overflow our stored offset.  */
65009f754620SRichard Henderson                 assert(s->gen_insn_end_off[num_insns] == off);
6501fca8a500SRichard Henderson             }
6502fca8a500SRichard Henderson             num_insns++;
6503747bd69dSRichard Henderson             for (i = 0; i < start_words; ++i) {
6504747bd69dSRichard Henderson                 s->gen_insn_data[num_insns * start_words + i] =
6505c9ad8d27SRichard Henderson                     tcg_get_insn_start_param(op, i);
6506bad729e2SRichard Henderson             }
6507c896fe29Sbellard             break;
65085ff9d6a4Sbellard         case INDEX_op_discard:
650943439139SRichard Henderson             temp_dead(s, arg_temp(op->args[0]));
65105ff9d6a4Sbellard             break;
6511c896fe29Sbellard         case INDEX_op_set_label:
6512e8996ee0Sbellard             tcg_reg_alloc_bb_end(s, s->reserved_regs);
651392ab8e7dSRichard Henderson             tcg_out_label(s, arg_label(op->args[0]));
6514c896fe29Sbellard             break;
6515c896fe29Sbellard         case INDEX_op_call:
6516dd186292SRichard Henderson             tcg_reg_alloc_call(s, op);
6517c45cb8bbSRichard Henderson             break;
6518b55a8d9dSRichard Henderson         case INDEX_op_exit_tb:
6519b55a8d9dSRichard Henderson             tcg_out_exit_tb(s, op->args[0]);
6520b55a8d9dSRichard Henderson             break;
6521cf7d6b8eSRichard Henderson         case INDEX_op_goto_tb:
6522cf7d6b8eSRichard Henderson             tcg_out_goto_tb(s, op->args[0]);
6523cf7d6b8eSRichard Henderson             break;
6524efe86b21SRichard Henderson         case INDEX_op_dup2_vec:
6525efe86b21SRichard Henderson             if (tcg_reg_alloc_dup2(s, op)) {
6526efe86b21SRichard Henderson                 break;
6527efe86b21SRichard Henderson             }
6528efe86b21SRichard Henderson             /* fall through */
6529c896fe29Sbellard         default:
653025c4d9ccSRichard Henderson             /* Sanity check that we've not introduced any unhandled opcodes. */
6531771a5925SRichard Henderson             tcg_debug_assert(tcg_op_supported(opc, TCGOP_TYPE(op),
6532771a5925SRichard Henderson                                               TCGOP_FLAGS(op)));
6533c896fe29Sbellard             /* Note: in order to speed up the code, it would be much
6534c896fe29Sbellard                faster to have specialized register allocator functions for
6535c896fe29Sbellard                some common argument patterns */
6536dd186292SRichard Henderson             tcg_reg_alloc_op(s, op);
6537c896fe29Sbellard             break;
6538c896fe29Sbellard         }
6539b125f9dcSRichard Henderson         /* Test for (pending) buffer overflow.  The assumption is that any
6540b125f9dcSRichard Henderson            one operation beginning below the high water mark cannot overrun
6541b125f9dcSRichard Henderson            the buffer completely.  Thus we can test for overflow after
6542b125f9dcSRichard Henderson            generating code without having to check during generation.  */
6543644da9b3SJohn Clarke         if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) {
6544b125f9dcSRichard Henderson             return -1;
6545b125f9dcSRichard Henderson         }
65466e6c4efeSRichard Henderson         /* Test for TB overflow, as seen by gen_insn_end_off.  */
65476e6c4efeSRichard Henderson         if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) {
65486e6c4efeSRichard Henderson             return -2;
65496e6c4efeSRichard Henderson         }
6550c896fe29Sbellard     }
6551747bd69dSRichard Henderson     tcg_debug_assert(num_insns + 1 == s->gen_tb->icount);
6552fca8a500SRichard Henderson     s->gen_insn_end_off[num_insns] = tcg_current_code_size(s);
6553c45cb8bbSRichard Henderson 
6554b76f0d8cSYeongkyoon Lee     /* Generate TB finalization at the end of block */
6555aeee05f5SRichard Henderson     i = tcg_out_ldst_finalize(s);
6556aeee05f5SRichard Henderson     if (i < 0) {
6557aeee05f5SRichard Henderson         return i;
655823dceda6SRichard Henderson     }
65591768987bSRichard Henderson     i = tcg_out_pool_finalize(s);
65601768987bSRichard Henderson     if (i < 0) {
65611768987bSRichard Henderson         return i;
656257a26946SRichard Henderson     }
65637ecd02a0SRichard Henderson     if (!tcg_resolve_relocs(s)) {
65647ecd02a0SRichard Henderson         return -2;
65657ecd02a0SRichard Henderson     }
6566c896fe29Sbellard 
6567df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
6568c896fe29Sbellard     /* flush instruction cache */
6569db0c51a3SRichard Henderson     flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf),
6570db0c51a3SRichard Henderson                         (uintptr_t)s->code_buf,
65711da8de39SRichard Henderson                         tcg_ptr_byte_diff(s->code_ptr, s->code_buf));
6572df5d2b16SRichard Henderson #endif
65732aeabc08SStefan Weil 
65741813e175SRichard Henderson     return tcg_current_code_size(s);
6575c896fe29Sbellard }
6576c896fe29Sbellard 
6577813da627SRichard Henderson #ifdef ELF_HOST_MACHINE
65785872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things:
65795872bbf2SRichard Henderson 
65805872bbf2SRichard Henderson    (1) Define ELF_HOST_MACHINE to indicate both what value to
65815872bbf2SRichard Henderson        put into the ELF image and to indicate support for the feature.
65825872bbf2SRichard Henderson 
65835872bbf2SRichard Henderson    (2) Define tcg_register_jit.  This should create a buffer containing
65845872bbf2SRichard Henderson        the contents of a .debug_frame section that describes the post-
65855872bbf2SRichard Henderson        prologue unwind info for the tcg machine.
65865872bbf2SRichard Henderson 
65875872bbf2SRichard Henderson    (3) Call tcg_register_jit_int, with the constructed .debug_frame.
65885872bbf2SRichard Henderson */
6589813da627SRichard Henderson 
6590813da627SRichard Henderson /* Begin GDB interface.  THE FOLLOWING MUST MATCH GDB DOCS.  */
6591813da627SRichard Henderson typedef enum {
6592813da627SRichard Henderson     JIT_NOACTION = 0,
6593813da627SRichard Henderson     JIT_REGISTER_FN,
6594813da627SRichard Henderson     JIT_UNREGISTER_FN
6595813da627SRichard Henderson } jit_actions_t;
6596813da627SRichard Henderson 
6597813da627SRichard Henderson struct jit_code_entry {
6598813da627SRichard Henderson     struct jit_code_entry *next_entry;
6599813da627SRichard Henderson     struct jit_code_entry *prev_entry;
6600813da627SRichard Henderson     const void *symfile_addr;
6601813da627SRichard Henderson     uint64_t symfile_size;
6602813da627SRichard Henderson };
6603813da627SRichard Henderson 
6604813da627SRichard Henderson struct jit_descriptor {
6605813da627SRichard Henderson     uint32_t version;
6606813da627SRichard Henderson     uint32_t action_flag;
6607813da627SRichard Henderson     struct jit_code_entry *relevant_entry;
6608813da627SRichard Henderson     struct jit_code_entry *first_entry;
6609813da627SRichard Henderson };
6610813da627SRichard Henderson 
6611813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline));
6612813da627SRichard Henderson void __jit_debug_register_code(void)
6613813da627SRichard Henderson {
6614813da627SRichard Henderson     asm("");
6615813da627SRichard Henderson }
6616813da627SRichard Henderson 
6617813da627SRichard Henderson /* Must statically initialize the version, because GDB may check
6618813da627SRichard Henderson    the version before we can set it.  */
6619813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
6620813da627SRichard Henderson 
6621813da627SRichard Henderson /* End GDB interface.  */
6622813da627SRichard Henderson 
6623813da627SRichard Henderson static int find_string(const char *strtab, const char *str)
6624813da627SRichard Henderson {
6625813da627SRichard Henderson     const char *p = strtab + 1;
6626813da627SRichard Henderson 
6627813da627SRichard Henderson     while (1) {
6628813da627SRichard Henderson         if (strcmp(p, str) == 0) {
6629813da627SRichard Henderson             return p - strtab;
6630813da627SRichard Henderson         }
6631813da627SRichard Henderson         p += strlen(p) + 1;
6632813da627SRichard Henderson     }
6633813da627SRichard Henderson }
6634813da627SRichard Henderson 
6635755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf_ptr, size_t buf_size,
66362c90784aSRichard Henderson                                  const void *debug_frame,
66372c90784aSRichard Henderson                                  size_t debug_frame_size)
6638813da627SRichard Henderson {
66395872bbf2SRichard Henderson     struct __attribute__((packed)) DebugInfo {
66405872bbf2SRichard Henderson         uint32_t  len;
66415872bbf2SRichard Henderson         uint16_t  version;
66425872bbf2SRichard Henderson         uint32_t  abbrev;
66435872bbf2SRichard Henderson         uint8_t   ptr_size;
66445872bbf2SRichard Henderson         uint8_t   cu_die;
66455872bbf2SRichard Henderson         uint16_t  cu_lang;
66465872bbf2SRichard Henderson         uintptr_t cu_low_pc;
66475872bbf2SRichard Henderson         uintptr_t cu_high_pc;
66485872bbf2SRichard Henderson         uint8_t   fn_die;
66495872bbf2SRichard Henderson         char      fn_name[16];
66505872bbf2SRichard Henderson         uintptr_t fn_low_pc;
66515872bbf2SRichard Henderson         uintptr_t fn_high_pc;
66525872bbf2SRichard Henderson         uint8_t   cu_eoc;
66535872bbf2SRichard Henderson     };
6654813da627SRichard Henderson 
6655813da627SRichard Henderson     struct ElfImage {
6656813da627SRichard Henderson         ElfW(Ehdr) ehdr;
6657813da627SRichard Henderson         ElfW(Phdr) phdr;
66585872bbf2SRichard Henderson         ElfW(Shdr) shdr[7];
66595872bbf2SRichard Henderson         ElfW(Sym)  sym[2];
66605872bbf2SRichard Henderson         struct DebugInfo di;
66615872bbf2SRichard Henderson         uint8_t    da[24];
66625872bbf2SRichard Henderson         char       str[80];
66635872bbf2SRichard Henderson     };
66645872bbf2SRichard Henderson 
66655872bbf2SRichard Henderson     struct ElfImage *img;
66665872bbf2SRichard Henderson 
66675872bbf2SRichard Henderson     static const struct ElfImage img_template = {
66685872bbf2SRichard Henderson         .ehdr = {
66695872bbf2SRichard Henderson             .e_ident[EI_MAG0] = ELFMAG0,
66705872bbf2SRichard Henderson             .e_ident[EI_MAG1] = ELFMAG1,
66715872bbf2SRichard Henderson             .e_ident[EI_MAG2] = ELFMAG2,
66725872bbf2SRichard Henderson             .e_ident[EI_MAG3] = ELFMAG3,
66735872bbf2SRichard Henderson             .e_ident[EI_CLASS] = ELF_CLASS,
66745872bbf2SRichard Henderson             .e_ident[EI_DATA] = ELF_DATA,
66755872bbf2SRichard Henderson             .e_ident[EI_VERSION] = EV_CURRENT,
66765872bbf2SRichard Henderson             .e_type = ET_EXEC,
66775872bbf2SRichard Henderson             .e_machine = ELF_HOST_MACHINE,
66785872bbf2SRichard Henderson             .e_version = EV_CURRENT,
66795872bbf2SRichard Henderson             .e_phoff = offsetof(struct ElfImage, phdr),
66805872bbf2SRichard Henderson             .e_shoff = offsetof(struct ElfImage, shdr),
66815872bbf2SRichard Henderson             .e_ehsize = sizeof(ElfW(Shdr)),
66825872bbf2SRichard Henderson             .e_phentsize = sizeof(ElfW(Phdr)),
66835872bbf2SRichard Henderson             .e_phnum = 1,
66845872bbf2SRichard Henderson             .e_shentsize = sizeof(ElfW(Shdr)),
66855872bbf2SRichard Henderson             .e_shnum = ARRAY_SIZE(img->shdr),
66865872bbf2SRichard Henderson             .e_shstrndx = ARRAY_SIZE(img->shdr) - 1,
6687abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS
6688abbb3eaeSRichard Henderson             .e_flags = ELF_HOST_FLAGS,
6689abbb3eaeSRichard Henderson #endif
6690abbb3eaeSRichard Henderson #ifdef ELF_OSABI
6691abbb3eaeSRichard Henderson             .e_ident[EI_OSABI] = ELF_OSABI,
6692abbb3eaeSRichard Henderson #endif
66935872bbf2SRichard Henderson         },
66945872bbf2SRichard Henderson         .phdr = {
66955872bbf2SRichard Henderson             .p_type = PT_LOAD,
66965872bbf2SRichard Henderson             .p_flags = PF_X,
66975872bbf2SRichard Henderson         },
66985872bbf2SRichard Henderson         .shdr = {
66995872bbf2SRichard Henderson             [0] = { .sh_type = SHT_NULL },
67005872bbf2SRichard Henderson             /* Trick: The contents of code_gen_buffer are not present in
67015872bbf2SRichard Henderson                this fake ELF file; that got allocated elsewhere.  Therefore
67025872bbf2SRichard Henderson                we mark .text as SHT_NOBITS (similar to .bss) so that readers
67035872bbf2SRichard Henderson                will not look for contents.  We can record any address.  */
67045872bbf2SRichard Henderson             [1] = { /* .text */
67055872bbf2SRichard Henderson                 .sh_type = SHT_NOBITS,
67065872bbf2SRichard Henderson                 .sh_flags = SHF_EXECINSTR | SHF_ALLOC,
67075872bbf2SRichard Henderson             },
67085872bbf2SRichard Henderson             [2] = { /* .debug_info */
67095872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
67105872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, di),
67115872bbf2SRichard Henderson                 .sh_size = sizeof(struct DebugInfo),
67125872bbf2SRichard Henderson             },
67135872bbf2SRichard Henderson             [3] = { /* .debug_abbrev */
67145872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
67155872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, da),
67165872bbf2SRichard Henderson                 .sh_size = sizeof(img->da),
67175872bbf2SRichard Henderson             },
67185872bbf2SRichard Henderson             [4] = { /* .debug_frame */
67195872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
67205872bbf2SRichard Henderson                 .sh_offset = sizeof(struct ElfImage),
67215872bbf2SRichard Henderson             },
67225872bbf2SRichard Henderson             [5] = { /* .symtab */
67235872bbf2SRichard Henderson                 .sh_type = SHT_SYMTAB,
67245872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, sym),
67255872bbf2SRichard Henderson                 .sh_size = sizeof(img->sym),
67265872bbf2SRichard Henderson                 .sh_info = 1,
67275872bbf2SRichard Henderson                 .sh_link = ARRAY_SIZE(img->shdr) - 1,
67285872bbf2SRichard Henderson                 .sh_entsize = sizeof(ElfW(Sym)),
67295872bbf2SRichard Henderson             },
67305872bbf2SRichard Henderson             [6] = { /* .strtab */
67315872bbf2SRichard Henderson                 .sh_type = SHT_STRTAB,
67325872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, str),
67335872bbf2SRichard Henderson                 .sh_size = sizeof(img->str),
67345872bbf2SRichard Henderson             }
67355872bbf2SRichard Henderson         },
67365872bbf2SRichard Henderson         .sym = {
67375872bbf2SRichard Henderson             [1] = { /* code_gen_buffer */
67385872bbf2SRichard Henderson                 .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC),
67395872bbf2SRichard Henderson                 .st_shndx = 1,
67405872bbf2SRichard Henderson             }
67415872bbf2SRichard Henderson         },
67425872bbf2SRichard Henderson         .di = {
67435872bbf2SRichard Henderson             .len = sizeof(struct DebugInfo) - 4,
67445872bbf2SRichard Henderson             .version = 2,
67455872bbf2SRichard Henderson             .ptr_size = sizeof(void *),
67465872bbf2SRichard Henderson             .cu_die = 1,
67475872bbf2SRichard Henderson             .cu_lang = 0x8001,  /* DW_LANG_Mips_Assembler */
67485872bbf2SRichard Henderson             .fn_die = 2,
67495872bbf2SRichard Henderson             .fn_name = "code_gen_buffer"
67505872bbf2SRichard Henderson         },
67515872bbf2SRichard Henderson         .da = {
67525872bbf2SRichard Henderson             1,          /* abbrev number (the cu) */
67535872bbf2SRichard Henderson             0x11, 1,    /* DW_TAG_compile_unit, has children */
67545872bbf2SRichard Henderson             0x13, 0x5,  /* DW_AT_language, DW_FORM_data2 */
67555872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
67565872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
67575872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
67585872bbf2SRichard Henderson             2,          /* abbrev number (the fn) */
67595872bbf2SRichard Henderson             0x2e, 0,    /* DW_TAG_subprogram, no children */
67605872bbf2SRichard Henderson             0x3, 0x8,   /* DW_AT_name, DW_FORM_string */
67615872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
67625872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
67635872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
67645872bbf2SRichard Henderson             0           /* no more abbrev */
67655872bbf2SRichard Henderson         },
67665872bbf2SRichard Henderson         .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0"
67675872bbf2SRichard Henderson                ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer",
6768813da627SRichard Henderson     };
6769813da627SRichard Henderson 
6770813da627SRichard Henderson     /* We only need a single jit entry; statically allocate it.  */
6771813da627SRichard Henderson     static struct jit_code_entry one_entry;
6772813da627SRichard Henderson 
67735872bbf2SRichard Henderson     uintptr_t buf = (uintptr_t)buf_ptr;
6774813da627SRichard Henderson     size_t img_size = sizeof(struct ElfImage) + debug_frame_size;
67752c90784aSRichard Henderson     DebugFrameHeader *dfh;
6776813da627SRichard Henderson 
67775872bbf2SRichard Henderson     img = g_malloc(img_size);
67785872bbf2SRichard Henderson     *img = img_template;
6779813da627SRichard Henderson 
67805872bbf2SRichard Henderson     img->phdr.p_vaddr = buf;
67815872bbf2SRichard Henderson     img->phdr.p_paddr = buf;
67825872bbf2SRichard Henderson     img->phdr.p_memsz = buf_size;
6783813da627SRichard Henderson 
67845872bbf2SRichard Henderson     img->shdr[1].sh_name = find_string(img->str, ".text");
67855872bbf2SRichard Henderson     img->shdr[1].sh_addr = buf;
67865872bbf2SRichard Henderson     img->shdr[1].sh_size = buf_size;
6787813da627SRichard Henderson 
67885872bbf2SRichard Henderson     img->shdr[2].sh_name = find_string(img->str, ".debug_info");
67895872bbf2SRichard Henderson     img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev");
67905872bbf2SRichard Henderson 
67915872bbf2SRichard Henderson     img->shdr[4].sh_name = find_string(img->str, ".debug_frame");
67925872bbf2SRichard Henderson     img->shdr[4].sh_size = debug_frame_size;
67935872bbf2SRichard Henderson 
67945872bbf2SRichard Henderson     img->shdr[5].sh_name = find_string(img->str, ".symtab");
67955872bbf2SRichard Henderson     img->shdr[6].sh_name = find_string(img->str, ".strtab");
67965872bbf2SRichard Henderson 
67975872bbf2SRichard Henderson     img->sym[1].st_name = find_string(img->str, "code_gen_buffer");
67985872bbf2SRichard Henderson     img->sym[1].st_value = buf;
67995872bbf2SRichard Henderson     img->sym[1].st_size = buf_size;
68005872bbf2SRichard Henderson 
68015872bbf2SRichard Henderson     img->di.cu_low_pc = buf;
680245aba097SRichard Henderson     img->di.cu_high_pc = buf + buf_size;
68035872bbf2SRichard Henderson     img->di.fn_low_pc = buf;
680445aba097SRichard Henderson     img->di.fn_high_pc = buf + buf_size;
6805813da627SRichard Henderson 
68062c90784aSRichard Henderson     dfh = (DebugFrameHeader *)(img + 1);
68072c90784aSRichard Henderson     memcpy(dfh, debug_frame, debug_frame_size);
68082c90784aSRichard Henderson     dfh->fde.func_start = buf;
68092c90784aSRichard Henderson     dfh->fde.func_len = buf_size;
68102c90784aSRichard Henderson 
6811813da627SRichard Henderson #ifdef DEBUG_JIT
6812813da627SRichard Henderson     /* Enable this block to be able to debug the ELF image file creation.
6813813da627SRichard Henderson        One can use readelf, objdump, or other inspection utilities.  */
6814813da627SRichard Henderson     {
6815eb6b2edfSBin Meng         g_autofree char *jit = g_strdup_printf("%s/qemu.jit", g_get_tmp_dir());
6816eb6b2edfSBin Meng         FILE *f = fopen(jit, "w+b");
6817813da627SRichard Henderson         if (f) {
68185872bbf2SRichard Henderson             if (fwrite(img, img_size, 1, f) != img_size) {
6819813da627SRichard Henderson                 /* Avoid stupid unused return value warning for fwrite.  */
6820813da627SRichard Henderson             }
6821813da627SRichard Henderson             fclose(f);
6822813da627SRichard Henderson         }
6823813da627SRichard Henderson     }
6824813da627SRichard Henderson #endif
6825813da627SRichard Henderson 
6826813da627SRichard Henderson     one_entry.symfile_addr = img;
6827813da627SRichard Henderson     one_entry.symfile_size = img_size;
6828813da627SRichard Henderson 
6829813da627SRichard Henderson     __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
6830813da627SRichard Henderson     __jit_debug_descriptor.relevant_entry = &one_entry;
6831813da627SRichard Henderson     __jit_debug_descriptor.first_entry = &one_entry;
6832813da627SRichard Henderson     __jit_debug_register_code();
6833813da627SRichard Henderson }
6834813da627SRichard Henderson #else
68355872bbf2SRichard Henderson /* No support for the feature.  Provide the entry point expected by exec.c,
68365872bbf2SRichard Henderson    and implement the internal function we declared earlier.  */
6837813da627SRichard Henderson 
6838755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size,
68392c90784aSRichard Henderson                                  const void *debug_frame,
68402c90784aSRichard Henderson                                  size_t debug_frame_size)
6841813da627SRichard Henderson {
6842813da627SRichard Henderson }
6843813da627SRichard Henderson 
6844755bf9e5SRichard Henderson void tcg_register_jit(const void *buf, size_t buf_size)
6845813da627SRichard Henderson {
6846813da627SRichard Henderson }
6847813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */
6848db432672SRichard Henderson 
6849db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec
6850db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...)
6851db432672SRichard Henderson {
6852db432672SRichard Henderson     g_assert_not_reached();
6853db432672SRichard Henderson }
6854db432672SRichard Henderson #endif
6855