xref: /qemu/tcg/tcg.c (revision 07d5d502f2b4a8eedda3c6bdfcab31dc36d1d1d5)
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 
98999ac4706SRichard Henderson typedef struct TCGOutOpBrcond {
99099ac4706SRichard Henderson     TCGOutOp base;
99199ac4706SRichard Henderson     void (*out_rr)(TCGContext *s, TCGType type, TCGCond cond,
99299ac4706SRichard Henderson                    TCGReg a1, TCGReg a2, TCGLabel *label);
99399ac4706SRichard Henderson     void (*out_ri)(TCGContext *s, TCGType type, TCGCond cond,
99499ac4706SRichard Henderson                    TCGReg a1, tcg_target_long a2, TCGLabel *label);
99599ac4706SRichard Henderson } TCGOutOpBrcond;
99699ac4706SRichard Henderson 
997f408df58SRichard Henderson typedef struct TCGOutOpBrcond2 {
998f408df58SRichard Henderson     TCGOutOp base;
999f408df58SRichard Henderson     void (*out)(TCGContext *s, TCGCond cond, TCGReg al, TCGReg ah,
1000f408df58SRichard Henderson                 TCGArg bl, bool const_bl,
1001f408df58SRichard Henderson                 TCGArg bh, bool const_bh, TCGLabel *l);
1002f408df58SRichard Henderson } TCGOutOpBrcond2;
1003f408df58SRichard Henderson 
10045fa8e138SRichard Henderson typedef struct TCGOutOpBswap {
10055fa8e138SRichard Henderson     TCGOutOp base;
10065fa8e138SRichard Henderson     void (*out_rr)(TCGContext *s, TCGType type,
10075fa8e138SRichard Henderson                    TCGReg a0, TCGReg a1, unsigned flags);
10085fa8e138SRichard Henderson } TCGOutOpBswap;
10095fa8e138SRichard Henderson 
1010d6cad9c9SRichard Henderson typedef struct TCGOutOpDivRem {
1011d6cad9c9SRichard Henderson     TCGOutOp base;
1012d6cad9c9SRichard Henderson     void (*out_rr01r)(TCGContext *s, TCGType type,
1013d6cad9c9SRichard Henderson                       TCGReg a0, TCGReg a1, TCGReg a4);
1014d6cad9c9SRichard Henderson } TCGOutOpDivRem;
1015d6cad9c9SRichard Henderson 
10165a4d034fSRichard Henderson typedef struct TCGOutOpExtract {
10175a4d034fSRichard Henderson     TCGOutOp base;
10185a4d034fSRichard Henderson     void (*out_rr)(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
10195a4d034fSRichard Henderson                    unsigned ofs, unsigned len);
10205a4d034fSRichard Henderson } TCGOutOpExtract;
10215a4d034fSRichard Henderson 
10221f406e46SRichard Henderson typedef struct TCGOutOpMovcond {
10231f406e46SRichard Henderson     TCGOutOp base;
10241f406e46SRichard Henderson     void (*out)(TCGContext *s, TCGType type, TCGCond cond,
10251f406e46SRichard Henderson                 TCGReg ret, TCGReg c1, TCGArg c2, bool const_c2,
10261f406e46SRichard Henderson                 TCGArg vt, bool const_vt, TCGArg vf, bool consf_vf);
10271f406e46SRichard Henderson } TCGOutOpMovcond;
10281f406e46SRichard Henderson 
10295641afdfSRichard Henderson typedef struct TCGOutOpMul2 {
10305641afdfSRichard Henderson     TCGOutOp base;
10315641afdfSRichard Henderson     void (*out_rrrr)(TCGContext *s, TCGType type,
10325641afdfSRichard Henderson                      TCGReg a0, TCGReg a1, TCGReg a2, TCGReg a3);
10335641afdfSRichard Henderson } TCGOutOpMul2;
10345641afdfSRichard Henderson 
1035e126a91cSRichard Henderson typedef struct TCGOutOpUnary {
1036e126a91cSRichard Henderson     TCGOutOp base;
1037e126a91cSRichard Henderson     void (*out_rr)(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1);
1038e126a91cSRichard Henderson } TCGOutOpUnary;
1039e126a91cSRichard Henderson 
10405a7b38c8SRichard Henderson typedef struct TCGOutOpSetcond {
10415a7b38c8SRichard Henderson     TCGOutOp base;
10425a7b38c8SRichard Henderson     void (*out_rrr)(TCGContext *s, TCGType type, TCGCond cond,
10435a7b38c8SRichard Henderson                     TCGReg ret, TCGReg a1, TCGReg a2);
10445a7b38c8SRichard Henderson     void (*out_rri)(TCGContext *s, TCGType type, TCGCond cond,
10455a7b38c8SRichard Henderson                     TCGReg ret, TCGReg a1, tcg_target_long a2);
10465a7b38c8SRichard Henderson } TCGOutOpSetcond;
10475a7b38c8SRichard Henderson 
1048e579c717SRichard Henderson typedef struct TCGOutOpSetcond2 {
1049e579c717SRichard Henderson     TCGOutOp base;
1050e579c717SRichard Henderson     void (*out)(TCGContext *s, TCGCond cond, TCGReg ret, TCGReg al, TCGReg ah,
1051e579c717SRichard Henderson                 TCGArg bl, bool const_bl, TCGArg bh, bool const_bh);
1052e579c717SRichard Henderson } TCGOutOpSetcond2;
1053e579c717SRichard Henderson 
10543f057e24SRichard Henderson typedef struct TCGOutOpSubtract {
10553f057e24SRichard Henderson     TCGOutOp base;
10563f057e24SRichard Henderson     void (*out_rrr)(TCGContext *s, TCGType type,
10573f057e24SRichard Henderson                     TCGReg a0, TCGReg a1, TCGReg a2);
10583f057e24SRichard Henderson     void (*out_rir)(TCGContext *s, TCGType type,
10593f057e24SRichard Henderson                     TCGReg a0, tcg_target_long a1, TCGReg a2);
10603f057e24SRichard Henderson } TCGOutOpSubtract;
10613f057e24SRichard Henderson 
1062139c1837SPaolo Bonzini #include "tcg-target.c.inc"
1063c896fe29Sbellard 
10647857ee11SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
10657857ee11SRichard Henderson /* Validate CPUTLBDescFast placement. */
10667857ee11SRichard Henderson QEMU_BUILD_BUG_ON((int)(offsetof(CPUNegativeOffsetState, tlb.f[0]) -
10677857ee11SRichard Henderson                         sizeof(CPUNegativeOffsetState))
10687857ee11SRichard Henderson                   < MIN_TLB_MASK_TABLE_OFS);
10697857ee11SRichard Henderson #endif
10707857ee11SRichard Henderson 
1071662cdbcfSRichard Henderson /*
1072662cdbcfSRichard Henderson  * Register V as the TCGOutOp for O.
1073662cdbcfSRichard Henderson  * This verifies that V is of type T, otherwise give a nice compiler error.
1074662cdbcfSRichard Henderson  * This prevents trivial mistakes within each arch/tcg-target.c.inc.
1075662cdbcfSRichard Henderson  */
1076662cdbcfSRichard Henderson #define OUTOP(O, T, V)  [O] = _Generic(V, T: &V.base)
1077662cdbcfSRichard Henderson 
10785500bd9eSRichard Henderson /* Register allocation descriptions for every TCGOpcode. */
10795500bd9eSRichard Henderson static const TCGOutOp * const all_outop[NB_OPS] = {
108079602f63SRichard Henderson     OUTOP(INDEX_op_add, TCGOutOpBinary, outop_add),
1081c3b920b3SRichard Henderson     OUTOP(INDEX_op_and, TCGOutOpBinary, outop_and),
108246f96bffSRichard Henderson     OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc),
1083b6d69fceSRichard Henderson     OUTOP(INDEX_op_brcond, TCGOutOpBrcond, outop_brcond),
10840dd07ee1SRichard Henderson     OUTOP(INDEX_op_bswap16, TCGOutOpBswap, outop_bswap16),
10857498d882SRichard Henderson     OUTOP(INDEX_op_bswap32, TCGOutOpBswap, outop_bswap32),
10865a5bb0a5SRichard Henderson     OUTOP(INDEX_op_clz, TCGOutOpBinary, outop_clz),
108797218ae9SRichard Henderson     OUTOP(INDEX_op_ctpop, TCGOutOpUnary, outop_ctpop),
1088c96447d8SRichard Henderson     OUTOP(INDEX_op_ctz, TCGOutOpBinary, outop_ctz),
1089b2c514f9SRichard Henderson     OUTOP(INDEX_op_divs, TCGOutOpBinary, outop_divs),
1090961b80aeSRichard Henderson     OUTOP(INDEX_op_divu, TCGOutOpBinary, outop_divu),
1091ee1805b9SRichard Henderson     OUTOP(INDEX_op_divs2, TCGOutOpDivRem, outop_divs2),
10928109598bSRichard Henderson     OUTOP(INDEX_op_divu2, TCGOutOpDivRem, outop_divu2),
10935c0968a7SRichard Henderson     OUTOP(INDEX_op_eqv, TCGOutOpBinary, outop_eqv),
1094*07d5d502SRichard Henderson     OUTOP(INDEX_op_extract, TCGOutOpExtract, outop_extract),
1095ea46c4bcSRichard Henderson     OUTOP(INDEX_op_movcond, TCGOutOpMovcond, outop_movcond),
1096d2c3ecadSRichard Henderson     OUTOP(INDEX_op_mul, TCGOutOpBinary, outop_mul),
1097bfe96480SRichard Henderson     OUTOP(INDEX_op_muls2, TCGOutOpMul2, outop_muls2),
1098c742824dSRichard Henderson     OUTOP(INDEX_op_mulsh, TCGOutOpBinary, outop_mulsh),
1099d776198cSRichard Henderson     OUTOP(INDEX_op_mulu2, TCGOutOpMul2, outop_mulu2),
1100aa28c9efSRichard Henderson     OUTOP(INDEX_op_muluh, TCGOutOpBinary, outop_muluh),
110159379a45SRichard Henderson     OUTOP(INDEX_op_nand, TCGOutOpBinary, outop_nand),
110269713587SRichard Henderson     OUTOP(INDEX_op_neg, TCGOutOpUnary, outop_neg),
1103a363e1e1SRichard Henderson     OUTOP(INDEX_op_negsetcond, TCGOutOpSetcond, outop_negsetcond),
11043a8c4e9eSRichard Henderson     OUTOP(INDEX_op_nor, TCGOutOpBinary, outop_nor),
11055c62d377SRichard Henderson     OUTOP(INDEX_op_not, TCGOutOpUnary, outop_not),
110649bd7514SRichard Henderson     OUTOP(INDEX_op_or, TCGOutOpBinary, outop_or),
11076aba25ebSRichard Henderson     OUTOP(INDEX_op_orc, TCGOutOpBinary, outop_orc),
11089a6bc184SRichard Henderson     OUTOP(INDEX_op_rems, TCGOutOpBinary, outop_rems),
1109cd9acd20SRichard Henderson     OUTOP(INDEX_op_remu, TCGOutOpBinary, outop_remu),
1110005a87e1SRichard Henderson     OUTOP(INDEX_op_rotl, TCGOutOpBinary, outop_rotl),
1111005a87e1SRichard Henderson     OUTOP(INDEX_op_rotr, TCGOutOpBinary, outop_rotr),
11123949f365SRichard Henderson     OUTOP(INDEX_op_sar, TCGOutOpBinary, outop_sar),
1113a363e1e1SRichard Henderson     OUTOP(INDEX_op_setcond, TCGOutOpSetcond, outop_setcond),
11146ca59451SRichard Henderson     OUTOP(INDEX_op_shl, TCGOutOpBinary, outop_shl),
111574dbd36fSRichard Henderson     OUTOP(INDEX_op_shr, TCGOutOpBinary, outop_shr),
111660f34f55SRichard Henderson     OUTOP(INDEX_op_sub, TCGOutOpSubtract, outop_sub),
1117fffd3dc9SRichard Henderson     OUTOP(INDEX_op_xor, TCGOutOpBinary, outop_xor),
1118f408df58SRichard Henderson 
1119f408df58SRichard Henderson #if TCG_TARGET_REG_BITS == 32
1120f408df58SRichard Henderson     OUTOP(INDEX_op_brcond2_i32, TCGOutOpBrcond2, outop_brcond2),
1121e579c717SRichard Henderson     OUTOP(INDEX_op_setcond2_i32, TCGOutOpSetcond2, outop_setcond2),
1122613b571cSRichard Henderson #else
11233ad5d4ccSRichard Henderson     OUTOP(INDEX_op_bswap64, TCGOutOpUnary, outop_bswap64),
1124f408df58SRichard Henderson #endif
11255500bd9eSRichard Henderson };
11265500bd9eSRichard Henderson 
1127662cdbcfSRichard Henderson #undef OUTOP
1128662cdbcfSRichard Henderson 
1129e8feb96fSEmilio G. Cota /*
11303468b59eSEmilio G. Cota  * All TCG threads except the parent (i.e. the one that called tcg_context_init
11313468b59eSEmilio G. Cota  * and registered the target's TCG globals) must register with this function
11323468b59eSEmilio G. Cota  * before initiating translation.
11333468b59eSEmilio G. Cota  *
11343468b59eSEmilio G. Cota  * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation
11353468b59eSEmilio G. Cota  * of tcg_region_init() for the reasoning behind this.
11363468b59eSEmilio G. Cota  *
11377893e42dSPhilippe Mathieu-Daudé  * In system-mode each caller registers its context in tcg_ctxs[]. Note that in
11387893e42dSPhilippe Mathieu-Daudé  * system-mode tcg_ctxs[] does not track tcg_ctx_init, since the initial context
11393468b59eSEmilio G. Cota  * is not used anymore for translation once this function is called.
11403468b59eSEmilio G. Cota  *
11417893e42dSPhilippe Mathieu-Daudé  * Not tracking tcg_init_ctx in tcg_ctxs[] in system-mode keeps code that
11427893e42dSPhilippe Mathieu-Daudé  * iterates over the array (e.g. tcg_code_size() the same for both system/user
11437893e42dSPhilippe Mathieu-Daudé  * modes.
11443468b59eSEmilio G. Cota  */
11453468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
11463468b59eSEmilio G. Cota void tcg_register_thread(void)
11473468b59eSEmilio G. Cota {
11483468b59eSEmilio G. Cota     tcg_ctx = &tcg_init_ctx;
11493468b59eSEmilio G. Cota }
11503468b59eSEmilio G. Cota #else
11513468b59eSEmilio G. Cota void tcg_register_thread(void)
11523468b59eSEmilio G. Cota {
11533468b59eSEmilio G. Cota     TCGContext *s = g_malloc(sizeof(*s));
11543468b59eSEmilio G. Cota     unsigned int i, n;
11553468b59eSEmilio G. Cota 
11563468b59eSEmilio G. Cota     *s = tcg_init_ctx;
11573468b59eSEmilio G. Cota 
11583468b59eSEmilio G. Cota     /* Relink mem_base.  */
11593468b59eSEmilio G. Cota     for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) {
11603468b59eSEmilio G. Cota         if (tcg_init_ctx.temps[i].mem_base) {
11613468b59eSEmilio G. Cota             ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps;
11623468b59eSEmilio G. Cota             tcg_debug_assert(b >= 0 && b < n);
11633468b59eSEmilio G. Cota             s->temps[i].mem_base = &s->temps[b];
11643468b59eSEmilio G. Cota         }
11653468b59eSEmilio G. Cota     }
11663468b59eSEmilio G. Cota 
11673468b59eSEmilio G. Cota     /* Claim an entry in tcg_ctxs */
11680e2d61cfSRichard Henderson     n = qatomic_fetch_inc(&tcg_cur_ctxs);
11690e2d61cfSRichard Henderson     g_assert(n < tcg_max_ctxs);
1170d73415a3SStefan Hajnoczi     qatomic_set(&tcg_ctxs[n], s);
11713468b59eSEmilio G. Cota 
117238b47b19SEmilio G. Cota     if (n > 0) {
1173bf042e8eSRichard Henderson         tcg_region_initial_alloc(s);
117438b47b19SEmilio G. Cota     }
117538b47b19SEmilio G. Cota 
11763468b59eSEmilio G. Cota     tcg_ctx = s;
11773468b59eSEmilio G. Cota }
11783468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */
11793468b59eSEmilio G. Cota 
1180c896fe29Sbellard /* pool based memory allocation */
1181c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size)
1182c896fe29Sbellard {
1183c896fe29Sbellard     TCGPool *p;
1184c896fe29Sbellard     int pool_size;
1185c896fe29Sbellard 
1186c896fe29Sbellard     if (size > TCG_POOL_CHUNK_SIZE) {
1187c896fe29Sbellard         /* big malloc: insert a new pool (XXX: could optimize) */
11887267c094SAnthony Liguori         p = g_malloc(sizeof(TCGPool) + size);
1189c896fe29Sbellard         p->size = size;
11904055299eSKirill Batuzov         p->next = s->pool_first_large;
11914055299eSKirill Batuzov         s->pool_first_large = p;
11924055299eSKirill Batuzov         return p->data;
1193c896fe29Sbellard     } else {
1194c896fe29Sbellard         p = s->pool_current;
1195c896fe29Sbellard         if (!p) {
1196c896fe29Sbellard             p = s->pool_first;
1197c896fe29Sbellard             if (!p)
1198c896fe29Sbellard                 goto new_pool;
1199c896fe29Sbellard         } else {
1200c896fe29Sbellard             if (!p->next) {
1201c896fe29Sbellard             new_pool:
1202c896fe29Sbellard                 pool_size = TCG_POOL_CHUNK_SIZE;
12037267c094SAnthony Liguori                 p = g_malloc(sizeof(TCGPool) + pool_size);
1204c896fe29Sbellard                 p->size = pool_size;
1205c896fe29Sbellard                 p->next = NULL;
1206a813e36fSRichard Henderson                 if (s->pool_current) {
1207c896fe29Sbellard                     s->pool_current->next = p;
1208a813e36fSRichard Henderson                 } else {
1209c896fe29Sbellard                     s->pool_first = p;
1210a813e36fSRichard Henderson                 }
1211c896fe29Sbellard             } else {
1212c896fe29Sbellard                 p = p->next;
1213c896fe29Sbellard             }
1214c896fe29Sbellard         }
1215c896fe29Sbellard     }
1216c896fe29Sbellard     s->pool_current = p;
1217c896fe29Sbellard     s->pool_cur = p->data + size;
1218c896fe29Sbellard     s->pool_end = p->data + p->size;
1219c896fe29Sbellard     return p->data;
1220c896fe29Sbellard }
1221c896fe29Sbellard 
1222c896fe29Sbellard void tcg_pool_reset(TCGContext *s)
1223c896fe29Sbellard {
12244055299eSKirill Batuzov     TCGPool *p, *t;
12254055299eSKirill Batuzov     for (p = s->pool_first_large; p; p = t) {
12264055299eSKirill Batuzov         t = p->next;
12274055299eSKirill Batuzov         g_free(p);
12284055299eSKirill Batuzov     }
12294055299eSKirill Batuzov     s->pool_first_large = NULL;
1230c896fe29Sbellard     s->pool_cur = s->pool_end = NULL;
1231c896fe29Sbellard     s->pool_current = NULL;
1232c896fe29Sbellard }
1233c896fe29Sbellard 
12348429a1caSRichard Henderson /*
12358429a1caSRichard Henderson  * Create TCGHelperInfo structures for "tcg/tcg-ldst.h" functions,
12368429a1caSRichard Henderson  * akin to what "exec/helper-tcg.h" does with DEF_HELPER_FLAGS_N.
12378429a1caSRichard Henderson  * We only use these for layout in tcg_out_ld_helper_ret and
12388429a1caSRichard Henderson  * tcg_out_st_helper_args, and share them between several of
12398429a1caSRichard Henderson  * the helpers, with the end result that it's easier to build manually.
12408429a1caSRichard Henderson  */
12418429a1caSRichard Henderson 
12428429a1caSRichard Henderson #if TCG_TARGET_REG_BITS == 32
12438429a1caSRichard Henderson # define dh_typecode_ttl  dh_typecode_i32
12448429a1caSRichard Henderson #else
12458429a1caSRichard Henderson # define dh_typecode_ttl  dh_typecode_i64
12468429a1caSRichard Henderson #endif
12478429a1caSRichard Henderson 
12488429a1caSRichard Henderson static TCGHelperInfo info_helper_ld32_mmu = {
12498429a1caSRichard Henderson     .flags = TCG_CALL_NO_WG,
12508429a1caSRichard Henderson     .typemask = dh_typemask(ttl, 0)  /* return tcg_target_ulong */
12518429a1caSRichard Henderson               | dh_typemask(env, 1)
125224e46e6cSRichard Henderson               | dh_typemask(i64, 2)  /* uint64_t addr */
12538429a1caSRichard Henderson               | dh_typemask(i32, 3)  /* unsigned oi */
12548429a1caSRichard Henderson               | dh_typemask(ptr, 4)  /* uintptr_t ra */
12558429a1caSRichard Henderson };
12568429a1caSRichard Henderson 
12578429a1caSRichard Henderson static TCGHelperInfo info_helper_ld64_mmu = {
12588429a1caSRichard Henderson     .flags = TCG_CALL_NO_WG,
12598429a1caSRichard Henderson     .typemask = dh_typemask(i64, 0)  /* return uint64_t */
12608429a1caSRichard Henderson               | dh_typemask(env, 1)
126124e46e6cSRichard Henderson               | dh_typemask(i64, 2)  /* uint64_t addr */
12628429a1caSRichard Henderson               | dh_typemask(i32, 3)  /* unsigned oi */
12638429a1caSRichard Henderson               | dh_typemask(ptr, 4)  /* uintptr_t ra */
12648429a1caSRichard Henderson };
12658429a1caSRichard Henderson 
1266ebebea53SRichard Henderson static TCGHelperInfo info_helper_ld128_mmu = {
1267ebebea53SRichard Henderson     .flags = TCG_CALL_NO_WG,
1268ebebea53SRichard Henderson     .typemask = dh_typemask(i128, 0) /* return Int128 */
1269ebebea53SRichard Henderson               | dh_typemask(env, 1)
127024e46e6cSRichard Henderson               | dh_typemask(i64, 2)  /* uint64_t addr */
1271ebebea53SRichard Henderson               | dh_typemask(i32, 3)  /* unsigned oi */
1272ebebea53SRichard Henderson               | dh_typemask(ptr, 4)  /* uintptr_t ra */
1273ebebea53SRichard Henderson };
1274ebebea53SRichard Henderson 
12758429a1caSRichard Henderson static TCGHelperInfo info_helper_st32_mmu = {
12768429a1caSRichard Henderson     .flags = TCG_CALL_NO_WG,
12778429a1caSRichard Henderson     .typemask = dh_typemask(void, 0)
12788429a1caSRichard Henderson               | dh_typemask(env, 1)
127924e46e6cSRichard Henderson               | dh_typemask(i64, 2)  /* uint64_t addr */
12808429a1caSRichard Henderson               | dh_typemask(i32, 3)  /* uint32_t data */
12818429a1caSRichard Henderson               | dh_typemask(i32, 4)  /* unsigned oi */
12828429a1caSRichard Henderson               | dh_typemask(ptr, 5)  /* uintptr_t ra */
12838429a1caSRichard Henderson };
12848429a1caSRichard Henderson 
12858429a1caSRichard Henderson static TCGHelperInfo info_helper_st64_mmu = {
12868429a1caSRichard Henderson     .flags = TCG_CALL_NO_WG,
12878429a1caSRichard Henderson     .typemask = dh_typemask(void, 0)
12888429a1caSRichard Henderson               | dh_typemask(env, 1)
128924e46e6cSRichard Henderson               | dh_typemask(i64, 2)  /* uint64_t addr */
12908429a1caSRichard Henderson               | dh_typemask(i64, 3)  /* uint64_t data */
12918429a1caSRichard Henderson               | dh_typemask(i32, 4)  /* unsigned oi */
12928429a1caSRichard Henderson               | dh_typemask(ptr, 5)  /* uintptr_t ra */
12938429a1caSRichard Henderson };
12948429a1caSRichard Henderson 
1295ebebea53SRichard Henderson static TCGHelperInfo info_helper_st128_mmu = {
1296ebebea53SRichard Henderson     .flags = TCG_CALL_NO_WG,
1297ebebea53SRichard Henderson     .typemask = dh_typemask(void, 0)
1298ebebea53SRichard Henderson               | dh_typemask(env, 1)
129924e46e6cSRichard Henderson               | dh_typemask(i64, 2)  /* uint64_t addr */
1300ebebea53SRichard Henderson               | dh_typemask(i128, 3) /* Int128 data */
1301ebebea53SRichard Henderson               | dh_typemask(i32, 4)  /* unsigned oi */
1302ebebea53SRichard Henderson               | dh_typemask(ptr, 5)  /* uintptr_t ra */
1303ebebea53SRichard Henderson };
1304ebebea53SRichard Henderson 
130522f15579SRichard Henderson #ifdef CONFIG_TCG_INTERPRETER
1306c6ef8c7bSPhilippe Mathieu-Daudé static ffi_type *typecode_to_ffi(int argmask)
1307c6ef8c7bSPhilippe Mathieu-Daudé {
1308e9709e17SRichard Henderson     /*
1309e9709e17SRichard Henderson      * libffi does not support __int128_t, so we have forced Int128
1310e9709e17SRichard Henderson      * to use the structure definition instead of the builtin type.
1311e9709e17SRichard Henderson      */
1312e9709e17SRichard Henderson     static ffi_type *ffi_type_i128_elements[3] = {
1313e9709e17SRichard Henderson         &ffi_type_uint64,
1314e9709e17SRichard Henderson         &ffi_type_uint64,
1315e9709e17SRichard Henderson         NULL
1316e9709e17SRichard Henderson     };
1317e9709e17SRichard Henderson     static ffi_type ffi_type_i128 = {
1318e9709e17SRichard Henderson         .size = 16,
1319e9709e17SRichard Henderson         .alignment = __alignof__(Int128),
1320e9709e17SRichard Henderson         .type = FFI_TYPE_STRUCT,
1321e9709e17SRichard Henderson         .elements = ffi_type_i128_elements,
1322e9709e17SRichard Henderson     };
1323e9709e17SRichard Henderson 
1324c6ef8c7bSPhilippe Mathieu-Daudé     switch (argmask) {
1325c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_void:
1326c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_void;
1327c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_i32:
1328c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_uint32;
1329c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_s32:
1330c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_sint32;
1331c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_i64:
1332c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_uint64;
1333c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_s64:
1334c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_sint64;
1335c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_ptr:
1336c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_pointer;
1337e9709e17SRichard Henderson     case dh_typecode_i128:
1338e9709e17SRichard Henderson         return &ffi_type_i128;
1339c6ef8c7bSPhilippe Mathieu-Daudé     }
1340c6ef8c7bSPhilippe Mathieu-Daudé     g_assert_not_reached();
1341c6ef8c7bSPhilippe Mathieu-Daudé }
13420c22e176SPhilippe Mathieu-Daudé 
1343d53106c9SRichard Henderson static ffi_cif *init_ffi_layout(TCGHelperInfo *info)
13440c22e176SPhilippe Mathieu-Daudé {
1345f9c4bb80SRichard Henderson     unsigned typemask = info->typemask;
13460c22e176SPhilippe Mathieu-Daudé     struct {
13470c22e176SPhilippe Mathieu-Daudé         ffi_cif cif;
13480c22e176SPhilippe Mathieu-Daudé         ffi_type *args[];
13490c22e176SPhilippe Mathieu-Daudé     } *ca;
13500c22e176SPhilippe Mathieu-Daudé     ffi_status status;
13510c22e176SPhilippe Mathieu-Daudé     int nargs;
13520c22e176SPhilippe Mathieu-Daudé 
13530c22e176SPhilippe Mathieu-Daudé     /* Ignoring the return type, find the last non-zero field. */
13540c22e176SPhilippe Mathieu-Daudé     nargs = 32 - clz32(typemask >> 3);
13550c22e176SPhilippe Mathieu-Daudé     nargs = DIV_ROUND_UP(nargs, 3);
1356e9709e17SRichard Henderson     assert(nargs <= MAX_CALL_IARGS);
13570c22e176SPhilippe Mathieu-Daudé 
13580c22e176SPhilippe Mathieu-Daudé     ca = g_malloc0(sizeof(*ca) + nargs * sizeof(ffi_type *));
13590c22e176SPhilippe Mathieu-Daudé     ca->cif.rtype = typecode_to_ffi(typemask & 7);
13600c22e176SPhilippe Mathieu-Daudé     ca->cif.nargs = nargs;
13610c22e176SPhilippe Mathieu-Daudé 
13620c22e176SPhilippe Mathieu-Daudé     if (nargs != 0) {
13630c22e176SPhilippe Mathieu-Daudé         ca->cif.arg_types = ca->args;
13640c22e176SPhilippe Mathieu-Daudé         for (int j = 0; j < nargs; ++j) {
13650c22e176SPhilippe Mathieu-Daudé             int typecode = extract32(typemask, (j + 1) * 3, 3);
13660c22e176SPhilippe Mathieu-Daudé             ca->args[j] = typecode_to_ffi(typecode);
13670c22e176SPhilippe Mathieu-Daudé         }
13680c22e176SPhilippe Mathieu-Daudé     }
13690c22e176SPhilippe Mathieu-Daudé 
13700c22e176SPhilippe Mathieu-Daudé     status = ffi_prep_cif(&ca->cif, FFI_DEFAULT_ABI, nargs,
13710c22e176SPhilippe Mathieu-Daudé                           ca->cif.rtype, ca->cif.arg_types);
13720c22e176SPhilippe Mathieu-Daudé     assert(status == FFI_OK);
13730c22e176SPhilippe Mathieu-Daudé 
1374d53106c9SRichard Henderson     return &ca->cif;
13750c22e176SPhilippe Mathieu-Daudé }
1376f9c4bb80SRichard Henderson 
1377d53106c9SRichard Henderson #define HELPER_INFO_INIT(I)      (&(I)->cif)
1378d53106c9SRichard Henderson #define HELPER_INFO_INIT_VAL(I)  init_ffi_layout(I)
1379d53106c9SRichard Henderson #else
1380d53106c9SRichard Henderson #define HELPER_INFO_INIT(I)      (&(I)->init)
1381d53106c9SRichard Henderson #define HELPER_INFO_INIT_VAL(I)  1
13820c22e176SPhilippe Mathieu-Daudé #endif /* CONFIG_TCG_INTERPRETER */
138322f15579SRichard Henderson 
1384338b61e9SRichard Henderson static inline bool arg_slot_reg_p(unsigned arg_slot)
1385338b61e9SRichard Henderson {
1386338b61e9SRichard Henderson     /*
1387338b61e9SRichard Henderson      * Split the sizeof away from the comparison to avoid Werror from
1388338b61e9SRichard Henderson      * "unsigned < 0 is always false", when iarg_regs is empty.
1389338b61e9SRichard Henderson      */
1390338b61e9SRichard Henderson     unsigned nreg = ARRAY_SIZE(tcg_target_call_iarg_regs);
1391338b61e9SRichard Henderson     return arg_slot < nreg;
1392338b61e9SRichard Henderson }
1393338b61e9SRichard Henderson 
1394d78e4a4fSRichard Henderson static inline int arg_slot_stk_ofs(unsigned arg_slot)
1395d78e4a4fSRichard Henderson {
1396d78e4a4fSRichard Henderson     unsigned max = TCG_STATIC_CALL_ARGS_SIZE / sizeof(tcg_target_long);
1397d78e4a4fSRichard Henderson     unsigned stk_slot = arg_slot - ARRAY_SIZE(tcg_target_call_iarg_regs);
1398d78e4a4fSRichard Henderson 
1399d78e4a4fSRichard Henderson     tcg_debug_assert(stk_slot < max);
1400d78e4a4fSRichard Henderson     return TCG_TARGET_CALL_STACK_OFFSET + stk_slot * sizeof(tcg_target_long);
1401d78e4a4fSRichard Henderson }
1402d78e4a4fSRichard Henderson 
140339004a71SRichard Henderson typedef struct TCGCumulativeArgs {
140439004a71SRichard Henderson     int arg_idx;                /* tcg_gen_callN args[] */
140539004a71SRichard Henderson     int info_in_idx;            /* TCGHelperInfo in[] */
140639004a71SRichard Henderson     int arg_slot;               /* regs+stack slot */
140739004a71SRichard Henderson     int ref_slot;               /* stack slots for references */
140839004a71SRichard Henderson } TCGCumulativeArgs;
140939004a71SRichard Henderson 
141039004a71SRichard Henderson static void layout_arg_even(TCGCumulativeArgs *cum)
141139004a71SRichard Henderson {
141239004a71SRichard Henderson     cum->arg_slot += cum->arg_slot & 1;
141339004a71SRichard Henderson }
141439004a71SRichard Henderson 
141539004a71SRichard Henderson static void layout_arg_1(TCGCumulativeArgs *cum, TCGHelperInfo *info,
141639004a71SRichard Henderson                          TCGCallArgumentKind kind)
141739004a71SRichard Henderson {
141839004a71SRichard Henderson     TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx];
141939004a71SRichard Henderson 
142039004a71SRichard Henderson     *loc = (TCGCallArgumentLoc){
142139004a71SRichard Henderson         .kind = kind,
142239004a71SRichard Henderson         .arg_idx = cum->arg_idx,
142339004a71SRichard Henderson         .arg_slot = cum->arg_slot,
142439004a71SRichard Henderson     };
142539004a71SRichard Henderson     cum->info_in_idx++;
142639004a71SRichard Henderson     cum->arg_slot++;
142739004a71SRichard Henderson }
142839004a71SRichard Henderson 
142939004a71SRichard Henderson static void layout_arg_normal_n(TCGCumulativeArgs *cum,
143039004a71SRichard Henderson                                 TCGHelperInfo *info, int n)
143139004a71SRichard Henderson {
143239004a71SRichard Henderson     TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx];
143339004a71SRichard Henderson 
143439004a71SRichard Henderson     for (int i = 0; i < n; ++i) {
143539004a71SRichard Henderson         /* Layout all using the same arg_idx, adjusting the subindex. */
143639004a71SRichard Henderson         loc[i] = (TCGCallArgumentLoc){
143739004a71SRichard Henderson             .kind = TCG_CALL_ARG_NORMAL,
143839004a71SRichard Henderson             .arg_idx = cum->arg_idx,
143939004a71SRichard Henderson             .tmp_subindex = i,
144039004a71SRichard Henderson             .arg_slot = cum->arg_slot + i,
144139004a71SRichard Henderson         };
144239004a71SRichard Henderson     }
144339004a71SRichard Henderson     cum->info_in_idx += n;
144439004a71SRichard Henderson     cum->arg_slot += n;
144539004a71SRichard Henderson }
144639004a71SRichard Henderson 
1447313bdea8SRichard Henderson static void layout_arg_by_ref(TCGCumulativeArgs *cum, TCGHelperInfo *info)
1448313bdea8SRichard Henderson {
1449313bdea8SRichard Henderson     TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx];
1450313bdea8SRichard Henderson     int n = 128 / TCG_TARGET_REG_BITS;
1451313bdea8SRichard Henderson 
1452313bdea8SRichard Henderson     /* The first subindex carries the pointer. */
1453313bdea8SRichard Henderson     layout_arg_1(cum, info, TCG_CALL_ARG_BY_REF);
1454313bdea8SRichard Henderson 
1455313bdea8SRichard Henderson     /*
1456313bdea8SRichard Henderson      * The callee is allowed to clobber memory associated with
1457313bdea8SRichard Henderson      * structure pass by-reference.  Therefore we must make copies.
1458313bdea8SRichard Henderson      * Allocate space from "ref_slot", which will be adjusted to
1459313bdea8SRichard Henderson      * follow the parameters on the stack.
1460313bdea8SRichard Henderson      */
1461313bdea8SRichard Henderson     loc[0].ref_slot = cum->ref_slot;
1462313bdea8SRichard Henderson 
1463313bdea8SRichard Henderson     /*
1464313bdea8SRichard Henderson      * Subsequent words also go into the reference slot, but
1465313bdea8SRichard Henderson      * do not accumulate into the regular arguments.
1466313bdea8SRichard Henderson      */
1467313bdea8SRichard Henderson     for (int i = 1; i < n; ++i) {
1468313bdea8SRichard Henderson         loc[i] = (TCGCallArgumentLoc){
1469313bdea8SRichard Henderson             .kind = TCG_CALL_ARG_BY_REF_N,
1470313bdea8SRichard Henderson             .arg_idx = cum->arg_idx,
1471313bdea8SRichard Henderson             .tmp_subindex = i,
1472313bdea8SRichard Henderson             .ref_slot = cum->ref_slot + i,
1473313bdea8SRichard Henderson         };
1474313bdea8SRichard Henderson     }
1475e18ed26cSRichard Henderson     cum->info_in_idx += n - 1;  /* i=0 accounted for in layout_arg_1 */
1476313bdea8SRichard Henderson     cum->ref_slot += n;
1477313bdea8SRichard Henderson }
1478313bdea8SRichard Henderson 
147939004a71SRichard Henderson static void init_call_layout(TCGHelperInfo *info)
148039004a71SRichard Henderson {
148139004a71SRichard Henderson     int max_reg_slots = ARRAY_SIZE(tcg_target_call_iarg_regs);
148239004a71SRichard Henderson     int max_stk_slots = TCG_STATIC_CALL_ARGS_SIZE / sizeof(tcg_target_long);
148339004a71SRichard Henderson     unsigned typemask = info->typemask;
148439004a71SRichard Henderson     unsigned typecode;
148539004a71SRichard Henderson     TCGCumulativeArgs cum = { };
148639004a71SRichard Henderson 
148739004a71SRichard Henderson     /*
148839004a71SRichard Henderson      * Parse and place any function return value.
148939004a71SRichard Henderson      */
149039004a71SRichard Henderson     typecode = typemask & 7;
149139004a71SRichard Henderson     switch (typecode) {
149239004a71SRichard Henderson     case dh_typecode_void:
149339004a71SRichard Henderson         info->nr_out = 0;
149439004a71SRichard Henderson         break;
149539004a71SRichard Henderson     case dh_typecode_i32:
149639004a71SRichard Henderson     case dh_typecode_s32:
149739004a71SRichard Henderson     case dh_typecode_ptr:
149839004a71SRichard Henderson         info->nr_out = 1;
149939004a71SRichard Henderson         info->out_kind = TCG_CALL_RET_NORMAL;
150039004a71SRichard Henderson         break;
150139004a71SRichard Henderson     case dh_typecode_i64:
150239004a71SRichard Henderson     case dh_typecode_s64:
150339004a71SRichard Henderson         info->nr_out = 64 / TCG_TARGET_REG_BITS;
150439004a71SRichard Henderson         info->out_kind = TCG_CALL_RET_NORMAL;
15055e3d0c19SRichard Henderson         /* Query the last register now to trigger any assert early. */
15065e3d0c19SRichard Henderson         tcg_target_call_oarg_reg(info->out_kind, info->nr_out - 1);
1507466d3759SRichard Henderson         break;
1508466d3759SRichard Henderson     case dh_typecode_i128:
1509466d3759SRichard Henderson         info->nr_out = 128 / TCG_TARGET_REG_BITS;
15105427a9a7SRichard Henderson         info->out_kind = TCG_TARGET_CALL_RET_I128;
15115427a9a7SRichard Henderson         switch (TCG_TARGET_CALL_RET_I128) {
1512466d3759SRichard Henderson         case TCG_CALL_RET_NORMAL:
15135e3d0c19SRichard Henderson             /* Query the last register now to trigger any assert early. */
15145e3d0c19SRichard Henderson             tcg_target_call_oarg_reg(info->out_kind, info->nr_out - 1);
1515466d3759SRichard Henderson             break;
1516c6556aa0SRichard Henderson         case TCG_CALL_RET_BY_VEC:
1517c6556aa0SRichard Henderson             /* Query the single register now to trigger any assert early. */
1518c6556aa0SRichard Henderson             tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0);
1519c6556aa0SRichard Henderson             break;
1520313bdea8SRichard Henderson         case TCG_CALL_RET_BY_REF:
1521313bdea8SRichard Henderson             /*
1522313bdea8SRichard Henderson              * Allocate the first argument to the output.
1523313bdea8SRichard Henderson              * We don't need to store this anywhere, just make it
1524313bdea8SRichard Henderson              * unavailable for use in the input loop below.
1525313bdea8SRichard Henderson              */
1526313bdea8SRichard Henderson             cum.arg_slot = 1;
1527313bdea8SRichard Henderson             break;
1528466d3759SRichard Henderson         default:
1529466d3759SRichard Henderson             qemu_build_not_reached();
1530466d3759SRichard Henderson         }
153139004a71SRichard Henderson         break;
153239004a71SRichard Henderson     default:
153339004a71SRichard Henderson         g_assert_not_reached();
153439004a71SRichard Henderson     }
153539004a71SRichard Henderson 
153639004a71SRichard Henderson     /*
153739004a71SRichard Henderson      * Parse and place function arguments.
153839004a71SRichard Henderson      */
153939004a71SRichard Henderson     for (typemask >>= 3; typemask; typemask >>= 3, cum.arg_idx++) {
154039004a71SRichard Henderson         TCGCallArgumentKind kind;
154139004a71SRichard Henderson         TCGType type;
154239004a71SRichard Henderson 
154339004a71SRichard Henderson         typecode = typemask & 7;
154439004a71SRichard Henderson         switch (typecode) {
154539004a71SRichard Henderson         case dh_typecode_i32:
154639004a71SRichard Henderson         case dh_typecode_s32:
154739004a71SRichard Henderson             type = TCG_TYPE_I32;
154839004a71SRichard Henderson             break;
154939004a71SRichard Henderson         case dh_typecode_i64:
155039004a71SRichard Henderson         case dh_typecode_s64:
155139004a71SRichard Henderson             type = TCG_TYPE_I64;
155239004a71SRichard Henderson             break;
155339004a71SRichard Henderson         case dh_typecode_ptr:
155439004a71SRichard Henderson             type = TCG_TYPE_PTR;
155539004a71SRichard Henderson             break;
1556466d3759SRichard Henderson         case dh_typecode_i128:
1557466d3759SRichard Henderson             type = TCG_TYPE_I128;
1558466d3759SRichard Henderson             break;
155939004a71SRichard Henderson         default:
156039004a71SRichard Henderson             g_assert_not_reached();
156139004a71SRichard Henderson         }
156239004a71SRichard Henderson 
156339004a71SRichard Henderson         switch (type) {
156439004a71SRichard Henderson         case TCG_TYPE_I32:
156539004a71SRichard Henderson             switch (TCG_TARGET_CALL_ARG_I32) {
156639004a71SRichard Henderson             case TCG_CALL_ARG_EVEN:
156739004a71SRichard Henderson                 layout_arg_even(&cum);
156839004a71SRichard Henderson                 /* fall through */
156939004a71SRichard Henderson             case TCG_CALL_ARG_NORMAL:
157039004a71SRichard Henderson                 layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL);
157139004a71SRichard Henderson                 break;
157239004a71SRichard Henderson             case TCG_CALL_ARG_EXTEND:
157339004a71SRichard Henderson                 kind = TCG_CALL_ARG_EXTEND_U + (typecode & 1);
157439004a71SRichard Henderson                 layout_arg_1(&cum, info, kind);
157539004a71SRichard Henderson                 break;
157639004a71SRichard Henderson             default:
157739004a71SRichard Henderson                 qemu_build_not_reached();
157839004a71SRichard Henderson             }
157939004a71SRichard Henderson             break;
158039004a71SRichard Henderson 
158139004a71SRichard Henderson         case TCG_TYPE_I64:
158239004a71SRichard Henderson             switch (TCG_TARGET_CALL_ARG_I64) {
158339004a71SRichard Henderson             case TCG_CALL_ARG_EVEN:
158439004a71SRichard Henderson                 layout_arg_even(&cum);
158539004a71SRichard Henderson                 /* fall through */
158639004a71SRichard Henderson             case TCG_CALL_ARG_NORMAL:
158739004a71SRichard Henderson                 if (TCG_TARGET_REG_BITS == 32) {
158839004a71SRichard Henderson                     layout_arg_normal_n(&cum, info, 2);
158939004a71SRichard Henderson                 } else {
159039004a71SRichard Henderson                     layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL);
159139004a71SRichard Henderson                 }
159239004a71SRichard Henderson                 break;
159339004a71SRichard Henderson             default:
159439004a71SRichard Henderson                 qemu_build_not_reached();
159539004a71SRichard Henderson             }
159639004a71SRichard Henderson             break;
159739004a71SRichard Henderson 
1598466d3759SRichard Henderson         case TCG_TYPE_I128:
15995427a9a7SRichard Henderson             switch (TCG_TARGET_CALL_ARG_I128) {
1600466d3759SRichard Henderson             case TCG_CALL_ARG_EVEN:
1601466d3759SRichard Henderson                 layout_arg_even(&cum);
1602466d3759SRichard Henderson                 /* fall through */
1603466d3759SRichard Henderson             case TCG_CALL_ARG_NORMAL:
1604466d3759SRichard Henderson                 layout_arg_normal_n(&cum, info, 128 / TCG_TARGET_REG_BITS);
1605466d3759SRichard Henderson                 break;
1606313bdea8SRichard Henderson             case TCG_CALL_ARG_BY_REF:
1607313bdea8SRichard Henderson                 layout_arg_by_ref(&cum, info);
1608313bdea8SRichard Henderson                 break;
1609466d3759SRichard Henderson             default:
1610466d3759SRichard Henderson                 qemu_build_not_reached();
1611466d3759SRichard Henderson             }
1612466d3759SRichard Henderson             break;
1613466d3759SRichard Henderson 
161439004a71SRichard Henderson         default:
161539004a71SRichard Henderson             g_assert_not_reached();
161639004a71SRichard Henderson         }
161739004a71SRichard Henderson     }
161839004a71SRichard Henderson     info->nr_in = cum.info_in_idx;
161939004a71SRichard Henderson 
162039004a71SRichard Henderson     /* Validate that we didn't overrun the input array. */
162139004a71SRichard Henderson     assert(cum.info_in_idx <= ARRAY_SIZE(info->in));
162239004a71SRichard Henderson     /* Validate the backend has enough argument space. */
162339004a71SRichard Henderson     assert(cum.arg_slot <= max_reg_slots + max_stk_slots);
1624313bdea8SRichard Henderson 
1625313bdea8SRichard Henderson     /*
1626313bdea8SRichard Henderson      * Relocate the "ref_slot" area to the end of the parameters.
1627313bdea8SRichard Henderson      * Minimizing this stack offset helps code size for x86,
1628313bdea8SRichard Henderson      * which has a signed 8-bit offset encoding.
1629313bdea8SRichard Henderson      */
1630313bdea8SRichard Henderson     if (cum.ref_slot != 0) {
1631313bdea8SRichard Henderson         int ref_base = 0;
1632313bdea8SRichard Henderson 
1633313bdea8SRichard Henderson         if (cum.arg_slot > max_reg_slots) {
1634313bdea8SRichard Henderson             int align = __alignof(Int128) / sizeof(tcg_target_long);
1635313bdea8SRichard Henderson 
1636313bdea8SRichard Henderson             ref_base = cum.arg_slot - max_reg_slots;
1637313bdea8SRichard Henderson             if (align > 1) {
1638313bdea8SRichard Henderson                 ref_base = ROUND_UP(ref_base, align);
1639313bdea8SRichard Henderson             }
1640313bdea8SRichard Henderson         }
1641313bdea8SRichard Henderson         assert(ref_base + cum.ref_slot <= max_stk_slots);
1642d78e4a4fSRichard Henderson         ref_base += max_reg_slots;
1643313bdea8SRichard Henderson 
1644313bdea8SRichard Henderson         if (ref_base != 0) {
1645313bdea8SRichard Henderson             for (int i = cum.info_in_idx - 1; i >= 0; --i) {
1646313bdea8SRichard Henderson                 TCGCallArgumentLoc *loc = &info->in[i];
1647313bdea8SRichard Henderson                 switch (loc->kind) {
1648313bdea8SRichard Henderson                 case TCG_CALL_ARG_BY_REF:
1649313bdea8SRichard Henderson                 case TCG_CALL_ARG_BY_REF_N:
1650313bdea8SRichard Henderson                     loc->ref_slot += ref_base;
1651313bdea8SRichard Henderson                     break;
1652313bdea8SRichard Henderson                 default:
1653313bdea8SRichard Henderson                     break;
1654313bdea8SRichard Henderson                 }
1655313bdea8SRichard Henderson             }
1656313bdea8SRichard Henderson         }
1657313bdea8SRichard Henderson     }
165839004a71SRichard Henderson }
165939004a71SRichard Henderson 
166091478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)];
1661501fb3daSRichard Henderson static void process_constraint_sets(void);
16621c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
16631c2adb95SRichard Henderson                                             TCGReg reg, const char *name);
166491478cefSRichard Henderson 
1665a9d107faSRichard Henderson static void tcg_context_init(unsigned max_threads)
1666c896fe29Sbellard {
1667a76aabd3SRichard Henderson     TCGContext *s = &tcg_init_ctx;
16683e80824eSRichard Henderson     int n, i;
16691c2adb95SRichard Henderson     TCGTemp *ts;
1670c896fe29Sbellard 
1671c896fe29Sbellard     memset(s, 0, sizeof(*s));
1672c896fe29Sbellard     s->nb_globals = 0;
1673c896fe29Sbellard 
16748429a1caSRichard Henderson     init_call_layout(&info_helper_ld32_mmu);
16758429a1caSRichard Henderson     init_call_layout(&info_helper_ld64_mmu);
1676ebebea53SRichard Henderson     init_call_layout(&info_helper_ld128_mmu);
16778429a1caSRichard Henderson     init_call_layout(&info_helper_st32_mmu);
16788429a1caSRichard Henderson     init_call_layout(&info_helper_st64_mmu);
1679ebebea53SRichard Henderson     init_call_layout(&info_helper_st128_mmu);
16808429a1caSRichard Henderson 
1681c896fe29Sbellard     tcg_target_init(s);
1682501fb3daSRichard Henderson     process_constraint_sets();
168391478cefSRichard Henderson 
168491478cefSRichard Henderson     /* Reverse the order of the saved registers, assuming they're all at
168591478cefSRichard Henderson        the start of tcg_target_reg_alloc_order.  */
168691478cefSRichard Henderson     for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) {
168791478cefSRichard Henderson         int r = tcg_target_reg_alloc_order[n];
168891478cefSRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) {
168991478cefSRichard Henderson             break;
169091478cefSRichard Henderson         }
169191478cefSRichard Henderson     }
169291478cefSRichard Henderson     for (i = 0; i < n; ++i) {
169391478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i];
169491478cefSRichard Henderson     }
169591478cefSRichard Henderson     for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) {
169691478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i];
169791478cefSRichard Henderson     }
1698b1311c4aSEmilio G. Cota 
1699b1311c4aSEmilio G. Cota     tcg_ctx = s;
17003468b59eSEmilio G. Cota     /*
17013468b59eSEmilio G. Cota      * In user-mode we simply share the init context among threads, since we
17023468b59eSEmilio G. Cota      * use a single region. See the documentation tcg_region_init() for the
17033468b59eSEmilio G. Cota      * reasoning behind this.
1704a9d107faSRichard Henderson      * In system-mode we will have at most max_threads TCG threads.
17053468b59eSEmilio G. Cota      */
17063468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
1707df2cce29SEmilio G. Cota     tcg_ctxs = &tcg_ctx;
17080e2d61cfSRichard Henderson     tcg_cur_ctxs = 1;
17090e2d61cfSRichard Henderson     tcg_max_ctxs = 1;
17103468b59eSEmilio G. Cota #else
1711a9d107faSRichard Henderson     tcg_max_ctxs = max_threads;
1712a9d107faSRichard Henderson     tcg_ctxs = g_new0(TCGContext *, max_threads);
17133468b59eSEmilio G. Cota #endif
17141c2adb95SRichard Henderson 
17151c2adb95SRichard Henderson     tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0));
17161c2adb95SRichard Henderson     ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env");
1717ad75a51eSRichard Henderson     tcg_env = temp_tcgv_ptr(ts);
17189002ec79SRichard Henderson }
1719b03cce8eSbellard 
1720a9d107faSRichard Henderson void tcg_init(size_t tb_size, int splitwx, unsigned max_threads)
1721a76aabd3SRichard Henderson {
1722a9d107faSRichard Henderson     tcg_context_init(max_threads);
1723a9d107faSRichard Henderson     tcg_region_init(tb_size, splitwx, max_threads);
1724a76aabd3SRichard Henderson }
1725a76aabd3SRichard Henderson 
17266e3b2bfdSEmilio G. Cota /*
17276e3b2bfdSEmilio G. Cota  * Allocate TBs right before their corresponding translated code, making
17286e3b2bfdSEmilio G. Cota  * sure that TBs and code are on different cache lines.
17296e3b2bfdSEmilio G. Cota  */
17306e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s)
17316e3b2bfdSEmilio G. Cota {
17326e3b2bfdSEmilio G. Cota     uintptr_t align = qemu_icache_linesize;
17336e3b2bfdSEmilio G. Cota     TranslationBlock *tb;
17346e3b2bfdSEmilio G. Cota     void *next;
17356e3b2bfdSEmilio G. Cota 
1736e8feb96fSEmilio G. Cota  retry:
17376e3b2bfdSEmilio G. Cota     tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align);
17386e3b2bfdSEmilio G. Cota     next = (void *)ROUND_UP((uintptr_t)(tb + 1), align);
17396e3b2bfdSEmilio G. Cota 
17406e3b2bfdSEmilio G. Cota     if (unlikely(next > s->code_gen_highwater)) {
1741e8feb96fSEmilio G. Cota         if (tcg_region_alloc(s)) {
17426e3b2bfdSEmilio G. Cota             return NULL;
17436e3b2bfdSEmilio G. Cota         }
1744e8feb96fSEmilio G. Cota         goto retry;
1745e8feb96fSEmilio G. Cota     }
1746d73415a3SStefan Hajnoczi     qatomic_set(&s->code_gen_ptr, next);
17476e3b2bfdSEmilio G. Cota     return tb;
17486e3b2bfdSEmilio G. Cota }
17496e3b2bfdSEmilio G. Cota 
1750935f75aeSRichard Henderson void tcg_prologue_init(void)
17519002ec79SRichard Henderson {
1752935f75aeSRichard Henderson     TCGContext *s = tcg_ctx;
1753b0a0794aSRichard Henderson     size_t prologue_size;
17548163b749SRichard Henderson 
1755b0a0794aSRichard Henderson     s->code_ptr = s->code_gen_ptr;
1756b0a0794aSRichard Henderson     s->code_buf = s->code_gen_ptr;
17575b38ee31SRichard Henderson     s->data_gen_ptr = NULL;
1758b91ccb31SRichard Henderson 
1759b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
1760b0a0794aSRichard Henderson     tcg_qemu_tb_exec = (tcg_prologue_fn *)tcg_splitwx_to_rx(s->code_ptr);
1761b91ccb31SRichard Henderson #endif
17628163b749SRichard Henderson 
17635b38ee31SRichard Henderson     s->pool_labels = NULL;
17645b38ee31SRichard Henderson 
1765653b87ebSRoman Bolshakov     qemu_thread_jit_write();
17668163b749SRichard Henderson     /* Generate the prologue.  */
1767b03cce8eSbellard     tcg_target_qemu_prologue(s);
17685b38ee31SRichard Henderson 
17695b38ee31SRichard Henderson     /* Allow the prologue to put e.g. guest_base into a pool entry.  */
17705b38ee31SRichard Henderson     {
17711768987bSRichard Henderson         int result = tcg_out_pool_finalize(s);
17721768987bSRichard Henderson         tcg_debug_assert(result == 0);
17735b38ee31SRichard Henderson     }
17745b38ee31SRichard Henderson 
1775b0a0794aSRichard Henderson     prologue_size = tcg_current_code_size(s);
17765584e2dbSIlya Leoshkevich     perf_report_prologue(s->code_gen_ptr, prologue_size);
1777b0a0794aSRichard Henderson 
1778df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
1779b0a0794aSRichard Henderson     flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf),
1780b0a0794aSRichard Henderson                         (uintptr_t)s->code_buf, prologue_size);
1781df5d2b16SRichard Henderson #endif
17828163b749SRichard Henderson 
1783d6b64b2bSRichard Henderson     if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) {
1784c60f599bSRichard Henderson         FILE *logfile = qemu_log_trylock();
178578b54858SRichard Henderson         if (logfile) {
178678b54858SRichard Henderson             fprintf(logfile, "PROLOGUE: [size=%zu]\n", prologue_size);
17875b38ee31SRichard Henderson             if (s->data_gen_ptr) {
1788b0a0794aSRichard Henderson                 size_t code_size = s->data_gen_ptr - s->code_gen_ptr;
17895b38ee31SRichard Henderson                 size_t data_size = prologue_size - code_size;
17905b38ee31SRichard Henderson                 size_t i;
17915b38ee31SRichard Henderson 
179278b54858SRichard Henderson                 disas(logfile, s->code_gen_ptr, code_size);
17935b38ee31SRichard Henderson 
17945b38ee31SRichard Henderson                 for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) {
17955b38ee31SRichard Henderson                     if (sizeof(tcg_target_ulong) == 8) {
179678b54858SRichard Henderson                         fprintf(logfile,
179778b54858SRichard Henderson                                 "0x%08" PRIxPTR ":  .quad  0x%016" PRIx64 "\n",
17985b38ee31SRichard Henderson                                 (uintptr_t)s->data_gen_ptr + i,
17995b38ee31SRichard Henderson                                 *(uint64_t *)(s->data_gen_ptr + i));
18005b38ee31SRichard Henderson                     } else {
180178b54858SRichard Henderson                         fprintf(logfile,
180278b54858SRichard Henderson                                 "0x%08" PRIxPTR ":  .long  0x%08x\n",
18035b38ee31SRichard Henderson                                 (uintptr_t)s->data_gen_ptr + i,
18045b38ee31SRichard Henderson                                 *(uint32_t *)(s->data_gen_ptr + i));
18055b38ee31SRichard Henderson                     }
18065b38ee31SRichard Henderson                 }
18075b38ee31SRichard Henderson             } else {
180878b54858SRichard Henderson                 disas(logfile, s->code_gen_ptr, prologue_size);
18095b38ee31SRichard Henderson             }
181078b54858SRichard Henderson             fprintf(logfile, "\n");
1811fc59d2d8SRobert Foley             qemu_log_unlock(logfile);
1812d6b64b2bSRichard Henderson         }
181378b54858SRichard Henderson     }
1814cedbcb01SEmilio G. Cota 
18156eea0434SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
18166eea0434SRichard Henderson     /*
18176eea0434SRichard Henderson      * Assert that goto_ptr is implemented completely, setting an epilogue.
18186eea0434SRichard Henderson      * For tci, we use NULL as the signal to return from the interpreter,
18196eea0434SRichard Henderson      * so skip this check.
18206eea0434SRichard Henderson      */
18218b5c2b62SRichard Henderson     tcg_debug_assert(tcg_code_gen_epilogue != NULL);
18226eea0434SRichard Henderson #endif
1823d1c74ab3SRichard Henderson 
1824d1c74ab3SRichard Henderson     tcg_region_prologue_set(s);
1825c896fe29Sbellard }
1826c896fe29Sbellard 
1827c896fe29Sbellard void tcg_func_start(TCGContext *s)
1828c896fe29Sbellard {
1829c896fe29Sbellard     tcg_pool_reset(s);
1830c896fe29Sbellard     s->nb_temps = s->nb_globals;
18310ec9eabcSRichard Henderson 
18320ec9eabcSRichard Henderson     /* No temps have been previously allocated for size or locality.  */
183304e006abSRichard Henderson     tcg_temp_ebb_reset_freed(s);
18340ec9eabcSRichard Henderson 
1835c0522136SRichard Henderson     /* No constant temps have been previously allocated. */
1836c0522136SRichard Henderson     for (int i = 0; i < TCG_TYPE_COUNT; ++i) {
1837c0522136SRichard Henderson         if (s->const_table[i]) {
1838c0522136SRichard Henderson             g_hash_table_remove_all(s->const_table[i]);
1839c0522136SRichard Henderson         }
1840c0522136SRichard Henderson     }
1841c0522136SRichard Henderson 
1842abebf925SRichard Henderson     s->nb_ops = 0;
1843c896fe29Sbellard     s->nb_labels = 0;
1844c896fe29Sbellard     s->current_frame_offset = s->frame_start;
1845c896fe29Sbellard 
18460a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG
18470a209d4bSRichard Henderson     s->goto_tb_issue_mask = 0;
18480a209d4bSRichard Henderson #endif
18490a209d4bSRichard Henderson 
185015fa08f8SRichard Henderson     QTAILQ_INIT(&s->ops);
185115fa08f8SRichard Henderson     QTAILQ_INIT(&s->free_ops);
185207843f75SRichard Henderson     s->emit_before_op = NULL;
1853bef16ab4SRichard Henderson     QSIMPLEQ_INIT(&s->labels);
18544baf3978SRichard Henderson 
1855a0ecb8e4SRichard Henderson     tcg_debug_assert(s->addr_type <= TCG_TYPE_REG);
1856747bd69dSRichard Henderson     tcg_debug_assert(s->insn_start_words > 0);
1857c896fe29Sbellard }
1858c896fe29Sbellard 
1859ae30e866SRichard Henderson static TCGTemp *tcg_temp_alloc(TCGContext *s)
18607ca4b752SRichard Henderson {
18617ca4b752SRichard Henderson     int n = s->nb_temps++;
1862ae30e866SRichard Henderson 
1863ae30e866SRichard Henderson     if (n >= TCG_MAX_TEMPS) {
1864db6b7d0cSRichard Henderson         tcg_raise_tb_overflow(s);
1865ae30e866SRichard Henderson     }
18667ca4b752SRichard Henderson     return memset(&s->temps[n], 0, sizeof(TCGTemp));
18677ca4b752SRichard Henderson }
18687ca4b752SRichard Henderson 
1869ae30e866SRichard Henderson static TCGTemp *tcg_global_alloc(TCGContext *s)
18707ca4b752SRichard Henderson {
1871fa477d25SRichard Henderson     TCGTemp *ts;
1872fa477d25SRichard Henderson 
18737ca4b752SRichard Henderson     tcg_debug_assert(s->nb_globals == s->nb_temps);
1874ae30e866SRichard Henderson     tcg_debug_assert(s->nb_globals < TCG_MAX_TEMPS);
18757ca4b752SRichard Henderson     s->nb_globals++;
1876fa477d25SRichard Henderson     ts = tcg_temp_alloc(s);
1877ee17db83SRichard Henderson     ts->kind = TEMP_GLOBAL;
1878fa477d25SRichard Henderson 
1879fa477d25SRichard Henderson     return ts;
1880c896fe29Sbellard }
1881c896fe29Sbellard 
1882085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
1883b6638662SRichard Henderson                                             TCGReg reg, const char *name)
1884c896fe29Sbellard {
1885c896fe29Sbellard     TCGTemp *ts;
1886c896fe29Sbellard 
18871a057554SRichard Henderson     tcg_debug_assert(TCG_TARGET_REG_BITS == 64 || type == TCG_TYPE_I32);
18887ca4b752SRichard Henderson 
18897ca4b752SRichard Henderson     ts = tcg_global_alloc(s);
1890c896fe29Sbellard     ts->base_type = type;
1891c896fe29Sbellard     ts->type = type;
1892ee17db83SRichard Henderson     ts->kind = TEMP_FIXED;
1893c896fe29Sbellard     ts->reg = reg;
1894c896fe29Sbellard     ts->name = name;
1895c896fe29Sbellard     tcg_regset_set_reg(s->reserved_regs, reg);
18967ca4b752SRichard Henderson 
1897085272b3SRichard Henderson     return ts;
1898a7812ae4Spbrook }
1899a7812ae4Spbrook 
1900b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size)
1901a7812ae4Spbrook {
1902b3a62939SRichard Henderson     s->frame_start = start;
1903b3a62939SRichard Henderson     s->frame_end = start + size;
1904085272b3SRichard Henderson     s->frame_temp
1905085272b3SRichard Henderson         = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame");
1906b3a62939SRichard Henderson }
1907a7812ae4Spbrook 
19084643f3e0SRichard Henderson static TCGTemp *tcg_global_mem_new_internal(TCGv_ptr base, intptr_t offset,
19094643f3e0SRichard Henderson                                             const char *name, TCGType type)
1910c896fe29Sbellard {
1911b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1912dc41aa7dSRichard Henderson     TCGTemp *base_ts = tcgv_ptr_temp(base);
19137ca4b752SRichard Henderson     TCGTemp *ts = tcg_global_alloc(s);
1914aef85402SRichard Henderson     int indirect_reg = 0;
1915c896fe29Sbellard 
1916c0522136SRichard Henderson     switch (base_ts->kind) {
1917c0522136SRichard Henderson     case TEMP_FIXED:
1918c0522136SRichard Henderson         break;
1919c0522136SRichard Henderson     case TEMP_GLOBAL:
19205a18407fSRichard Henderson         /* We do not support double-indirect registers.  */
19215a18407fSRichard Henderson         tcg_debug_assert(!base_ts->indirect_reg);
1922b3915dbbSRichard Henderson         base_ts->indirect_base = 1;
19235a18407fSRichard Henderson         s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64
19245a18407fSRichard Henderson                             ? 2 : 1);
19255a18407fSRichard Henderson         indirect_reg = 1;
1926c0522136SRichard Henderson         break;
1927c0522136SRichard Henderson     default:
1928c0522136SRichard Henderson         g_assert_not_reached();
1929b3915dbbSRichard Henderson     }
1930b3915dbbSRichard Henderson 
19317ca4b752SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
19327ca4b752SRichard Henderson         TCGTemp *ts2 = tcg_global_alloc(s);
1933c896fe29Sbellard         char buf[64];
19347ca4b752SRichard Henderson 
19357ca4b752SRichard Henderson         ts->base_type = TCG_TYPE_I64;
1936c896fe29Sbellard         ts->type = TCG_TYPE_I32;
1937b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1938c896fe29Sbellard         ts->mem_allocated = 1;
1939b3a62939SRichard Henderson         ts->mem_base = base_ts;
1940aef85402SRichard Henderson         ts->mem_offset = offset;
1941c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1942c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_0");
1943c896fe29Sbellard         ts->name = strdup(buf);
1944c896fe29Sbellard 
19457ca4b752SRichard Henderson         tcg_debug_assert(ts2 == ts + 1);
19467ca4b752SRichard Henderson         ts2->base_type = TCG_TYPE_I64;
19477ca4b752SRichard Henderson         ts2->type = TCG_TYPE_I32;
1948b3915dbbSRichard Henderson         ts2->indirect_reg = indirect_reg;
19497ca4b752SRichard Henderson         ts2->mem_allocated = 1;
19507ca4b752SRichard Henderson         ts2->mem_base = base_ts;
1951aef85402SRichard Henderson         ts2->mem_offset = offset + 4;
1952fac87bd2SRichard Henderson         ts2->temp_subindex = 1;
1953c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1954c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_1");
1955120c1084SRichard Henderson         ts2->name = strdup(buf);
19567ca4b752SRichard Henderson     } else {
1957c896fe29Sbellard         ts->base_type = type;
1958c896fe29Sbellard         ts->type = type;
1959b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1960c896fe29Sbellard         ts->mem_allocated = 1;
1961b3a62939SRichard Henderson         ts->mem_base = base_ts;
1962c896fe29Sbellard         ts->mem_offset = offset;
1963c896fe29Sbellard         ts->name = name;
1964c896fe29Sbellard     }
1965085272b3SRichard Henderson     return ts;
1966c896fe29Sbellard }
1967c896fe29Sbellard 
19684643f3e0SRichard Henderson TCGv_i32 tcg_global_mem_new_i32(TCGv_ptr reg, intptr_t off, const char *name)
19694643f3e0SRichard Henderson {
19704643f3e0SRichard Henderson     TCGTemp *ts = tcg_global_mem_new_internal(reg, off, name, TCG_TYPE_I32);
19714643f3e0SRichard Henderson     return temp_tcgv_i32(ts);
19724643f3e0SRichard Henderson }
19734643f3e0SRichard Henderson 
19744643f3e0SRichard Henderson TCGv_i64 tcg_global_mem_new_i64(TCGv_ptr reg, intptr_t off, const char *name)
19754643f3e0SRichard Henderson {
19764643f3e0SRichard Henderson     TCGTemp *ts = tcg_global_mem_new_internal(reg, off, name, TCG_TYPE_I64);
19774643f3e0SRichard Henderson     return temp_tcgv_i64(ts);
19784643f3e0SRichard Henderson }
19794643f3e0SRichard Henderson 
19804643f3e0SRichard Henderson TCGv_ptr tcg_global_mem_new_ptr(TCGv_ptr reg, intptr_t off, const char *name)
19814643f3e0SRichard Henderson {
19824643f3e0SRichard Henderson     TCGTemp *ts = tcg_global_mem_new_internal(reg, off, name, TCG_TYPE_PTR);
19834643f3e0SRichard Henderson     return temp_tcgv_ptr(ts);
19844643f3e0SRichard Henderson }
19854643f3e0SRichard Henderson 
1986fb04ab7dSRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, TCGTempKind kind)
1987c896fe29Sbellard {
1988b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1989c896fe29Sbellard     TCGTemp *ts;
1990e1c08b00SRichard Henderson     int n;
1991c896fe29Sbellard 
1992e1c08b00SRichard Henderson     if (kind == TEMP_EBB) {
1993e1c08b00SRichard Henderson         int idx = find_first_bit(s->free_temps[type].l, TCG_MAX_TEMPS);
1994e1c08b00SRichard Henderson 
19950ec9eabcSRichard Henderson         if (idx < TCG_MAX_TEMPS) {
19960ec9eabcSRichard Henderson             /* There is already an available temp with the right type.  */
1997e1c08b00SRichard Henderson             clear_bit(idx, s->free_temps[type].l);
19980ec9eabcSRichard Henderson 
1999e8996ee0Sbellard             ts = &s->temps[idx];
2000e8996ee0Sbellard             ts->temp_allocated = 1;
20017ca4b752SRichard Henderson             tcg_debug_assert(ts->base_type == type);
2002ee17db83SRichard Henderson             tcg_debug_assert(ts->kind == kind);
20032f2e911dSRichard Henderson             return ts;
2004e1c08b00SRichard Henderson         }
2005e8996ee0Sbellard     } else {
2006e1c08b00SRichard Henderson         tcg_debug_assert(kind == TEMP_TB);
2007e1c08b00SRichard Henderson     }
200843eef72fSRichard Henderson 
200943eef72fSRichard Henderson     switch (type) {
201043eef72fSRichard Henderson     case TCG_TYPE_I32:
201143eef72fSRichard Henderson     case TCG_TYPE_V64:
201243eef72fSRichard Henderson     case TCG_TYPE_V128:
201343eef72fSRichard Henderson     case TCG_TYPE_V256:
201443eef72fSRichard Henderson         n = 1;
201543eef72fSRichard Henderson         break;
201643eef72fSRichard Henderson     case TCG_TYPE_I64:
201743eef72fSRichard Henderson         n = 64 / TCG_TARGET_REG_BITS;
201843eef72fSRichard Henderson         break;
201943eef72fSRichard Henderson     case TCG_TYPE_I128:
202043eef72fSRichard Henderson         n = 128 / TCG_TARGET_REG_BITS;
202143eef72fSRichard Henderson         break;
202243eef72fSRichard Henderson     default:
202343eef72fSRichard Henderson         g_assert_not_reached();
202443eef72fSRichard Henderson     }
202543eef72fSRichard Henderson 
20267ca4b752SRichard Henderson     ts = tcg_temp_alloc(s);
202743eef72fSRichard Henderson     ts->base_type = type;
202843eef72fSRichard Henderson     ts->temp_allocated = 1;
202943eef72fSRichard Henderson     ts->kind = kind;
203043eef72fSRichard Henderson 
203143eef72fSRichard Henderson     if (n == 1) {
203243eef72fSRichard Henderson         ts->type = type;
203343eef72fSRichard Henderson     } else {
203443eef72fSRichard Henderson         ts->type = TCG_TYPE_REG;
203543eef72fSRichard Henderson 
2036e1c08b00SRichard Henderson         for (int i = 1; i < n; ++i) {
20377ca4b752SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
20387ca4b752SRichard Henderson 
203943eef72fSRichard Henderson             tcg_debug_assert(ts2 == ts + i);
204043eef72fSRichard Henderson             ts2->base_type = type;
204143eef72fSRichard Henderson             ts2->type = TCG_TYPE_REG;
20427ca4b752SRichard Henderson             ts2->temp_allocated = 1;
204343eef72fSRichard Henderson             ts2->temp_subindex = i;
2044ee17db83SRichard Henderson             ts2->kind = kind;
204543eef72fSRichard Henderson         }
2046c896fe29Sbellard     }
2047085272b3SRichard Henderson     return ts;
2048c896fe29Sbellard }
2049c896fe29Sbellard 
20504643f3e0SRichard Henderson TCGv_i32 tcg_temp_new_i32(void)
20514643f3e0SRichard Henderson {
20524643f3e0SRichard Henderson     return temp_tcgv_i32(tcg_temp_new_internal(TCG_TYPE_I32, TEMP_TB));
20534643f3e0SRichard Henderson }
20544643f3e0SRichard Henderson 
20554643f3e0SRichard Henderson TCGv_i32 tcg_temp_ebb_new_i32(void)
20564643f3e0SRichard Henderson {
20574643f3e0SRichard Henderson     return temp_tcgv_i32(tcg_temp_new_internal(TCG_TYPE_I32, TEMP_EBB));
20584643f3e0SRichard Henderson }
20594643f3e0SRichard Henderson 
20604643f3e0SRichard Henderson TCGv_i64 tcg_temp_new_i64(void)
20614643f3e0SRichard Henderson {
20624643f3e0SRichard Henderson     return temp_tcgv_i64(tcg_temp_new_internal(TCG_TYPE_I64, TEMP_TB));
20634643f3e0SRichard Henderson }
20644643f3e0SRichard Henderson 
20654643f3e0SRichard Henderson TCGv_i64 tcg_temp_ebb_new_i64(void)
20664643f3e0SRichard Henderson {
20674643f3e0SRichard Henderson     return temp_tcgv_i64(tcg_temp_new_internal(TCG_TYPE_I64, TEMP_EBB));
20684643f3e0SRichard Henderson }
20694643f3e0SRichard Henderson 
20704643f3e0SRichard Henderson TCGv_ptr tcg_temp_new_ptr(void)
20714643f3e0SRichard Henderson {
20724643f3e0SRichard Henderson     return temp_tcgv_ptr(tcg_temp_new_internal(TCG_TYPE_PTR, TEMP_TB));
20734643f3e0SRichard Henderson }
20744643f3e0SRichard Henderson 
20754643f3e0SRichard Henderson TCGv_ptr tcg_temp_ebb_new_ptr(void)
20764643f3e0SRichard Henderson {
20774643f3e0SRichard Henderson     return temp_tcgv_ptr(tcg_temp_new_internal(TCG_TYPE_PTR, TEMP_EBB));
20784643f3e0SRichard Henderson }
20794643f3e0SRichard Henderson 
20804643f3e0SRichard Henderson TCGv_i128 tcg_temp_new_i128(void)
20814643f3e0SRichard Henderson {
20824643f3e0SRichard Henderson     return temp_tcgv_i128(tcg_temp_new_internal(TCG_TYPE_I128, TEMP_TB));
20834643f3e0SRichard Henderson }
20844643f3e0SRichard Henderson 
20854643f3e0SRichard Henderson TCGv_i128 tcg_temp_ebb_new_i128(void)
20864643f3e0SRichard Henderson {
20874643f3e0SRichard Henderson     return temp_tcgv_i128(tcg_temp_new_internal(TCG_TYPE_I128, TEMP_EBB));
20884643f3e0SRichard Henderson }
20894643f3e0SRichard Henderson 
2090d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type)
2091d2fd745fSRichard Henderson {
2092d2fd745fSRichard Henderson     TCGTemp *t;
2093d2fd745fSRichard Henderson 
2094d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG
2095d2fd745fSRichard Henderson     switch (type) {
2096d2fd745fSRichard Henderson     case TCG_TYPE_V64:
2097d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v64);
2098d2fd745fSRichard Henderson         break;
2099d2fd745fSRichard Henderson     case TCG_TYPE_V128:
2100d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v128);
2101d2fd745fSRichard Henderson         break;
2102d2fd745fSRichard Henderson     case TCG_TYPE_V256:
2103d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v256);
2104d2fd745fSRichard Henderson         break;
2105d2fd745fSRichard Henderson     default:
2106d2fd745fSRichard Henderson         g_assert_not_reached();
2107d2fd745fSRichard Henderson     }
2108d2fd745fSRichard Henderson #endif
2109d2fd745fSRichard Henderson 
2110bbf989bfSRichard Henderson     t = tcg_temp_new_internal(type, TEMP_EBB);
2111d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
2112d2fd745fSRichard Henderson }
2113d2fd745fSRichard Henderson 
2114d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp.  */
2115d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match)
2116d2fd745fSRichard Henderson {
2117d2fd745fSRichard Henderson     TCGTemp *t = tcgv_vec_temp(match);
2118d2fd745fSRichard Henderson 
2119d2fd745fSRichard Henderson     tcg_debug_assert(t->temp_allocated != 0);
2120d2fd745fSRichard Henderson 
2121bbf989bfSRichard Henderson     t = tcg_temp_new_internal(t->base_type, TEMP_EBB);
2122d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
2123d2fd745fSRichard Henderson }
2124d2fd745fSRichard Henderson 
21255bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts)
2126c896fe29Sbellard {
2127b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
2128c896fe29Sbellard 
2129c7482438SRichard Henderson     switch (ts->kind) {
2130c7482438SRichard Henderson     case TEMP_CONST:
2131f57c6915SRichard Henderson     case TEMP_TB:
21322f2e911dSRichard Henderson         /* Silently ignore free. */
2133c7482438SRichard Henderson         break;
21342f2e911dSRichard Henderson     case TEMP_EBB:
2135eabb7b91SAurelien Jarno         tcg_debug_assert(ts->temp_allocated != 0);
2136e8996ee0Sbellard         ts->temp_allocated = 0;
21372f2e911dSRichard Henderson         set_bit(temp_idx(ts), s->free_temps[ts->base_type].l);
21382f2e911dSRichard Henderson         break;
21392f2e911dSRichard Henderson     default:
21402f2e911dSRichard Henderson         /* It never made sense to free TEMP_FIXED or TEMP_GLOBAL. */
21412f2e911dSRichard Henderson         g_assert_not_reached();
2142e1c08b00SRichard Henderson     }
2143e8996ee0Sbellard }
2144e8996ee0Sbellard 
214558b79713SRichard Henderson void tcg_temp_free_i32(TCGv_i32 arg)
214658b79713SRichard Henderson {
214758b79713SRichard Henderson     tcg_temp_free_internal(tcgv_i32_temp(arg));
214858b79713SRichard Henderson }
214958b79713SRichard Henderson 
215058b79713SRichard Henderson void tcg_temp_free_i64(TCGv_i64 arg)
215158b79713SRichard Henderson {
215258b79713SRichard Henderson     tcg_temp_free_internal(tcgv_i64_temp(arg));
215358b79713SRichard Henderson }
215458b79713SRichard Henderson 
215558b79713SRichard Henderson void tcg_temp_free_i128(TCGv_i128 arg)
215658b79713SRichard Henderson {
215758b79713SRichard Henderson     tcg_temp_free_internal(tcgv_i128_temp(arg));
215858b79713SRichard Henderson }
215958b79713SRichard Henderson 
216058b79713SRichard Henderson void tcg_temp_free_ptr(TCGv_ptr arg)
216158b79713SRichard Henderson {
216258b79713SRichard Henderson     tcg_temp_free_internal(tcgv_ptr_temp(arg));
216358b79713SRichard Henderson }
216458b79713SRichard Henderson 
216558b79713SRichard Henderson void tcg_temp_free_vec(TCGv_vec arg)
216658b79713SRichard Henderson {
216758b79713SRichard Henderson     tcg_temp_free_internal(tcgv_vec_temp(arg));
216858b79713SRichard Henderson }
216958b79713SRichard Henderson 
2170c0522136SRichard Henderson TCGTemp *tcg_constant_internal(TCGType type, int64_t val)
2171c0522136SRichard Henderson {
2172c0522136SRichard Henderson     TCGContext *s = tcg_ctx;
2173c0522136SRichard Henderson     GHashTable *h = s->const_table[type];
2174c0522136SRichard Henderson     TCGTemp *ts;
2175c0522136SRichard Henderson 
2176c0522136SRichard Henderson     if (h == NULL) {
2177c0522136SRichard Henderson         h = g_hash_table_new(g_int64_hash, g_int64_equal);
2178c0522136SRichard Henderson         s->const_table[type] = h;
2179c0522136SRichard Henderson     }
2180c0522136SRichard Henderson 
2181c0522136SRichard Henderson     ts = g_hash_table_lookup(h, &val);
2182c0522136SRichard Henderson     if (ts == NULL) {
2183aef85402SRichard Henderson         int64_t *val_ptr;
2184aef85402SRichard Henderson 
2185c0522136SRichard Henderson         ts = tcg_temp_alloc(s);
2186c0522136SRichard Henderson 
2187c0522136SRichard Henderson         if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
2188c0522136SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
2189c0522136SRichard Henderson 
2190aef85402SRichard Henderson             tcg_debug_assert(ts2 == ts + 1);
2191aef85402SRichard Henderson 
2192c0522136SRichard Henderson             ts->base_type = TCG_TYPE_I64;
2193c0522136SRichard Henderson             ts->type = TCG_TYPE_I32;
2194c0522136SRichard Henderson             ts->kind = TEMP_CONST;
2195c0522136SRichard Henderson             ts->temp_allocated = 1;
2196c0522136SRichard Henderson 
2197c0522136SRichard Henderson             ts2->base_type = TCG_TYPE_I64;
2198c0522136SRichard Henderson             ts2->type = TCG_TYPE_I32;
2199c0522136SRichard Henderson             ts2->kind = TEMP_CONST;
2200c0522136SRichard Henderson             ts2->temp_allocated = 1;
2201fac87bd2SRichard Henderson             ts2->temp_subindex = 1;
2202aef85402SRichard Henderson 
2203aef85402SRichard Henderson             /*
2204aef85402SRichard Henderson              * Retain the full value of the 64-bit constant in the low
2205aef85402SRichard Henderson              * part, so that the hash table works.  Actual uses will
2206aef85402SRichard Henderson              * truncate the value to the low part.
2207aef85402SRichard Henderson              */
2208aef85402SRichard Henderson             ts[HOST_BIG_ENDIAN].val = val;
2209aef85402SRichard Henderson             ts[!HOST_BIG_ENDIAN].val = val >> 32;
2210aef85402SRichard Henderson             val_ptr = &ts[HOST_BIG_ENDIAN].val;
2211c0522136SRichard Henderson         } else {
2212c0522136SRichard Henderson             ts->base_type = type;
2213c0522136SRichard Henderson             ts->type = type;
2214c0522136SRichard Henderson             ts->kind = TEMP_CONST;
2215c0522136SRichard Henderson             ts->temp_allocated = 1;
2216c0522136SRichard Henderson             ts->val = val;
2217aef85402SRichard Henderson             val_ptr = &ts->val;
2218c0522136SRichard Henderson         }
2219aef85402SRichard Henderson         g_hash_table_insert(h, val_ptr, ts);
2220c0522136SRichard Henderson     }
2221c0522136SRichard Henderson 
2222c0522136SRichard Henderson     return ts;
2223c0522136SRichard Henderson }
2224c0522136SRichard Henderson 
222516edaee7SRichard Henderson TCGv_i32 tcg_constant_i32(int32_t val)
222616edaee7SRichard Henderson {
222716edaee7SRichard Henderson     return temp_tcgv_i32(tcg_constant_internal(TCG_TYPE_I32, val));
222816edaee7SRichard Henderson }
222916edaee7SRichard Henderson 
223016edaee7SRichard Henderson TCGv_i64 tcg_constant_i64(int64_t val)
223116edaee7SRichard Henderson {
223216edaee7SRichard Henderson     return temp_tcgv_i64(tcg_constant_internal(TCG_TYPE_I64, val));
223316edaee7SRichard Henderson }
223416edaee7SRichard Henderson 
223516edaee7SRichard Henderson TCGv_ptr tcg_constant_ptr_int(intptr_t val)
223616edaee7SRichard Henderson {
223716edaee7SRichard Henderson     return temp_tcgv_ptr(tcg_constant_internal(TCG_TYPE_PTR, val));
223816edaee7SRichard Henderson }
223916edaee7SRichard Henderson 
2240c0522136SRichard Henderson TCGv_vec tcg_constant_vec(TCGType type, unsigned vece, int64_t val)
2241c0522136SRichard Henderson {
2242c0522136SRichard Henderson     val = dup_const(vece, val);
2243c0522136SRichard Henderson     return temp_tcgv_vec(tcg_constant_internal(type, val));
2244c0522136SRichard Henderson }
2245c0522136SRichard Henderson 
224688d4005bSRichard Henderson TCGv_vec tcg_constant_vec_matching(TCGv_vec match, unsigned vece, int64_t val)
224788d4005bSRichard Henderson {
224888d4005bSRichard Henderson     TCGTemp *t = tcgv_vec_temp(match);
224988d4005bSRichard Henderson 
225088d4005bSRichard Henderson     tcg_debug_assert(t->temp_allocated != 0);
225188d4005bSRichard Henderson     return tcg_constant_vec(t->base_type, vece, val);
225288d4005bSRichard Henderson }
225388d4005bSRichard Henderson 
2254177f648fSRichard Henderson #ifdef CONFIG_DEBUG_TCG
2255177f648fSRichard Henderson size_t temp_idx(TCGTemp *ts)
2256177f648fSRichard Henderson {
2257177f648fSRichard Henderson     ptrdiff_t n = ts - tcg_ctx->temps;
2258177f648fSRichard Henderson     assert(n >= 0 && n < tcg_ctx->nb_temps);
2259177f648fSRichard Henderson     return n;
2260177f648fSRichard Henderson }
2261177f648fSRichard Henderson 
2262177f648fSRichard Henderson TCGTemp *tcgv_i32_temp(TCGv_i32 v)
2263177f648fSRichard Henderson {
2264177f648fSRichard Henderson     uintptr_t o = (uintptr_t)v - offsetof(TCGContext, temps);
2265177f648fSRichard Henderson 
2266177f648fSRichard Henderson     assert(o < sizeof(TCGTemp) * tcg_ctx->nb_temps);
2267177f648fSRichard Henderson     assert(o % sizeof(TCGTemp) == 0);
2268177f648fSRichard Henderson 
2269177f648fSRichard Henderson     return (void *)tcg_ctx + (uintptr_t)v;
2270177f648fSRichard Henderson }
2271177f648fSRichard Henderson #endif /* CONFIG_DEBUG_TCG */
2272177f648fSRichard Henderson 
2273771a5925SRichard Henderson /*
2274771a5925SRichard Henderson  * Return true if OP may appear in the opcode stream with TYPE.
2275771a5925SRichard Henderson  * Test the runtime variable that controls each opcode.
2276771a5925SRichard Henderson  */
2277771a5925SRichard Henderson bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags)
2278be0f34b5SRichard Henderson {
2279f44824ccSRichard Henderson     bool has_type;
2280f44824ccSRichard Henderson 
2281f44824ccSRichard Henderson     switch (type) {
2282f44824ccSRichard Henderson     case TCG_TYPE_I32:
2283f44824ccSRichard Henderson         has_type = true;
2284f44824ccSRichard Henderson         break;
2285f44824ccSRichard Henderson     case TCG_TYPE_I64:
2286f44824ccSRichard Henderson         has_type = TCG_TARGET_REG_BITS == 64;
2287f44824ccSRichard Henderson         break;
2288f44824ccSRichard Henderson     case TCG_TYPE_V64:
2289f44824ccSRichard Henderson         has_type = TCG_TARGET_HAS_v64;
2290f44824ccSRichard Henderson         break;
2291f44824ccSRichard Henderson     case TCG_TYPE_V128:
2292f44824ccSRichard Henderson         has_type = TCG_TARGET_HAS_v128;
2293f44824ccSRichard Henderson         break;
2294f44824ccSRichard Henderson     case TCG_TYPE_V256:
2295f44824ccSRichard Henderson         has_type = TCG_TARGET_HAS_v256;
2296f44824ccSRichard Henderson         break;
2297f44824ccSRichard Henderson     default:
2298f44824ccSRichard Henderson         has_type = false;
2299f44824ccSRichard Henderson         break;
2300f44824ccSRichard Henderson     }
2301d2fd745fSRichard Henderson 
2302be0f34b5SRichard Henderson     switch (op) {
2303be0f34b5SRichard Henderson     case INDEX_op_discard:
2304be0f34b5SRichard Henderson     case INDEX_op_set_label:
2305be0f34b5SRichard Henderson     case INDEX_op_call:
2306be0f34b5SRichard Henderson     case INDEX_op_br:
2307be0f34b5SRichard Henderson     case INDEX_op_mb:
2308be0f34b5SRichard Henderson     case INDEX_op_insn_start:
2309be0f34b5SRichard Henderson     case INDEX_op_exit_tb:
2310be0f34b5SRichard Henderson     case INDEX_op_goto_tb:
2311f4e01e30SRichard Henderson     case INDEX_op_goto_ptr:
231250b7a197SRichard Henderson     case INDEX_op_qemu_ld_i32:
231350b7a197SRichard Henderson     case INDEX_op_qemu_st_i32:
231450b7a197SRichard Henderson     case INDEX_op_qemu_ld_i64:
231550b7a197SRichard Henderson     case INDEX_op_qemu_st_i64:
2316be0f34b5SRichard Henderson         return true;
2317be0f34b5SRichard Henderson 
231850b7a197SRichard Henderson     case INDEX_op_qemu_st8_i32:
231907ce0b05SRichard Henderson         return TCG_TARGET_HAS_qemu_st8_i32;
232007ce0b05SRichard Henderson 
232150b7a197SRichard Henderson     case INDEX_op_qemu_ld_i128:
232250b7a197SRichard Henderson     case INDEX_op_qemu_st_i128:
232312fde9bcSRichard Henderson         return TCG_TARGET_HAS_qemu_ldst_i128;
232412fde9bcSRichard Henderson 
232579602f63SRichard Henderson     case INDEX_op_add:
2326c3b920b3SRichard Henderson     case INDEX_op_and:
2327b6d69fceSRichard Henderson     case INDEX_op_brcond:
2328*07d5d502SRichard Henderson     case INDEX_op_extract:
2329b5701261SRichard Henderson     case INDEX_op_mov:
2330ea46c4bcSRichard Henderson     case INDEX_op_movcond:
2331a363e1e1SRichard Henderson     case INDEX_op_negsetcond:
233249bd7514SRichard Henderson     case INDEX_op_or:
2333a363e1e1SRichard Henderson     case INDEX_op_setcond:
2334fffd3dc9SRichard Henderson     case INDEX_op_xor:
2335b5701261SRichard Henderson         return has_type;
2336b5701261SRichard Henderson 
2337be0f34b5SRichard Henderson     case INDEX_op_ld8u_i32:
2338be0f34b5SRichard Henderson     case INDEX_op_ld8s_i32:
2339be0f34b5SRichard Henderson     case INDEX_op_ld16u_i32:
2340be0f34b5SRichard Henderson     case INDEX_op_ld16s_i32:
2341be0f34b5SRichard Henderson     case INDEX_op_ld_i32:
2342be0f34b5SRichard Henderson     case INDEX_op_st8_i32:
2343be0f34b5SRichard Henderson     case INDEX_op_st16_i32:
2344be0f34b5SRichard Henderson     case INDEX_op_st_i32:
2345c334de11SRichard Henderson     case INDEX_op_sextract_i32:
23466482e9d2SRichard Henderson     case INDEX_op_deposit_i32:
2347be0f34b5SRichard Henderson         return true;
2348be0f34b5SRichard Henderson 
2349fce1296fSRichard Henderson     case INDEX_op_extract2_i32:
2350fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i32;
2351be0f34b5SRichard Henderson     case INDEX_op_add2_i32:
2352be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i32;
2353be0f34b5SRichard Henderson     case INDEX_op_sub2_i32:
2354be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i32;
2355be0f34b5SRichard Henderson 
2356be0f34b5SRichard Henderson     case INDEX_op_brcond2_i32:
2357be0f34b5SRichard Henderson     case INDEX_op_setcond2_i32:
2358be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 32;
2359be0f34b5SRichard Henderson 
2360be0f34b5SRichard Henderson     case INDEX_op_ld8u_i64:
2361be0f34b5SRichard Henderson     case INDEX_op_ld8s_i64:
2362be0f34b5SRichard Henderson     case INDEX_op_ld16u_i64:
2363be0f34b5SRichard Henderson     case INDEX_op_ld16s_i64:
2364be0f34b5SRichard Henderson     case INDEX_op_ld32u_i64:
2365be0f34b5SRichard Henderson     case INDEX_op_ld32s_i64:
2366be0f34b5SRichard Henderson     case INDEX_op_ld_i64:
2367be0f34b5SRichard Henderson     case INDEX_op_st8_i64:
2368be0f34b5SRichard Henderson     case INDEX_op_st16_i64:
2369be0f34b5SRichard Henderson     case INDEX_op_st32_i64:
2370be0f34b5SRichard Henderson     case INDEX_op_st_i64:
2371be0f34b5SRichard Henderson     case INDEX_op_ext_i32_i64:
2372be0f34b5SRichard Henderson     case INDEX_op_extu_i32_i64:
2373c334de11SRichard Henderson     case INDEX_op_sextract_i64:
23746482e9d2SRichard Henderson     case INDEX_op_deposit_i64:
2375be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 64;
2376be0f34b5SRichard Henderson 
2377fce1296fSRichard Henderson     case INDEX_op_extract2_i64:
2378fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i64;
2379be0f34b5SRichard Henderson     case INDEX_op_extrl_i64_i32:
2380be0f34b5SRichard Henderson     case INDEX_op_extrh_i64_i32:
238113d885b0SRichard Henderson         return TCG_TARGET_HAS_extr_i64_i32;
2382be0f34b5SRichard Henderson     case INDEX_op_add2_i64:
2383be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i64;
2384be0f34b5SRichard Henderson     case INDEX_op_sub2_i64:
2385be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i64;
2386be0f34b5SRichard Henderson 
2387d2fd745fSRichard Henderson     case INDEX_op_mov_vec:
2388d2fd745fSRichard Henderson     case INDEX_op_dup_vec:
238937ee55a0SRichard Henderson     case INDEX_op_dupm_vec:
2390d2fd745fSRichard Henderson     case INDEX_op_ld_vec:
2391d2fd745fSRichard Henderson     case INDEX_op_st_vec:
2392d2fd745fSRichard Henderson     case INDEX_op_add_vec:
2393d2fd745fSRichard Henderson     case INDEX_op_sub_vec:
2394d2fd745fSRichard Henderson     case INDEX_op_and_vec:
2395d2fd745fSRichard Henderson     case INDEX_op_or_vec:
2396d2fd745fSRichard Henderson     case INDEX_op_xor_vec:
2397212be173SRichard Henderson     case INDEX_op_cmp_vec:
2398f44824ccSRichard Henderson         return has_type;
2399d2fd745fSRichard Henderson     case INDEX_op_dup2_vec:
2400f44824ccSRichard Henderson         return has_type && TCG_TARGET_REG_BITS == 32;
2401d2fd745fSRichard Henderson     case INDEX_op_not_vec:
2402f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_not_vec;
2403d2fd745fSRichard Henderson     case INDEX_op_neg_vec:
2404f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_neg_vec;
2405bcefc902SRichard Henderson     case INDEX_op_abs_vec:
2406f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_abs_vec;
2407d2fd745fSRichard Henderson     case INDEX_op_andc_vec:
2408f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_andc_vec;
2409d2fd745fSRichard Henderson     case INDEX_op_orc_vec:
2410f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_orc_vec;
2411ed523473SRichard Henderson     case INDEX_op_nand_vec:
2412f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_nand_vec;
2413ed523473SRichard Henderson     case INDEX_op_nor_vec:
2414f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_nor_vec;
2415ed523473SRichard Henderson     case INDEX_op_eqv_vec:
2416f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_eqv_vec;
24173774030aSRichard Henderson     case INDEX_op_mul_vec:
2418f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_mul_vec;
2419d0ec9796SRichard Henderson     case INDEX_op_shli_vec:
2420d0ec9796SRichard Henderson     case INDEX_op_shri_vec:
2421d0ec9796SRichard Henderson     case INDEX_op_sari_vec:
2422f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_shi_vec;
2423d0ec9796SRichard Henderson     case INDEX_op_shls_vec:
2424d0ec9796SRichard Henderson     case INDEX_op_shrs_vec:
2425d0ec9796SRichard Henderson     case INDEX_op_sars_vec:
2426f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_shs_vec;
2427d0ec9796SRichard Henderson     case INDEX_op_shlv_vec:
2428d0ec9796SRichard Henderson     case INDEX_op_shrv_vec:
2429d0ec9796SRichard Henderson     case INDEX_op_sarv_vec:
2430f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_shv_vec;
2431b0f7e744SRichard Henderson     case INDEX_op_rotli_vec:
2432f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_roti_vec;
243323850a74SRichard Henderson     case INDEX_op_rotls_vec:
2434f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_rots_vec;
24355d0ceda9SRichard Henderson     case INDEX_op_rotlv_vec:
24365d0ceda9SRichard Henderson     case INDEX_op_rotrv_vec:
2437f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_rotv_vec;
24388afaf050SRichard Henderson     case INDEX_op_ssadd_vec:
24398afaf050SRichard Henderson     case INDEX_op_usadd_vec:
24408afaf050SRichard Henderson     case INDEX_op_sssub_vec:
24418afaf050SRichard Henderson     case INDEX_op_ussub_vec:
2442f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_sat_vec;
2443dd0a0fcdSRichard Henderson     case INDEX_op_smin_vec:
2444dd0a0fcdSRichard Henderson     case INDEX_op_umin_vec:
2445dd0a0fcdSRichard Henderson     case INDEX_op_smax_vec:
2446dd0a0fcdSRichard Henderson     case INDEX_op_umax_vec:
2447f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_minmax_vec;
244838dc1294SRichard Henderson     case INDEX_op_bitsel_vec:
2449f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_bitsel_vec;
2450f75da298SRichard Henderson     case INDEX_op_cmpsel_vec:
2451f44824ccSRichard Henderson         return has_type && TCG_TARGET_HAS_cmpsel_vec;
2452d2fd745fSRichard Henderson 
2453db432672SRichard Henderson     default:
24545500bd9eSRichard Henderson         if (op < INDEX_op_last_generic) {
24555500bd9eSRichard Henderson             const TCGOutOp *outop;
24565500bd9eSRichard Henderson             TCGConstraintSetIndex con_set;
24575500bd9eSRichard Henderson 
24585500bd9eSRichard Henderson             if (!has_type) {
24595500bd9eSRichard Henderson                 return false;
24605500bd9eSRichard Henderson             }
24615500bd9eSRichard Henderson 
24625500bd9eSRichard Henderson             outop = all_outop[op];
24635500bd9eSRichard Henderson             tcg_debug_assert(outop != NULL);
24645500bd9eSRichard Henderson 
24655500bd9eSRichard Henderson             con_set = outop->static_constraint;
24665500bd9eSRichard Henderson             if (con_set == C_Dynamic) {
24675500bd9eSRichard Henderson                 con_set = outop->dynamic_constraint(type, flags);
24685500bd9eSRichard Henderson             }
24695500bd9eSRichard Henderson             if (con_set >= 0) {
2470db432672SRichard Henderson                 return true;
2471be0f34b5SRichard Henderson             }
24725500bd9eSRichard Henderson             tcg_debug_assert(con_set == C_NotImplemented);
24735500bd9eSRichard Henderson             return false;
24745500bd9eSRichard Henderson         }
24755500bd9eSRichard Henderson         tcg_debug_assert(op < NB_OPS);
24765500bd9eSRichard Henderson         return true;
24775500bd9eSRichard Henderson 
24785500bd9eSRichard Henderson     case INDEX_op_last_generic:
24795500bd9eSRichard Henderson         g_assert_not_reached();
24805500bd9eSRichard Henderson     }
2481be0f34b5SRichard Henderson }
2482be0f34b5SRichard Henderson 
24830e4c6424SRichard Henderson bool tcg_op_deposit_valid(TCGType type, unsigned ofs, unsigned len)
24840e4c6424SRichard Henderson {
24856482e9d2SRichard Henderson     unsigned width;
24866482e9d2SRichard Henderson 
24876482e9d2SRichard Henderson     tcg_debug_assert(type == TCG_TYPE_I32 || type == TCG_TYPE_I64);
24886482e9d2SRichard Henderson     width = (type == TCG_TYPE_I32 ? 32 : 64);
24896482e9d2SRichard Henderson 
24906482e9d2SRichard Henderson     tcg_debug_assert(ofs < width);
24910e4c6424SRichard Henderson     tcg_debug_assert(len > 0);
24926482e9d2SRichard Henderson     tcg_debug_assert(len <= width - ofs);
24936482e9d2SRichard Henderson 
24946482e9d2SRichard Henderson     return TCG_TARGET_deposit_valid(type, ofs, len);
24950e4c6424SRichard Henderson }
24960e4c6424SRichard Henderson 
249739004a71SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs);
249839004a71SRichard Henderson 
249983a0ad26SRichard Henderson static void tcg_gen_callN(void *func, TCGHelperInfo *info,
250083a0ad26SRichard Henderson                           TCGTemp *ret, TCGTemp **args)
2501c896fe29Sbellard {
250239004a71SRichard Henderson     TCGv_i64 extend_free[MAX_CALL_IARGS];
250339004a71SRichard Henderson     int n_extend = 0;
250475e8b9b7SRichard Henderson     TCGOp *op;
250539004a71SRichard Henderson     int i, n, pi = 0, total_args;
2506afb49896SRichard Henderson 
2507d53106c9SRichard Henderson     if (unlikely(g_once_init_enter(HELPER_INFO_INIT(info)))) {
2508d53106c9SRichard Henderson         init_call_layout(info);
2509d53106c9SRichard Henderson         g_once_init_leave(HELPER_INFO_INIT(info), HELPER_INFO_INIT_VAL(info));
2510d53106c9SRichard Henderson     }
2511d53106c9SRichard Henderson 
251239004a71SRichard Henderson     total_args = info->nr_out + info->nr_in + 2;
251339004a71SRichard Henderson     op = tcg_op_alloc(INDEX_op_call, total_args);
25142bece2c8SRichard Henderson 
251538b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN
251617083f6fSEmilio Cota     /* Flag helpers that may affect guest state */
2517b0748975SRichard Henderson     if (tcg_ctx->plugin_insn && !(info->flags & TCG_CALL_NO_SIDE_EFFECTS)) {
251838b47b19SEmilio G. Cota         tcg_ctx->plugin_insn->calls_helpers = true;
251938b47b19SEmilio G. Cota     }
252038b47b19SEmilio G. Cota #endif
252138b47b19SEmilio G. Cota 
252239004a71SRichard Henderson     TCGOP_CALLO(op) = n = info->nr_out;
252339004a71SRichard Henderson     switch (n) {
252439004a71SRichard Henderson     case 0:
252539004a71SRichard Henderson         tcg_debug_assert(ret == NULL);
252639004a71SRichard Henderson         break;
252739004a71SRichard Henderson     case 1:
252839004a71SRichard Henderson         tcg_debug_assert(ret != NULL);
252939004a71SRichard Henderson         op->args[pi++] = temp_arg(ret);
253039004a71SRichard Henderson         break;
253139004a71SRichard Henderson     case 2:
2532466d3759SRichard Henderson     case 4:
253339004a71SRichard Henderson         tcg_debug_assert(ret != NULL);
2534466d3759SRichard Henderson         tcg_debug_assert(ret->base_type == ret->type + ctz32(n));
253539004a71SRichard Henderson         tcg_debug_assert(ret->temp_subindex == 0);
2536466d3759SRichard Henderson         for (i = 0; i < n; ++i) {
2537466d3759SRichard Henderson             op->args[pi++] = temp_arg(ret + i);
2538466d3759SRichard Henderson         }
253939004a71SRichard Henderson         break;
254039004a71SRichard Henderson     default:
254139004a71SRichard Henderson         g_assert_not_reached();
254239004a71SRichard Henderson     }
25437319d83aSRichard Henderson 
254439004a71SRichard Henderson     TCGOP_CALLI(op) = n = info->nr_in;
254539004a71SRichard Henderson     for (i = 0; i < n; i++) {
254639004a71SRichard Henderson         const TCGCallArgumentLoc *loc = &info->in[i];
254739004a71SRichard Henderson         TCGTemp *ts = args[loc->arg_idx] + loc->tmp_subindex;
254839004a71SRichard Henderson 
254939004a71SRichard Henderson         switch (loc->kind) {
255039004a71SRichard Henderson         case TCG_CALL_ARG_NORMAL:
2551313bdea8SRichard Henderson         case TCG_CALL_ARG_BY_REF:
2552313bdea8SRichard Henderson         case TCG_CALL_ARG_BY_REF_N:
255339004a71SRichard Henderson             op->args[pi++] = temp_arg(ts);
255439004a71SRichard Henderson             break;
255539004a71SRichard Henderson 
255639004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_U:
255739004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_S:
255839004a71SRichard Henderson             {
25595dd48602SRichard Henderson                 TCGv_i64 temp = tcg_temp_ebb_new_i64();
256039004a71SRichard Henderson                 TCGv_i32 orig = temp_tcgv_i32(ts);
256139004a71SRichard Henderson 
256239004a71SRichard Henderson                 if (loc->kind == TCG_CALL_ARG_EXTEND_S) {
256318cf3d07SRichard Henderson                     tcg_gen_ext_i32_i64(temp, orig);
25642bece2c8SRichard Henderson                 } else {
256518cf3d07SRichard Henderson                     tcg_gen_extu_i32_i64(temp, orig);
25662bece2c8SRichard Henderson                 }
256739004a71SRichard Henderson                 op->args[pi++] = tcgv_i64_arg(temp);
256839004a71SRichard Henderson                 extend_free[n_extend++] = temp;
25692bece2c8SRichard Henderson             }
257039004a71SRichard Henderson             break;
25712bece2c8SRichard Henderson 
2572e2a9dd6bSRichard Henderson         default:
2573e2a9dd6bSRichard Henderson             g_assert_not_reached();
2574e2a9dd6bSRichard Henderson         }
2575c896fe29Sbellard     }
257683a0ad26SRichard Henderson     op->args[pi++] = (uintptr_t)func;
25773e92aa34SRichard Henderson     op->args[pi++] = (uintptr_t)info;
257839004a71SRichard Henderson     tcg_debug_assert(pi == total_args);
2579a7812ae4Spbrook 
258007843f75SRichard Henderson     if (tcg_ctx->emit_before_op) {
258107843f75SRichard Henderson         QTAILQ_INSERT_BEFORE(tcg_ctx->emit_before_op, op, link);
258207843f75SRichard Henderson     } else {
258339004a71SRichard Henderson         QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
258407843f75SRichard Henderson     }
25852bece2c8SRichard Henderson 
258639004a71SRichard Henderson     tcg_debug_assert(n_extend < ARRAY_SIZE(extend_free));
258739004a71SRichard Henderson     for (i = 0; i < n_extend; ++i) {
258839004a71SRichard Henderson         tcg_temp_free_i64(extend_free[i]);
2589eb8b0224SRichard Henderson     }
2590a7812ae4Spbrook }
2591c896fe29Sbellard 
259283a0ad26SRichard Henderson void tcg_gen_call0(void *func, TCGHelperInfo *info, TCGTemp *ret)
2593a3a692b8SRichard Henderson {
259483a0ad26SRichard Henderson     tcg_gen_callN(func, info, ret, NULL);
2595a3a692b8SRichard Henderson }
2596a3a692b8SRichard Henderson 
259783a0ad26SRichard Henderson void tcg_gen_call1(void *func, TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1)
2598a3a692b8SRichard Henderson {
259983a0ad26SRichard Henderson     tcg_gen_callN(func, info, ret, &t1);
2600a3a692b8SRichard Henderson }
2601a3a692b8SRichard Henderson 
260283a0ad26SRichard Henderson void tcg_gen_call2(void *func, TCGHelperInfo *info, TCGTemp *ret,
260383a0ad26SRichard Henderson                    TCGTemp *t1, TCGTemp *t2)
2604a3a692b8SRichard Henderson {
2605a3a692b8SRichard Henderson     TCGTemp *args[2] = { t1, t2 };
260683a0ad26SRichard Henderson     tcg_gen_callN(func, info, ret, args);
2607a3a692b8SRichard Henderson }
2608a3a692b8SRichard Henderson 
260983a0ad26SRichard Henderson void tcg_gen_call3(void *func, TCGHelperInfo *info, TCGTemp *ret,
261083a0ad26SRichard Henderson                    TCGTemp *t1, TCGTemp *t2, TCGTemp *t3)
2611a3a692b8SRichard Henderson {
2612a3a692b8SRichard Henderson     TCGTemp *args[3] = { t1, t2, t3 };
261383a0ad26SRichard Henderson     tcg_gen_callN(func, info, ret, args);
2614a3a692b8SRichard Henderson }
2615a3a692b8SRichard Henderson 
261683a0ad26SRichard Henderson void tcg_gen_call4(void *func, TCGHelperInfo *info, TCGTemp *ret,
261783a0ad26SRichard Henderson                    TCGTemp *t1, TCGTemp *t2, TCGTemp *t3, TCGTemp *t4)
2618a3a692b8SRichard Henderson {
2619a3a692b8SRichard Henderson     TCGTemp *args[4] = { t1, t2, t3, t4 };
262083a0ad26SRichard Henderson     tcg_gen_callN(func, info, ret, args);
2621a3a692b8SRichard Henderson }
2622a3a692b8SRichard Henderson 
262383a0ad26SRichard Henderson void tcg_gen_call5(void *func, TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1,
2624a3a692b8SRichard Henderson                    TCGTemp *t2, TCGTemp *t3, TCGTemp *t4, TCGTemp *t5)
2625a3a692b8SRichard Henderson {
2626a3a692b8SRichard Henderson     TCGTemp *args[5] = { t1, t2, t3, t4, t5 };
262783a0ad26SRichard Henderson     tcg_gen_callN(func, info, ret, args);
2628a3a692b8SRichard Henderson }
2629a3a692b8SRichard Henderson 
263083a0ad26SRichard Henderson void tcg_gen_call6(void *func, TCGHelperInfo *info, TCGTemp *ret,
263183a0ad26SRichard Henderson                    TCGTemp *t1, TCGTemp *t2, TCGTemp *t3,
263283a0ad26SRichard Henderson                    TCGTemp *t4, TCGTemp *t5, TCGTemp *t6)
2633a3a692b8SRichard Henderson {
2634a3a692b8SRichard Henderson     TCGTemp *args[6] = { t1, t2, t3, t4, t5, t6 };
263583a0ad26SRichard Henderson     tcg_gen_callN(func, info, ret, args);
2636a3a692b8SRichard Henderson }
2637a3a692b8SRichard Henderson 
263883a0ad26SRichard Henderson void tcg_gen_call7(void *func, TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1,
2639a3a692b8SRichard Henderson                    TCGTemp *t2, TCGTemp *t3, TCGTemp *t4,
2640a3a692b8SRichard Henderson                    TCGTemp *t5, TCGTemp *t6, TCGTemp *t7)
2641a3a692b8SRichard Henderson {
2642a3a692b8SRichard Henderson     TCGTemp *args[7] = { t1, t2, t3, t4, t5, t6, t7 };
264383a0ad26SRichard Henderson     tcg_gen_callN(func, info, ret, args);
2644a3a692b8SRichard Henderson }
2645a3a692b8SRichard Henderson 
26468fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s)
2647c896fe29Sbellard {
2648ac3b8891SRichard Henderson     int i, n;
2649ac3b8891SRichard Henderson 
2650ee17db83SRichard Henderson     for (i = 0, n = s->nb_temps; i < n; i++) {
2651ee17db83SRichard Henderson         TCGTemp *ts = &s->temps[i];
2652ee17db83SRichard Henderson         TCGTempVal val = TEMP_VAL_MEM;
2653ee17db83SRichard Henderson 
2654ee17db83SRichard Henderson         switch (ts->kind) {
2655c0522136SRichard Henderson         case TEMP_CONST:
2656c0522136SRichard Henderson             val = TEMP_VAL_CONST;
2657c0522136SRichard Henderson             break;
2658ee17db83SRichard Henderson         case TEMP_FIXED:
2659ee17db83SRichard Henderson             val = TEMP_VAL_REG;
2660ee17db83SRichard Henderson             break;
2661ee17db83SRichard Henderson         case TEMP_GLOBAL:
2662ee17db83SRichard Henderson             break;
2663c7482438SRichard Henderson         case TEMP_EBB:
2664ee17db83SRichard Henderson             val = TEMP_VAL_DEAD;
2665ee17db83SRichard Henderson             /* fall through */
2666f57c6915SRichard Henderson         case TEMP_TB:
2667e8996ee0Sbellard             ts->mem_allocated = 0;
2668ee17db83SRichard Henderson             break;
2669ee17db83SRichard Henderson         default:
2670ee17db83SRichard Henderson             g_assert_not_reached();
2671ee17db83SRichard Henderson         }
2672ee17db83SRichard Henderson         ts->val_type = val;
2673e8996ee0Sbellard     }
2674f8b2f202SRichard Henderson 
2675f8b2f202SRichard Henderson     memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp));
2676c896fe29Sbellard }
2677c896fe29Sbellard 
2678f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size,
2679f8b2f202SRichard Henderson                                  TCGTemp *ts)
2680c896fe29Sbellard {
26811807f4c4SRichard Henderson     int idx = temp_idx(ts);
2682ac56dd48Spbrook 
2683ee17db83SRichard Henderson     switch (ts->kind) {
2684ee17db83SRichard Henderson     case TEMP_FIXED:
2685ee17db83SRichard Henderson     case TEMP_GLOBAL:
2686ac56dd48Spbrook         pstrcpy(buf, buf_size, ts->name);
2687ee17db83SRichard Henderson         break;
2688f57c6915SRichard Henderson     case TEMP_TB:
2689641d5fbeSbellard         snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
2690ee17db83SRichard Henderson         break;
2691c7482438SRichard Henderson     case TEMP_EBB:
2692ac56dd48Spbrook         snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
2693ee17db83SRichard Henderson         break;
2694c0522136SRichard Henderson     case TEMP_CONST:
2695c0522136SRichard Henderson         switch (ts->type) {
2696c0522136SRichard Henderson         case TCG_TYPE_I32:
2697c0522136SRichard Henderson             snprintf(buf, buf_size, "$0x%x", (int32_t)ts->val);
2698c0522136SRichard Henderson             break;
2699c0522136SRichard Henderson #if TCG_TARGET_REG_BITS > 32
2700c0522136SRichard Henderson         case TCG_TYPE_I64:
2701c0522136SRichard Henderson             snprintf(buf, buf_size, "$0x%" PRIx64, ts->val);
2702c0522136SRichard Henderson             break;
2703c0522136SRichard Henderson #endif
2704c0522136SRichard Henderson         case TCG_TYPE_V64:
2705c0522136SRichard Henderson         case TCG_TYPE_V128:
2706c0522136SRichard Henderson         case TCG_TYPE_V256:
2707c0522136SRichard Henderson             snprintf(buf, buf_size, "v%d$0x%" PRIx64,
2708c0522136SRichard Henderson                      64 << (ts->type - TCG_TYPE_V64), ts->val);
2709c0522136SRichard Henderson             break;
2710c0522136SRichard Henderson         default:
2711c0522136SRichard Henderson             g_assert_not_reached();
2712c0522136SRichard Henderson         }
2713c0522136SRichard Henderson         break;
2714c896fe29Sbellard     }
2715c896fe29Sbellard     return buf;
2716c896fe29Sbellard }
2717c896fe29Sbellard 
271843439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf,
271943439139SRichard Henderson                              int buf_size, TCGArg arg)
2720f8b2f202SRichard Henderson {
272143439139SRichard Henderson     return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg));
2722f8b2f202SRichard Henderson }
2723f8b2f202SRichard Henderson 
2724f48f3edeSblueswir1 static const char * const cond_name[] =
2725f48f3edeSblueswir1 {
27260aed257fSRichard Henderson     [TCG_COND_NEVER] = "never",
27270aed257fSRichard Henderson     [TCG_COND_ALWAYS] = "always",
2728f48f3edeSblueswir1     [TCG_COND_EQ] = "eq",
2729f48f3edeSblueswir1     [TCG_COND_NE] = "ne",
2730f48f3edeSblueswir1     [TCG_COND_LT] = "lt",
2731f48f3edeSblueswir1     [TCG_COND_GE] = "ge",
2732f48f3edeSblueswir1     [TCG_COND_LE] = "le",
2733f48f3edeSblueswir1     [TCG_COND_GT] = "gt",
2734f48f3edeSblueswir1     [TCG_COND_LTU] = "ltu",
2735f48f3edeSblueswir1     [TCG_COND_GEU] = "geu",
2736f48f3edeSblueswir1     [TCG_COND_LEU] = "leu",
2737d48097d0SRichard Henderson     [TCG_COND_GTU] = "gtu",
2738d48097d0SRichard Henderson     [TCG_COND_TSTEQ] = "tsteq",
2739d48097d0SRichard Henderson     [TCG_COND_TSTNE] = "tstne",
2740f48f3edeSblueswir1 };
2741f48f3edeSblueswir1 
274212fde9bcSRichard Henderson static const char * const ldst_name[(MO_BSWAP | MO_SSIZE) + 1] =
2743f713d6adSRichard Henderson {
2744f713d6adSRichard Henderson     [MO_UB]   = "ub",
2745f713d6adSRichard Henderson     [MO_SB]   = "sb",
2746f713d6adSRichard Henderson     [MO_LEUW] = "leuw",
2747f713d6adSRichard Henderson     [MO_LESW] = "lesw",
2748f713d6adSRichard Henderson     [MO_LEUL] = "leul",
2749f713d6adSRichard Henderson     [MO_LESL] = "lesl",
2750fc313c64SFrédéric Pétrot     [MO_LEUQ] = "leq",
2751f713d6adSRichard Henderson     [MO_BEUW] = "beuw",
2752f713d6adSRichard Henderson     [MO_BESW] = "besw",
2753f713d6adSRichard Henderson     [MO_BEUL] = "beul",
2754f713d6adSRichard Henderson     [MO_BESL] = "besl",
2755fc313c64SFrédéric Pétrot     [MO_BEUQ] = "beq",
275612fde9bcSRichard Henderson     [MO_128 + MO_BE] = "beo",
275712fde9bcSRichard Henderson     [MO_128 + MO_LE] = "leo",
2758f713d6adSRichard Henderson };
2759f713d6adSRichard Henderson 
27601f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = {
27611f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "un+",
27621f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "al+",
27631f00b27fSSergey Sorokin     [MO_ALIGN_2 >> MO_ASHIFT]  = "al2+",
27641f00b27fSSergey Sorokin     [MO_ALIGN_4 >> MO_ASHIFT]  = "al4+",
27651f00b27fSSergey Sorokin     [MO_ALIGN_8 >> MO_ASHIFT]  = "al8+",
27661f00b27fSSergey Sorokin     [MO_ALIGN_16 >> MO_ASHIFT] = "al16+",
27671f00b27fSSergey Sorokin     [MO_ALIGN_32 >> MO_ASHIFT] = "al32+",
27681f00b27fSSergey Sorokin     [MO_ALIGN_64 >> MO_ASHIFT] = "al64+",
27691f00b27fSSergey Sorokin };
27701f00b27fSSergey Sorokin 
277137031fefSRichard Henderson static const char * const atom_name[(MO_ATOM_MASK >> MO_ATOM_SHIFT) + 1] = {
277237031fefSRichard Henderson     [MO_ATOM_IFALIGN >> MO_ATOM_SHIFT] = "",
277337031fefSRichard Henderson     [MO_ATOM_IFALIGN_PAIR >> MO_ATOM_SHIFT] = "pair+",
277437031fefSRichard Henderson     [MO_ATOM_WITHIN16 >> MO_ATOM_SHIFT] = "w16+",
277537031fefSRichard Henderson     [MO_ATOM_WITHIN16_PAIR >> MO_ATOM_SHIFT] = "w16p+",
277637031fefSRichard Henderson     [MO_ATOM_SUBALIGN >> MO_ATOM_SHIFT] = "sub+",
277737031fefSRichard Henderson     [MO_ATOM_NONE >> MO_ATOM_SHIFT] = "noat+",
277837031fefSRichard Henderson };
277937031fefSRichard Henderson 
2780587195bdSRichard Henderson static const char bswap_flag_name[][6] = {
2781587195bdSRichard Henderson     [TCG_BSWAP_IZ] = "iz",
2782587195bdSRichard Henderson     [TCG_BSWAP_OZ] = "oz",
2783587195bdSRichard Henderson     [TCG_BSWAP_OS] = "os",
2784587195bdSRichard Henderson     [TCG_BSWAP_IZ | TCG_BSWAP_OZ] = "iz,oz",
2785587195bdSRichard Henderson     [TCG_BSWAP_IZ | TCG_BSWAP_OS] = "iz,os",
2786587195bdSRichard Henderson };
2787587195bdSRichard Henderson 
2788b384c734SRichard Henderson #ifdef CONFIG_PLUGIN
2789b384c734SRichard Henderson static const char * const plugin_from_name[] = {
2790b384c734SRichard Henderson     "from-tb",
2791b384c734SRichard Henderson     "from-insn",
2792b384c734SRichard Henderson     "after-insn",
2793b384c734SRichard Henderson     "after-tb",
2794b384c734SRichard Henderson };
2795b384c734SRichard Henderson #endif
2796b384c734SRichard Henderson 
2797b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d)
2798b016486eSRichard Henderson {
2799b016486eSRichard Henderson     return (d & (d - 1)) == 0;
2800b016486eSRichard Henderson }
2801b016486eSRichard Henderson 
2802b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d)
2803b016486eSRichard Henderson {
2804b016486eSRichard Henderson     if (TCG_TARGET_NB_REGS <= 32) {
2805b016486eSRichard Henderson         return ctz32(d);
2806b016486eSRichard Henderson     } else {
2807b016486eSRichard Henderson         return ctz64(d);
2808b016486eSRichard Henderson     }
2809b016486eSRichard Henderson }
2810b016486eSRichard Henderson 
2811b7a83ff8SRichard Henderson /* Return only the number of characters output -- no error return. */
2812b7a83ff8SRichard Henderson #define ne_fprintf(...) \
2813b7a83ff8SRichard Henderson     ({ int ret_ = fprintf(__VA_ARGS__); ret_ >= 0 ? ret_ : 0; })
2814b7a83ff8SRichard Henderson 
2815b384c734SRichard Henderson void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs)
2816c896fe29Sbellard {
2817c896fe29Sbellard     char buf[128];
2818c45cb8bbSRichard Henderson     TCGOp *op;
2819c896fe29Sbellard 
282015fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
2821c45cb8bbSRichard Henderson         int i, k, nb_oargs, nb_iargs, nb_cargs;
2822c45cb8bbSRichard Henderson         const TCGOpDef *def;
2823c45cb8bbSRichard Henderson         TCGOpcode c;
2824bdfb460eSRichard Henderson         int col = 0;
2825c45cb8bbSRichard Henderson 
2826c45cb8bbSRichard Henderson         c = op->opc;
2827c896fe29Sbellard         def = &tcg_op_defs[c];
2828c45cb8bbSRichard Henderson 
2829765b842aSRichard Henderson         if (c == INDEX_op_insn_start) {
2830b016486eSRichard Henderson             nb_oargs = 0;
2831b7a83ff8SRichard Henderson             col += ne_fprintf(f, "\n ----");
28329aef40edSRichard Henderson 
2833747bd69dSRichard Henderson             for (i = 0, k = s->insn_start_words; i < k; ++i) {
2834c9ad8d27SRichard Henderson                 col += ne_fprintf(f, " %016" PRIx64,
2835c9ad8d27SRichard Henderson                                   tcg_get_insn_start_param(op, i));
2836eeacee4dSBlue Swirl             }
28377e4597d7Sbellard         } else if (c == INDEX_op_call) {
28383e92aa34SRichard Henderson             const TCGHelperInfo *info = tcg_call_info(op);
2839fa52e660SRichard Henderson             void *func = tcg_call_func(op);
28403e92aa34SRichard Henderson 
2841c896fe29Sbellard             /* variable number of arguments */
2842cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
2843cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
2844c896fe29Sbellard             nb_cargs = def->nb_cargs;
2845b03cce8eSbellard 
2846b7a83ff8SRichard Henderson             col += ne_fprintf(f, " %s ", def->name);
28473e92aa34SRichard Henderson 
28483e92aa34SRichard Henderson             /*
28493e92aa34SRichard Henderson              * Print the function name from TCGHelperInfo, if available.
28503e92aa34SRichard Henderson              * Note that plugins have a template function for the info,
28513e92aa34SRichard Henderson              * but the actual function pointer comes from the plugin.
28523e92aa34SRichard Henderson              */
28533e92aa34SRichard Henderson             if (func == info->func) {
2854b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s", info->name);
28553e92aa34SRichard Henderson             } else {
2856b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "plugin(%p)", func);
28573e92aa34SRichard Henderson             }
28583e92aa34SRichard Henderson 
2859b7a83ff8SRichard Henderson             col += ne_fprintf(f, ",$0x%x,$%d", info->flags, nb_oargs);
2860b03cce8eSbellard             for (i = 0; i < nb_oargs; i++) {
2861b7a83ff8SRichard Henderson                 col += ne_fprintf(f, ",%s", tcg_get_arg_str(s, buf, sizeof(buf),
2862efee3746SRichard Henderson                                                             op->args[i]));
2863b03cce8eSbellard             }
2864cf066674SRichard Henderson             for (i = 0; i < nb_iargs; i++) {
2865efee3746SRichard Henderson                 TCGArg arg = op->args[nb_oargs + i];
286639004a71SRichard Henderson                 const char *t = tcg_get_arg_str(s, buf, sizeof(buf), arg);
2867b7a83ff8SRichard Henderson                 col += ne_fprintf(f, ",%s", t);
2868e8996ee0Sbellard             }
2869b03cce8eSbellard         } else {
2870b5701261SRichard Henderson             if (def->flags & TCG_OPF_INT) {
2871b5701261SRichard Henderson                 col += ne_fprintf(f, " %s_i%d ",
2872b5701261SRichard Henderson                                   def->name,
2873b5701261SRichard Henderson                                   8 * tcg_type_size(TCGOP_TYPE(op)));
2874b5701261SRichard Henderson             } else if (def->flags & TCG_OPF_VECTOR) {
2875b5701261SRichard Henderson                 col += ne_fprintf(f, "%s v%d,e%d,",
2876b5701261SRichard Henderson                                   def->name,
2877b5701261SRichard Henderson                                   8 * tcg_type_size(TCGOP_TYPE(op)),
2878b5701261SRichard Henderson                                   8 << TCGOP_VECE(op));
2879b5701261SRichard Henderson             } else {
2880b7a83ff8SRichard Henderson                 col += ne_fprintf(f, " %s ", def->name);
2881b5701261SRichard Henderson             }
2882c45cb8bbSRichard Henderson 
2883c896fe29Sbellard             nb_oargs = def->nb_oargs;
2884c896fe29Sbellard             nb_iargs = def->nb_iargs;
2885c896fe29Sbellard             nb_cargs = def->nb_cargs;
2886c896fe29Sbellard 
2887c896fe29Sbellard             k = 0;
2888c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
2889b7a83ff8SRichard Henderson                 const char *sep =  k ? "," : "";
2890b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s%s", sep,
2891b7a83ff8SRichard Henderson                                   tcg_get_arg_str(s, buf, sizeof(buf),
2892efee3746SRichard Henderson                                                   op->args[k++]));
2893c896fe29Sbellard             }
2894c896fe29Sbellard             for (i = 0; i < nb_iargs; i++) {
2895b7a83ff8SRichard Henderson                 const char *sep =  k ? "," : "";
2896b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s%s", sep,
2897b7a83ff8SRichard Henderson                                   tcg_get_arg_str(s, buf, sizeof(buf),
2898efee3746SRichard Henderson                                                   op->args[k++]));
2899c896fe29Sbellard             }
2900be210acbSRichard Henderson             switch (c) {
2901b6d69fceSRichard Henderson             case INDEX_op_brcond:
2902a363e1e1SRichard Henderson             case INDEX_op_setcond:
2903a363e1e1SRichard Henderson             case INDEX_op_negsetcond:
2904ea46c4bcSRichard Henderson             case INDEX_op_movcond:
2905be210acbSRichard Henderson             case INDEX_op_brcond2_i32:
2906be210acbSRichard Henderson             case INDEX_op_setcond2_i32:
2907212be173SRichard Henderson             case INDEX_op_cmp_vec:
2908f75da298SRichard Henderson             case INDEX_op_cmpsel_vec:
2909efee3746SRichard Henderson                 if (op->args[k] < ARRAY_SIZE(cond_name)
2910efee3746SRichard Henderson                     && cond_name[op->args[k]]) {
2911b7a83ff8SRichard Henderson                     col += ne_fprintf(f, ",%s", cond_name[op->args[k++]]);
2912eeacee4dSBlue Swirl                 } else {
2913b7a83ff8SRichard Henderson                     col += ne_fprintf(f, ",$0x%" TCG_PRIlx, op->args[k++]);
2914eeacee4dSBlue Swirl                 }
2915f48f3edeSblueswir1                 i = 1;
2916be210acbSRichard Henderson                 break;
291750b7a197SRichard Henderson             case INDEX_op_qemu_ld_i32:
291850b7a197SRichard Henderson             case INDEX_op_qemu_st_i32:
291950b7a197SRichard Henderson             case INDEX_op_qemu_st8_i32:
292050b7a197SRichard Henderson             case INDEX_op_qemu_ld_i64:
292150b7a197SRichard Henderson             case INDEX_op_qemu_st_i64:
292250b7a197SRichard Henderson             case INDEX_op_qemu_ld_i128:
292350b7a197SRichard Henderson             case INDEX_op_qemu_st_i128:
292459227d5dSRichard Henderson                 {
292537031fefSRichard Henderson                     const char *s_al, *s_op, *s_at;
29269002ffcbSRichard Henderson                     MemOpIdx oi = op->args[k++];
29279a239c6eSPhilippe Mathieu-Daudé                     MemOp mop = get_memop(oi);
292859227d5dSRichard Henderson                     unsigned ix = get_mmuidx(oi);
292959227d5dSRichard Henderson 
29309a239c6eSPhilippe Mathieu-Daudé                     s_al = alignment_name[(mop & MO_AMASK) >> MO_ASHIFT];
29319a239c6eSPhilippe Mathieu-Daudé                     s_op = ldst_name[mop & (MO_BSWAP | MO_SSIZE)];
29329a239c6eSPhilippe Mathieu-Daudé                     s_at = atom_name[(mop & MO_ATOM_MASK) >> MO_ATOM_SHIFT];
29339a239c6eSPhilippe Mathieu-Daudé                     mop &= ~(MO_AMASK | MO_BSWAP | MO_SSIZE | MO_ATOM_MASK);
293437031fefSRichard Henderson 
293537031fefSRichard Henderson                     /* If all fields are accounted for, print symbolically. */
29369a239c6eSPhilippe Mathieu-Daudé                     if (!mop && s_al && s_op && s_at) {
293737031fefSRichard Henderson                         col += ne_fprintf(f, ",%s%s%s,%u",
293837031fefSRichard Henderson                                           s_at, s_al, s_op, ix);
293937031fefSRichard Henderson                     } else {
29409a239c6eSPhilippe Mathieu-Daudé                         mop = get_memop(oi);
29419a239c6eSPhilippe Mathieu-Daudé                         col += ne_fprintf(f, ",$0x%x,%u", mop, ix);
2942f713d6adSRichard Henderson                     }
2943f713d6adSRichard Henderson                     i = 1;
294459227d5dSRichard Henderson                 }
2945f713d6adSRichard Henderson                 break;
29460dd07ee1SRichard Henderson             case INDEX_op_bswap16:
29477498d882SRichard Henderson             case INDEX_op_bswap32:
29483ad5d4ccSRichard Henderson             case INDEX_op_bswap64:
2949587195bdSRichard Henderson                 {
2950587195bdSRichard Henderson                     TCGArg flags = op->args[k];
2951587195bdSRichard Henderson                     const char *name = NULL;
2952587195bdSRichard Henderson 
2953587195bdSRichard Henderson                     if (flags < ARRAY_SIZE(bswap_flag_name)) {
2954587195bdSRichard Henderson                         name = bswap_flag_name[flags];
2955587195bdSRichard Henderson                     }
2956587195bdSRichard Henderson                     if (name) {
2957b7a83ff8SRichard Henderson                         col += ne_fprintf(f, ",%s", name);
2958587195bdSRichard Henderson                     } else {
2959b7a83ff8SRichard Henderson                         col += ne_fprintf(f, ",$0x%" TCG_PRIlx, flags);
2960587195bdSRichard Henderson                     }
2961587195bdSRichard Henderson                     i = k = 1;
2962587195bdSRichard Henderson                 }
2963587195bdSRichard Henderson                 break;
2964b384c734SRichard Henderson #ifdef CONFIG_PLUGIN
2965b384c734SRichard Henderson             case INDEX_op_plugin_cb:
2966b384c734SRichard Henderson                 {
2967b384c734SRichard Henderson                     TCGArg from = op->args[k++];
2968b384c734SRichard Henderson                     const char *name = NULL;
2969b384c734SRichard Henderson 
2970b384c734SRichard Henderson                     if (from < ARRAY_SIZE(plugin_from_name)) {
2971b384c734SRichard Henderson                         name = plugin_from_name[from];
2972b384c734SRichard Henderson                     }
2973b384c734SRichard Henderson                     if (name) {
2974b384c734SRichard Henderson                         col += ne_fprintf(f, "%s", name);
2975b384c734SRichard Henderson                     } else {
2976b384c734SRichard Henderson                         col += ne_fprintf(f, "$0x%" TCG_PRIlx, from);
2977b384c734SRichard Henderson                     }
2978b384c734SRichard Henderson                     i = 1;
2979b384c734SRichard Henderson                 }
2980b384c734SRichard Henderson                 break;
2981b384c734SRichard Henderson #endif
2982be210acbSRichard Henderson             default:
2983f48f3edeSblueswir1                 i = 0;
2984be210acbSRichard Henderson                 break;
2985be210acbSRichard Henderson             }
298651e3972cSRichard Henderson             switch (c) {
298751e3972cSRichard Henderson             case INDEX_op_set_label:
298851e3972cSRichard Henderson             case INDEX_op_br:
2989b6d69fceSRichard Henderson             case INDEX_op_brcond:
299051e3972cSRichard Henderson             case INDEX_op_brcond2_i32:
2991b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s$L%d", k ? "," : "",
2992efee3746SRichard Henderson                                   arg_label(op->args[k])->id);
299351e3972cSRichard Henderson                 i++, k++;
299451e3972cSRichard Henderson                 break;
29953470867bSRichard Henderson             case INDEX_op_mb:
29963470867bSRichard Henderson                 {
29973470867bSRichard Henderson                     TCGBar membar = op->args[k];
29983470867bSRichard Henderson                     const char *b_op, *m_op;
29993470867bSRichard Henderson 
30003470867bSRichard Henderson                     switch (membar & TCG_BAR_SC) {
30013470867bSRichard Henderson                     case 0:
30023470867bSRichard Henderson                         b_op = "none";
30033470867bSRichard Henderson                         break;
30043470867bSRichard Henderson                     case TCG_BAR_LDAQ:
30053470867bSRichard Henderson                         b_op = "acq";
30063470867bSRichard Henderson                         break;
30073470867bSRichard Henderson                     case TCG_BAR_STRL:
30083470867bSRichard Henderson                         b_op = "rel";
30093470867bSRichard Henderson                         break;
30103470867bSRichard Henderson                     case TCG_BAR_SC:
30113470867bSRichard Henderson                         b_op = "seq";
30123470867bSRichard Henderson                         break;
30133470867bSRichard Henderson                     default:
30143470867bSRichard Henderson                         g_assert_not_reached();
30153470867bSRichard Henderson                     }
30163470867bSRichard Henderson 
30173470867bSRichard Henderson                     switch (membar & TCG_MO_ALL) {
30183470867bSRichard Henderson                     case 0:
30193470867bSRichard Henderson                         m_op = "none";
30203470867bSRichard Henderson                         break;
30213470867bSRichard Henderson                     case TCG_MO_LD_LD:
30223470867bSRichard Henderson                         m_op = "rr";
30233470867bSRichard Henderson                         break;
30243470867bSRichard Henderson                     case TCG_MO_LD_ST:
30253470867bSRichard Henderson                         m_op = "rw";
30263470867bSRichard Henderson                         break;
30273470867bSRichard Henderson                     case TCG_MO_ST_LD:
30283470867bSRichard Henderson                         m_op = "wr";
30293470867bSRichard Henderson                         break;
30303470867bSRichard Henderson                     case TCG_MO_ST_ST:
30313470867bSRichard Henderson                         m_op = "ww";
30323470867bSRichard Henderson                         break;
30333470867bSRichard Henderson                     case TCG_MO_LD_LD | TCG_MO_LD_ST:
30343470867bSRichard Henderson                         m_op = "rr+rw";
30353470867bSRichard Henderson                         break;
30363470867bSRichard Henderson                     case TCG_MO_LD_LD | TCG_MO_ST_LD:
30373470867bSRichard Henderson                         m_op = "rr+wr";
30383470867bSRichard Henderson                         break;
30393470867bSRichard Henderson                     case TCG_MO_LD_LD | TCG_MO_ST_ST:
30403470867bSRichard Henderson                         m_op = "rr+ww";
30413470867bSRichard Henderson                         break;
30423470867bSRichard Henderson                     case TCG_MO_LD_ST | TCG_MO_ST_LD:
30433470867bSRichard Henderson                         m_op = "rw+wr";
30443470867bSRichard Henderson                         break;
30453470867bSRichard Henderson                     case TCG_MO_LD_ST | TCG_MO_ST_ST:
30463470867bSRichard Henderson                         m_op = "rw+ww";
30473470867bSRichard Henderson                         break;
30483470867bSRichard Henderson                     case TCG_MO_ST_LD | TCG_MO_ST_ST:
30493470867bSRichard Henderson                         m_op = "wr+ww";
30503470867bSRichard Henderson                         break;
30513470867bSRichard Henderson                     case TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_MO_ST_LD:
30523470867bSRichard Henderson                         m_op = "rr+rw+wr";
30533470867bSRichard Henderson                         break;
30543470867bSRichard Henderson                     case TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_MO_ST_ST:
30553470867bSRichard Henderson                         m_op = "rr+rw+ww";
30563470867bSRichard Henderson                         break;
30573470867bSRichard Henderson                     case TCG_MO_LD_LD | TCG_MO_ST_LD | TCG_MO_ST_ST:
30583470867bSRichard Henderson                         m_op = "rr+wr+ww";
30593470867bSRichard Henderson                         break;
30603470867bSRichard Henderson                     case TCG_MO_LD_ST | TCG_MO_ST_LD | TCG_MO_ST_ST:
30613470867bSRichard Henderson                         m_op = "rw+wr+ww";
30623470867bSRichard Henderson                         break;
30633470867bSRichard Henderson                     case TCG_MO_ALL:
30643470867bSRichard Henderson                         m_op = "all";
30653470867bSRichard Henderson                         break;
30663470867bSRichard Henderson                     default:
30673470867bSRichard Henderson                         g_assert_not_reached();
30683470867bSRichard Henderson                     }
30693470867bSRichard Henderson 
30703470867bSRichard Henderson                     col += ne_fprintf(f, "%s%s:%s", (k ? "," : ""), b_op, m_op);
30713470867bSRichard Henderson                     i++, k++;
30723470867bSRichard Henderson                 }
30733470867bSRichard Henderson                 break;
307451e3972cSRichard Henderson             default:
307551e3972cSRichard Henderson                 break;
3076eeacee4dSBlue Swirl             }
307751e3972cSRichard Henderson             for (; i < nb_cargs; i++, k++) {
3078b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s$0x%" TCG_PRIlx, k ? "," : "",
3079b7a83ff8SRichard Henderson                                   op->args[k]);
3080bdfb460eSRichard Henderson             }
3081bdfb460eSRichard Henderson         }
3082bdfb460eSRichard Henderson 
30831894f69aSRichard Henderson         if (have_prefs || op->life) {
30841894f69aSRichard Henderson             for (; col < 40; ++col) {
3085b7a83ff8SRichard Henderson                 putc(' ', f);
3086bdfb460eSRichard Henderson             }
30871894f69aSRichard Henderson         }
30881894f69aSRichard Henderson 
30891894f69aSRichard Henderson         if (op->life) {
30901894f69aSRichard Henderson             unsigned life = op->life;
3091bdfb460eSRichard Henderson 
3092bdfb460eSRichard Henderson             if (life & (SYNC_ARG * 3)) {
3093b7a83ff8SRichard Henderson                 ne_fprintf(f, "  sync:");
3094bdfb460eSRichard Henderson                 for (i = 0; i < 2; ++i) {
3095bdfb460eSRichard Henderson                     if (life & (SYNC_ARG << i)) {
3096b7a83ff8SRichard Henderson                         ne_fprintf(f, " %d", i);
3097bdfb460eSRichard Henderson                     }
3098bdfb460eSRichard Henderson                 }
3099bdfb460eSRichard Henderson             }
3100bdfb460eSRichard Henderson             life /= DEAD_ARG;
3101bdfb460eSRichard Henderson             if (life) {
3102b7a83ff8SRichard Henderson                 ne_fprintf(f, "  dead:");
3103bdfb460eSRichard Henderson                 for (i = 0; life; ++i, life >>= 1) {
3104bdfb460eSRichard Henderson                     if (life & 1) {
3105b7a83ff8SRichard Henderson                         ne_fprintf(f, " %d", i);
3106bdfb460eSRichard Henderson                     }
3107bdfb460eSRichard Henderson                 }
3108c896fe29Sbellard             }
3109b03cce8eSbellard         }
31101894f69aSRichard Henderson 
31111894f69aSRichard Henderson         if (have_prefs) {
31121894f69aSRichard Henderson             for (i = 0; i < nb_oargs; ++i) {
311331fd884bSRichard Henderson                 TCGRegSet set = output_pref(op, i);
31141894f69aSRichard Henderson 
31151894f69aSRichard Henderson                 if (i == 0) {
3116b7a83ff8SRichard Henderson                     ne_fprintf(f, "  pref=");
31171894f69aSRichard Henderson                 } else {
3118b7a83ff8SRichard Henderson                     ne_fprintf(f, ",");
31191894f69aSRichard Henderson                 }
31201894f69aSRichard Henderson                 if (set == 0) {
3121b7a83ff8SRichard Henderson                     ne_fprintf(f, "none");
31221894f69aSRichard Henderson                 } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) {
3123b7a83ff8SRichard Henderson                     ne_fprintf(f, "all");
31241894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG
31251894f69aSRichard Henderson                 } else if (tcg_regset_single(set)) {
31261894f69aSRichard Henderson                     TCGReg reg = tcg_regset_first(set);
3127b7a83ff8SRichard Henderson                     ne_fprintf(f, "%s", tcg_target_reg_names[reg]);
31281894f69aSRichard Henderson #endif
31291894f69aSRichard Henderson                 } else if (TCG_TARGET_NB_REGS <= 32) {
3130b7a83ff8SRichard Henderson                     ne_fprintf(f, "0x%x", (uint32_t)set);
31311894f69aSRichard Henderson                 } else {
3132b7a83ff8SRichard Henderson                     ne_fprintf(f, "0x%" PRIx64, (uint64_t)set);
31331894f69aSRichard Henderson                 }
31341894f69aSRichard Henderson             }
31351894f69aSRichard Henderson         }
31361894f69aSRichard Henderson 
3137b7a83ff8SRichard Henderson         putc('\n', f);
3138c896fe29Sbellard     }
3139c896fe29Sbellard }
3140c896fe29Sbellard 
3141c896fe29Sbellard /* we give more priority to constraints with less registers */
31423e80824eSRichard Henderson static int get_constraint_priority(const TCGArgConstraint *arg_ct, int k)
3143c896fe29Sbellard {
31443e80824eSRichard Henderson     int n;
31453e80824eSRichard Henderson 
31463e80824eSRichard Henderson     arg_ct += k;
31473e80824eSRichard Henderson     n = ctpop64(arg_ct->regs);
3148c896fe29Sbellard 
314929f5e925SRichard Henderson     /*
315029f5e925SRichard Henderson      * Sort constraints of a single register first, which includes output
315129f5e925SRichard Henderson      * aliases (which must exactly match the input already allocated).
315229f5e925SRichard Henderson      */
315329f5e925SRichard Henderson     if (n == 1 || arg_ct->oalias) {
315429f5e925SRichard Henderson         return INT_MAX;
3155c896fe29Sbellard     }
315629f5e925SRichard Henderson 
315729f5e925SRichard Henderson     /*
315829f5e925SRichard Henderson      * Sort register pairs next, first then second immediately after.
315929f5e925SRichard Henderson      * Arbitrarily sort multiple pairs by the index of the first reg;
316029f5e925SRichard Henderson      * there shouldn't be many pairs.
316129f5e925SRichard Henderson      */
316229f5e925SRichard Henderson     switch (arg_ct->pair) {
316329f5e925SRichard Henderson     case 1:
316429f5e925SRichard Henderson     case 3:
316529f5e925SRichard Henderson         return (k + 1) * 2;
316629f5e925SRichard Henderson     case 2:
316729f5e925SRichard Henderson         return (arg_ct->pair_index + 1) * 2 - 1;
316829f5e925SRichard Henderson     }
316929f5e925SRichard Henderson 
317029f5e925SRichard Henderson     /* Finally, sort by decreasing register count. */
317129f5e925SRichard Henderson     assert(n > 1);
317229f5e925SRichard Henderson     return -n;
3173c896fe29Sbellard }
3174c896fe29Sbellard 
3175c896fe29Sbellard /* sort from highest priority to lowest */
31763e80824eSRichard Henderson static void sort_constraints(TCGArgConstraint *a, int start, int n)
3177c896fe29Sbellard {
317866792f90SRichard Henderson     int i, j;
3179c896fe29Sbellard 
318066792f90SRichard Henderson     for (i = 0; i < n; i++) {
318166792f90SRichard Henderson         a[start + i].sort_index = start + i;
318266792f90SRichard Henderson     }
318366792f90SRichard Henderson     if (n <= 1) {
3184c896fe29Sbellard         return;
318566792f90SRichard Henderson     }
3186c896fe29Sbellard     for (i = 0; i < n - 1; i++) {
3187c896fe29Sbellard         for (j = i + 1; j < n; j++) {
31883e80824eSRichard Henderson             int p1 = get_constraint_priority(a, a[start + i].sort_index);
31893e80824eSRichard Henderson             int p2 = get_constraint_priority(a, a[start + j].sort_index);
3190c896fe29Sbellard             if (p1 < p2) {
319166792f90SRichard Henderson                 int tmp = a[start + i].sort_index;
319266792f90SRichard Henderson                 a[start + i].sort_index = a[start + j].sort_index;
319366792f90SRichard Henderson                 a[start + j].sort_index = tmp;
3194c896fe29Sbellard             }
3195c896fe29Sbellard         }
3196c896fe29Sbellard     }
3197c896fe29Sbellard }
3198c896fe29Sbellard 
31993e80824eSRichard Henderson static const TCGArgConstraint empty_cts[TCG_MAX_OP_ARGS];
32003e80824eSRichard Henderson static TCGArgConstraint all_cts[ARRAY_SIZE(constraint_sets)][TCG_MAX_OP_ARGS];
32013e80824eSRichard Henderson 
3202501fb3daSRichard Henderson static void process_constraint_sets(void)
3203c896fe29Sbellard {
32043e80824eSRichard Henderson     for (size_t c = 0; c < ARRAY_SIZE(constraint_sets); ++c) {
32053e80824eSRichard Henderson         const TCGConstraintSet *tdefs = &constraint_sets[c];
32063e80824eSRichard Henderson         TCGArgConstraint *args_ct = all_cts[c];
32073e80824eSRichard Henderson         int nb_oargs = tdefs->nb_oargs;
32083e80824eSRichard Henderson         int nb_iargs = tdefs->nb_iargs;
32093e80824eSRichard Henderson         int nb_args = nb_oargs + nb_iargs;
321029f5e925SRichard Henderson         bool saw_alias_pair = false;
3211f69d277eSRichard Henderson 
32123e80824eSRichard Henderson         for (int i = 0; i < nb_args; i++) {
3213f69d277eSRichard Henderson             const char *ct_str = tdefs->args_ct_str[i];
32143e80824eSRichard Henderson             bool input_p = i >= nb_oargs;
32153e80824eSRichard Henderson             int o;
3216f69d277eSRichard Henderson 
321717280ff4SRichard Henderson             switch (*ct_str) {
321817280ff4SRichard Henderson             case '0' ... '9':
32198940ea0dSPhilippe Mathieu-Daudé                 o = *ct_str - '0';
32208940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(input_p);
32213e80824eSRichard Henderson                 tcg_debug_assert(o < nb_oargs);
32223e80824eSRichard Henderson                 tcg_debug_assert(args_ct[o].regs != 0);
32233e80824eSRichard Henderson                 tcg_debug_assert(!args_ct[o].oalias);
32243e80824eSRichard Henderson                 args_ct[i] = args_ct[o];
3225bc2b17e6SRichard Henderson                 /* The output sets oalias.  */
32263e80824eSRichard Henderson                 args_ct[o].oalias = 1;
32273e80824eSRichard Henderson                 args_ct[o].alias_index = i;
3228bc2b17e6SRichard Henderson                 /* The input sets ialias. */
32293e80824eSRichard Henderson                 args_ct[i].ialias = 1;
32303e80824eSRichard Henderson                 args_ct[i].alias_index = o;
32313e80824eSRichard Henderson                 if (args_ct[i].pair) {
323229f5e925SRichard Henderson                     saw_alias_pair = true;
323329f5e925SRichard Henderson                 }
32348940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(ct_str[1] == '\0');
32358940ea0dSPhilippe Mathieu-Daudé                 continue;
32368940ea0dSPhilippe Mathieu-Daudé 
323782790a87SRichard Henderson             case '&':
32388940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(!input_p);
32393e80824eSRichard Henderson                 args_ct[i].newreg = true;
324082790a87SRichard Henderson                 ct_str++;
324182790a87SRichard Henderson                 break;
324229f5e925SRichard Henderson 
324329f5e925SRichard Henderson             case 'p': /* plus */
324429f5e925SRichard Henderson                 /* Allocate to the register after the previous. */
32453e80824eSRichard Henderson                 tcg_debug_assert(i > (input_p ? nb_oargs : 0));
324629f5e925SRichard Henderson                 o = i - 1;
32473e80824eSRichard Henderson                 tcg_debug_assert(!args_ct[o].pair);
32483e80824eSRichard Henderson                 tcg_debug_assert(!args_ct[o].ct);
32493e80824eSRichard Henderson                 args_ct[i] = (TCGArgConstraint){
325029f5e925SRichard Henderson                     .pair = 2,
325129f5e925SRichard Henderson                     .pair_index = o,
32523e80824eSRichard Henderson                     .regs = args_ct[o].regs << 1,
32533e80824eSRichard Henderson                     .newreg = args_ct[o].newreg,
325429f5e925SRichard Henderson                 };
32553e80824eSRichard Henderson                 args_ct[o].pair = 1;
32563e80824eSRichard Henderson                 args_ct[o].pair_index = i;
325729f5e925SRichard Henderson                 tcg_debug_assert(ct_str[1] == '\0');
325829f5e925SRichard Henderson                 continue;
325929f5e925SRichard Henderson 
326029f5e925SRichard Henderson             case 'm': /* minus */
326129f5e925SRichard Henderson                 /* Allocate to the register before the previous. */
32623e80824eSRichard Henderson                 tcg_debug_assert(i > (input_p ? nb_oargs : 0));
326329f5e925SRichard Henderson                 o = i - 1;
32643e80824eSRichard Henderson                 tcg_debug_assert(!args_ct[o].pair);
32653e80824eSRichard Henderson                 tcg_debug_assert(!args_ct[o].ct);
32663e80824eSRichard Henderson                 args_ct[i] = (TCGArgConstraint){
326729f5e925SRichard Henderson                     .pair = 1,
326829f5e925SRichard Henderson                     .pair_index = o,
32693e80824eSRichard Henderson                     .regs = args_ct[o].regs >> 1,
32703e80824eSRichard Henderson                     .newreg = args_ct[o].newreg,
327129f5e925SRichard Henderson                 };
32723e80824eSRichard Henderson                 args_ct[o].pair = 2;
32733e80824eSRichard Henderson                 args_ct[o].pair_index = i;
327429f5e925SRichard Henderson                 tcg_debug_assert(ct_str[1] == '\0');
327529f5e925SRichard Henderson                 continue;
32768940ea0dSPhilippe Mathieu-Daudé             }
32778940ea0dSPhilippe Mathieu-Daudé 
32788940ea0dSPhilippe Mathieu-Daudé             do {
32798940ea0dSPhilippe Mathieu-Daudé                 switch (*ct_str) {
3280c896fe29Sbellard                 case 'i':
32813e80824eSRichard Henderson                     args_ct[i].ct |= TCG_CT_CONST;
3282c896fe29Sbellard                     break;
32836b8abd24SRichard Henderson #ifdef TCG_REG_ZERO
32846b8abd24SRichard Henderson                 case 'z':
32856b8abd24SRichard Henderson                     args_ct[i].ct |= TCG_CT_REG_ZERO;
32866b8abd24SRichard Henderson                     break;
32876b8abd24SRichard Henderson #endif
3288358b4923SRichard Henderson 
3289358b4923SRichard Henderson                 /* Include all of the target-specific constraints. */
3290358b4923SRichard Henderson 
3291358b4923SRichard Henderson #undef CONST
3292358b4923SRichard Henderson #define CONST(CASE, MASK) \
32933e80824eSRichard Henderson     case CASE: args_ct[i].ct |= MASK; break;
3294358b4923SRichard Henderson #define REGS(CASE, MASK) \
32953e80824eSRichard Henderson     case CASE: args_ct[i].regs |= MASK; break;
3296358b4923SRichard Henderson 
3297358b4923SRichard Henderson #include "tcg-target-con-str.h"
3298358b4923SRichard Henderson 
3299358b4923SRichard Henderson #undef REGS
3300358b4923SRichard Henderson #undef CONST
3301c896fe29Sbellard                 default:
33028940ea0dSPhilippe Mathieu-Daudé                 case '0' ... '9':
33038940ea0dSPhilippe Mathieu-Daudé                 case '&':
330429f5e925SRichard Henderson                 case 'p':
330529f5e925SRichard Henderson                 case 'm':
33063e80824eSRichard Henderson                     /* Typo in TCGConstraintSet constraint. */
3307358b4923SRichard Henderson                     g_assert_not_reached();
3308358b4923SRichard Henderson                 }
33098940ea0dSPhilippe Mathieu-Daudé             } while (*++ct_str != '\0');
3310c896fe29Sbellard         }
3311c896fe29Sbellard 
331229f5e925SRichard Henderson         /*
331329f5e925SRichard Henderson          * Fix up output pairs that are aliased with inputs.
331429f5e925SRichard Henderson          * When we created the alias, we copied pair from the output.
331529f5e925SRichard Henderson          * There are three cases:
331629f5e925SRichard Henderson          *    (1a) Pairs of inputs alias pairs of outputs.
331729f5e925SRichard Henderson          *    (1b) One input aliases the first of a pair of outputs.
331829f5e925SRichard Henderson          *    (2)  One input aliases the second of a pair of outputs.
331929f5e925SRichard Henderson          *
332029f5e925SRichard Henderson          * Case 1a is handled by making sure that the pair_index'es are
332129f5e925SRichard Henderson          * properly updated so that they appear the same as a pair of inputs.
332229f5e925SRichard Henderson          *
332329f5e925SRichard Henderson          * Case 1b is handled by setting the pair_index of the input to
332429f5e925SRichard Henderson          * itself, simply so it doesn't point to an unrelated argument.
332529f5e925SRichard Henderson          * Since we don't encounter the "second" during the input allocation
332629f5e925SRichard Henderson          * phase, nothing happens with the second half of the input pair.
332729f5e925SRichard Henderson          *
332829f5e925SRichard Henderson          * Case 2 is handled by setting the second input to pair=3, the
332929f5e925SRichard Henderson          * first output to pair=3, and the pair_index'es to match.
333029f5e925SRichard Henderson          */
333129f5e925SRichard Henderson         if (saw_alias_pair) {
33323e80824eSRichard Henderson             for (int i = nb_oargs; i < nb_args; i++) {
33333e80824eSRichard Henderson                 int o, o2, i2;
33343e80824eSRichard Henderson 
333529f5e925SRichard Henderson                 /*
333629f5e925SRichard Henderson                  * Since [0-9pm] must be alone in the constraint string,
333729f5e925SRichard Henderson                  * the only way they can both be set is if the pair comes
333829f5e925SRichard Henderson                  * from the output alias.
333929f5e925SRichard Henderson                  */
33403e80824eSRichard Henderson                 if (!args_ct[i].ialias) {
334129f5e925SRichard Henderson                     continue;
334229f5e925SRichard Henderson                 }
33433e80824eSRichard Henderson                 switch (args_ct[i].pair) {
334429f5e925SRichard Henderson                 case 0:
334529f5e925SRichard Henderson                     break;
334629f5e925SRichard Henderson                 case 1:
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 == 1);
33503e80824eSRichard Henderson                     tcg_debug_assert(args_ct[o2].pair == 2);
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 == 2);
33553e80824eSRichard Henderson                         args_ct[i2].pair_index = i;
33563e80824eSRichard Henderson                         args_ct[i].pair_index = i2;
335729f5e925SRichard Henderson                     } else {
335829f5e925SRichard Henderson                         /* Case 1b */
33593e80824eSRichard Henderson                         args_ct[i].pair_index = i;
336029f5e925SRichard Henderson                     }
336129f5e925SRichard Henderson                     break;
336229f5e925SRichard Henderson                 case 2:
33633e80824eSRichard Henderson                     o = args_ct[i].alias_index;
33643e80824eSRichard Henderson                     o2 = args_ct[o].pair_index;
33653e80824eSRichard Henderson                     tcg_debug_assert(args_ct[o].pair == 2);
33663e80824eSRichard Henderson                     tcg_debug_assert(args_ct[o2].pair == 1);
33673e80824eSRichard Henderson                     if (args_ct[o2].oalias) {
336829f5e925SRichard Henderson                         /* Case 1a */
33693e80824eSRichard Henderson                         i2 = args_ct[o2].alias_index;
33703e80824eSRichard Henderson                         tcg_debug_assert(args_ct[i2].pair == 1);
33713e80824eSRichard Henderson                         args_ct[i2].pair_index = i;
33723e80824eSRichard Henderson                         args_ct[i].pair_index = i2;
337329f5e925SRichard Henderson                     } else {
337429f5e925SRichard Henderson                         /* Case 2 */
33753e80824eSRichard Henderson                         args_ct[i].pair = 3;
33763e80824eSRichard Henderson                         args_ct[o2].pair = 3;
33773e80824eSRichard Henderson                         args_ct[i].pair_index = o2;
33783e80824eSRichard Henderson                         args_ct[o2].pair_index = i;
337929f5e925SRichard Henderson                     }
338029f5e925SRichard Henderson                     break;
338129f5e925SRichard Henderson                 default:
338229f5e925SRichard Henderson                     g_assert_not_reached();
338329f5e925SRichard Henderson                 }
338429f5e925SRichard Henderson             }
338529f5e925SRichard Henderson         }
338629f5e925SRichard Henderson 
3387c896fe29Sbellard         /* sort the constraints (XXX: this is just an heuristic) */
33883e80824eSRichard Henderson         sort_constraints(args_ct, 0, nb_oargs);
33893e80824eSRichard Henderson         sort_constraints(args_ct, nb_oargs, nb_iargs);
33903e80824eSRichard Henderson     }
3391501fb3daSRichard Henderson }
33923e80824eSRichard Henderson 
3393501fb3daSRichard Henderson static const TCGArgConstraint *opcode_args_ct(const TCGOp *op)
3394501fb3daSRichard Henderson {
33955500bd9eSRichard Henderson     TCGOpcode opc = op->opc;
33965500bd9eSRichard Henderson     TCGType type = TCGOP_TYPE(op);
33975500bd9eSRichard Henderson     unsigned flags = TCGOP_FLAGS(op);
33985500bd9eSRichard Henderson     const TCGOpDef *def = &tcg_op_defs[opc];
33995500bd9eSRichard Henderson     const TCGOutOp *outop = all_outop[opc];
34003e80824eSRichard Henderson     TCGConstraintSetIndex con_set;
34013e80824eSRichard Henderson 
34023e80824eSRichard Henderson     if (def->flags & TCG_OPF_NOT_PRESENT) {
3403501fb3daSRichard Henderson         return empty_cts;
34043e80824eSRichard Henderson     }
34053e80824eSRichard Henderson 
34065500bd9eSRichard Henderson     if (outop) {
34075500bd9eSRichard Henderson         con_set = outop->static_constraint;
34085500bd9eSRichard Henderson         if (con_set == C_Dynamic) {
34095500bd9eSRichard Henderson             con_set = outop->dynamic_constraint(type, flags);
34105500bd9eSRichard Henderson         }
34115500bd9eSRichard Henderson     } else {
34125500bd9eSRichard Henderson         con_set = tcg_target_op_def(opc, type, flags);
34135500bd9eSRichard Henderson     }
34145500bd9eSRichard Henderson     tcg_debug_assert(con_set >= 0);
34155500bd9eSRichard Henderson     tcg_debug_assert(con_set < ARRAY_SIZE(constraint_sets));
34163e80824eSRichard Henderson 
34173e80824eSRichard Henderson     /* The constraint arguments must match TCGOpcode arguments. */
3418501fb3daSRichard Henderson     tcg_debug_assert(constraint_sets[con_set].nb_oargs == def->nb_oargs);
3419501fb3daSRichard Henderson     tcg_debug_assert(constraint_sets[con_set].nb_iargs == def->nb_iargs);
34203e80824eSRichard Henderson 
3421501fb3daSRichard Henderson     return all_cts[con_set];
3422c896fe29Sbellard }
3423c896fe29Sbellard 
3424f85b1fc4SRichard Henderson static void remove_label_use(TCGOp *op, int idx)
3425f85b1fc4SRichard Henderson {
3426f85b1fc4SRichard Henderson     TCGLabel *label = arg_label(op->args[idx]);
3427f85b1fc4SRichard Henderson     TCGLabelUse *use;
3428f85b1fc4SRichard Henderson 
3429f85b1fc4SRichard Henderson     QSIMPLEQ_FOREACH(use, &label->branches, next) {
3430f85b1fc4SRichard Henderson         if (use->op == op) {
3431f85b1fc4SRichard Henderson             QSIMPLEQ_REMOVE(&label->branches, use, TCGLabelUse, next);
3432f85b1fc4SRichard Henderson             return;
3433f85b1fc4SRichard Henderson         }
3434f85b1fc4SRichard Henderson     }
3435f85b1fc4SRichard Henderson     g_assert_not_reached();
3436f85b1fc4SRichard Henderson }
3437f85b1fc4SRichard Henderson 
34380c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op)
34390c627cdcSRichard Henderson {
3440d88a117eSRichard Henderson     switch (op->opc) {
3441d88a117eSRichard Henderson     case INDEX_op_br:
3442f85b1fc4SRichard Henderson         remove_label_use(op, 0);
3443d88a117eSRichard Henderson         break;
3444b6d69fceSRichard Henderson     case INDEX_op_brcond:
3445f85b1fc4SRichard Henderson         remove_label_use(op, 3);
3446d88a117eSRichard Henderson         break;
3447d88a117eSRichard Henderson     case INDEX_op_brcond2_i32:
3448f85b1fc4SRichard Henderson         remove_label_use(op, 5);
3449d88a117eSRichard Henderson         break;
3450d88a117eSRichard Henderson     default:
3451d88a117eSRichard Henderson         break;
3452d88a117eSRichard Henderson     }
3453d88a117eSRichard Henderson 
345415fa08f8SRichard Henderson     QTAILQ_REMOVE(&s->ops, op, link);
345515fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&s->free_ops, op, link);
3456abebf925SRichard Henderson     s->nb_ops--;
34570c627cdcSRichard Henderson }
34580c627cdcSRichard Henderson 
3459a80cdd31SRichard Henderson void tcg_remove_ops_after(TCGOp *op)
3460a80cdd31SRichard Henderson {
3461a80cdd31SRichard Henderson     TCGContext *s = tcg_ctx;
3462a80cdd31SRichard Henderson 
3463a80cdd31SRichard Henderson     while (true) {
3464a80cdd31SRichard Henderson         TCGOp *last = tcg_last_op();
3465a80cdd31SRichard Henderson         if (last == op) {
3466a80cdd31SRichard Henderson             return;
3467a80cdd31SRichard Henderson         }
3468a80cdd31SRichard Henderson         tcg_op_remove(s, last);
3469a80cdd31SRichard Henderson     }
3470a80cdd31SRichard Henderson }
3471a80cdd31SRichard Henderson 
3472d4478943SPhilippe Mathieu-Daudé static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs)
347315fa08f8SRichard Henderson {
347415fa08f8SRichard Henderson     TCGContext *s = tcg_ctx;
3475cb10bc63SRichard Henderson     TCGOp *op = NULL;
347615fa08f8SRichard Henderson 
3477cb10bc63SRichard Henderson     if (unlikely(!QTAILQ_EMPTY(&s->free_ops))) {
3478cb10bc63SRichard Henderson         QTAILQ_FOREACH(op, &s->free_ops, link) {
3479cb10bc63SRichard Henderson             if (nargs <= op->nargs) {
348015fa08f8SRichard Henderson                 QTAILQ_REMOVE(&s->free_ops, op, link);
3481cb10bc63SRichard Henderson                 nargs = op->nargs;
3482cb10bc63SRichard Henderson                 goto found;
348315fa08f8SRichard Henderson             }
3484cb10bc63SRichard Henderson         }
3485cb10bc63SRichard Henderson     }
3486cb10bc63SRichard Henderson 
3487cb10bc63SRichard Henderson     /* Most opcodes have 3 or 4 operands: reduce fragmentation. */
3488cb10bc63SRichard Henderson     nargs = MAX(4, nargs);
3489cb10bc63SRichard Henderson     op = tcg_malloc(sizeof(TCGOp) + sizeof(TCGArg) * nargs);
3490cb10bc63SRichard Henderson 
3491cb10bc63SRichard Henderson  found:
349215fa08f8SRichard Henderson     memset(op, 0, offsetof(TCGOp, link));
349315fa08f8SRichard Henderson     op->opc = opc;
3494cb10bc63SRichard Henderson     op->nargs = nargs;
349515fa08f8SRichard Henderson 
3496cb10bc63SRichard Henderson     /* Check for bitfield overflow. */
3497cb10bc63SRichard Henderson     tcg_debug_assert(op->nargs == nargs);
3498cb10bc63SRichard Henderson 
3499cb10bc63SRichard Henderson     s->nb_ops++;
350015fa08f8SRichard Henderson     return op;
350115fa08f8SRichard Henderson }
350215fa08f8SRichard Henderson 
3503d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_emit_op(TCGOpcode opc, unsigned nargs)
350415fa08f8SRichard Henderson {
3505d4478943SPhilippe Mathieu-Daudé     TCGOp *op = tcg_op_alloc(opc, nargs);
350607843f75SRichard Henderson 
350707843f75SRichard Henderson     if (tcg_ctx->emit_before_op) {
350807843f75SRichard Henderson         QTAILQ_INSERT_BEFORE(tcg_ctx->emit_before_op, op, link);
350907843f75SRichard Henderson     } else {
351015fa08f8SRichard Henderson         QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
351107843f75SRichard Henderson     }
351215fa08f8SRichard Henderson     return op;
351315fa08f8SRichard Henderson }
351415fa08f8SRichard Henderson 
3515d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op,
3516cf5c9f69SRichard Henderson                             TCGOpcode opc, TCGType type, unsigned nargs)
35175a18407fSRichard Henderson {
3518d4478943SPhilippe Mathieu-Daudé     TCGOp *new_op = tcg_op_alloc(opc, nargs);
3519fb744eceSRichard Henderson 
3520cf5c9f69SRichard Henderson     TCGOP_TYPE(new_op) = type;
352115fa08f8SRichard Henderson     QTAILQ_INSERT_BEFORE(old_op, new_op, link);
35225a18407fSRichard Henderson     return new_op;
35235a18407fSRichard Henderson }
35245a18407fSRichard Henderson 
3525d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op,
3526cf5c9f69SRichard Henderson                            TCGOpcode opc, TCGType type, unsigned nargs)
35275a18407fSRichard Henderson {
3528d4478943SPhilippe Mathieu-Daudé     TCGOp *new_op = tcg_op_alloc(opc, nargs);
3529fb744eceSRichard Henderson 
3530cf5c9f69SRichard Henderson     TCGOP_TYPE(new_op) = type;
353115fa08f8SRichard Henderson     QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link);
35325a18407fSRichard Henderson     return new_op;
35335a18407fSRichard Henderson }
35345a18407fSRichard Henderson 
3535968f305eSRichard Henderson static void move_label_uses(TCGLabel *to, TCGLabel *from)
3536968f305eSRichard Henderson {
3537968f305eSRichard Henderson     TCGLabelUse *u;
3538968f305eSRichard Henderson 
3539968f305eSRichard Henderson     QSIMPLEQ_FOREACH(u, &from->branches, next) {
3540968f305eSRichard Henderson         TCGOp *op = u->op;
3541968f305eSRichard Henderson         switch (op->opc) {
3542968f305eSRichard Henderson         case INDEX_op_br:
3543968f305eSRichard Henderson             op->args[0] = label_arg(to);
3544968f305eSRichard Henderson             break;
3545b6d69fceSRichard Henderson         case INDEX_op_brcond:
3546968f305eSRichard Henderson             op->args[3] = label_arg(to);
3547968f305eSRichard Henderson             break;
3548968f305eSRichard Henderson         case INDEX_op_brcond2_i32:
3549968f305eSRichard Henderson             op->args[5] = label_arg(to);
3550968f305eSRichard Henderson             break;
3551968f305eSRichard Henderson         default:
3552968f305eSRichard Henderson             g_assert_not_reached();
3553968f305eSRichard Henderson         }
3554968f305eSRichard Henderson     }
3555968f305eSRichard Henderson 
3556968f305eSRichard Henderson     QSIMPLEQ_CONCAT(&to->branches, &from->branches);
3557968f305eSRichard Henderson }
3558968f305eSRichard Henderson 
3559b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code.  */
35609bbee4c0SRichard Henderson static void __attribute__((noinline))
35619bbee4c0SRichard Henderson reachable_code_pass(TCGContext *s)
3562b4fc67c7SRichard Henderson {
35634d89d0bbSRichard Henderson     TCGOp *op, *op_next, *op_prev;
3564b4fc67c7SRichard Henderson     bool dead = false;
3565b4fc67c7SRichard Henderson 
3566b4fc67c7SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
3567b4fc67c7SRichard Henderson         bool remove = dead;
3568b4fc67c7SRichard Henderson         TCGLabel *label;
3569b4fc67c7SRichard Henderson 
3570b4fc67c7SRichard Henderson         switch (op->opc) {
3571b4fc67c7SRichard Henderson         case INDEX_op_set_label:
3572b4fc67c7SRichard Henderson             label = arg_label(op->args[0]);
35734d89d0bbSRichard Henderson 
35744d89d0bbSRichard Henderson             /*
3575968f305eSRichard Henderson              * Note that the first op in the TB is always a load,
3576968f305eSRichard Henderson              * so there is always something before a label.
3577968f305eSRichard Henderson              */
3578968f305eSRichard Henderson             op_prev = QTAILQ_PREV(op, link);
3579968f305eSRichard Henderson 
3580968f305eSRichard Henderson             /*
3581968f305eSRichard Henderson              * If we find two sequential labels, move all branches to
3582968f305eSRichard Henderson              * reference the second label and remove the first label.
3583968f305eSRichard Henderson              * Do this before branch to next optimization, so that the
3584968f305eSRichard Henderson              * middle label is out of the way.
3585968f305eSRichard Henderson              */
3586968f305eSRichard Henderson             if (op_prev->opc == INDEX_op_set_label) {
3587968f305eSRichard Henderson                 move_label_uses(label, arg_label(op_prev->args[0]));
3588968f305eSRichard Henderson                 tcg_op_remove(s, op_prev);
3589968f305eSRichard Henderson                 op_prev = QTAILQ_PREV(op, link);
3590968f305eSRichard Henderson             }
3591968f305eSRichard Henderson 
3592968f305eSRichard Henderson             /*
35934d89d0bbSRichard Henderson              * Optimization can fold conditional branches to unconditional.
35944d89d0bbSRichard Henderson              * If we find a label which is preceded by an unconditional
35954d89d0bbSRichard Henderson              * branch to next, remove the branch.  We couldn't do this when
35964d89d0bbSRichard Henderson              * processing the branch because any dead code between the branch
35974d89d0bbSRichard Henderson              * and label had not yet been removed.
35984d89d0bbSRichard Henderson              */
35994d89d0bbSRichard Henderson             if (op_prev->opc == INDEX_op_br &&
36004d89d0bbSRichard Henderson                 label == arg_label(op_prev->args[0])) {
36014d89d0bbSRichard Henderson                 tcg_op_remove(s, op_prev);
36024d89d0bbSRichard Henderson                 /* Fall through means insns become live again.  */
36034d89d0bbSRichard Henderson                 dead = false;
36044d89d0bbSRichard Henderson             }
36054d89d0bbSRichard Henderson 
3606f85b1fc4SRichard Henderson             if (QSIMPLEQ_EMPTY(&label->branches)) {
3607b4fc67c7SRichard Henderson                 /*
3608b4fc67c7SRichard Henderson                  * While there is an occasional backward branch, virtually
3609b4fc67c7SRichard Henderson                  * all branches generated by the translators are forward.
3610b4fc67c7SRichard Henderson                  * Which means that generally we will have already removed
3611b4fc67c7SRichard Henderson                  * all references to the label that will be, and there is
3612b4fc67c7SRichard Henderson                  * little to be gained by iterating.
3613b4fc67c7SRichard Henderson                  */
3614b4fc67c7SRichard Henderson                 remove = true;
3615b4fc67c7SRichard Henderson             } else {
3616b4fc67c7SRichard Henderson                 /* Once we see a label, insns become live again.  */
3617b4fc67c7SRichard Henderson                 dead = false;
3618b4fc67c7SRichard Henderson                 remove = false;
3619b4fc67c7SRichard Henderson             }
3620b4fc67c7SRichard Henderson             break;
3621b4fc67c7SRichard Henderson 
3622b4fc67c7SRichard Henderson         case INDEX_op_br:
3623b4fc67c7SRichard Henderson         case INDEX_op_exit_tb:
3624b4fc67c7SRichard Henderson         case INDEX_op_goto_ptr:
3625b4fc67c7SRichard Henderson             /* Unconditional branches; everything following is dead.  */
3626b4fc67c7SRichard Henderson             dead = true;
3627b4fc67c7SRichard Henderson             break;
3628b4fc67c7SRichard Henderson 
3629b4fc67c7SRichard Henderson         case INDEX_op_call:
3630b4fc67c7SRichard Henderson             /* Notice noreturn helper calls, raising exceptions.  */
363190163900SRichard Henderson             if (tcg_call_flags(op) & TCG_CALL_NO_RETURN) {
3632b4fc67c7SRichard Henderson                 dead = true;
3633b4fc67c7SRichard Henderson             }
3634b4fc67c7SRichard Henderson             break;
3635b4fc67c7SRichard Henderson 
3636b4fc67c7SRichard Henderson         case INDEX_op_insn_start:
3637b4fc67c7SRichard Henderson             /* Never remove -- we need to keep these for unwind.  */
3638b4fc67c7SRichard Henderson             remove = false;
3639b4fc67c7SRichard Henderson             break;
3640b4fc67c7SRichard Henderson 
3641b4fc67c7SRichard Henderson         default:
3642b4fc67c7SRichard Henderson             break;
3643b4fc67c7SRichard Henderson         }
3644b4fc67c7SRichard Henderson 
3645b4fc67c7SRichard Henderson         if (remove) {
3646b4fc67c7SRichard Henderson             tcg_op_remove(s, op);
3647b4fc67c7SRichard Henderson         }
3648b4fc67c7SRichard Henderson     }
3649b4fc67c7SRichard Henderson }
3650b4fc67c7SRichard Henderson 
3651c70fbf0aSRichard Henderson #define TS_DEAD  1
3652c70fbf0aSRichard Henderson #define TS_MEM   2
3653c70fbf0aSRichard Henderson 
36545a18407fSRichard Henderson #define IS_DEAD_ARG(n)   (arg_life & (DEAD_ARG << (n)))
36555a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n)))
36565a18407fSRichard Henderson 
365725f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp.  */
365825f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts)
365925f49c5fSRichard Henderson {
366025f49c5fSRichard Henderson     return ts->state_ptr;
366125f49c5fSRichard Henderson }
366225f49c5fSRichard Henderson 
366325f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the
366425f49c5fSRichard Henderson  * maximal regset for its type.
366525f49c5fSRichard Henderson  */
366625f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts)
366725f49c5fSRichard Henderson {
366825f49c5fSRichard Henderson     *la_temp_pref(ts)
366925f49c5fSRichard Henderson         = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]);
367025f49c5fSRichard Henderson }
367125f49c5fSRichard Henderson 
36729c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals
36739c43b68dSAurelien Jarno    should be in memory. */
36742616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt)
3675c896fe29Sbellard {
3676b83eabeaSRichard Henderson     int i;
3677b83eabeaSRichard Henderson 
3678b83eabeaSRichard Henderson     for (i = 0; i < ng; ++i) {
3679b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
368025f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
3681b83eabeaSRichard Henderson     }
3682b83eabeaSRichard Henderson     for (i = ng; i < nt; ++i) {
3683b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD;
368425f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
3685b83eabeaSRichard Henderson     }
3686c896fe29Sbellard }
3687c896fe29Sbellard 
36889c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals
36899c43b68dSAurelien Jarno    and local temps should be in memory. */
36902616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt)
3691641d5fbeSbellard {
3692b83eabeaSRichard Henderson     int i;
3693641d5fbeSbellard 
3694ee17db83SRichard Henderson     for (i = 0; i < nt; ++i) {
3695ee17db83SRichard Henderson         TCGTemp *ts = &s->temps[i];
3696ee17db83SRichard Henderson         int state;
3697ee17db83SRichard Henderson 
3698ee17db83SRichard Henderson         switch (ts->kind) {
3699ee17db83SRichard Henderson         case TEMP_FIXED:
3700ee17db83SRichard Henderson         case TEMP_GLOBAL:
3701f57c6915SRichard Henderson         case TEMP_TB:
3702ee17db83SRichard Henderson             state = TS_DEAD | TS_MEM;
3703ee17db83SRichard Henderson             break;
3704c7482438SRichard Henderson         case TEMP_EBB:
3705c0522136SRichard Henderson         case TEMP_CONST:
3706ee17db83SRichard Henderson             state = TS_DEAD;
3707ee17db83SRichard Henderson             break;
3708ee17db83SRichard Henderson         default:
3709ee17db83SRichard Henderson             g_assert_not_reached();
3710c70fbf0aSRichard Henderson         }
3711ee17db83SRichard Henderson         ts->state = state;
3712ee17db83SRichard Henderson         la_reset_pref(ts);
3713641d5fbeSbellard     }
3714641d5fbeSbellard }
3715641d5fbeSbellard 
3716f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory.  */
3717f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng)
3718f65a061cSRichard Henderson {
3719f65a061cSRichard Henderson     int i;
3720f65a061cSRichard Henderson 
3721f65a061cSRichard Henderson     for (i = 0; i < ng; ++i) {
372225f49c5fSRichard Henderson         int state = s->temps[i].state;
372325f49c5fSRichard Henderson         s->temps[i].state = state | TS_MEM;
372425f49c5fSRichard Henderson         if (state == TS_DEAD) {
372525f49c5fSRichard Henderson             /* If the global was previously dead, reset prefs.  */
372625f49c5fSRichard Henderson             la_reset_pref(&s->temps[i]);
372725f49c5fSRichard Henderson         }
3728f65a061cSRichard Henderson     }
3729f65a061cSRichard Henderson }
3730f65a061cSRichard Henderson 
3731b4cb76e6SRichard Henderson /*
3732c7482438SRichard Henderson  * liveness analysis: conditional branch: all temps are dead unless
3733c7482438SRichard Henderson  * explicitly live-across-conditional-branch, globals and local temps
3734c7482438SRichard Henderson  * should be synced.
3735b4cb76e6SRichard Henderson  */
3736b4cb76e6SRichard Henderson static void la_bb_sync(TCGContext *s, int ng, int nt)
3737b4cb76e6SRichard Henderson {
3738b4cb76e6SRichard Henderson     la_global_sync(s, ng);
3739b4cb76e6SRichard Henderson 
3740b4cb76e6SRichard Henderson     for (int i = ng; i < nt; ++i) {
3741c0522136SRichard Henderson         TCGTemp *ts = &s->temps[i];
3742c0522136SRichard Henderson         int state;
3743c0522136SRichard Henderson 
3744c0522136SRichard Henderson         switch (ts->kind) {
3745f57c6915SRichard Henderson         case TEMP_TB:
3746c0522136SRichard Henderson             state = ts->state;
3747c0522136SRichard Henderson             ts->state = state | TS_MEM;
3748b4cb76e6SRichard Henderson             if (state != TS_DEAD) {
3749b4cb76e6SRichard Henderson                 continue;
3750b4cb76e6SRichard Henderson             }
3751c0522136SRichard Henderson             break;
3752c7482438SRichard Henderson         case TEMP_EBB:
3753c0522136SRichard Henderson         case TEMP_CONST:
3754c0522136SRichard Henderson             continue;
3755c0522136SRichard Henderson         default:
3756c0522136SRichard Henderson             g_assert_not_reached();
3757b4cb76e6SRichard Henderson         }
3758b4cb76e6SRichard Henderson         la_reset_pref(&s->temps[i]);
3759b4cb76e6SRichard Henderson     }
3760b4cb76e6SRichard Henderson }
3761b4cb76e6SRichard Henderson 
3762f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill.  */
3763f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng)
3764f65a061cSRichard Henderson {
3765f65a061cSRichard Henderson     int i;
3766f65a061cSRichard Henderson 
3767f65a061cSRichard Henderson     for (i = 0; i < ng; i++) {
3768f65a061cSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
376925f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
377025f49c5fSRichard Henderson     }
377125f49c5fSRichard Henderson }
377225f49c5fSRichard Henderson 
377325f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls.  */
377425f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt)
377525f49c5fSRichard Henderson {
377625f49c5fSRichard Henderson     TCGRegSet mask = ~tcg_target_call_clobber_regs;
377725f49c5fSRichard Henderson     int i;
377825f49c5fSRichard Henderson 
377925f49c5fSRichard Henderson     for (i = 0; i < nt; i++) {
378025f49c5fSRichard Henderson         TCGTemp *ts = &s->temps[i];
378125f49c5fSRichard Henderson         if (!(ts->state & TS_DEAD)) {
378225f49c5fSRichard Henderson             TCGRegSet *pset = la_temp_pref(ts);
378325f49c5fSRichard Henderson             TCGRegSet set = *pset;
378425f49c5fSRichard Henderson 
378525f49c5fSRichard Henderson             set &= mask;
378625f49c5fSRichard Henderson             /* If the combination is not possible, restart.  */
378725f49c5fSRichard Henderson             if (set == 0) {
378825f49c5fSRichard Henderson                 set = tcg_target_available_regs[ts->type] & mask;
378925f49c5fSRichard Henderson             }
379025f49c5fSRichard Henderson             *pset = set;
379125f49c5fSRichard Henderson         }
3792f65a061cSRichard Henderson     }
3793f65a061cSRichard Henderson }
3794f65a061cSRichard Henderson 
3795874b8574SRichard Henderson /*
3796874b8574SRichard Henderson  * Liveness analysis: Verify the lifetime of TEMP_TB, and reduce
3797874b8574SRichard Henderson  * to TEMP_EBB, if possible.
3798874b8574SRichard Henderson  */
3799874b8574SRichard Henderson static void __attribute__((noinline))
3800874b8574SRichard Henderson liveness_pass_0(TCGContext *s)
3801874b8574SRichard Henderson {
3802874b8574SRichard Henderson     void * const multiple_ebb = (void *)(uintptr_t)-1;
3803874b8574SRichard Henderson     int nb_temps = s->nb_temps;
3804874b8574SRichard Henderson     TCGOp *op, *ebb;
3805874b8574SRichard Henderson 
3806874b8574SRichard Henderson     for (int i = s->nb_globals; i < nb_temps; ++i) {
3807874b8574SRichard Henderson         s->temps[i].state_ptr = NULL;
3808874b8574SRichard Henderson     }
3809874b8574SRichard Henderson 
3810874b8574SRichard Henderson     /*
3811874b8574SRichard Henderson      * Represent each EBB by the op at which it begins.  In the case of
3812874b8574SRichard Henderson      * the first EBB, this is the first op, otherwise it is a label.
3813874b8574SRichard Henderson      * Collect the uses of each TEMP_TB: NULL for unused, EBB for use
3814874b8574SRichard Henderson      * within a single EBB, else MULTIPLE_EBB.
3815874b8574SRichard Henderson      */
3816874b8574SRichard Henderson     ebb = QTAILQ_FIRST(&s->ops);
3817874b8574SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
3818874b8574SRichard Henderson         const TCGOpDef *def;
3819874b8574SRichard Henderson         int nb_oargs, nb_iargs;
3820874b8574SRichard Henderson 
3821874b8574SRichard Henderson         switch (op->opc) {
3822874b8574SRichard Henderson         case INDEX_op_set_label:
3823874b8574SRichard Henderson             ebb = op;
3824874b8574SRichard Henderson             continue;
3825874b8574SRichard Henderson         case INDEX_op_discard:
3826874b8574SRichard Henderson             continue;
3827874b8574SRichard Henderson         case INDEX_op_call:
3828874b8574SRichard Henderson             nb_oargs = TCGOP_CALLO(op);
3829874b8574SRichard Henderson             nb_iargs = TCGOP_CALLI(op);
3830874b8574SRichard Henderson             break;
3831874b8574SRichard Henderson         default:
3832874b8574SRichard Henderson             def = &tcg_op_defs[op->opc];
3833874b8574SRichard Henderson             nb_oargs = def->nb_oargs;
3834874b8574SRichard Henderson             nb_iargs = def->nb_iargs;
3835874b8574SRichard Henderson             break;
3836874b8574SRichard Henderson         }
3837874b8574SRichard Henderson 
3838874b8574SRichard Henderson         for (int i = 0; i < nb_oargs + nb_iargs; ++i) {
3839874b8574SRichard Henderson             TCGTemp *ts = arg_temp(op->args[i]);
3840874b8574SRichard Henderson 
3841874b8574SRichard Henderson             if (ts->kind != TEMP_TB) {
3842874b8574SRichard Henderson                 continue;
3843874b8574SRichard Henderson             }
3844874b8574SRichard Henderson             if (ts->state_ptr == NULL) {
3845874b8574SRichard Henderson                 ts->state_ptr = ebb;
3846874b8574SRichard Henderson             } else if (ts->state_ptr != ebb) {
3847874b8574SRichard Henderson                 ts->state_ptr = multiple_ebb;
3848874b8574SRichard Henderson             }
3849874b8574SRichard Henderson         }
3850874b8574SRichard Henderson     }
3851874b8574SRichard Henderson 
3852874b8574SRichard Henderson     /*
3853874b8574SRichard Henderson      * For TEMP_TB that turned out not to be used beyond one EBB,
3854874b8574SRichard Henderson      * reduce the liveness to TEMP_EBB.
3855874b8574SRichard Henderson      */
3856874b8574SRichard Henderson     for (int i = s->nb_globals; i < nb_temps; ++i) {
3857874b8574SRichard Henderson         TCGTemp *ts = &s->temps[i];
3858874b8574SRichard Henderson         if (ts->kind == TEMP_TB && ts->state_ptr != multiple_ebb) {
3859874b8574SRichard Henderson             ts->kind = TEMP_EBB;
3860874b8574SRichard Henderson         }
3861874b8574SRichard Henderson     }
3862874b8574SRichard Henderson }
3863874b8574SRichard Henderson 
3864a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a
3865c896fe29Sbellard    given input arguments is dead. Instructions updating dead
3866c896fe29Sbellard    temporaries are removed. */
38679bbee4c0SRichard Henderson static void __attribute__((noinline))
38689bbee4c0SRichard Henderson liveness_pass_1(TCGContext *s)
3869c896fe29Sbellard {
3870c70fbf0aSRichard Henderson     int nb_globals = s->nb_globals;
38712616c808SRichard Henderson     int nb_temps = s->nb_temps;
387215fa08f8SRichard Henderson     TCGOp *op, *op_prev;
387325f49c5fSRichard Henderson     TCGRegSet *prefs;
387425f49c5fSRichard Henderson     int i;
387525f49c5fSRichard Henderson 
387625f49c5fSRichard Henderson     prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps);
387725f49c5fSRichard Henderson     for (i = 0; i < nb_temps; ++i) {
387825f49c5fSRichard Henderson         s->temps[i].state_ptr = prefs + i;
387925f49c5fSRichard Henderson     }
3880c896fe29Sbellard 
3881ae36a246SRichard Henderson     /* ??? Should be redundant with the exit_tb that ends the TB.  */
38822616c808SRichard Henderson     la_func_end(s, nb_globals, nb_temps);
3883c896fe29Sbellard 
3884eae3eb3eSPaolo Bonzini     QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) {
388525f49c5fSRichard Henderson         int nb_iargs, nb_oargs;
3886c45cb8bbSRichard Henderson         TCGOpcode opc_new, opc_new2;
3887a1b3c48dSRichard Henderson         TCGLifeData arg_life = 0;
388825f49c5fSRichard Henderson         TCGTemp *ts;
3889c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
3890c45cb8bbSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
3891501fb3daSRichard Henderson         const TCGArgConstraint *args_ct;
3892c45cb8bbSRichard Henderson 
3893c45cb8bbSRichard Henderson         switch (opc) {
3894c896fe29Sbellard         case INDEX_op_call:
3895c6e113f5Sbellard             {
389639004a71SRichard Henderson                 const TCGHelperInfo *info = tcg_call_info(op);
389739004a71SRichard Henderson                 int call_flags = tcg_call_flags(op);
3898c6e113f5Sbellard 
3899cd9090aaSRichard Henderson                 nb_oargs = TCGOP_CALLO(op);
3900cd9090aaSRichard Henderson                 nb_iargs = TCGOP_CALLI(op);
3901c6e113f5Sbellard 
3902c45cb8bbSRichard Henderson                 /* pure functions can be removed if their result is unused */
390378505279SAurelien Jarno                 if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) {
3904c6e113f5Sbellard                     for (i = 0; i < nb_oargs; i++) {
390525f49c5fSRichard Henderson                         ts = arg_temp(op->args[i]);
390625f49c5fSRichard Henderson                         if (ts->state != TS_DEAD) {
3907c6e113f5Sbellard                             goto do_not_remove_call;
3908c6e113f5Sbellard                         }
39099c43b68dSAurelien Jarno                     }
3910c45cb8bbSRichard Henderson                     goto do_remove;
3911152c35aaSRichard Henderson                 }
3912c6e113f5Sbellard             do_not_remove_call:
3913c896fe29Sbellard 
391425f49c5fSRichard Henderson                 /* Output args are dead.  */
3915c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
391625f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
391725f49c5fSRichard Henderson                     if (ts->state & TS_DEAD) {
3918a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
39196b64b624SAurelien Jarno                     }
392025f49c5fSRichard Henderson                     if (ts->state & TS_MEM) {
3921a1b3c48dSRichard Henderson                         arg_life |= SYNC_ARG << i;
39229c43b68dSAurelien Jarno                     }
392325f49c5fSRichard Henderson                     ts->state = TS_DEAD;
392425f49c5fSRichard Henderson                     la_reset_pref(ts);
3925c896fe29Sbellard                 }
3926c896fe29Sbellard 
392731fd884bSRichard Henderson                 /* Not used -- it will be tcg_target_call_oarg_reg().  */
392831fd884bSRichard Henderson                 memset(op->output_pref, 0, sizeof(op->output_pref));
392931fd884bSRichard Henderson 
393078505279SAurelien Jarno                 if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS |
393178505279SAurelien Jarno                                     TCG_CALL_NO_READ_GLOBALS))) {
3932f65a061cSRichard Henderson                     la_global_kill(s, nb_globals);
3933c70fbf0aSRichard Henderson                 } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) {
3934f65a061cSRichard Henderson                     la_global_sync(s, nb_globals);
3935b9c18f56Saurel32                 }
3936c896fe29Sbellard 
393725f49c5fSRichard Henderson                 /* Record arguments that die in this helper.  */
3938866cb6cbSAurelien Jarno                 for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
393925f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
394039004a71SRichard Henderson                     if (ts->state & TS_DEAD) {
3941a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
3942c896fe29Sbellard                     }
3943c896fe29Sbellard                 }
394425f49c5fSRichard Henderson 
394525f49c5fSRichard Henderson                 /* For all live registers, remove call-clobbered prefs.  */
394625f49c5fSRichard Henderson                 la_cross_call(s, nb_temps);
394725f49c5fSRichard Henderson 
394839004a71SRichard Henderson                 /*
394939004a71SRichard Henderson                  * Input arguments are live for preceding opcodes.
395039004a71SRichard Henderson                  *
395139004a71SRichard Henderson                  * For those arguments that die, and will be allocated in
395239004a71SRichard Henderson                  * registers, clear the register set for that arg, to be
395339004a71SRichard Henderson                  * filled in below.  For args that will be on the stack,
395439004a71SRichard Henderson                  * reset to any available reg.  Process arguments in reverse
395539004a71SRichard Henderson                  * order so that if a temp is used more than once, the stack
395639004a71SRichard Henderson                  * reset to max happens before the register reset to 0.
395725f49c5fSRichard Henderson                  */
395839004a71SRichard Henderson                 for (i = nb_iargs - 1; i >= 0; i--) {
395939004a71SRichard Henderson                     const TCGCallArgumentLoc *loc = &info->in[i];
396039004a71SRichard Henderson                     ts = arg_temp(op->args[nb_oargs + i]);
396139004a71SRichard Henderson 
396239004a71SRichard Henderson                     if (ts->state & TS_DEAD) {
396339004a71SRichard Henderson                         switch (loc->kind) {
396439004a71SRichard Henderson                         case TCG_CALL_ARG_NORMAL:
396539004a71SRichard Henderson                         case TCG_CALL_ARG_EXTEND_U:
396639004a71SRichard Henderson                         case TCG_CALL_ARG_EXTEND_S:
3967338b61e9SRichard Henderson                             if (arg_slot_reg_p(loc->arg_slot)) {
396839004a71SRichard Henderson                                 *la_temp_pref(ts) = 0;
396939004a71SRichard Henderson                                 break;
397039004a71SRichard Henderson                             }
397139004a71SRichard Henderson                             /* fall through */
397239004a71SRichard Henderson                         default:
397339004a71SRichard Henderson                             *la_temp_pref(ts) =
397439004a71SRichard Henderson                                 tcg_target_available_regs[ts->type];
397539004a71SRichard Henderson                             break;
397639004a71SRichard Henderson                         }
397725f49c5fSRichard Henderson                         ts->state &= ~TS_DEAD;
397825f49c5fSRichard Henderson                     }
397925f49c5fSRichard Henderson                 }
398025f49c5fSRichard Henderson 
398139004a71SRichard Henderson                 /*
398239004a71SRichard Henderson                  * For each input argument, add its input register to prefs.
398339004a71SRichard Henderson                  * If a temp is used once, this produces a single set bit;
398439004a71SRichard Henderson                  * if a temp is used multiple times, this produces a set.
398539004a71SRichard Henderson                  */
398639004a71SRichard Henderson                 for (i = 0; i < nb_iargs; i++) {
398739004a71SRichard Henderson                     const TCGCallArgumentLoc *loc = &info->in[i];
398839004a71SRichard Henderson                     ts = arg_temp(op->args[nb_oargs + i]);
398939004a71SRichard Henderson 
399039004a71SRichard Henderson                     switch (loc->kind) {
399139004a71SRichard Henderson                     case TCG_CALL_ARG_NORMAL:
399239004a71SRichard Henderson                     case TCG_CALL_ARG_EXTEND_U:
399339004a71SRichard Henderson                     case TCG_CALL_ARG_EXTEND_S:
3994338b61e9SRichard Henderson                         if (arg_slot_reg_p(loc->arg_slot)) {
399525f49c5fSRichard Henderson                             tcg_regset_set_reg(*la_temp_pref(ts),
399639004a71SRichard Henderson                                 tcg_target_call_iarg_regs[loc->arg_slot]);
399739004a71SRichard Henderson                         }
399839004a71SRichard Henderson                         break;
399939004a71SRichard Henderson                     default:
400039004a71SRichard Henderson                         break;
4001c70fbf0aSRichard Henderson                     }
4002c19f47bfSAurelien Jarno                 }
4003c6e113f5Sbellard             }
4004c896fe29Sbellard             break;
4005765b842aSRichard Henderson         case INDEX_op_insn_start:
4006c896fe29Sbellard             break;
40075ff9d6a4Sbellard         case INDEX_op_discard:
40085ff9d6a4Sbellard             /* mark the temporary as dead */
400925f49c5fSRichard Henderson             ts = arg_temp(op->args[0]);
401025f49c5fSRichard Henderson             ts->state = TS_DEAD;
401125f49c5fSRichard Henderson             la_reset_pref(ts);
40125ff9d6a4Sbellard             break;
40131305c451SRichard Henderson 
40141305c451SRichard Henderson         case INDEX_op_add2_i32:
401579602f63SRichard Henderson         case INDEX_op_add2_i64:
401679602f63SRichard Henderson             opc_new = INDEX_op_add;
4017f1fae40cSRichard Henderson             goto do_addsub2;
40181305c451SRichard Henderson         case INDEX_op_sub2_i32:
4019f1fae40cSRichard Henderson         case INDEX_op_sub2_i64:
402060f34f55SRichard Henderson             opc_new = INDEX_op_sub;
4021f1fae40cSRichard Henderson         do_addsub2:
40221305c451SRichard Henderson             nb_iargs = 4;
40231305c451SRichard Henderson             nb_oargs = 2;
40241305c451SRichard Henderson             /* Test if the high part of the operation is dead, but not
40251305c451SRichard Henderson                the low part.  The result can be optimized to a simple
40261305c451SRichard Henderson                add or sub.  This happens often for x86_64 guest when the
40271305c451SRichard Henderson                cpu mode is set to 32 bit.  */
4028b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
4029b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
40301305c451SRichard Henderson                     goto do_remove;
40311305c451SRichard Henderson                 }
4032c45cb8bbSRichard Henderson                 /* Replace the opcode and adjust the args in place,
4033c45cb8bbSRichard Henderson                    leaving 3 unused args at the end.  */
4034c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
4035efee3746SRichard Henderson                 op->args[1] = op->args[2];
4036efee3746SRichard Henderson                 op->args[2] = op->args[4];
40371305c451SRichard Henderson                 /* Fall through and mark the single-word operation live.  */
40381305c451SRichard Henderson                 nb_iargs = 2;
40391305c451SRichard Henderson                 nb_oargs = 1;
40401305c451SRichard Henderson             }
40411305c451SRichard Henderson             goto do_not_remove;
40421305c451SRichard Henderson 
4043bfe96480SRichard Henderson         case INDEX_op_muls2:
4044d2c3ecadSRichard Henderson             opc_new = INDEX_op_mul;
4045c742824dSRichard Henderson             opc_new2 = INDEX_op_mulsh;
4046f1fae40cSRichard Henderson             goto do_mul2;
4047d776198cSRichard Henderson         case INDEX_op_mulu2:
4048d2c3ecadSRichard Henderson             opc_new = INDEX_op_mul;
4049aa28c9efSRichard Henderson             opc_new2 = INDEX_op_muluh;
4050f1fae40cSRichard Henderson         do_mul2:
40511414968aSRichard Henderson             nb_iargs = 2;
40521414968aSRichard Henderson             nb_oargs = 2;
4053b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
4054b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
405503271524SRichard Henderson                     /* Both parts of the operation are dead.  */
40561414968aSRichard Henderson                     goto do_remove;
40571414968aSRichard Henderson                 }
405803271524SRichard Henderson                 /* The high part of the operation is dead; generate the low. */
4059c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
4060efee3746SRichard Henderson                 op->args[1] = op->args[2];
4061efee3746SRichard Henderson                 op->args[2] = op->args[3];
4062937246f2SRichard Henderson             } else if (arg_temp(op->args[0])->state == TS_DEAD &&
4063937246f2SRichard Henderson                        tcg_op_supported(opc_new2, TCGOP_TYPE(op), 0)) {
406403271524SRichard Henderson                 /* The low part of the operation is dead; generate the high. */
4065c45cb8bbSRichard Henderson                 op->opc = opc = opc_new2;
4066efee3746SRichard Henderson                 op->args[0] = op->args[1];
4067efee3746SRichard Henderson                 op->args[1] = op->args[2];
4068efee3746SRichard Henderson                 op->args[2] = op->args[3];
406903271524SRichard Henderson             } else {
407003271524SRichard Henderson                 goto do_not_remove;
407103271524SRichard Henderson             }
407203271524SRichard Henderson             /* Mark the single-word operation live.  */
40731414968aSRichard Henderson             nb_oargs = 1;
40741414968aSRichard Henderson             goto do_not_remove;
40751414968aSRichard Henderson 
4076c896fe29Sbellard         default:
40771305c451SRichard Henderson             /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
4078c896fe29Sbellard             nb_iargs = def->nb_iargs;
4079c896fe29Sbellard             nb_oargs = def->nb_oargs;
4080c896fe29Sbellard 
4081c896fe29Sbellard             /* Test if the operation can be removed because all
40825ff9d6a4Sbellard                its outputs are dead. We assume that nb_oargs == 0
40835ff9d6a4Sbellard                implies side effects */
40845ff9d6a4Sbellard             if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
4085c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
4086b83eabeaSRichard Henderson                     if (arg_temp(op->args[i])->state != TS_DEAD) {
4087c896fe29Sbellard                         goto do_not_remove;
4088c896fe29Sbellard                     }
40899c43b68dSAurelien Jarno                 }
4090152c35aaSRichard Henderson                 goto do_remove;
4091152c35aaSRichard Henderson             }
4092152c35aaSRichard Henderson             goto do_not_remove;
4093152c35aaSRichard Henderson 
40941305c451SRichard Henderson         do_remove:
40950c627cdcSRichard Henderson             tcg_op_remove(s, op);
4096152c35aaSRichard Henderson             break;
4097152c35aaSRichard Henderson 
4098c896fe29Sbellard         do_not_remove:
4099c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
410025f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
410125f49c5fSRichard Henderson 
410225f49c5fSRichard Henderson                 /* Remember the preference of the uses that followed.  */
410331fd884bSRichard Henderson                 if (i < ARRAY_SIZE(op->output_pref)) {
410425f49c5fSRichard Henderson                     op->output_pref[i] = *la_temp_pref(ts);
410531fd884bSRichard Henderson                 }
410625f49c5fSRichard Henderson 
410725f49c5fSRichard Henderson                 /* Output args are dead.  */
410825f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
4109a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
41106b64b624SAurelien Jarno                 }
411125f49c5fSRichard Henderson                 if (ts->state & TS_MEM) {
4112a1b3c48dSRichard Henderson                     arg_life |= SYNC_ARG << i;
41139c43b68dSAurelien Jarno                 }
411425f49c5fSRichard Henderson                 ts->state = TS_DEAD;
411525f49c5fSRichard Henderson                 la_reset_pref(ts);
4116c896fe29Sbellard             }
4117c896fe29Sbellard 
411825f49c5fSRichard Henderson             /* If end of basic block, update.  */
4119ae36a246SRichard Henderson             if (def->flags & TCG_OPF_BB_EXIT) {
4120ae36a246SRichard Henderson                 la_func_end(s, nb_globals, nb_temps);
4121b4cb76e6SRichard Henderson             } else if (def->flags & TCG_OPF_COND_BRANCH) {
4122b4cb76e6SRichard Henderson                 la_bb_sync(s, nb_globals, nb_temps);
4123ae36a246SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
41242616c808SRichard Henderson                 la_bb_end(s, nb_globals, nb_temps);
41253d5c5f87SAurelien Jarno             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
4126f65a061cSRichard Henderson                 la_global_sync(s, nb_globals);
412725f49c5fSRichard Henderson                 if (def->flags & TCG_OPF_CALL_CLOBBER) {
412825f49c5fSRichard Henderson                     la_cross_call(s, nb_temps);
412925f49c5fSRichard Henderson                 }
4130c896fe29Sbellard             }
4131c896fe29Sbellard 
413225f49c5fSRichard Henderson             /* Record arguments that die in this opcode.  */
4133866cb6cbSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
413425f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
413525f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
4136a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
4137c896fe29Sbellard                 }
4138c19f47bfSAurelien Jarno             }
413925f49c5fSRichard Henderson 
414025f49c5fSRichard Henderson             /* Input arguments are live for preceding opcodes.  */
4141c19f47bfSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
414225f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
414325f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
414425f49c5fSRichard Henderson                     /* For operands that were dead, initially allow
414525f49c5fSRichard Henderson                        all regs for the type.  */
414625f49c5fSRichard Henderson                     *la_temp_pref(ts) = tcg_target_available_regs[ts->type];
414725f49c5fSRichard Henderson                     ts->state &= ~TS_DEAD;
414825f49c5fSRichard Henderson                 }
414925f49c5fSRichard Henderson             }
415025f49c5fSRichard Henderson 
415125f49c5fSRichard Henderson             /* Incorporate constraints for this operand.  */
415225f49c5fSRichard Henderson             switch (opc) {
4153b5701261SRichard Henderson             case INDEX_op_mov:
415425f49c5fSRichard Henderson                 /* Note that these are TCG_OPF_NOT_PRESENT and do not
415525f49c5fSRichard Henderson                    have proper constraints.  That said, special case
415625f49c5fSRichard Henderson                    moves to propagate preferences backward.  */
415725f49c5fSRichard Henderson                 if (IS_DEAD_ARG(1)) {
415825f49c5fSRichard Henderson                     *la_temp_pref(arg_temp(op->args[0]))
415925f49c5fSRichard Henderson                         = *la_temp_pref(arg_temp(op->args[1]));
416025f49c5fSRichard Henderson                 }
416125f49c5fSRichard Henderson                 break;
416225f49c5fSRichard Henderson 
416325f49c5fSRichard Henderson             default:
4164501fb3daSRichard Henderson                 args_ct = opcode_args_ct(op);
416525f49c5fSRichard Henderson                 for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
4166501fb3daSRichard Henderson                     const TCGArgConstraint *ct = &args_ct[i];
416725f49c5fSRichard Henderson                     TCGRegSet set, *pset;
416825f49c5fSRichard Henderson 
416925f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
417025f49c5fSRichard Henderson                     pset = la_temp_pref(ts);
417125f49c5fSRichard Henderson                     set = *pset;
417225f49c5fSRichard Henderson 
41739be0d080SRichard Henderson                     set &= ct->regs;
4174bc2b17e6SRichard Henderson                     if (ct->ialias) {
417531fd884bSRichard Henderson                         set &= output_pref(op, ct->alias_index);
417625f49c5fSRichard Henderson                     }
417725f49c5fSRichard Henderson                     /* If the combination is not possible, restart.  */
417825f49c5fSRichard Henderson                     if (set == 0) {
41799be0d080SRichard Henderson                         set = ct->regs;
418025f49c5fSRichard Henderson                     }
418125f49c5fSRichard Henderson                     *pset = set;
418225f49c5fSRichard Henderson                 }
418325f49c5fSRichard Henderson                 break;
4184c896fe29Sbellard             }
4185c896fe29Sbellard             break;
4186c896fe29Sbellard         }
4187bee158cbSRichard Henderson         op->life = arg_life;
4188c896fe29Sbellard     }
41891ff0a2c5SEvgeny Voevodin }
4190c896fe29Sbellard 
41915a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries.  */
41929bbee4c0SRichard Henderson static bool __attribute__((noinline))
41939bbee4c0SRichard Henderson liveness_pass_2(TCGContext *s)
41945a18407fSRichard Henderson {
41955a18407fSRichard Henderson     int nb_globals = s->nb_globals;
419615fa08f8SRichard Henderson     int nb_temps, i;
41975a18407fSRichard Henderson     bool changes = false;
419815fa08f8SRichard Henderson     TCGOp *op, *op_next;
41995a18407fSRichard Henderson 
42005a18407fSRichard Henderson     /* Create a temporary for each indirect global.  */
42015a18407fSRichard Henderson     for (i = 0; i < nb_globals; ++i) {
42025a18407fSRichard Henderson         TCGTemp *its = &s->temps[i];
42035a18407fSRichard Henderson         if (its->indirect_reg) {
42045a18407fSRichard Henderson             TCGTemp *dts = tcg_temp_alloc(s);
42055a18407fSRichard Henderson             dts->type = its->type;
42065a18407fSRichard Henderson             dts->base_type = its->base_type;
4207e1e64652SRichard Henderson             dts->temp_subindex = its->temp_subindex;
4208c7482438SRichard Henderson             dts->kind = TEMP_EBB;
4209b83eabeaSRichard Henderson             its->state_ptr = dts;
4210b83eabeaSRichard Henderson         } else {
4211b83eabeaSRichard Henderson             its->state_ptr = NULL;
42125a18407fSRichard Henderson         }
4213b83eabeaSRichard Henderson         /* All globals begin dead.  */
4214b83eabeaSRichard Henderson         its->state = TS_DEAD;
42155a18407fSRichard Henderson     }
4216b83eabeaSRichard Henderson     for (nb_temps = s->nb_temps; i < nb_temps; ++i) {
4217b83eabeaSRichard Henderson         TCGTemp *its = &s->temps[i];
4218b83eabeaSRichard Henderson         its->state_ptr = NULL;
4219b83eabeaSRichard Henderson         its->state = TS_DEAD;
4220b83eabeaSRichard Henderson     }
42215a18407fSRichard Henderson 
422215fa08f8SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
42235a18407fSRichard Henderson         TCGOpcode opc = op->opc;
42245a18407fSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
42255a18407fSRichard Henderson         TCGLifeData arg_life = op->life;
42265a18407fSRichard Henderson         int nb_iargs, nb_oargs, call_flags;
4227b83eabeaSRichard Henderson         TCGTemp *arg_ts, *dir_ts;
42285a18407fSRichard Henderson 
42295a18407fSRichard Henderson         if (opc == INDEX_op_call) {
4230cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
4231cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
423290163900SRichard Henderson             call_flags = tcg_call_flags(op);
42335a18407fSRichard Henderson         } else {
42345a18407fSRichard Henderson             nb_iargs = def->nb_iargs;
42355a18407fSRichard Henderson             nb_oargs = def->nb_oargs;
42365a18407fSRichard Henderson 
42375a18407fSRichard Henderson             /* Set flags similar to how calls require.  */
4238b4cb76e6SRichard Henderson             if (def->flags & TCG_OPF_COND_BRANCH) {
4239b4cb76e6SRichard Henderson                 /* Like reading globals: sync_globals */
4240b4cb76e6SRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
4241b4cb76e6SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
42425a18407fSRichard Henderson                 /* Like writing globals: save_globals */
42435a18407fSRichard Henderson                 call_flags = 0;
42445a18407fSRichard Henderson             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
42455a18407fSRichard Henderson                 /* Like reading globals: sync_globals */
42465a18407fSRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
42475a18407fSRichard Henderson             } else {
42485a18407fSRichard Henderson                 /* No effect on globals.  */
42495a18407fSRichard Henderson                 call_flags = (TCG_CALL_NO_READ_GLOBALS |
42505a18407fSRichard Henderson                               TCG_CALL_NO_WRITE_GLOBALS);
42515a18407fSRichard Henderson             }
42525a18407fSRichard Henderson         }
42535a18407fSRichard Henderson 
42545a18407fSRichard Henderson         /* Make sure that input arguments are available.  */
42555a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
4256b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
4257b83eabeaSRichard Henderson             dir_ts = arg_ts->state_ptr;
4258b83eabeaSRichard Henderson             if (dir_ts && arg_ts->state == TS_DEAD) {
4259b83eabeaSRichard Henderson                 TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32
42605a18407fSRichard Henderson                                   ? INDEX_op_ld_i32
42615a18407fSRichard Henderson                                   : INDEX_op_ld_i64);
4262cf5c9f69SRichard Henderson                 TCGOp *lop = tcg_op_insert_before(s, op, lopc,
4263cf5c9f69SRichard Henderson                                                   arg_ts->type, 3);
42645a18407fSRichard Henderson 
4265b83eabeaSRichard Henderson                 lop->args[0] = temp_arg(dir_ts);
4266b83eabeaSRichard Henderson                 lop->args[1] = temp_arg(arg_ts->mem_base);
4267b83eabeaSRichard Henderson                 lop->args[2] = arg_ts->mem_offset;
42685a18407fSRichard Henderson 
42695a18407fSRichard Henderson                 /* Loaded, but synced with memory.  */
4270b83eabeaSRichard Henderson                 arg_ts->state = TS_MEM;
42715a18407fSRichard Henderson             }
42725a18407fSRichard Henderson         }
42735a18407fSRichard Henderson 
42745a18407fSRichard Henderson         /* Perform input replacement, and mark inputs that became dead.
42755a18407fSRichard Henderson            No action is required except keeping temp_state up to date
42765a18407fSRichard Henderson            so that we reload when needed.  */
42775a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
4278b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
4279b83eabeaSRichard Henderson             dir_ts = arg_ts->state_ptr;
4280b83eabeaSRichard Henderson             if (dir_ts) {
4281b83eabeaSRichard Henderson                 op->args[i] = temp_arg(dir_ts);
42825a18407fSRichard Henderson                 changes = true;
42835a18407fSRichard Henderson                 if (IS_DEAD_ARG(i)) {
4284b83eabeaSRichard Henderson                     arg_ts->state = TS_DEAD;
42855a18407fSRichard Henderson                 }
42865a18407fSRichard Henderson             }
42875a18407fSRichard Henderson         }
42885a18407fSRichard Henderson 
42895a18407fSRichard Henderson         /* Liveness analysis should ensure that the following are
42905a18407fSRichard Henderson            all correct, for call sites and basic block end points.  */
42915a18407fSRichard Henderson         if (call_flags & TCG_CALL_NO_READ_GLOBALS) {
42925a18407fSRichard Henderson             /* Nothing to do */
42935a18407fSRichard Henderson         } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) {
42945a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
42955a18407fSRichard Henderson                 /* Liveness should see that globals are synced back,
42965a18407fSRichard Henderson                    that is, either TS_DEAD or TS_MEM.  */
4297b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
4298b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
4299b83eabeaSRichard Henderson                                  || arg_ts->state != 0);
43005a18407fSRichard Henderson             }
43015a18407fSRichard Henderson         } else {
43025a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
43035a18407fSRichard Henderson                 /* Liveness should see that globals are saved back,
43045a18407fSRichard Henderson                    that is, TS_DEAD, waiting to be reloaded.  */
4305b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
4306b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
4307b83eabeaSRichard Henderson                                  || arg_ts->state == TS_DEAD);
43085a18407fSRichard Henderson             }
43095a18407fSRichard Henderson         }
43105a18407fSRichard Henderson 
43115a18407fSRichard Henderson         /* Outputs become available.  */
4312b5701261SRichard Henderson         if (opc == INDEX_op_mov) {
431361f15c48SRichard Henderson             arg_ts = arg_temp(op->args[0]);
431461f15c48SRichard Henderson             dir_ts = arg_ts->state_ptr;
431561f15c48SRichard Henderson             if (dir_ts) {
431661f15c48SRichard Henderson                 op->args[0] = temp_arg(dir_ts);
431761f15c48SRichard Henderson                 changes = true;
431861f15c48SRichard Henderson 
431961f15c48SRichard Henderson                 /* The output is now live and modified.  */
432061f15c48SRichard Henderson                 arg_ts->state = 0;
432161f15c48SRichard Henderson 
432261f15c48SRichard Henderson                 if (NEED_SYNC_ARG(0)) {
432361f15c48SRichard Henderson                     TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
432461f15c48SRichard Henderson                                       ? INDEX_op_st_i32
432561f15c48SRichard Henderson                                       : INDEX_op_st_i64);
4326cf5c9f69SRichard Henderson                     TCGOp *sop = tcg_op_insert_after(s, op, sopc,
4327cf5c9f69SRichard Henderson                                                      arg_ts->type, 3);
432861f15c48SRichard Henderson                     TCGTemp *out_ts = dir_ts;
432961f15c48SRichard Henderson 
433061f15c48SRichard Henderson                     if (IS_DEAD_ARG(0)) {
433161f15c48SRichard Henderson                         out_ts = arg_temp(op->args[1]);
433261f15c48SRichard Henderson                         arg_ts->state = TS_DEAD;
433361f15c48SRichard Henderson                         tcg_op_remove(s, op);
433461f15c48SRichard Henderson                     } else {
433561f15c48SRichard Henderson                         arg_ts->state = TS_MEM;
433661f15c48SRichard Henderson                     }
433761f15c48SRichard Henderson 
433861f15c48SRichard Henderson                     sop->args[0] = temp_arg(out_ts);
433961f15c48SRichard Henderson                     sop->args[1] = temp_arg(arg_ts->mem_base);
434061f15c48SRichard Henderson                     sop->args[2] = arg_ts->mem_offset;
434161f15c48SRichard Henderson                 } else {
434261f15c48SRichard Henderson                     tcg_debug_assert(!IS_DEAD_ARG(0));
434361f15c48SRichard Henderson                 }
434461f15c48SRichard Henderson             }
434561f15c48SRichard Henderson         } else {
43465a18407fSRichard Henderson             for (i = 0; i < nb_oargs; i++) {
4347b83eabeaSRichard Henderson                 arg_ts = arg_temp(op->args[i]);
4348b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
4349b83eabeaSRichard Henderson                 if (!dir_ts) {
43505a18407fSRichard Henderson                     continue;
43515a18407fSRichard Henderson                 }
4352b83eabeaSRichard Henderson                 op->args[i] = temp_arg(dir_ts);
43535a18407fSRichard Henderson                 changes = true;
43545a18407fSRichard Henderson 
43555a18407fSRichard Henderson                 /* The output is now live and modified.  */
4356b83eabeaSRichard Henderson                 arg_ts->state = 0;
43575a18407fSRichard Henderson 
43585a18407fSRichard Henderson                 /* Sync outputs upon their last write.  */
43595a18407fSRichard Henderson                 if (NEED_SYNC_ARG(i)) {
4360b83eabeaSRichard Henderson                     TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
43615a18407fSRichard Henderson                                       ? INDEX_op_st_i32
43625a18407fSRichard Henderson                                       : INDEX_op_st_i64);
4363cf5c9f69SRichard Henderson                     TCGOp *sop = tcg_op_insert_after(s, op, sopc,
4364cf5c9f69SRichard Henderson                                                      arg_ts->type, 3);
43655a18407fSRichard Henderson 
4366b83eabeaSRichard Henderson                     sop->args[0] = temp_arg(dir_ts);
4367b83eabeaSRichard Henderson                     sop->args[1] = temp_arg(arg_ts->mem_base);
4368b83eabeaSRichard Henderson                     sop->args[2] = arg_ts->mem_offset;
43695a18407fSRichard Henderson 
4370b83eabeaSRichard Henderson                     arg_ts->state = TS_MEM;
43715a18407fSRichard Henderson                 }
43725a18407fSRichard Henderson                 /* Drop outputs that are dead.  */
43735a18407fSRichard Henderson                 if (IS_DEAD_ARG(i)) {
4374b83eabeaSRichard Henderson                     arg_ts->state = TS_DEAD;
43755a18407fSRichard Henderson                 }
43765a18407fSRichard Henderson             }
43775a18407fSRichard Henderson         }
437861f15c48SRichard Henderson     }
43795a18407fSRichard Henderson 
43805a18407fSRichard Henderson     return changes;
43815a18407fSRichard Henderson }
43825a18407fSRichard Henderson 
43832272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts)
4384c896fe29Sbellard {
438531c96417SRichard Henderson     intptr_t off;
4386273eb50cSRichard Henderson     int size, align;
4387c1c09194SRichard Henderson 
4388273eb50cSRichard Henderson     /* When allocating an object, look at the full type. */
4389273eb50cSRichard Henderson     size = tcg_type_size(ts->base_type);
4390273eb50cSRichard Henderson     switch (ts->base_type) {
4391c1c09194SRichard Henderson     case TCG_TYPE_I32:
439231c96417SRichard Henderson         align = 4;
4393c1c09194SRichard Henderson         break;
4394c1c09194SRichard Henderson     case TCG_TYPE_I64:
4395c1c09194SRichard Henderson     case TCG_TYPE_V64:
439631c96417SRichard Henderson         align = 8;
4397c1c09194SRichard Henderson         break;
439843eef72fSRichard Henderson     case TCG_TYPE_I128:
4399c1c09194SRichard Henderson     case TCG_TYPE_V128:
4400c1c09194SRichard Henderson     case TCG_TYPE_V256:
440143eef72fSRichard Henderson         /*
440243eef72fSRichard Henderson          * Note that we do not require aligned storage for V256,
440343eef72fSRichard Henderson          * and that we provide alignment for I128 to match V128,
440443eef72fSRichard Henderson          * even if that's above what the host ABI requires.
440543eef72fSRichard Henderson          */
440631c96417SRichard Henderson         align = 16;
4407c1c09194SRichard Henderson         break;
4408c1c09194SRichard Henderson     default:
4409c1c09194SRichard Henderson         g_assert_not_reached();
4410b591dc59SBlue Swirl     }
4411c1c09194SRichard Henderson 
4412b9537d59SRichard Henderson     /*
4413b9537d59SRichard Henderson      * Assume the stack is sufficiently aligned.
4414b9537d59SRichard Henderson      * This affects e.g. ARM NEON, where we have 8 byte stack alignment
4415b9537d59SRichard Henderson      * and do not require 16 byte vector alignment.  This seems slightly
4416b9537d59SRichard Henderson      * easier than fully parameterizing the above switch statement.
4417b9537d59SRichard Henderson      */
4418b9537d59SRichard Henderson     align = MIN(TCG_TARGET_STACK_ALIGN, align);
4419c1c09194SRichard Henderson     off = ROUND_UP(s->current_frame_offset, align);
4420732d5897SRichard Henderson 
4421732d5897SRichard Henderson     /* If we've exhausted the stack frame, restart with a smaller TB. */
4422732d5897SRichard Henderson     if (off + size > s->frame_end) {
4423732d5897SRichard Henderson         tcg_raise_tb_overflow(s);
4424732d5897SRichard Henderson     }
4425c1c09194SRichard Henderson     s->current_frame_offset = off + size;
44269defd1bdSRichard Henderson #if defined(__sparc__)
4427273eb50cSRichard Henderson     off += TCG_TARGET_STACK_BIAS;
44289defd1bdSRichard Henderson #endif
4429273eb50cSRichard Henderson 
4430273eb50cSRichard Henderson     /* If the object was subdivided, assign memory to all the parts. */
4431273eb50cSRichard Henderson     if (ts->base_type != ts->type) {
4432273eb50cSRichard Henderson         int part_size = tcg_type_size(ts->type);
4433273eb50cSRichard Henderson         int part_count = size / part_size;
4434273eb50cSRichard Henderson 
4435273eb50cSRichard Henderson         /*
4436273eb50cSRichard Henderson          * Each part is allocated sequentially in tcg_temp_new_internal.
4437273eb50cSRichard Henderson          * Jump back to the first part by subtracting the current index.
4438273eb50cSRichard Henderson          */
4439273eb50cSRichard Henderson         ts -= ts->temp_subindex;
4440273eb50cSRichard Henderson         for (int i = 0; i < part_count; ++i) {
4441273eb50cSRichard Henderson             ts[i].mem_offset = off + i * part_size;
4442273eb50cSRichard Henderson             ts[i].mem_base = s->frame_temp;
4443273eb50cSRichard Henderson             ts[i].mem_allocated = 1;
4444273eb50cSRichard Henderson         }
4445273eb50cSRichard Henderson     } else {
4446273eb50cSRichard Henderson         ts->mem_offset = off;
4447b3a62939SRichard Henderson         ts->mem_base = s->frame_temp;
4448c896fe29Sbellard         ts->mem_allocated = 1;
4449c896fe29Sbellard     }
4450273eb50cSRichard Henderson }
4451c896fe29Sbellard 
4452098859f1SRichard Henderson /* Assign @reg to @ts, and update reg_to_temp[]. */
4453098859f1SRichard Henderson static void set_temp_val_reg(TCGContext *s, TCGTemp *ts, TCGReg reg)
4454098859f1SRichard Henderson {
4455098859f1SRichard Henderson     if (ts->val_type == TEMP_VAL_REG) {
4456098859f1SRichard Henderson         TCGReg old = ts->reg;
4457098859f1SRichard Henderson         tcg_debug_assert(s->reg_to_temp[old] == ts);
4458098859f1SRichard Henderson         if (old == reg) {
4459098859f1SRichard Henderson             return;
4460098859f1SRichard Henderson         }
4461098859f1SRichard Henderson         s->reg_to_temp[old] = NULL;
4462098859f1SRichard Henderson     }
4463098859f1SRichard Henderson     tcg_debug_assert(s->reg_to_temp[reg] == NULL);
4464098859f1SRichard Henderson     s->reg_to_temp[reg] = ts;
4465098859f1SRichard Henderson     ts->val_type = TEMP_VAL_REG;
4466098859f1SRichard Henderson     ts->reg = reg;
4467098859f1SRichard Henderson }
4468098859f1SRichard Henderson 
4469098859f1SRichard Henderson /* Assign a non-register value type to @ts, and update reg_to_temp[]. */
4470098859f1SRichard Henderson static void set_temp_val_nonreg(TCGContext *s, TCGTemp *ts, TCGTempVal type)
4471098859f1SRichard Henderson {
4472098859f1SRichard Henderson     tcg_debug_assert(type != TEMP_VAL_REG);
4473098859f1SRichard Henderson     if (ts->val_type == TEMP_VAL_REG) {
4474098859f1SRichard Henderson         TCGReg reg = ts->reg;
4475098859f1SRichard Henderson         tcg_debug_assert(s->reg_to_temp[reg] == ts);
4476098859f1SRichard Henderson         s->reg_to_temp[reg] = NULL;
4477098859f1SRichard Henderson     }
4478098859f1SRichard Henderson     ts->val_type = type;
4479098859f1SRichard Henderson }
4480098859f1SRichard Henderson 
4481b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet);
4482b3915dbbSRichard Henderson 
448359d7c14eSRichard Henderson /* Mark a temporary as free or dead.  If 'free_or_dead' is negative,
448459d7c14eSRichard Henderson    mark it free; otherwise mark it dead.  */
448559d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead)
4486c896fe29Sbellard {
4487c0522136SRichard Henderson     TCGTempVal new_type;
4488c0522136SRichard Henderson 
4489c0522136SRichard Henderson     switch (ts->kind) {
4490c0522136SRichard Henderson     case TEMP_FIXED:
449159d7c14eSRichard Henderson         return;
4492c0522136SRichard Henderson     case TEMP_GLOBAL:
4493f57c6915SRichard Henderson     case TEMP_TB:
4494c0522136SRichard Henderson         new_type = TEMP_VAL_MEM;
4495c0522136SRichard Henderson         break;
4496c7482438SRichard Henderson     case TEMP_EBB:
4497c0522136SRichard Henderson         new_type = free_or_dead < 0 ? TEMP_VAL_MEM : TEMP_VAL_DEAD;
4498c0522136SRichard Henderson         break;
4499c0522136SRichard Henderson     case TEMP_CONST:
4500c0522136SRichard Henderson         new_type = TEMP_VAL_CONST;
4501c0522136SRichard Henderson         break;
4502c0522136SRichard Henderson     default:
4503c0522136SRichard Henderson         g_assert_not_reached();
450459d7c14eSRichard Henderson     }
4505098859f1SRichard Henderson     set_temp_val_nonreg(s, ts, new_type);
450659d7c14eSRichard Henderson }
4507c896fe29Sbellard 
450859d7c14eSRichard Henderson /* Mark a temporary as dead.  */
450959d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts)
451059d7c14eSRichard Henderson {
451159d7c14eSRichard Henderson     temp_free_or_dead(s, ts, 1);
451259d7c14eSRichard Henderson }
451359d7c14eSRichard Henderson 
451459d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary
451559d7c14eSRichard Henderson    registers needs to be allocated to store a constant.  If 'free_or_dead'
451659d7c14eSRichard Henderson    is non-zero, subsequently release the temporary; if it is positive, the
451759d7c14eSRichard Henderson    temp is dead; if it is negative, the temp is free.  */
451898b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs,
451998b4e186SRichard Henderson                       TCGRegSet preferred_regs, int free_or_dead)
452059d7c14eSRichard Henderson {
4521c0522136SRichard Henderson     if (!temp_readonly(ts) && !ts->mem_coherent) {
45227f6ceedfSAurelien Jarno         if (!ts->mem_allocated) {
45232272e4a7SRichard Henderson             temp_allocate_frame(s, ts);
452459d7c14eSRichard Henderson         }
452559d7c14eSRichard Henderson         switch (ts->val_type) {
452659d7c14eSRichard Henderson         case TEMP_VAL_CONST:
452759d7c14eSRichard Henderson             /* If we're going to free the temp immediately, then we won't
452859d7c14eSRichard Henderson                require it later in a register, so attempt to store the
452959d7c14eSRichard Henderson                constant to memory directly.  */
453059d7c14eSRichard Henderson             if (free_or_dead
453159d7c14eSRichard Henderson                 && tcg_out_sti(s, ts->type, ts->val,
453259d7c14eSRichard Henderson                                ts->mem_base->reg, ts->mem_offset)) {
453359d7c14eSRichard Henderson                 break;
453459d7c14eSRichard Henderson             }
453559d7c14eSRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
453698b4e186SRichard Henderson                       allocated_regs, preferred_regs);
453759d7c14eSRichard Henderson             /* fallthrough */
453859d7c14eSRichard Henderson 
453959d7c14eSRichard Henderson         case TEMP_VAL_REG:
454059d7c14eSRichard Henderson             tcg_out_st(s, ts->type, ts->reg,
454159d7c14eSRichard Henderson                        ts->mem_base->reg, ts->mem_offset);
454259d7c14eSRichard Henderson             break;
454359d7c14eSRichard Henderson 
454459d7c14eSRichard Henderson         case TEMP_VAL_MEM:
454559d7c14eSRichard Henderson             break;
454659d7c14eSRichard Henderson 
454759d7c14eSRichard Henderson         case TEMP_VAL_DEAD:
454859d7c14eSRichard Henderson         default:
4549732e89f4SRichard Henderson             g_assert_not_reached();
4550c896fe29Sbellard         }
45517f6ceedfSAurelien Jarno         ts->mem_coherent = 1;
45527f6ceedfSAurelien Jarno     }
455359d7c14eSRichard Henderson     if (free_or_dead) {
455459d7c14eSRichard Henderson         temp_free_or_dead(s, ts, free_or_dead);
455559d7c14eSRichard Henderson     }
455659d7c14eSRichard Henderson }
45577f6ceedfSAurelien Jarno 
45587f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */
4559b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs)
45607f6ceedfSAurelien Jarno {
4561f8b2f202SRichard Henderson     TCGTemp *ts = s->reg_to_temp[reg];
4562f8b2f202SRichard Henderson     if (ts != NULL) {
456398b4e186SRichard Henderson         temp_sync(s, ts, allocated_regs, 0, -1);
4564c896fe29Sbellard     }
4565c896fe29Sbellard }
4566c896fe29Sbellard 
4567b016486eSRichard Henderson /**
4568b016486eSRichard Henderson  * tcg_reg_alloc:
4569b016486eSRichard Henderson  * @required_regs: Set of registers in which we must allocate.
4570b016486eSRichard Henderson  * @allocated_regs: Set of registers which must be avoided.
4571b016486eSRichard Henderson  * @preferred_regs: Set of registers we should prefer.
4572b016486eSRichard Henderson  * @rev: True if we search the registers in "indirect" order.
4573b016486eSRichard Henderson  *
4574b016486eSRichard Henderson  * The allocated register must be in @required_regs & ~@allocated_regs,
4575b016486eSRichard Henderson  * but if we can put it in @preferred_regs we may save a move later.
4576b016486eSRichard Henderson  */
4577b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs,
4578b016486eSRichard Henderson                             TCGRegSet allocated_regs,
4579b016486eSRichard Henderson                             TCGRegSet preferred_regs, bool rev)
4580c896fe29Sbellard {
4581b016486eSRichard Henderson     int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
4582b016486eSRichard Henderson     TCGRegSet reg_ct[2];
458391478cefSRichard Henderson     const int *order;
4584c896fe29Sbellard 
4585b016486eSRichard Henderson     reg_ct[1] = required_regs & ~allocated_regs;
4586b016486eSRichard Henderson     tcg_debug_assert(reg_ct[1] != 0);
4587b016486eSRichard Henderson     reg_ct[0] = reg_ct[1] & preferred_regs;
4588b016486eSRichard Henderson 
4589b016486eSRichard Henderson     /* Skip the preferred_regs option if it cannot be satisfied,
4590b016486eSRichard Henderson        or if the preference made no difference.  */
4591b016486eSRichard Henderson     f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1];
4592b016486eSRichard Henderson 
459391478cefSRichard Henderson     order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
4594c896fe29Sbellard 
4595b016486eSRichard Henderson     /* Try free registers, preferences first.  */
4596b016486eSRichard Henderson     for (j = f; j < 2; j++) {
4597b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
4598b016486eSRichard Henderson 
4599b016486eSRichard Henderson         if (tcg_regset_single(set)) {
4600b016486eSRichard Henderson             /* One register in the set.  */
4601b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
4602b016486eSRichard Henderson             if (s->reg_to_temp[reg] == NULL) {
4603c896fe29Sbellard                 return reg;
4604c896fe29Sbellard             }
4605b016486eSRichard Henderson         } else {
460691478cefSRichard Henderson             for (i = 0; i < n; i++) {
4607b016486eSRichard Henderson                 TCGReg reg = order[i];
4608b016486eSRichard Henderson                 if (s->reg_to_temp[reg] == NULL &&
4609b016486eSRichard Henderson                     tcg_regset_test_reg(set, reg)) {
4610b016486eSRichard Henderson                     return reg;
4611b016486eSRichard Henderson                 }
4612b016486eSRichard Henderson             }
4613b016486eSRichard Henderson         }
4614b016486eSRichard Henderson     }
4615b016486eSRichard Henderson 
4616b016486eSRichard Henderson     /* We must spill something.  */
4617b016486eSRichard Henderson     for (j = f; j < 2; j++) {
4618b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
4619b016486eSRichard Henderson 
4620b016486eSRichard Henderson         if (tcg_regset_single(set)) {
4621b016486eSRichard Henderson             /* One register in the set.  */
4622b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
4623b3915dbbSRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
4624c896fe29Sbellard             return reg;
4625b016486eSRichard Henderson         } else {
4626b016486eSRichard Henderson             for (i = 0; i < n; i++) {
4627b016486eSRichard Henderson                 TCGReg reg = order[i];
4628b016486eSRichard Henderson                 if (tcg_regset_test_reg(set, reg)) {
4629b016486eSRichard Henderson                     tcg_reg_free(s, reg, allocated_regs);
4630b016486eSRichard Henderson                     return reg;
4631b016486eSRichard Henderson                 }
4632b016486eSRichard Henderson             }
4633c896fe29Sbellard         }
4634c896fe29Sbellard     }
4635c896fe29Sbellard 
4636732e89f4SRichard Henderson     g_assert_not_reached();
4637c896fe29Sbellard }
4638c896fe29Sbellard 
463929f5e925SRichard Henderson static TCGReg tcg_reg_alloc_pair(TCGContext *s, TCGRegSet required_regs,
464029f5e925SRichard Henderson                                  TCGRegSet allocated_regs,
464129f5e925SRichard Henderson                                  TCGRegSet preferred_regs, bool rev)
464229f5e925SRichard Henderson {
464329f5e925SRichard Henderson     int i, j, k, fmin, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
464429f5e925SRichard Henderson     TCGRegSet reg_ct[2];
464529f5e925SRichard Henderson     const int *order;
464629f5e925SRichard Henderson 
464729f5e925SRichard Henderson     /* Ensure that if I is not in allocated_regs, I+1 is not either. */
464829f5e925SRichard Henderson     reg_ct[1] = required_regs & ~(allocated_regs | (allocated_regs >> 1));
464929f5e925SRichard Henderson     tcg_debug_assert(reg_ct[1] != 0);
465029f5e925SRichard Henderson     reg_ct[0] = reg_ct[1] & preferred_regs;
465129f5e925SRichard Henderson 
465229f5e925SRichard Henderson     order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
465329f5e925SRichard Henderson 
465429f5e925SRichard Henderson     /*
465529f5e925SRichard Henderson      * Skip the preferred_regs option if it cannot be satisfied,
465629f5e925SRichard Henderson      * or if the preference made no difference.
465729f5e925SRichard Henderson      */
465829f5e925SRichard Henderson     k = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1];
465929f5e925SRichard Henderson 
466029f5e925SRichard Henderson     /*
466129f5e925SRichard Henderson      * Minimize the number of flushes by looking for 2 free registers first,
466229f5e925SRichard Henderson      * then a single flush, then two flushes.
466329f5e925SRichard Henderson      */
466429f5e925SRichard Henderson     for (fmin = 2; fmin >= 0; fmin--) {
466529f5e925SRichard Henderson         for (j = k; j < 2; j++) {
466629f5e925SRichard Henderson             TCGRegSet set = reg_ct[j];
466729f5e925SRichard Henderson 
466829f5e925SRichard Henderson             for (i = 0; i < n; i++) {
466929f5e925SRichard Henderson                 TCGReg reg = order[i];
467029f5e925SRichard Henderson 
467129f5e925SRichard Henderson                 if (tcg_regset_test_reg(set, reg)) {
467229f5e925SRichard Henderson                     int f = !s->reg_to_temp[reg] + !s->reg_to_temp[reg + 1];
467329f5e925SRichard Henderson                     if (f >= fmin) {
467429f5e925SRichard Henderson                         tcg_reg_free(s, reg, allocated_regs);
467529f5e925SRichard Henderson                         tcg_reg_free(s, reg + 1, allocated_regs);
467629f5e925SRichard Henderson                         return reg;
467729f5e925SRichard Henderson                     }
467829f5e925SRichard Henderson                 }
467929f5e925SRichard Henderson             }
468029f5e925SRichard Henderson         }
468129f5e925SRichard Henderson     }
4682732e89f4SRichard Henderson     g_assert_not_reached();
468329f5e925SRichard Henderson }
468429f5e925SRichard Henderson 
468540ae5c62SRichard Henderson /* Make sure the temporary is in a register.  If needed, allocate the register
468640ae5c62SRichard Henderson    from DESIRED while avoiding ALLOCATED.  */
468740ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs,
4688b722452aSRichard Henderson                       TCGRegSet allocated_regs, TCGRegSet preferred_regs)
468940ae5c62SRichard Henderson {
469040ae5c62SRichard Henderson     TCGReg reg;
469140ae5c62SRichard Henderson 
469240ae5c62SRichard Henderson     switch (ts->val_type) {
469340ae5c62SRichard Henderson     case TEMP_VAL_REG:
469440ae5c62SRichard Henderson         return;
469540ae5c62SRichard Henderson     case TEMP_VAL_CONST:
4696b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
4697b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
46980a6a8bc8SRichard Henderson         if (ts->type <= TCG_TYPE_I64) {
469940ae5c62SRichard Henderson             tcg_out_movi(s, ts->type, reg, ts->val);
47000a6a8bc8SRichard Henderson         } else {
47014e186175SRichard Henderson             uint64_t val = ts->val;
47024e186175SRichard Henderson             MemOp vece = MO_64;
47034e186175SRichard Henderson 
47044e186175SRichard Henderson             /*
47054e186175SRichard Henderson              * Find the minimal vector element that matches the constant.
47064e186175SRichard Henderson              * The targets will, in general, have to do this search anyway,
47074e186175SRichard Henderson              * do this generically.
47084e186175SRichard Henderson              */
47094e186175SRichard Henderson             if (val == dup_const(MO_8, val)) {
47104e186175SRichard Henderson                 vece = MO_8;
47114e186175SRichard Henderson             } else if (val == dup_const(MO_16, val)) {
47124e186175SRichard Henderson                 vece = MO_16;
47130b4286ddSRichard Henderson             } else if (val == dup_const(MO_32, val)) {
47144e186175SRichard Henderson                 vece = MO_32;
47154e186175SRichard Henderson             }
47164e186175SRichard Henderson 
47174e186175SRichard Henderson             tcg_out_dupi_vec(s, ts->type, vece, reg, ts->val);
47180a6a8bc8SRichard Henderson         }
471940ae5c62SRichard Henderson         ts->mem_coherent = 0;
472040ae5c62SRichard Henderson         break;
472140ae5c62SRichard Henderson     case TEMP_VAL_MEM:
4722e139bc4bSPhilippe Mathieu-Daudé         if (!ts->mem_allocated) {
4723e139bc4bSPhilippe Mathieu-Daudé             temp_allocate_frame(s, ts);
4724e139bc4bSPhilippe Mathieu-Daudé         }
4725b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
4726b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
472740ae5c62SRichard Henderson         tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset);
472840ae5c62SRichard Henderson         ts->mem_coherent = 1;
472940ae5c62SRichard Henderson         break;
473040ae5c62SRichard Henderson     case TEMP_VAL_DEAD:
473140ae5c62SRichard Henderson     default:
4732732e89f4SRichard Henderson         g_assert_not_reached();
473340ae5c62SRichard Henderson     }
4734098859f1SRichard Henderson     set_temp_val_reg(s, ts, reg);
473540ae5c62SRichard Henderson }
473640ae5c62SRichard Henderson 
473759d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a
4738e8996ee0Sbellard    temporary registers needs to be allocated to store a constant.  */
473959d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs)
47401ad80729SAurelien Jarno {
47412c0366f0SAurelien Jarno     /* The liveness analysis already ensures that globals are back
4742eabb7b91SAurelien Jarno        in memory. Keep an tcg_debug_assert for safety. */
4743e01fa97dSRichard Henderson     tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || temp_readonly(ts));
47441ad80729SAurelien Jarno }
47451ad80729SAurelien Jarno 
47469814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be
4747641d5fbeSbellard    modified be the following code. 'allocated_regs' is used in case a
4748641d5fbeSbellard    temporary registers needs to be allocated to store a constant. */
4749641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
4750641d5fbeSbellard {
4751ac3b8891SRichard Henderson     int i, n;
4752641d5fbeSbellard 
4753ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
4754b13eb728SRichard Henderson         temp_save(s, &s->temps[i], allocated_regs);
4755641d5fbeSbellard     }
4756e5097dc8Sbellard }
4757e5097dc8Sbellard 
47583d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be
47593d5c5f87SAurelien Jarno    read by the following code. 'allocated_regs' is used in case a
47603d5c5f87SAurelien Jarno    temporary registers needs to be allocated to store a constant. */
47613d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs)
47623d5c5f87SAurelien Jarno {
4763ac3b8891SRichard Henderson     int i, n;
47643d5c5f87SAurelien Jarno 
4765ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
476612b9b11aSRichard Henderson         TCGTemp *ts = &s->temps[i];
476712b9b11aSRichard Henderson         tcg_debug_assert(ts->val_type != TEMP_VAL_REG
4768ee17db83SRichard Henderson                          || ts->kind == TEMP_FIXED
476912b9b11aSRichard Henderson                          || ts->mem_coherent);
47703d5c5f87SAurelien Jarno     }
47713d5c5f87SAurelien Jarno }
47723d5c5f87SAurelien Jarno 
4773e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and
4774e8996ee0Sbellard    all globals are stored at their canonical location. */
4775e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
4776e5097dc8Sbellard {
4777e5097dc8Sbellard     int i;
4778e5097dc8Sbellard 
4779c896fe29Sbellard     for (i = s->nb_globals; i < s->nb_temps; i++) {
4780b13eb728SRichard Henderson         TCGTemp *ts = &s->temps[i];
4781c0522136SRichard Henderson 
4782c0522136SRichard Henderson         switch (ts->kind) {
4783f57c6915SRichard Henderson         case TEMP_TB:
4784b13eb728SRichard Henderson             temp_save(s, ts, allocated_regs);
4785c0522136SRichard Henderson             break;
4786c7482438SRichard Henderson         case TEMP_EBB:
47872c0366f0SAurelien Jarno             /* The liveness analysis already ensures that temps are dead.
4788eabb7b91SAurelien Jarno                Keep an tcg_debug_assert for safety. */
4789eabb7b91SAurelien Jarno             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
4790c0522136SRichard Henderson             break;
4791c0522136SRichard Henderson         case TEMP_CONST:
4792c0522136SRichard Henderson             /* Similarly, we should have freed any allocated register. */
4793c0522136SRichard Henderson             tcg_debug_assert(ts->val_type == TEMP_VAL_CONST);
4794c0522136SRichard Henderson             break;
4795c0522136SRichard Henderson         default:
4796c0522136SRichard Henderson             g_assert_not_reached();
4797c896fe29Sbellard         }
4798641d5fbeSbellard     }
4799e8996ee0Sbellard 
4800e8996ee0Sbellard     save_globals(s, allocated_regs);
4801c896fe29Sbellard }
4802c896fe29Sbellard 
4803bab1671fSRichard Henderson /*
4804c7482438SRichard Henderson  * At a conditional branch, we assume all temporaries are dead unless
4805c7482438SRichard Henderson  * explicitly live-across-conditional-branch; all globals and local
4806c7482438SRichard Henderson  * temps are synced to their location.
4807b4cb76e6SRichard Henderson  */
4808b4cb76e6SRichard Henderson static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs)
4809b4cb76e6SRichard Henderson {
4810b4cb76e6SRichard Henderson     sync_globals(s, allocated_regs);
4811b4cb76e6SRichard Henderson 
4812b4cb76e6SRichard Henderson     for (int i = s->nb_globals; i < s->nb_temps; i++) {
4813b4cb76e6SRichard Henderson         TCGTemp *ts = &s->temps[i];
4814b4cb76e6SRichard Henderson         /*
4815b4cb76e6SRichard Henderson          * The liveness analysis already ensures that temps are dead.
4816b4cb76e6SRichard Henderson          * Keep tcg_debug_asserts for safety.
4817b4cb76e6SRichard Henderson          */
4818c0522136SRichard Henderson         switch (ts->kind) {
4819f57c6915SRichard Henderson         case TEMP_TB:
4820b4cb76e6SRichard Henderson             tcg_debug_assert(ts->val_type != TEMP_VAL_REG || ts->mem_coherent);
4821c0522136SRichard Henderson             break;
4822c7482438SRichard Henderson         case TEMP_EBB:
4823c0522136SRichard Henderson         case TEMP_CONST:
4824c0522136SRichard Henderson             break;
4825c0522136SRichard Henderson         default:
4826c0522136SRichard Henderson             g_assert_not_reached();
4827b4cb76e6SRichard Henderson         }
4828b4cb76e6SRichard Henderson     }
4829b4cb76e6SRichard Henderson }
4830b4cb76e6SRichard Henderson 
4831b4cb76e6SRichard Henderson /*
4832c58f4c97SRichard Henderson  * Specialized code generation for INDEX_op_mov_* with a constant.
4833bab1671fSRichard Henderson  */
48340fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots,
4835ba87719cSRichard Henderson                                   tcg_target_ulong val, TCGLifeData arg_life,
4836ba87719cSRichard Henderson                                   TCGRegSet preferred_regs)
4837e8996ee0Sbellard {
4838d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
4839e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
484059d7c14eSRichard Henderson 
484159d7c14eSRichard Henderson     /* The movi is not explicitly generated here.  */
4842098859f1SRichard Henderson     set_temp_val_nonreg(s, ots, TEMP_VAL_CONST);
4843e8996ee0Sbellard     ots->val = val;
484459d7c14eSRichard Henderson     ots->mem_coherent = 0;
4845ec7a869dSAurelien Jarno     if (NEED_SYNC_ARG(0)) {
4846ba87719cSRichard Henderson         temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0));
484759d7c14eSRichard Henderson     } else if (IS_DEAD_ARG(0)) {
4848f8bf00f1SRichard Henderson         temp_dead(s, ots);
48494c4e1ab2SAurelien Jarno     }
4850e8996ee0Sbellard }
4851e8996ee0Sbellard 
4852bab1671fSRichard Henderson /*
4853bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_mov_*.
4854bab1671fSRichard Henderson  */
4855dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op)
4856c896fe29Sbellard {
4857dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
485869e3706dSRichard Henderson     TCGRegSet allocated_regs, preferred_regs;
4859c896fe29Sbellard     TCGTemp *ts, *ots;
4860450445d5SRichard Henderson     TCGType otype, itype;
4861098859f1SRichard Henderson     TCGReg oreg, ireg;
4862c896fe29Sbellard 
4863d21369f5SRichard Henderson     allocated_regs = s->reserved_regs;
486431fd884bSRichard Henderson     preferred_regs = output_pref(op, 0);
486543439139SRichard Henderson     ots = arg_temp(op->args[0]);
486643439139SRichard Henderson     ts = arg_temp(op->args[1]);
4867450445d5SRichard Henderson 
4868d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
4869e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
4870d63e3b6eSRichard Henderson 
4871450445d5SRichard Henderson     /* Note that otype != itype for no-op truncation.  */
4872450445d5SRichard Henderson     otype = ots->type;
4873450445d5SRichard Henderson     itype = ts->type;
4874c896fe29Sbellard 
48750fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_CONST) {
48760fe4fca4SPaolo Bonzini         /* propagate constant or generate sti */
48770fe4fca4SPaolo Bonzini         tcg_target_ulong val = ts->val;
48780fe4fca4SPaolo Bonzini         if (IS_DEAD_ARG(1)) {
48790fe4fca4SPaolo Bonzini             temp_dead(s, ts);
48800fe4fca4SPaolo Bonzini         }
488169e3706dSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs);
48820fe4fca4SPaolo Bonzini         return;
48830fe4fca4SPaolo Bonzini     }
48840fe4fca4SPaolo Bonzini 
48850fe4fca4SPaolo Bonzini     /* If the source value is in memory we're going to be forced
48860fe4fca4SPaolo Bonzini        to have it in a register in order to perform the copy.  Copy
48870fe4fca4SPaolo Bonzini        the SOURCE value into its own register first, that way we
48880fe4fca4SPaolo Bonzini        don't have to reload SOURCE the next time it is used. */
48890fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_MEM) {
489069e3706dSRichard Henderson         temp_load(s, ts, tcg_target_available_regs[itype],
489169e3706dSRichard Henderson                   allocated_regs, preferred_regs);
4892c29c1d7eSAurelien Jarno     }
48930fe4fca4SPaolo Bonzini     tcg_debug_assert(ts->val_type == TEMP_VAL_REG);
4894098859f1SRichard Henderson     ireg = ts->reg;
4895098859f1SRichard Henderson 
4896d63e3b6eSRichard Henderson     if (IS_DEAD_ARG(0)) {
4897c29c1d7eSAurelien Jarno         /* mov to a non-saved dead register makes no sense (even with
4898c29c1d7eSAurelien Jarno            liveness analysis disabled). */
4899eabb7b91SAurelien Jarno         tcg_debug_assert(NEED_SYNC_ARG(0));
4900c29c1d7eSAurelien Jarno         if (!ots->mem_allocated) {
49012272e4a7SRichard Henderson             temp_allocate_frame(s, ots);
4902c29c1d7eSAurelien Jarno         }
4903098859f1SRichard Henderson         tcg_out_st(s, otype, ireg, ots->mem_base->reg, ots->mem_offset);
4904c29c1d7eSAurelien Jarno         if (IS_DEAD_ARG(1)) {
4905f8bf00f1SRichard Henderson             temp_dead(s, ts);
4906c29c1d7eSAurelien Jarno         }
4907f8bf00f1SRichard Henderson         temp_dead(s, ots);
4908098859f1SRichard Henderson         return;
4909098859f1SRichard Henderson     }
4910098859f1SRichard Henderson 
4911ee17db83SRichard Henderson     if (IS_DEAD_ARG(1) && ts->kind != TEMP_FIXED) {
4912098859f1SRichard Henderson         /*
4913098859f1SRichard Henderson          * The mov can be suppressed.  Kill input first, so that it
4914098859f1SRichard Henderson          * is unlinked from reg_to_temp, then set the output to the
4915098859f1SRichard Henderson          * reg that we saved from the input.
4916098859f1SRichard Henderson          */
4917f8bf00f1SRichard Henderson         temp_dead(s, ts);
4918098859f1SRichard Henderson         oreg = ireg;
4919c29c1d7eSAurelien Jarno     } else {
4920098859f1SRichard Henderson         if (ots->val_type == TEMP_VAL_REG) {
4921098859f1SRichard Henderson             oreg = ots->reg;
4922098859f1SRichard Henderson         } else {
4923098859f1SRichard Henderson             /* Make sure to not spill the input register during allocation. */
4924098859f1SRichard Henderson             oreg = tcg_reg_alloc(s, tcg_target_available_regs[otype],
4925098859f1SRichard Henderson                                  allocated_regs | ((TCGRegSet)1 << ireg),
4926098859f1SRichard Henderson                                  preferred_regs, ots->indirect_base);
4927c29c1d7eSAurelien Jarno         }
4928098859f1SRichard Henderson         if (!tcg_out_mov(s, otype, oreg, ireg)) {
4929240c08d0SRichard Henderson             /*
4930240c08d0SRichard Henderson              * Cross register class move not supported.
4931240c08d0SRichard Henderson              * Store the source register into the destination slot
4932240c08d0SRichard Henderson              * and leave the destination temp as TEMP_VAL_MEM.
4933240c08d0SRichard Henderson              */
4934e01fa97dSRichard Henderson             assert(!temp_readonly(ots));
4935240c08d0SRichard Henderson             if (!ts->mem_allocated) {
4936240c08d0SRichard Henderson                 temp_allocate_frame(s, ots);
4937240c08d0SRichard Henderson             }
4938098859f1SRichard Henderson             tcg_out_st(s, ts->type, ireg, ots->mem_base->reg, ots->mem_offset);
4939098859f1SRichard Henderson             set_temp_val_nonreg(s, ts, TEMP_VAL_MEM);
4940240c08d0SRichard Henderson             ots->mem_coherent = 1;
4941240c08d0SRichard Henderson             return;
494278113e83SRichard Henderson         }
4943c29c1d7eSAurelien Jarno     }
4944098859f1SRichard Henderson     set_temp_val_reg(s, ots, oreg);
4945c896fe29Sbellard     ots->mem_coherent = 0;
4946098859f1SRichard Henderson 
4947ec7a869dSAurelien Jarno     if (NEED_SYNC_ARG(0)) {
494898b4e186SRichard Henderson         temp_sync(s, ots, allocated_regs, 0, 0);
4949c29c1d7eSAurelien Jarno     }
4950ec7a869dSAurelien Jarno }
4951c896fe29Sbellard 
4952bab1671fSRichard Henderson /*
4953bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_dup_vec.
4954bab1671fSRichard Henderson  */
4955bab1671fSRichard Henderson static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op)
4956bab1671fSRichard Henderson {
4957bab1671fSRichard Henderson     const TCGLifeData arg_life = op->life;
4958bab1671fSRichard Henderson     TCGRegSet dup_out_regs, dup_in_regs;
4959501fb3daSRichard Henderson     const TCGArgConstraint *dup_args_ct;
4960bab1671fSRichard Henderson     TCGTemp *its, *ots;
4961bab1671fSRichard Henderson     TCGType itype, vtype;
4962bab1671fSRichard Henderson     unsigned vece;
496331c96417SRichard Henderson     int lowpart_ofs;
4964bab1671fSRichard Henderson     bool ok;
4965bab1671fSRichard Henderson 
4966bab1671fSRichard Henderson     ots = arg_temp(op->args[0]);
4967bab1671fSRichard Henderson     its = arg_temp(op->args[1]);
4968bab1671fSRichard Henderson 
4969bab1671fSRichard Henderson     /* ENV should not be modified.  */
4970e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
4971bab1671fSRichard Henderson 
4972bab1671fSRichard Henderson     itype = its->type;
4973bab1671fSRichard Henderson     vece = TCGOP_VECE(op);
49744d872218SRichard Henderson     vtype = TCGOP_TYPE(op);
4975bab1671fSRichard Henderson 
4976bab1671fSRichard Henderson     if (its->val_type == TEMP_VAL_CONST) {
4977bab1671fSRichard Henderson         /* Propagate constant via movi -> dupi.  */
4978bab1671fSRichard Henderson         tcg_target_ulong val = its->val;
4979bab1671fSRichard Henderson         if (IS_DEAD_ARG(1)) {
4980bab1671fSRichard Henderson             temp_dead(s, its);
4981bab1671fSRichard Henderson         }
498231fd884bSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, output_pref(op, 0));
4983bab1671fSRichard Henderson         return;
4984bab1671fSRichard Henderson     }
4985bab1671fSRichard Henderson 
4986501fb3daSRichard Henderson     dup_args_ct = opcode_args_ct(op);
4987501fb3daSRichard Henderson     dup_out_regs = dup_args_ct[0].regs;
4988501fb3daSRichard Henderson     dup_in_regs = dup_args_ct[1].regs;
4989bab1671fSRichard Henderson 
4990bab1671fSRichard Henderson     /* Allocate the output register now.  */
4991bab1671fSRichard Henderson     if (ots->val_type != TEMP_VAL_REG) {
4992bab1671fSRichard Henderson         TCGRegSet allocated_regs = s->reserved_regs;
4993098859f1SRichard Henderson         TCGReg oreg;
4994bab1671fSRichard Henderson 
4995bab1671fSRichard Henderson         if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) {
4996bab1671fSRichard Henderson             /* Make sure to not spill the input register. */
4997bab1671fSRichard Henderson             tcg_regset_set_reg(allocated_regs, its->reg);
4998bab1671fSRichard Henderson         }
4999098859f1SRichard Henderson         oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
500031fd884bSRichard Henderson                              output_pref(op, 0), ots->indirect_base);
5001098859f1SRichard Henderson         set_temp_val_reg(s, ots, oreg);
5002bab1671fSRichard Henderson     }
5003bab1671fSRichard Henderson 
5004bab1671fSRichard Henderson     switch (its->val_type) {
5005bab1671fSRichard Henderson     case TEMP_VAL_REG:
5006bab1671fSRichard Henderson         /*
5007bab1671fSRichard Henderson          * The dup constriaints must be broad, covering all possible VECE.
5008bab1671fSRichard Henderson          * However, tcg_op_dup_vec() gets to see the VECE and we allow it
5009bab1671fSRichard Henderson          * to fail, indicating that extra moves are required for that case.
5010bab1671fSRichard Henderson          */
5011bab1671fSRichard Henderson         if (tcg_regset_test_reg(dup_in_regs, its->reg)) {
5012bab1671fSRichard Henderson             if (tcg_out_dup_vec(s, vtype, vece, ots->reg, its->reg)) {
5013bab1671fSRichard Henderson                 goto done;
5014bab1671fSRichard Henderson             }
5015bab1671fSRichard Henderson             /* Try again from memory or a vector input register.  */
5016bab1671fSRichard Henderson         }
5017bab1671fSRichard Henderson         if (!its->mem_coherent) {
5018bab1671fSRichard Henderson             /*
5019bab1671fSRichard Henderson              * The input register is not synced, and so an extra store
5020bab1671fSRichard Henderson              * would be required to use memory.  Attempt an integer-vector
5021bab1671fSRichard Henderson              * register move first.  We do not have a TCGRegSet for this.
5022bab1671fSRichard Henderson              */
5023bab1671fSRichard Henderson             if (tcg_out_mov(s, itype, ots->reg, its->reg)) {
5024bab1671fSRichard Henderson                 break;
5025bab1671fSRichard Henderson             }
5026bab1671fSRichard Henderson             /* Sync the temp back to its slot and load from there.  */
5027bab1671fSRichard Henderson             temp_sync(s, its, s->reserved_regs, 0, 0);
5028bab1671fSRichard Henderson         }
5029bab1671fSRichard Henderson         /* fall through */
5030bab1671fSRichard Henderson 
5031bab1671fSRichard Henderson     case TEMP_VAL_MEM:
503231c96417SRichard Henderson         lowpart_ofs = 0;
503331c96417SRichard Henderson         if (HOST_BIG_ENDIAN) {
503431c96417SRichard Henderson             lowpart_ofs = tcg_type_size(itype) - (1 << vece);
503531c96417SRichard Henderson         }
5036d6ecb4a9SRichard Henderson         if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg,
503731c96417SRichard Henderson                              its->mem_offset + lowpart_ofs)) {
5038d6ecb4a9SRichard Henderson             goto done;
5039d6ecb4a9SRichard Henderson         }
5040098859f1SRichard Henderson         /* Load the input into the destination vector register. */
5041bab1671fSRichard Henderson         tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset);
5042bab1671fSRichard Henderson         break;
5043bab1671fSRichard Henderson 
5044bab1671fSRichard Henderson     default:
5045bab1671fSRichard Henderson         g_assert_not_reached();
5046bab1671fSRichard Henderson     }
5047bab1671fSRichard Henderson 
5048bab1671fSRichard Henderson     /* We now have a vector input register, so dup must succeed. */
5049bab1671fSRichard Henderson     ok = tcg_out_dup_vec(s, vtype, vece, ots->reg, ots->reg);
5050bab1671fSRichard Henderson     tcg_debug_assert(ok);
5051bab1671fSRichard Henderson 
5052bab1671fSRichard Henderson  done:
505336f5539cSRichard Henderson     ots->mem_coherent = 0;
5054bab1671fSRichard Henderson     if (IS_DEAD_ARG(1)) {
5055bab1671fSRichard Henderson         temp_dead(s, its);
5056bab1671fSRichard Henderson     }
5057bab1671fSRichard Henderson     if (NEED_SYNC_ARG(0)) {
5058bab1671fSRichard Henderson         temp_sync(s, ots, s->reserved_regs, 0, 0);
5059bab1671fSRichard Henderson     }
5060bab1671fSRichard Henderson     if (IS_DEAD_ARG(0)) {
5061bab1671fSRichard Henderson         temp_dead(s, ots);
5062bab1671fSRichard Henderson     }
5063bab1671fSRichard Henderson }
5064bab1671fSRichard Henderson 
5065dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op)
5066c896fe29Sbellard {
5067dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
5068dd186292SRichard Henderson     const TCGOpDef * const def = &tcg_op_defs[op->opc];
506982790a87SRichard Henderson     TCGRegSet i_allocated_regs;
507082790a87SRichard Henderson     TCGRegSet o_allocated_regs;
5071b6638662SRichard Henderson     int i, k, nb_iargs, nb_oargs;
5072b6638662SRichard Henderson     TCGReg reg;
5073c896fe29Sbellard     TCGArg arg;
5074501fb3daSRichard Henderson     const TCGArgConstraint *args_ct;
5075c896fe29Sbellard     const TCGArgConstraint *arg_ct;
5076c896fe29Sbellard     TCGTemp *ts;
5077c896fe29Sbellard     TCGArg new_args[TCG_MAX_OP_ARGS];
5078c896fe29Sbellard     int const_args[TCG_MAX_OP_ARGS];
507921e9a8aeSRichard Henderson     TCGCond op_cond;
5080c896fe29Sbellard 
5081c896fe29Sbellard     nb_oargs = def->nb_oargs;
5082c896fe29Sbellard     nb_iargs = def->nb_iargs;
5083c896fe29Sbellard 
5084c896fe29Sbellard     /* copy constants */
5085c896fe29Sbellard     memcpy(new_args + nb_oargs + nb_iargs,
5086dd186292SRichard Henderson            op->args + nb_oargs + nb_iargs,
5087c896fe29Sbellard            sizeof(TCGArg) * def->nb_cargs);
5088c896fe29Sbellard 
5089d21369f5SRichard Henderson     i_allocated_regs = s->reserved_regs;
5090d21369f5SRichard Henderson     o_allocated_regs = s->reserved_regs;
509182790a87SRichard Henderson 
509221e9a8aeSRichard Henderson     switch (op->opc) {
5093b6d69fceSRichard Henderson     case INDEX_op_brcond:
509421e9a8aeSRichard Henderson         op_cond = op->args[2];
509521e9a8aeSRichard Henderson         break;
5096a363e1e1SRichard Henderson     case INDEX_op_setcond:
5097a363e1e1SRichard Henderson     case INDEX_op_negsetcond:
509821e9a8aeSRichard Henderson     case INDEX_op_cmp_vec:
509921e9a8aeSRichard Henderson         op_cond = op->args[3];
510021e9a8aeSRichard Henderson         break;
510121e9a8aeSRichard Henderson     case INDEX_op_brcond2_i32:
510221e9a8aeSRichard Henderson         op_cond = op->args[4];
510321e9a8aeSRichard Henderson         break;
5104ea46c4bcSRichard Henderson     case INDEX_op_movcond:
510521e9a8aeSRichard Henderson     case INDEX_op_setcond2_i32:
510621e9a8aeSRichard Henderson     case INDEX_op_cmpsel_vec:
510721e9a8aeSRichard Henderson         op_cond = op->args[5];
510821e9a8aeSRichard Henderson         break;
510921e9a8aeSRichard Henderson     default:
511021e9a8aeSRichard Henderson         /* No condition within opcode. */
511121e9a8aeSRichard Henderson         op_cond = TCG_COND_ALWAYS;
511221e9a8aeSRichard Henderson         break;
511321e9a8aeSRichard Henderson     }
511421e9a8aeSRichard Henderson 
5115501fb3daSRichard Henderson     args_ct = opcode_args_ct(op);
5116501fb3daSRichard Henderson 
5117c896fe29Sbellard     /* satisfy input constraints */
5118c896fe29Sbellard     for (k = 0; k < nb_iargs; k++) {
511929f5e925SRichard Henderson         TCGRegSet i_preferred_regs, i_required_regs;
512029f5e925SRichard Henderson         bool allocate_new_reg, copyto_new_reg;
512129f5e925SRichard Henderson         TCGTemp *ts2;
512229f5e925SRichard Henderson         int i1, i2;
5123d62816f2SRichard Henderson 
5124501fb3daSRichard Henderson         i = args_ct[nb_oargs + k].sort_index;
5125dd186292SRichard Henderson         arg = op->args[i];
5126501fb3daSRichard Henderson         arg_ct = &args_ct[i];
512743439139SRichard Henderson         ts = arg_temp(arg);
512840ae5c62SRichard Henderson 
51296b8abd24SRichard Henderson         if (ts->val_type == TEMP_VAL_CONST) {
51306b8abd24SRichard Henderson #ifdef TCG_REG_ZERO
51316b8abd24SRichard Henderson             if (ts->val == 0 && (arg_ct->ct & TCG_CT_REG_ZERO)) {
51326b8abd24SRichard Henderson                 /* Hardware zero register: indicate register via non-const. */
51336b8abd24SRichard Henderson                 const_args[i] = 0;
51346b8abd24SRichard Henderson                 new_args[i] = TCG_REG_ZERO;
51356b8abd24SRichard Henderson                 continue;
51366b8abd24SRichard Henderson             }
51376b8abd24SRichard Henderson #endif
51386b8abd24SRichard Henderson 
51396b8abd24SRichard Henderson             if (tcg_target_const_match(ts->val, arg_ct->ct, ts->type,
514021e9a8aeSRichard Henderson                                        op_cond, TCGOP_VECE(op))) {
5141c896fe29Sbellard                 /* constant is OK for instruction */
5142c896fe29Sbellard                 const_args[i] = 1;
5143c896fe29Sbellard                 new_args[i] = ts->val;
5144d62816f2SRichard Henderson                 continue;
5145c896fe29Sbellard             }
51466b8abd24SRichard Henderson         }
514740ae5c62SRichard Henderson 
51481c1824dcSRichard Henderson         reg = ts->reg;
51491c1824dcSRichard Henderson         i_preferred_regs = 0;
515029f5e925SRichard Henderson         i_required_regs = arg_ct->regs;
51511c1824dcSRichard Henderson         allocate_new_reg = false;
515229f5e925SRichard Henderson         copyto_new_reg = false;
51531c1824dcSRichard Henderson 
515429f5e925SRichard Henderson         switch (arg_ct->pair) {
515529f5e925SRichard Henderson         case 0: /* not paired */
5156bc2b17e6SRichard Henderson             if (arg_ct->ialias) {
515731fd884bSRichard Henderson                 i_preferred_regs = output_pref(op, arg_ct->alias_index);
5158c0522136SRichard Henderson 
5159c0522136SRichard Henderson                 /*
5160c0522136SRichard Henderson                  * If the input is readonly, then it cannot also be an
5161c0522136SRichard Henderson                  * output and aliased to itself.  If the input is not
5162c0522136SRichard Henderson                  * dead after the instruction, we must allocate a new
5163c0522136SRichard Henderson                  * register and move it.
5164c0522136SRichard Henderson                  */
516522d2e535SIlya Leoshkevich                 if (temp_readonly(ts) || !IS_DEAD_ARG(i)
5166501fb3daSRichard Henderson                     || args_ct[arg_ct->alias_index].newreg) {
51671c1824dcSRichard Henderson                     allocate_new_reg = true;
51681c1824dcSRichard Henderson                 } else if (ts->val_type == TEMP_VAL_REG) {
5169c0522136SRichard Henderson                     /*
51701c1824dcSRichard Henderson                      * Check if the current register has already been
51711c1824dcSRichard Henderson                      * allocated for another input.
5172c0522136SRichard Henderson                      */
517329f5e925SRichard Henderson                     allocate_new_reg =
517429f5e925SRichard Henderson                         tcg_regset_test_reg(i_allocated_regs, reg);
51757e1df267SAurelien Jarno                 }
51767e1df267SAurelien Jarno             }
51771c1824dcSRichard Henderson             if (!allocate_new_reg) {
517829f5e925SRichard Henderson                 temp_load(s, ts, i_required_regs, i_allocated_regs,
517929f5e925SRichard Henderson                           i_preferred_regs);
5180c896fe29Sbellard                 reg = ts->reg;
518129f5e925SRichard Henderson                 allocate_new_reg = !tcg_regset_test_reg(i_required_regs, reg);
51821c1824dcSRichard Henderson             }
51831c1824dcSRichard Henderson             if (allocate_new_reg) {
5184c0522136SRichard Henderson                 /*
5185c0522136SRichard Henderson                  * Allocate a new register matching the constraint
5186c0522136SRichard Henderson                  * and move the temporary register into it.
5187c0522136SRichard Henderson                  */
5188d62816f2SRichard Henderson                 temp_load(s, ts, tcg_target_available_regs[ts->type],
5189d62816f2SRichard Henderson                           i_allocated_regs, 0);
519029f5e925SRichard Henderson                 reg = tcg_reg_alloc(s, i_required_regs, i_allocated_regs,
51911c1824dcSRichard Henderson                                     i_preferred_regs, ts->indirect_base);
519229f5e925SRichard Henderson                 copyto_new_reg = true;
519329f5e925SRichard Henderson             }
519429f5e925SRichard Henderson             break;
519529f5e925SRichard Henderson 
519629f5e925SRichard Henderson         case 1:
519729f5e925SRichard Henderson             /* First of an input pair; if i1 == i2, the second is an output. */
519829f5e925SRichard Henderson             i1 = i;
519929f5e925SRichard Henderson             i2 = arg_ct->pair_index;
520029f5e925SRichard Henderson             ts2 = i1 != i2 ? arg_temp(op->args[i2]) : NULL;
520129f5e925SRichard Henderson 
520229f5e925SRichard Henderson             /*
520329f5e925SRichard Henderson              * It is easier to default to allocating a new pair
520429f5e925SRichard Henderson              * and to identify a few cases where it's not required.
520529f5e925SRichard Henderson              */
520629f5e925SRichard Henderson             if (arg_ct->ialias) {
520731fd884bSRichard Henderson                 i_preferred_regs = output_pref(op, arg_ct->alias_index);
520829f5e925SRichard Henderson                 if (IS_DEAD_ARG(i1) &&
520929f5e925SRichard Henderson                     IS_DEAD_ARG(i2) &&
521029f5e925SRichard Henderson                     !temp_readonly(ts) &&
521129f5e925SRichard Henderson                     ts->val_type == TEMP_VAL_REG &&
521229f5e925SRichard Henderson                     ts->reg < TCG_TARGET_NB_REGS - 1 &&
521329f5e925SRichard Henderson                     tcg_regset_test_reg(i_required_regs, reg) &&
521429f5e925SRichard Henderson                     !tcg_regset_test_reg(i_allocated_regs, reg) &&
521529f5e925SRichard Henderson                     !tcg_regset_test_reg(i_allocated_regs, reg + 1) &&
521629f5e925SRichard Henderson                     (ts2
521729f5e925SRichard Henderson                      ? ts2->val_type == TEMP_VAL_REG &&
521829f5e925SRichard Henderson                        ts2->reg == reg + 1 &&
521929f5e925SRichard Henderson                        !temp_readonly(ts2)
522029f5e925SRichard Henderson                      : s->reg_to_temp[reg + 1] == NULL)) {
522129f5e925SRichard Henderson                     break;
522229f5e925SRichard Henderson                 }
522329f5e925SRichard Henderson             } else {
522429f5e925SRichard Henderson                 /* Without aliasing, the pair must also be an input. */
522529f5e925SRichard Henderson                 tcg_debug_assert(ts2);
522629f5e925SRichard Henderson                 if (ts->val_type == TEMP_VAL_REG &&
522729f5e925SRichard Henderson                     ts2->val_type == TEMP_VAL_REG &&
522829f5e925SRichard Henderson                     ts2->reg == reg + 1 &&
522929f5e925SRichard Henderson                     tcg_regset_test_reg(i_required_regs, reg)) {
523029f5e925SRichard Henderson                     break;
523129f5e925SRichard Henderson                 }
523229f5e925SRichard Henderson             }
523329f5e925SRichard Henderson             reg = tcg_reg_alloc_pair(s, i_required_regs, i_allocated_regs,
523429f5e925SRichard Henderson                                      0, ts->indirect_base);
523529f5e925SRichard Henderson             goto do_pair;
523629f5e925SRichard Henderson 
523729f5e925SRichard Henderson         case 2: /* pair second */
523829f5e925SRichard Henderson             reg = new_args[arg_ct->pair_index] + 1;
523929f5e925SRichard Henderson             goto do_pair;
524029f5e925SRichard Henderson 
524129f5e925SRichard Henderson         case 3: /* ialias with second output, no first input */
524229f5e925SRichard Henderson             tcg_debug_assert(arg_ct->ialias);
524331fd884bSRichard Henderson             i_preferred_regs = output_pref(op, arg_ct->alias_index);
524429f5e925SRichard Henderson 
524529f5e925SRichard Henderson             if (IS_DEAD_ARG(i) &&
524629f5e925SRichard Henderson                 !temp_readonly(ts) &&
524729f5e925SRichard Henderson                 ts->val_type == TEMP_VAL_REG &&
524829f5e925SRichard Henderson                 reg > 0 &&
524929f5e925SRichard Henderson                 s->reg_to_temp[reg - 1] == NULL &&
525029f5e925SRichard Henderson                 tcg_regset_test_reg(i_required_regs, reg) &&
525129f5e925SRichard Henderson                 !tcg_regset_test_reg(i_allocated_regs, reg) &&
525229f5e925SRichard Henderson                 !tcg_regset_test_reg(i_allocated_regs, reg - 1)) {
525329f5e925SRichard Henderson                 tcg_regset_set_reg(i_allocated_regs, reg - 1);
525429f5e925SRichard Henderson                 break;
525529f5e925SRichard Henderson             }
525629f5e925SRichard Henderson             reg = tcg_reg_alloc_pair(s, i_required_regs >> 1,
525729f5e925SRichard Henderson                                      i_allocated_regs, 0,
525829f5e925SRichard Henderson                                      ts->indirect_base);
525929f5e925SRichard Henderson             tcg_regset_set_reg(i_allocated_regs, reg);
526029f5e925SRichard Henderson             reg += 1;
526129f5e925SRichard Henderson             goto do_pair;
526229f5e925SRichard Henderson 
526329f5e925SRichard Henderson         do_pair:
526429f5e925SRichard Henderson             /*
526529f5e925SRichard Henderson              * If an aliased input is not dead after the instruction,
526629f5e925SRichard Henderson              * we must allocate a new register and move it.
526729f5e925SRichard Henderson              */
526829f5e925SRichard Henderson             if (arg_ct->ialias && (!IS_DEAD_ARG(i) || temp_readonly(ts))) {
526929f5e925SRichard Henderson                 TCGRegSet t_allocated_regs = i_allocated_regs;
527029f5e925SRichard Henderson 
527129f5e925SRichard Henderson                 /*
527229f5e925SRichard Henderson                  * Because of the alias, and the continued life, make sure
527329f5e925SRichard Henderson                  * that the temp is somewhere *other* than the reg pair,
527429f5e925SRichard Henderson                  * and we get a copy in reg.
527529f5e925SRichard Henderson                  */
527629f5e925SRichard Henderson                 tcg_regset_set_reg(t_allocated_regs, reg);
527729f5e925SRichard Henderson                 tcg_regset_set_reg(t_allocated_regs, reg + 1);
527829f5e925SRichard Henderson                 if (ts->val_type == TEMP_VAL_REG && ts->reg == reg) {
527929f5e925SRichard Henderson                     /* If ts was already in reg, copy it somewhere else. */
528029f5e925SRichard Henderson                     TCGReg nr;
528129f5e925SRichard Henderson                     bool ok;
528229f5e925SRichard Henderson 
528329f5e925SRichard Henderson                     tcg_debug_assert(ts->kind != TEMP_FIXED);
528429f5e925SRichard Henderson                     nr = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
528529f5e925SRichard Henderson                                        t_allocated_regs, 0, ts->indirect_base);
528629f5e925SRichard Henderson                     ok = tcg_out_mov(s, ts->type, nr, reg);
528729f5e925SRichard Henderson                     tcg_debug_assert(ok);
528829f5e925SRichard Henderson 
528929f5e925SRichard Henderson                     set_temp_val_reg(s, ts, nr);
529029f5e925SRichard Henderson                 } else {
529129f5e925SRichard Henderson                     temp_load(s, ts, tcg_target_available_regs[ts->type],
529229f5e925SRichard Henderson                               t_allocated_regs, 0);
529329f5e925SRichard Henderson                     copyto_new_reg = true;
529429f5e925SRichard Henderson                 }
529529f5e925SRichard Henderson             } else {
529629f5e925SRichard Henderson                 /* Preferably allocate to reg, otherwise copy. */
529729f5e925SRichard Henderson                 i_required_regs = (TCGRegSet)1 << reg;
529829f5e925SRichard Henderson                 temp_load(s, ts, i_required_regs, i_allocated_regs,
529929f5e925SRichard Henderson                           i_preferred_regs);
530029f5e925SRichard Henderson                 copyto_new_reg = ts->reg != reg;
530129f5e925SRichard Henderson             }
530229f5e925SRichard Henderson             break;
530329f5e925SRichard Henderson 
530429f5e925SRichard Henderson         default:
530529f5e925SRichard Henderson             g_assert_not_reached();
530629f5e925SRichard Henderson         }
530729f5e925SRichard Henderson 
530829f5e925SRichard Henderson         if (copyto_new_reg) {
530978113e83SRichard Henderson             if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
5310240c08d0SRichard Henderson                 /*
5311240c08d0SRichard Henderson                  * Cross register class move not supported.  Sync the
5312240c08d0SRichard Henderson                  * temp back to its slot and load from there.
5313240c08d0SRichard Henderson                  */
5314240c08d0SRichard Henderson                 temp_sync(s, ts, i_allocated_regs, 0, 0);
5315240c08d0SRichard Henderson                 tcg_out_ld(s, ts->type, reg,
5316240c08d0SRichard Henderson                            ts->mem_base->reg, ts->mem_offset);
531778113e83SRichard Henderson             }
5318c896fe29Sbellard         }
5319c896fe29Sbellard         new_args[i] = reg;
5320c896fe29Sbellard         const_args[i] = 0;
532182790a87SRichard Henderson         tcg_regset_set_reg(i_allocated_regs, reg);
5322c896fe29Sbellard     }
5323c896fe29Sbellard 
5324c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
5325866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
5326866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
532743439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
5328c896fe29Sbellard         }
5329c896fe29Sbellard     }
5330c896fe29Sbellard 
5331b4cb76e6SRichard Henderson     if (def->flags & TCG_OPF_COND_BRANCH) {
5332b4cb76e6SRichard Henderson         tcg_reg_alloc_cbranch(s, i_allocated_regs);
5333b4cb76e6SRichard Henderson     } else if (def->flags & TCG_OPF_BB_END) {
533482790a87SRichard Henderson         tcg_reg_alloc_bb_end(s, i_allocated_regs);
5335a52ad07eSAurelien Jarno     } else {
5336c896fe29Sbellard         if (def->flags & TCG_OPF_CALL_CLOBBER) {
5337b03cce8eSbellard             /* XXX: permit generic clobber register list ? */
5338c8074023SRichard Henderson             for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
5339c8074023SRichard Henderson                 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
534082790a87SRichard Henderson                     tcg_reg_free(s, i, i_allocated_regs);
5341c896fe29Sbellard                 }
5342c896fe29Sbellard             }
53433d5c5f87SAurelien Jarno         }
53443d5c5f87SAurelien Jarno         if (def->flags & TCG_OPF_SIDE_EFFECTS) {
53453d5c5f87SAurelien Jarno             /* sync globals if the op has side effects and might trigger
53463d5c5f87SAurelien Jarno                an exception. */
534782790a87SRichard Henderson             sync_globals(s, i_allocated_regs);
5348c896fe29Sbellard         }
5349c896fe29Sbellard 
5350c896fe29Sbellard         /* satisfy the output constraints */
5351c896fe29Sbellard         for (k = 0; k < nb_oargs; k++) {
5352501fb3daSRichard Henderson             i = args_ct[k].sort_index;
5353dd186292SRichard Henderson             arg = op->args[i];
5354501fb3daSRichard Henderson             arg_ct = &args_ct[i];
535543439139SRichard Henderson             ts = arg_temp(arg);
5356d63e3b6eSRichard Henderson 
5357d63e3b6eSRichard Henderson             /* ENV should not be modified.  */
5358e01fa97dSRichard Henderson             tcg_debug_assert(!temp_readonly(ts));
5359d63e3b6eSRichard Henderson 
536029f5e925SRichard Henderson             switch (arg_ct->pair) {
536129f5e925SRichard Henderson             case 0: /* not paired */
5362bc2b17e6SRichard Henderson                 if (arg_ct->oalias && !const_args[arg_ct->alias_index]) {
53635ff9d6a4Sbellard                     reg = new_args[arg_ct->alias_index];
5364bc2b17e6SRichard Henderson                 } else if (arg_ct->newreg) {
53659be0d080SRichard Henderson                     reg = tcg_reg_alloc(s, arg_ct->regs,
536682790a87SRichard Henderson                                         i_allocated_regs | o_allocated_regs,
536731fd884bSRichard Henderson                                         output_pref(op, k), ts->indirect_base);
5368c896fe29Sbellard                 } else {
53699be0d080SRichard Henderson                     reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs,
537031fd884bSRichard Henderson                                         output_pref(op, k), ts->indirect_base);
5371c896fe29Sbellard                 }
537229f5e925SRichard Henderson                 break;
537329f5e925SRichard Henderson 
537429f5e925SRichard Henderson             case 1: /* first of pair */
537529f5e925SRichard Henderson                 if (arg_ct->oalias) {
537629f5e925SRichard Henderson                     reg = new_args[arg_ct->alias_index];
5377ca5bed07SRichard Henderson                 } else if (arg_ct->newreg) {
5378ca5bed07SRichard Henderson                     reg = tcg_reg_alloc_pair(s, arg_ct->regs,
5379ca5bed07SRichard Henderson                                              i_allocated_regs | o_allocated_regs,
5380ca5bed07SRichard Henderson                                              output_pref(op, k),
5381ca5bed07SRichard Henderson                                              ts->indirect_base);
5382ca5bed07SRichard Henderson                 } else {
538329f5e925SRichard Henderson                     reg = tcg_reg_alloc_pair(s, arg_ct->regs, o_allocated_regs,
5384ca5bed07SRichard Henderson                                              output_pref(op, k),
5385ca5bed07SRichard Henderson                                              ts->indirect_base);
5386ca5bed07SRichard Henderson                 }
538729f5e925SRichard Henderson                 break;
538829f5e925SRichard Henderson 
538929f5e925SRichard Henderson             case 2: /* second of pair */
539029f5e925SRichard Henderson                 if (arg_ct->oalias) {
539129f5e925SRichard Henderson                     reg = new_args[arg_ct->alias_index];
539229f5e925SRichard Henderson                 } else {
539329f5e925SRichard Henderson                     reg = new_args[arg_ct->pair_index] + 1;
539429f5e925SRichard Henderson                 }
539529f5e925SRichard Henderson                 break;
539629f5e925SRichard Henderson 
539729f5e925SRichard Henderson             case 3: /* first of pair, aliasing with a second input */
539829f5e925SRichard Henderson                 tcg_debug_assert(!arg_ct->newreg);
539929f5e925SRichard Henderson                 reg = new_args[arg_ct->pair_index] - 1;
540029f5e925SRichard Henderson                 break;
540129f5e925SRichard Henderson 
540229f5e925SRichard Henderson             default:
540329f5e925SRichard Henderson                 g_assert_not_reached();
540429f5e925SRichard Henderson             }
540582790a87SRichard Henderson             tcg_regset_set_reg(o_allocated_regs, reg);
5406098859f1SRichard Henderson             set_temp_val_reg(s, ts, reg);
5407c896fe29Sbellard             ts->mem_coherent = 0;
5408c896fe29Sbellard             new_args[i] = reg;
5409c896fe29Sbellard         }
5410e8996ee0Sbellard     }
5411c896fe29Sbellard 
5412c896fe29Sbellard     /* emit instruction */
5413662cdbcfSRichard Henderson     TCGType type = TCGOP_TYPE(op);
5414678155b2SRichard Henderson     switch (op->opc) {
54159c6aa274SRichard Henderson     case INDEX_op_ext_i32_i64:
54169c6aa274SRichard Henderson         tcg_out_exts_i32_i64(s, new_args[0], new_args[1]);
54179c6aa274SRichard Henderson         break;
5418b9bfe000SRichard Henderson     case INDEX_op_extu_i32_i64:
5419b9bfe000SRichard Henderson         tcg_out_extu_i32_i64(s, new_args[0], new_args[1]);
5420b9bfe000SRichard Henderson         break;
5421b8b94ac6SRichard Henderson     case INDEX_op_extrl_i64_i32:
5422b8b94ac6SRichard Henderson         tcg_out_extrl_i64_i32(s, new_args[0], new_args[1]);
5423b8b94ac6SRichard Henderson         break;
5424662cdbcfSRichard Henderson 
542579602f63SRichard Henderson     case INDEX_op_add:
5426c3b920b3SRichard Henderson     case INDEX_op_and:
542746f96bffSRichard Henderson     case INDEX_op_andc:
54285a5bb0a5SRichard Henderson     case INDEX_op_clz:
5429c96447d8SRichard Henderson     case INDEX_op_ctz:
5430b2c514f9SRichard Henderson     case INDEX_op_divs:
5431961b80aeSRichard Henderson     case INDEX_op_divu:
54325c0968a7SRichard Henderson     case INDEX_op_eqv:
5433d2c3ecadSRichard Henderson     case INDEX_op_mul:
5434c742824dSRichard Henderson     case INDEX_op_mulsh:
5435aa28c9efSRichard Henderson     case INDEX_op_muluh:
543659379a45SRichard Henderson     case INDEX_op_nand:
54373a8c4e9eSRichard Henderson     case INDEX_op_nor:
543849bd7514SRichard Henderson     case INDEX_op_or:
54396aba25ebSRichard Henderson     case INDEX_op_orc:
54409a6bc184SRichard Henderson     case INDEX_op_rems:
5441cd9acd20SRichard Henderson     case INDEX_op_remu:
5442005a87e1SRichard Henderson     case INDEX_op_rotl:
5443005a87e1SRichard Henderson     case INDEX_op_rotr:
54443949f365SRichard Henderson     case INDEX_op_sar:
54456ca59451SRichard Henderson     case INDEX_op_shl:
544674dbd36fSRichard Henderson     case INDEX_op_shr:
5447fffd3dc9SRichard Henderson     case INDEX_op_xor:
5448662cdbcfSRichard Henderson         {
5449662cdbcfSRichard Henderson             const TCGOutOpBinary *out =
5450662cdbcfSRichard Henderson                 container_of(all_outop[op->opc], TCGOutOpBinary, base);
5451662cdbcfSRichard Henderson 
5452662cdbcfSRichard Henderson             /* Constants should never appear in the first source operand. */
5453662cdbcfSRichard Henderson             tcg_debug_assert(!const_args[1]);
5454662cdbcfSRichard Henderson             if (const_args[2]) {
5455662cdbcfSRichard Henderson                 out->out_rri(s, type, new_args[0], new_args[1], new_args[2]);
5456662cdbcfSRichard Henderson             } else {
5457662cdbcfSRichard Henderson                 out->out_rrr(s, type, new_args[0], new_args[1], new_args[2]);
5458662cdbcfSRichard Henderson             }
5459662cdbcfSRichard Henderson         }
5460662cdbcfSRichard Henderson         break;
5461662cdbcfSRichard Henderson 
546260f34f55SRichard Henderson     case INDEX_op_sub:
54633f057e24SRichard Henderson         {
54643f057e24SRichard Henderson             const TCGOutOpSubtract *out = &outop_sub;
54653f057e24SRichard Henderson 
54663f057e24SRichard Henderson             /*
54673f057e24SRichard Henderson              * Constants should never appear in the second source operand.
54683f057e24SRichard Henderson              * These are folded to add with negative constant.
54693f057e24SRichard Henderson              */
54703f057e24SRichard Henderson             tcg_debug_assert(!const_args[2]);
54713f057e24SRichard Henderson             if (const_args[1]) {
54723f057e24SRichard Henderson                 out->out_rir(s, type, new_args[0], new_args[1], new_args[2]);
54733f057e24SRichard Henderson             } else {
54743f057e24SRichard Henderson                 out->out_rrr(s, type, new_args[0], new_args[1], new_args[2]);
54753f057e24SRichard Henderson             }
54763f057e24SRichard Henderson         }
54773f057e24SRichard Henderson         break;
54783f057e24SRichard Henderson 
54793ad5d4ccSRichard Henderson     case INDEX_op_bswap64:
5480613b571cSRichard Henderson         assert(TCG_TARGET_REG_BITS == 64);
5481613b571cSRichard Henderson         /* fall through */
548297218ae9SRichard Henderson     case INDEX_op_ctpop:
548369713587SRichard Henderson     case INDEX_op_neg:
54845c62d377SRichard Henderson     case INDEX_op_not:
5485e126a91cSRichard Henderson         {
5486e126a91cSRichard Henderson             const TCGOutOpUnary *out =
5487e126a91cSRichard Henderson                 container_of(all_outop[op->opc], TCGOutOpUnary, base);
5488e126a91cSRichard Henderson 
5489e126a91cSRichard Henderson             /* Constants should have been folded. */
5490e126a91cSRichard Henderson             tcg_debug_assert(!const_args[1]);
5491e126a91cSRichard Henderson             out->out_rr(s, type, new_args[0], new_args[1]);
5492e126a91cSRichard Henderson         }
5493e126a91cSRichard Henderson         break;
5494e126a91cSRichard Henderson 
54950dd07ee1SRichard Henderson     case INDEX_op_bswap16:
54967498d882SRichard Henderson     case INDEX_op_bswap32:
54975fa8e138SRichard Henderson         {
54985fa8e138SRichard Henderson             const TCGOutOpBswap *out =
54995fa8e138SRichard Henderson                 container_of(all_outop[op->opc], TCGOutOpBswap, base);
55005fa8e138SRichard Henderson 
55015fa8e138SRichard Henderson             tcg_debug_assert(!const_args[1]);
55025fa8e138SRichard Henderson             out->out_rr(s, type, new_args[0], new_args[1], new_args[2]);
55035fa8e138SRichard Henderson         }
55045fa8e138SRichard Henderson         break;
55055fa8e138SRichard Henderson 
5506ee1805b9SRichard Henderson     case INDEX_op_divs2:
55078109598bSRichard Henderson     case INDEX_op_divu2:
5508d6cad9c9SRichard Henderson         {
5509d6cad9c9SRichard Henderson             const TCGOutOpDivRem *out =
5510d6cad9c9SRichard Henderson                 container_of(all_outop[op->opc], TCGOutOpDivRem, base);
5511d6cad9c9SRichard Henderson 
5512d6cad9c9SRichard Henderson             /* Only used by x86 and s390x, which use matching constraints. */
5513d6cad9c9SRichard Henderson             tcg_debug_assert(new_args[0] == new_args[2]);
5514d6cad9c9SRichard Henderson             tcg_debug_assert(new_args[1] == new_args[3]);
5515d6cad9c9SRichard Henderson             tcg_debug_assert(!const_args[4]);
5516d6cad9c9SRichard Henderson             out->out_rr01r(s, type, new_args[0], new_args[1], new_args[4]);
5517d6cad9c9SRichard Henderson         }
5518d6cad9c9SRichard Henderson         break;
5519d6cad9c9SRichard Henderson 
5520*07d5d502SRichard Henderson     case INDEX_op_extract:
55215a4d034fSRichard Henderson         {
55225a4d034fSRichard Henderson             const TCGOutOpExtract *out =
55235a4d034fSRichard Henderson                 container_of(all_outop[op->opc], TCGOutOpExtract, base);
55245a4d034fSRichard Henderson 
55255a4d034fSRichard Henderson             tcg_debug_assert(!const_args[1]);
55265a4d034fSRichard Henderson             out->out_rr(s, type, new_args[0], new_args[1],
55275a4d034fSRichard Henderson                         new_args[2], new_args[3]);
55285a4d034fSRichard Henderson         }
55295a4d034fSRichard Henderson         break;
55305a4d034fSRichard Henderson 
5531bfe96480SRichard Henderson     case INDEX_op_muls2:
5532d776198cSRichard Henderson     case INDEX_op_mulu2:
55335641afdfSRichard Henderson         {
55345641afdfSRichard Henderson             const TCGOutOpMul2 *out =
55355641afdfSRichard Henderson                 container_of(all_outop[op->opc], TCGOutOpMul2, base);
55365641afdfSRichard Henderson 
55375641afdfSRichard Henderson             tcg_debug_assert(!const_args[2]);
55385641afdfSRichard Henderson             tcg_debug_assert(!const_args[3]);
55395641afdfSRichard Henderson             out->out_rrrr(s, type, new_args[0], new_args[1],
55405641afdfSRichard Henderson                           new_args[2], new_args[3]);
55415641afdfSRichard Henderson         }
55425641afdfSRichard Henderson         break;
55435641afdfSRichard Henderson 
5544b6d69fceSRichard Henderson     case INDEX_op_brcond:
554599ac4706SRichard Henderson         {
554699ac4706SRichard Henderson             const TCGOutOpBrcond *out = &outop_brcond;
554799ac4706SRichard Henderson             TCGCond cond = new_args[2];
554899ac4706SRichard Henderson             TCGLabel *label = arg_label(new_args[3]);
554999ac4706SRichard Henderson 
555099ac4706SRichard Henderson             tcg_debug_assert(!const_args[0]);
555199ac4706SRichard Henderson             if (const_args[1]) {
555299ac4706SRichard Henderson                 out->out_ri(s, type, cond, new_args[0], new_args[1], label);
555399ac4706SRichard Henderson             } else {
555499ac4706SRichard Henderson                 out->out_rr(s, type, cond, new_args[0], new_args[1], label);
555599ac4706SRichard Henderson             }
555699ac4706SRichard Henderson         }
555799ac4706SRichard Henderson         break;
555899ac4706SRichard Henderson 
5559ea46c4bcSRichard Henderson     case INDEX_op_movcond:
55601f406e46SRichard Henderson         {
55611f406e46SRichard Henderson             const TCGOutOpMovcond *out = &outop_movcond;
55621f406e46SRichard Henderson             TCGCond cond = new_args[5];
55631f406e46SRichard Henderson 
55641f406e46SRichard Henderson             tcg_debug_assert(!const_args[1]);
55651f406e46SRichard Henderson             out->out(s, type, cond, new_args[0],
55661f406e46SRichard Henderson                      new_args[1], new_args[2], const_args[2],
55671f406e46SRichard Henderson                      new_args[3], const_args[3],
55681f406e46SRichard Henderson                      new_args[4], const_args[4]);
55691f406e46SRichard Henderson         }
55701f406e46SRichard Henderson         break;
55711f406e46SRichard Henderson 
5572a363e1e1SRichard Henderson     case INDEX_op_setcond:
5573a363e1e1SRichard Henderson     case INDEX_op_negsetcond:
55745a7b38c8SRichard Henderson         {
55755a7b38c8SRichard Henderson             const TCGOutOpSetcond *out =
55765a7b38c8SRichard Henderson                 container_of(all_outop[op->opc], TCGOutOpSetcond, base);
55775a7b38c8SRichard Henderson             TCGCond cond = new_args[3];
55785a7b38c8SRichard Henderson 
55795a7b38c8SRichard Henderson             tcg_debug_assert(!const_args[1]);
55805a7b38c8SRichard Henderson             if (const_args[2]) {
55815a7b38c8SRichard Henderson                 out->out_rri(s, type, cond,
55825a7b38c8SRichard Henderson                              new_args[0], new_args[1], new_args[2]);
55835a7b38c8SRichard Henderson             } else {
55845a7b38c8SRichard Henderson                 out->out_rrr(s, type, cond,
55855a7b38c8SRichard Henderson                              new_args[0], new_args[1], new_args[2]);
55865a7b38c8SRichard Henderson             }
55875a7b38c8SRichard Henderson         }
55885a7b38c8SRichard Henderson         break;
55895641afdfSRichard Henderson 
5590f408df58SRichard Henderson #if TCG_TARGET_REG_BITS == 32
5591f408df58SRichard Henderson     case INDEX_op_brcond2_i32:
5592f408df58SRichard Henderson         {
5593f408df58SRichard Henderson             const TCGOutOpBrcond2 *out = &outop_brcond2;
5594f408df58SRichard Henderson             TCGCond cond = new_args[4];
5595f408df58SRichard Henderson             TCGLabel *label = arg_label(new_args[5]);
5596f408df58SRichard Henderson 
5597f408df58SRichard Henderson             tcg_debug_assert(!const_args[0]);
5598f408df58SRichard Henderson             tcg_debug_assert(!const_args[1]);
5599f408df58SRichard Henderson             out->out(s, cond, new_args[0], new_args[1],
5600f408df58SRichard Henderson                      new_args[2], const_args[2],
5601f408df58SRichard Henderson                      new_args[3], const_args[3], label);
5602f408df58SRichard Henderson         }
5603f408df58SRichard Henderson         break;
5604e579c717SRichard Henderson     case INDEX_op_setcond2_i32:
5605e579c717SRichard Henderson         {
5606e579c717SRichard Henderson             const TCGOutOpSetcond2 *out = &outop_setcond2;
5607e579c717SRichard Henderson             TCGCond cond = new_args[5];
5608e579c717SRichard Henderson 
5609e579c717SRichard Henderson             tcg_debug_assert(!const_args[1]);
5610e579c717SRichard Henderson             tcg_debug_assert(!const_args[2]);
5611e579c717SRichard Henderson             out->out(s, cond, new_args[0], new_args[1], new_args[2],
5612e579c717SRichard Henderson                      new_args[3], const_args[3], new_args[4], const_args[4]);
5613e579c717SRichard Henderson         }
5614e579c717SRichard Henderson         break;
5615f408df58SRichard Henderson #else
5616f408df58SRichard Henderson     case INDEX_op_brcond2_i32:
5617e579c717SRichard Henderson     case INDEX_op_setcond2_i32:
5618f408df58SRichard Henderson         g_assert_not_reached();
5619f408df58SRichard Henderson #endif
5620f408df58SRichard Henderson 
5621678155b2SRichard Henderson     default:
5622d2fd745fSRichard Henderson         if (def->flags & TCG_OPF_VECTOR) {
5623662cdbcfSRichard Henderson             tcg_out_vec_op(s, op->opc, type - TCG_TYPE_V64,
56244d872218SRichard Henderson                            TCGOP_VECE(op), new_args, const_args);
5625d2fd745fSRichard Henderson         } else {
5626662cdbcfSRichard Henderson             tcg_out_op(s, op->opc, type, new_args, const_args);
5627d2fd745fSRichard Henderson         }
5628678155b2SRichard Henderson         break;
5629678155b2SRichard Henderson     }
5630c896fe29Sbellard 
5631c896fe29Sbellard     /* move the outputs in the correct register if needed */
5632c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
563343439139SRichard Henderson         ts = arg_temp(op->args[i]);
5634d63e3b6eSRichard Henderson 
5635d63e3b6eSRichard Henderson         /* ENV should not be modified.  */
5636e01fa97dSRichard Henderson         tcg_debug_assert(!temp_readonly(ts));
5637d63e3b6eSRichard Henderson 
5638ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
563998b4e186SRichard Henderson             temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i));
564059d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
5641f8bf00f1SRichard Henderson             temp_dead(s, ts);
5642ec7a869dSAurelien Jarno         }
5643c896fe29Sbellard     }
5644c896fe29Sbellard }
5645c896fe29Sbellard 
5646efe86b21SRichard Henderson static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op)
5647efe86b21SRichard Henderson {
5648efe86b21SRichard Henderson     const TCGLifeData arg_life = op->life;
5649efe86b21SRichard Henderson     TCGTemp *ots, *itsl, *itsh;
56504d872218SRichard Henderson     TCGType vtype = TCGOP_TYPE(op);
5651efe86b21SRichard Henderson 
5652efe86b21SRichard Henderson     /* This opcode is only valid for 32-bit hosts, for 64-bit elements. */
5653efe86b21SRichard Henderson     tcg_debug_assert(TCG_TARGET_REG_BITS == 32);
5654efe86b21SRichard Henderson     tcg_debug_assert(TCGOP_VECE(op) == MO_64);
5655efe86b21SRichard Henderson 
5656efe86b21SRichard Henderson     ots = arg_temp(op->args[0]);
5657efe86b21SRichard Henderson     itsl = arg_temp(op->args[1]);
5658efe86b21SRichard Henderson     itsh = arg_temp(op->args[2]);
5659efe86b21SRichard Henderson 
5660efe86b21SRichard Henderson     /* ENV should not be modified.  */
5661efe86b21SRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
5662efe86b21SRichard Henderson 
5663efe86b21SRichard Henderson     /* Allocate the output register now.  */
5664efe86b21SRichard Henderson     if (ots->val_type != TEMP_VAL_REG) {
5665efe86b21SRichard Henderson         TCGRegSet allocated_regs = s->reserved_regs;
5666501fb3daSRichard Henderson         TCGRegSet dup_out_regs = opcode_args_ct(op)[0].regs;
5667098859f1SRichard Henderson         TCGReg oreg;
5668efe86b21SRichard Henderson 
5669efe86b21SRichard Henderson         /* Make sure to not spill the input registers. */
5670efe86b21SRichard Henderson         if (!IS_DEAD_ARG(1) && itsl->val_type == TEMP_VAL_REG) {
5671efe86b21SRichard Henderson             tcg_regset_set_reg(allocated_regs, itsl->reg);
5672efe86b21SRichard Henderson         }
5673efe86b21SRichard Henderson         if (!IS_DEAD_ARG(2) && itsh->val_type == TEMP_VAL_REG) {
5674efe86b21SRichard Henderson             tcg_regset_set_reg(allocated_regs, itsh->reg);
5675efe86b21SRichard Henderson         }
5676efe86b21SRichard Henderson 
5677098859f1SRichard Henderson         oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
567831fd884bSRichard Henderson                              output_pref(op, 0), ots->indirect_base);
5679098859f1SRichard Henderson         set_temp_val_reg(s, ots, oreg);
5680efe86b21SRichard Henderson     }
5681efe86b21SRichard Henderson 
5682efe86b21SRichard Henderson     /* Promote dup2 of immediates to dupi_vec. */
5683efe86b21SRichard Henderson     if (itsl->val_type == TEMP_VAL_CONST && itsh->val_type == TEMP_VAL_CONST) {
5684efe86b21SRichard Henderson         uint64_t val = deposit64(itsl->val, 32, 32, itsh->val);
5685efe86b21SRichard Henderson         MemOp vece = MO_64;
5686efe86b21SRichard Henderson 
5687efe86b21SRichard Henderson         if (val == dup_const(MO_8, val)) {
5688efe86b21SRichard Henderson             vece = MO_8;
5689efe86b21SRichard Henderson         } else if (val == dup_const(MO_16, val)) {
5690efe86b21SRichard Henderson             vece = MO_16;
5691efe86b21SRichard Henderson         } else if (val == dup_const(MO_32, val)) {
5692efe86b21SRichard Henderson             vece = MO_32;
5693efe86b21SRichard Henderson         }
5694efe86b21SRichard Henderson 
5695efe86b21SRichard Henderson         tcg_out_dupi_vec(s, vtype, vece, ots->reg, val);
5696efe86b21SRichard Henderson         goto done;
5697efe86b21SRichard Henderson     }
5698efe86b21SRichard Henderson 
5699efe86b21SRichard Henderson     /* If the two inputs form one 64-bit value, try dupm_vec. */
5700aef85402SRichard Henderson     if (itsl->temp_subindex == HOST_BIG_ENDIAN &&
5701aef85402SRichard Henderson         itsh->temp_subindex == !HOST_BIG_ENDIAN &&
5702aef85402SRichard Henderson         itsl == itsh + (HOST_BIG_ENDIAN ? 1 : -1)) {
5703aef85402SRichard Henderson         TCGTemp *its = itsl - HOST_BIG_ENDIAN;
5704aef85402SRichard Henderson 
5705aef85402SRichard Henderson         temp_sync(s, its + 0, s->reserved_regs, 0, 0);
5706aef85402SRichard Henderson         temp_sync(s, its + 1, s->reserved_regs, 0, 0);
5707aef85402SRichard Henderson 
5708efe86b21SRichard Henderson         if (tcg_out_dupm_vec(s, vtype, MO_64, ots->reg,
5709efe86b21SRichard Henderson                              its->mem_base->reg, its->mem_offset)) {
5710efe86b21SRichard Henderson             goto done;
5711efe86b21SRichard Henderson         }
5712efe86b21SRichard Henderson     }
5713efe86b21SRichard Henderson 
5714efe86b21SRichard Henderson     /* Fall back to generic expansion. */
5715efe86b21SRichard Henderson     return false;
5716efe86b21SRichard Henderson 
5717efe86b21SRichard Henderson  done:
571836f5539cSRichard Henderson     ots->mem_coherent = 0;
5719efe86b21SRichard Henderson     if (IS_DEAD_ARG(1)) {
5720efe86b21SRichard Henderson         temp_dead(s, itsl);
5721efe86b21SRichard Henderson     }
5722efe86b21SRichard Henderson     if (IS_DEAD_ARG(2)) {
5723efe86b21SRichard Henderson         temp_dead(s, itsh);
5724efe86b21SRichard Henderson     }
5725efe86b21SRichard Henderson     if (NEED_SYNC_ARG(0)) {
5726efe86b21SRichard Henderson         temp_sync(s, ots, s->reserved_regs, 0, IS_DEAD_ARG(0));
5727efe86b21SRichard Henderson     } else if (IS_DEAD_ARG(0)) {
5728efe86b21SRichard Henderson         temp_dead(s, ots);
5729efe86b21SRichard Henderson     }
5730efe86b21SRichard Henderson     return true;
5731efe86b21SRichard Henderson }
5732efe86b21SRichard Henderson 
573339004a71SRichard Henderson static void load_arg_reg(TCGContext *s, TCGReg reg, TCGTemp *ts,
573439004a71SRichard Henderson                          TCGRegSet allocated_regs)
5735c896fe29Sbellard {
5736c896fe29Sbellard     if (ts->val_type == TEMP_VAL_REG) {
5737c896fe29Sbellard         if (ts->reg != reg) {
57384250da10SRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
573978113e83SRichard Henderson             if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
5740240c08d0SRichard Henderson                 /*
5741240c08d0SRichard Henderson                  * Cross register class move not supported.  Sync the
5742240c08d0SRichard Henderson                  * temp back to its slot and load from there.
5743240c08d0SRichard Henderson                  */
5744240c08d0SRichard Henderson                 temp_sync(s, ts, allocated_regs, 0, 0);
5745240c08d0SRichard Henderson                 tcg_out_ld(s, ts->type, reg,
5746240c08d0SRichard Henderson                            ts->mem_base->reg, ts->mem_offset);
574778113e83SRichard Henderson             }
5748c896fe29Sbellard         }
5749c896fe29Sbellard     } else {
5750ccb1bb66SRichard Henderson         TCGRegSet arg_set = 0;
575140ae5c62SRichard Henderson 
57524250da10SRichard Henderson         tcg_reg_free(s, reg, allocated_regs);
575340ae5c62SRichard Henderson         tcg_regset_set_reg(arg_set, reg);
5754b722452aSRichard Henderson         temp_load(s, ts, arg_set, allocated_regs, 0);
5755c896fe29Sbellard     }
575639004a71SRichard Henderson }
575740ae5c62SRichard Henderson 
5758d78e4a4fSRichard Henderson static void load_arg_stk(TCGContext *s, unsigned arg_slot, TCGTemp *ts,
575939004a71SRichard Henderson                          TCGRegSet allocated_regs)
576039004a71SRichard Henderson {
576139004a71SRichard Henderson     /*
576239004a71SRichard Henderson      * When the destination is on the stack, load up the temp and store.
576339004a71SRichard Henderson      * If there are many call-saved registers, the temp might live to
576439004a71SRichard Henderson      * see another use; otherwise it'll be discarded.
576539004a71SRichard Henderson      */
576639004a71SRichard Henderson     temp_load(s, ts, tcg_target_available_regs[ts->type], allocated_regs, 0);
576739004a71SRichard Henderson     tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK,
5768d78e4a4fSRichard Henderson                arg_slot_stk_ofs(arg_slot));
576939004a71SRichard Henderson }
577039004a71SRichard Henderson 
577139004a71SRichard Henderson static void load_arg_normal(TCGContext *s, const TCGCallArgumentLoc *l,
577239004a71SRichard Henderson                             TCGTemp *ts, TCGRegSet *allocated_regs)
577339004a71SRichard Henderson {
5774338b61e9SRichard Henderson     if (arg_slot_reg_p(l->arg_slot)) {
577539004a71SRichard Henderson         TCGReg reg = tcg_target_call_iarg_regs[l->arg_slot];
577639004a71SRichard Henderson         load_arg_reg(s, reg, ts, *allocated_regs);
577739004a71SRichard Henderson         tcg_regset_set_reg(*allocated_regs, reg);
577839004a71SRichard Henderson     } else {
5779d78e4a4fSRichard Henderson         load_arg_stk(s, l->arg_slot, ts, *allocated_regs);
5780c896fe29Sbellard     }
578139cf05d3Sbellard }
5782c896fe29Sbellard 
5783d78e4a4fSRichard Henderson static void load_arg_ref(TCGContext *s, unsigned arg_slot, TCGReg ref_base,
5784313bdea8SRichard Henderson                          intptr_t ref_off, TCGRegSet *allocated_regs)
5785313bdea8SRichard Henderson {
5786313bdea8SRichard Henderson     TCGReg reg;
5787313bdea8SRichard Henderson 
5788d78e4a4fSRichard Henderson     if (arg_slot_reg_p(arg_slot)) {
5789313bdea8SRichard Henderson         reg = tcg_target_call_iarg_regs[arg_slot];
5790313bdea8SRichard Henderson         tcg_reg_free(s, reg, *allocated_regs);
5791313bdea8SRichard Henderson         tcg_out_addi_ptr(s, reg, ref_base, ref_off);
5792313bdea8SRichard Henderson         tcg_regset_set_reg(*allocated_regs, reg);
5793313bdea8SRichard Henderson     } else {
5794313bdea8SRichard Henderson         reg = tcg_reg_alloc(s, tcg_target_available_regs[TCG_TYPE_PTR],
5795313bdea8SRichard Henderson                             *allocated_regs, 0, false);
5796313bdea8SRichard Henderson         tcg_out_addi_ptr(s, reg, ref_base, ref_off);
5797313bdea8SRichard Henderson         tcg_out_st(s, TCG_TYPE_PTR, reg, TCG_REG_CALL_STACK,
5798d78e4a4fSRichard Henderson                    arg_slot_stk_ofs(arg_slot));
5799313bdea8SRichard Henderson     }
5800313bdea8SRichard Henderson }
5801313bdea8SRichard Henderson 
580239004a71SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op)
580339004a71SRichard Henderson {
580439004a71SRichard Henderson     const int nb_oargs = TCGOP_CALLO(op);
580539004a71SRichard Henderson     const int nb_iargs = TCGOP_CALLI(op);
580639004a71SRichard Henderson     const TCGLifeData arg_life = op->life;
580739004a71SRichard Henderson     const TCGHelperInfo *info = tcg_call_info(op);
580839004a71SRichard Henderson     TCGRegSet allocated_regs = s->reserved_regs;
580939004a71SRichard Henderson     int i;
581039004a71SRichard Henderson 
581139004a71SRichard Henderson     /*
581239004a71SRichard Henderson      * Move inputs into place in reverse order,
581339004a71SRichard Henderson      * so that we place stacked arguments first.
581439004a71SRichard Henderson      */
581539004a71SRichard Henderson     for (i = nb_iargs - 1; i >= 0; --i) {
581639004a71SRichard Henderson         const TCGCallArgumentLoc *loc = &info->in[i];
581739004a71SRichard Henderson         TCGTemp *ts = arg_temp(op->args[nb_oargs + i]);
581839004a71SRichard Henderson 
581939004a71SRichard Henderson         switch (loc->kind) {
582039004a71SRichard Henderson         case TCG_CALL_ARG_NORMAL:
582139004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_U:
582239004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_S:
582339004a71SRichard Henderson             load_arg_normal(s, loc, ts, &allocated_regs);
582439004a71SRichard Henderson             break;
5825313bdea8SRichard Henderson         case TCG_CALL_ARG_BY_REF:
5826313bdea8SRichard Henderson             load_arg_stk(s, loc->ref_slot, ts, allocated_regs);
5827313bdea8SRichard Henderson             load_arg_ref(s, loc->arg_slot, TCG_REG_CALL_STACK,
5828d78e4a4fSRichard Henderson                          arg_slot_stk_ofs(loc->ref_slot),
5829313bdea8SRichard Henderson                          &allocated_regs);
5830313bdea8SRichard Henderson             break;
5831313bdea8SRichard Henderson         case TCG_CALL_ARG_BY_REF_N:
5832313bdea8SRichard Henderson             load_arg_stk(s, loc->ref_slot, ts, allocated_regs);
5833313bdea8SRichard Henderson             break;
583439004a71SRichard Henderson         default:
583539004a71SRichard Henderson             g_assert_not_reached();
583639004a71SRichard Henderson         }
583739004a71SRichard Henderson     }
583839004a71SRichard Henderson 
583939004a71SRichard Henderson     /* Mark dead temporaries and free the associated registers.  */
5840866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
5841866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
584243439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
5843c896fe29Sbellard         }
5844c896fe29Sbellard     }
5845c896fe29Sbellard 
584639004a71SRichard Henderson     /* Clobber call registers.  */
5847c8074023SRichard Henderson     for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
5848c8074023SRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
5849b3915dbbSRichard Henderson             tcg_reg_free(s, i, allocated_regs);
5850c896fe29Sbellard         }
5851c896fe29Sbellard     }
5852c896fe29Sbellard 
585339004a71SRichard Henderson     /*
585439004a71SRichard Henderson      * Save globals if they might be written by the helper,
585539004a71SRichard Henderson      * sync them if they might be read.
585639004a71SRichard Henderson      */
585739004a71SRichard Henderson     if (info->flags & TCG_CALL_NO_READ_GLOBALS) {
585878505279SAurelien Jarno         /* Nothing to do */
585939004a71SRichard Henderson     } else if (info->flags & TCG_CALL_NO_WRITE_GLOBALS) {
586078505279SAurelien Jarno         sync_globals(s, allocated_regs);
586178505279SAurelien Jarno     } else {
5862e8996ee0Sbellard         save_globals(s, allocated_regs);
5863b9c18f56Saurel32     }
5864c896fe29Sbellard 
5865313bdea8SRichard Henderson     /*
5866313bdea8SRichard Henderson      * If the ABI passes a pointer to the returned struct as the first
5867313bdea8SRichard Henderson      * argument, load that now.  Pass a pointer to the output home slot.
5868313bdea8SRichard Henderson      */
5869313bdea8SRichard Henderson     if (info->out_kind == TCG_CALL_RET_BY_REF) {
5870313bdea8SRichard Henderson         TCGTemp *ts = arg_temp(op->args[0]);
5871313bdea8SRichard Henderson 
5872313bdea8SRichard Henderson         if (!ts->mem_allocated) {
5873313bdea8SRichard Henderson             temp_allocate_frame(s, ts);
5874313bdea8SRichard Henderson         }
5875313bdea8SRichard Henderson         load_arg_ref(s, 0, ts->mem_base->reg, ts->mem_offset, &allocated_regs);
5876313bdea8SRichard Henderson     }
5877313bdea8SRichard Henderson 
5878cee44b03SRichard Henderson     tcg_out_call(s, tcg_call_func(op), info);
5879c896fe29Sbellard 
588039004a71SRichard Henderson     /* Assign output registers and emit moves if needed.  */
588139004a71SRichard Henderson     switch (info->out_kind) {
588239004a71SRichard Henderson     case TCG_CALL_RET_NORMAL:
5883c896fe29Sbellard         for (i = 0; i < nb_oargs; i++) {
588439004a71SRichard Henderson             TCGTemp *ts = arg_temp(op->args[i]);
58855e3d0c19SRichard Henderson             TCGReg reg = tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, i);
5886d63e3b6eSRichard Henderson 
5887d63e3b6eSRichard Henderson             /* ENV should not be modified.  */
5888e01fa97dSRichard Henderson             tcg_debug_assert(!temp_readonly(ts));
5889d63e3b6eSRichard Henderson 
5890098859f1SRichard Henderson             set_temp_val_reg(s, ts, reg);
5891c896fe29Sbellard             ts->mem_coherent = 0;
589239004a71SRichard Henderson         }
589339004a71SRichard Henderson         break;
5894313bdea8SRichard Henderson 
5895c6556aa0SRichard Henderson     case TCG_CALL_RET_BY_VEC:
5896c6556aa0SRichard Henderson         {
5897c6556aa0SRichard Henderson             TCGTemp *ts = arg_temp(op->args[0]);
5898c6556aa0SRichard Henderson 
5899c6556aa0SRichard Henderson             tcg_debug_assert(ts->base_type == TCG_TYPE_I128);
5900c6556aa0SRichard Henderson             tcg_debug_assert(ts->temp_subindex == 0);
5901c6556aa0SRichard Henderson             if (!ts->mem_allocated) {
5902c6556aa0SRichard Henderson                 temp_allocate_frame(s, ts);
5903c6556aa0SRichard Henderson             }
5904c6556aa0SRichard Henderson             tcg_out_st(s, TCG_TYPE_V128,
5905c6556aa0SRichard Henderson                        tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0),
5906c6556aa0SRichard Henderson                        ts->mem_base->reg, ts->mem_offset);
5907c6556aa0SRichard Henderson         }
5908c6556aa0SRichard Henderson         /* fall through to mark all parts in memory */
5909c6556aa0SRichard Henderson 
5910313bdea8SRichard Henderson     case TCG_CALL_RET_BY_REF:
5911313bdea8SRichard Henderson         /* The callee has performed a write through the reference. */
5912313bdea8SRichard Henderson         for (i = 0; i < nb_oargs; i++) {
5913313bdea8SRichard Henderson             TCGTemp *ts = arg_temp(op->args[i]);
5914313bdea8SRichard Henderson             ts->val_type = TEMP_VAL_MEM;
5915313bdea8SRichard Henderson         }
5916313bdea8SRichard Henderson         break;
5917313bdea8SRichard Henderson 
591839004a71SRichard Henderson     default:
591939004a71SRichard Henderson         g_assert_not_reached();
592039004a71SRichard Henderson     }
592139004a71SRichard Henderson 
592239004a71SRichard Henderson     /* Flush or discard output registers as needed. */
592339004a71SRichard Henderson     for (i = 0; i < nb_oargs; i++) {
592439004a71SRichard Henderson         TCGTemp *ts = arg_temp(op->args[i]);
5925ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
592639004a71SRichard Henderson             temp_sync(s, ts, s->reserved_regs, 0, IS_DEAD_ARG(i));
592759d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
5928f8bf00f1SRichard Henderson             temp_dead(s, ts);
5929c896fe29Sbellard         }
5930c896fe29Sbellard     }
59318c11ad25SAurelien Jarno }
5932c896fe29Sbellard 
5933e63b8a29SRichard Henderson /**
5934e63b8a29SRichard Henderson  * atom_and_align_for_opc:
5935e63b8a29SRichard Henderson  * @s: tcg context
5936e63b8a29SRichard Henderson  * @opc: memory operation code
5937e63b8a29SRichard Henderson  * @host_atom: MO_ATOM_{IFALIGN,WITHIN16,SUBALIGN} for host operations
5938e63b8a29SRichard Henderson  * @allow_two_ops: true if we are prepared to issue two operations
5939e63b8a29SRichard Henderson  *
5940e63b8a29SRichard Henderson  * Return the alignment and atomicity to use for the inline fast path
5941e63b8a29SRichard Henderson  * for the given memory operation.  The alignment may be larger than
5942e63b8a29SRichard Henderson  * that specified in @opc, and the correct alignment will be diagnosed
5943e63b8a29SRichard Henderson  * by the slow path helper.
5944e63b8a29SRichard Henderson  *
5945e63b8a29SRichard Henderson  * If @allow_two_ops, the host is prepared to test for 2x alignment,
5946e63b8a29SRichard Henderson  * and issue two loads or stores for subalignment.
5947e63b8a29SRichard Henderson  */
5948e63b8a29SRichard Henderson static TCGAtomAlign atom_and_align_for_opc(TCGContext *s, MemOp opc,
5949e63b8a29SRichard Henderson                                            MemOp host_atom, bool allow_two_ops)
5950e63b8a29SRichard Henderson {
5951c5809eeeSRichard Henderson     MemOp align = memop_alignment_bits(opc);
5952e63b8a29SRichard Henderson     MemOp size = opc & MO_SIZE;
5953e63b8a29SRichard Henderson     MemOp half = size ? size - 1 : 0;
5954cbb14556SRichard Henderson     MemOp atom = opc & MO_ATOM_MASK;
5955e63b8a29SRichard Henderson     MemOp atmax;
5956e63b8a29SRichard Henderson 
5957e63b8a29SRichard Henderson     switch (atom) {
5958e63b8a29SRichard Henderson     case MO_ATOM_NONE:
5959e63b8a29SRichard Henderson         /* The operation requires no specific atomicity. */
5960e63b8a29SRichard Henderson         atmax = MO_8;
5961e63b8a29SRichard Henderson         break;
5962e63b8a29SRichard Henderson 
5963e63b8a29SRichard Henderson     case MO_ATOM_IFALIGN:
5964e63b8a29SRichard Henderson         atmax = size;
5965e63b8a29SRichard Henderson         break;
5966e63b8a29SRichard Henderson 
5967e63b8a29SRichard Henderson     case MO_ATOM_IFALIGN_PAIR:
5968e63b8a29SRichard Henderson         atmax = half;
5969e63b8a29SRichard Henderson         break;
5970e63b8a29SRichard Henderson 
5971e63b8a29SRichard Henderson     case MO_ATOM_WITHIN16:
5972e63b8a29SRichard Henderson         atmax = size;
5973e63b8a29SRichard Henderson         if (size == MO_128) {
5974e63b8a29SRichard Henderson             /* Misalignment implies !within16, and therefore no atomicity. */
5975e63b8a29SRichard Henderson         } else if (host_atom != MO_ATOM_WITHIN16) {
5976e63b8a29SRichard Henderson             /* The host does not implement within16, so require alignment. */
5977e63b8a29SRichard Henderson             align = MAX(align, size);
5978e63b8a29SRichard Henderson         }
5979e63b8a29SRichard Henderson         break;
5980e63b8a29SRichard Henderson 
5981e63b8a29SRichard Henderson     case MO_ATOM_WITHIN16_PAIR:
5982e63b8a29SRichard Henderson         atmax = size;
5983e63b8a29SRichard Henderson         /*
5984e63b8a29SRichard Henderson          * Misalignment implies !within16, and therefore half atomicity.
5985e63b8a29SRichard Henderson          * Any host prepared for two operations can implement this with
5986e63b8a29SRichard Henderson          * half alignment.
5987e63b8a29SRichard Henderson          */
5988e63b8a29SRichard Henderson         if (host_atom != MO_ATOM_WITHIN16 && allow_two_ops) {
5989e63b8a29SRichard Henderson             align = MAX(align, half);
5990e63b8a29SRichard Henderson         }
5991e63b8a29SRichard Henderson         break;
5992e63b8a29SRichard Henderson 
5993e63b8a29SRichard Henderson     case MO_ATOM_SUBALIGN:
5994e63b8a29SRichard Henderson         atmax = size;
5995e63b8a29SRichard Henderson         if (host_atom != MO_ATOM_SUBALIGN) {
5996e63b8a29SRichard Henderson             /* If unaligned but not odd, there are subobjects up to half. */
5997e63b8a29SRichard Henderson             if (allow_two_ops) {
5998e63b8a29SRichard Henderson                 align = MAX(align, half);
5999e63b8a29SRichard Henderson             } else {
6000e63b8a29SRichard Henderson                 align = MAX(align, size);
6001e63b8a29SRichard Henderson             }
6002e63b8a29SRichard Henderson         }
6003e63b8a29SRichard Henderson         break;
6004e63b8a29SRichard Henderson 
6005e63b8a29SRichard Henderson     default:
6006e63b8a29SRichard Henderson         g_assert_not_reached();
6007e63b8a29SRichard Henderson     }
6008e63b8a29SRichard Henderson 
6009e63b8a29SRichard Henderson     return (TCGAtomAlign){ .atom = atmax, .align = align };
6010e63b8a29SRichard Henderson }
6011e63b8a29SRichard Henderson 
60128429a1caSRichard Henderson /*
60138429a1caSRichard Henderson  * Similarly for qemu_ld/st slow path helpers.
60148429a1caSRichard Henderson  * We must re-implement tcg_gen_callN and tcg_reg_alloc_call simultaneously,
60158429a1caSRichard Henderson  * using only the provided backend tcg_out_* functions.
60168429a1caSRichard Henderson  */
60178429a1caSRichard Henderson 
60188429a1caSRichard Henderson static int tcg_out_helper_stk_ofs(TCGType type, unsigned slot)
60198429a1caSRichard Henderson {
60208429a1caSRichard Henderson     int ofs = arg_slot_stk_ofs(slot);
60218429a1caSRichard Henderson 
60228429a1caSRichard Henderson     /*
60238429a1caSRichard Henderson      * Each stack slot is TCG_TARGET_LONG_BITS.  If the host does not
60248429a1caSRichard Henderson      * require extension to uint64_t, adjust the address for uint32_t.
60258429a1caSRichard Henderson      */
60268429a1caSRichard Henderson     if (HOST_BIG_ENDIAN &&
60278429a1caSRichard Henderson         TCG_TARGET_REG_BITS == 64 &&
60288429a1caSRichard Henderson         type == TCG_TYPE_I32) {
60298429a1caSRichard Henderson         ofs += 4;
60308429a1caSRichard Henderson     }
60318429a1caSRichard Henderson     return ofs;
60328429a1caSRichard Henderson }
60338429a1caSRichard Henderson 
60348d314041SRichard Henderson static void tcg_out_helper_load_slots(TCGContext *s,
60358429a1caSRichard Henderson                                       unsigned nmov, TCGMovExtend *mov,
60362462e30eSRichard Henderson                                       const TCGLdstHelperParam *parm)
60378429a1caSRichard Henderson {
60388d314041SRichard Henderson     unsigned i;
60392462e30eSRichard Henderson     TCGReg dst3;
60402462e30eSRichard Henderson 
60418d314041SRichard Henderson     /*
60428d314041SRichard Henderson      * Start from the end, storing to the stack first.
60438d314041SRichard Henderson      * This frees those registers, so we need not consider overlap.
60448d314041SRichard Henderson      */
60458d314041SRichard Henderson     for (i = nmov; i-- > 0; ) {
60468d314041SRichard Henderson         unsigned slot = mov[i].dst;
60478d314041SRichard Henderson 
60488d314041SRichard Henderson         if (arg_slot_reg_p(slot)) {
60498d314041SRichard Henderson             goto found_reg;
60508d314041SRichard Henderson         }
60518d314041SRichard Henderson 
60528d314041SRichard Henderson         TCGReg src = mov[i].src;
60538d314041SRichard Henderson         TCGType dst_type = mov[i].dst_type;
60548d314041SRichard Henderson         MemOp dst_mo = dst_type == TCG_TYPE_I32 ? MO_32 : MO_64;
60558d314041SRichard Henderson 
60568d314041SRichard Henderson         /* The argument is going onto the stack; extend into scratch. */
60578d314041SRichard Henderson         if ((mov[i].src_ext & MO_SIZE) != dst_mo) {
60588d314041SRichard Henderson             tcg_debug_assert(parm->ntmp != 0);
60598d314041SRichard Henderson             mov[i].dst = src = parm->tmp[0];
60608d314041SRichard Henderson             tcg_out_movext1(s, &mov[i]);
60618d314041SRichard Henderson         }
60628d314041SRichard Henderson 
60638d314041SRichard Henderson         tcg_out_st(s, dst_type, src, TCG_REG_CALL_STACK,
60648d314041SRichard Henderson                    tcg_out_helper_stk_ofs(dst_type, slot));
60658d314041SRichard Henderson     }
60668d314041SRichard Henderson     return;
60678d314041SRichard Henderson 
60688d314041SRichard Henderson  found_reg:
60698d314041SRichard Henderson     /*
60708d314041SRichard Henderson      * The remaining arguments are in registers.
60718d314041SRichard Henderson      * Convert slot numbers to argument registers.
60728d314041SRichard Henderson      */
60738d314041SRichard Henderson     nmov = i + 1;
60748d314041SRichard Henderson     for (i = 0; i < nmov; ++i) {
60758d314041SRichard Henderson         mov[i].dst = tcg_target_call_iarg_regs[mov[i].dst];
60768d314041SRichard Henderson     }
60778d314041SRichard Henderson 
60788429a1caSRichard Henderson     switch (nmov) {
60792462e30eSRichard Henderson     case 4:
60808429a1caSRichard Henderson         /* The backend must have provided enough temps for the worst case. */
60812462e30eSRichard Henderson         tcg_debug_assert(parm->ntmp >= 2);
60828429a1caSRichard Henderson 
60832462e30eSRichard Henderson         dst3 = mov[3].dst;
60842462e30eSRichard Henderson         for (unsigned j = 0; j < 3; ++j) {
60852462e30eSRichard Henderson             if (dst3 == mov[j].src) {
60868429a1caSRichard Henderson                 /*
60872462e30eSRichard Henderson                  * Conflict. Copy the source to a temporary, perform the
60882462e30eSRichard Henderson                  * remaining moves, then the extension from our scratch
60892462e30eSRichard Henderson                  * on the way out.
60908429a1caSRichard Henderson                  */
60912462e30eSRichard Henderson                 TCGReg scratch = parm->tmp[1];
60928429a1caSRichard Henderson 
60932462e30eSRichard Henderson                 tcg_out_mov(s, mov[3].src_type, scratch, mov[3].src);
60942462e30eSRichard Henderson                 tcg_out_movext3(s, mov, mov + 1, mov + 2, parm->tmp[0]);
60952462e30eSRichard Henderson                 tcg_out_movext1_new_src(s, &mov[3], scratch);
60962462e30eSRichard Henderson                 break;
60978429a1caSRichard Henderson             }
60988429a1caSRichard Henderson         }
60998429a1caSRichard Henderson 
61008429a1caSRichard Henderson         /* No conflicts: perform this move and continue. */
61012462e30eSRichard Henderson         tcg_out_movext1(s, &mov[3]);
61022462e30eSRichard Henderson         /* fall through */
61038429a1caSRichard Henderson 
61042462e30eSRichard Henderson     case 3:
61052462e30eSRichard Henderson         tcg_out_movext3(s, mov, mov + 1, mov + 2,
61062462e30eSRichard Henderson                         parm->ntmp ? parm->tmp[0] : -1);
61072462e30eSRichard Henderson         break;
61088429a1caSRichard Henderson     case 2:
61092462e30eSRichard Henderson         tcg_out_movext2(s, mov, mov + 1,
61102462e30eSRichard Henderson                         parm->ntmp ? parm->tmp[0] : -1);
61112462e30eSRichard Henderson         break;
61128429a1caSRichard Henderson     case 1:
61138429a1caSRichard Henderson         tcg_out_movext1(s, mov);
61142462e30eSRichard Henderson         break;
61152462e30eSRichard Henderson     default:
61168429a1caSRichard Henderson         g_assert_not_reached();
61178429a1caSRichard Henderson     }
61188429a1caSRichard Henderson }
61198429a1caSRichard Henderson 
61208429a1caSRichard Henderson static void tcg_out_helper_load_imm(TCGContext *s, unsigned slot,
61218429a1caSRichard Henderson                                     TCGType type, tcg_target_long imm,
61228429a1caSRichard Henderson                                     const TCGLdstHelperParam *parm)
61238429a1caSRichard Henderson {
61248429a1caSRichard Henderson     if (arg_slot_reg_p(slot)) {
61258429a1caSRichard Henderson         tcg_out_movi(s, type, tcg_target_call_iarg_regs[slot], imm);
61268429a1caSRichard Henderson     } else {
61278429a1caSRichard Henderson         int ofs = tcg_out_helper_stk_ofs(type, slot);
61288429a1caSRichard Henderson         if (!tcg_out_sti(s, type, imm, TCG_REG_CALL_STACK, ofs)) {
61298429a1caSRichard Henderson             tcg_debug_assert(parm->ntmp != 0);
61308429a1caSRichard Henderson             tcg_out_movi(s, type, parm->tmp[0], imm);
61318429a1caSRichard Henderson             tcg_out_st(s, type, parm->tmp[0], TCG_REG_CALL_STACK, ofs);
61328429a1caSRichard Henderson         }
61338429a1caSRichard Henderson     }
61348429a1caSRichard Henderson }
61358429a1caSRichard Henderson 
61368429a1caSRichard Henderson static void tcg_out_helper_load_common_args(TCGContext *s,
61378429a1caSRichard Henderson                                             const TCGLabelQemuLdst *ldst,
61388429a1caSRichard Henderson                                             const TCGLdstHelperParam *parm,
61398429a1caSRichard Henderson                                             const TCGHelperInfo *info,
61408429a1caSRichard Henderson                                             unsigned next_arg)
61418429a1caSRichard Henderson {
61428429a1caSRichard Henderson     TCGMovExtend ptr_mov = {
61438429a1caSRichard Henderson         .dst_type = TCG_TYPE_PTR,
61448429a1caSRichard Henderson         .src_type = TCG_TYPE_PTR,
61458429a1caSRichard Henderson         .src_ext = sizeof(void *) == 4 ? MO_32 : MO_64
61468429a1caSRichard Henderson     };
61478429a1caSRichard Henderson     const TCGCallArgumentLoc *loc = &info->in[0];
61488429a1caSRichard Henderson     TCGType type;
61498429a1caSRichard Henderson     unsigned slot;
61508429a1caSRichard Henderson     tcg_target_ulong imm;
61518429a1caSRichard Henderson 
61528429a1caSRichard Henderson     /*
61538429a1caSRichard Henderson      * Handle env, which is always first.
61548429a1caSRichard Henderson      */
61558429a1caSRichard Henderson     ptr_mov.dst = loc->arg_slot;
61568429a1caSRichard Henderson     ptr_mov.src = TCG_AREG0;
61578429a1caSRichard Henderson     tcg_out_helper_load_slots(s, 1, &ptr_mov, parm);
61588429a1caSRichard Henderson 
61598429a1caSRichard Henderson     /*
61608429a1caSRichard Henderson      * Handle oi.
61618429a1caSRichard Henderson      */
61628429a1caSRichard Henderson     imm = ldst->oi;
61638429a1caSRichard Henderson     loc = &info->in[next_arg];
61648429a1caSRichard Henderson     type = TCG_TYPE_I32;
61658429a1caSRichard Henderson     switch (loc->kind) {
61668429a1caSRichard Henderson     case TCG_CALL_ARG_NORMAL:
61678429a1caSRichard Henderson         break;
61688429a1caSRichard Henderson     case TCG_CALL_ARG_EXTEND_U:
61698429a1caSRichard Henderson     case TCG_CALL_ARG_EXTEND_S:
61708429a1caSRichard Henderson         /* No extension required for MemOpIdx. */
61718429a1caSRichard Henderson         tcg_debug_assert(imm <= INT32_MAX);
61728429a1caSRichard Henderson         type = TCG_TYPE_REG;
61738429a1caSRichard Henderson         break;
61748429a1caSRichard Henderson     default:
61758429a1caSRichard Henderson         g_assert_not_reached();
61768429a1caSRichard Henderson     }
61778429a1caSRichard Henderson     tcg_out_helper_load_imm(s, loc->arg_slot, type, imm, parm);
61788429a1caSRichard Henderson     next_arg++;
61798429a1caSRichard Henderson 
61808429a1caSRichard Henderson     /*
61818429a1caSRichard Henderson      * Handle ra.
61828429a1caSRichard Henderson      */
61838429a1caSRichard Henderson     loc = &info->in[next_arg];
61848429a1caSRichard Henderson     slot = loc->arg_slot;
61858429a1caSRichard Henderson     if (parm->ra_gen) {
61868429a1caSRichard Henderson         int arg_reg = -1;
61878429a1caSRichard Henderson         TCGReg ra_reg;
61888429a1caSRichard Henderson 
61898429a1caSRichard Henderson         if (arg_slot_reg_p(slot)) {
61908429a1caSRichard Henderson             arg_reg = tcg_target_call_iarg_regs[slot];
61918429a1caSRichard Henderson         }
61928429a1caSRichard Henderson         ra_reg = parm->ra_gen(s, ldst, arg_reg);
61938429a1caSRichard Henderson 
61948429a1caSRichard Henderson         ptr_mov.dst = slot;
61958429a1caSRichard Henderson         ptr_mov.src = ra_reg;
61968429a1caSRichard Henderson         tcg_out_helper_load_slots(s, 1, &ptr_mov, parm);
61978429a1caSRichard Henderson     } else {
61988429a1caSRichard Henderson         imm = (uintptr_t)ldst->raddr;
61998429a1caSRichard Henderson         tcg_out_helper_load_imm(s, slot, TCG_TYPE_PTR, imm, parm);
62008429a1caSRichard Henderson     }
62018429a1caSRichard Henderson }
62028429a1caSRichard Henderson 
62038429a1caSRichard Henderson static unsigned tcg_out_helper_add_mov(TCGMovExtend *mov,
62048429a1caSRichard Henderson                                        const TCGCallArgumentLoc *loc,
62058429a1caSRichard Henderson                                        TCGType dst_type, TCGType src_type,
62068429a1caSRichard Henderson                                        TCGReg lo, TCGReg hi)
62078429a1caSRichard Henderson {
6208ebebea53SRichard Henderson     MemOp reg_mo;
6209ebebea53SRichard Henderson 
62108429a1caSRichard Henderson     if (dst_type <= TCG_TYPE_REG) {
62118429a1caSRichard Henderson         MemOp src_ext;
62128429a1caSRichard Henderson 
62138429a1caSRichard Henderson         switch (loc->kind) {
62148429a1caSRichard Henderson         case TCG_CALL_ARG_NORMAL:
62158429a1caSRichard Henderson             src_ext = src_type == TCG_TYPE_I32 ? MO_32 : MO_64;
62168429a1caSRichard Henderson             break;
62178429a1caSRichard Henderson         case TCG_CALL_ARG_EXTEND_U:
62188429a1caSRichard Henderson             dst_type = TCG_TYPE_REG;
62198429a1caSRichard Henderson             src_ext = MO_UL;
62208429a1caSRichard Henderson             break;
62218429a1caSRichard Henderson         case TCG_CALL_ARG_EXTEND_S:
62228429a1caSRichard Henderson             dst_type = TCG_TYPE_REG;
62238429a1caSRichard Henderson             src_ext = MO_SL;
62248429a1caSRichard Henderson             break;
62258429a1caSRichard Henderson         default:
62268429a1caSRichard Henderson             g_assert_not_reached();
62278429a1caSRichard Henderson         }
62288429a1caSRichard Henderson 
62298429a1caSRichard Henderson         mov[0].dst = loc->arg_slot;
62308429a1caSRichard Henderson         mov[0].dst_type = dst_type;
62318429a1caSRichard Henderson         mov[0].src = lo;
62328429a1caSRichard Henderson         mov[0].src_type = src_type;
62338429a1caSRichard Henderson         mov[0].src_ext = src_ext;
62348429a1caSRichard Henderson         return 1;
62358429a1caSRichard Henderson     }
62368429a1caSRichard Henderson 
6237ebebea53SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
6238ebebea53SRichard Henderson         assert(dst_type == TCG_TYPE_I64);
6239ebebea53SRichard Henderson         reg_mo = MO_32;
6240ebebea53SRichard Henderson     } else {
6241ebebea53SRichard Henderson         assert(dst_type == TCG_TYPE_I128);
6242ebebea53SRichard Henderson         reg_mo = MO_64;
6243ebebea53SRichard Henderson     }
62448429a1caSRichard Henderson 
62458429a1caSRichard Henderson     mov[0].dst = loc[HOST_BIG_ENDIAN].arg_slot;
62468429a1caSRichard Henderson     mov[0].src = lo;
6247ebebea53SRichard Henderson     mov[0].dst_type = TCG_TYPE_REG;
6248ebebea53SRichard Henderson     mov[0].src_type = TCG_TYPE_REG;
6249ebebea53SRichard Henderson     mov[0].src_ext = reg_mo;
62508429a1caSRichard Henderson 
62518429a1caSRichard Henderson     mov[1].dst = loc[!HOST_BIG_ENDIAN].arg_slot;
62528429a1caSRichard Henderson     mov[1].src = hi;
6253ebebea53SRichard Henderson     mov[1].dst_type = TCG_TYPE_REG;
6254ebebea53SRichard Henderson     mov[1].src_type = TCG_TYPE_REG;
6255ebebea53SRichard Henderson     mov[1].src_ext = reg_mo;
62568429a1caSRichard Henderson 
62578429a1caSRichard Henderson     return 2;
62588429a1caSRichard Henderson }
62598429a1caSRichard Henderson 
62608429a1caSRichard Henderson static void tcg_out_ld_helper_args(TCGContext *s, const TCGLabelQemuLdst *ldst,
62618429a1caSRichard Henderson                                    const TCGLdstHelperParam *parm)
62628429a1caSRichard Henderson {
62638429a1caSRichard Henderson     const TCGHelperInfo *info;
62648429a1caSRichard Henderson     const TCGCallArgumentLoc *loc;
62658429a1caSRichard Henderson     TCGMovExtend mov[2];
62668429a1caSRichard Henderson     unsigned next_arg, nmov;
62678429a1caSRichard Henderson     MemOp mop = get_memop(ldst->oi);
62688429a1caSRichard Henderson 
62698429a1caSRichard Henderson     switch (mop & MO_SIZE) {
62708429a1caSRichard Henderson     case MO_8:
62718429a1caSRichard Henderson     case MO_16:
62728429a1caSRichard Henderson     case MO_32:
62738429a1caSRichard Henderson         info = &info_helper_ld32_mmu;
62748429a1caSRichard Henderson         break;
62758429a1caSRichard Henderson     case MO_64:
62768429a1caSRichard Henderson         info = &info_helper_ld64_mmu;
62778429a1caSRichard Henderson         break;
6278ebebea53SRichard Henderson     case MO_128:
6279ebebea53SRichard Henderson         info = &info_helper_ld128_mmu;
6280ebebea53SRichard Henderson         break;
62818429a1caSRichard Henderson     default:
62828429a1caSRichard Henderson         g_assert_not_reached();
62838429a1caSRichard Henderson     }
62848429a1caSRichard Henderson 
62858429a1caSRichard Henderson     /* Defer env argument. */
62868429a1caSRichard Henderson     next_arg = 1;
62878429a1caSRichard Henderson 
62888429a1caSRichard Henderson     loc = &info->in[next_arg];
6289c31e5fa4SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && s->addr_type == TCG_TYPE_I32) {
629024e46e6cSRichard Henderson         /*
629124e46e6cSRichard Henderson          * 32-bit host with 32-bit guest: zero-extend the guest address
629224e46e6cSRichard Henderson          * to 64-bits for the helper by storing the low part, then
629324e46e6cSRichard Henderson          * load a zero for the high part.
629424e46e6cSRichard Henderson          */
629524e46e6cSRichard Henderson         tcg_out_helper_add_mov(mov, loc + HOST_BIG_ENDIAN,
629624e46e6cSRichard Henderson                                TCG_TYPE_I32, TCG_TYPE_I32,
62970cd38379SRichard Henderson                                ldst->addr_reg, -1);
629824e46e6cSRichard Henderson         tcg_out_helper_load_slots(s, 1, mov, parm);
629924e46e6cSRichard Henderson 
630024e46e6cSRichard Henderson         tcg_out_helper_load_imm(s, loc[!HOST_BIG_ENDIAN].arg_slot,
630124e46e6cSRichard Henderson                                 TCG_TYPE_I32, 0, parm);
630224e46e6cSRichard Henderson         next_arg += 2;
6303c31e5fa4SRichard Henderson     } else {
6304c31e5fa4SRichard Henderson         nmov = tcg_out_helper_add_mov(mov, loc, TCG_TYPE_I64, s->addr_type,
63050cd38379SRichard Henderson                                       ldst->addr_reg, -1);
6306c31e5fa4SRichard Henderson         tcg_out_helper_load_slots(s, nmov, mov, parm);
6307c31e5fa4SRichard Henderson         next_arg += nmov;
630824e46e6cSRichard Henderson     }
63098429a1caSRichard Henderson 
6310ebebea53SRichard Henderson     switch (info->out_kind) {
6311ebebea53SRichard Henderson     case TCG_CALL_RET_NORMAL:
6312ebebea53SRichard Henderson     case TCG_CALL_RET_BY_VEC:
6313ebebea53SRichard Henderson         break;
6314ebebea53SRichard Henderson     case TCG_CALL_RET_BY_REF:
6315ebebea53SRichard Henderson         /*
6316ebebea53SRichard Henderson          * The return reference is in the first argument slot.
6317ebebea53SRichard Henderson          * We need memory in which to return: re-use the top of stack.
6318ebebea53SRichard Henderson          */
6319ebebea53SRichard Henderson         {
6320ebebea53SRichard Henderson             int ofs_slot0 = TCG_TARGET_CALL_STACK_OFFSET;
6321ebebea53SRichard Henderson 
6322ebebea53SRichard Henderson             if (arg_slot_reg_p(0)) {
6323ebebea53SRichard Henderson                 tcg_out_addi_ptr(s, tcg_target_call_iarg_regs[0],
6324ebebea53SRichard Henderson                                  TCG_REG_CALL_STACK, ofs_slot0);
6325ebebea53SRichard Henderson             } else {
6326ebebea53SRichard Henderson                 tcg_debug_assert(parm->ntmp != 0);
6327ebebea53SRichard Henderson                 tcg_out_addi_ptr(s, parm->tmp[0],
6328ebebea53SRichard Henderson                                  TCG_REG_CALL_STACK, ofs_slot0);
6329ebebea53SRichard Henderson                 tcg_out_st(s, TCG_TYPE_PTR, parm->tmp[0],
6330ebebea53SRichard Henderson                            TCG_REG_CALL_STACK, ofs_slot0);
6331ebebea53SRichard Henderson             }
6332ebebea53SRichard Henderson         }
6333ebebea53SRichard Henderson         break;
6334ebebea53SRichard Henderson     default:
6335ebebea53SRichard Henderson         g_assert_not_reached();
6336ebebea53SRichard Henderson     }
63378429a1caSRichard Henderson 
63388429a1caSRichard Henderson     tcg_out_helper_load_common_args(s, ldst, parm, info, next_arg);
63398429a1caSRichard Henderson }
63408429a1caSRichard Henderson 
63418429a1caSRichard Henderson static void tcg_out_ld_helper_ret(TCGContext *s, const TCGLabelQemuLdst *ldst,
63428429a1caSRichard Henderson                                   bool load_sign,
63438429a1caSRichard Henderson                                   const TCGLdstHelperParam *parm)
63448429a1caSRichard Henderson {
63458429a1caSRichard Henderson     MemOp mop = get_memop(ldst->oi);
6346ebebea53SRichard Henderson     TCGMovExtend mov[2];
6347ebebea53SRichard Henderson     int ofs_slot0;
63488429a1caSRichard Henderson 
6349ebebea53SRichard Henderson     switch (ldst->type) {
6350ebebea53SRichard Henderson     case TCG_TYPE_I64:
6351ebebea53SRichard Henderson         if (TCG_TARGET_REG_BITS == 32) {
6352ebebea53SRichard Henderson             break;
6353ebebea53SRichard Henderson         }
6354ebebea53SRichard Henderson         /* fall through */
6355ebebea53SRichard Henderson 
6356ebebea53SRichard Henderson     case TCG_TYPE_I32:
63578429a1caSRichard Henderson         mov[0].dst = ldst->datalo_reg;
63588429a1caSRichard Henderson         mov[0].src = tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, 0);
63598429a1caSRichard Henderson         mov[0].dst_type = ldst->type;
63608429a1caSRichard Henderson         mov[0].src_type = TCG_TYPE_REG;
63618429a1caSRichard Henderson 
63628429a1caSRichard Henderson         /*
63638429a1caSRichard Henderson          * If load_sign, then we allowed the helper to perform the
63648429a1caSRichard Henderson          * appropriate sign extension to tcg_target_ulong, and all
63658429a1caSRichard Henderson          * we need now is a plain move.
63668429a1caSRichard Henderson          *
63678429a1caSRichard Henderson          * If they do not, then we expect the relevant extension
63688429a1caSRichard Henderson          * instruction to be no more expensive than a move, and
63698429a1caSRichard Henderson          * we thus save the icache etc by only using one of two
63708429a1caSRichard Henderson          * helper functions.
63718429a1caSRichard Henderson          */
63728429a1caSRichard Henderson         if (load_sign || !(mop & MO_SIGN)) {
63738429a1caSRichard Henderson             if (TCG_TARGET_REG_BITS == 32 || ldst->type == TCG_TYPE_I32) {
63748429a1caSRichard Henderson                 mov[0].src_ext = MO_32;
63758429a1caSRichard Henderson             } else {
63768429a1caSRichard Henderson                 mov[0].src_ext = MO_64;
63778429a1caSRichard Henderson             }
63788429a1caSRichard Henderson         } else {
63798429a1caSRichard Henderson             mov[0].src_ext = mop & MO_SSIZE;
63808429a1caSRichard Henderson         }
63818429a1caSRichard Henderson         tcg_out_movext1(s, mov);
6382ebebea53SRichard Henderson         return;
6383ebebea53SRichard Henderson 
6384ebebea53SRichard Henderson     case TCG_TYPE_I128:
6385ebebea53SRichard Henderson         tcg_debug_assert(TCG_TARGET_REG_BITS == 64);
6386ebebea53SRichard Henderson         ofs_slot0 = TCG_TARGET_CALL_STACK_OFFSET;
6387ebebea53SRichard Henderson         switch (TCG_TARGET_CALL_RET_I128) {
6388ebebea53SRichard Henderson         case TCG_CALL_RET_NORMAL:
6389ebebea53SRichard Henderson             break;
6390ebebea53SRichard Henderson         case TCG_CALL_RET_BY_VEC:
6391ebebea53SRichard Henderson             tcg_out_st(s, TCG_TYPE_V128,
6392ebebea53SRichard Henderson                        tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0),
6393ebebea53SRichard Henderson                        TCG_REG_CALL_STACK, ofs_slot0);
6394ebebea53SRichard Henderson             /* fall through */
6395ebebea53SRichard Henderson         case TCG_CALL_RET_BY_REF:
6396ebebea53SRichard Henderson             tcg_out_ld(s, TCG_TYPE_I64, ldst->datalo_reg,
6397ebebea53SRichard Henderson                        TCG_REG_CALL_STACK, ofs_slot0 + 8 * HOST_BIG_ENDIAN);
6398ebebea53SRichard Henderson             tcg_out_ld(s, TCG_TYPE_I64, ldst->datahi_reg,
6399ebebea53SRichard Henderson                        TCG_REG_CALL_STACK, ofs_slot0 + 8 * !HOST_BIG_ENDIAN);
6400ebebea53SRichard Henderson             return;
6401ebebea53SRichard Henderson         default:
6402ebebea53SRichard Henderson             g_assert_not_reached();
6403ebebea53SRichard Henderson         }
6404ebebea53SRichard Henderson         break;
6405ebebea53SRichard Henderson 
6406ebebea53SRichard Henderson     default:
6407ebebea53SRichard Henderson         g_assert_not_reached();
6408ebebea53SRichard Henderson     }
64098429a1caSRichard Henderson 
64108429a1caSRichard Henderson     mov[0].dst = ldst->datalo_reg;
64118429a1caSRichard Henderson     mov[0].src =
64128429a1caSRichard Henderson         tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, HOST_BIG_ENDIAN);
6413723d3a27SRichard Henderson     mov[0].dst_type = TCG_TYPE_REG;
6414723d3a27SRichard Henderson     mov[0].src_type = TCG_TYPE_REG;
6415ebebea53SRichard Henderson     mov[0].src_ext = TCG_TARGET_REG_BITS == 32 ? MO_32 : MO_64;
64168429a1caSRichard Henderson 
64178429a1caSRichard Henderson     mov[1].dst = ldst->datahi_reg;
64188429a1caSRichard Henderson     mov[1].src =
64198429a1caSRichard Henderson         tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, !HOST_BIG_ENDIAN);
64208429a1caSRichard Henderson     mov[1].dst_type = TCG_TYPE_REG;
64218429a1caSRichard Henderson     mov[1].src_type = TCG_TYPE_REG;
6422ebebea53SRichard Henderson     mov[1].src_ext = TCG_TARGET_REG_BITS == 32 ? MO_32 : MO_64;
64238429a1caSRichard Henderson 
64248429a1caSRichard Henderson     tcg_out_movext2(s, mov, mov + 1, parm->ntmp ? parm->tmp[0] : -1);
64258429a1caSRichard Henderson }
64268429a1caSRichard Henderson 
64278429a1caSRichard Henderson static void tcg_out_st_helper_args(TCGContext *s, const TCGLabelQemuLdst *ldst,
64288429a1caSRichard Henderson                                    const TCGLdstHelperParam *parm)
64298429a1caSRichard Henderson {
64308429a1caSRichard Henderson     const TCGHelperInfo *info;
64318429a1caSRichard Henderson     const TCGCallArgumentLoc *loc;
64328429a1caSRichard Henderson     TCGMovExtend mov[4];
64338429a1caSRichard Henderson     TCGType data_type;
64348429a1caSRichard Henderson     unsigned next_arg, nmov, n;
64358429a1caSRichard Henderson     MemOp mop = get_memop(ldst->oi);
64368429a1caSRichard Henderson 
64378429a1caSRichard Henderson     switch (mop & MO_SIZE) {
64388429a1caSRichard Henderson     case MO_8:
64398429a1caSRichard Henderson     case MO_16:
64408429a1caSRichard Henderson     case MO_32:
64418429a1caSRichard Henderson         info = &info_helper_st32_mmu;
64428429a1caSRichard Henderson         data_type = TCG_TYPE_I32;
64438429a1caSRichard Henderson         break;
64448429a1caSRichard Henderson     case MO_64:
64458429a1caSRichard Henderson         info = &info_helper_st64_mmu;
64468429a1caSRichard Henderson         data_type = TCG_TYPE_I64;
64478429a1caSRichard Henderson         break;
6448ebebea53SRichard Henderson     case MO_128:
6449ebebea53SRichard Henderson         info = &info_helper_st128_mmu;
6450ebebea53SRichard Henderson         data_type = TCG_TYPE_I128;
6451ebebea53SRichard Henderson         break;
64528429a1caSRichard Henderson     default:
64538429a1caSRichard Henderson         g_assert_not_reached();
64548429a1caSRichard Henderson     }
64558429a1caSRichard Henderson 
64568429a1caSRichard Henderson     /* Defer env argument. */
64578429a1caSRichard Henderson     next_arg = 1;
64588429a1caSRichard Henderson     nmov = 0;
64598429a1caSRichard Henderson 
64608429a1caSRichard Henderson     /* Handle addr argument. */
64618429a1caSRichard Henderson     loc = &info->in[next_arg];
64620cd38379SRichard Henderson     tcg_debug_assert(s->addr_type <= TCG_TYPE_REG);
64630cd38379SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
646424e46e6cSRichard Henderson         /*
64650cd38379SRichard Henderson          * 32-bit host (and thus 32-bit guest): zero-extend the guest address
646624e46e6cSRichard Henderson          * to 64-bits for the helper by storing the low part.  Later,
646724e46e6cSRichard Henderson          * after we have processed the register inputs, we will load a
646824e46e6cSRichard Henderson          * zero for the high part.
646924e46e6cSRichard Henderson          */
647024e46e6cSRichard Henderson         tcg_out_helper_add_mov(mov, loc + HOST_BIG_ENDIAN,
647124e46e6cSRichard Henderson                                TCG_TYPE_I32, TCG_TYPE_I32,
64720cd38379SRichard Henderson                                ldst->addr_reg, -1);
647324e46e6cSRichard Henderson         next_arg += 2;
647424e46e6cSRichard Henderson         nmov += 1;
6475c31e5fa4SRichard Henderson     } else {
6476c31e5fa4SRichard Henderson         n = tcg_out_helper_add_mov(mov, loc, TCG_TYPE_I64, s->addr_type,
64770cd38379SRichard Henderson                                    ldst->addr_reg, -1);
6478c31e5fa4SRichard Henderson         next_arg += n;
6479c31e5fa4SRichard Henderson         nmov += n;
648024e46e6cSRichard Henderson     }
64818429a1caSRichard Henderson 
64828429a1caSRichard Henderson     /* Handle data argument. */
64838429a1caSRichard Henderson     loc = &info->in[next_arg];
6484ebebea53SRichard Henderson     switch (loc->kind) {
6485ebebea53SRichard Henderson     case TCG_CALL_ARG_NORMAL:
6486ebebea53SRichard Henderson     case TCG_CALL_ARG_EXTEND_U:
6487ebebea53SRichard Henderson     case TCG_CALL_ARG_EXTEND_S:
64888429a1caSRichard Henderson         n = tcg_out_helper_add_mov(mov + nmov, loc, data_type, ldst->type,
64898429a1caSRichard Henderson                                    ldst->datalo_reg, ldst->datahi_reg);
64908429a1caSRichard Henderson         next_arg += n;
64918429a1caSRichard Henderson         nmov += n;
6492ebebea53SRichard Henderson         tcg_out_helper_load_slots(s, nmov, mov, parm);
6493ebebea53SRichard Henderson         break;
6494ebebea53SRichard Henderson 
6495ebebea53SRichard Henderson     case TCG_CALL_ARG_BY_REF:
6496ebebea53SRichard Henderson         tcg_debug_assert(TCG_TARGET_REG_BITS == 64);
6497ebebea53SRichard Henderson         tcg_debug_assert(data_type == TCG_TYPE_I128);
6498ebebea53SRichard Henderson         tcg_out_st(s, TCG_TYPE_I64,
6499ebebea53SRichard Henderson                    HOST_BIG_ENDIAN ? ldst->datahi_reg : ldst->datalo_reg,
6500ebebea53SRichard Henderson                    TCG_REG_CALL_STACK, arg_slot_stk_ofs(loc[0].ref_slot));
6501ebebea53SRichard Henderson         tcg_out_st(s, TCG_TYPE_I64,
6502ebebea53SRichard Henderson                    HOST_BIG_ENDIAN ? ldst->datalo_reg : ldst->datahi_reg,
6503ebebea53SRichard Henderson                    TCG_REG_CALL_STACK, arg_slot_stk_ofs(loc[1].ref_slot));
65048429a1caSRichard Henderson 
65058429a1caSRichard Henderson         tcg_out_helper_load_slots(s, nmov, mov, parm);
6506ebebea53SRichard Henderson 
6507ebebea53SRichard Henderson         if (arg_slot_reg_p(loc->arg_slot)) {
6508ebebea53SRichard Henderson             tcg_out_addi_ptr(s, tcg_target_call_iarg_regs[loc->arg_slot],
6509ebebea53SRichard Henderson                              TCG_REG_CALL_STACK,
6510ebebea53SRichard Henderson                              arg_slot_stk_ofs(loc->ref_slot));
6511ebebea53SRichard Henderson         } else {
6512ebebea53SRichard Henderson             tcg_debug_assert(parm->ntmp != 0);
6513ebebea53SRichard Henderson             tcg_out_addi_ptr(s, parm->tmp[0], TCG_REG_CALL_STACK,
6514ebebea53SRichard Henderson                              arg_slot_stk_ofs(loc->ref_slot));
6515ebebea53SRichard Henderson             tcg_out_st(s, TCG_TYPE_PTR, parm->tmp[0],
6516ebebea53SRichard Henderson                        TCG_REG_CALL_STACK, arg_slot_stk_ofs(loc->arg_slot));
6517ebebea53SRichard Henderson         }
6518ebebea53SRichard Henderson         next_arg += 2;
6519ebebea53SRichard Henderson         break;
6520ebebea53SRichard Henderson 
6521ebebea53SRichard Henderson     default:
6522ebebea53SRichard Henderson         g_assert_not_reached();
6523ebebea53SRichard Henderson     }
6524ebebea53SRichard Henderson 
65250cd38379SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
6526c31e5fa4SRichard Henderson         /* Zero extend the address by loading a zero for the high part. */
652724e46e6cSRichard Henderson         loc = &info->in[1 + !HOST_BIG_ENDIAN];
652824e46e6cSRichard Henderson         tcg_out_helper_load_imm(s, loc->arg_slot, TCG_TYPE_I32, 0, parm);
652924e46e6cSRichard Henderson     }
653024e46e6cSRichard Henderson 
65318429a1caSRichard Henderson     tcg_out_helper_load_common_args(s, ldst, parm, info, next_arg);
65328429a1caSRichard Henderson }
65338429a1caSRichard Henderson 
653476cef4b2SRichard Henderson int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start)
6535c896fe29Sbellard {
6536747bd69dSRichard Henderson     int i, start_words, num_insns;
653715fa08f8SRichard Henderson     TCGOp *op;
6538c896fe29Sbellard 
6539d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)
6540fbf59aadSRichard Henderson                  && qemu_log_in_addr_range(pc_start))) {
6541c60f599bSRichard Henderson         FILE *logfile = qemu_log_trylock();
654278b54858SRichard Henderson         if (logfile) {
654378b54858SRichard Henderson             fprintf(logfile, "OP:\n");
6544b7a83ff8SRichard Henderson             tcg_dump_ops(s, logfile, false);
654578b54858SRichard Henderson             fprintf(logfile, "\n");
6546fc59d2d8SRobert Foley             qemu_log_unlock(logfile);
6547c896fe29Sbellard         }
654878b54858SRichard Henderson     }
6549c896fe29Sbellard 
6550bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG
6551bef16ab4SRichard Henderson     /* Ensure all labels referenced have been emitted.  */
6552bef16ab4SRichard Henderson     {
6553bef16ab4SRichard Henderson         TCGLabel *l;
6554bef16ab4SRichard Henderson         bool error = false;
6555bef16ab4SRichard Henderson 
6556bef16ab4SRichard Henderson         QSIMPLEQ_FOREACH(l, &s->labels, next) {
6557f85b1fc4SRichard Henderson             if (unlikely(!l->present) && !QSIMPLEQ_EMPTY(&l->branches)) {
6558bef16ab4SRichard Henderson                 qemu_log_mask(CPU_LOG_TB_OP,
6559bef16ab4SRichard Henderson                               "$L%d referenced but not present.\n", l->id);
6560bef16ab4SRichard Henderson                 error = true;
6561bef16ab4SRichard Henderson             }
6562bef16ab4SRichard Henderson         }
6563bef16ab4SRichard Henderson         assert(!error);
6564bef16ab4SRichard Henderson     }
6565bef16ab4SRichard Henderson #endif
6566bef16ab4SRichard Henderson 
656704e006abSRichard Henderson     /* Do not reuse any EBB that may be allocated within the TB. */
656804e006abSRichard Henderson     tcg_temp_ebb_reset_freed(s);
656904e006abSRichard Henderson 
6570c45cb8bbSRichard Henderson     tcg_optimize(s);
65718f2e8c07SKirill Batuzov 
6572b4fc67c7SRichard Henderson     reachable_code_pass(s);
6573874b8574SRichard Henderson     liveness_pass_0(s);
6574b83eabeaSRichard Henderson     liveness_pass_1(s);
65755a18407fSRichard Henderson 
65765a18407fSRichard Henderson     if (s->nb_indirects > 0) {
65775a18407fSRichard Henderson         if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND)
6578fbf59aadSRichard Henderson                      && qemu_log_in_addr_range(pc_start))) {
6579c60f599bSRichard Henderson             FILE *logfile = qemu_log_trylock();
658078b54858SRichard Henderson             if (logfile) {
658178b54858SRichard Henderson                 fprintf(logfile, "OP before indirect lowering:\n");
6582b7a83ff8SRichard Henderson                 tcg_dump_ops(s, logfile, false);
658378b54858SRichard Henderson                 fprintf(logfile, "\n");
6584fc59d2d8SRobert Foley                 qemu_log_unlock(logfile);
65855a18407fSRichard Henderson             }
658678b54858SRichard Henderson         }
6587645e3a81SRichard Henderson 
65885a18407fSRichard Henderson         /* Replace indirect temps with direct temps.  */
6589b83eabeaSRichard Henderson         if (liveness_pass_2(s)) {
65905a18407fSRichard Henderson             /* If changes were made, re-run liveness.  */
6591b83eabeaSRichard Henderson             liveness_pass_1(s);
65925a18407fSRichard Henderson         }
65935a18407fSRichard Henderson     }
6594c5cc28ffSAurelien Jarno 
6595d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT)
6596fbf59aadSRichard Henderson                  && qemu_log_in_addr_range(pc_start))) {
6597c60f599bSRichard Henderson         FILE *logfile = qemu_log_trylock();
659878b54858SRichard Henderson         if (logfile) {
659978b54858SRichard Henderson             fprintf(logfile, "OP after optimization and liveness analysis:\n");
6600b7a83ff8SRichard Henderson             tcg_dump_ops(s, logfile, true);
660178b54858SRichard Henderson             fprintf(logfile, "\n");
6602fc59d2d8SRobert Foley             qemu_log_unlock(logfile);
6603c896fe29Sbellard         }
660478b54858SRichard Henderson     }
6605c896fe29Sbellard 
660635abb009SRichard Henderson     /* Initialize goto_tb jump offsets. */
66073a50f424SRichard Henderson     tb->jmp_reset_offset[0] = TB_JMP_OFFSET_INVALID;
66083a50f424SRichard Henderson     tb->jmp_reset_offset[1] = TB_JMP_OFFSET_INVALID;
66099da6079bSRichard Henderson     tb->jmp_insn_offset[0] = TB_JMP_OFFSET_INVALID;
66109da6079bSRichard Henderson     tb->jmp_insn_offset[1] = TB_JMP_OFFSET_INVALID;
661135abb009SRichard Henderson 
6612c896fe29Sbellard     tcg_reg_alloc_start(s);
6613c896fe29Sbellard 
6614db0c51a3SRichard Henderson     /*
6615db0c51a3SRichard Henderson      * Reset the buffer pointers when restarting after overflow.
6616db0c51a3SRichard Henderson      * TODO: Move this into translate-all.c with the rest of the
6617db0c51a3SRichard Henderson      * buffer management.  Having only this done here is confusing.
6618db0c51a3SRichard Henderson      */
6619db0c51a3SRichard Henderson     s->code_buf = tcg_splitwx_to_rw(tb->tc.ptr);
6620db0c51a3SRichard Henderson     s->code_ptr = s->code_buf;
6621a7cfd751SRichard Henderson     s->data_gen_ptr = NULL;
6622c896fe29Sbellard 
66236001f772SLaurent Vivier     QSIMPLEQ_INIT(&s->ldst_labels);
662457a26946SRichard Henderson     s->pool_labels = NULL;
66259ecefc84SRichard Henderson 
6626747bd69dSRichard Henderson     start_words = s->insn_start_words;
6627747bd69dSRichard Henderson     s->gen_insn_data =
6628747bd69dSRichard Henderson         tcg_malloc(sizeof(uint64_t) * s->gen_tb->icount * start_words);
6629747bd69dSRichard Henderson 
66309358fbbfSRichard Henderson     tcg_out_tb_start(s);
66319358fbbfSRichard Henderson 
6632fca8a500SRichard Henderson     num_insns = -1;
663315fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
6634c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
6635b3db8758Sblueswir1 
6636c896fe29Sbellard         switch (opc) {
6637b5701261SRichard Henderson         case INDEX_op_mov:
6638d2fd745fSRichard Henderson         case INDEX_op_mov_vec:
6639dd186292SRichard Henderson             tcg_reg_alloc_mov(s, op);
6640c896fe29Sbellard             break;
6641bab1671fSRichard Henderson         case INDEX_op_dup_vec:
6642bab1671fSRichard Henderson             tcg_reg_alloc_dup(s, op);
6643bab1671fSRichard Henderson             break;
6644765b842aSRichard Henderson         case INDEX_op_insn_start:
6645fca8a500SRichard Henderson             if (num_insns >= 0) {
66469f754620SRichard Henderson                 size_t off = tcg_current_code_size(s);
66479f754620SRichard Henderson                 s->gen_insn_end_off[num_insns] = off;
66489f754620SRichard Henderson                 /* Assert that we do not overflow our stored offset.  */
66499f754620SRichard Henderson                 assert(s->gen_insn_end_off[num_insns] == off);
6650fca8a500SRichard Henderson             }
6651fca8a500SRichard Henderson             num_insns++;
6652747bd69dSRichard Henderson             for (i = 0; i < start_words; ++i) {
6653747bd69dSRichard Henderson                 s->gen_insn_data[num_insns * start_words + i] =
6654c9ad8d27SRichard Henderson                     tcg_get_insn_start_param(op, i);
6655bad729e2SRichard Henderson             }
6656c896fe29Sbellard             break;
66575ff9d6a4Sbellard         case INDEX_op_discard:
665843439139SRichard Henderson             temp_dead(s, arg_temp(op->args[0]));
66595ff9d6a4Sbellard             break;
6660c896fe29Sbellard         case INDEX_op_set_label:
6661e8996ee0Sbellard             tcg_reg_alloc_bb_end(s, s->reserved_regs);
666292ab8e7dSRichard Henderson             tcg_out_label(s, arg_label(op->args[0]));
6663c896fe29Sbellard             break;
6664c896fe29Sbellard         case INDEX_op_call:
6665dd186292SRichard Henderson             tcg_reg_alloc_call(s, op);
6666c45cb8bbSRichard Henderson             break;
6667b55a8d9dSRichard Henderson         case INDEX_op_exit_tb:
6668b55a8d9dSRichard Henderson             tcg_out_exit_tb(s, op->args[0]);
6669b55a8d9dSRichard Henderson             break;
6670cf7d6b8eSRichard Henderson         case INDEX_op_goto_tb:
6671cf7d6b8eSRichard Henderson             tcg_out_goto_tb(s, op->args[0]);
6672cf7d6b8eSRichard Henderson             break;
6673efe86b21SRichard Henderson         case INDEX_op_dup2_vec:
6674efe86b21SRichard Henderson             if (tcg_reg_alloc_dup2(s, op)) {
6675efe86b21SRichard Henderson                 break;
6676efe86b21SRichard Henderson             }
6677efe86b21SRichard Henderson             /* fall through */
6678c896fe29Sbellard         default:
667925c4d9ccSRichard Henderson             /* Sanity check that we've not introduced any unhandled opcodes. */
6680771a5925SRichard Henderson             tcg_debug_assert(tcg_op_supported(opc, TCGOP_TYPE(op),
6681771a5925SRichard Henderson                                               TCGOP_FLAGS(op)));
6682c896fe29Sbellard             /* Note: in order to speed up the code, it would be much
6683c896fe29Sbellard                faster to have specialized register allocator functions for
6684c896fe29Sbellard                some common argument patterns */
6685dd186292SRichard Henderson             tcg_reg_alloc_op(s, op);
6686c896fe29Sbellard             break;
6687c896fe29Sbellard         }
6688b125f9dcSRichard Henderson         /* Test for (pending) buffer overflow.  The assumption is that any
6689b125f9dcSRichard Henderson            one operation beginning below the high water mark cannot overrun
6690b125f9dcSRichard Henderson            the buffer completely.  Thus we can test for overflow after
6691b125f9dcSRichard Henderson            generating code without having to check during generation.  */
6692644da9b3SJohn Clarke         if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) {
6693b125f9dcSRichard Henderson             return -1;
6694b125f9dcSRichard Henderson         }
66956e6c4efeSRichard Henderson         /* Test for TB overflow, as seen by gen_insn_end_off.  */
66966e6c4efeSRichard Henderson         if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) {
66976e6c4efeSRichard Henderson             return -2;
66986e6c4efeSRichard Henderson         }
6699c896fe29Sbellard     }
6700747bd69dSRichard Henderson     tcg_debug_assert(num_insns + 1 == s->gen_tb->icount);
6701fca8a500SRichard Henderson     s->gen_insn_end_off[num_insns] = tcg_current_code_size(s);
6702c45cb8bbSRichard Henderson 
6703b76f0d8cSYeongkyoon Lee     /* Generate TB finalization at the end of block */
6704aeee05f5SRichard Henderson     i = tcg_out_ldst_finalize(s);
6705aeee05f5SRichard Henderson     if (i < 0) {
6706aeee05f5SRichard Henderson         return i;
670723dceda6SRichard Henderson     }
67081768987bSRichard Henderson     i = tcg_out_pool_finalize(s);
67091768987bSRichard Henderson     if (i < 0) {
67101768987bSRichard Henderson         return i;
671157a26946SRichard Henderson     }
67127ecd02a0SRichard Henderson     if (!tcg_resolve_relocs(s)) {
67137ecd02a0SRichard Henderson         return -2;
67147ecd02a0SRichard Henderson     }
6715c896fe29Sbellard 
6716df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
6717c896fe29Sbellard     /* flush instruction cache */
6718db0c51a3SRichard Henderson     flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf),
6719db0c51a3SRichard Henderson                         (uintptr_t)s->code_buf,
67201da8de39SRichard Henderson                         tcg_ptr_byte_diff(s->code_ptr, s->code_buf));
6721df5d2b16SRichard Henderson #endif
67222aeabc08SStefan Weil 
67231813e175SRichard Henderson     return tcg_current_code_size(s);
6724c896fe29Sbellard }
6725c896fe29Sbellard 
6726813da627SRichard Henderson #ifdef ELF_HOST_MACHINE
67275872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things:
67285872bbf2SRichard Henderson 
67295872bbf2SRichard Henderson    (1) Define ELF_HOST_MACHINE to indicate both what value to
67305872bbf2SRichard Henderson        put into the ELF image and to indicate support for the feature.
67315872bbf2SRichard Henderson 
67325872bbf2SRichard Henderson    (2) Define tcg_register_jit.  This should create a buffer containing
67335872bbf2SRichard Henderson        the contents of a .debug_frame section that describes the post-
67345872bbf2SRichard Henderson        prologue unwind info for the tcg machine.
67355872bbf2SRichard Henderson 
67365872bbf2SRichard Henderson    (3) Call tcg_register_jit_int, with the constructed .debug_frame.
67375872bbf2SRichard Henderson */
6738813da627SRichard Henderson 
6739813da627SRichard Henderson /* Begin GDB interface.  THE FOLLOWING MUST MATCH GDB DOCS.  */
6740813da627SRichard Henderson typedef enum {
6741813da627SRichard Henderson     JIT_NOACTION = 0,
6742813da627SRichard Henderson     JIT_REGISTER_FN,
6743813da627SRichard Henderson     JIT_UNREGISTER_FN
6744813da627SRichard Henderson } jit_actions_t;
6745813da627SRichard Henderson 
6746813da627SRichard Henderson struct jit_code_entry {
6747813da627SRichard Henderson     struct jit_code_entry *next_entry;
6748813da627SRichard Henderson     struct jit_code_entry *prev_entry;
6749813da627SRichard Henderson     const void *symfile_addr;
6750813da627SRichard Henderson     uint64_t symfile_size;
6751813da627SRichard Henderson };
6752813da627SRichard Henderson 
6753813da627SRichard Henderson struct jit_descriptor {
6754813da627SRichard Henderson     uint32_t version;
6755813da627SRichard Henderson     uint32_t action_flag;
6756813da627SRichard Henderson     struct jit_code_entry *relevant_entry;
6757813da627SRichard Henderson     struct jit_code_entry *first_entry;
6758813da627SRichard Henderson };
6759813da627SRichard Henderson 
6760813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline));
6761813da627SRichard Henderson void __jit_debug_register_code(void)
6762813da627SRichard Henderson {
6763813da627SRichard Henderson     asm("");
6764813da627SRichard Henderson }
6765813da627SRichard Henderson 
6766813da627SRichard Henderson /* Must statically initialize the version, because GDB may check
6767813da627SRichard Henderson    the version before we can set it.  */
6768813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
6769813da627SRichard Henderson 
6770813da627SRichard Henderson /* End GDB interface.  */
6771813da627SRichard Henderson 
6772813da627SRichard Henderson static int find_string(const char *strtab, const char *str)
6773813da627SRichard Henderson {
6774813da627SRichard Henderson     const char *p = strtab + 1;
6775813da627SRichard Henderson 
6776813da627SRichard Henderson     while (1) {
6777813da627SRichard Henderson         if (strcmp(p, str) == 0) {
6778813da627SRichard Henderson             return p - strtab;
6779813da627SRichard Henderson         }
6780813da627SRichard Henderson         p += strlen(p) + 1;
6781813da627SRichard Henderson     }
6782813da627SRichard Henderson }
6783813da627SRichard Henderson 
6784755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf_ptr, size_t buf_size,
67852c90784aSRichard Henderson                                  const void *debug_frame,
67862c90784aSRichard Henderson                                  size_t debug_frame_size)
6787813da627SRichard Henderson {
67885872bbf2SRichard Henderson     struct __attribute__((packed)) DebugInfo {
67895872bbf2SRichard Henderson         uint32_t  len;
67905872bbf2SRichard Henderson         uint16_t  version;
67915872bbf2SRichard Henderson         uint32_t  abbrev;
67925872bbf2SRichard Henderson         uint8_t   ptr_size;
67935872bbf2SRichard Henderson         uint8_t   cu_die;
67945872bbf2SRichard Henderson         uint16_t  cu_lang;
67955872bbf2SRichard Henderson         uintptr_t cu_low_pc;
67965872bbf2SRichard Henderson         uintptr_t cu_high_pc;
67975872bbf2SRichard Henderson         uint8_t   fn_die;
67985872bbf2SRichard Henderson         char      fn_name[16];
67995872bbf2SRichard Henderson         uintptr_t fn_low_pc;
68005872bbf2SRichard Henderson         uintptr_t fn_high_pc;
68015872bbf2SRichard Henderson         uint8_t   cu_eoc;
68025872bbf2SRichard Henderson     };
6803813da627SRichard Henderson 
6804813da627SRichard Henderson     struct ElfImage {
6805813da627SRichard Henderson         ElfW(Ehdr) ehdr;
6806813da627SRichard Henderson         ElfW(Phdr) phdr;
68075872bbf2SRichard Henderson         ElfW(Shdr) shdr[7];
68085872bbf2SRichard Henderson         ElfW(Sym)  sym[2];
68095872bbf2SRichard Henderson         struct DebugInfo di;
68105872bbf2SRichard Henderson         uint8_t    da[24];
68115872bbf2SRichard Henderson         char       str[80];
68125872bbf2SRichard Henderson     };
68135872bbf2SRichard Henderson 
68145872bbf2SRichard Henderson     struct ElfImage *img;
68155872bbf2SRichard Henderson 
68165872bbf2SRichard Henderson     static const struct ElfImage img_template = {
68175872bbf2SRichard Henderson         .ehdr = {
68185872bbf2SRichard Henderson             .e_ident[EI_MAG0] = ELFMAG0,
68195872bbf2SRichard Henderson             .e_ident[EI_MAG1] = ELFMAG1,
68205872bbf2SRichard Henderson             .e_ident[EI_MAG2] = ELFMAG2,
68215872bbf2SRichard Henderson             .e_ident[EI_MAG3] = ELFMAG3,
68225872bbf2SRichard Henderson             .e_ident[EI_CLASS] = ELF_CLASS,
68235872bbf2SRichard Henderson             .e_ident[EI_DATA] = ELF_DATA,
68245872bbf2SRichard Henderson             .e_ident[EI_VERSION] = EV_CURRENT,
68255872bbf2SRichard Henderson             .e_type = ET_EXEC,
68265872bbf2SRichard Henderson             .e_machine = ELF_HOST_MACHINE,
68275872bbf2SRichard Henderson             .e_version = EV_CURRENT,
68285872bbf2SRichard Henderson             .e_phoff = offsetof(struct ElfImage, phdr),
68295872bbf2SRichard Henderson             .e_shoff = offsetof(struct ElfImage, shdr),
68305872bbf2SRichard Henderson             .e_ehsize = sizeof(ElfW(Shdr)),
68315872bbf2SRichard Henderson             .e_phentsize = sizeof(ElfW(Phdr)),
68325872bbf2SRichard Henderson             .e_phnum = 1,
68335872bbf2SRichard Henderson             .e_shentsize = sizeof(ElfW(Shdr)),
68345872bbf2SRichard Henderson             .e_shnum = ARRAY_SIZE(img->shdr),
68355872bbf2SRichard Henderson             .e_shstrndx = ARRAY_SIZE(img->shdr) - 1,
6836abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS
6837abbb3eaeSRichard Henderson             .e_flags = ELF_HOST_FLAGS,
6838abbb3eaeSRichard Henderson #endif
6839abbb3eaeSRichard Henderson #ifdef ELF_OSABI
6840abbb3eaeSRichard Henderson             .e_ident[EI_OSABI] = ELF_OSABI,
6841abbb3eaeSRichard Henderson #endif
68425872bbf2SRichard Henderson         },
68435872bbf2SRichard Henderson         .phdr = {
68445872bbf2SRichard Henderson             .p_type = PT_LOAD,
68455872bbf2SRichard Henderson             .p_flags = PF_X,
68465872bbf2SRichard Henderson         },
68475872bbf2SRichard Henderson         .shdr = {
68485872bbf2SRichard Henderson             [0] = { .sh_type = SHT_NULL },
68495872bbf2SRichard Henderson             /* Trick: The contents of code_gen_buffer are not present in
68505872bbf2SRichard Henderson                this fake ELF file; that got allocated elsewhere.  Therefore
68515872bbf2SRichard Henderson                we mark .text as SHT_NOBITS (similar to .bss) so that readers
68525872bbf2SRichard Henderson                will not look for contents.  We can record any address.  */
68535872bbf2SRichard Henderson             [1] = { /* .text */
68545872bbf2SRichard Henderson                 .sh_type = SHT_NOBITS,
68555872bbf2SRichard Henderson                 .sh_flags = SHF_EXECINSTR | SHF_ALLOC,
68565872bbf2SRichard Henderson             },
68575872bbf2SRichard Henderson             [2] = { /* .debug_info */
68585872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
68595872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, di),
68605872bbf2SRichard Henderson                 .sh_size = sizeof(struct DebugInfo),
68615872bbf2SRichard Henderson             },
68625872bbf2SRichard Henderson             [3] = { /* .debug_abbrev */
68635872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
68645872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, da),
68655872bbf2SRichard Henderson                 .sh_size = sizeof(img->da),
68665872bbf2SRichard Henderson             },
68675872bbf2SRichard Henderson             [4] = { /* .debug_frame */
68685872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
68695872bbf2SRichard Henderson                 .sh_offset = sizeof(struct ElfImage),
68705872bbf2SRichard Henderson             },
68715872bbf2SRichard Henderson             [5] = { /* .symtab */
68725872bbf2SRichard Henderson                 .sh_type = SHT_SYMTAB,
68735872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, sym),
68745872bbf2SRichard Henderson                 .sh_size = sizeof(img->sym),
68755872bbf2SRichard Henderson                 .sh_info = 1,
68765872bbf2SRichard Henderson                 .sh_link = ARRAY_SIZE(img->shdr) - 1,
68775872bbf2SRichard Henderson                 .sh_entsize = sizeof(ElfW(Sym)),
68785872bbf2SRichard Henderson             },
68795872bbf2SRichard Henderson             [6] = { /* .strtab */
68805872bbf2SRichard Henderson                 .sh_type = SHT_STRTAB,
68815872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, str),
68825872bbf2SRichard Henderson                 .sh_size = sizeof(img->str),
68835872bbf2SRichard Henderson             }
68845872bbf2SRichard Henderson         },
68855872bbf2SRichard Henderson         .sym = {
68865872bbf2SRichard Henderson             [1] = { /* code_gen_buffer */
68875872bbf2SRichard Henderson                 .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC),
68885872bbf2SRichard Henderson                 .st_shndx = 1,
68895872bbf2SRichard Henderson             }
68905872bbf2SRichard Henderson         },
68915872bbf2SRichard Henderson         .di = {
68925872bbf2SRichard Henderson             .len = sizeof(struct DebugInfo) - 4,
68935872bbf2SRichard Henderson             .version = 2,
68945872bbf2SRichard Henderson             .ptr_size = sizeof(void *),
68955872bbf2SRichard Henderson             .cu_die = 1,
68965872bbf2SRichard Henderson             .cu_lang = 0x8001,  /* DW_LANG_Mips_Assembler */
68975872bbf2SRichard Henderson             .fn_die = 2,
68985872bbf2SRichard Henderson             .fn_name = "code_gen_buffer"
68995872bbf2SRichard Henderson         },
69005872bbf2SRichard Henderson         .da = {
69015872bbf2SRichard Henderson             1,          /* abbrev number (the cu) */
69025872bbf2SRichard Henderson             0x11, 1,    /* DW_TAG_compile_unit, has children */
69035872bbf2SRichard Henderson             0x13, 0x5,  /* DW_AT_language, DW_FORM_data2 */
69045872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
69055872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
69065872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
69075872bbf2SRichard Henderson             2,          /* abbrev number (the fn) */
69085872bbf2SRichard Henderson             0x2e, 0,    /* DW_TAG_subprogram, no children */
69095872bbf2SRichard Henderson             0x3, 0x8,   /* DW_AT_name, DW_FORM_string */
69105872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
69115872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
69125872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
69135872bbf2SRichard Henderson             0           /* no more abbrev */
69145872bbf2SRichard Henderson         },
69155872bbf2SRichard Henderson         .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0"
69165872bbf2SRichard Henderson                ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer",
6917813da627SRichard Henderson     };
6918813da627SRichard Henderson 
6919813da627SRichard Henderson     /* We only need a single jit entry; statically allocate it.  */
6920813da627SRichard Henderson     static struct jit_code_entry one_entry;
6921813da627SRichard Henderson 
69225872bbf2SRichard Henderson     uintptr_t buf = (uintptr_t)buf_ptr;
6923813da627SRichard Henderson     size_t img_size = sizeof(struct ElfImage) + debug_frame_size;
69242c90784aSRichard Henderson     DebugFrameHeader *dfh;
6925813da627SRichard Henderson 
69265872bbf2SRichard Henderson     img = g_malloc(img_size);
69275872bbf2SRichard Henderson     *img = img_template;
6928813da627SRichard Henderson 
69295872bbf2SRichard Henderson     img->phdr.p_vaddr = buf;
69305872bbf2SRichard Henderson     img->phdr.p_paddr = buf;
69315872bbf2SRichard Henderson     img->phdr.p_memsz = buf_size;
6932813da627SRichard Henderson 
69335872bbf2SRichard Henderson     img->shdr[1].sh_name = find_string(img->str, ".text");
69345872bbf2SRichard Henderson     img->shdr[1].sh_addr = buf;
69355872bbf2SRichard Henderson     img->shdr[1].sh_size = buf_size;
6936813da627SRichard Henderson 
69375872bbf2SRichard Henderson     img->shdr[2].sh_name = find_string(img->str, ".debug_info");
69385872bbf2SRichard Henderson     img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev");
69395872bbf2SRichard Henderson 
69405872bbf2SRichard Henderson     img->shdr[4].sh_name = find_string(img->str, ".debug_frame");
69415872bbf2SRichard Henderson     img->shdr[4].sh_size = debug_frame_size;
69425872bbf2SRichard Henderson 
69435872bbf2SRichard Henderson     img->shdr[5].sh_name = find_string(img->str, ".symtab");
69445872bbf2SRichard Henderson     img->shdr[6].sh_name = find_string(img->str, ".strtab");
69455872bbf2SRichard Henderson 
69465872bbf2SRichard Henderson     img->sym[1].st_name = find_string(img->str, "code_gen_buffer");
69475872bbf2SRichard Henderson     img->sym[1].st_value = buf;
69485872bbf2SRichard Henderson     img->sym[1].st_size = buf_size;
69495872bbf2SRichard Henderson 
69505872bbf2SRichard Henderson     img->di.cu_low_pc = buf;
695145aba097SRichard Henderson     img->di.cu_high_pc = buf + buf_size;
69525872bbf2SRichard Henderson     img->di.fn_low_pc = buf;
695345aba097SRichard Henderson     img->di.fn_high_pc = buf + buf_size;
6954813da627SRichard Henderson 
69552c90784aSRichard Henderson     dfh = (DebugFrameHeader *)(img + 1);
69562c90784aSRichard Henderson     memcpy(dfh, debug_frame, debug_frame_size);
69572c90784aSRichard Henderson     dfh->fde.func_start = buf;
69582c90784aSRichard Henderson     dfh->fde.func_len = buf_size;
69592c90784aSRichard Henderson 
6960813da627SRichard Henderson #ifdef DEBUG_JIT
6961813da627SRichard Henderson     /* Enable this block to be able to debug the ELF image file creation.
6962813da627SRichard Henderson        One can use readelf, objdump, or other inspection utilities.  */
6963813da627SRichard Henderson     {
6964eb6b2edfSBin Meng         g_autofree char *jit = g_strdup_printf("%s/qemu.jit", g_get_tmp_dir());
6965eb6b2edfSBin Meng         FILE *f = fopen(jit, "w+b");
6966813da627SRichard Henderson         if (f) {
69675872bbf2SRichard Henderson             if (fwrite(img, img_size, 1, f) != img_size) {
6968813da627SRichard Henderson                 /* Avoid stupid unused return value warning for fwrite.  */
6969813da627SRichard Henderson             }
6970813da627SRichard Henderson             fclose(f);
6971813da627SRichard Henderson         }
6972813da627SRichard Henderson     }
6973813da627SRichard Henderson #endif
6974813da627SRichard Henderson 
6975813da627SRichard Henderson     one_entry.symfile_addr = img;
6976813da627SRichard Henderson     one_entry.symfile_size = img_size;
6977813da627SRichard Henderson 
6978813da627SRichard Henderson     __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
6979813da627SRichard Henderson     __jit_debug_descriptor.relevant_entry = &one_entry;
6980813da627SRichard Henderson     __jit_debug_descriptor.first_entry = &one_entry;
6981813da627SRichard Henderson     __jit_debug_register_code();
6982813da627SRichard Henderson }
6983813da627SRichard Henderson #else
69845872bbf2SRichard Henderson /* No support for the feature.  Provide the entry point expected by exec.c,
69855872bbf2SRichard Henderson    and implement the internal function we declared earlier.  */
6986813da627SRichard Henderson 
6987755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size,
69882c90784aSRichard Henderson                                  const void *debug_frame,
69892c90784aSRichard Henderson                                  size_t debug_frame_size)
6990813da627SRichard Henderson {
6991813da627SRichard Henderson }
6992813da627SRichard Henderson 
6993755bf9e5SRichard Henderson void tcg_register_jit(const void *buf, size_t buf_size)
6994813da627SRichard Henderson {
6995813da627SRichard Henderson }
6996813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */
6997db432672SRichard Henderson 
6998db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec
6999db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...)
7000db432672SRichard Henderson {
7001db432672SRichard Henderson     g_assert_not_reached();
7002db432672SRichard Henderson }
7003db432672SRichard Henderson #endif
7004