xref: /qemu/tcg/tcg.c (revision d7ec12f83cbb63343dd6e76392241e16a58f41e8)
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"
39*d7ec12f8SRichard 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"
585584e2dbSIlya Leoshkevich #include "accel/tcg/perf.h"
597d478306SRichard Henderson #ifdef CONFIG_USER_ONLY
607d478306SRichard Henderson #include "exec/user/guest-base.h"
617d478306SRichard Henderson #endif
62c896fe29Sbellard 
63139c1837SPaolo Bonzini /* Forward declarations for functions declared in tcg-target.c.inc and
64ce151109SPeter Maydell    used here. */
65e4d58b41SRichard Henderson static void tcg_target_init(TCGContext *s);
66e4d58b41SRichard Henderson static void tcg_target_qemu_prologue(TCGContext *s);
676ac17786SRichard Henderson static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
682ba7fae2SRichard Henderson                         intptr_t value, intptr_t addend);
69c896fe29Sbellard 
70497a22ebSRichard Henderson /* The CIE and FDE header definitions will be common to all hosts.  */
71497a22ebSRichard Henderson typedef struct {
72497a22ebSRichard Henderson     uint32_t len __attribute__((aligned((sizeof(void *)))));
73497a22ebSRichard Henderson     uint32_t id;
74497a22ebSRichard Henderson     uint8_t version;
75497a22ebSRichard Henderson     char augmentation[1];
76497a22ebSRichard Henderson     uint8_t code_align;
77497a22ebSRichard Henderson     uint8_t data_align;
78497a22ebSRichard Henderson     uint8_t return_column;
79497a22ebSRichard Henderson } DebugFrameCIE;
80497a22ebSRichard Henderson 
81497a22ebSRichard Henderson typedef struct QEMU_PACKED {
82497a22ebSRichard Henderson     uint32_t len __attribute__((aligned((sizeof(void *)))));
83497a22ebSRichard Henderson     uint32_t cie_offset;
84edee2579SRichard Henderson     uintptr_t func_start;
85edee2579SRichard Henderson     uintptr_t func_len;
86497a22ebSRichard Henderson } DebugFrameFDEHeader;
87497a22ebSRichard Henderson 
882c90784aSRichard Henderson typedef struct QEMU_PACKED {
892c90784aSRichard Henderson     DebugFrameCIE cie;
902c90784aSRichard Henderson     DebugFrameFDEHeader fde;
912c90784aSRichard Henderson } DebugFrameHeader;
922c90784aSRichard Henderson 
932528f771SRichard Henderson typedef struct TCGLabelQemuLdst {
942528f771SRichard Henderson     bool is_ld;             /* qemu_ld: true, qemu_st: false */
952528f771SRichard Henderson     MemOpIdx oi;
962528f771SRichard Henderson     TCGType type;           /* result type of a load */
972528f771SRichard Henderson     TCGReg addrlo_reg;      /* reg index for low word of guest virtual addr */
982528f771SRichard Henderson     TCGReg addrhi_reg;      /* reg index for high word of guest virtual addr */
992528f771SRichard Henderson     TCGReg datalo_reg;      /* reg index for low word to be loaded or stored */
1002528f771SRichard Henderson     TCGReg datahi_reg;      /* reg index for high word to be loaded or stored */
1012528f771SRichard Henderson     const tcg_insn_unit *raddr;   /* addr of the next IR of qemu_ld/st IR */
1022528f771SRichard Henderson     tcg_insn_unit *label_ptr[2]; /* label pointers to be updated */
1032528f771SRichard Henderson     QSIMPLEQ_ENTRY(TCGLabelQemuLdst) next;
1042528f771SRichard Henderson } TCGLabelQemuLdst;
1052528f771SRichard Henderson 
106755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size,
1072c90784aSRichard Henderson                                  const void *debug_frame,
1082c90784aSRichard Henderson                                  size_t debug_frame_size)
109813da627SRichard Henderson     __attribute__((unused));
110813da627SRichard Henderson 
111139c1837SPaolo Bonzini /* Forward declarations for functions declared and used in tcg-target.c.inc. */
1129358fbbfSRichard Henderson static void tcg_out_tb_start(TCGContext *s);
1132a534affSRichard Henderson static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
114a05b5b9bSRichard Henderson                        intptr_t arg2);
11578113e83SRichard Henderson static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
116c0ad3001SStefan Weil static void tcg_out_movi(TCGContext *s, TCGType type,
1172a534affSRichard Henderson                          TCGReg ret, tcg_target_long arg);
118678155b2SRichard Henderson static void tcg_out_ext8s(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
119753e42eaSRichard Henderson static void tcg_out_ext16s(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
120d0e66c89SRichard Henderson static void tcg_out_ext8u(TCGContext *s, TCGReg ret, TCGReg arg);
121379afdffSRichard Henderson static void tcg_out_ext16u(TCGContext *s, TCGReg ret, TCGReg arg);
12252bf3398SRichard Henderson static void tcg_out_ext32s(TCGContext *s, TCGReg ret, TCGReg arg);
1239ecf5f61SRichard Henderson static void tcg_out_ext32u(TCGContext *s, TCGReg ret, TCGReg arg);
1249c6aa274SRichard Henderson static void tcg_out_exts_i32_i64(TCGContext *s, TCGReg ret, TCGReg arg);
125b9bfe000SRichard Henderson static void tcg_out_extu_i32_i64(TCGContext *s, TCGReg ret, TCGReg arg);
126b8b94ac6SRichard Henderson static void tcg_out_extrl_i64_i32(TCGContext *s, TCGReg ret, TCGReg arg);
127313bdea8SRichard Henderson static void tcg_out_addi_ptr(TCGContext *s, TCGReg, TCGReg, tcg_target_long);
128129f1f9eSRichard Henderson static bool tcg_out_xchg(TCGContext *s, TCGType type, TCGReg r1, TCGReg r2);
129b55a8d9dSRichard Henderson static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg);
130cf7d6b8eSRichard Henderson static void tcg_out_goto_tb(TCGContext *s, int which);
1315e8892dbSMiroslav Rezanina static void tcg_out_op(TCGContext *s, TCGOpcode opc,
1325e8892dbSMiroslav Rezanina                        const TCGArg args[TCG_MAX_OP_ARGS],
1335e8892dbSMiroslav Rezanina                        const int const_args[TCG_MAX_OP_ARGS]);
134d2fd745fSRichard Henderson #if TCG_TARGET_MAYBE_vec
135e7632cfaSRichard Henderson static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
136e7632cfaSRichard Henderson                             TCGReg dst, TCGReg src);
137d6ecb4a9SRichard Henderson static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
138d6ecb4a9SRichard Henderson                              TCGReg dst, TCGReg base, intptr_t offset);
1394e186175SRichard Henderson static void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece,
1404e186175SRichard Henderson                              TCGReg dst, int64_t arg);
1415e8892dbSMiroslav Rezanina static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
1425e8892dbSMiroslav Rezanina                            unsigned vecl, unsigned vece,
1435e8892dbSMiroslav Rezanina                            const TCGArg args[TCG_MAX_OP_ARGS],
1445e8892dbSMiroslav Rezanina                            const int const_args[TCG_MAX_OP_ARGS]);
145d2fd745fSRichard Henderson #else
146e7632cfaSRichard Henderson static inline bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
147e7632cfaSRichard Henderson                                    TCGReg dst, TCGReg src)
148e7632cfaSRichard Henderson {
149e7632cfaSRichard Henderson     g_assert_not_reached();
150e7632cfaSRichard Henderson }
151d6ecb4a9SRichard Henderson static inline bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
152d6ecb4a9SRichard Henderson                                     TCGReg dst, TCGReg base, intptr_t offset)
153d6ecb4a9SRichard Henderson {
154d6ecb4a9SRichard Henderson     g_assert_not_reached();
155d6ecb4a9SRichard Henderson }
1564e186175SRichard Henderson static inline void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece,
1574e186175SRichard Henderson                                     TCGReg dst, int64_t arg)
158e7632cfaSRichard Henderson {
159e7632cfaSRichard Henderson     g_assert_not_reached();
160e7632cfaSRichard Henderson }
1615e8892dbSMiroslav Rezanina static inline void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
1625e8892dbSMiroslav Rezanina                                   unsigned vecl, unsigned vece,
1635e8892dbSMiroslav Rezanina                                   const TCGArg args[TCG_MAX_OP_ARGS],
1645e8892dbSMiroslav Rezanina                                   const int const_args[TCG_MAX_OP_ARGS])
165d2fd745fSRichard Henderson {
166d2fd745fSRichard Henderson     g_assert_not_reached();
167d2fd745fSRichard Henderson }
168d2fd745fSRichard Henderson #endif
1692a534affSRichard Henderson static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
170a05b5b9bSRichard Henderson                        intptr_t arg2);
17159d7c14eSRichard Henderson static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
17259d7c14eSRichard Henderson                         TCGReg base, intptr_t ofs);
1737b7d8b2dSRichard Henderson static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target,
174cee44b03SRichard Henderson                          const TCGHelperInfo *info);
1755e3d0c19SRichard Henderson static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot);
176ebe92db2SJiajie Chen static bool tcg_target_const_match(int64_t val, TCGType type, int ct, int vece);
177659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
178aeee05f5SRichard Henderson static int tcg_out_ldst_finalize(TCGContext *s);
179659ef5cbSRichard Henderson #endif
180c896fe29Sbellard 
1818429a1caSRichard Henderson typedef struct TCGLdstHelperParam {
1828429a1caSRichard Henderson     TCGReg (*ra_gen)(TCGContext *s, const TCGLabelQemuLdst *l, int arg_reg);
1838429a1caSRichard Henderson     unsigned ntmp;
1848429a1caSRichard Henderson     int tmp[3];
1858429a1caSRichard Henderson } TCGLdstHelperParam;
1868429a1caSRichard Henderson 
1878429a1caSRichard Henderson static void tcg_out_ld_helper_args(TCGContext *s, const TCGLabelQemuLdst *l,
1888429a1caSRichard Henderson                                    const TCGLdstHelperParam *p)
1898429a1caSRichard Henderson     __attribute__((unused));
1908429a1caSRichard Henderson static void tcg_out_ld_helper_ret(TCGContext *s, const TCGLabelQemuLdst *l,
1918429a1caSRichard Henderson                                   bool load_sign, const TCGLdstHelperParam *p)
1928429a1caSRichard Henderson     __attribute__((unused));
1938429a1caSRichard Henderson static void tcg_out_st_helper_args(TCGContext *s, const TCGLabelQemuLdst *l,
1948429a1caSRichard Henderson                                    const TCGLdstHelperParam *p)
1958429a1caSRichard Henderson     __attribute__((unused));
1968429a1caSRichard Henderson 
197de95016dSRichard Henderson static void * const qemu_ld_helpers[MO_SSIZE + 1] __attribute__((unused)) = {
1980cadc1edSRichard Henderson     [MO_UB] = helper_ldub_mmu,
1990cadc1edSRichard Henderson     [MO_SB] = helper_ldsb_mmu,
2000cadc1edSRichard Henderson     [MO_UW] = helper_lduw_mmu,
2010cadc1edSRichard Henderson     [MO_SW] = helper_ldsw_mmu,
2020cadc1edSRichard Henderson     [MO_UL] = helper_ldul_mmu,
2030cadc1edSRichard Henderson     [MO_UQ] = helper_ldq_mmu,
2040cadc1edSRichard Henderson #if TCG_TARGET_REG_BITS == 64
2050cadc1edSRichard Henderson     [MO_SL] = helper_ldsl_mmu,
206ebebea53SRichard Henderson     [MO_128] = helper_ld16_mmu,
2070cadc1edSRichard Henderson #endif
2080cadc1edSRichard Henderson };
2090cadc1edSRichard Henderson 
210de95016dSRichard Henderson static void * const qemu_st_helpers[MO_SIZE + 1] __attribute__((unused)) = {
2110cadc1edSRichard Henderson     [MO_8]  = helper_stb_mmu,
2120cadc1edSRichard Henderson     [MO_16] = helper_stw_mmu,
2130cadc1edSRichard Henderson     [MO_32] = helper_stl_mmu,
2140cadc1edSRichard Henderson     [MO_64] = helper_stq_mmu,
215ebebea53SRichard Henderson #if TCG_TARGET_REG_BITS == 64
216ebebea53SRichard Henderson     [MO_128] = helper_st16_mmu,
217ebebea53SRichard Henderson #endif
2180cadc1edSRichard Henderson };
2190cadc1edSRichard Henderson 
220e63b8a29SRichard Henderson typedef struct {
221e63b8a29SRichard Henderson     MemOp atom;   /* lg2 bits of atomicity required */
222e63b8a29SRichard Henderson     MemOp align;  /* lg2 bits of alignment to use */
223e63b8a29SRichard Henderson } TCGAtomAlign;
224e63b8a29SRichard Henderson 
225e63b8a29SRichard Henderson static TCGAtomAlign atom_and_align_for_opc(TCGContext *s, MemOp opc,
226e63b8a29SRichard Henderson                                            MemOp host_atom, bool allow_two_ops)
227e63b8a29SRichard Henderson     __attribute__((unused));
228e63b8a29SRichard Henderson 
22942eb6dfcSRichard Henderson TCGContext tcg_init_ctx;
23042eb6dfcSRichard Henderson __thread TCGContext *tcg_ctx;
23142eb6dfcSRichard Henderson 
2325ff7258cSRichard Henderson TCGContext **tcg_ctxs;
2330e2d61cfSRichard Henderson unsigned int tcg_cur_ctxs;
2340e2d61cfSRichard Henderson unsigned int tcg_max_ctxs;
235ad75a51eSRichard Henderson TCGv_env tcg_env;
236c8bc1168SRichard Henderson const void *tcg_code_gen_epilogue;
237db0c51a3SRichard Henderson uintptr_t tcg_splitwx_diff;
238df2cce29SEmilio G. Cota 
239b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
240b91ccb31SRichard Henderson tcg_prologue_fn *tcg_qemu_tb_exec;
241b91ccb31SRichard Henderson #endif
242b91ccb31SRichard Henderson 
243d2fd745fSRichard Henderson static TCGRegSet tcg_target_available_regs[TCG_TYPE_COUNT];
244b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs;
245c896fe29Sbellard 
2461813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1
2474196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v)
248c896fe29Sbellard {
249c896fe29Sbellard     *s->code_ptr++ = v;
250c896fe29Sbellard }
251c896fe29Sbellard 
2524196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p,
2534196dca6SPeter Maydell                                                       uint8_t v)
2545c53bb81SPeter Maydell {
2551813e175SRichard Henderson     *p = v;
2565c53bb81SPeter Maydell }
2571813e175SRichard Henderson #endif
2585c53bb81SPeter Maydell 
2591813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2
2604196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v)
261c896fe29Sbellard {
2621813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
2631813e175SRichard Henderson         *s->code_ptr++ = v;
2641813e175SRichard Henderson     } else {
2651813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2664387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2671813e175SRichard Henderson         s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE);
2681813e175SRichard Henderson     }
269c896fe29Sbellard }
270c896fe29Sbellard 
2714196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p,
2724196dca6SPeter Maydell                                                        uint16_t v)
2735c53bb81SPeter Maydell {
2741813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
2751813e175SRichard Henderson         *p = v;
2761813e175SRichard Henderson     } else {
2775c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2785c53bb81SPeter Maydell     }
2791813e175SRichard Henderson }
2801813e175SRichard Henderson #endif
2815c53bb81SPeter Maydell 
2821813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4
2834196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v)
284c896fe29Sbellard {
2851813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
2861813e175SRichard Henderson         *s->code_ptr++ = v;
2871813e175SRichard Henderson     } else {
2881813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2894387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2901813e175SRichard Henderson         s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE);
2911813e175SRichard Henderson     }
292c896fe29Sbellard }
293c896fe29Sbellard 
2944196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p,
2954196dca6SPeter Maydell                                                        uint32_t v)
2965c53bb81SPeter Maydell {
2971813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
2981813e175SRichard Henderson         *p = v;
2991813e175SRichard Henderson     } else {
3005c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
3015c53bb81SPeter Maydell     }
3021813e175SRichard Henderson }
3031813e175SRichard Henderson #endif
3045c53bb81SPeter Maydell 
3051813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 8
3064196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v)
307ac26eb69SRichard Henderson {
3081813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
3091813e175SRichard Henderson         *s->code_ptr++ = v;
3101813e175SRichard Henderson     } else {
3111813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
3124387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
3131813e175SRichard Henderson         s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE);
3141813e175SRichard Henderson     }
315ac26eb69SRichard Henderson }
316ac26eb69SRichard Henderson 
3174196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p,
3184196dca6SPeter Maydell                                                        uint64_t v)
3195c53bb81SPeter Maydell {
3201813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
3211813e175SRichard Henderson         *p = v;
3221813e175SRichard Henderson     } else {
3235c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
3245c53bb81SPeter Maydell     }
3251813e175SRichard Henderson }
3261813e175SRichard Henderson #endif
3275c53bb81SPeter Maydell 
328c896fe29Sbellard /* label relocation processing */
329c896fe29Sbellard 
3301813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
331bec16311SRichard Henderson                           TCGLabel *l, intptr_t addend)
332c896fe29Sbellard {
3337ecd02a0SRichard Henderson     TCGRelocation *r = tcg_malloc(sizeof(TCGRelocation));
334c896fe29Sbellard 
335c896fe29Sbellard     r->type = type;
336c896fe29Sbellard     r->ptr = code_ptr;
337c896fe29Sbellard     r->addend = addend;
3387ecd02a0SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next);
339c896fe29Sbellard }
340c896fe29Sbellard 
34192ab8e7dSRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l)
342c896fe29Sbellard {
343eabb7b91SAurelien Jarno     tcg_debug_assert(!l->has_value);
344c896fe29Sbellard     l->has_value = 1;
34592ab8e7dSRichard Henderson     l->u.value_ptr = tcg_splitwx_to_rx(s->code_ptr);
346c896fe29Sbellard }
347c896fe29Sbellard 
34842a268c2SRichard Henderson TCGLabel *gen_new_label(void)
349c896fe29Sbellard {
350b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
35151e3972cSRichard Henderson     TCGLabel *l = tcg_malloc(sizeof(TCGLabel));
352c896fe29Sbellard 
3537ecd02a0SRichard Henderson     memset(l, 0, sizeof(TCGLabel));
3547ecd02a0SRichard Henderson     l->id = s->nb_labels++;
355f85b1fc4SRichard Henderson     QSIMPLEQ_INIT(&l->branches);
3567ecd02a0SRichard Henderson     QSIMPLEQ_INIT(&l->relocs);
3577ecd02a0SRichard Henderson 
358bef16ab4SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&s->labels, l, next);
35942a268c2SRichard Henderson 
36042a268c2SRichard Henderson     return l;
361c896fe29Sbellard }
362c896fe29Sbellard 
3637ecd02a0SRichard Henderson static bool tcg_resolve_relocs(TCGContext *s)
3647ecd02a0SRichard Henderson {
3657ecd02a0SRichard Henderson     TCGLabel *l;
3667ecd02a0SRichard Henderson 
3677ecd02a0SRichard Henderson     QSIMPLEQ_FOREACH(l, &s->labels, next) {
3687ecd02a0SRichard Henderson         TCGRelocation *r;
3697ecd02a0SRichard Henderson         uintptr_t value = l->u.value;
3707ecd02a0SRichard Henderson 
3717ecd02a0SRichard Henderson         QSIMPLEQ_FOREACH(r, &l->relocs, next) {
3727ecd02a0SRichard Henderson             if (!patch_reloc(r->ptr, r->type, value, r->addend)) {
3737ecd02a0SRichard Henderson                 return false;
3747ecd02a0SRichard Henderson             }
3757ecd02a0SRichard Henderson         }
3767ecd02a0SRichard Henderson     }
3777ecd02a0SRichard Henderson     return true;
3787ecd02a0SRichard Henderson }
3797ecd02a0SRichard Henderson 
3809f754620SRichard Henderson static void set_jmp_reset_offset(TCGContext *s, int which)
3819f754620SRichard Henderson {
382f14bed3fSRichard Henderson     /*
383f14bed3fSRichard Henderson      * We will check for overflow at the end of the opcode loop in
384f14bed3fSRichard Henderson      * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX.
385f14bed3fSRichard Henderson      */
386b7e4afbdSRichard Henderson     s->gen_tb->jmp_reset_offset[which] = tcg_current_code_size(s);
3879f754620SRichard Henderson }
3889f754620SRichard Henderson 
389b52a2c03SRichard Henderson static void G_GNUC_UNUSED set_jmp_insn_offset(TCGContext *s, int which)
390b52a2c03SRichard Henderson {
391b52a2c03SRichard Henderson     /*
392b52a2c03SRichard Henderson      * We will check for overflow at the end of the opcode loop in
393b52a2c03SRichard Henderson      * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX.
394b52a2c03SRichard Henderson      */
3959da6079bSRichard Henderson     s->gen_tb->jmp_insn_offset[which] = tcg_current_code_size(s);
396b52a2c03SRichard Henderson }
397b52a2c03SRichard Henderson 
398becc452aSRichard Henderson static uintptr_t G_GNUC_UNUSED get_jmp_target_addr(TCGContext *s, int which)
399becc452aSRichard Henderson {
400becc452aSRichard Henderson     /*
401becc452aSRichard Henderson      * Return the read-execute version of the pointer, for the benefit
402becc452aSRichard Henderson      * of any pc-relative addressing mode.
403becc452aSRichard Henderson      */
4049da6079bSRichard Henderson     return (uintptr_t)tcg_splitwx_to_rx(&s->gen_tb->jmp_target_addr[which]);
405becc452aSRichard Henderson }
406becc452aSRichard Henderson 
407d0a9bb5eSRichard Henderson #if defined(CONFIG_SOFTMMU) && !defined(CONFIG_TCG_INTERPRETER)
408d0a9bb5eSRichard Henderson static int tlb_mask_table_ofs(TCGContext *s, int which)
409d0a9bb5eSRichard Henderson {
4107857ee11SRichard Henderson     return (offsetof(CPUNegativeOffsetState, tlb.f[which]) -
4117857ee11SRichard Henderson             sizeof(CPUNegativeOffsetState));
412d0a9bb5eSRichard Henderson }
413d0a9bb5eSRichard Henderson #endif
414d0a9bb5eSRichard Henderson 
415db6b7d0cSRichard Henderson /* Signal overflow, starting over with fewer guest insns. */
4168905770bSMarc-André Lureau static G_NORETURN
4178905770bSMarc-André Lureau void tcg_raise_tb_overflow(TCGContext *s)
418db6b7d0cSRichard Henderson {
419db6b7d0cSRichard Henderson     siglongjmp(s->jmp_trans, -2);
420db6b7d0cSRichard Henderson }
421db6b7d0cSRichard Henderson 
4228429a1caSRichard Henderson /*
4238429a1caSRichard Henderson  * Used by tcg_out_movext{1,2} to hold the arguments for tcg_out_movext.
4248429a1caSRichard Henderson  * By the time we arrive at tcg_out_movext1, @dst is always a TCGReg.
4258429a1caSRichard Henderson  *
4268429a1caSRichard Henderson  * However, tcg_out_helper_load_slots reuses this field to hold an
4278429a1caSRichard Henderson  * argument slot number (which may designate a argument register or an
4288429a1caSRichard Henderson  * argument stack slot), converting to TCGReg once all arguments that
4298429a1caSRichard Henderson  * are destined for the stack are processed.
4308429a1caSRichard Henderson  */
431129f1f9eSRichard Henderson typedef struct TCGMovExtend {
4328429a1caSRichard Henderson     unsigned dst;
433129f1f9eSRichard Henderson     TCGReg src;
434129f1f9eSRichard Henderson     TCGType dst_type;
435129f1f9eSRichard Henderson     TCGType src_type;
436129f1f9eSRichard Henderson     MemOp src_ext;
437129f1f9eSRichard Henderson } TCGMovExtend;
438129f1f9eSRichard Henderson 
439b3dfd5fcSRichard Henderson /**
440b3dfd5fcSRichard Henderson  * tcg_out_movext -- move and extend
441b3dfd5fcSRichard Henderson  * @s: tcg context
442b3dfd5fcSRichard Henderson  * @dst_type: integral type for destination
443b3dfd5fcSRichard Henderson  * @dst: destination register
444b3dfd5fcSRichard Henderson  * @src_type: integral type for source
445b3dfd5fcSRichard Henderson  * @src_ext: extension to apply to source
446b3dfd5fcSRichard Henderson  * @src: source register
447b3dfd5fcSRichard Henderson  *
448b3dfd5fcSRichard Henderson  * Move or extend @src into @dst, depending on @src_ext and the types.
449b3dfd5fcSRichard Henderson  */
450129f1f9eSRichard Henderson static void tcg_out_movext(TCGContext *s, TCGType dst_type, TCGReg dst,
451b3dfd5fcSRichard Henderson                            TCGType src_type, MemOp src_ext, TCGReg src)
452b3dfd5fcSRichard Henderson {
453b3dfd5fcSRichard Henderson     switch (src_ext) {
454b3dfd5fcSRichard Henderson     case MO_UB:
455b3dfd5fcSRichard Henderson         tcg_out_ext8u(s, dst, src);
456b3dfd5fcSRichard Henderson         break;
457b3dfd5fcSRichard Henderson     case MO_SB:
458b3dfd5fcSRichard Henderson         tcg_out_ext8s(s, dst_type, dst, src);
459b3dfd5fcSRichard Henderson         break;
460b3dfd5fcSRichard Henderson     case MO_UW:
461b3dfd5fcSRichard Henderson         tcg_out_ext16u(s, dst, src);
462b3dfd5fcSRichard Henderson         break;
463b3dfd5fcSRichard Henderson     case MO_SW:
464b3dfd5fcSRichard Henderson         tcg_out_ext16s(s, dst_type, dst, src);
465b3dfd5fcSRichard Henderson         break;
466b3dfd5fcSRichard Henderson     case MO_UL:
467b3dfd5fcSRichard Henderson     case MO_SL:
468b3dfd5fcSRichard Henderson         if (dst_type == TCG_TYPE_I32) {
469b3dfd5fcSRichard Henderson             if (src_type == TCG_TYPE_I32) {
470b3dfd5fcSRichard Henderson                 tcg_out_mov(s, TCG_TYPE_I32, dst, src);
471b3dfd5fcSRichard Henderson             } else {
472b3dfd5fcSRichard Henderson                 tcg_out_extrl_i64_i32(s, dst, src);
473b3dfd5fcSRichard Henderson             }
474b3dfd5fcSRichard Henderson         } else if (src_type == TCG_TYPE_I32) {
475b3dfd5fcSRichard Henderson             if (src_ext & MO_SIGN) {
476b3dfd5fcSRichard Henderson                 tcg_out_exts_i32_i64(s, dst, src);
477b3dfd5fcSRichard Henderson             } else {
478b3dfd5fcSRichard Henderson                 tcg_out_extu_i32_i64(s, dst, src);
479b3dfd5fcSRichard Henderson             }
480b3dfd5fcSRichard Henderson         } else {
481b3dfd5fcSRichard Henderson             if (src_ext & MO_SIGN) {
482b3dfd5fcSRichard Henderson                 tcg_out_ext32s(s, dst, src);
483b3dfd5fcSRichard Henderson             } else {
484b3dfd5fcSRichard Henderson                 tcg_out_ext32u(s, dst, src);
485b3dfd5fcSRichard Henderson             }
486b3dfd5fcSRichard Henderson         }
487b3dfd5fcSRichard Henderson         break;
488b3dfd5fcSRichard Henderson     case MO_UQ:
489b3dfd5fcSRichard Henderson         tcg_debug_assert(TCG_TARGET_REG_BITS == 64);
490b3dfd5fcSRichard Henderson         if (dst_type == TCG_TYPE_I32) {
491b3dfd5fcSRichard Henderson             tcg_out_extrl_i64_i32(s, dst, src);
492b3dfd5fcSRichard Henderson         } else {
493b3dfd5fcSRichard Henderson             tcg_out_mov(s, TCG_TYPE_I64, dst, src);
494b3dfd5fcSRichard Henderson         }
495b3dfd5fcSRichard Henderson         break;
496b3dfd5fcSRichard Henderson     default:
497b3dfd5fcSRichard Henderson         g_assert_not_reached();
498b3dfd5fcSRichard Henderson     }
499b3dfd5fcSRichard Henderson }
500b3dfd5fcSRichard Henderson 
501129f1f9eSRichard Henderson /* Minor variations on a theme, using a structure. */
502129f1f9eSRichard Henderson static void tcg_out_movext1_new_src(TCGContext *s, const TCGMovExtend *i,
503129f1f9eSRichard Henderson                                     TCGReg src)
504129f1f9eSRichard Henderson {
505129f1f9eSRichard Henderson     tcg_out_movext(s, i->dst_type, i->dst, i->src_type, i->src_ext, src);
506129f1f9eSRichard Henderson }
507129f1f9eSRichard Henderson 
508129f1f9eSRichard Henderson static void tcg_out_movext1(TCGContext *s, const TCGMovExtend *i)
509129f1f9eSRichard Henderson {
510129f1f9eSRichard Henderson     tcg_out_movext1_new_src(s, i, i->src);
511129f1f9eSRichard Henderson }
512129f1f9eSRichard Henderson 
513129f1f9eSRichard Henderson /**
514129f1f9eSRichard Henderson  * tcg_out_movext2 -- move and extend two pair
515129f1f9eSRichard Henderson  * @s: tcg context
516129f1f9eSRichard Henderson  * @i1: first move description
517129f1f9eSRichard Henderson  * @i2: second move description
518129f1f9eSRichard Henderson  * @scratch: temporary register, or -1 for none
519129f1f9eSRichard Henderson  *
520129f1f9eSRichard Henderson  * As tcg_out_movext, for both @i1 and @i2, caring for overlap
521129f1f9eSRichard Henderson  * between the sources and destinations.
522129f1f9eSRichard Henderson  */
523129f1f9eSRichard Henderson 
5248429a1caSRichard Henderson static void tcg_out_movext2(TCGContext *s, const TCGMovExtend *i1,
525129f1f9eSRichard Henderson                             const TCGMovExtend *i2, int scratch)
526129f1f9eSRichard Henderson {
527129f1f9eSRichard Henderson     TCGReg src1 = i1->src;
528129f1f9eSRichard Henderson     TCGReg src2 = i2->src;
529129f1f9eSRichard Henderson 
530129f1f9eSRichard Henderson     if (i1->dst != src2) {
531129f1f9eSRichard Henderson         tcg_out_movext1(s, i1);
532129f1f9eSRichard Henderson         tcg_out_movext1(s, i2);
533129f1f9eSRichard Henderson         return;
534129f1f9eSRichard Henderson     }
535129f1f9eSRichard Henderson     if (i2->dst == src1) {
536129f1f9eSRichard Henderson         TCGType src1_type = i1->src_type;
537129f1f9eSRichard Henderson         TCGType src2_type = i2->src_type;
538129f1f9eSRichard Henderson 
539129f1f9eSRichard Henderson         if (tcg_out_xchg(s, MAX(src1_type, src2_type), src1, src2)) {
540129f1f9eSRichard Henderson             /* The data is now in the correct registers, now extend. */
541129f1f9eSRichard Henderson             src1 = i2->src;
542129f1f9eSRichard Henderson             src2 = i1->src;
543129f1f9eSRichard Henderson         } else {
544129f1f9eSRichard Henderson             tcg_debug_assert(scratch >= 0);
545129f1f9eSRichard Henderson             tcg_out_mov(s, src1_type, scratch, src1);
546129f1f9eSRichard Henderson             src1 = scratch;
547129f1f9eSRichard Henderson         }
548129f1f9eSRichard Henderson     }
549129f1f9eSRichard Henderson     tcg_out_movext1_new_src(s, i2, src2);
550129f1f9eSRichard Henderson     tcg_out_movext1_new_src(s, i1, src1);
551129f1f9eSRichard Henderson }
552129f1f9eSRichard Henderson 
5532462e30eSRichard Henderson /**
5542462e30eSRichard Henderson  * tcg_out_movext3 -- move and extend three pair
5552462e30eSRichard Henderson  * @s: tcg context
5562462e30eSRichard Henderson  * @i1: first move description
5572462e30eSRichard Henderson  * @i2: second move description
5582462e30eSRichard Henderson  * @i3: third move description
5592462e30eSRichard Henderson  * @scratch: temporary register, or -1 for none
5602462e30eSRichard Henderson  *
5612462e30eSRichard Henderson  * As tcg_out_movext, for all of @i1, @i2 and @i3, caring for overlap
5622462e30eSRichard Henderson  * between the sources and destinations.
5632462e30eSRichard Henderson  */
5642462e30eSRichard Henderson 
5652462e30eSRichard Henderson static void tcg_out_movext3(TCGContext *s, const TCGMovExtend *i1,
5662462e30eSRichard Henderson                             const TCGMovExtend *i2, const TCGMovExtend *i3,
5672462e30eSRichard Henderson                             int scratch)
5682462e30eSRichard Henderson {
5692462e30eSRichard Henderson     TCGReg src1 = i1->src;
5702462e30eSRichard Henderson     TCGReg src2 = i2->src;
5712462e30eSRichard Henderson     TCGReg src3 = i3->src;
5722462e30eSRichard Henderson 
5732462e30eSRichard Henderson     if (i1->dst != src2 && i1->dst != src3) {
5742462e30eSRichard Henderson         tcg_out_movext1(s, i1);
5752462e30eSRichard Henderson         tcg_out_movext2(s, i2, i3, scratch);
5762462e30eSRichard Henderson         return;
5772462e30eSRichard Henderson     }
5782462e30eSRichard Henderson     if (i2->dst != src1 && i2->dst != src3) {
5792462e30eSRichard Henderson         tcg_out_movext1(s, i2);
5802462e30eSRichard Henderson         tcg_out_movext2(s, i1, i3, scratch);
5812462e30eSRichard Henderson         return;
5822462e30eSRichard Henderson     }
5832462e30eSRichard Henderson     if (i3->dst != src1 && i3->dst != src2) {
5842462e30eSRichard Henderson         tcg_out_movext1(s, i3);
5852462e30eSRichard Henderson         tcg_out_movext2(s, i1, i2, scratch);
5862462e30eSRichard Henderson         return;
5872462e30eSRichard Henderson     }
5882462e30eSRichard Henderson 
5892462e30eSRichard Henderson     /*
5902462e30eSRichard Henderson      * There is a cycle.  Since there are only 3 nodes, the cycle is
5912462e30eSRichard Henderson      * either "clockwise" or "anti-clockwise", and can be solved with
5922462e30eSRichard Henderson      * a single scratch or two xchg.
5932462e30eSRichard Henderson      */
5942462e30eSRichard Henderson     if (i1->dst == src2 && i2->dst == src3 && i3->dst == src1) {
5952462e30eSRichard Henderson         /* "Clockwise" */
5962462e30eSRichard Henderson         if (tcg_out_xchg(s, MAX(i1->src_type, i2->src_type), src1, src2)) {
5972462e30eSRichard Henderson             tcg_out_xchg(s, MAX(i2->src_type, i3->src_type), src2, src3);
5982462e30eSRichard Henderson             /* The data is now in the correct registers, now extend. */
5992462e30eSRichard Henderson             tcg_out_movext1_new_src(s, i1, i1->dst);
6002462e30eSRichard Henderson             tcg_out_movext1_new_src(s, i2, i2->dst);
6012462e30eSRichard Henderson             tcg_out_movext1_new_src(s, i3, i3->dst);
6022462e30eSRichard Henderson         } else {
6032462e30eSRichard Henderson             tcg_debug_assert(scratch >= 0);
6042462e30eSRichard Henderson             tcg_out_mov(s, i1->src_type, scratch, src1);
6052462e30eSRichard Henderson             tcg_out_movext1(s, i3);
6062462e30eSRichard Henderson             tcg_out_movext1(s, i2);
6072462e30eSRichard Henderson             tcg_out_movext1_new_src(s, i1, scratch);
6082462e30eSRichard Henderson         }
6092462e30eSRichard Henderson     } else if (i1->dst == src3 && i2->dst == src1 && i3->dst == src2) {
6102462e30eSRichard Henderson         /* "Anti-clockwise" */
6112462e30eSRichard Henderson         if (tcg_out_xchg(s, MAX(i2->src_type, i3->src_type), src2, src3)) {
6122462e30eSRichard Henderson             tcg_out_xchg(s, MAX(i1->src_type, i2->src_type), src1, src2);
6132462e30eSRichard Henderson             /* The data is now in the correct registers, now extend. */
6142462e30eSRichard Henderson             tcg_out_movext1_new_src(s, i1, i1->dst);
6152462e30eSRichard Henderson             tcg_out_movext1_new_src(s, i2, i2->dst);
6162462e30eSRichard Henderson             tcg_out_movext1_new_src(s, i3, i3->dst);
6172462e30eSRichard Henderson         } else {
6182462e30eSRichard Henderson             tcg_debug_assert(scratch >= 0);
6192462e30eSRichard Henderson             tcg_out_mov(s, i1->src_type, scratch, src1);
6202462e30eSRichard Henderson             tcg_out_movext1(s, i2);
6212462e30eSRichard Henderson             tcg_out_movext1(s, i3);
6222462e30eSRichard Henderson             tcg_out_movext1_new_src(s, i1, scratch);
6232462e30eSRichard Henderson         }
6242462e30eSRichard Henderson     } else {
6252462e30eSRichard Henderson         g_assert_not_reached();
6262462e30eSRichard Henderson     }
6272462e30eSRichard Henderson }
6282462e30eSRichard Henderson 
6294c22e840SRichard Henderson #define C_PFX1(P, A)                    P##A
6304c22e840SRichard Henderson #define C_PFX2(P, A, B)                 P##A##_##B
6314c22e840SRichard Henderson #define C_PFX3(P, A, B, C)              P##A##_##B##_##C
6324c22e840SRichard Henderson #define C_PFX4(P, A, B, C, D)           P##A##_##B##_##C##_##D
6334c22e840SRichard Henderson #define C_PFX5(P, A, B, C, D, E)        P##A##_##B##_##C##_##D##_##E
6344c22e840SRichard Henderson #define C_PFX6(P, A, B, C, D, E, F)     P##A##_##B##_##C##_##D##_##E##_##F
6354c22e840SRichard Henderson 
6364c22e840SRichard Henderson /* Define an enumeration for the various combinations. */
6374c22e840SRichard Henderson 
6384c22e840SRichard Henderson #define C_O0_I1(I1)                     C_PFX1(c_o0_i1_, I1),
6394c22e840SRichard Henderson #define C_O0_I2(I1, I2)                 C_PFX2(c_o0_i2_, I1, I2),
6404c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3)             C_PFX3(c_o0_i3_, I1, I2, I3),
6414c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4)         C_PFX4(c_o0_i4_, I1, I2, I3, I4),
6424c22e840SRichard Henderson 
6434c22e840SRichard Henderson #define C_O1_I1(O1, I1)                 C_PFX2(c_o1_i1_, O1, I1),
6444c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2)             C_PFX3(c_o1_i2_, O1, I1, I2),
6454c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3)         C_PFX4(c_o1_i3_, O1, I1, I2, I3),
6464c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4)     C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4),
6474c22e840SRichard Henderson 
6484c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2)             C_PFX3(c_n1_i2_, O1, I1, I2),
6494c22e840SRichard Henderson 
6504c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1)             C_PFX3(c_o2_i1_, O1, O2, I1),
6514c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2)         C_PFX4(c_o2_i2_, O1, O2, I1, I2),
6524c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3)     C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3),
6534c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4),
65422d2e535SIlya Leoshkevich #define C_N1_O1_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_n1_o1_i4_, O1, O2, I1, I2, I3, I4),
6554c22e840SRichard Henderson 
6564c22e840SRichard Henderson typedef enum {
6574c22e840SRichard Henderson #include "tcg-target-con-set.h"
6584c22e840SRichard Henderson } TCGConstraintSetIndex;
6594c22e840SRichard Henderson 
6604c22e840SRichard Henderson static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode);
6614c22e840SRichard Henderson 
6624c22e840SRichard Henderson #undef C_O0_I1
6634c22e840SRichard Henderson #undef C_O0_I2
6644c22e840SRichard Henderson #undef C_O0_I3
6654c22e840SRichard Henderson #undef C_O0_I4
6664c22e840SRichard Henderson #undef C_O1_I1
6674c22e840SRichard Henderson #undef C_O1_I2
6684c22e840SRichard Henderson #undef C_O1_I3
6694c22e840SRichard Henderson #undef C_O1_I4
6704c22e840SRichard Henderson #undef C_N1_I2
6714c22e840SRichard Henderson #undef C_O2_I1
6724c22e840SRichard Henderson #undef C_O2_I2
6734c22e840SRichard Henderson #undef C_O2_I3
6744c22e840SRichard Henderson #undef C_O2_I4
67522d2e535SIlya Leoshkevich #undef C_N1_O1_I4
6764c22e840SRichard Henderson 
6774c22e840SRichard Henderson /* Put all of the constraint sets into an array, indexed by the enum. */
6784c22e840SRichard Henderson 
6794c22e840SRichard Henderson #define C_O0_I1(I1)                     { .args_ct_str = { #I1 } },
6804c22e840SRichard Henderson #define C_O0_I2(I1, I2)                 { .args_ct_str = { #I1, #I2 } },
6814c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3)             { .args_ct_str = { #I1, #I2, #I3 } },
6824c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4)         { .args_ct_str = { #I1, #I2, #I3, #I4 } },
6834c22e840SRichard Henderson 
6844c22e840SRichard Henderson #define C_O1_I1(O1, I1)                 { .args_ct_str = { #O1, #I1 } },
6854c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2)             { .args_ct_str = { #O1, #I1, #I2 } },
6864c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3)         { .args_ct_str = { #O1, #I1, #I2, #I3 } },
6874c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4)     { .args_ct_str = { #O1, #I1, #I2, #I3, #I4 } },
6884c22e840SRichard Henderson 
6894c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2)             { .args_ct_str = { "&" #O1, #I1, #I2 } },
6904c22e840SRichard Henderson 
6914c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1)             { .args_ct_str = { #O1, #O2, #I1 } },
6924c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2)         { .args_ct_str = { #O1, #O2, #I1, #I2 } },
6934c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3)     { .args_ct_str = { #O1, #O2, #I1, #I2, #I3 } },
6944c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) { .args_ct_str = { #O1, #O2, #I1, #I2, #I3, #I4 } },
69522d2e535SIlya Leoshkevich #define C_N1_O1_I4(O1, O2, I1, I2, I3, I4) { .args_ct_str = { "&" #O1, #O2, #I1, #I2, #I3, #I4 } },
6964c22e840SRichard Henderson 
6974c22e840SRichard Henderson static const TCGTargetOpDef constraint_sets[] = {
6984c22e840SRichard Henderson #include "tcg-target-con-set.h"
6994c22e840SRichard Henderson };
7004c22e840SRichard Henderson 
7014c22e840SRichard Henderson 
7024c22e840SRichard Henderson #undef C_O0_I1
7034c22e840SRichard Henderson #undef C_O0_I2
7044c22e840SRichard Henderson #undef C_O0_I3
7054c22e840SRichard Henderson #undef C_O0_I4
7064c22e840SRichard Henderson #undef C_O1_I1
7074c22e840SRichard Henderson #undef C_O1_I2
7084c22e840SRichard Henderson #undef C_O1_I3
7094c22e840SRichard Henderson #undef C_O1_I4
7104c22e840SRichard Henderson #undef C_N1_I2
7114c22e840SRichard Henderson #undef C_O2_I1
7124c22e840SRichard Henderson #undef C_O2_I2
7134c22e840SRichard Henderson #undef C_O2_I3
7144c22e840SRichard Henderson #undef C_O2_I4
71522d2e535SIlya Leoshkevich #undef C_N1_O1_I4
7164c22e840SRichard Henderson 
7174c22e840SRichard Henderson /* Expand the enumerator to be returned from tcg_target_op_def(). */
7184c22e840SRichard Henderson 
7194c22e840SRichard Henderson #define C_O0_I1(I1)                     C_PFX1(c_o0_i1_, I1)
7204c22e840SRichard Henderson #define C_O0_I2(I1, I2)                 C_PFX2(c_o0_i2_, I1, I2)
7214c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3)             C_PFX3(c_o0_i3_, I1, I2, I3)
7224c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4)         C_PFX4(c_o0_i4_, I1, I2, I3, I4)
7234c22e840SRichard Henderson 
7244c22e840SRichard Henderson #define C_O1_I1(O1, I1)                 C_PFX2(c_o1_i1_, O1, I1)
7254c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2)             C_PFX3(c_o1_i2_, O1, I1, I2)
7264c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3)         C_PFX4(c_o1_i3_, O1, I1, I2, I3)
7274c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4)     C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4)
7284c22e840SRichard Henderson 
7294c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2)             C_PFX3(c_n1_i2_, O1, I1, I2)
7304c22e840SRichard Henderson 
7314c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1)             C_PFX3(c_o2_i1_, O1, O2, I1)
7324c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2)         C_PFX4(c_o2_i2_, O1, O2, I1, I2)
7334c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3)     C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3)
7344c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4)
73522d2e535SIlya Leoshkevich #define C_N1_O1_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_n1_o1_i4_, O1, O2, I1, I2, I3, I4)
7364c22e840SRichard Henderson 
737139c1837SPaolo Bonzini #include "tcg-target.c.inc"
738c896fe29Sbellard 
7397857ee11SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
7407857ee11SRichard Henderson /* Validate CPUTLBDescFast placement. */
7417857ee11SRichard Henderson QEMU_BUILD_BUG_ON((int)(offsetof(CPUNegativeOffsetState, tlb.f[0]) -
7427857ee11SRichard Henderson                         sizeof(CPUNegativeOffsetState))
7437857ee11SRichard Henderson                   < MIN_TLB_MASK_TABLE_OFS);
7447857ee11SRichard Henderson #endif
7457857ee11SRichard Henderson 
74638b47b19SEmilio G. Cota static void alloc_tcg_plugin_context(TCGContext *s)
74738b47b19SEmilio G. Cota {
74838b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN
74938b47b19SEmilio G. Cota     s->plugin_tb = g_new0(struct qemu_plugin_tb, 1);
75038b47b19SEmilio G. Cota     s->plugin_tb->insns =
75138b47b19SEmilio G. Cota         g_ptr_array_new_with_free_func(qemu_plugin_insn_cleanup_fn);
75238b47b19SEmilio G. Cota #endif
75338b47b19SEmilio G. Cota }
75438b47b19SEmilio G. Cota 
755e8feb96fSEmilio G. Cota /*
7563468b59eSEmilio G. Cota  * All TCG threads except the parent (i.e. the one that called tcg_context_init
7573468b59eSEmilio G. Cota  * and registered the target's TCG globals) must register with this function
7583468b59eSEmilio G. Cota  * before initiating translation.
7593468b59eSEmilio G. Cota  *
7603468b59eSEmilio G. Cota  * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation
7613468b59eSEmilio G. Cota  * of tcg_region_init() for the reasoning behind this.
7623468b59eSEmilio G. Cota  *
7633468b59eSEmilio G. Cota  * In softmmu each caller registers its context in tcg_ctxs[]. Note that in
7643468b59eSEmilio G. Cota  * softmmu tcg_ctxs[] does not track tcg_ctx_init, since the initial context
7653468b59eSEmilio G. Cota  * is not used anymore for translation once this function is called.
7663468b59eSEmilio G. Cota  *
7673468b59eSEmilio G. Cota  * Not tracking tcg_init_ctx in tcg_ctxs[] in softmmu keeps code that iterates
7683468b59eSEmilio G. Cota  * over the array (e.g. tcg_code_size() the same for both softmmu and user-mode.
7693468b59eSEmilio G. Cota  */
7703468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
7713468b59eSEmilio G. Cota void tcg_register_thread(void)
7723468b59eSEmilio G. Cota {
7733468b59eSEmilio G. Cota     tcg_ctx = &tcg_init_ctx;
7743468b59eSEmilio G. Cota }
7753468b59eSEmilio G. Cota #else
7763468b59eSEmilio G. Cota void tcg_register_thread(void)
7773468b59eSEmilio G. Cota {
7783468b59eSEmilio G. Cota     TCGContext *s = g_malloc(sizeof(*s));
7793468b59eSEmilio G. Cota     unsigned int i, n;
7803468b59eSEmilio G. Cota 
7813468b59eSEmilio G. Cota     *s = tcg_init_ctx;
7823468b59eSEmilio G. Cota 
7833468b59eSEmilio G. Cota     /* Relink mem_base.  */
7843468b59eSEmilio G. Cota     for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) {
7853468b59eSEmilio G. Cota         if (tcg_init_ctx.temps[i].mem_base) {
7863468b59eSEmilio G. Cota             ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps;
7873468b59eSEmilio G. Cota             tcg_debug_assert(b >= 0 && b < n);
7883468b59eSEmilio G. Cota             s->temps[i].mem_base = &s->temps[b];
7893468b59eSEmilio G. Cota         }
7903468b59eSEmilio G. Cota     }
7913468b59eSEmilio G. Cota 
7923468b59eSEmilio G. Cota     /* Claim an entry in tcg_ctxs */
7930e2d61cfSRichard Henderson     n = qatomic_fetch_inc(&tcg_cur_ctxs);
7940e2d61cfSRichard Henderson     g_assert(n < tcg_max_ctxs);
795d73415a3SStefan Hajnoczi     qatomic_set(&tcg_ctxs[n], s);
7963468b59eSEmilio G. Cota 
79738b47b19SEmilio G. Cota     if (n > 0) {
79838b47b19SEmilio G. Cota         alloc_tcg_plugin_context(s);
799bf042e8eSRichard Henderson         tcg_region_initial_alloc(s);
80038b47b19SEmilio G. Cota     }
80138b47b19SEmilio G. Cota 
8023468b59eSEmilio G. Cota     tcg_ctx = s;
8033468b59eSEmilio G. Cota }
8043468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */
8053468b59eSEmilio G. Cota 
806c896fe29Sbellard /* pool based memory allocation */
807c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size)
808c896fe29Sbellard {
809c896fe29Sbellard     TCGPool *p;
810c896fe29Sbellard     int pool_size;
811c896fe29Sbellard 
812c896fe29Sbellard     if (size > TCG_POOL_CHUNK_SIZE) {
813c896fe29Sbellard         /* big malloc: insert a new pool (XXX: could optimize) */
8147267c094SAnthony Liguori         p = g_malloc(sizeof(TCGPool) + size);
815c896fe29Sbellard         p->size = size;
8164055299eSKirill Batuzov         p->next = s->pool_first_large;
8174055299eSKirill Batuzov         s->pool_first_large = p;
8184055299eSKirill Batuzov         return p->data;
819c896fe29Sbellard     } else {
820c896fe29Sbellard         p = s->pool_current;
821c896fe29Sbellard         if (!p) {
822c896fe29Sbellard             p = s->pool_first;
823c896fe29Sbellard             if (!p)
824c896fe29Sbellard                 goto new_pool;
825c896fe29Sbellard         } else {
826c896fe29Sbellard             if (!p->next) {
827c896fe29Sbellard             new_pool:
828c896fe29Sbellard                 pool_size = TCG_POOL_CHUNK_SIZE;
8297267c094SAnthony Liguori                 p = g_malloc(sizeof(TCGPool) + pool_size);
830c896fe29Sbellard                 p->size = pool_size;
831c896fe29Sbellard                 p->next = NULL;
832a813e36fSRichard Henderson                 if (s->pool_current) {
833c896fe29Sbellard                     s->pool_current->next = p;
834a813e36fSRichard Henderson                 } else {
835c896fe29Sbellard                     s->pool_first = p;
836a813e36fSRichard Henderson                 }
837c896fe29Sbellard             } else {
838c896fe29Sbellard                 p = p->next;
839c896fe29Sbellard             }
840c896fe29Sbellard         }
841c896fe29Sbellard     }
842c896fe29Sbellard     s->pool_current = p;
843c896fe29Sbellard     s->pool_cur = p->data + size;
844c896fe29Sbellard     s->pool_end = p->data + p->size;
845c896fe29Sbellard     return p->data;
846c896fe29Sbellard }
847c896fe29Sbellard 
848c896fe29Sbellard void tcg_pool_reset(TCGContext *s)
849c896fe29Sbellard {
8504055299eSKirill Batuzov     TCGPool *p, *t;
8514055299eSKirill Batuzov     for (p = s->pool_first_large; p; p = t) {
8524055299eSKirill Batuzov         t = p->next;
8534055299eSKirill Batuzov         g_free(p);
8544055299eSKirill Batuzov     }
8554055299eSKirill Batuzov     s->pool_first_large = NULL;
856c896fe29Sbellard     s->pool_cur = s->pool_end = NULL;
857c896fe29Sbellard     s->pool_current = NULL;
858c896fe29Sbellard }
859c896fe29Sbellard 
8608429a1caSRichard Henderson /*
8618429a1caSRichard Henderson  * Create TCGHelperInfo structures for "tcg/tcg-ldst.h" functions,
8628429a1caSRichard Henderson  * akin to what "exec/helper-tcg.h" does with DEF_HELPER_FLAGS_N.
8638429a1caSRichard Henderson  * We only use these for layout in tcg_out_ld_helper_ret and
8648429a1caSRichard Henderson  * tcg_out_st_helper_args, and share them between several of
8658429a1caSRichard Henderson  * the helpers, with the end result that it's easier to build manually.
8668429a1caSRichard Henderson  */
8678429a1caSRichard Henderson 
8688429a1caSRichard Henderson #if TCG_TARGET_REG_BITS == 32
8698429a1caSRichard Henderson # define dh_typecode_ttl  dh_typecode_i32
8708429a1caSRichard Henderson #else
8718429a1caSRichard Henderson # define dh_typecode_ttl  dh_typecode_i64
8728429a1caSRichard Henderson #endif
8738429a1caSRichard Henderson 
8748429a1caSRichard Henderson static TCGHelperInfo info_helper_ld32_mmu = {
8758429a1caSRichard Henderson     .flags = TCG_CALL_NO_WG,
8768429a1caSRichard Henderson     .typemask = dh_typemask(ttl, 0)  /* return tcg_target_ulong */
8778429a1caSRichard Henderson               | dh_typemask(env, 1)
87824e46e6cSRichard Henderson               | dh_typemask(i64, 2)  /* uint64_t addr */
8798429a1caSRichard Henderson               | dh_typemask(i32, 3)  /* unsigned oi */
8808429a1caSRichard Henderson               | dh_typemask(ptr, 4)  /* uintptr_t ra */
8818429a1caSRichard Henderson };
8828429a1caSRichard Henderson 
8838429a1caSRichard Henderson static TCGHelperInfo info_helper_ld64_mmu = {
8848429a1caSRichard Henderson     .flags = TCG_CALL_NO_WG,
8858429a1caSRichard Henderson     .typemask = dh_typemask(i64, 0)  /* return uint64_t */
8868429a1caSRichard Henderson               | dh_typemask(env, 1)
88724e46e6cSRichard Henderson               | dh_typemask(i64, 2)  /* uint64_t addr */
8888429a1caSRichard Henderson               | dh_typemask(i32, 3)  /* unsigned oi */
8898429a1caSRichard Henderson               | dh_typemask(ptr, 4)  /* uintptr_t ra */
8908429a1caSRichard Henderson };
8918429a1caSRichard Henderson 
892ebebea53SRichard Henderson static TCGHelperInfo info_helper_ld128_mmu = {
893ebebea53SRichard Henderson     .flags = TCG_CALL_NO_WG,
894ebebea53SRichard Henderson     .typemask = dh_typemask(i128, 0) /* return Int128 */
895ebebea53SRichard Henderson               | dh_typemask(env, 1)
89624e46e6cSRichard Henderson               | dh_typemask(i64, 2)  /* uint64_t addr */
897ebebea53SRichard Henderson               | dh_typemask(i32, 3)  /* unsigned oi */
898ebebea53SRichard Henderson               | dh_typemask(ptr, 4)  /* uintptr_t ra */
899ebebea53SRichard Henderson };
900ebebea53SRichard Henderson 
9018429a1caSRichard Henderson static TCGHelperInfo info_helper_st32_mmu = {
9028429a1caSRichard Henderson     .flags = TCG_CALL_NO_WG,
9038429a1caSRichard Henderson     .typemask = dh_typemask(void, 0)
9048429a1caSRichard Henderson               | dh_typemask(env, 1)
90524e46e6cSRichard Henderson               | dh_typemask(i64, 2)  /* uint64_t addr */
9068429a1caSRichard Henderson               | dh_typemask(i32, 3)  /* uint32_t data */
9078429a1caSRichard Henderson               | dh_typemask(i32, 4)  /* unsigned oi */
9088429a1caSRichard Henderson               | dh_typemask(ptr, 5)  /* uintptr_t ra */
9098429a1caSRichard Henderson };
9108429a1caSRichard Henderson 
9118429a1caSRichard Henderson static TCGHelperInfo info_helper_st64_mmu = {
9128429a1caSRichard Henderson     .flags = TCG_CALL_NO_WG,
9138429a1caSRichard Henderson     .typemask = dh_typemask(void, 0)
9148429a1caSRichard Henderson               | dh_typemask(env, 1)
91524e46e6cSRichard Henderson               | dh_typemask(i64, 2)  /* uint64_t addr */
9168429a1caSRichard Henderson               | dh_typemask(i64, 3)  /* uint64_t data */
9178429a1caSRichard Henderson               | dh_typemask(i32, 4)  /* unsigned oi */
9188429a1caSRichard Henderson               | dh_typemask(ptr, 5)  /* uintptr_t ra */
9198429a1caSRichard Henderson };
9208429a1caSRichard Henderson 
921ebebea53SRichard Henderson static TCGHelperInfo info_helper_st128_mmu = {
922ebebea53SRichard Henderson     .flags = TCG_CALL_NO_WG,
923ebebea53SRichard Henderson     .typemask = dh_typemask(void, 0)
924ebebea53SRichard Henderson               | dh_typemask(env, 1)
92524e46e6cSRichard Henderson               | dh_typemask(i64, 2)  /* uint64_t addr */
926ebebea53SRichard Henderson               | dh_typemask(i128, 3) /* Int128 data */
927ebebea53SRichard Henderson               | dh_typemask(i32, 4)  /* unsigned oi */
928ebebea53SRichard Henderson               | dh_typemask(ptr, 5)  /* uintptr_t ra */
929ebebea53SRichard Henderson };
930ebebea53SRichard Henderson 
93122f15579SRichard Henderson #ifdef CONFIG_TCG_INTERPRETER
932c6ef8c7bSPhilippe Mathieu-Daudé static ffi_type *typecode_to_ffi(int argmask)
933c6ef8c7bSPhilippe Mathieu-Daudé {
934e9709e17SRichard Henderson     /*
935e9709e17SRichard Henderson      * libffi does not support __int128_t, so we have forced Int128
936e9709e17SRichard Henderson      * to use the structure definition instead of the builtin type.
937e9709e17SRichard Henderson      */
938e9709e17SRichard Henderson     static ffi_type *ffi_type_i128_elements[3] = {
939e9709e17SRichard Henderson         &ffi_type_uint64,
940e9709e17SRichard Henderson         &ffi_type_uint64,
941e9709e17SRichard Henderson         NULL
942e9709e17SRichard Henderson     };
943e9709e17SRichard Henderson     static ffi_type ffi_type_i128 = {
944e9709e17SRichard Henderson         .size = 16,
945e9709e17SRichard Henderson         .alignment = __alignof__(Int128),
946e9709e17SRichard Henderson         .type = FFI_TYPE_STRUCT,
947e9709e17SRichard Henderson         .elements = ffi_type_i128_elements,
948e9709e17SRichard Henderson     };
949e9709e17SRichard Henderson 
950c6ef8c7bSPhilippe Mathieu-Daudé     switch (argmask) {
951c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_void:
952c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_void;
953c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_i32:
954c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_uint32;
955c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_s32:
956c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_sint32;
957c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_i64:
958c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_uint64;
959c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_s64:
960c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_sint64;
961c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_ptr:
962c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_pointer;
963e9709e17SRichard Henderson     case dh_typecode_i128:
964e9709e17SRichard Henderson         return &ffi_type_i128;
965c6ef8c7bSPhilippe Mathieu-Daudé     }
966c6ef8c7bSPhilippe Mathieu-Daudé     g_assert_not_reached();
967c6ef8c7bSPhilippe Mathieu-Daudé }
9680c22e176SPhilippe Mathieu-Daudé 
969d53106c9SRichard Henderson static ffi_cif *init_ffi_layout(TCGHelperInfo *info)
9700c22e176SPhilippe Mathieu-Daudé {
971f9c4bb80SRichard Henderson     unsigned typemask = info->typemask;
9720c22e176SPhilippe Mathieu-Daudé     struct {
9730c22e176SPhilippe Mathieu-Daudé         ffi_cif cif;
9740c22e176SPhilippe Mathieu-Daudé         ffi_type *args[];
9750c22e176SPhilippe Mathieu-Daudé     } *ca;
9760c22e176SPhilippe Mathieu-Daudé     ffi_status status;
9770c22e176SPhilippe Mathieu-Daudé     int nargs;
9780c22e176SPhilippe Mathieu-Daudé 
9790c22e176SPhilippe Mathieu-Daudé     /* Ignoring the return type, find the last non-zero field. */
9800c22e176SPhilippe Mathieu-Daudé     nargs = 32 - clz32(typemask >> 3);
9810c22e176SPhilippe Mathieu-Daudé     nargs = DIV_ROUND_UP(nargs, 3);
982e9709e17SRichard Henderson     assert(nargs <= MAX_CALL_IARGS);
9830c22e176SPhilippe Mathieu-Daudé 
9840c22e176SPhilippe Mathieu-Daudé     ca = g_malloc0(sizeof(*ca) + nargs * sizeof(ffi_type *));
9850c22e176SPhilippe Mathieu-Daudé     ca->cif.rtype = typecode_to_ffi(typemask & 7);
9860c22e176SPhilippe Mathieu-Daudé     ca->cif.nargs = nargs;
9870c22e176SPhilippe Mathieu-Daudé 
9880c22e176SPhilippe Mathieu-Daudé     if (nargs != 0) {
9890c22e176SPhilippe Mathieu-Daudé         ca->cif.arg_types = ca->args;
9900c22e176SPhilippe Mathieu-Daudé         for (int j = 0; j < nargs; ++j) {
9910c22e176SPhilippe Mathieu-Daudé             int typecode = extract32(typemask, (j + 1) * 3, 3);
9920c22e176SPhilippe Mathieu-Daudé             ca->args[j] = typecode_to_ffi(typecode);
9930c22e176SPhilippe Mathieu-Daudé         }
9940c22e176SPhilippe Mathieu-Daudé     }
9950c22e176SPhilippe Mathieu-Daudé 
9960c22e176SPhilippe Mathieu-Daudé     status = ffi_prep_cif(&ca->cif, FFI_DEFAULT_ABI, nargs,
9970c22e176SPhilippe Mathieu-Daudé                           ca->cif.rtype, ca->cif.arg_types);
9980c22e176SPhilippe Mathieu-Daudé     assert(status == FFI_OK);
9990c22e176SPhilippe Mathieu-Daudé 
1000d53106c9SRichard Henderson     return &ca->cif;
10010c22e176SPhilippe Mathieu-Daudé }
1002f9c4bb80SRichard Henderson 
1003d53106c9SRichard Henderson #define HELPER_INFO_INIT(I)      (&(I)->cif)
1004d53106c9SRichard Henderson #define HELPER_INFO_INIT_VAL(I)  init_ffi_layout(I)
1005d53106c9SRichard Henderson #else
1006d53106c9SRichard Henderson #define HELPER_INFO_INIT(I)      (&(I)->init)
1007d53106c9SRichard Henderson #define HELPER_INFO_INIT_VAL(I)  1
10080c22e176SPhilippe Mathieu-Daudé #endif /* CONFIG_TCG_INTERPRETER */
100922f15579SRichard Henderson 
1010338b61e9SRichard Henderson static inline bool arg_slot_reg_p(unsigned arg_slot)
1011338b61e9SRichard Henderson {
1012338b61e9SRichard Henderson     /*
1013338b61e9SRichard Henderson      * Split the sizeof away from the comparison to avoid Werror from
1014338b61e9SRichard Henderson      * "unsigned < 0 is always false", when iarg_regs is empty.
1015338b61e9SRichard Henderson      */
1016338b61e9SRichard Henderson     unsigned nreg = ARRAY_SIZE(tcg_target_call_iarg_regs);
1017338b61e9SRichard Henderson     return arg_slot < nreg;
1018338b61e9SRichard Henderson }
1019338b61e9SRichard Henderson 
1020d78e4a4fSRichard Henderson static inline int arg_slot_stk_ofs(unsigned arg_slot)
1021d78e4a4fSRichard Henderson {
1022d78e4a4fSRichard Henderson     unsigned max = TCG_STATIC_CALL_ARGS_SIZE / sizeof(tcg_target_long);
1023d78e4a4fSRichard Henderson     unsigned stk_slot = arg_slot - ARRAY_SIZE(tcg_target_call_iarg_regs);
1024d78e4a4fSRichard Henderson 
1025d78e4a4fSRichard Henderson     tcg_debug_assert(stk_slot < max);
1026d78e4a4fSRichard Henderson     return TCG_TARGET_CALL_STACK_OFFSET + stk_slot * sizeof(tcg_target_long);
1027d78e4a4fSRichard Henderson }
1028d78e4a4fSRichard Henderson 
102939004a71SRichard Henderson typedef struct TCGCumulativeArgs {
103039004a71SRichard Henderson     int arg_idx;                /* tcg_gen_callN args[] */
103139004a71SRichard Henderson     int info_in_idx;            /* TCGHelperInfo in[] */
103239004a71SRichard Henderson     int arg_slot;               /* regs+stack slot */
103339004a71SRichard Henderson     int ref_slot;               /* stack slots for references */
103439004a71SRichard Henderson } TCGCumulativeArgs;
103539004a71SRichard Henderson 
103639004a71SRichard Henderson static void layout_arg_even(TCGCumulativeArgs *cum)
103739004a71SRichard Henderson {
103839004a71SRichard Henderson     cum->arg_slot += cum->arg_slot & 1;
103939004a71SRichard Henderson }
104039004a71SRichard Henderson 
104139004a71SRichard Henderson static void layout_arg_1(TCGCumulativeArgs *cum, TCGHelperInfo *info,
104239004a71SRichard Henderson                          TCGCallArgumentKind kind)
104339004a71SRichard Henderson {
104439004a71SRichard Henderson     TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx];
104539004a71SRichard Henderson 
104639004a71SRichard Henderson     *loc = (TCGCallArgumentLoc){
104739004a71SRichard Henderson         .kind = kind,
104839004a71SRichard Henderson         .arg_idx = cum->arg_idx,
104939004a71SRichard Henderson         .arg_slot = cum->arg_slot,
105039004a71SRichard Henderson     };
105139004a71SRichard Henderson     cum->info_in_idx++;
105239004a71SRichard Henderson     cum->arg_slot++;
105339004a71SRichard Henderson }
105439004a71SRichard Henderson 
105539004a71SRichard Henderson static void layout_arg_normal_n(TCGCumulativeArgs *cum,
105639004a71SRichard Henderson                                 TCGHelperInfo *info, int n)
105739004a71SRichard Henderson {
105839004a71SRichard Henderson     TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx];
105939004a71SRichard Henderson 
106039004a71SRichard Henderson     for (int i = 0; i < n; ++i) {
106139004a71SRichard Henderson         /* Layout all using the same arg_idx, adjusting the subindex. */
106239004a71SRichard Henderson         loc[i] = (TCGCallArgumentLoc){
106339004a71SRichard Henderson             .kind = TCG_CALL_ARG_NORMAL,
106439004a71SRichard Henderson             .arg_idx = cum->arg_idx,
106539004a71SRichard Henderson             .tmp_subindex = i,
106639004a71SRichard Henderson             .arg_slot = cum->arg_slot + i,
106739004a71SRichard Henderson         };
106839004a71SRichard Henderson     }
106939004a71SRichard Henderson     cum->info_in_idx += n;
107039004a71SRichard Henderson     cum->arg_slot += n;
107139004a71SRichard Henderson }
107239004a71SRichard Henderson 
1073313bdea8SRichard Henderson static void layout_arg_by_ref(TCGCumulativeArgs *cum, TCGHelperInfo *info)
1074313bdea8SRichard Henderson {
1075313bdea8SRichard Henderson     TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx];
1076313bdea8SRichard Henderson     int n = 128 / TCG_TARGET_REG_BITS;
1077313bdea8SRichard Henderson 
1078313bdea8SRichard Henderson     /* The first subindex carries the pointer. */
1079313bdea8SRichard Henderson     layout_arg_1(cum, info, TCG_CALL_ARG_BY_REF);
1080313bdea8SRichard Henderson 
1081313bdea8SRichard Henderson     /*
1082313bdea8SRichard Henderson      * The callee is allowed to clobber memory associated with
1083313bdea8SRichard Henderson      * structure pass by-reference.  Therefore we must make copies.
1084313bdea8SRichard Henderson      * Allocate space from "ref_slot", which will be adjusted to
1085313bdea8SRichard Henderson      * follow the parameters on the stack.
1086313bdea8SRichard Henderson      */
1087313bdea8SRichard Henderson     loc[0].ref_slot = cum->ref_slot;
1088313bdea8SRichard Henderson 
1089313bdea8SRichard Henderson     /*
1090313bdea8SRichard Henderson      * Subsequent words also go into the reference slot, but
1091313bdea8SRichard Henderson      * do not accumulate into the regular arguments.
1092313bdea8SRichard Henderson      */
1093313bdea8SRichard Henderson     for (int i = 1; i < n; ++i) {
1094313bdea8SRichard Henderson         loc[i] = (TCGCallArgumentLoc){
1095313bdea8SRichard Henderson             .kind = TCG_CALL_ARG_BY_REF_N,
1096313bdea8SRichard Henderson             .arg_idx = cum->arg_idx,
1097313bdea8SRichard Henderson             .tmp_subindex = i,
1098313bdea8SRichard Henderson             .ref_slot = cum->ref_slot + i,
1099313bdea8SRichard Henderson         };
1100313bdea8SRichard Henderson     }
1101e18ed26cSRichard Henderson     cum->info_in_idx += n - 1;  /* i=0 accounted for in layout_arg_1 */
1102313bdea8SRichard Henderson     cum->ref_slot += n;
1103313bdea8SRichard Henderson }
1104313bdea8SRichard Henderson 
110539004a71SRichard Henderson static void init_call_layout(TCGHelperInfo *info)
110639004a71SRichard Henderson {
110739004a71SRichard Henderson     int max_reg_slots = ARRAY_SIZE(tcg_target_call_iarg_regs);
110839004a71SRichard Henderson     int max_stk_slots = TCG_STATIC_CALL_ARGS_SIZE / sizeof(tcg_target_long);
110939004a71SRichard Henderson     unsigned typemask = info->typemask;
111039004a71SRichard Henderson     unsigned typecode;
111139004a71SRichard Henderson     TCGCumulativeArgs cum = { };
111239004a71SRichard Henderson 
111339004a71SRichard Henderson     /*
111439004a71SRichard Henderson      * Parse and place any function return value.
111539004a71SRichard Henderson      */
111639004a71SRichard Henderson     typecode = typemask & 7;
111739004a71SRichard Henderson     switch (typecode) {
111839004a71SRichard Henderson     case dh_typecode_void:
111939004a71SRichard Henderson         info->nr_out = 0;
112039004a71SRichard Henderson         break;
112139004a71SRichard Henderson     case dh_typecode_i32:
112239004a71SRichard Henderson     case dh_typecode_s32:
112339004a71SRichard Henderson     case dh_typecode_ptr:
112439004a71SRichard Henderson         info->nr_out = 1;
112539004a71SRichard Henderson         info->out_kind = TCG_CALL_RET_NORMAL;
112639004a71SRichard Henderson         break;
112739004a71SRichard Henderson     case dh_typecode_i64:
112839004a71SRichard Henderson     case dh_typecode_s64:
112939004a71SRichard Henderson         info->nr_out = 64 / TCG_TARGET_REG_BITS;
113039004a71SRichard Henderson         info->out_kind = TCG_CALL_RET_NORMAL;
11315e3d0c19SRichard Henderson         /* Query the last register now to trigger any assert early. */
11325e3d0c19SRichard Henderson         tcg_target_call_oarg_reg(info->out_kind, info->nr_out - 1);
1133466d3759SRichard Henderson         break;
1134466d3759SRichard Henderson     case dh_typecode_i128:
1135466d3759SRichard Henderson         info->nr_out = 128 / TCG_TARGET_REG_BITS;
11365427a9a7SRichard Henderson         info->out_kind = TCG_TARGET_CALL_RET_I128;
11375427a9a7SRichard Henderson         switch (TCG_TARGET_CALL_RET_I128) {
1138466d3759SRichard Henderson         case TCG_CALL_RET_NORMAL:
11395e3d0c19SRichard Henderson             /* Query the last register now to trigger any assert early. */
11405e3d0c19SRichard Henderson             tcg_target_call_oarg_reg(info->out_kind, info->nr_out - 1);
1141466d3759SRichard Henderson             break;
1142c6556aa0SRichard Henderson         case TCG_CALL_RET_BY_VEC:
1143c6556aa0SRichard Henderson             /* Query the single register now to trigger any assert early. */
1144c6556aa0SRichard Henderson             tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0);
1145c6556aa0SRichard Henderson             break;
1146313bdea8SRichard Henderson         case TCG_CALL_RET_BY_REF:
1147313bdea8SRichard Henderson             /*
1148313bdea8SRichard Henderson              * Allocate the first argument to the output.
1149313bdea8SRichard Henderson              * We don't need to store this anywhere, just make it
1150313bdea8SRichard Henderson              * unavailable for use in the input loop below.
1151313bdea8SRichard Henderson              */
1152313bdea8SRichard Henderson             cum.arg_slot = 1;
1153313bdea8SRichard Henderson             break;
1154466d3759SRichard Henderson         default:
1155466d3759SRichard Henderson             qemu_build_not_reached();
1156466d3759SRichard Henderson         }
115739004a71SRichard Henderson         break;
115839004a71SRichard Henderson     default:
115939004a71SRichard Henderson         g_assert_not_reached();
116039004a71SRichard Henderson     }
116139004a71SRichard Henderson 
116239004a71SRichard Henderson     /*
116339004a71SRichard Henderson      * Parse and place function arguments.
116439004a71SRichard Henderson      */
116539004a71SRichard Henderson     for (typemask >>= 3; typemask; typemask >>= 3, cum.arg_idx++) {
116639004a71SRichard Henderson         TCGCallArgumentKind kind;
116739004a71SRichard Henderson         TCGType type;
116839004a71SRichard Henderson 
116939004a71SRichard Henderson         typecode = typemask & 7;
117039004a71SRichard Henderson         switch (typecode) {
117139004a71SRichard Henderson         case dh_typecode_i32:
117239004a71SRichard Henderson         case dh_typecode_s32:
117339004a71SRichard Henderson             type = TCG_TYPE_I32;
117439004a71SRichard Henderson             break;
117539004a71SRichard Henderson         case dh_typecode_i64:
117639004a71SRichard Henderson         case dh_typecode_s64:
117739004a71SRichard Henderson             type = TCG_TYPE_I64;
117839004a71SRichard Henderson             break;
117939004a71SRichard Henderson         case dh_typecode_ptr:
118039004a71SRichard Henderson             type = TCG_TYPE_PTR;
118139004a71SRichard Henderson             break;
1182466d3759SRichard Henderson         case dh_typecode_i128:
1183466d3759SRichard Henderson             type = TCG_TYPE_I128;
1184466d3759SRichard Henderson             break;
118539004a71SRichard Henderson         default:
118639004a71SRichard Henderson             g_assert_not_reached();
118739004a71SRichard Henderson         }
118839004a71SRichard Henderson 
118939004a71SRichard Henderson         switch (type) {
119039004a71SRichard Henderson         case TCG_TYPE_I32:
119139004a71SRichard Henderson             switch (TCG_TARGET_CALL_ARG_I32) {
119239004a71SRichard Henderson             case TCG_CALL_ARG_EVEN:
119339004a71SRichard Henderson                 layout_arg_even(&cum);
119439004a71SRichard Henderson                 /* fall through */
119539004a71SRichard Henderson             case TCG_CALL_ARG_NORMAL:
119639004a71SRichard Henderson                 layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL);
119739004a71SRichard Henderson                 break;
119839004a71SRichard Henderson             case TCG_CALL_ARG_EXTEND:
119939004a71SRichard Henderson                 kind = TCG_CALL_ARG_EXTEND_U + (typecode & 1);
120039004a71SRichard Henderson                 layout_arg_1(&cum, info, kind);
120139004a71SRichard Henderson                 break;
120239004a71SRichard Henderson             default:
120339004a71SRichard Henderson                 qemu_build_not_reached();
120439004a71SRichard Henderson             }
120539004a71SRichard Henderson             break;
120639004a71SRichard Henderson 
120739004a71SRichard Henderson         case TCG_TYPE_I64:
120839004a71SRichard Henderson             switch (TCG_TARGET_CALL_ARG_I64) {
120939004a71SRichard Henderson             case TCG_CALL_ARG_EVEN:
121039004a71SRichard Henderson                 layout_arg_even(&cum);
121139004a71SRichard Henderson                 /* fall through */
121239004a71SRichard Henderson             case TCG_CALL_ARG_NORMAL:
121339004a71SRichard Henderson                 if (TCG_TARGET_REG_BITS == 32) {
121439004a71SRichard Henderson                     layout_arg_normal_n(&cum, info, 2);
121539004a71SRichard Henderson                 } else {
121639004a71SRichard Henderson                     layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL);
121739004a71SRichard Henderson                 }
121839004a71SRichard Henderson                 break;
121939004a71SRichard Henderson             default:
122039004a71SRichard Henderson                 qemu_build_not_reached();
122139004a71SRichard Henderson             }
122239004a71SRichard Henderson             break;
122339004a71SRichard Henderson 
1224466d3759SRichard Henderson         case TCG_TYPE_I128:
12255427a9a7SRichard Henderson             switch (TCG_TARGET_CALL_ARG_I128) {
1226466d3759SRichard Henderson             case TCG_CALL_ARG_EVEN:
1227466d3759SRichard Henderson                 layout_arg_even(&cum);
1228466d3759SRichard Henderson                 /* fall through */
1229466d3759SRichard Henderson             case TCG_CALL_ARG_NORMAL:
1230466d3759SRichard Henderson                 layout_arg_normal_n(&cum, info, 128 / TCG_TARGET_REG_BITS);
1231466d3759SRichard Henderson                 break;
1232313bdea8SRichard Henderson             case TCG_CALL_ARG_BY_REF:
1233313bdea8SRichard Henderson                 layout_arg_by_ref(&cum, info);
1234313bdea8SRichard Henderson                 break;
1235466d3759SRichard Henderson             default:
1236466d3759SRichard Henderson                 qemu_build_not_reached();
1237466d3759SRichard Henderson             }
1238466d3759SRichard Henderson             break;
1239466d3759SRichard Henderson 
124039004a71SRichard Henderson         default:
124139004a71SRichard Henderson             g_assert_not_reached();
124239004a71SRichard Henderson         }
124339004a71SRichard Henderson     }
124439004a71SRichard Henderson     info->nr_in = cum.info_in_idx;
124539004a71SRichard Henderson 
124639004a71SRichard Henderson     /* Validate that we didn't overrun the input array. */
124739004a71SRichard Henderson     assert(cum.info_in_idx <= ARRAY_SIZE(info->in));
124839004a71SRichard Henderson     /* Validate the backend has enough argument space. */
124939004a71SRichard Henderson     assert(cum.arg_slot <= max_reg_slots + max_stk_slots);
1250313bdea8SRichard Henderson 
1251313bdea8SRichard Henderson     /*
1252313bdea8SRichard Henderson      * Relocate the "ref_slot" area to the end of the parameters.
1253313bdea8SRichard Henderson      * Minimizing this stack offset helps code size for x86,
1254313bdea8SRichard Henderson      * which has a signed 8-bit offset encoding.
1255313bdea8SRichard Henderson      */
1256313bdea8SRichard Henderson     if (cum.ref_slot != 0) {
1257313bdea8SRichard Henderson         int ref_base = 0;
1258313bdea8SRichard Henderson 
1259313bdea8SRichard Henderson         if (cum.arg_slot > max_reg_slots) {
1260313bdea8SRichard Henderson             int align = __alignof(Int128) / sizeof(tcg_target_long);
1261313bdea8SRichard Henderson 
1262313bdea8SRichard Henderson             ref_base = cum.arg_slot - max_reg_slots;
1263313bdea8SRichard Henderson             if (align > 1) {
1264313bdea8SRichard Henderson                 ref_base = ROUND_UP(ref_base, align);
1265313bdea8SRichard Henderson             }
1266313bdea8SRichard Henderson         }
1267313bdea8SRichard Henderson         assert(ref_base + cum.ref_slot <= max_stk_slots);
1268d78e4a4fSRichard Henderson         ref_base += max_reg_slots;
1269313bdea8SRichard Henderson 
1270313bdea8SRichard Henderson         if (ref_base != 0) {
1271313bdea8SRichard Henderson             for (int i = cum.info_in_idx - 1; i >= 0; --i) {
1272313bdea8SRichard Henderson                 TCGCallArgumentLoc *loc = &info->in[i];
1273313bdea8SRichard Henderson                 switch (loc->kind) {
1274313bdea8SRichard Henderson                 case TCG_CALL_ARG_BY_REF:
1275313bdea8SRichard Henderson                 case TCG_CALL_ARG_BY_REF_N:
1276313bdea8SRichard Henderson                     loc->ref_slot += ref_base;
1277313bdea8SRichard Henderson                     break;
1278313bdea8SRichard Henderson                 default:
1279313bdea8SRichard Henderson                     break;
1280313bdea8SRichard Henderson                 }
1281313bdea8SRichard Henderson             }
1282313bdea8SRichard Henderson         }
1283313bdea8SRichard Henderson     }
128439004a71SRichard Henderson }
128539004a71SRichard Henderson 
128691478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)];
1287f69d277eSRichard Henderson static void process_op_defs(TCGContext *s);
12881c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
12891c2adb95SRichard Henderson                                             TCGReg reg, const char *name);
129091478cefSRichard Henderson 
129143b972b7SRichard Henderson static void tcg_context_init(unsigned max_cpus)
1292c896fe29Sbellard {
1293a76aabd3SRichard Henderson     TCGContext *s = &tcg_init_ctx;
1294100b5e01SRichard Henderson     int op, total_args, n, i;
1295c896fe29Sbellard     TCGOpDef *def;
1296c896fe29Sbellard     TCGArgConstraint *args_ct;
12971c2adb95SRichard Henderson     TCGTemp *ts;
1298c896fe29Sbellard 
1299c896fe29Sbellard     memset(s, 0, sizeof(*s));
1300c896fe29Sbellard     s->nb_globals = 0;
1301c896fe29Sbellard 
1302c896fe29Sbellard     /* Count total number of arguments and allocate the corresponding
1303c896fe29Sbellard        space */
1304c896fe29Sbellard     total_args = 0;
1305c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
1306c896fe29Sbellard         def = &tcg_op_defs[op];
1307c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
1308c896fe29Sbellard         total_args += n;
1309c896fe29Sbellard     }
1310c896fe29Sbellard 
1311bc2b17e6SRichard Henderson     args_ct = g_new0(TCGArgConstraint, total_args);
1312c896fe29Sbellard 
1313c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
1314c896fe29Sbellard         def = &tcg_op_defs[op];
1315c896fe29Sbellard         def->args_ct = args_ct;
1316c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
1317c896fe29Sbellard         args_ct += n;
1318c896fe29Sbellard     }
1319c896fe29Sbellard 
13208429a1caSRichard Henderson     init_call_layout(&info_helper_ld32_mmu);
13218429a1caSRichard Henderson     init_call_layout(&info_helper_ld64_mmu);
1322ebebea53SRichard Henderson     init_call_layout(&info_helper_ld128_mmu);
13238429a1caSRichard Henderson     init_call_layout(&info_helper_st32_mmu);
13248429a1caSRichard Henderson     init_call_layout(&info_helper_st64_mmu);
1325ebebea53SRichard Henderson     init_call_layout(&info_helper_st128_mmu);
13268429a1caSRichard Henderson 
1327c896fe29Sbellard     tcg_target_init(s);
1328f69d277eSRichard Henderson     process_op_defs(s);
132991478cefSRichard Henderson 
133091478cefSRichard Henderson     /* Reverse the order of the saved registers, assuming they're all at
133191478cefSRichard Henderson        the start of tcg_target_reg_alloc_order.  */
133291478cefSRichard Henderson     for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) {
133391478cefSRichard Henderson         int r = tcg_target_reg_alloc_order[n];
133491478cefSRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) {
133591478cefSRichard Henderson             break;
133691478cefSRichard Henderson         }
133791478cefSRichard Henderson     }
133891478cefSRichard Henderson     for (i = 0; i < n; ++i) {
133991478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i];
134091478cefSRichard Henderson     }
134191478cefSRichard Henderson     for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) {
134291478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i];
134391478cefSRichard Henderson     }
1344b1311c4aSEmilio G. Cota 
134538b47b19SEmilio G. Cota     alloc_tcg_plugin_context(s);
134638b47b19SEmilio G. Cota 
1347b1311c4aSEmilio G. Cota     tcg_ctx = s;
13483468b59eSEmilio G. Cota     /*
13493468b59eSEmilio G. Cota      * In user-mode we simply share the init context among threads, since we
13503468b59eSEmilio G. Cota      * use a single region. See the documentation tcg_region_init() for the
13513468b59eSEmilio G. Cota      * reasoning behind this.
13523468b59eSEmilio G. Cota      * In softmmu we will have at most max_cpus TCG threads.
13533468b59eSEmilio G. Cota      */
13543468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
1355df2cce29SEmilio G. Cota     tcg_ctxs = &tcg_ctx;
13560e2d61cfSRichard Henderson     tcg_cur_ctxs = 1;
13570e2d61cfSRichard Henderson     tcg_max_ctxs = 1;
13583468b59eSEmilio G. Cota #else
13590e2d61cfSRichard Henderson     tcg_max_ctxs = max_cpus;
13600e2d61cfSRichard Henderson     tcg_ctxs = g_new0(TCGContext *, max_cpus);
13613468b59eSEmilio G. Cota #endif
13621c2adb95SRichard Henderson 
13631c2adb95SRichard Henderson     tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0));
13641c2adb95SRichard Henderson     ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env");
1365ad75a51eSRichard Henderson     tcg_env = temp_tcgv_ptr(ts);
13669002ec79SRichard Henderson }
1367b03cce8eSbellard 
136843b972b7SRichard Henderson void tcg_init(size_t tb_size, int splitwx, unsigned max_cpus)
1369a76aabd3SRichard Henderson {
137043b972b7SRichard Henderson     tcg_context_init(max_cpus);
137143b972b7SRichard Henderson     tcg_region_init(tb_size, splitwx, max_cpus);
1372a76aabd3SRichard Henderson }
1373a76aabd3SRichard Henderson 
13746e3b2bfdSEmilio G. Cota /*
13756e3b2bfdSEmilio G. Cota  * Allocate TBs right before their corresponding translated code, making
13766e3b2bfdSEmilio G. Cota  * sure that TBs and code are on different cache lines.
13776e3b2bfdSEmilio G. Cota  */
13786e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s)
13796e3b2bfdSEmilio G. Cota {
13806e3b2bfdSEmilio G. Cota     uintptr_t align = qemu_icache_linesize;
13816e3b2bfdSEmilio G. Cota     TranslationBlock *tb;
13826e3b2bfdSEmilio G. Cota     void *next;
13836e3b2bfdSEmilio G. Cota 
1384e8feb96fSEmilio G. Cota  retry:
13856e3b2bfdSEmilio G. Cota     tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align);
13866e3b2bfdSEmilio G. Cota     next = (void *)ROUND_UP((uintptr_t)(tb + 1), align);
13876e3b2bfdSEmilio G. Cota 
13886e3b2bfdSEmilio G. Cota     if (unlikely(next > s->code_gen_highwater)) {
1389e8feb96fSEmilio G. Cota         if (tcg_region_alloc(s)) {
13906e3b2bfdSEmilio G. Cota             return NULL;
13916e3b2bfdSEmilio G. Cota         }
1392e8feb96fSEmilio G. Cota         goto retry;
1393e8feb96fSEmilio G. Cota     }
1394d73415a3SStefan Hajnoczi     qatomic_set(&s->code_gen_ptr, next);
139557a26946SRichard Henderson     s->data_gen_ptr = NULL;
13966e3b2bfdSEmilio G. Cota     return tb;
13976e3b2bfdSEmilio G. Cota }
13986e3b2bfdSEmilio G. Cota 
1399935f75aeSRichard Henderson void tcg_prologue_init(void)
14009002ec79SRichard Henderson {
1401935f75aeSRichard Henderson     TCGContext *s = tcg_ctx;
1402b0a0794aSRichard Henderson     size_t prologue_size;
14038163b749SRichard Henderson 
1404b0a0794aSRichard Henderson     s->code_ptr = s->code_gen_ptr;
1405b0a0794aSRichard Henderson     s->code_buf = s->code_gen_ptr;
14065b38ee31SRichard Henderson     s->data_gen_ptr = NULL;
1407b91ccb31SRichard Henderson 
1408b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
1409b0a0794aSRichard Henderson     tcg_qemu_tb_exec = (tcg_prologue_fn *)tcg_splitwx_to_rx(s->code_ptr);
1410b91ccb31SRichard Henderson #endif
14118163b749SRichard Henderson 
14125b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
14135b38ee31SRichard Henderson     s->pool_labels = NULL;
14145b38ee31SRichard Henderson #endif
14155b38ee31SRichard Henderson 
1416653b87ebSRoman Bolshakov     qemu_thread_jit_write();
14178163b749SRichard Henderson     /* Generate the prologue.  */
1418b03cce8eSbellard     tcg_target_qemu_prologue(s);
14195b38ee31SRichard Henderson 
14205b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
14215b38ee31SRichard Henderson     /* Allow the prologue to put e.g. guest_base into a pool entry.  */
14225b38ee31SRichard Henderson     {
14231768987bSRichard Henderson         int result = tcg_out_pool_finalize(s);
14241768987bSRichard Henderson         tcg_debug_assert(result == 0);
14255b38ee31SRichard Henderson     }
14265b38ee31SRichard Henderson #endif
14275b38ee31SRichard Henderson 
1428b0a0794aSRichard Henderson     prologue_size = tcg_current_code_size(s);
14295584e2dbSIlya Leoshkevich     perf_report_prologue(s->code_gen_ptr, prologue_size);
1430b0a0794aSRichard Henderson 
1431df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
1432b0a0794aSRichard Henderson     flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf),
1433b0a0794aSRichard Henderson                         (uintptr_t)s->code_buf, prologue_size);
1434df5d2b16SRichard Henderson #endif
14358163b749SRichard Henderson 
1436d6b64b2bSRichard Henderson     if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) {
1437c60f599bSRichard Henderson         FILE *logfile = qemu_log_trylock();
143878b54858SRichard Henderson         if (logfile) {
143978b54858SRichard Henderson             fprintf(logfile, "PROLOGUE: [size=%zu]\n", prologue_size);
14405b38ee31SRichard Henderson             if (s->data_gen_ptr) {
1441b0a0794aSRichard Henderson                 size_t code_size = s->data_gen_ptr - s->code_gen_ptr;
14425b38ee31SRichard Henderson                 size_t data_size = prologue_size - code_size;
14435b38ee31SRichard Henderson                 size_t i;
14445b38ee31SRichard Henderson 
144578b54858SRichard Henderson                 disas(logfile, s->code_gen_ptr, code_size);
14465b38ee31SRichard Henderson 
14475b38ee31SRichard Henderson                 for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) {
14485b38ee31SRichard Henderson                     if (sizeof(tcg_target_ulong) == 8) {
144978b54858SRichard Henderson                         fprintf(logfile,
145078b54858SRichard Henderson                                 "0x%08" PRIxPTR ":  .quad  0x%016" PRIx64 "\n",
14515b38ee31SRichard Henderson                                 (uintptr_t)s->data_gen_ptr + i,
14525b38ee31SRichard Henderson                                 *(uint64_t *)(s->data_gen_ptr + i));
14535b38ee31SRichard Henderson                     } else {
145478b54858SRichard Henderson                         fprintf(logfile,
145578b54858SRichard Henderson                                 "0x%08" PRIxPTR ":  .long  0x%08x\n",
14565b38ee31SRichard Henderson                                 (uintptr_t)s->data_gen_ptr + i,
14575b38ee31SRichard Henderson                                 *(uint32_t *)(s->data_gen_ptr + i));
14585b38ee31SRichard Henderson                     }
14595b38ee31SRichard Henderson                 }
14605b38ee31SRichard Henderson             } else {
146178b54858SRichard Henderson                 disas(logfile, s->code_gen_ptr, prologue_size);
14625b38ee31SRichard Henderson             }
146378b54858SRichard Henderson             fprintf(logfile, "\n");
1464fc59d2d8SRobert Foley             qemu_log_unlock(logfile);
1465d6b64b2bSRichard Henderson         }
146678b54858SRichard Henderson     }
1467cedbcb01SEmilio G. Cota 
14686eea0434SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
14696eea0434SRichard Henderson     /*
14706eea0434SRichard Henderson      * Assert that goto_ptr is implemented completely, setting an epilogue.
14716eea0434SRichard Henderson      * For tci, we use NULL as the signal to return from the interpreter,
14726eea0434SRichard Henderson      * so skip this check.
14736eea0434SRichard Henderson      */
14748b5c2b62SRichard Henderson     tcg_debug_assert(tcg_code_gen_epilogue != NULL);
14756eea0434SRichard Henderson #endif
1476d1c74ab3SRichard Henderson 
1477d1c74ab3SRichard Henderson     tcg_region_prologue_set(s);
1478c896fe29Sbellard }
1479c896fe29Sbellard 
1480c896fe29Sbellard void tcg_func_start(TCGContext *s)
1481c896fe29Sbellard {
1482c896fe29Sbellard     tcg_pool_reset(s);
1483c896fe29Sbellard     s->nb_temps = s->nb_globals;
14840ec9eabcSRichard Henderson 
14850ec9eabcSRichard Henderson     /* No temps have been previously allocated for size or locality.  */
14860ec9eabcSRichard Henderson     memset(s->free_temps, 0, sizeof(s->free_temps));
14870ec9eabcSRichard Henderson 
1488c0522136SRichard Henderson     /* No constant temps have been previously allocated. */
1489c0522136SRichard Henderson     for (int i = 0; i < TCG_TYPE_COUNT; ++i) {
1490c0522136SRichard Henderson         if (s->const_table[i]) {
1491c0522136SRichard Henderson             g_hash_table_remove_all(s->const_table[i]);
1492c0522136SRichard Henderson         }
1493c0522136SRichard Henderson     }
1494c0522136SRichard Henderson 
1495abebf925SRichard Henderson     s->nb_ops = 0;
1496c896fe29Sbellard     s->nb_labels = 0;
1497c896fe29Sbellard     s->current_frame_offset = s->frame_start;
1498c896fe29Sbellard 
14990a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG
15000a209d4bSRichard Henderson     s->goto_tb_issue_mask = 0;
15010a209d4bSRichard Henderson #endif
15020a209d4bSRichard Henderson 
150315fa08f8SRichard Henderson     QTAILQ_INIT(&s->ops);
150415fa08f8SRichard Henderson     QTAILQ_INIT(&s->free_ops);
1505bef16ab4SRichard Henderson     QSIMPLEQ_INIT(&s->labels);
15064baf3978SRichard Henderson 
15074baf3978SRichard Henderson     tcg_debug_assert(s->addr_type == TCG_TYPE_I32 ||
15084baf3978SRichard Henderson                      s->addr_type == TCG_TYPE_I64);
1509d0a9bb5eSRichard Henderson 
1510747bd69dSRichard Henderson     tcg_debug_assert(s->insn_start_words > 0);
1511c896fe29Sbellard }
1512c896fe29Sbellard 
1513ae30e866SRichard Henderson static TCGTemp *tcg_temp_alloc(TCGContext *s)
15147ca4b752SRichard Henderson {
15157ca4b752SRichard Henderson     int n = s->nb_temps++;
1516ae30e866SRichard Henderson 
1517ae30e866SRichard Henderson     if (n >= TCG_MAX_TEMPS) {
1518db6b7d0cSRichard Henderson         tcg_raise_tb_overflow(s);
1519ae30e866SRichard Henderson     }
15207ca4b752SRichard Henderson     return memset(&s->temps[n], 0, sizeof(TCGTemp));
15217ca4b752SRichard Henderson }
15227ca4b752SRichard Henderson 
1523ae30e866SRichard Henderson static TCGTemp *tcg_global_alloc(TCGContext *s)
15247ca4b752SRichard Henderson {
1525fa477d25SRichard Henderson     TCGTemp *ts;
1526fa477d25SRichard Henderson 
15277ca4b752SRichard Henderson     tcg_debug_assert(s->nb_globals == s->nb_temps);
1528ae30e866SRichard Henderson     tcg_debug_assert(s->nb_globals < TCG_MAX_TEMPS);
15297ca4b752SRichard Henderson     s->nb_globals++;
1530fa477d25SRichard Henderson     ts = tcg_temp_alloc(s);
1531ee17db83SRichard Henderson     ts->kind = TEMP_GLOBAL;
1532fa477d25SRichard Henderson 
1533fa477d25SRichard Henderson     return ts;
1534c896fe29Sbellard }
1535c896fe29Sbellard 
1536085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
1537b6638662SRichard Henderson                                             TCGReg reg, const char *name)
1538c896fe29Sbellard {
1539c896fe29Sbellard     TCGTemp *ts;
1540c896fe29Sbellard 
15411a057554SRichard Henderson     tcg_debug_assert(TCG_TARGET_REG_BITS == 64 || type == TCG_TYPE_I32);
15427ca4b752SRichard Henderson 
15437ca4b752SRichard Henderson     ts = tcg_global_alloc(s);
1544c896fe29Sbellard     ts->base_type = type;
1545c896fe29Sbellard     ts->type = type;
1546ee17db83SRichard Henderson     ts->kind = TEMP_FIXED;
1547c896fe29Sbellard     ts->reg = reg;
1548c896fe29Sbellard     ts->name = name;
1549c896fe29Sbellard     tcg_regset_set_reg(s->reserved_regs, reg);
15507ca4b752SRichard Henderson 
1551085272b3SRichard Henderson     return ts;
1552a7812ae4Spbrook }
1553a7812ae4Spbrook 
1554b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size)
1555a7812ae4Spbrook {
1556b3a62939SRichard Henderson     s->frame_start = start;
1557b3a62939SRichard Henderson     s->frame_end = start + size;
1558085272b3SRichard Henderson     s->frame_temp
1559085272b3SRichard Henderson         = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame");
1560b3a62939SRichard Henderson }
1561a7812ae4Spbrook 
1562085272b3SRichard Henderson TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base,
1563e1ccc054SRichard Henderson                                      intptr_t offset, const char *name)
1564c896fe29Sbellard {
1565b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1566dc41aa7dSRichard Henderson     TCGTemp *base_ts = tcgv_ptr_temp(base);
15677ca4b752SRichard Henderson     TCGTemp *ts = tcg_global_alloc(s);
1568aef85402SRichard Henderson     int indirect_reg = 0;
1569c896fe29Sbellard 
1570c0522136SRichard Henderson     switch (base_ts->kind) {
1571c0522136SRichard Henderson     case TEMP_FIXED:
1572c0522136SRichard Henderson         break;
1573c0522136SRichard Henderson     case TEMP_GLOBAL:
15745a18407fSRichard Henderson         /* We do not support double-indirect registers.  */
15755a18407fSRichard Henderson         tcg_debug_assert(!base_ts->indirect_reg);
1576b3915dbbSRichard Henderson         base_ts->indirect_base = 1;
15775a18407fSRichard Henderson         s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64
15785a18407fSRichard Henderson                             ? 2 : 1);
15795a18407fSRichard Henderson         indirect_reg = 1;
1580c0522136SRichard Henderson         break;
1581c0522136SRichard Henderson     default:
1582c0522136SRichard Henderson         g_assert_not_reached();
1583b3915dbbSRichard Henderson     }
1584b3915dbbSRichard Henderson 
15857ca4b752SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
15867ca4b752SRichard Henderson         TCGTemp *ts2 = tcg_global_alloc(s);
1587c896fe29Sbellard         char buf[64];
15887ca4b752SRichard Henderson 
15897ca4b752SRichard Henderson         ts->base_type = TCG_TYPE_I64;
1590c896fe29Sbellard         ts->type = TCG_TYPE_I32;
1591b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1592c896fe29Sbellard         ts->mem_allocated = 1;
1593b3a62939SRichard Henderson         ts->mem_base = base_ts;
1594aef85402SRichard Henderson         ts->mem_offset = offset;
1595c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1596c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_0");
1597c896fe29Sbellard         ts->name = strdup(buf);
1598c896fe29Sbellard 
15997ca4b752SRichard Henderson         tcg_debug_assert(ts2 == ts + 1);
16007ca4b752SRichard Henderson         ts2->base_type = TCG_TYPE_I64;
16017ca4b752SRichard Henderson         ts2->type = TCG_TYPE_I32;
1602b3915dbbSRichard Henderson         ts2->indirect_reg = indirect_reg;
16037ca4b752SRichard Henderson         ts2->mem_allocated = 1;
16047ca4b752SRichard Henderson         ts2->mem_base = base_ts;
1605aef85402SRichard Henderson         ts2->mem_offset = offset + 4;
1606fac87bd2SRichard Henderson         ts2->temp_subindex = 1;
1607c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1608c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_1");
1609120c1084SRichard Henderson         ts2->name = strdup(buf);
16107ca4b752SRichard Henderson     } else {
1611c896fe29Sbellard         ts->base_type = type;
1612c896fe29Sbellard         ts->type = type;
1613b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1614c896fe29Sbellard         ts->mem_allocated = 1;
1615b3a62939SRichard Henderson         ts->mem_base = base_ts;
1616c896fe29Sbellard         ts->mem_offset = offset;
1617c896fe29Sbellard         ts->name = name;
1618c896fe29Sbellard     }
1619085272b3SRichard Henderson     return ts;
1620c896fe29Sbellard }
1621c896fe29Sbellard 
1622bbf989bfSRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, TCGTempKind kind)
1623c896fe29Sbellard {
1624b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1625c896fe29Sbellard     TCGTemp *ts;
1626e1c08b00SRichard Henderson     int n;
1627c896fe29Sbellard 
1628e1c08b00SRichard Henderson     if (kind == TEMP_EBB) {
1629e1c08b00SRichard Henderson         int idx = find_first_bit(s->free_temps[type].l, TCG_MAX_TEMPS);
1630e1c08b00SRichard Henderson 
16310ec9eabcSRichard Henderson         if (idx < TCG_MAX_TEMPS) {
16320ec9eabcSRichard Henderson             /* There is already an available temp with the right type.  */
1633e1c08b00SRichard Henderson             clear_bit(idx, s->free_temps[type].l);
16340ec9eabcSRichard Henderson 
1635e8996ee0Sbellard             ts = &s->temps[idx];
1636e8996ee0Sbellard             ts->temp_allocated = 1;
16377ca4b752SRichard Henderson             tcg_debug_assert(ts->base_type == type);
1638ee17db83SRichard Henderson             tcg_debug_assert(ts->kind == kind);
16392f2e911dSRichard Henderson             return ts;
1640e1c08b00SRichard Henderson         }
1641e8996ee0Sbellard     } else {
1642e1c08b00SRichard Henderson         tcg_debug_assert(kind == TEMP_TB);
1643e1c08b00SRichard Henderson     }
164443eef72fSRichard Henderson 
164543eef72fSRichard Henderson     switch (type) {
164643eef72fSRichard Henderson     case TCG_TYPE_I32:
164743eef72fSRichard Henderson     case TCG_TYPE_V64:
164843eef72fSRichard Henderson     case TCG_TYPE_V128:
164943eef72fSRichard Henderson     case TCG_TYPE_V256:
165043eef72fSRichard Henderson         n = 1;
165143eef72fSRichard Henderson         break;
165243eef72fSRichard Henderson     case TCG_TYPE_I64:
165343eef72fSRichard Henderson         n = 64 / TCG_TARGET_REG_BITS;
165443eef72fSRichard Henderson         break;
165543eef72fSRichard Henderson     case TCG_TYPE_I128:
165643eef72fSRichard Henderson         n = 128 / TCG_TARGET_REG_BITS;
165743eef72fSRichard Henderson         break;
165843eef72fSRichard Henderson     default:
165943eef72fSRichard Henderson         g_assert_not_reached();
166043eef72fSRichard Henderson     }
166143eef72fSRichard Henderson 
16627ca4b752SRichard Henderson     ts = tcg_temp_alloc(s);
166343eef72fSRichard Henderson     ts->base_type = type;
166443eef72fSRichard Henderson     ts->temp_allocated = 1;
166543eef72fSRichard Henderson     ts->kind = kind;
166643eef72fSRichard Henderson 
166743eef72fSRichard Henderson     if (n == 1) {
166843eef72fSRichard Henderson         ts->type = type;
166943eef72fSRichard Henderson     } else {
167043eef72fSRichard Henderson         ts->type = TCG_TYPE_REG;
167143eef72fSRichard Henderson 
1672e1c08b00SRichard Henderson         for (int i = 1; i < n; ++i) {
16737ca4b752SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
16747ca4b752SRichard Henderson 
167543eef72fSRichard Henderson             tcg_debug_assert(ts2 == ts + i);
167643eef72fSRichard Henderson             ts2->base_type = type;
167743eef72fSRichard Henderson             ts2->type = TCG_TYPE_REG;
16787ca4b752SRichard Henderson             ts2->temp_allocated = 1;
167943eef72fSRichard Henderson             ts2->temp_subindex = i;
1680ee17db83SRichard Henderson             ts2->kind = kind;
168143eef72fSRichard Henderson         }
1682c896fe29Sbellard     }
1683085272b3SRichard Henderson     return ts;
1684c896fe29Sbellard }
1685c896fe29Sbellard 
1686d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type)
1687d2fd745fSRichard Henderson {
1688d2fd745fSRichard Henderson     TCGTemp *t;
1689d2fd745fSRichard Henderson 
1690d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG
1691d2fd745fSRichard Henderson     switch (type) {
1692d2fd745fSRichard Henderson     case TCG_TYPE_V64:
1693d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v64);
1694d2fd745fSRichard Henderson         break;
1695d2fd745fSRichard Henderson     case TCG_TYPE_V128:
1696d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v128);
1697d2fd745fSRichard Henderson         break;
1698d2fd745fSRichard Henderson     case TCG_TYPE_V256:
1699d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v256);
1700d2fd745fSRichard Henderson         break;
1701d2fd745fSRichard Henderson     default:
1702d2fd745fSRichard Henderson         g_assert_not_reached();
1703d2fd745fSRichard Henderson     }
1704d2fd745fSRichard Henderson #endif
1705d2fd745fSRichard Henderson 
1706bbf989bfSRichard Henderson     t = tcg_temp_new_internal(type, TEMP_EBB);
1707d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1708d2fd745fSRichard Henderson }
1709d2fd745fSRichard Henderson 
1710d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp.  */
1711d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match)
1712d2fd745fSRichard Henderson {
1713d2fd745fSRichard Henderson     TCGTemp *t = tcgv_vec_temp(match);
1714d2fd745fSRichard Henderson 
1715d2fd745fSRichard Henderson     tcg_debug_assert(t->temp_allocated != 0);
1716d2fd745fSRichard Henderson 
1717bbf989bfSRichard Henderson     t = tcg_temp_new_internal(t->base_type, TEMP_EBB);
1718d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1719d2fd745fSRichard Henderson }
1720d2fd745fSRichard Henderson 
17215bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts)
1722c896fe29Sbellard {
1723b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1724c896fe29Sbellard 
1725c7482438SRichard Henderson     switch (ts->kind) {
1726c7482438SRichard Henderson     case TEMP_CONST:
1727f57c6915SRichard Henderson     case TEMP_TB:
17282f2e911dSRichard Henderson         /* Silently ignore free. */
1729c7482438SRichard Henderson         break;
17302f2e911dSRichard Henderson     case TEMP_EBB:
1731eabb7b91SAurelien Jarno         tcg_debug_assert(ts->temp_allocated != 0);
1732e8996ee0Sbellard         ts->temp_allocated = 0;
17332f2e911dSRichard Henderson         set_bit(temp_idx(ts), s->free_temps[ts->base_type].l);
17342f2e911dSRichard Henderson         break;
17352f2e911dSRichard Henderson     default:
17362f2e911dSRichard Henderson         /* It never made sense to free TEMP_FIXED or TEMP_GLOBAL. */
17372f2e911dSRichard Henderson         g_assert_not_reached();
1738e1c08b00SRichard Henderson     }
1739e8996ee0Sbellard }
1740e8996ee0Sbellard 
1741c0522136SRichard Henderson TCGTemp *tcg_constant_internal(TCGType type, int64_t val)
1742c0522136SRichard Henderson {
1743c0522136SRichard Henderson     TCGContext *s = tcg_ctx;
1744c0522136SRichard Henderson     GHashTable *h = s->const_table[type];
1745c0522136SRichard Henderson     TCGTemp *ts;
1746c0522136SRichard Henderson 
1747c0522136SRichard Henderson     if (h == NULL) {
1748c0522136SRichard Henderson         h = g_hash_table_new(g_int64_hash, g_int64_equal);
1749c0522136SRichard Henderson         s->const_table[type] = h;
1750c0522136SRichard Henderson     }
1751c0522136SRichard Henderson 
1752c0522136SRichard Henderson     ts = g_hash_table_lookup(h, &val);
1753c0522136SRichard Henderson     if (ts == NULL) {
1754aef85402SRichard Henderson         int64_t *val_ptr;
1755aef85402SRichard Henderson 
1756c0522136SRichard Henderson         ts = tcg_temp_alloc(s);
1757c0522136SRichard Henderson 
1758c0522136SRichard Henderson         if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
1759c0522136SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
1760c0522136SRichard Henderson 
1761aef85402SRichard Henderson             tcg_debug_assert(ts2 == ts + 1);
1762aef85402SRichard Henderson 
1763c0522136SRichard Henderson             ts->base_type = TCG_TYPE_I64;
1764c0522136SRichard Henderson             ts->type = TCG_TYPE_I32;
1765c0522136SRichard Henderson             ts->kind = TEMP_CONST;
1766c0522136SRichard Henderson             ts->temp_allocated = 1;
1767c0522136SRichard Henderson 
1768c0522136SRichard Henderson             ts2->base_type = TCG_TYPE_I64;
1769c0522136SRichard Henderson             ts2->type = TCG_TYPE_I32;
1770c0522136SRichard Henderson             ts2->kind = TEMP_CONST;
1771c0522136SRichard Henderson             ts2->temp_allocated = 1;
1772fac87bd2SRichard Henderson             ts2->temp_subindex = 1;
1773aef85402SRichard Henderson 
1774aef85402SRichard Henderson             /*
1775aef85402SRichard Henderson              * Retain the full value of the 64-bit constant in the low
1776aef85402SRichard Henderson              * part, so that the hash table works.  Actual uses will
1777aef85402SRichard Henderson              * truncate the value to the low part.
1778aef85402SRichard Henderson              */
1779aef85402SRichard Henderson             ts[HOST_BIG_ENDIAN].val = val;
1780aef85402SRichard Henderson             ts[!HOST_BIG_ENDIAN].val = val >> 32;
1781aef85402SRichard Henderson             val_ptr = &ts[HOST_BIG_ENDIAN].val;
1782c0522136SRichard Henderson         } else {
1783c0522136SRichard Henderson             ts->base_type = type;
1784c0522136SRichard Henderson             ts->type = type;
1785c0522136SRichard Henderson             ts->kind = TEMP_CONST;
1786c0522136SRichard Henderson             ts->temp_allocated = 1;
1787c0522136SRichard Henderson             ts->val = val;
1788aef85402SRichard Henderson             val_ptr = &ts->val;
1789c0522136SRichard Henderson         }
1790aef85402SRichard Henderson         g_hash_table_insert(h, val_ptr, ts);
1791c0522136SRichard Henderson     }
1792c0522136SRichard Henderson 
1793c0522136SRichard Henderson     return ts;
1794c0522136SRichard Henderson }
1795c0522136SRichard Henderson 
1796c0522136SRichard Henderson TCGv_vec tcg_constant_vec(TCGType type, unsigned vece, int64_t val)
1797c0522136SRichard Henderson {
1798c0522136SRichard Henderson     val = dup_const(vece, val);
1799c0522136SRichard Henderson     return temp_tcgv_vec(tcg_constant_internal(type, val));
1800c0522136SRichard Henderson }
1801c0522136SRichard Henderson 
180288d4005bSRichard Henderson TCGv_vec tcg_constant_vec_matching(TCGv_vec match, unsigned vece, int64_t val)
180388d4005bSRichard Henderson {
180488d4005bSRichard Henderson     TCGTemp *t = tcgv_vec_temp(match);
180588d4005bSRichard Henderson 
180688d4005bSRichard Henderson     tcg_debug_assert(t->temp_allocated != 0);
180788d4005bSRichard Henderson     return tcg_constant_vec(t->base_type, vece, val);
180888d4005bSRichard Henderson }
180988d4005bSRichard Henderson 
1810177f648fSRichard Henderson #ifdef CONFIG_DEBUG_TCG
1811177f648fSRichard Henderson size_t temp_idx(TCGTemp *ts)
1812177f648fSRichard Henderson {
1813177f648fSRichard Henderson     ptrdiff_t n = ts - tcg_ctx->temps;
1814177f648fSRichard Henderson     assert(n >= 0 && n < tcg_ctx->nb_temps);
1815177f648fSRichard Henderson     return n;
1816177f648fSRichard Henderson }
1817177f648fSRichard Henderson 
1818177f648fSRichard Henderson TCGTemp *tcgv_i32_temp(TCGv_i32 v)
1819177f648fSRichard Henderson {
1820177f648fSRichard Henderson     uintptr_t o = (uintptr_t)v - offsetof(TCGContext, temps);
1821177f648fSRichard Henderson 
1822177f648fSRichard Henderson     assert(o < sizeof(TCGTemp) * tcg_ctx->nb_temps);
1823177f648fSRichard Henderson     assert(o % sizeof(TCGTemp) == 0);
1824177f648fSRichard Henderson 
1825177f648fSRichard Henderson     return (void *)tcg_ctx + (uintptr_t)v;
1826177f648fSRichard Henderson }
1827177f648fSRichard Henderson #endif /* CONFIG_DEBUG_TCG */
1828177f648fSRichard Henderson 
1829be0f34b5SRichard Henderson /* Return true if OP may appear in the opcode stream.
1830be0f34b5SRichard Henderson    Test the runtime variable that controls each opcode.  */
1831be0f34b5SRichard Henderson bool tcg_op_supported(TCGOpcode op)
1832be0f34b5SRichard Henderson {
1833d2fd745fSRichard Henderson     const bool have_vec
1834d2fd745fSRichard Henderson         = TCG_TARGET_HAS_v64 | TCG_TARGET_HAS_v128 | TCG_TARGET_HAS_v256;
1835d2fd745fSRichard Henderson 
1836be0f34b5SRichard Henderson     switch (op) {
1837be0f34b5SRichard Henderson     case INDEX_op_discard:
1838be0f34b5SRichard Henderson     case INDEX_op_set_label:
1839be0f34b5SRichard Henderson     case INDEX_op_call:
1840be0f34b5SRichard Henderson     case INDEX_op_br:
1841be0f34b5SRichard Henderson     case INDEX_op_mb:
1842be0f34b5SRichard Henderson     case INDEX_op_insn_start:
1843be0f34b5SRichard Henderson     case INDEX_op_exit_tb:
1844be0f34b5SRichard Henderson     case INDEX_op_goto_tb:
1845f4e01e30SRichard Henderson     case INDEX_op_goto_ptr:
1846fecccfccSRichard Henderson     case INDEX_op_qemu_ld_a32_i32:
1847fecccfccSRichard Henderson     case INDEX_op_qemu_ld_a64_i32:
1848fecccfccSRichard Henderson     case INDEX_op_qemu_st_a32_i32:
1849fecccfccSRichard Henderson     case INDEX_op_qemu_st_a64_i32:
1850fecccfccSRichard Henderson     case INDEX_op_qemu_ld_a32_i64:
1851fecccfccSRichard Henderson     case INDEX_op_qemu_ld_a64_i64:
1852fecccfccSRichard Henderson     case INDEX_op_qemu_st_a32_i64:
1853fecccfccSRichard Henderson     case INDEX_op_qemu_st_a64_i64:
1854be0f34b5SRichard Henderson         return true;
1855be0f34b5SRichard Henderson 
1856fecccfccSRichard Henderson     case INDEX_op_qemu_st8_a32_i32:
1857fecccfccSRichard Henderson     case INDEX_op_qemu_st8_a64_i32:
185807ce0b05SRichard Henderson         return TCG_TARGET_HAS_qemu_st8_i32;
185907ce0b05SRichard Henderson 
1860fecccfccSRichard Henderson     case INDEX_op_qemu_ld_a32_i128:
1861fecccfccSRichard Henderson     case INDEX_op_qemu_ld_a64_i128:
1862fecccfccSRichard Henderson     case INDEX_op_qemu_st_a32_i128:
1863fecccfccSRichard Henderson     case INDEX_op_qemu_st_a64_i128:
186412fde9bcSRichard Henderson         return TCG_TARGET_HAS_qemu_ldst_i128;
186512fde9bcSRichard Henderson 
1866be0f34b5SRichard Henderson     case INDEX_op_mov_i32:
1867be0f34b5SRichard Henderson     case INDEX_op_setcond_i32:
1868be0f34b5SRichard Henderson     case INDEX_op_brcond_i32:
1869be0f34b5SRichard Henderson     case INDEX_op_ld8u_i32:
1870be0f34b5SRichard Henderson     case INDEX_op_ld8s_i32:
1871be0f34b5SRichard Henderson     case INDEX_op_ld16u_i32:
1872be0f34b5SRichard Henderson     case INDEX_op_ld16s_i32:
1873be0f34b5SRichard Henderson     case INDEX_op_ld_i32:
1874be0f34b5SRichard Henderson     case INDEX_op_st8_i32:
1875be0f34b5SRichard Henderson     case INDEX_op_st16_i32:
1876be0f34b5SRichard Henderson     case INDEX_op_st_i32:
1877be0f34b5SRichard Henderson     case INDEX_op_add_i32:
1878be0f34b5SRichard Henderson     case INDEX_op_sub_i32:
1879be0f34b5SRichard Henderson     case INDEX_op_mul_i32:
1880be0f34b5SRichard Henderson     case INDEX_op_and_i32:
1881be0f34b5SRichard Henderson     case INDEX_op_or_i32:
1882be0f34b5SRichard Henderson     case INDEX_op_xor_i32:
1883be0f34b5SRichard Henderson     case INDEX_op_shl_i32:
1884be0f34b5SRichard Henderson     case INDEX_op_shr_i32:
1885be0f34b5SRichard Henderson     case INDEX_op_sar_i32:
1886be0f34b5SRichard Henderson         return true;
1887be0f34b5SRichard Henderson 
18883635502dSRichard Henderson     case INDEX_op_negsetcond_i32:
18893635502dSRichard Henderson         return TCG_TARGET_HAS_negsetcond_i32;
1890be0f34b5SRichard Henderson     case INDEX_op_movcond_i32:
1891be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i32;
1892be0f34b5SRichard Henderson     case INDEX_op_div_i32:
1893be0f34b5SRichard Henderson     case INDEX_op_divu_i32:
1894be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i32;
1895be0f34b5SRichard Henderson     case INDEX_op_rem_i32:
1896be0f34b5SRichard Henderson     case INDEX_op_remu_i32:
1897be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i32;
1898be0f34b5SRichard Henderson     case INDEX_op_div2_i32:
1899be0f34b5SRichard Henderson     case INDEX_op_divu2_i32:
1900be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i32;
1901be0f34b5SRichard Henderson     case INDEX_op_rotl_i32:
1902be0f34b5SRichard Henderson     case INDEX_op_rotr_i32:
1903be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i32;
1904be0f34b5SRichard Henderson     case INDEX_op_deposit_i32:
1905be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i32;
1906be0f34b5SRichard Henderson     case INDEX_op_extract_i32:
1907be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i32;
1908be0f34b5SRichard Henderson     case INDEX_op_sextract_i32:
1909be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i32;
1910fce1296fSRichard Henderson     case INDEX_op_extract2_i32:
1911fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i32;
1912be0f34b5SRichard Henderson     case INDEX_op_add2_i32:
1913be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i32;
1914be0f34b5SRichard Henderson     case INDEX_op_sub2_i32:
1915be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i32;
1916be0f34b5SRichard Henderson     case INDEX_op_mulu2_i32:
1917be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i32;
1918be0f34b5SRichard Henderson     case INDEX_op_muls2_i32:
1919be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i32;
1920be0f34b5SRichard Henderson     case INDEX_op_muluh_i32:
1921be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i32;
1922be0f34b5SRichard Henderson     case INDEX_op_mulsh_i32:
1923be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i32;
1924be0f34b5SRichard Henderson     case INDEX_op_ext8s_i32:
1925be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i32;
1926be0f34b5SRichard Henderson     case INDEX_op_ext16s_i32:
1927be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i32;
1928be0f34b5SRichard Henderson     case INDEX_op_ext8u_i32:
1929be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i32;
1930be0f34b5SRichard Henderson     case INDEX_op_ext16u_i32:
1931be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i32;
1932be0f34b5SRichard Henderson     case INDEX_op_bswap16_i32:
1933be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i32;
1934be0f34b5SRichard Henderson     case INDEX_op_bswap32_i32:
1935be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i32;
1936be0f34b5SRichard Henderson     case INDEX_op_not_i32:
1937be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i32;
1938be0f34b5SRichard Henderson     case INDEX_op_neg_i32:
1939be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i32;
1940be0f34b5SRichard Henderson     case INDEX_op_andc_i32:
1941be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i32;
1942be0f34b5SRichard Henderson     case INDEX_op_orc_i32:
1943be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i32;
1944be0f34b5SRichard Henderson     case INDEX_op_eqv_i32:
1945be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i32;
1946be0f34b5SRichard Henderson     case INDEX_op_nand_i32:
1947be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i32;
1948be0f34b5SRichard Henderson     case INDEX_op_nor_i32:
1949be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i32;
1950be0f34b5SRichard Henderson     case INDEX_op_clz_i32:
1951be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i32;
1952be0f34b5SRichard Henderson     case INDEX_op_ctz_i32:
1953be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i32;
1954be0f34b5SRichard Henderson     case INDEX_op_ctpop_i32:
1955be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i32;
1956be0f34b5SRichard Henderson 
1957be0f34b5SRichard Henderson     case INDEX_op_brcond2_i32:
1958be0f34b5SRichard Henderson     case INDEX_op_setcond2_i32:
1959be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 32;
1960be0f34b5SRichard Henderson 
1961be0f34b5SRichard Henderson     case INDEX_op_mov_i64:
1962be0f34b5SRichard Henderson     case INDEX_op_setcond_i64:
1963be0f34b5SRichard Henderson     case INDEX_op_brcond_i64:
1964be0f34b5SRichard Henderson     case INDEX_op_ld8u_i64:
1965be0f34b5SRichard Henderson     case INDEX_op_ld8s_i64:
1966be0f34b5SRichard Henderson     case INDEX_op_ld16u_i64:
1967be0f34b5SRichard Henderson     case INDEX_op_ld16s_i64:
1968be0f34b5SRichard Henderson     case INDEX_op_ld32u_i64:
1969be0f34b5SRichard Henderson     case INDEX_op_ld32s_i64:
1970be0f34b5SRichard Henderson     case INDEX_op_ld_i64:
1971be0f34b5SRichard Henderson     case INDEX_op_st8_i64:
1972be0f34b5SRichard Henderson     case INDEX_op_st16_i64:
1973be0f34b5SRichard Henderson     case INDEX_op_st32_i64:
1974be0f34b5SRichard Henderson     case INDEX_op_st_i64:
1975be0f34b5SRichard Henderson     case INDEX_op_add_i64:
1976be0f34b5SRichard Henderson     case INDEX_op_sub_i64:
1977be0f34b5SRichard Henderson     case INDEX_op_mul_i64:
1978be0f34b5SRichard Henderson     case INDEX_op_and_i64:
1979be0f34b5SRichard Henderson     case INDEX_op_or_i64:
1980be0f34b5SRichard Henderson     case INDEX_op_xor_i64:
1981be0f34b5SRichard Henderson     case INDEX_op_shl_i64:
1982be0f34b5SRichard Henderson     case INDEX_op_shr_i64:
1983be0f34b5SRichard Henderson     case INDEX_op_sar_i64:
1984be0f34b5SRichard Henderson     case INDEX_op_ext_i32_i64:
1985be0f34b5SRichard Henderson     case INDEX_op_extu_i32_i64:
1986be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 64;
1987be0f34b5SRichard Henderson 
19883635502dSRichard Henderson     case INDEX_op_negsetcond_i64:
19893635502dSRichard Henderson         return TCG_TARGET_HAS_negsetcond_i64;
1990be0f34b5SRichard Henderson     case INDEX_op_movcond_i64:
1991be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i64;
1992be0f34b5SRichard Henderson     case INDEX_op_div_i64:
1993be0f34b5SRichard Henderson     case INDEX_op_divu_i64:
1994be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i64;
1995be0f34b5SRichard Henderson     case INDEX_op_rem_i64:
1996be0f34b5SRichard Henderson     case INDEX_op_remu_i64:
1997be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i64;
1998be0f34b5SRichard Henderson     case INDEX_op_div2_i64:
1999be0f34b5SRichard Henderson     case INDEX_op_divu2_i64:
2000be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i64;
2001be0f34b5SRichard Henderson     case INDEX_op_rotl_i64:
2002be0f34b5SRichard Henderson     case INDEX_op_rotr_i64:
2003be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i64;
2004be0f34b5SRichard Henderson     case INDEX_op_deposit_i64:
2005be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i64;
2006be0f34b5SRichard Henderson     case INDEX_op_extract_i64:
2007be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i64;
2008be0f34b5SRichard Henderson     case INDEX_op_sextract_i64:
2009be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i64;
2010fce1296fSRichard Henderson     case INDEX_op_extract2_i64:
2011fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i64;
2012be0f34b5SRichard Henderson     case INDEX_op_extrl_i64_i32:
2013be0f34b5SRichard Henderson     case INDEX_op_extrh_i64_i32:
201413d885b0SRichard Henderson         return TCG_TARGET_HAS_extr_i64_i32;
2015be0f34b5SRichard Henderson     case INDEX_op_ext8s_i64:
2016be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i64;
2017be0f34b5SRichard Henderson     case INDEX_op_ext16s_i64:
2018be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i64;
2019be0f34b5SRichard Henderson     case INDEX_op_ext32s_i64:
2020be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32s_i64;
2021be0f34b5SRichard Henderson     case INDEX_op_ext8u_i64:
2022be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i64;
2023be0f34b5SRichard Henderson     case INDEX_op_ext16u_i64:
2024be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i64;
2025be0f34b5SRichard Henderson     case INDEX_op_ext32u_i64:
2026be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32u_i64;
2027be0f34b5SRichard Henderson     case INDEX_op_bswap16_i64:
2028be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i64;
2029be0f34b5SRichard Henderson     case INDEX_op_bswap32_i64:
2030be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i64;
2031be0f34b5SRichard Henderson     case INDEX_op_bswap64_i64:
2032be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap64_i64;
2033be0f34b5SRichard Henderson     case INDEX_op_not_i64:
2034be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i64;
2035be0f34b5SRichard Henderson     case INDEX_op_neg_i64:
2036be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i64;
2037be0f34b5SRichard Henderson     case INDEX_op_andc_i64:
2038be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i64;
2039be0f34b5SRichard Henderson     case INDEX_op_orc_i64:
2040be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i64;
2041be0f34b5SRichard Henderson     case INDEX_op_eqv_i64:
2042be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i64;
2043be0f34b5SRichard Henderson     case INDEX_op_nand_i64:
2044be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i64;
2045be0f34b5SRichard Henderson     case INDEX_op_nor_i64:
2046be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i64;
2047be0f34b5SRichard Henderson     case INDEX_op_clz_i64:
2048be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i64;
2049be0f34b5SRichard Henderson     case INDEX_op_ctz_i64:
2050be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i64;
2051be0f34b5SRichard Henderson     case INDEX_op_ctpop_i64:
2052be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i64;
2053be0f34b5SRichard Henderson     case INDEX_op_add2_i64:
2054be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i64;
2055be0f34b5SRichard Henderson     case INDEX_op_sub2_i64:
2056be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i64;
2057be0f34b5SRichard Henderson     case INDEX_op_mulu2_i64:
2058be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i64;
2059be0f34b5SRichard Henderson     case INDEX_op_muls2_i64:
2060be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i64;
2061be0f34b5SRichard Henderson     case INDEX_op_muluh_i64:
2062be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i64;
2063be0f34b5SRichard Henderson     case INDEX_op_mulsh_i64:
2064be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i64;
2065be0f34b5SRichard Henderson 
2066d2fd745fSRichard Henderson     case INDEX_op_mov_vec:
2067d2fd745fSRichard Henderson     case INDEX_op_dup_vec:
206837ee55a0SRichard Henderson     case INDEX_op_dupm_vec:
2069d2fd745fSRichard Henderson     case INDEX_op_ld_vec:
2070d2fd745fSRichard Henderson     case INDEX_op_st_vec:
2071d2fd745fSRichard Henderson     case INDEX_op_add_vec:
2072d2fd745fSRichard Henderson     case INDEX_op_sub_vec:
2073d2fd745fSRichard Henderson     case INDEX_op_and_vec:
2074d2fd745fSRichard Henderson     case INDEX_op_or_vec:
2075d2fd745fSRichard Henderson     case INDEX_op_xor_vec:
2076212be173SRichard Henderson     case INDEX_op_cmp_vec:
2077d2fd745fSRichard Henderson         return have_vec;
2078d2fd745fSRichard Henderson     case INDEX_op_dup2_vec:
2079d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_REG_BITS == 32;
2080d2fd745fSRichard Henderson     case INDEX_op_not_vec:
2081d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_not_vec;
2082d2fd745fSRichard Henderson     case INDEX_op_neg_vec:
2083d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_neg_vec;
2084bcefc902SRichard Henderson     case INDEX_op_abs_vec:
2085bcefc902SRichard Henderson         return have_vec && TCG_TARGET_HAS_abs_vec;
2086d2fd745fSRichard Henderson     case INDEX_op_andc_vec:
2087d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_andc_vec;
2088d2fd745fSRichard Henderson     case INDEX_op_orc_vec:
2089d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_orc_vec;
2090ed523473SRichard Henderson     case INDEX_op_nand_vec:
2091ed523473SRichard Henderson         return have_vec && TCG_TARGET_HAS_nand_vec;
2092ed523473SRichard Henderson     case INDEX_op_nor_vec:
2093ed523473SRichard Henderson         return have_vec && TCG_TARGET_HAS_nor_vec;
2094ed523473SRichard Henderson     case INDEX_op_eqv_vec:
2095ed523473SRichard Henderson         return have_vec && TCG_TARGET_HAS_eqv_vec;
20963774030aSRichard Henderson     case INDEX_op_mul_vec:
20973774030aSRichard Henderson         return have_vec && TCG_TARGET_HAS_mul_vec;
2098d0ec9796SRichard Henderson     case INDEX_op_shli_vec:
2099d0ec9796SRichard Henderson     case INDEX_op_shri_vec:
2100d0ec9796SRichard Henderson     case INDEX_op_sari_vec:
2101d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shi_vec;
2102d0ec9796SRichard Henderson     case INDEX_op_shls_vec:
2103d0ec9796SRichard Henderson     case INDEX_op_shrs_vec:
2104d0ec9796SRichard Henderson     case INDEX_op_sars_vec:
2105d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shs_vec;
2106d0ec9796SRichard Henderson     case INDEX_op_shlv_vec:
2107d0ec9796SRichard Henderson     case INDEX_op_shrv_vec:
2108d0ec9796SRichard Henderson     case INDEX_op_sarv_vec:
2109d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shv_vec;
2110b0f7e744SRichard Henderson     case INDEX_op_rotli_vec:
2111b0f7e744SRichard Henderson         return have_vec && TCG_TARGET_HAS_roti_vec;
211223850a74SRichard Henderson     case INDEX_op_rotls_vec:
211323850a74SRichard Henderson         return have_vec && TCG_TARGET_HAS_rots_vec;
21145d0ceda9SRichard Henderson     case INDEX_op_rotlv_vec:
21155d0ceda9SRichard Henderson     case INDEX_op_rotrv_vec:
21165d0ceda9SRichard Henderson         return have_vec && TCG_TARGET_HAS_rotv_vec;
21178afaf050SRichard Henderson     case INDEX_op_ssadd_vec:
21188afaf050SRichard Henderson     case INDEX_op_usadd_vec:
21198afaf050SRichard Henderson     case INDEX_op_sssub_vec:
21208afaf050SRichard Henderson     case INDEX_op_ussub_vec:
21218afaf050SRichard Henderson         return have_vec && TCG_TARGET_HAS_sat_vec;
2122dd0a0fcdSRichard Henderson     case INDEX_op_smin_vec:
2123dd0a0fcdSRichard Henderson     case INDEX_op_umin_vec:
2124dd0a0fcdSRichard Henderson     case INDEX_op_smax_vec:
2125dd0a0fcdSRichard Henderson     case INDEX_op_umax_vec:
2126dd0a0fcdSRichard Henderson         return have_vec && TCG_TARGET_HAS_minmax_vec;
212738dc1294SRichard Henderson     case INDEX_op_bitsel_vec:
212838dc1294SRichard Henderson         return have_vec && TCG_TARGET_HAS_bitsel_vec;
2129f75da298SRichard Henderson     case INDEX_op_cmpsel_vec:
2130f75da298SRichard Henderson         return have_vec && TCG_TARGET_HAS_cmpsel_vec;
2131d2fd745fSRichard Henderson 
2132db432672SRichard Henderson     default:
2133db432672SRichard Henderson         tcg_debug_assert(op > INDEX_op_last_generic && op < NB_OPS);
2134db432672SRichard Henderson         return true;
2135be0f34b5SRichard Henderson     }
2136be0f34b5SRichard Henderson }
2137be0f34b5SRichard Henderson 
213839004a71SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs);
213939004a71SRichard Henderson 
2140a3a692b8SRichard Henderson static void tcg_gen_callN(TCGHelperInfo *info, TCGTemp *ret, TCGTemp **args)
2141c896fe29Sbellard {
214239004a71SRichard Henderson     TCGv_i64 extend_free[MAX_CALL_IARGS];
214339004a71SRichard Henderson     int n_extend = 0;
214475e8b9b7SRichard Henderson     TCGOp *op;
214539004a71SRichard Henderson     int i, n, pi = 0, total_args;
2146afb49896SRichard Henderson 
2147d53106c9SRichard Henderson     if (unlikely(g_once_init_enter(HELPER_INFO_INIT(info)))) {
2148d53106c9SRichard Henderson         init_call_layout(info);
2149d53106c9SRichard Henderson         g_once_init_leave(HELPER_INFO_INIT(info), HELPER_INFO_INIT_VAL(info));
2150d53106c9SRichard Henderson     }
2151d53106c9SRichard Henderson 
215239004a71SRichard Henderson     total_args = info->nr_out + info->nr_in + 2;
215339004a71SRichard Henderson     op = tcg_op_alloc(INDEX_op_call, total_args);
21542bece2c8SRichard Henderson 
215538b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN
215617083f6fSEmilio Cota     /* Flag helpers that may affect guest state */
215717083f6fSEmilio Cota     if (tcg_ctx->plugin_insn &&
215817083f6fSEmilio Cota         !(info->flags & TCG_CALL_PLUGIN) &&
215917083f6fSEmilio Cota         !(info->flags & TCG_CALL_NO_SIDE_EFFECTS)) {
216038b47b19SEmilio G. Cota         tcg_ctx->plugin_insn->calls_helpers = true;
216138b47b19SEmilio G. Cota     }
216238b47b19SEmilio G. Cota #endif
216338b47b19SEmilio G. Cota 
216439004a71SRichard Henderson     TCGOP_CALLO(op) = n = info->nr_out;
216539004a71SRichard Henderson     switch (n) {
216639004a71SRichard Henderson     case 0:
216739004a71SRichard Henderson         tcg_debug_assert(ret == NULL);
216839004a71SRichard Henderson         break;
216939004a71SRichard Henderson     case 1:
217039004a71SRichard Henderson         tcg_debug_assert(ret != NULL);
217139004a71SRichard Henderson         op->args[pi++] = temp_arg(ret);
217239004a71SRichard Henderson         break;
217339004a71SRichard Henderson     case 2:
2174466d3759SRichard Henderson     case 4:
217539004a71SRichard Henderson         tcg_debug_assert(ret != NULL);
2176466d3759SRichard Henderson         tcg_debug_assert(ret->base_type == ret->type + ctz32(n));
217739004a71SRichard Henderson         tcg_debug_assert(ret->temp_subindex == 0);
2178466d3759SRichard Henderson         for (i = 0; i < n; ++i) {
2179466d3759SRichard Henderson             op->args[pi++] = temp_arg(ret + i);
2180466d3759SRichard Henderson         }
218139004a71SRichard Henderson         break;
218239004a71SRichard Henderson     default:
218339004a71SRichard Henderson         g_assert_not_reached();
218439004a71SRichard Henderson     }
21857319d83aSRichard Henderson 
218639004a71SRichard Henderson     TCGOP_CALLI(op) = n = info->nr_in;
218739004a71SRichard Henderson     for (i = 0; i < n; i++) {
218839004a71SRichard Henderson         const TCGCallArgumentLoc *loc = &info->in[i];
218939004a71SRichard Henderson         TCGTemp *ts = args[loc->arg_idx] + loc->tmp_subindex;
219039004a71SRichard Henderson 
219139004a71SRichard Henderson         switch (loc->kind) {
219239004a71SRichard Henderson         case TCG_CALL_ARG_NORMAL:
2193313bdea8SRichard Henderson         case TCG_CALL_ARG_BY_REF:
2194313bdea8SRichard Henderson         case TCG_CALL_ARG_BY_REF_N:
219539004a71SRichard Henderson             op->args[pi++] = temp_arg(ts);
219639004a71SRichard Henderson             break;
219739004a71SRichard Henderson 
219839004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_U:
219939004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_S:
220039004a71SRichard Henderson             {
22015dd48602SRichard Henderson                 TCGv_i64 temp = tcg_temp_ebb_new_i64();
220239004a71SRichard Henderson                 TCGv_i32 orig = temp_tcgv_i32(ts);
220339004a71SRichard Henderson 
220439004a71SRichard Henderson                 if (loc->kind == TCG_CALL_ARG_EXTEND_S) {
220518cf3d07SRichard Henderson                     tcg_gen_ext_i32_i64(temp, orig);
22062bece2c8SRichard Henderson                 } else {
220718cf3d07SRichard Henderson                     tcg_gen_extu_i32_i64(temp, orig);
22082bece2c8SRichard Henderson                 }
220939004a71SRichard Henderson                 op->args[pi++] = tcgv_i64_arg(temp);
221039004a71SRichard Henderson                 extend_free[n_extend++] = temp;
22112bece2c8SRichard Henderson             }
221239004a71SRichard Henderson             break;
22132bece2c8SRichard Henderson 
2214e2a9dd6bSRichard Henderson         default:
2215e2a9dd6bSRichard Henderson             g_assert_not_reached();
2216e2a9dd6bSRichard Henderson         }
2217c896fe29Sbellard     }
2218d53106c9SRichard Henderson     op->args[pi++] = (uintptr_t)info->func;
22193e92aa34SRichard Henderson     op->args[pi++] = (uintptr_t)info;
222039004a71SRichard Henderson     tcg_debug_assert(pi == total_args);
2221a7812ae4Spbrook 
222239004a71SRichard Henderson     QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
22232bece2c8SRichard Henderson 
222439004a71SRichard Henderson     tcg_debug_assert(n_extend < ARRAY_SIZE(extend_free));
222539004a71SRichard Henderson     for (i = 0; i < n_extend; ++i) {
222639004a71SRichard Henderson         tcg_temp_free_i64(extend_free[i]);
2227eb8b0224SRichard Henderson     }
2228a7812ae4Spbrook }
2229c896fe29Sbellard 
2230a3a692b8SRichard Henderson void tcg_gen_call0(TCGHelperInfo *info, TCGTemp *ret)
2231a3a692b8SRichard Henderson {
2232a3a692b8SRichard Henderson     tcg_gen_callN(info, ret, NULL);
2233a3a692b8SRichard Henderson }
2234a3a692b8SRichard Henderson 
2235a3a692b8SRichard Henderson void tcg_gen_call1(TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1)
2236a3a692b8SRichard Henderson {
2237a3a692b8SRichard Henderson     tcg_gen_callN(info, ret, &t1);
2238a3a692b8SRichard Henderson }
2239a3a692b8SRichard Henderson 
2240a3a692b8SRichard Henderson void tcg_gen_call2(TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1, TCGTemp *t2)
2241a3a692b8SRichard Henderson {
2242a3a692b8SRichard Henderson     TCGTemp *args[2] = { t1, t2 };
2243a3a692b8SRichard Henderson     tcg_gen_callN(info, ret, args);
2244a3a692b8SRichard Henderson }
2245a3a692b8SRichard Henderson 
2246a3a692b8SRichard Henderson void tcg_gen_call3(TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1,
2247a3a692b8SRichard Henderson                    TCGTemp *t2, TCGTemp *t3)
2248a3a692b8SRichard Henderson {
2249a3a692b8SRichard Henderson     TCGTemp *args[3] = { t1, t2, t3 };
2250a3a692b8SRichard Henderson     tcg_gen_callN(info, ret, args);
2251a3a692b8SRichard Henderson }
2252a3a692b8SRichard Henderson 
2253a3a692b8SRichard Henderson void tcg_gen_call4(TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1,
2254a3a692b8SRichard Henderson                    TCGTemp *t2, TCGTemp *t3, TCGTemp *t4)
2255a3a692b8SRichard Henderson {
2256a3a692b8SRichard Henderson     TCGTemp *args[4] = { t1, t2, t3, t4 };
2257a3a692b8SRichard Henderson     tcg_gen_callN(info, ret, args);
2258a3a692b8SRichard Henderson }
2259a3a692b8SRichard Henderson 
2260a3a692b8SRichard Henderson void tcg_gen_call5(TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1,
2261a3a692b8SRichard Henderson                    TCGTemp *t2, TCGTemp *t3, TCGTemp *t4, TCGTemp *t5)
2262a3a692b8SRichard Henderson {
2263a3a692b8SRichard Henderson     TCGTemp *args[5] = { t1, t2, t3, t4, t5 };
2264a3a692b8SRichard Henderson     tcg_gen_callN(info, ret, args);
2265a3a692b8SRichard Henderson }
2266a3a692b8SRichard Henderson 
2267a3a692b8SRichard Henderson void tcg_gen_call6(TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1, TCGTemp *t2,
2268a3a692b8SRichard Henderson                    TCGTemp *t3, TCGTemp *t4, TCGTemp *t5, TCGTemp *t6)
2269a3a692b8SRichard Henderson {
2270a3a692b8SRichard Henderson     TCGTemp *args[6] = { t1, t2, t3, t4, t5, t6 };
2271a3a692b8SRichard Henderson     tcg_gen_callN(info, ret, args);
2272a3a692b8SRichard Henderson }
2273a3a692b8SRichard Henderson 
2274a3a692b8SRichard Henderson void tcg_gen_call7(TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1,
2275a3a692b8SRichard Henderson                    TCGTemp *t2, TCGTemp *t3, TCGTemp *t4,
2276a3a692b8SRichard Henderson                    TCGTemp *t5, TCGTemp *t6, TCGTemp *t7)
2277a3a692b8SRichard Henderson {
2278a3a692b8SRichard Henderson     TCGTemp *args[7] = { t1, t2, t3, t4, t5, t6, t7 };
2279a3a692b8SRichard Henderson     tcg_gen_callN(info, ret, args);
2280a3a692b8SRichard Henderson }
2281a3a692b8SRichard Henderson 
22828fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s)
2283c896fe29Sbellard {
2284ac3b8891SRichard Henderson     int i, n;
2285ac3b8891SRichard Henderson 
2286ee17db83SRichard Henderson     for (i = 0, n = s->nb_temps; i < n; i++) {
2287ee17db83SRichard Henderson         TCGTemp *ts = &s->temps[i];
2288ee17db83SRichard Henderson         TCGTempVal val = TEMP_VAL_MEM;
2289ee17db83SRichard Henderson 
2290ee17db83SRichard Henderson         switch (ts->kind) {
2291c0522136SRichard Henderson         case TEMP_CONST:
2292c0522136SRichard Henderson             val = TEMP_VAL_CONST;
2293c0522136SRichard Henderson             break;
2294ee17db83SRichard Henderson         case TEMP_FIXED:
2295ee17db83SRichard Henderson             val = TEMP_VAL_REG;
2296ee17db83SRichard Henderson             break;
2297ee17db83SRichard Henderson         case TEMP_GLOBAL:
2298ee17db83SRichard Henderson             break;
2299c7482438SRichard Henderson         case TEMP_EBB:
2300ee17db83SRichard Henderson             val = TEMP_VAL_DEAD;
2301ee17db83SRichard Henderson             /* fall through */
2302f57c6915SRichard Henderson         case TEMP_TB:
2303e8996ee0Sbellard             ts->mem_allocated = 0;
2304ee17db83SRichard Henderson             break;
2305ee17db83SRichard Henderson         default:
2306ee17db83SRichard Henderson             g_assert_not_reached();
2307ee17db83SRichard Henderson         }
2308ee17db83SRichard Henderson         ts->val_type = val;
2309e8996ee0Sbellard     }
2310f8b2f202SRichard Henderson 
2311f8b2f202SRichard Henderson     memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp));
2312c896fe29Sbellard }
2313c896fe29Sbellard 
2314f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size,
2315f8b2f202SRichard Henderson                                  TCGTemp *ts)
2316c896fe29Sbellard {
23171807f4c4SRichard Henderson     int idx = temp_idx(ts);
2318ac56dd48Spbrook 
2319ee17db83SRichard Henderson     switch (ts->kind) {
2320ee17db83SRichard Henderson     case TEMP_FIXED:
2321ee17db83SRichard Henderson     case TEMP_GLOBAL:
2322ac56dd48Spbrook         pstrcpy(buf, buf_size, ts->name);
2323ee17db83SRichard Henderson         break;
2324f57c6915SRichard Henderson     case TEMP_TB:
2325641d5fbeSbellard         snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
2326ee17db83SRichard Henderson         break;
2327c7482438SRichard Henderson     case TEMP_EBB:
2328ac56dd48Spbrook         snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
2329ee17db83SRichard Henderson         break;
2330c0522136SRichard Henderson     case TEMP_CONST:
2331c0522136SRichard Henderson         switch (ts->type) {
2332c0522136SRichard Henderson         case TCG_TYPE_I32:
2333c0522136SRichard Henderson             snprintf(buf, buf_size, "$0x%x", (int32_t)ts->val);
2334c0522136SRichard Henderson             break;
2335c0522136SRichard Henderson #if TCG_TARGET_REG_BITS > 32
2336c0522136SRichard Henderson         case TCG_TYPE_I64:
2337c0522136SRichard Henderson             snprintf(buf, buf_size, "$0x%" PRIx64, ts->val);
2338c0522136SRichard Henderson             break;
2339c0522136SRichard Henderson #endif
2340c0522136SRichard Henderson         case TCG_TYPE_V64:
2341c0522136SRichard Henderson         case TCG_TYPE_V128:
2342c0522136SRichard Henderson         case TCG_TYPE_V256:
2343c0522136SRichard Henderson             snprintf(buf, buf_size, "v%d$0x%" PRIx64,
2344c0522136SRichard Henderson                      64 << (ts->type - TCG_TYPE_V64), ts->val);
2345c0522136SRichard Henderson             break;
2346c0522136SRichard Henderson         default:
2347c0522136SRichard Henderson             g_assert_not_reached();
2348c0522136SRichard Henderson         }
2349c0522136SRichard Henderson         break;
2350c896fe29Sbellard     }
2351c896fe29Sbellard     return buf;
2352c896fe29Sbellard }
2353c896fe29Sbellard 
235443439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf,
235543439139SRichard Henderson                              int buf_size, TCGArg arg)
2356f8b2f202SRichard Henderson {
235743439139SRichard Henderson     return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg));
2358f8b2f202SRichard Henderson }
2359f8b2f202SRichard Henderson 
2360f48f3edeSblueswir1 static const char * const cond_name[] =
2361f48f3edeSblueswir1 {
23620aed257fSRichard Henderson     [TCG_COND_NEVER] = "never",
23630aed257fSRichard Henderson     [TCG_COND_ALWAYS] = "always",
2364f48f3edeSblueswir1     [TCG_COND_EQ] = "eq",
2365f48f3edeSblueswir1     [TCG_COND_NE] = "ne",
2366f48f3edeSblueswir1     [TCG_COND_LT] = "lt",
2367f48f3edeSblueswir1     [TCG_COND_GE] = "ge",
2368f48f3edeSblueswir1     [TCG_COND_LE] = "le",
2369f48f3edeSblueswir1     [TCG_COND_GT] = "gt",
2370f48f3edeSblueswir1     [TCG_COND_LTU] = "ltu",
2371f48f3edeSblueswir1     [TCG_COND_GEU] = "geu",
2372f48f3edeSblueswir1     [TCG_COND_LEU] = "leu",
2373f48f3edeSblueswir1     [TCG_COND_GTU] = "gtu"
2374f48f3edeSblueswir1 };
2375f48f3edeSblueswir1 
237612fde9bcSRichard Henderson static const char * const ldst_name[(MO_BSWAP | MO_SSIZE) + 1] =
2377f713d6adSRichard Henderson {
2378f713d6adSRichard Henderson     [MO_UB]   = "ub",
2379f713d6adSRichard Henderson     [MO_SB]   = "sb",
2380f713d6adSRichard Henderson     [MO_LEUW] = "leuw",
2381f713d6adSRichard Henderson     [MO_LESW] = "lesw",
2382f713d6adSRichard Henderson     [MO_LEUL] = "leul",
2383f713d6adSRichard Henderson     [MO_LESL] = "lesl",
2384fc313c64SFrédéric Pétrot     [MO_LEUQ] = "leq",
2385f713d6adSRichard Henderson     [MO_BEUW] = "beuw",
2386f713d6adSRichard Henderson     [MO_BESW] = "besw",
2387f713d6adSRichard Henderson     [MO_BEUL] = "beul",
2388f713d6adSRichard Henderson     [MO_BESL] = "besl",
2389fc313c64SFrédéric Pétrot     [MO_BEUQ] = "beq",
239012fde9bcSRichard Henderson     [MO_128 + MO_BE] = "beo",
239112fde9bcSRichard Henderson     [MO_128 + MO_LE] = "leo",
2392f713d6adSRichard Henderson };
2393f713d6adSRichard Henderson 
23941f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = {
23951f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "un+",
23961f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "al+",
23971f00b27fSSergey Sorokin     [MO_ALIGN_2 >> MO_ASHIFT]  = "al2+",
23981f00b27fSSergey Sorokin     [MO_ALIGN_4 >> MO_ASHIFT]  = "al4+",
23991f00b27fSSergey Sorokin     [MO_ALIGN_8 >> MO_ASHIFT]  = "al8+",
24001f00b27fSSergey Sorokin     [MO_ALIGN_16 >> MO_ASHIFT] = "al16+",
24011f00b27fSSergey Sorokin     [MO_ALIGN_32 >> MO_ASHIFT] = "al32+",
24021f00b27fSSergey Sorokin     [MO_ALIGN_64 >> MO_ASHIFT] = "al64+",
24031f00b27fSSergey Sorokin };
24041f00b27fSSergey Sorokin 
240537031fefSRichard Henderson static const char * const atom_name[(MO_ATOM_MASK >> MO_ATOM_SHIFT) + 1] = {
240637031fefSRichard Henderson     [MO_ATOM_IFALIGN >> MO_ATOM_SHIFT] = "",
240737031fefSRichard Henderson     [MO_ATOM_IFALIGN_PAIR >> MO_ATOM_SHIFT] = "pair+",
240837031fefSRichard Henderson     [MO_ATOM_WITHIN16 >> MO_ATOM_SHIFT] = "w16+",
240937031fefSRichard Henderson     [MO_ATOM_WITHIN16_PAIR >> MO_ATOM_SHIFT] = "w16p+",
241037031fefSRichard Henderson     [MO_ATOM_SUBALIGN >> MO_ATOM_SHIFT] = "sub+",
241137031fefSRichard Henderson     [MO_ATOM_NONE >> MO_ATOM_SHIFT] = "noat+",
241237031fefSRichard Henderson };
241337031fefSRichard Henderson 
2414587195bdSRichard Henderson static const char bswap_flag_name[][6] = {
2415587195bdSRichard Henderson     [TCG_BSWAP_IZ] = "iz",
2416587195bdSRichard Henderson     [TCG_BSWAP_OZ] = "oz",
2417587195bdSRichard Henderson     [TCG_BSWAP_OS] = "os",
2418587195bdSRichard Henderson     [TCG_BSWAP_IZ | TCG_BSWAP_OZ] = "iz,oz",
2419587195bdSRichard Henderson     [TCG_BSWAP_IZ | TCG_BSWAP_OS] = "iz,os",
2420587195bdSRichard Henderson };
2421587195bdSRichard Henderson 
2422b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d)
2423b016486eSRichard Henderson {
2424b016486eSRichard Henderson     return (d & (d - 1)) == 0;
2425b016486eSRichard Henderson }
2426b016486eSRichard Henderson 
2427b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d)
2428b016486eSRichard Henderson {
2429b016486eSRichard Henderson     if (TCG_TARGET_NB_REGS <= 32) {
2430b016486eSRichard Henderson         return ctz32(d);
2431b016486eSRichard Henderson     } else {
2432b016486eSRichard Henderson         return ctz64(d);
2433b016486eSRichard Henderson     }
2434b016486eSRichard Henderson }
2435b016486eSRichard Henderson 
2436b7a83ff8SRichard Henderson /* Return only the number of characters output -- no error return. */
2437b7a83ff8SRichard Henderson #define ne_fprintf(...) \
2438b7a83ff8SRichard Henderson     ({ int ret_ = fprintf(__VA_ARGS__); ret_ >= 0 ? ret_ : 0; })
2439b7a83ff8SRichard Henderson 
2440b7a83ff8SRichard Henderson static void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs)
2441c896fe29Sbellard {
2442c896fe29Sbellard     char buf[128];
2443c45cb8bbSRichard Henderson     TCGOp *op;
2444c896fe29Sbellard 
244515fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
2446c45cb8bbSRichard Henderson         int i, k, nb_oargs, nb_iargs, nb_cargs;
2447c45cb8bbSRichard Henderson         const TCGOpDef *def;
2448c45cb8bbSRichard Henderson         TCGOpcode c;
2449bdfb460eSRichard Henderson         int col = 0;
2450c45cb8bbSRichard Henderson 
2451c45cb8bbSRichard Henderson         c = op->opc;
2452c896fe29Sbellard         def = &tcg_op_defs[c];
2453c45cb8bbSRichard Henderson 
2454765b842aSRichard Henderson         if (c == INDEX_op_insn_start) {
2455b016486eSRichard Henderson             nb_oargs = 0;
2456b7a83ff8SRichard Henderson             col += ne_fprintf(f, "\n ----");
24579aef40edSRichard Henderson 
2458747bd69dSRichard Henderson             for (i = 0, k = s->insn_start_words; i < k; ++i) {
2459c9ad8d27SRichard Henderson                 col += ne_fprintf(f, " %016" PRIx64,
2460c9ad8d27SRichard Henderson                                   tcg_get_insn_start_param(op, i));
2461eeacee4dSBlue Swirl             }
24627e4597d7Sbellard         } else if (c == INDEX_op_call) {
24633e92aa34SRichard Henderson             const TCGHelperInfo *info = tcg_call_info(op);
2464fa52e660SRichard Henderson             void *func = tcg_call_func(op);
24653e92aa34SRichard Henderson 
2466c896fe29Sbellard             /* variable number of arguments */
2467cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
2468cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
2469c896fe29Sbellard             nb_cargs = def->nb_cargs;
2470b03cce8eSbellard 
2471b7a83ff8SRichard Henderson             col += ne_fprintf(f, " %s ", def->name);
24723e92aa34SRichard Henderson 
24733e92aa34SRichard Henderson             /*
24743e92aa34SRichard Henderson              * Print the function name from TCGHelperInfo, if available.
24753e92aa34SRichard Henderson              * Note that plugins have a template function for the info,
24763e92aa34SRichard Henderson              * but the actual function pointer comes from the plugin.
24773e92aa34SRichard Henderson              */
24783e92aa34SRichard Henderson             if (func == info->func) {
2479b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s", info->name);
24803e92aa34SRichard Henderson             } else {
2481b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "plugin(%p)", func);
24823e92aa34SRichard Henderson             }
24833e92aa34SRichard Henderson 
2484b7a83ff8SRichard Henderson             col += ne_fprintf(f, ",$0x%x,$%d", info->flags, nb_oargs);
2485b03cce8eSbellard             for (i = 0; i < nb_oargs; i++) {
2486b7a83ff8SRichard Henderson                 col += ne_fprintf(f, ",%s", tcg_get_arg_str(s, buf, sizeof(buf),
2487efee3746SRichard Henderson                                                             op->args[i]));
2488b03cce8eSbellard             }
2489cf066674SRichard Henderson             for (i = 0; i < nb_iargs; i++) {
2490efee3746SRichard Henderson                 TCGArg arg = op->args[nb_oargs + i];
249139004a71SRichard Henderson                 const char *t = tcg_get_arg_str(s, buf, sizeof(buf), arg);
2492b7a83ff8SRichard Henderson                 col += ne_fprintf(f, ",%s", t);
2493e8996ee0Sbellard             }
2494b03cce8eSbellard         } else {
2495b7a83ff8SRichard Henderson             col += ne_fprintf(f, " %s ", def->name);
2496c45cb8bbSRichard Henderson 
2497c896fe29Sbellard             nb_oargs = def->nb_oargs;
2498c896fe29Sbellard             nb_iargs = def->nb_iargs;
2499c896fe29Sbellard             nb_cargs = def->nb_cargs;
2500c896fe29Sbellard 
2501d2fd745fSRichard Henderson             if (def->flags & TCG_OPF_VECTOR) {
2502b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "v%d,e%d,", 64 << TCGOP_VECL(op),
2503d2fd745fSRichard Henderson                                   8 << TCGOP_VECE(op));
2504d2fd745fSRichard Henderson             }
2505d2fd745fSRichard Henderson 
2506c896fe29Sbellard             k = 0;
2507c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
2508b7a83ff8SRichard Henderson                 const char *sep =  k ? "," : "";
2509b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s%s", sep,
2510b7a83ff8SRichard Henderson                                   tcg_get_arg_str(s, buf, sizeof(buf),
2511efee3746SRichard Henderson                                                   op->args[k++]));
2512c896fe29Sbellard             }
2513c896fe29Sbellard             for (i = 0; i < nb_iargs; i++) {
2514b7a83ff8SRichard Henderson                 const char *sep =  k ? "," : "";
2515b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s%s", sep,
2516b7a83ff8SRichard Henderson                                   tcg_get_arg_str(s, buf, sizeof(buf),
2517efee3746SRichard Henderson                                                   op->args[k++]));
2518c896fe29Sbellard             }
2519be210acbSRichard Henderson             switch (c) {
2520be210acbSRichard Henderson             case INDEX_op_brcond_i32:
2521ffc5ea09SRichard Henderson             case INDEX_op_setcond_i32:
25223635502dSRichard Henderson             case INDEX_op_negsetcond_i32:
2523ffc5ea09SRichard Henderson             case INDEX_op_movcond_i32:
2524be210acbSRichard Henderson             case INDEX_op_brcond2_i32:
2525be210acbSRichard Henderson             case INDEX_op_setcond2_i32:
2526ffc5ea09SRichard Henderson             case INDEX_op_brcond_i64:
2527be210acbSRichard Henderson             case INDEX_op_setcond_i64:
25283635502dSRichard Henderson             case INDEX_op_negsetcond_i64:
2529ffc5ea09SRichard Henderson             case INDEX_op_movcond_i64:
2530212be173SRichard Henderson             case INDEX_op_cmp_vec:
2531f75da298SRichard Henderson             case INDEX_op_cmpsel_vec:
2532efee3746SRichard Henderson                 if (op->args[k] < ARRAY_SIZE(cond_name)
2533efee3746SRichard Henderson                     && cond_name[op->args[k]]) {
2534b7a83ff8SRichard Henderson                     col += ne_fprintf(f, ",%s", cond_name[op->args[k++]]);
2535eeacee4dSBlue Swirl                 } else {
2536b7a83ff8SRichard Henderson                     col += ne_fprintf(f, ",$0x%" TCG_PRIlx, op->args[k++]);
2537eeacee4dSBlue Swirl                 }
2538f48f3edeSblueswir1                 i = 1;
2539be210acbSRichard Henderson                 break;
2540fecccfccSRichard Henderson             case INDEX_op_qemu_ld_a32_i32:
2541fecccfccSRichard Henderson             case INDEX_op_qemu_ld_a64_i32:
2542fecccfccSRichard Henderson             case INDEX_op_qemu_st_a32_i32:
2543fecccfccSRichard Henderson             case INDEX_op_qemu_st_a64_i32:
2544fecccfccSRichard Henderson             case INDEX_op_qemu_st8_a32_i32:
2545fecccfccSRichard Henderson             case INDEX_op_qemu_st8_a64_i32:
2546fecccfccSRichard Henderson             case INDEX_op_qemu_ld_a32_i64:
2547fecccfccSRichard Henderson             case INDEX_op_qemu_ld_a64_i64:
2548fecccfccSRichard Henderson             case INDEX_op_qemu_st_a32_i64:
2549fecccfccSRichard Henderson             case INDEX_op_qemu_st_a64_i64:
2550fecccfccSRichard Henderson             case INDEX_op_qemu_ld_a32_i128:
2551fecccfccSRichard Henderson             case INDEX_op_qemu_ld_a64_i128:
2552fecccfccSRichard Henderson             case INDEX_op_qemu_st_a32_i128:
2553fecccfccSRichard Henderson             case INDEX_op_qemu_st_a64_i128:
255459227d5dSRichard Henderson                 {
255537031fefSRichard Henderson                     const char *s_al, *s_op, *s_at;
25569002ffcbSRichard Henderson                     MemOpIdx oi = op->args[k++];
25579a239c6eSPhilippe Mathieu-Daudé                     MemOp mop = get_memop(oi);
255859227d5dSRichard Henderson                     unsigned ix = get_mmuidx(oi);
255959227d5dSRichard Henderson 
25609a239c6eSPhilippe Mathieu-Daudé                     s_al = alignment_name[(mop & MO_AMASK) >> MO_ASHIFT];
25619a239c6eSPhilippe Mathieu-Daudé                     s_op = ldst_name[mop & (MO_BSWAP | MO_SSIZE)];
25629a239c6eSPhilippe Mathieu-Daudé                     s_at = atom_name[(mop & MO_ATOM_MASK) >> MO_ATOM_SHIFT];
25639a239c6eSPhilippe Mathieu-Daudé                     mop &= ~(MO_AMASK | MO_BSWAP | MO_SSIZE | MO_ATOM_MASK);
256437031fefSRichard Henderson 
256537031fefSRichard Henderson                     /* If all fields are accounted for, print symbolically. */
25669a239c6eSPhilippe Mathieu-Daudé                     if (!mop && s_al && s_op && s_at) {
256737031fefSRichard Henderson                         col += ne_fprintf(f, ",%s%s%s,%u",
256837031fefSRichard Henderson                                           s_at, s_al, s_op, ix);
256937031fefSRichard Henderson                     } else {
25709a239c6eSPhilippe Mathieu-Daudé                         mop = get_memop(oi);
25719a239c6eSPhilippe Mathieu-Daudé                         col += ne_fprintf(f, ",$0x%x,%u", mop, ix);
2572f713d6adSRichard Henderson                     }
2573f713d6adSRichard Henderson                     i = 1;
257459227d5dSRichard Henderson                 }
2575f713d6adSRichard Henderson                 break;
2576587195bdSRichard Henderson             case INDEX_op_bswap16_i32:
2577587195bdSRichard Henderson             case INDEX_op_bswap16_i64:
2578587195bdSRichard Henderson             case INDEX_op_bswap32_i32:
2579587195bdSRichard Henderson             case INDEX_op_bswap32_i64:
2580587195bdSRichard Henderson             case INDEX_op_bswap64_i64:
2581587195bdSRichard Henderson                 {
2582587195bdSRichard Henderson                     TCGArg flags = op->args[k];
2583587195bdSRichard Henderson                     const char *name = NULL;
2584587195bdSRichard Henderson 
2585587195bdSRichard Henderson                     if (flags < ARRAY_SIZE(bswap_flag_name)) {
2586587195bdSRichard Henderson                         name = bswap_flag_name[flags];
2587587195bdSRichard Henderson                     }
2588587195bdSRichard Henderson                     if (name) {
2589b7a83ff8SRichard Henderson                         col += ne_fprintf(f, ",%s", name);
2590587195bdSRichard Henderson                     } else {
2591b7a83ff8SRichard Henderson                         col += ne_fprintf(f, ",$0x%" TCG_PRIlx, flags);
2592587195bdSRichard Henderson                     }
2593587195bdSRichard Henderson                     i = k = 1;
2594587195bdSRichard Henderson                 }
2595587195bdSRichard Henderson                 break;
2596be210acbSRichard Henderson             default:
2597f48f3edeSblueswir1                 i = 0;
2598be210acbSRichard Henderson                 break;
2599be210acbSRichard Henderson             }
260051e3972cSRichard Henderson             switch (c) {
260151e3972cSRichard Henderson             case INDEX_op_set_label:
260251e3972cSRichard Henderson             case INDEX_op_br:
260351e3972cSRichard Henderson             case INDEX_op_brcond_i32:
260451e3972cSRichard Henderson             case INDEX_op_brcond_i64:
260551e3972cSRichard Henderson             case INDEX_op_brcond2_i32:
2606b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s$L%d", k ? "," : "",
2607efee3746SRichard Henderson                                   arg_label(op->args[k])->id);
260851e3972cSRichard Henderson                 i++, k++;
260951e3972cSRichard Henderson                 break;
26103470867bSRichard Henderson             case INDEX_op_mb:
26113470867bSRichard Henderson                 {
26123470867bSRichard Henderson                     TCGBar membar = op->args[k];
26133470867bSRichard Henderson                     const char *b_op, *m_op;
26143470867bSRichard Henderson 
26153470867bSRichard Henderson                     switch (membar & TCG_BAR_SC) {
26163470867bSRichard Henderson                     case 0:
26173470867bSRichard Henderson                         b_op = "none";
26183470867bSRichard Henderson                         break;
26193470867bSRichard Henderson                     case TCG_BAR_LDAQ:
26203470867bSRichard Henderson                         b_op = "acq";
26213470867bSRichard Henderson                         break;
26223470867bSRichard Henderson                     case TCG_BAR_STRL:
26233470867bSRichard Henderson                         b_op = "rel";
26243470867bSRichard Henderson                         break;
26253470867bSRichard Henderson                     case TCG_BAR_SC:
26263470867bSRichard Henderson                         b_op = "seq";
26273470867bSRichard Henderson                         break;
26283470867bSRichard Henderson                     default:
26293470867bSRichard Henderson                         g_assert_not_reached();
26303470867bSRichard Henderson                     }
26313470867bSRichard Henderson 
26323470867bSRichard Henderson                     switch (membar & TCG_MO_ALL) {
26333470867bSRichard Henderson                     case 0:
26343470867bSRichard Henderson                         m_op = "none";
26353470867bSRichard Henderson                         break;
26363470867bSRichard Henderson                     case TCG_MO_LD_LD:
26373470867bSRichard Henderson                         m_op = "rr";
26383470867bSRichard Henderson                         break;
26393470867bSRichard Henderson                     case TCG_MO_LD_ST:
26403470867bSRichard Henderson                         m_op = "rw";
26413470867bSRichard Henderson                         break;
26423470867bSRichard Henderson                     case TCG_MO_ST_LD:
26433470867bSRichard Henderson                         m_op = "wr";
26443470867bSRichard Henderson                         break;
26453470867bSRichard Henderson                     case TCG_MO_ST_ST:
26463470867bSRichard Henderson                         m_op = "ww";
26473470867bSRichard Henderson                         break;
26483470867bSRichard Henderson                     case TCG_MO_LD_LD | TCG_MO_LD_ST:
26493470867bSRichard Henderson                         m_op = "rr+rw";
26503470867bSRichard Henderson                         break;
26513470867bSRichard Henderson                     case TCG_MO_LD_LD | TCG_MO_ST_LD:
26523470867bSRichard Henderson                         m_op = "rr+wr";
26533470867bSRichard Henderson                         break;
26543470867bSRichard Henderson                     case TCG_MO_LD_LD | TCG_MO_ST_ST:
26553470867bSRichard Henderson                         m_op = "rr+ww";
26563470867bSRichard Henderson                         break;
26573470867bSRichard Henderson                     case TCG_MO_LD_ST | TCG_MO_ST_LD:
26583470867bSRichard Henderson                         m_op = "rw+wr";
26593470867bSRichard Henderson                         break;
26603470867bSRichard Henderson                     case TCG_MO_LD_ST | TCG_MO_ST_ST:
26613470867bSRichard Henderson                         m_op = "rw+ww";
26623470867bSRichard Henderson                         break;
26633470867bSRichard Henderson                     case TCG_MO_ST_LD | TCG_MO_ST_ST:
26643470867bSRichard Henderson                         m_op = "wr+ww";
26653470867bSRichard Henderson                         break;
26663470867bSRichard Henderson                     case TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_MO_ST_LD:
26673470867bSRichard Henderson                         m_op = "rr+rw+wr";
26683470867bSRichard Henderson                         break;
26693470867bSRichard Henderson                     case TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_MO_ST_ST:
26703470867bSRichard Henderson                         m_op = "rr+rw+ww";
26713470867bSRichard Henderson                         break;
26723470867bSRichard Henderson                     case TCG_MO_LD_LD | TCG_MO_ST_LD | TCG_MO_ST_ST:
26733470867bSRichard Henderson                         m_op = "rr+wr+ww";
26743470867bSRichard Henderson                         break;
26753470867bSRichard Henderson                     case TCG_MO_LD_ST | TCG_MO_ST_LD | TCG_MO_ST_ST:
26763470867bSRichard Henderson                         m_op = "rw+wr+ww";
26773470867bSRichard Henderson                         break;
26783470867bSRichard Henderson                     case TCG_MO_ALL:
26793470867bSRichard Henderson                         m_op = "all";
26803470867bSRichard Henderson                         break;
26813470867bSRichard Henderson                     default:
26823470867bSRichard Henderson                         g_assert_not_reached();
26833470867bSRichard Henderson                     }
26843470867bSRichard Henderson 
26853470867bSRichard Henderson                     col += ne_fprintf(f, "%s%s:%s", (k ? "," : ""), b_op, m_op);
26863470867bSRichard Henderson                     i++, k++;
26873470867bSRichard Henderson                 }
26883470867bSRichard Henderson                 break;
268951e3972cSRichard Henderson             default:
269051e3972cSRichard Henderson                 break;
2691eeacee4dSBlue Swirl             }
269251e3972cSRichard Henderson             for (; i < nb_cargs; i++, k++) {
2693b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s$0x%" TCG_PRIlx, k ? "," : "",
2694b7a83ff8SRichard Henderson                                   op->args[k]);
2695bdfb460eSRichard Henderson             }
2696bdfb460eSRichard Henderson         }
2697bdfb460eSRichard Henderson 
26981894f69aSRichard Henderson         if (have_prefs || op->life) {
26991894f69aSRichard Henderson             for (; col < 40; ++col) {
2700b7a83ff8SRichard Henderson                 putc(' ', f);
2701bdfb460eSRichard Henderson             }
27021894f69aSRichard Henderson         }
27031894f69aSRichard Henderson 
27041894f69aSRichard Henderson         if (op->life) {
27051894f69aSRichard Henderson             unsigned life = op->life;
2706bdfb460eSRichard Henderson 
2707bdfb460eSRichard Henderson             if (life & (SYNC_ARG * 3)) {
2708b7a83ff8SRichard Henderson                 ne_fprintf(f, "  sync:");
2709bdfb460eSRichard Henderson                 for (i = 0; i < 2; ++i) {
2710bdfb460eSRichard Henderson                     if (life & (SYNC_ARG << i)) {
2711b7a83ff8SRichard Henderson                         ne_fprintf(f, " %d", i);
2712bdfb460eSRichard Henderson                     }
2713bdfb460eSRichard Henderson                 }
2714bdfb460eSRichard Henderson             }
2715bdfb460eSRichard Henderson             life /= DEAD_ARG;
2716bdfb460eSRichard Henderson             if (life) {
2717b7a83ff8SRichard Henderson                 ne_fprintf(f, "  dead:");
2718bdfb460eSRichard Henderson                 for (i = 0; life; ++i, life >>= 1) {
2719bdfb460eSRichard Henderson                     if (life & 1) {
2720b7a83ff8SRichard Henderson                         ne_fprintf(f, " %d", i);
2721bdfb460eSRichard Henderson                     }
2722bdfb460eSRichard Henderson                 }
2723c896fe29Sbellard             }
2724b03cce8eSbellard         }
27251894f69aSRichard Henderson 
27261894f69aSRichard Henderson         if (have_prefs) {
27271894f69aSRichard Henderson             for (i = 0; i < nb_oargs; ++i) {
272831fd884bSRichard Henderson                 TCGRegSet set = output_pref(op, i);
27291894f69aSRichard Henderson 
27301894f69aSRichard Henderson                 if (i == 0) {
2731b7a83ff8SRichard Henderson                     ne_fprintf(f, "  pref=");
27321894f69aSRichard Henderson                 } else {
2733b7a83ff8SRichard Henderson                     ne_fprintf(f, ",");
27341894f69aSRichard Henderson                 }
27351894f69aSRichard Henderson                 if (set == 0) {
2736b7a83ff8SRichard Henderson                     ne_fprintf(f, "none");
27371894f69aSRichard Henderson                 } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) {
2738b7a83ff8SRichard Henderson                     ne_fprintf(f, "all");
27391894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG
27401894f69aSRichard Henderson                 } else if (tcg_regset_single(set)) {
27411894f69aSRichard Henderson                     TCGReg reg = tcg_regset_first(set);
2742b7a83ff8SRichard Henderson                     ne_fprintf(f, "%s", tcg_target_reg_names[reg]);
27431894f69aSRichard Henderson #endif
27441894f69aSRichard Henderson                 } else if (TCG_TARGET_NB_REGS <= 32) {
2745b7a83ff8SRichard Henderson                     ne_fprintf(f, "0x%x", (uint32_t)set);
27461894f69aSRichard Henderson                 } else {
2747b7a83ff8SRichard Henderson                     ne_fprintf(f, "0x%" PRIx64, (uint64_t)set);
27481894f69aSRichard Henderson                 }
27491894f69aSRichard Henderson             }
27501894f69aSRichard Henderson         }
27511894f69aSRichard Henderson 
2752b7a83ff8SRichard Henderson         putc('\n', f);
2753c896fe29Sbellard     }
2754c896fe29Sbellard }
2755c896fe29Sbellard 
2756c896fe29Sbellard /* we give more priority to constraints with less registers */
2757c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k)
2758c896fe29Sbellard {
275974a11790SRichard Henderson     const TCGArgConstraint *arg_ct = &def->args_ct[k];
276029f5e925SRichard Henderson     int n = ctpop64(arg_ct->regs);
2761c896fe29Sbellard 
276229f5e925SRichard Henderson     /*
276329f5e925SRichard Henderson      * Sort constraints of a single register first, which includes output
276429f5e925SRichard Henderson      * aliases (which must exactly match the input already allocated).
276529f5e925SRichard Henderson      */
276629f5e925SRichard Henderson     if (n == 1 || arg_ct->oalias) {
276729f5e925SRichard Henderson         return INT_MAX;
2768c896fe29Sbellard     }
276929f5e925SRichard Henderson 
277029f5e925SRichard Henderson     /*
277129f5e925SRichard Henderson      * Sort register pairs next, first then second immediately after.
277229f5e925SRichard Henderson      * Arbitrarily sort multiple pairs by the index of the first reg;
277329f5e925SRichard Henderson      * there shouldn't be many pairs.
277429f5e925SRichard Henderson      */
277529f5e925SRichard Henderson     switch (arg_ct->pair) {
277629f5e925SRichard Henderson     case 1:
277729f5e925SRichard Henderson     case 3:
277829f5e925SRichard Henderson         return (k + 1) * 2;
277929f5e925SRichard Henderson     case 2:
278029f5e925SRichard Henderson         return (arg_ct->pair_index + 1) * 2 - 1;
278129f5e925SRichard Henderson     }
278229f5e925SRichard Henderson 
278329f5e925SRichard Henderson     /* Finally, sort by decreasing register count. */
278429f5e925SRichard Henderson     assert(n > 1);
278529f5e925SRichard Henderson     return -n;
2786c896fe29Sbellard }
2787c896fe29Sbellard 
2788c896fe29Sbellard /* sort from highest priority to lowest */
2789c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n)
2790c896fe29Sbellard {
279166792f90SRichard Henderson     int i, j;
279266792f90SRichard Henderson     TCGArgConstraint *a = def->args_ct;
2793c896fe29Sbellard 
279466792f90SRichard Henderson     for (i = 0; i < n; i++) {
279566792f90SRichard Henderson         a[start + i].sort_index = start + i;
279666792f90SRichard Henderson     }
279766792f90SRichard Henderson     if (n <= 1) {
2798c896fe29Sbellard         return;
279966792f90SRichard Henderson     }
2800c896fe29Sbellard     for (i = 0; i < n - 1; i++) {
2801c896fe29Sbellard         for (j = i + 1; j < n; j++) {
280266792f90SRichard Henderson             int p1 = get_constraint_priority(def, a[start + i].sort_index);
280366792f90SRichard Henderson             int p2 = get_constraint_priority(def, a[start + j].sort_index);
2804c896fe29Sbellard             if (p1 < p2) {
280566792f90SRichard Henderson                 int tmp = a[start + i].sort_index;
280666792f90SRichard Henderson                 a[start + i].sort_index = a[start + j].sort_index;
280766792f90SRichard Henderson                 a[start + j].sort_index = tmp;
2808c896fe29Sbellard             }
2809c896fe29Sbellard         }
2810c896fe29Sbellard     }
2811c896fe29Sbellard }
2812c896fe29Sbellard 
2813f69d277eSRichard Henderson static void process_op_defs(TCGContext *s)
2814c896fe29Sbellard {
2815a9751609SRichard Henderson     TCGOpcode op;
2816c896fe29Sbellard 
2817f69d277eSRichard Henderson     for (op = 0; op < NB_OPS; op++) {
2818f69d277eSRichard Henderson         TCGOpDef *def = &tcg_op_defs[op];
2819f69d277eSRichard Henderson         const TCGTargetOpDef *tdefs;
282029f5e925SRichard Henderson         bool saw_alias_pair = false;
282129f5e925SRichard Henderson         int i, o, i2, o2, nb_args;
2822f69d277eSRichard Henderson 
2823f69d277eSRichard Henderson         if (def->flags & TCG_OPF_NOT_PRESENT) {
2824f69d277eSRichard Henderson             continue;
2825f69d277eSRichard Henderson         }
2826f69d277eSRichard Henderson 
2827c896fe29Sbellard         nb_args = def->nb_iargs + def->nb_oargs;
2828f69d277eSRichard Henderson         if (nb_args == 0) {
2829f69d277eSRichard Henderson             continue;
2830f69d277eSRichard Henderson         }
2831f69d277eSRichard Henderson 
28324c22e840SRichard Henderson         /*
28334c22e840SRichard Henderson          * Macro magic should make it impossible, but double-check that
28344c22e840SRichard Henderson          * the array index is in range.  Since the signness of an enum
28354c22e840SRichard Henderson          * is implementation defined, force the result to unsigned.
28364c22e840SRichard Henderson          */
28374c22e840SRichard Henderson         unsigned con_set = tcg_target_op_def(op);
28384c22e840SRichard Henderson         tcg_debug_assert(con_set < ARRAY_SIZE(constraint_sets));
28394c22e840SRichard Henderson         tdefs = &constraint_sets[con_set];
2840f69d277eSRichard Henderson 
2841c896fe29Sbellard         for (i = 0; i < nb_args; i++) {
2842f69d277eSRichard Henderson             const char *ct_str = tdefs->args_ct_str[i];
28438940ea0dSPhilippe Mathieu-Daudé             bool input_p = i >= def->nb_oargs;
28448940ea0dSPhilippe Mathieu-Daudé 
2845f69d277eSRichard Henderson             /* Incomplete TCGTargetOpDef entry. */
2846eabb7b91SAurelien Jarno             tcg_debug_assert(ct_str != NULL);
2847f69d277eSRichard Henderson 
284817280ff4SRichard Henderson             switch (*ct_str) {
284917280ff4SRichard Henderson             case '0' ... '9':
28508940ea0dSPhilippe Mathieu-Daudé                 o = *ct_str - '0';
28518940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(input_p);
28528940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(o < def->nb_oargs);
28538940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(def->args_ct[o].regs != 0);
28548940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(!def->args_ct[o].oalias);
28558940ea0dSPhilippe Mathieu-Daudé                 def->args_ct[i] = def->args_ct[o];
2856bc2b17e6SRichard Henderson                 /* The output sets oalias.  */
28578940ea0dSPhilippe Mathieu-Daudé                 def->args_ct[o].oalias = 1;
28588940ea0dSPhilippe Mathieu-Daudé                 def->args_ct[o].alias_index = i;
2859bc2b17e6SRichard Henderson                 /* The input sets ialias. */
28608940ea0dSPhilippe Mathieu-Daudé                 def->args_ct[i].ialias = 1;
28618940ea0dSPhilippe Mathieu-Daudé                 def->args_ct[i].alias_index = o;
286229f5e925SRichard Henderson                 if (def->args_ct[i].pair) {
286329f5e925SRichard Henderson                     saw_alias_pair = true;
286429f5e925SRichard Henderson                 }
28658940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(ct_str[1] == '\0');
28668940ea0dSPhilippe Mathieu-Daudé                 continue;
28678940ea0dSPhilippe Mathieu-Daudé 
286882790a87SRichard Henderson             case '&':
28698940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(!input_p);
2870bc2b17e6SRichard Henderson                 def->args_ct[i].newreg = true;
287182790a87SRichard Henderson                 ct_str++;
287282790a87SRichard Henderson                 break;
287329f5e925SRichard Henderson 
287429f5e925SRichard Henderson             case 'p': /* plus */
287529f5e925SRichard Henderson                 /* Allocate to the register after the previous. */
287629f5e925SRichard Henderson                 tcg_debug_assert(i > (input_p ? def->nb_oargs : 0));
287729f5e925SRichard Henderson                 o = i - 1;
287829f5e925SRichard Henderson                 tcg_debug_assert(!def->args_ct[o].pair);
287929f5e925SRichard Henderson                 tcg_debug_assert(!def->args_ct[o].ct);
288029f5e925SRichard Henderson                 def->args_ct[i] = (TCGArgConstraint){
288129f5e925SRichard Henderson                     .pair = 2,
288229f5e925SRichard Henderson                     .pair_index = o,
288329f5e925SRichard Henderson                     .regs = def->args_ct[o].regs << 1,
288429f5e925SRichard Henderson                 };
288529f5e925SRichard Henderson                 def->args_ct[o].pair = 1;
288629f5e925SRichard Henderson                 def->args_ct[o].pair_index = i;
288729f5e925SRichard Henderson                 tcg_debug_assert(ct_str[1] == '\0');
288829f5e925SRichard Henderson                 continue;
288929f5e925SRichard Henderson 
289029f5e925SRichard Henderson             case 'm': /* minus */
289129f5e925SRichard Henderson                 /* Allocate to the register before the previous. */
289229f5e925SRichard Henderson                 tcg_debug_assert(i > (input_p ? def->nb_oargs : 0));
289329f5e925SRichard Henderson                 o = i - 1;
289429f5e925SRichard Henderson                 tcg_debug_assert(!def->args_ct[o].pair);
289529f5e925SRichard Henderson                 tcg_debug_assert(!def->args_ct[o].ct);
289629f5e925SRichard Henderson                 def->args_ct[i] = (TCGArgConstraint){
289729f5e925SRichard Henderson                     .pair = 1,
289829f5e925SRichard Henderson                     .pair_index = o,
289929f5e925SRichard Henderson                     .regs = def->args_ct[o].regs >> 1,
290029f5e925SRichard Henderson                 };
290129f5e925SRichard Henderson                 def->args_ct[o].pair = 2;
290229f5e925SRichard Henderson                 def->args_ct[o].pair_index = i;
290329f5e925SRichard Henderson                 tcg_debug_assert(ct_str[1] == '\0');
290429f5e925SRichard Henderson                 continue;
29058940ea0dSPhilippe Mathieu-Daudé             }
29068940ea0dSPhilippe Mathieu-Daudé 
29078940ea0dSPhilippe Mathieu-Daudé             do {
29088940ea0dSPhilippe Mathieu-Daudé                 switch (*ct_str) {
2909c896fe29Sbellard                 case 'i':
2910c896fe29Sbellard                     def->args_ct[i].ct |= TCG_CT_CONST;
2911c896fe29Sbellard                     break;
2912358b4923SRichard Henderson 
2913358b4923SRichard Henderson                 /* Include all of the target-specific constraints. */
2914358b4923SRichard Henderson 
2915358b4923SRichard Henderson #undef CONST
2916358b4923SRichard Henderson #define CONST(CASE, MASK) \
29178940ea0dSPhilippe Mathieu-Daudé     case CASE: def->args_ct[i].ct |= MASK; break;
2918358b4923SRichard Henderson #define REGS(CASE, MASK) \
29198940ea0dSPhilippe Mathieu-Daudé     case CASE: def->args_ct[i].regs |= MASK; break;
2920358b4923SRichard Henderson 
2921358b4923SRichard Henderson #include "tcg-target-con-str.h"
2922358b4923SRichard Henderson 
2923358b4923SRichard Henderson #undef REGS
2924358b4923SRichard Henderson #undef CONST
2925c896fe29Sbellard                 default:
29268940ea0dSPhilippe Mathieu-Daudé                 case '0' ... '9':
29278940ea0dSPhilippe Mathieu-Daudé                 case '&':
292829f5e925SRichard Henderson                 case 'p':
292929f5e925SRichard Henderson                 case 'm':
2930358b4923SRichard Henderson                     /* Typo in TCGTargetOpDef constraint. */
2931358b4923SRichard Henderson                     g_assert_not_reached();
2932358b4923SRichard Henderson                 }
29338940ea0dSPhilippe Mathieu-Daudé             } while (*++ct_str != '\0');
2934c896fe29Sbellard         }
2935c896fe29Sbellard 
2936c68aaa18SStefan Weil         /* TCGTargetOpDef entry with too much information? */
2937eabb7b91SAurelien Jarno         tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
2938c68aaa18SStefan Weil 
293929f5e925SRichard Henderson         /*
294029f5e925SRichard Henderson          * Fix up output pairs that are aliased with inputs.
294129f5e925SRichard Henderson          * When we created the alias, we copied pair from the output.
294229f5e925SRichard Henderson          * There are three cases:
294329f5e925SRichard Henderson          *    (1a) Pairs of inputs alias pairs of outputs.
294429f5e925SRichard Henderson          *    (1b) One input aliases the first of a pair of outputs.
294529f5e925SRichard Henderson          *    (2)  One input aliases the second of a pair of outputs.
294629f5e925SRichard Henderson          *
294729f5e925SRichard Henderson          * Case 1a is handled by making sure that the pair_index'es are
294829f5e925SRichard Henderson          * properly updated so that they appear the same as a pair of inputs.
294929f5e925SRichard Henderson          *
295029f5e925SRichard Henderson          * Case 1b is handled by setting the pair_index of the input to
295129f5e925SRichard Henderson          * itself, simply so it doesn't point to an unrelated argument.
295229f5e925SRichard Henderson          * Since we don't encounter the "second" during the input allocation
295329f5e925SRichard Henderson          * phase, nothing happens with the second half of the input pair.
295429f5e925SRichard Henderson          *
295529f5e925SRichard Henderson          * Case 2 is handled by setting the second input to pair=3, the
295629f5e925SRichard Henderson          * first output to pair=3, and the pair_index'es to match.
295729f5e925SRichard Henderson          */
295829f5e925SRichard Henderson         if (saw_alias_pair) {
295929f5e925SRichard Henderson             for (i = def->nb_oargs; i < nb_args; i++) {
296029f5e925SRichard Henderson                 /*
296129f5e925SRichard Henderson                  * Since [0-9pm] must be alone in the constraint string,
296229f5e925SRichard Henderson                  * the only way they can both be set is if the pair comes
296329f5e925SRichard Henderson                  * from the output alias.
296429f5e925SRichard Henderson                  */
296529f5e925SRichard Henderson                 if (!def->args_ct[i].ialias) {
296629f5e925SRichard Henderson                     continue;
296729f5e925SRichard Henderson                 }
296829f5e925SRichard Henderson                 switch (def->args_ct[i].pair) {
296929f5e925SRichard Henderson                 case 0:
297029f5e925SRichard Henderson                     break;
297129f5e925SRichard Henderson                 case 1:
297229f5e925SRichard Henderson                     o = def->args_ct[i].alias_index;
297329f5e925SRichard Henderson                     o2 = def->args_ct[o].pair_index;
297429f5e925SRichard Henderson                     tcg_debug_assert(def->args_ct[o].pair == 1);
297529f5e925SRichard Henderson                     tcg_debug_assert(def->args_ct[o2].pair == 2);
297629f5e925SRichard Henderson                     if (def->args_ct[o2].oalias) {
297729f5e925SRichard Henderson                         /* Case 1a */
297829f5e925SRichard Henderson                         i2 = def->args_ct[o2].alias_index;
297929f5e925SRichard Henderson                         tcg_debug_assert(def->args_ct[i2].pair == 2);
298029f5e925SRichard Henderson                         def->args_ct[i2].pair_index = i;
298129f5e925SRichard Henderson                         def->args_ct[i].pair_index = i2;
298229f5e925SRichard Henderson                     } else {
298329f5e925SRichard Henderson                         /* Case 1b */
298429f5e925SRichard Henderson                         def->args_ct[i].pair_index = i;
298529f5e925SRichard Henderson                     }
298629f5e925SRichard Henderson                     break;
298729f5e925SRichard Henderson                 case 2:
298829f5e925SRichard Henderson                     o = def->args_ct[i].alias_index;
298929f5e925SRichard Henderson                     o2 = def->args_ct[o].pair_index;
299029f5e925SRichard Henderson                     tcg_debug_assert(def->args_ct[o].pair == 2);
299129f5e925SRichard Henderson                     tcg_debug_assert(def->args_ct[o2].pair == 1);
299229f5e925SRichard Henderson                     if (def->args_ct[o2].oalias) {
299329f5e925SRichard Henderson                         /* Case 1a */
299429f5e925SRichard Henderson                         i2 = def->args_ct[o2].alias_index;
299529f5e925SRichard Henderson                         tcg_debug_assert(def->args_ct[i2].pair == 1);
299629f5e925SRichard Henderson                         def->args_ct[i2].pair_index = i;
299729f5e925SRichard Henderson                         def->args_ct[i].pair_index = i2;
299829f5e925SRichard Henderson                     } else {
299929f5e925SRichard Henderson                         /* Case 2 */
300029f5e925SRichard Henderson                         def->args_ct[i].pair = 3;
300129f5e925SRichard Henderson                         def->args_ct[o2].pair = 3;
300229f5e925SRichard Henderson                         def->args_ct[i].pair_index = o2;
300329f5e925SRichard Henderson                         def->args_ct[o2].pair_index = i;
300429f5e925SRichard Henderson                     }
300529f5e925SRichard Henderson                     break;
300629f5e925SRichard Henderson                 default:
300729f5e925SRichard Henderson                     g_assert_not_reached();
300829f5e925SRichard Henderson                 }
300929f5e925SRichard Henderson             }
301029f5e925SRichard Henderson         }
301129f5e925SRichard Henderson 
3012c896fe29Sbellard         /* sort the constraints (XXX: this is just an heuristic) */
3013c896fe29Sbellard         sort_constraints(def, 0, def->nb_oargs);
3014c896fe29Sbellard         sort_constraints(def, def->nb_oargs, def->nb_iargs);
3015c896fe29Sbellard     }
3016c896fe29Sbellard }
3017c896fe29Sbellard 
3018f85b1fc4SRichard Henderson static void remove_label_use(TCGOp *op, int idx)
3019f85b1fc4SRichard Henderson {
3020f85b1fc4SRichard Henderson     TCGLabel *label = arg_label(op->args[idx]);
3021f85b1fc4SRichard Henderson     TCGLabelUse *use;
3022f85b1fc4SRichard Henderson 
3023f85b1fc4SRichard Henderson     QSIMPLEQ_FOREACH(use, &label->branches, next) {
3024f85b1fc4SRichard Henderson         if (use->op == op) {
3025f85b1fc4SRichard Henderson             QSIMPLEQ_REMOVE(&label->branches, use, TCGLabelUse, next);
3026f85b1fc4SRichard Henderson             return;
3027f85b1fc4SRichard Henderson         }
3028f85b1fc4SRichard Henderson     }
3029f85b1fc4SRichard Henderson     g_assert_not_reached();
3030f85b1fc4SRichard Henderson }
3031f85b1fc4SRichard Henderson 
30320c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op)
30330c627cdcSRichard Henderson {
3034d88a117eSRichard Henderson     switch (op->opc) {
3035d88a117eSRichard Henderson     case INDEX_op_br:
3036f85b1fc4SRichard Henderson         remove_label_use(op, 0);
3037d88a117eSRichard Henderson         break;
3038d88a117eSRichard Henderson     case INDEX_op_brcond_i32:
3039d88a117eSRichard Henderson     case INDEX_op_brcond_i64:
3040f85b1fc4SRichard Henderson         remove_label_use(op, 3);
3041d88a117eSRichard Henderson         break;
3042d88a117eSRichard Henderson     case INDEX_op_brcond2_i32:
3043f85b1fc4SRichard Henderson         remove_label_use(op, 5);
3044d88a117eSRichard Henderson         break;
3045d88a117eSRichard Henderson     default:
3046d88a117eSRichard Henderson         break;
3047d88a117eSRichard Henderson     }
3048d88a117eSRichard Henderson 
304915fa08f8SRichard Henderson     QTAILQ_REMOVE(&s->ops, op, link);
305015fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&s->free_ops, op, link);
3051abebf925SRichard Henderson     s->nb_ops--;
30520c627cdcSRichard Henderson }
30530c627cdcSRichard Henderson 
3054a80cdd31SRichard Henderson void tcg_remove_ops_after(TCGOp *op)
3055a80cdd31SRichard Henderson {
3056a80cdd31SRichard Henderson     TCGContext *s = tcg_ctx;
3057a80cdd31SRichard Henderson 
3058a80cdd31SRichard Henderson     while (true) {
3059a80cdd31SRichard Henderson         TCGOp *last = tcg_last_op();
3060a80cdd31SRichard Henderson         if (last == op) {
3061a80cdd31SRichard Henderson             return;
3062a80cdd31SRichard Henderson         }
3063a80cdd31SRichard Henderson         tcg_op_remove(s, last);
3064a80cdd31SRichard Henderson     }
3065a80cdd31SRichard Henderson }
3066a80cdd31SRichard Henderson 
3067d4478943SPhilippe Mathieu-Daudé static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs)
306815fa08f8SRichard Henderson {
306915fa08f8SRichard Henderson     TCGContext *s = tcg_ctx;
3070cb10bc63SRichard Henderson     TCGOp *op = NULL;
307115fa08f8SRichard Henderson 
3072cb10bc63SRichard Henderson     if (unlikely(!QTAILQ_EMPTY(&s->free_ops))) {
3073cb10bc63SRichard Henderson         QTAILQ_FOREACH(op, &s->free_ops, link) {
3074cb10bc63SRichard Henderson             if (nargs <= op->nargs) {
307515fa08f8SRichard Henderson                 QTAILQ_REMOVE(&s->free_ops, op, link);
3076cb10bc63SRichard Henderson                 nargs = op->nargs;
3077cb10bc63SRichard Henderson                 goto found;
307815fa08f8SRichard Henderson             }
3079cb10bc63SRichard Henderson         }
3080cb10bc63SRichard Henderson     }
3081cb10bc63SRichard Henderson 
3082cb10bc63SRichard Henderson     /* Most opcodes have 3 or 4 operands: reduce fragmentation. */
3083cb10bc63SRichard Henderson     nargs = MAX(4, nargs);
3084cb10bc63SRichard Henderson     op = tcg_malloc(sizeof(TCGOp) + sizeof(TCGArg) * nargs);
3085cb10bc63SRichard Henderson 
3086cb10bc63SRichard Henderson  found:
308715fa08f8SRichard Henderson     memset(op, 0, offsetof(TCGOp, link));
308815fa08f8SRichard Henderson     op->opc = opc;
3089cb10bc63SRichard Henderson     op->nargs = nargs;
309015fa08f8SRichard Henderson 
3091cb10bc63SRichard Henderson     /* Check for bitfield overflow. */
3092cb10bc63SRichard Henderson     tcg_debug_assert(op->nargs == nargs);
3093cb10bc63SRichard Henderson 
3094cb10bc63SRichard Henderson     s->nb_ops++;
309515fa08f8SRichard Henderson     return op;
309615fa08f8SRichard Henderson }
309715fa08f8SRichard Henderson 
3098d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_emit_op(TCGOpcode opc, unsigned nargs)
309915fa08f8SRichard Henderson {
3100d4478943SPhilippe Mathieu-Daudé     TCGOp *op = tcg_op_alloc(opc, nargs);
310115fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
310215fa08f8SRichard Henderson     return op;
310315fa08f8SRichard Henderson }
310415fa08f8SRichard Henderson 
3105d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op,
3106d4478943SPhilippe Mathieu-Daudé                             TCGOpcode opc, unsigned nargs)
31075a18407fSRichard Henderson {
3108d4478943SPhilippe Mathieu-Daudé     TCGOp *new_op = tcg_op_alloc(opc, nargs);
310915fa08f8SRichard Henderson     QTAILQ_INSERT_BEFORE(old_op, new_op, link);
31105a18407fSRichard Henderson     return new_op;
31115a18407fSRichard Henderson }
31125a18407fSRichard Henderson 
3113d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op,
3114d4478943SPhilippe Mathieu-Daudé                            TCGOpcode opc, unsigned nargs)
31155a18407fSRichard Henderson {
3116d4478943SPhilippe Mathieu-Daudé     TCGOp *new_op = tcg_op_alloc(opc, nargs);
311715fa08f8SRichard Henderson     QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link);
31185a18407fSRichard Henderson     return new_op;
31195a18407fSRichard Henderson }
31205a18407fSRichard Henderson 
3121968f305eSRichard Henderson static void move_label_uses(TCGLabel *to, TCGLabel *from)
3122968f305eSRichard Henderson {
3123968f305eSRichard Henderson     TCGLabelUse *u;
3124968f305eSRichard Henderson 
3125968f305eSRichard Henderson     QSIMPLEQ_FOREACH(u, &from->branches, next) {
3126968f305eSRichard Henderson         TCGOp *op = u->op;
3127968f305eSRichard Henderson         switch (op->opc) {
3128968f305eSRichard Henderson         case INDEX_op_br:
3129968f305eSRichard Henderson             op->args[0] = label_arg(to);
3130968f305eSRichard Henderson             break;
3131968f305eSRichard Henderson         case INDEX_op_brcond_i32:
3132968f305eSRichard Henderson         case INDEX_op_brcond_i64:
3133968f305eSRichard Henderson             op->args[3] = label_arg(to);
3134968f305eSRichard Henderson             break;
3135968f305eSRichard Henderson         case INDEX_op_brcond2_i32:
3136968f305eSRichard Henderson             op->args[5] = label_arg(to);
3137968f305eSRichard Henderson             break;
3138968f305eSRichard Henderson         default:
3139968f305eSRichard Henderson             g_assert_not_reached();
3140968f305eSRichard Henderson         }
3141968f305eSRichard Henderson     }
3142968f305eSRichard Henderson 
3143968f305eSRichard Henderson     QSIMPLEQ_CONCAT(&to->branches, &from->branches);
3144968f305eSRichard Henderson }
3145968f305eSRichard Henderson 
3146b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code.  */
31479bbee4c0SRichard Henderson static void __attribute__((noinline))
31489bbee4c0SRichard Henderson reachable_code_pass(TCGContext *s)
3149b4fc67c7SRichard Henderson {
31504d89d0bbSRichard Henderson     TCGOp *op, *op_next, *op_prev;
3151b4fc67c7SRichard Henderson     bool dead = false;
3152b4fc67c7SRichard Henderson 
3153b4fc67c7SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
3154b4fc67c7SRichard Henderson         bool remove = dead;
3155b4fc67c7SRichard Henderson         TCGLabel *label;
3156b4fc67c7SRichard Henderson 
3157b4fc67c7SRichard Henderson         switch (op->opc) {
3158b4fc67c7SRichard Henderson         case INDEX_op_set_label:
3159b4fc67c7SRichard Henderson             label = arg_label(op->args[0]);
31604d89d0bbSRichard Henderson 
31614d89d0bbSRichard Henderson             /*
3162968f305eSRichard Henderson              * Note that the first op in the TB is always a load,
3163968f305eSRichard Henderson              * so there is always something before a label.
3164968f305eSRichard Henderson              */
3165968f305eSRichard Henderson             op_prev = QTAILQ_PREV(op, link);
3166968f305eSRichard Henderson 
3167968f305eSRichard Henderson             /*
3168968f305eSRichard Henderson              * If we find two sequential labels, move all branches to
3169968f305eSRichard Henderson              * reference the second label and remove the first label.
3170968f305eSRichard Henderson              * Do this before branch to next optimization, so that the
3171968f305eSRichard Henderson              * middle label is out of the way.
3172968f305eSRichard Henderson              */
3173968f305eSRichard Henderson             if (op_prev->opc == INDEX_op_set_label) {
3174968f305eSRichard Henderson                 move_label_uses(label, arg_label(op_prev->args[0]));
3175968f305eSRichard Henderson                 tcg_op_remove(s, op_prev);
3176968f305eSRichard Henderson                 op_prev = QTAILQ_PREV(op, link);
3177968f305eSRichard Henderson             }
3178968f305eSRichard Henderson 
3179968f305eSRichard Henderson             /*
31804d89d0bbSRichard Henderson              * Optimization can fold conditional branches to unconditional.
31814d89d0bbSRichard Henderson              * If we find a label which is preceded by an unconditional
31824d89d0bbSRichard Henderson              * branch to next, remove the branch.  We couldn't do this when
31834d89d0bbSRichard Henderson              * processing the branch because any dead code between the branch
31844d89d0bbSRichard Henderson              * and label had not yet been removed.
31854d89d0bbSRichard Henderson              */
31864d89d0bbSRichard Henderson             if (op_prev->opc == INDEX_op_br &&
31874d89d0bbSRichard Henderson                 label == arg_label(op_prev->args[0])) {
31884d89d0bbSRichard Henderson                 tcg_op_remove(s, op_prev);
31894d89d0bbSRichard Henderson                 /* Fall through means insns become live again.  */
31904d89d0bbSRichard Henderson                 dead = false;
31914d89d0bbSRichard Henderson             }
31924d89d0bbSRichard Henderson 
3193f85b1fc4SRichard Henderson             if (QSIMPLEQ_EMPTY(&label->branches)) {
3194b4fc67c7SRichard Henderson                 /*
3195b4fc67c7SRichard Henderson                  * While there is an occasional backward branch, virtually
3196b4fc67c7SRichard Henderson                  * all branches generated by the translators are forward.
3197b4fc67c7SRichard Henderson                  * Which means that generally we will have already removed
3198b4fc67c7SRichard Henderson                  * all references to the label that will be, and there is
3199b4fc67c7SRichard Henderson                  * little to be gained by iterating.
3200b4fc67c7SRichard Henderson                  */
3201b4fc67c7SRichard Henderson                 remove = true;
3202b4fc67c7SRichard Henderson             } else {
3203b4fc67c7SRichard Henderson                 /* Once we see a label, insns become live again.  */
3204b4fc67c7SRichard Henderson                 dead = false;
3205b4fc67c7SRichard Henderson                 remove = false;
3206b4fc67c7SRichard Henderson             }
3207b4fc67c7SRichard Henderson             break;
3208b4fc67c7SRichard Henderson 
3209b4fc67c7SRichard Henderson         case INDEX_op_br:
3210b4fc67c7SRichard Henderson         case INDEX_op_exit_tb:
3211b4fc67c7SRichard Henderson         case INDEX_op_goto_ptr:
3212b4fc67c7SRichard Henderson             /* Unconditional branches; everything following is dead.  */
3213b4fc67c7SRichard Henderson             dead = true;
3214b4fc67c7SRichard Henderson             break;
3215b4fc67c7SRichard Henderson 
3216b4fc67c7SRichard Henderson         case INDEX_op_call:
3217b4fc67c7SRichard Henderson             /* Notice noreturn helper calls, raising exceptions.  */
321890163900SRichard Henderson             if (tcg_call_flags(op) & TCG_CALL_NO_RETURN) {
3219b4fc67c7SRichard Henderson                 dead = true;
3220b4fc67c7SRichard Henderson             }
3221b4fc67c7SRichard Henderson             break;
3222b4fc67c7SRichard Henderson 
3223b4fc67c7SRichard Henderson         case INDEX_op_insn_start:
3224b4fc67c7SRichard Henderson             /* Never remove -- we need to keep these for unwind.  */
3225b4fc67c7SRichard Henderson             remove = false;
3226b4fc67c7SRichard Henderson             break;
3227b4fc67c7SRichard Henderson 
3228b4fc67c7SRichard Henderson         default:
3229b4fc67c7SRichard Henderson             break;
3230b4fc67c7SRichard Henderson         }
3231b4fc67c7SRichard Henderson 
3232b4fc67c7SRichard Henderson         if (remove) {
3233b4fc67c7SRichard Henderson             tcg_op_remove(s, op);
3234b4fc67c7SRichard Henderson         }
3235b4fc67c7SRichard Henderson     }
3236b4fc67c7SRichard Henderson }
3237b4fc67c7SRichard Henderson 
3238c70fbf0aSRichard Henderson #define TS_DEAD  1
3239c70fbf0aSRichard Henderson #define TS_MEM   2
3240c70fbf0aSRichard Henderson 
32415a18407fSRichard Henderson #define IS_DEAD_ARG(n)   (arg_life & (DEAD_ARG << (n)))
32425a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n)))
32435a18407fSRichard Henderson 
324425f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp.  */
324525f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts)
324625f49c5fSRichard Henderson {
324725f49c5fSRichard Henderson     return ts->state_ptr;
324825f49c5fSRichard Henderson }
324925f49c5fSRichard Henderson 
325025f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the
325125f49c5fSRichard Henderson  * maximal regset for its type.
325225f49c5fSRichard Henderson  */
325325f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts)
325425f49c5fSRichard Henderson {
325525f49c5fSRichard Henderson     *la_temp_pref(ts)
325625f49c5fSRichard Henderson         = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]);
325725f49c5fSRichard Henderson }
325825f49c5fSRichard Henderson 
32599c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals
32609c43b68dSAurelien Jarno    should be in memory. */
32612616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt)
3262c896fe29Sbellard {
3263b83eabeaSRichard Henderson     int i;
3264b83eabeaSRichard Henderson 
3265b83eabeaSRichard Henderson     for (i = 0; i < ng; ++i) {
3266b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
326725f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
3268b83eabeaSRichard Henderson     }
3269b83eabeaSRichard Henderson     for (i = ng; i < nt; ++i) {
3270b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD;
327125f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
3272b83eabeaSRichard Henderson     }
3273c896fe29Sbellard }
3274c896fe29Sbellard 
32759c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals
32769c43b68dSAurelien Jarno    and local temps should be in memory. */
32772616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt)
3278641d5fbeSbellard {
3279b83eabeaSRichard Henderson     int i;
3280641d5fbeSbellard 
3281ee17db83SRichard Henderson     for (i = 0; i < nt; ++i) {
3282ee17db83SRichard Henderson         TCGTemp *ts = &s->temps[i];
3283ee17db83SRichard Henderson         int state;
3284ee17db83SRichard Henderson 
3285ee17db83SRichard Henderson         switch (ts->kind) {
3286ee17db83SRichard Henderson         case TEMP_FIXED:
3287ee17db83SRichard Henderson         case TEMP_GLOBAL:
3288f57c6915SRichard Henderson         case TEMP_TB:
3289ee17db83SRichard Henderson             state = TS_DEAD | TS_MEM;
3290ee17db83SRichard Henderson             break;
3291c7482438SRichard Henderson         case TEMP_EBB:
3292c0522136SRichard Henderson         case TEMP_CONST:
3293ee17db83SRichard Henderson             state = TS_DEAD;
3294ee17db83SRichard Henderson             break;
3295ee17db83SRichard Henderson         default:
3296ee17db83SRichard Henderson             g_assert_not_reached();
3297c70fbf0aSRichard Henderson         }
3298ee17db83SRichard Henderson         ts->state = state;
3299ee17db83SRichard Henderson         la_reset_pref(ts);
3300641d5fbeSbellard     }
3301641d5fbeSbellard }
3302641d5fbeSbellard 
3303f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory.  */
3304f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng)
3305f65a061cSRichard Henderson {
3306f65a061cSRichard Henderson     int i;
3307f65a061cSRichard Henderson 
3308f65a061cSRichard Henderson     for (i = 0; i < ng; ++i) {
330925f49c5fSRichard Henderson         int state = s->temps[i].state;
331025f49c5fSRichard Henderson         s->temps[i].state = state | TS_MEM;
331125f49c5fSRichard Henderson         if (state == TS_DEAD) {
331225f49c5fSRichard Henderson             /* If the global was previously dead, reset prefs.  */
331325f49c5fSRichard Henderson             la_reset_pref(&s->temps[i]);
331425f49c5fSRichard Henderson         }
3315f65a061cSRichard Henderson     }
3316f65a061cSRichard Henderson }
3317f65a061cSRichard Henderson 
3318b4cb76e6SRichard Henderson /*
3319c7482438SRichard Henderson  * liveness analysis: conditional branch: all temps are dead unless
3320c7482438SRichard Henderson  * explicitly live-across-conditional-branch, globals and local temps
3321c7482438SRichard Henderson  * should be synced.
3322b4cb76e6SRichard Henderson  */
3323b4cb76e6SRichard Henderson static void la_bb_sync(TCGContext *s, int ng, int nt)
3324b4cb76e6SRichard Henderson {
3325b4cb76e6SRichard Henderson     la_global_sync(s, ng);
3326b4cb76e6SRichard Henderson 
3327b4cb76e6SRichard Henderson     for (int i = ng; i < nt; ++i) {
3328c0522136SRichard Henderson         TCGTemp *ts = &s->temps[i];
3329c0522136SRichard Henderson         int state;
3330c0522136SRichard Henderson 
3331c0522136SRichard Henderson         switch (ts->kind) {
3332f57c6915SRichard Henderson         case TEMP_TB:
3333c0522136SRichard Henderson             state = ts->state;
3334c0522136SRichard Henderson             ts->state = state | TS_MEM;
3335b4cb76e6SRichard Henderson             if (state != TS_DEAD) {
3336b4cb76e6SRichard Henderson                 continue;
3337b4cb76e6SRichard Henderson             }
3338c0522136SRichard Henderson             break;
3339c7482438SRichard Henderson         case TEMP_EBB:
3340c0522136SRichard Henderson         case TEMP_CONST:
3341c0522136SRichard Henderson             continue;
3342c0522136SRichard Henderson         default:
3343c0522136SRichard Henderson             g_assert_not_reached();
3344b4cb76e6SRichard Henderson         }
3345b4cb76e6SRichard Henderson         la_reset_pref(&s->temps[i]);
3346b4cb76e6SRichard Henderson     }
3347b4cb76e6SRichard Henderson }
3348b4cb76e6SRichard Henderson 
3349f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill.  */
3350f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng)
3351f65a061cSRichard Henderson {
3352f65a061cSRichard Henderson     int i;
3353f65a061cSRichard Henderson 
3354f65a061cSRichard Henderson     for (i = 0; i < ng; i++) {
3355f65a061cSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
335625f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
335725f49c5fSRichard Henderson     }
335825f49c5fSRichard Henderson }
335925f49c5fSRichard Henderson 
336025f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls.  */
336125f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt)
336225f49c5fSRichard Henderson {
336325f49c5fSRichard Henderson     TCGRegSet mask = ~tcg_target_call_clobber_regs;
336425f49c5fSRichard Henderson     int i;
336525f49c5fSRichard Henderson 
336625f49c5fSRichard Henderson     for (i = 0; i < nt; i++) {
336725f49c5fSRichard Henderson         TCGTemp *ts = &s->temps[i];
336825f49c5fSRichard Henderson         if (!(ts->state & TS_DEAD)) {
336925f49c5fSRichard Henderson             TCGRegSet *pset = la_temp_pref(ts);
337025f49c5fSRichard Henderson             TCGRegSet set = *pset;
337125f49c5fSRichard Henderson 
337225f49c5fSRichard Henderson             set &= mask;
337325f49c5fSRichard Henderson             /* If the combination is not possible, restart.  */
337425f49c5fSRichard Henderson             if (set == 0) {
337525f49c5fSRichard Henderson                 set = tcg_target_available_regs[ts->type] & mask;
337625f49c5fSRichard Henderson             }
337725f49c5fSRichard Henderson             *pset = set;
337825f49c5fSRichard Henderson         }
3379f65a061cSRichard Henderson     }
3380f65a061cSRichard Henderson }
3381f65a061cSRichard Henderson 
3382874b8574SRichard Henderson /*
3383874b8574SRichard Henderson  * Liveness analysis: Verify the lifetime of TEMP_TB, and reduce
3384874b8574SRichard Henderson  * to TEMP_EBB, if possible.
3385874b8574SRichard Henderson  */
3386874b8574SRichard Henderson static void __attribute__((noinline))
3387874b8574SRichard Henderson liveness_pass_0(TCGContext *s)
3388874b8574SRichard Henderson {
3389874b8574SRichard Henderson     void * const multiple_ebb = (void *)(uintptr_t)-1;
3390874b8574SRichard Henderson     int nb_temps = s->nb_temps;
3391874b8574SRichard Henderson     TCGOp *op, *ebb;
3392874b8574SRichard Henderson 
3393874b8574SRichard Henderson     for (int i = s->nb_globals; i < nb_temps; ++i) {
3394874b8574SRichard Henderson         s->temps[i].state_ptr = NULL;
3395874b8574SRichard Henderson     }
3396874b8574SRichard Henderson 
3397874b8574SRichard Henderson     /*
3398874b8574SRichard Henderson      * Represent each EBB by the op at which it begins.  In the case of
3399874b8574SRichard Henderson      * the first EBB, this is the first op, otherwise it is a label.
3400874b8574SRichard Henderson      * Collect the uses of each TEMP_TB: NULL for unused, EBB for use
3401874b8574SRichard Henderson      * within a single EBB, else MULTIPLE_EBB.
3402874b8574SRichard Henderson      */
3403874b8574SRichard Henderson     ebb = QTAILQ_FIRST(&s->ops);
3404874b8574SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
3405874b8574SRichard Henderson         const TCGOpDef *def;
3406874b8574SRichard Henderson         int nb_oargs, nb_iargs;
3407874b8574SRichard Henderson 
3408874b8574SRichard Henderson         switch (op->opc) {
3409874b8574SRichard Henderson         case INDEX_op_set_label:
3410874b8574SRichard Henderson             ebb = op;
3411874b8574SRichard Henderson             continue;
3412874b8574SRichard Henderson         case INDEX_op_discard:
3413874b8574SRichard Henderson             continue;
3414874b8574SRichard Henderson         case INDEX_op_call:
3415874b8574SRichard Henderson             nb_oargs = TCGOP_CALLO(op);
3416874b8574SRichard Henderson             nb_iargs = TCGOP_CALLI(op);
3417874b8574SRichard Henderson             break;
3418874b8574SRichard Henderson         default:
3419874b8574SRichard Henderson             def = &tcg_op_defs[op->opc];
3420874b8574SRichard Henderson             nb_oargs = def->nb_oargs;
3421874b8574SRichard Henderson             nb_iargs = def->nb_iargs;
3422874b8574SRichard Henderson             break;
3423874b8574SRichard Henderson         }
3424874b8574SRichard Henderson 
3425874b8574SRichard Henderson         for (int i = 0; i < nb_oargs + nb_iargs; ++i) {
3426874b8574SRichard Henderson             TCGTemp *ts = arg_temp(op->args[i]);
3427874b8574SRichard Henderson 
3428874b8574SRichard Henderson             if (ts->kind != TEMP_TB) {
3429874b8574SRichard Henderson                 continue;
3430874b8574SRichard Henderson             }
3431874b8574SRichard Henderson             if (ts->state_ptr == NULL) {
3432874b8574SRichard Henderson                 ts->state_ptr = ebb;
3433874b8574SRichard Henderson             } else if (ts->state_ptr != ebb) {
3434874b8574SRichard Henderson                 ts->state_ptr = multiple_ebb;
3435874b8574SRichard Henderson             }
3436874b8574SRichard Henderson         }
3437874b8574SRichard Henderson     }
3438874b8574SRichard Henderson 
3439874b8574SRichard Henderson     /*
3440874b8574SRichard Henderson      * For TEMP_TB that turned out not to be used beyond one EBB,
3441874b8574SRichard Henderson      * reduce the liveness to TEMP_EBB.
3442874b8574SRichard Henderson      */
3443874b8574SRichard Henderson     for (int i = s->nb_globals; i < nb_temps; ++i) {
3444874b8574SRichard Henderson         TCGTemp *ts = &s->temps[i];
3445874b8574SRichard Henderson         if (ts->kind == TEMP_TB && ts->state_ptr != multiple_ebb) {
3446874b8574SRichard Henderson             ts->kind = TEMP_EBB;
3447874b8574SRichard Henderson         }
3448874b8574SRichard Henderson     }
3449874b8574SRichard Henderson }
3450874b8574SRichard Henderson 
3451a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a
3452c896fe29Sbellard    given input arguments is dead. Instructions updating dead
3453c896fe29Sbellard    temporaries are removed. */
34549bbee4c0SRichard Henderson static void __attribute__((noinline))
34559bbee4c0SRichard Henderson liveness_pass_1(TCGContext *s)
3456c896fe29Sbellard {
3457c70fbf0aSRichard Henderson     int nb_globals = s->nb_globals;
34582616c808SRichard Henderson     int nb_temps = s->nb_temps;
345915fa08f8SRichard Henderson     TCGOp *op, *op_prev;
346025f49c5fSRichard Henderson     TCGRegSet *prefs;
346125f49c5fSRichard Henderson     int i;
346225f49c5fSRichard Henderson 
346325f49c5fSRichard Henderson     prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps);
346425f49c5fSRichard Henderson     for (i = 0; i < nb_temps; ++i) {
346525f49c5fSRichard Henderson         s->temps[i].state_ptr = prefs + i;
346625f49c5fSRichard Henderson     }
3467c896fe29Sbellard 
3468ae36a246SRichard Henderson     /* ??? Should be redundant with the exit_tb that ends the TB.  */
34692616c808SRichard Henderson     la_func_end(s, nb_globals, nb_temps);
3470c896fe29Sbellard 
3471eae3eb3eSPaolo Bonzini     QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) {
347225f49c5fSRichard Henderson         int nb_iargs, nb_oargs;
3473c45cb8bbSRichard Henderson         TCGOpcode opc_new, opc_new2;
3474c45cb8bbSRichard Henderson         bool have_opc_new2;
3475a1b3c48dSRichard Henderson         TCGLifeData arg_life = 0;
347625f49c5fSRichard Henderson         TCGTemp *ts;
3477c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
3478c45cb8bbSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
3479c45cb8bbSRichard Henderson 
3480c45cb8bbSRichard Henderson         switch (opc) {
3481c896fe29Sbellard         case INDEX_op_call:
3482c6e113f5Sbellard             {
348339004a71SRichard Henderson                 const TCGHelperInfo *info = tcg_call_info(op);
348439004a71SRichard Henderson                 int call_flags = tcg_call_flags(op);
3485c6e113f5Sbellard 
3486cd9090aaSRichard Henderson                 nb_oargs = TCGOP_CALLO(op);
3487cd9090aaSRichard Henderson                 nb_iargs = TCGOP_CALLI(op);
3488c6e113f5Sbellard 
3489c45cb8bbSRichard Henderson                 /* pure functions can be removed if their result is unused */
349078505279SAurelien Jarno                 if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) {
3491c6e113f5Sbellard                     for (i = 0; i < nb_oargs; i++) {
349225f49c5fSRichard Henderson                         ts = arg_temp(op->args[i]);
349325f49c5fSRichard Henderson                         if (ts->state != TS_DEAD) {
3494c6e113f5Sbellard                             goto do_not_remove_call;
3495c6e113f5Sbellard                         }
34969c43b68dSAurelien Jarno                     }
3497c45cb8bbSRichard Henderson                     goto do_remove;
3498152c35aaSRichard Henderson                 }
3499c6e113f5Sbellard             do_not_remove_call:
3500c896fe29Sbellard 
350125f49c5fSRichard Henderson                 /* Output args are dead.  */
3502c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
350325f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
350425f49c5fSRichard Henderson                     if (ts->state & TS_DEAD) {
3505a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
35066b64b624SAurelien Jarno                     }
350725f49c5fSRichard Henderson                     if (ts->state & TS_MEM) {
3508a1b3c48dSRichard Henderson                         arg_life |= SYNC_ARG << i;
35099c43b68dSAurelien Jarno                     }
351025f49c5fSRichard Henderson                     ts->state = TS_DEAD;
351125f49c5fSRichard Henderson                     la_reset_pref(ts);
3512c896fe29Sbellard                 }
3513c896fe29Sbellard 
351431fd884bSRichard Henderson                 /* Not used -- it will be tcg_target_call_oarg_reg().  */
351531fd884bSRichard Henderson                 memset(op->output_pref, 0, sizeof(op->output_pref));
351631fd884bSRichard Henderson 
351778505279SAurelien Jarno                 if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS |
351878505279SAurelien Jarno                                     TCG_CALL_NO_READ_GLOBALS))) {
3519f65a061cSRichard Henderson                     la_global_kill(s, nb_globals);
3520c70fbf0aSRichard Henderson                 } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) {
3521f65a061cSRichard Henderson                     la_global_sync(s, nb_globals);
3522b9c18f56Saurel32                 }
3523c896fe29Sbellard 
352425f49c5fSRichard Henderson                 /* Record arguments that die in this helper.  */
3525866cb6cbSAurelien Jarno                 for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
352625f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
352739004a71SRichard Henderson                     if (ts->state & TS_DEAD) {
3528a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
3529c896fe29Sbellard                     }
3530c896fe29Sbellard                 }
353125f49c5fSRichard Henderson 
353225f49c5fSRichard Henderson                 /* For all live registers, remove call-clobbered prefs.  */
353325f49c5fSRichard Henderson                 la_cross_call(s, nb_temps);
353425f49c5fSRichard Henderson 
353539004a71SRichard Henderson                 /*
353639004a71SRichard Henderson                  * Input arguments are live for preceding opcodes.
353739004a71SRichard Henderson                  *
353839004a71SRichard Henderson                  * For those arguments that die, and will be allocated in
353939004a71SRichard Henderson                  * registers, clear the register set for that arg, to be
354039004a71SRichard Henderson                  * filled in below.  For args that will be on the stack,
354139004a71SRichard Henderson                  * reset to any available reg.  Process arguments in reverse
354239004a71SRichard Henderson                  * order so that if a temp is used more than once, the stack
354339004a71SRichard Henderson                  * reset to max happens before the register reset to 0.
354425f49c5fSRichard Henderson                  */
354539004a71SRichard Henderson                 for (i = nb_iargs - 1; i >= 0; i--) {
354639004a71SRichard Henderson                     const TCGCallArgumentLoc *loc = &info->in[i];
354739004a71SRichard Henderson                     ts = arg_temp(op->args[nb_oargs + i]);
354839004a71SRichard Henderson 
354939004a71SRichard Henderson                     if (ts->state & TS_DEAD) {
355039004a71SRichard Henderson                         switch (loc->kind) {
355139004a71SRichard Henderson                         case TCG_CALL_ARG_NORMAL:
355239004a71SRichard Henderson                         case TCG_CALL_ARG_EXTEND_U:
355339004a71SRichard Henderson                         case TCG_CALL_ARG_EXTEND_S:
3554338b61e9SRichard Henderson                             if (arg_slot_reg_p(loc->arg_slot)) {
355539004a71SRichard Henderson                                 *la_temp_pref(ts) = 0;
355639004a71SRichard Henderson                                 break;
355739004a71SRichard Henderson                             }
355839004a71SRichard Henderson                             /* fall through */
355939004a71SRichard Henderson                         default:
356039004a71SRichard Henderson                             *la_temp_pref(ts) =
356139004a71SRichard Henderson                                 tcg_target_available_regs[ts->type];
356239004a71SRichard Henderson                             break;
356339004a71SRichard Henderson                         }
356425f49c5fSRichard Henderson                         ts->state &= ~TS_DEAD;
356525f49c5fSRichard Henderson                     }
356625f49c5fSRichard Henderson                 }
356725f49c5fSRichard Henderson 
356839004a71SRichard Henderson                 /*
356939004a71SRichard Henderson                  * For each input argument, add its input register to prefs.
357039004a71SRichard Henderson                  * If a temp is used once, this produces a single set bit;
357139004a71SRichard Henderson                  * if a temp is used multiple times, this produces a set.
357239004a71SRichard Henderson                  */
357339004a71SRichard Henderson                 for (i = 0; i < nb_iargs; i++) {
357439004a71SRichard Henderson                     const TCGCallArgumentLoc *loc = &info->in[i];
357539004a71SRichard Henderson                     ts = arg_temp(op->args[nb_oargs + i]);
357639004a71SRichard Henderson 
357739004a71SRichard Henderson                     switch (loc->kind) {
357839004a71SRichard Henderson                     case TCG_CALL_ARG_NORMAL:
357939004a71SRichard Henderson                     case TCG_CALL_ARG_EXTEND_U:
358039004a71SRichard Henderson                     case TCG_CALL_ARG_EXTEND_S:
3581338b61e9SRichard Henderson                         if (arg_slot_reg_p(loc->arg_slot)) {
358225f49c5fSRichard Henderson                             tcg_regset_set_reg(*la_temp_pref(ts),
358339004a71SRichard Henderson                                 tcg_target_call_iarg_regs[loc->arg_slot]);
358439004a71SRichard Henderson                         }
358539004a71SRichard Henderson                         break;
358639004a71SRichard Henderson                     default:
358739004a71SRichard Henderson                         break;
3588c70fbf0aSRichard Henderson                     }
3589c19f47bfSAurelien Jarno                 }
3590c6e113f5Sbellard             }
3591c896fe29Sbellard             break;
3592765b842aSRichard Henderson         case INDEX_op_insn_start:
3593c896fe29Sbellard             break;
35945ff9d6a4Sbellard         case INDEX_op_discard:
35955ff9d6a4Sbellard             /* mark the temporary as dead */
359625f49c5fSRichard Henderson             ts = arg_temp(op->args[0]);
359725f49c5fSRichard Henderson             ts->state = TS_DEAD;
359825f49c5fSRichard Henderson             la_reset_pref(ts);
35995ff9d6a4Sbellard             break;
36001305c451SRichard Henderson 
36011305c451SRichard Henderson         case INDEX_op_add2_i32:
3602c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i32;
3603f1fae40cSRichard Henderson             goto do_addsub2;
36041305c451SRichard Henderson         case INDEX_op_sub2_i32:
3605c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i32;
3606f1fae40cSRichard Henderson             goto do_addsub2;
3607f1fae40cSRichard Henderson         case INDEX_op_add2_i64:
3608c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i64;
3609f1fae40cSRichard Henderson             goto do_addsub2;
3610f1fae40cSRichard Henderson         case INDEX_op_sub2_i64:
3611c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i64;
3612f1fae40cSRichard Henderson         do_addsub2:
36131305c451SRichard Henderson             nb_iargs = 4;
36141305c451SRichard Henderson             nb_oargs = 2;
36151305c451SRichard Henderson             /* Test if the high part of the operation is dead, but not
36161305c451SRichard Henderson                the low part.  The result can be optimized to a simple
36171305c451SRichard Henderson                add or sub.  This happens often for x86_64 guest when the
36181305c451SRichard Henderson                cpu mode is set to 32 bit.  */
3619b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
3620b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
36211305c451SRichard Henderson                     goto do_remove;
36221305c451SRichard Henderson                 }
3623c45cb8bbSRichard Henderson                 /* Replace the opcode and adjust the args in place,
3624c45cb8bbSRichard Henderson                    leaving 3 unused args at the end.  */
3625c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
3626efee3746SRichard Henderson                 op->args[1] = op->args[2];
3627efee3746SRichard Henderson                 op->args[2] = op->args[4];
36281305c451SRichard Henderson                 /* Fall through and mark the single-word operation live.  */
36291305c451SRichard Henderson                 nb_iargs = 2;
36301305c451SRichard Henderson                 nb_oargs = 1;
36311305c451SRichard Henderson             }
36321305c451SRichard Henderson             goto do_not_remove;
36331305c451SRichard Henderson 
36341414968aSRichard Henderson         case INDEX_op_mulu2_i32:
3635c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
3636c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i32;
3637c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i32;
363803271524SRichard Henderson             goto do_mul2;
3639f1fae40cSRichard Henderson         case INDEX_op_muls2_i32:
3640c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
3641c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i32;
3642c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i32;
3643f1fae40cSRichard Henderson             goto do_mul2;
3644f1fae40cSRichard Henderson         case INDEX_op_mulu2_i64:
3645c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
3646c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i64;
3647c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i64;
364803271524SRichard Henderson             goto do_mul2;
3649f1fae40cSRichard Henderson         case INDEX_op_muls2_i64:
3650c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
3651c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i64;
3652c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i64;
365303271524SRichard Henderson             goto do_mul2;
3654f1fae40cSRichard Henderson         do_mul2:
36551414968aSRichard Henderson             nb_iargs = 2;
36561414968aSRichard Henderson             nb_oargs = 2;
3657b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
3658b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
365903271524SRichard Henderson                     /* Both parts of the operation are dead.  */
36601414968aSRichard Henderson                     goto do_remove;
36611414968aSRichard Henderson                 }
366203271524SRichard Henderson                 /* The high part of the operation is dead; generate the low. */
3663c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
3664efee3746SRichard Henderson                 op->args[1] = op->args[2];
3665efee3746SRichard Henderson                 op->args[2] = op->args[3];
3666b83eabeaSRichard Henderson             } else if (arg_temp(op->args[0])->state == TS_DEAD && have_opc_new2) {
366703271524SRichard Henderson                 /* The low part of the operation is dead; generate the high. */
3668c45cb8bbSRichard Henderson                 op->opc = opc = opc_new2;
3669efee3746SRichard Henderson                 op->args[0] = op->args[1];
3670efee3746SRichard Henderson                 op->args[1] = op->args[2];
3671efee3746SRichard Henderson                 op->args[2] = op->args[3];
367203271524SRichard Henderson             } else {
367303271524SRichard Henderson                 goto do_not_remove;
367403271524SRichard Henderson             }
367503271524SRichard Henderson             /* Mark the single-word operation live.  */
36761414968aSRichard Henderson             nb_oargs = 1;
36771414968aSRichard Henderson             goto do_not_remove;
36781414968aSRichard Henderson 
3679c896fe29Sbellard         default:
36801305c451SRichard Henderson             /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
3681c896fe29Sbellard             nb_iargs = def->nb_iargs;
3682c896fe29Sbellard             nb_oargs = def->nb_oargs;
3683c896fe29Sbellard 
3684c896fe29Sbellard             /* Test if the operation can be removed because all
36855ff9d6a4Sbellard                its outputs are dead. We assume that nb_oargs == 0
36865ff9d6a4Sbellard                implies side effects */
36875ff9d6a4Sbellard             if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
3688c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
3689b83eabeaSRichard Henderson                     if (arg_temp(op->args[i])->state != TS_DEAD) {
3690c896fe29Sbellard                         goto do_not_remove;
3691c896fe29Sbellard                     }
36929c43b68dSAurelien Jarno                 }
3693152c35aaSRichard Henderson                 goto do_remove;
3694152c35aaSRichard Henderson             }
3695152c35aaSRichard Henderson             goto do_not_remove;
3696152c35aaSRichard Henderson 
36971305c451SRichard Henderson         do_remove:
36980c627cdcSRichard Henderson             tcg_op_remove(s, op);
3699152c35aaSRichard Henderson             break;
3700152c35aaSRichard Henderson 
3701c896fe29Sbellard         do_not_remove:
3702c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
370325f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
370425f49c5fSRichard Henderson 
370525f49c5fSRichard Henderson                 /* Remember the preference of the uses that followed.  */
370631fd884bSRichard Henderson                 if (i < ARRAY_SIZE(op->output_pref)) {
370725f49c5fSRichard Henderson                     op->output_pref[i] = *la_temp_pref(ts);
370831fd884bSRichard Henderson                 }
370925f49c5fSRichard Henderson 
371025f49c5fSRichard Henderson                 /* Output args are dead.  */
371125f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
3712a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
37136b64b624SAurelien Jarno                 }
371425f49c5fSRichard Henderson                 if (ts->state & TS_MEM) {
3715a1b3c48dSRichard Henderson                     arg_life |= SYNC_ARG << i;
37169c43b68dSAurelien Jarno                 }
371725f49c5fSRichard Henderson                 ts->state = TS_DEAD;
371825f49c5fSRichard Henderson                 la_reset_pref(ts);
3719c896fe29Sbellard             }
3720c896fe29Sbellard 
372125f49c5fSRichard Henderson             /* If end of basic block, update.  */
3722ae36a246SRichard Henderson             if (def->flags & TCG_OPF_BB_EXIT) {
3723ae36a246SRichard Henderson                 la_func_end(s, nb_globals, nb_temps);
3724b4cb76e6SRichard Henderson             } else if (def->flags & TCG_OPF_COND_BRANCH) {
3725b4cb76e6SRichard Henderson                 la_bb_sync(s, nb_globals, nb_temps);
3726ae36a246SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
37272616c808SRichard Henderson                 la_bb_end(s, nb_globals, nb_temps);
37283d5c5f87SAurelien Jarno             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
3729f65a061cSRichard Henderson                 la_global_sync(s, nb_globals);
373025f49c5fSRichard Henderson                 if (def->flags & TCG_OPF_CALL_CLOBBER) {
373125f49c5fSRichard Henderson                     la_cross_call(s, nb_temps);
373225f49c5fSRichard Henderson                 }
3733c896fe29Sbellard             }
3734c896fe29Sbellard 
373525f49c5fSRichard Henderson             /* Record arguments that die in this opcode.  */
3736866cb6cbSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
373725f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
373825f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
3739a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
3740c896fe29Sbellard                 }
3741c19f47bfSAurelien Jarno             }
374225f49c5fSRichard Henderson 
374325f49c5fSRichard Henderson             /* Input arguments are live for preceding opcodes.  */
3744c19f47bfSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
374525f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
374625f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
374725f49c5fSRichard Henderson                     /* For operands that were dead, initially allow
374825f49c5fSRichard Henderson                        all regs for the type.  */
374925f49c5fSRichard Henderson                     *la_temp_pref(ts) = tcg_target_available_regs[ts->type];
375025f49c5fSRichard Henderson                     ts->state &= ~TS_DEAD;
375125f49c5fSRichard Henderson                 }
375225f49c5fSRichard Henderson             }
375325f49c5fSRichard Henderson 
375425f49c5fSRichard Henderson             /* Incorporate constraints for this operand.  */
375525f49c5fSRichard Henderson             switch (opc) {
375625f49c5fSRichard Henderson             case INDEX_op_mov_i32:
375725f49c5fSRichard Henderson             case INDEX_op_mov_i64:
375825f49c5fSRichard Henderson                 /* Note that these are TCG_OPF_NOT_PRESENT and do not
375925f49c5fSRichard Henderson                    have proper constraints.  That said, special case
376025f49c5fSRichard Henderson                    moves to propagate preferences backward.  */
376125f49c5fSRichard Henderson                 if (IS_DEAD_ARG(1)) {
376225f49c5fSRichard Henderson                     *la_temp_pref(arg_temp(op->args[0]))
376325f49c5fSRichard Henderson                         = *la_temp_pref(arg_temp(op->args[1]));
376425f49c5fSRichard Henderson                 }
376525f49c5fSRichard Henderson                 break;
376625f49c5fSRichard Henderson 
376725f49c5fSRichard Henderson             default:
376825f49c5fSRichard Henderson                 for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
376925f49c5fSRichard Henderson                     const TCGArgConstraint *ct = &def->args_ct[i];
377025f49c5fSRichard Henderson                     TCGRegSet set, *pset;
377125f49c5fSRichard Henderson 
377225f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
377325f49c5fSRichard Henderson                     pset = la_temp_pref(ts);
377425f49c5fSRichard Henderson                     set = *pset;
377525f49c5fSRichard Henderson 
37769be0d080SRichard Henderson                     set &= ct->regs;
3777bc2b17e6SRichard Henderson                     if (ct->ialias) {
377831fd884bSRichard Henderson                         set &= output_pref(op, ct->alias_index);
377925f49c5fSRichard Henderson                     }
378025f49c5fSRichard Henderson                     /* If the combination is not possible, restart.  */
378125f49c5fSRichard Henderson                     if (set == 0) {
37829be0d080SRichard Henderson                         set = ct->regs;
378325f49c5fSRichard Henderson                     }
378425f49c5fSRichard Henderson                     *pset = set;
378525f49c5fSRichard Henderson                 }
378625f49c5fSRichard Henderson                 break;
3787c896fe29Sbellard             }
3788c896fe29Sbellard             break;
3789c896fe29Sbellard         }
3790bee158cbSRichard Henderson         op->life = arg_life;
3791c896fe29Sbellard     }
37921ff0a2c5SEvgeny Voevodin }
3793c896fe29Sbellard 
37945a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries.  */
37959bbee4c0SRichard Henderson static bool __attribute__((noinline))
37969bbee4c0SRichard Henderson liveness_pass_2(TCGContext *s)
37975a18407fSRichard Henderson {
37985a18407fSRichard Henderson     int nb_globals = s->nb_globals;
379915fa08f8SRichard Henderson     int nb_temps, i;
38005a18407fSRichard Henderson     bool changes = false;
380115fa08f8SRichard Henderson     TCGOp *op, *op_next;
38025a18407fSRichard Henderson 
38035a18407fSRichard Henderson     /* Create a temporary for each indirect global.  */
38045a18407fSRichard Henderson     for (i = 0; i < nb_globals; ++i) {
38055a18407fSRichard Henderson         TCGTemp *its = &s->temps[i];
38065a18407fSRichard Henderson         if (its->indirect_reg) {
38075a18407fSRichard Henderson             TCGTemp *dts = tcg_temp_alloc(s);
38085a18407fSRichard Henderson             dts->type = its->type;
38095a18407fSRichard Henderson             dts->base_type = its->base_type;
3810e1e64652SRichard Henderson             dts->temp_subindex = its->temp_subindex;
3811c7482438SRichard Henderson             dts->kind = TEMP_EBB;
3812b83eabeaSRichard Henderson             its->state_ptr = dts;
3813b83eabeaSRichard Henderson         } else {
3814b83eabeaSRichard Henderson             its->state_ptr = NULL;
38155a18407fSRichard Henderson         }
3816b83eabeaSRichard Henderson         /* All globals begin dead.  */
3817b83eabeaSRichard Henderson         its->state = TS_DEAD;
38185a18407fSRichard Henderson     }
3819b83eabeaSRichard Henderson     for (nb_temps = s->nb_temps; i < nb_temps; ++i) {
3820b83eabeaSRichard Henderson         TCGTemp *its = &s->temps[i];
3821b83eabeaSRichard Henderson         its->state_ptr = NULL;
3822b83eabeaSRichard Henderson         its->state = TS_DEAD;
3823b83eabeaSRichard Henderson     }
38245a18407fSRichard Henderson 
382515fa08f8SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
38265a18407fSRichard Henderson         TCGOpcode opc = op->opc;
38275a18407fSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
38285a18407fSRichard Henderson         TCGLifeData arg_life = op->life;
38295a18407fSRichard Henderson         int nb_iargs, nb_oargs, call_flags;
3830b83eabeaSRichard Henderson         TCGTemp *arg_ts, *dir_ts;
38315a18407fSRichard Henderson 
38325a18407fSRichard Henderson         if (opc == INDEX_op_call) {
3833cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
3834cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
383590163900SRichard Henderson             call_flags = tcg_call_flags(op);
38365a18407fSRichard Henderson         } else {
38375a18407fSRichard Henderson             nb_iargs = def->nb_iargs;
38385a18407fSRichard Henderson             nb_oargs = def->nb_oargs;
38395a18407fSRichard Henderson 
38405a18407fSRichard Henderson             /* Set flags similar to how calls require.  */
3841b4cb76e6SRichard Henderson             if (def->flags & TCG_OPF_COND_BRANCH) {
3842b4cb76e6SRichard Henderson                 /* Like reading globals: sync_globals */
3843b4cb76e6SRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
3844b4cb76e6SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
38455a18407fSRichard Henderson                 /* Like writing globals: save_globals */
38465a18407fSRichard Henderson                 call_flags = 0;
38475a18407fSRichard Henderson             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
38485a18407fSRichard Henderson                 /* Like reading globals: sync_globals */
38495a18407fSRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
38505a18407fSRichard Henderson             } else {
38515a18407fSRichard Henderson                 /* No effect on globals.  */
38525a18407fSRichard Henderson                 call_flags = (TCG_CALL_NO_READ_GLOBALS |
38535a18407fSRichard Henderson                               TCG_CALL_NO_WRITE_GLOBALS);
38545a18407fSRichard Henderson             }
38555a18407fSRichard Henderson         }
38565a18407fSRichard Henderson 
38575a18407fSRichard Henderson         /* Make sure that input arguments are available.  */
38585a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
3859b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
3860b83eabeaSRichard Henderson             dir_ts = arg_ts->state_ptr;
3861b83eabeaSRichard Henderson             if (dir_ts && arg_ts->state == TS_DEAD) {
3862b83eabeaSRichard Henderson                 TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32
38635a18407fSRichard Henderson                                   ? INDEX_op_ld_i32
38645a18407fSRichard Henderson                                   : INDEX_op_ld_i64);
3865d4478943SPhilippe Mathieu-Daudé                 TCGOp *lop = tcg_op_insert_before(s, op, lopc, 3);
38665a18407fSRichard Henderson 
3867b83eabeaSRichard Henderson                 lop->args[0] = temp_arg(dir_ts);
3868b83eabeaSRichard Henderson                 lop->args[1] = temp_arg(arg_ts->mem_base);
3869b83eabeaSRichard Henderson                 lop->args[2] = arg_ts->mem_offset;
38705a18407fSRichard Henderson 
38715a18407fSRichard Henderson                 /* Loaded, but synced with memory.  */
3872b83eabeaSRichard Henderson                 arg_ts->state = TS_MEM;
38735a18407fSRichard Henderson             }
38745a18407fSRichard Henderson         }
38755a18407fSRichard Henderson 
38765a18407fSRichard Henderson         /* Perform input replacement, and mark inputs that became dead.
38775a18407fSRichard Henderson            No action is required except keeping temp_state up to date
38785a18407fSRichard Henderson            so that we reload when needed.  */
38795a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
3880b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
3881b83eabeaSRichard Henderson             dir_ts = arg_ts->state_ptr;
3882b83eabeaSRichard Henderson             if (dir_ts) {
3883b83eabeaSRichard Henderson                 op->args[i] = temp_arg(dir_ts);
38845a18407fSRichard Henderson                 changes = true;
38855a18407fSRichard Henderson                 if (IS_DEAD_ARG(i)) {
3886b83eabeaSRichard Henderson                     arg_ts->state = TS_DEAD;
38875a18407fSRichard Henderson                 }
38885a18407fSRichard Henderson             }
38895a18407fSRichard Henderson         }
38905a18407fSRichard Henderson 
38915a18407fSRichard Henderson         /* Liveness analysis should ensure that the following are
38925a18407fSRichard Henderson            all correct, for call sites and basic block end points.  */
38935a18407fSRichard Henderson         if (call_flags & TCG_CALL_NO_READ_GLOBALS) {
38945a18407fSRichard Henderson             /* Nothing to do */
38955a18407fSRichard Henderson         } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) {
38965a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
38975a18407fSRichard Henderson                 /* Liveness should see that globals are synced back,
38985a18407fSRichard Henderson                    that is, either TS_DEAD or TS_MEM.  */
3899b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
3900b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
3901b83eabeaSRichard Henderson                                  || arg_ts->state != 0);
39025a18407fSRichard Henderson             }
39035a18407fSRichard Henderson         } else {
39045a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
39055a18407fSRichard Henderson                 /* Liveness should see that globals are saved back,
39065a18407fSRichard Henderson                    that is, TS_DEAD, waiting to be reloaded.  */
3907b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
3908b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
3909b83eabeaSRichard Henderson                                  || arg_ts->state == TS_DEAD);
39105a18407fSRichard Henderson             }
39115a18407fSRichard Henderson         }
39125a18407fSRichard Henderson 
39135a18407fSRichard Henderson         /* Outputs become available.  */
391461f15c48SRichard Henderson         if (opc == INDEX_op_mov_i32 || opc == INDEX_op_mov_i64) {
391561f15c48SRichard Henderson             arg_ts = arg_temp(op->args[0]);
391661f15c48SRichard Henderson             dir_ts = arg_ts->state_ptr;
391761f15c48SRichard Henderson             if (dir_ts) {
391861f15c48SRichard Henderson                 op->args[0] = temp_arg(dir_ts);
391961f15c48SRichard Henderson                 changes = true;
392061f15c48SRichard Henderson 
392161f15c48SRichard Henderson                 /* The output is now live and modified.  */
392261f15c48SRichard Henderson                 arg_ts->state = 0;
392361f15c48SRichard Henderson 
392461f15c48SRichard Henderson                 if (NEED_SYNC_ARG(0)) {
392561f15c48SRichard Henderson                     TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
392661f15c48SRichard Henderson                                       ? INDEX_op_st_i32
392761f15c48SRichard Henderson                                       : INDEX_op_st_i64);
3928d4478943SPhilippe Mathieu-Daudé                     TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3);
392961f15c48SRichard Henderson                     TCGTemp *out_ts = dir_ts;
393061f15c48SRichard Henderson 
393161f15c48SRichard Henderson                     if (IS_DEAD_ARG(0)) {
393261f15c48SRichard Henderson                         out_ts = arg_temp(op->args[1]);
393361f15c48SRichard Henderson                         arg_ts->state = TS_DEAD;
393461f15c48SRichard Henderson                         tcg_op_remove(s, op);
393561f15c48SRichard Henderson                     } else {
393661f15c48SRichard Henderson                         arg_ts->state = TS_MEM;
393761f15c48SRichard Henderson                     }
393861f15c48SRichard Henderson 
393961f15c48SRichard Henderson                     sop->args[0] = temp_arg(out_ts);
394061f15c48SRichard Henderson                     sop->args[1] = temp_arg(arg_ts->mem_base);
394161f15c48SRichard Henderson                     sop->args[2] = arg_ts->mem_offset;
394261f15c48SRichard Henderson                 } else {
394361f15c48SRichard Henderson                     tcg_debug_assert(!IS_DEAD_ARG(0));
394461f15c48SRichard Henderson                 }
394561f15c48SRichard Henderson             }
394661f15c48SRichard Henderson         } else {
39475a18407fSRichard Henderson             for (i = 0; i < nb_oargs; i++) {
3948b83eabeaSRichard Henderson                 arg_ts = arg_temp(op->args[i]);
3949b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
3950b83eabeaSRichard Henderson                 if (!dir_ts) {
39515a18407fSRichard Henderson                     continue;
39525a18407fSRichard Henderson                 }
3953b83eabeaSRichard Henderson                 op->args[i] = temp_arg(dir_ts);
39545a18407fSRichard Henderson                 changes = true;
39555a18407fSRichard Henderson 
39565a18407fSRichard Henderson                 /* The output is now live and modified.  */
3957b83eabeaSRichard Henderson                 arg_ts->state = 0;
39585a18407fSRichard Henderson 
39595a18407fSRichard Henderson                 /* Sync outputs upon their last write.  */
39605a18407fSRichard Henderson                 if (NEED_SYNC_ARG(i)) {
3961b83eabeaSRichard Henderson                     TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
39625a18407fSRichard Henderson                                       ? INDEX_op_st_i32
39635a18407fSRichard Henderson                                       : INDEX_op_st_i64);
3964d4478943SPhilippe Mathieu-Daudé                     TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3);
39655a18407fSRichard Henderson 
3966b83eabeaSRichard Henderson                     sop->args[0] = temp_arg(dir_ts);
3967b83eabeaSRichard Henderson                     sop->args[1] = temp_arg(arg_ts->mem_base);
3968b83eabeaSRichard Henderson                     sop->args[2] = arg_ts->mem_offset;
39695a18407fSRichard Henderson 
3970b83eabeaSRichard Henderson                     arg_ts->state = TS_MEM;
39715a18407fSRichard Henderson                 }
39725a18407fSRichard Henderson                 /* Drop outputs that are dead.  */
39735a18407fSRichard Henderson                 if (IS_DEAD_ARG(i)) {
3974b83eabeaSRichard Henderson                     arg_ts->state = TS_DEAD;
39755a18407fSRichard Henderson                 }
39765a18407fSRichard Henderson             }
39775a18407fSRichard Henderson         }
397861f15c48SRichard Henderson     }
39795a18407fSRichard Henderson 
39805a18407fSRichard Henderson     return changes;
39815a18407fSRichard Henderson }
39825a18407fSRichard Henderson 
39832272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts)
3984c896fe29Sbellard {
398531c96417SRichard Henderson     intptr_t off;
3986273eb50cSRichard Henderson     int size, align;
3987c1c09194SRichard Henderson 
3988273eb50cSRichard Henderson     /* When allocating an object, look at the full type. */
3989273eb50cSRichard Henderson     size = tcg_type_size(ts->base_type);
3990273eb50cSRichard Henderson     switch (ts->base_type) {
3991c1c09194SRichard Henderson     case TCG_TYPE_I32:
399231c96417SRichard Henderson         align = 4;
3993c1c09194SRichard Henderson         break;
3994c1c09194SRichard Henderson     case TCG_TYPE_I64:
3995c1c09194SRichard Henderson     case TCG_TYPE_V64:
399631c96417SRichard Henderson         align = 8;
3997c1c09194SRichard Henderson         break;
399843eef72fSRichard Henderson     case TCG_TYPE_I128:
3999c1c09194SRichard Henderson     case TCG_TYPE_V128:
4000c1c09194SRichard Henderson     case TCG_TYPE_V256:
400143eef72fSRichard Henderson         /*
400243eef72fSRichard Henderson          * Note that we do not require aligned storage for V256,
400343eef72fSRichard Henderson          * and that we provide alignment for I128 to match V128,
400443eef72fSRichard Henderson          * even if that's above what the host ABI requires.
400543eef72fSRichard Henderson          */
400631c96417SRichard Henderson         align = 16;
4007c1c09194SRichard Henderson         break;
4008c1c09194SRichard Henderson     default:
4009c1c09194SRichard Henderson         g_assert_not_reached();
4010b591dc59SBlue Swirl     }
4011c1c09194SRichard Henderson 
4012b9537d59SRichard Henderson     /*
4013b9537d59SRichard Henderson      * Assume the stack is sufficiently aligned.
4014b9537d59SRichard Henderson      * This affects e.g. ARM NEON, where we have 8 byte stack alignment
4015b9537d59SRichard Henderson      * and do not require 16 byte vector alignment.  This seems slightly
4016b9537d59SRichard Henderson      * easier than fully parameterizing the above switch statement.
4017b9537d59SRichard Henderson      */
4018b9537d59SRichard Henderson     align = MIN(TCG_TARGET_STACK_ALIGN, align);
4019c1c09194SRichard Henderson     off = ROUND_UP(s->current_frame_offset, align);
4020732d5897SRichard Henderson 
4021732d5897SRichard Henderson     /* If we've exhausted the stack frame, restart with a smaller TB. */
4022732d5897SRichard Henderson     if (off + size > s->frame_end) {
4023732d5897SRichard Henderson         tcg_raise_tb_overflow(s);
4024732d5897SRichard Henderson     }
4025c1c09194SRichard Henderson     s->current_frame_offset = off + size;
40269defd1bdSRichard Henderson #if defined(__sparc__)
4027273eb50cSRichard Henderson     off += TCG_TARGET_STACK_BIAS;
40289defd1bdSRichard Henderson #endif
4029273eb50cSRichard Henderson 
4030273eb50cSRichard Henderson     /* If the object was subdivided, assign memory to all the parts. */
4031273eb50cSRichard Henderson     if (ts->base_type != ts->type) {
4032273eb50cSRichard Henderson         int part_size = tcg_type_size(ts->type);
4033273eb50cSRichard Henderson         int part_count = size / part_size;
4034273eb50cSRichard Henderson 
4035273eb50cSRichard Henderson         /*
4036273eb50cSRichard Henderson          * Each part is allocated sequentially in tcg_temp_new_internal.
4037273eb50cSRichard Henderson          * Jump back to the first part by subtracting the current index.
4038273eb50cSRichard Henderson          */
4039273eb50cSRichard Henderson         ts -= ts->temp_subindex;
4040273eb50cSRichard Henderson         for (int i = 0; i < part_count; ++i) {
4041273eb50cSRichard Henderson             ts[i].mem_offset = off + i * part_size;
4042273eb50cSRichard Henderson             ts[i].mem_base = s->frame_temp;
4043273eb50cSRichard Henderson             ts[i].mem_allocated = 1;
4044273eb50cSRichard Henderson         }
4045273eb50cSRichard Henderson     } else {
4046273eb50cSRichard Henderson         ts->mem_offset = off;
4047b3a62939SRichard Henderson         ts->mem_base = s->frame_temp;
4048c896fe29Sbellard         ts->mem_allocated = 1;
4049c896fe29Sbellard     }
4050273eb50cSRichard Henderson }
4051c896fe29Sbellard 
4052098859f1SRichard Henderson /* Assign @reg to @ts, and update reg_to_temp[]. */
4053098859f1SRichard Henderson static void set_temp_val_reg(TCGContext *s, TCGTemp *ts, TCGReg reg)
4054098859f1SRichard Henderson {
4055098859f1SRichard Henderson     if (ts->val_type == TEMP_VAL_REG) {
4056098859f1SRichard Henderson         TCGReg old = ts->reg;
4057098859f1SRichard Henderson         tcg_debug_assert(s->reg_to_temp[old] == ts);
4058098859f1SRichard Henderson         if (old == reg) {
4059098859f1SRichard Henderson             return;
4060098859f1SRichard Henderson         }
4061098859f1SRichard Henderson         s->reg_to_temp[old] = NULL;
4062098859f1SRichard Henderson     }
4063098859f1SRichard Henderson     tcg_debug_assert(s->reg_to_temp[reg] == NULL);
4064098859f1SRichard Henderson     s->reg_to_temp[reg] = ts;
4065098859f1SRichard Henderson     ts->val_type = TEMP_VAL_REG;
4066098859f1SRichard Henderson     ts->reg = reg;
4067098859f1SRichard Henderson }
4068098859f1SRichard Henderson 
4069098859f1SRichard Henderson /* Assign a non-register value type to @ts, and update reg_to_temp[]. */
4070098859f1SRichard Henderson static void set_temp_val_nonreg(TCGContext *s, TCGTemp *ts, TCGTempVal type)
4071098859f1SRichard Henderson {
4072098859f1SRichard Henderson     tcg_debug_assert(type != TEMP_VAL_REG);
4073098859f1SRichard Henderson     if (ts->val_type == TEMP_VAL_REG) {
4074098859f1SRichard Henderson         TCGReg reg = ts->reg;
4075098859f1SRichard Henderson         tcg_debug_assert(s->reg_to_temp[reg] == ts);
4076098859f1SRichard Henderson         s->reg_to_temp[reg] = NULL;
4077098859f1SRichard Henderson     }
4078098859f1SRichard Henderson     ts->val_type = type;
4079098859f1SRichard Henderson }
4080098859f1SRichard Henderson 
4081b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet);
4082b3915dbbSRichard Henderson 
408359d7c14eSRichard Henderson /* Mark a temporary as free or dead.  If 'free_or_dead' is negative,
408459d7c14eSRichard Henderson    mark it free; otherwise mark it dead.  */
408559d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead)
4086c896fe29Sbellard {
4087c0522136SRichard Henderson     TCGTempVal new_type;
4088c0522136SRichard Henderson 
4089c0522136SRichard Henderson     switch (ts->kind) {
4090c0522136SRichard Henderson     case TEMP_FIXED:
409159d7c14eSRichard Henderson         return;
4092c0522136SRichard Henderson     case TEMP_GLOBAL:
4093f57c6915SRichard Henderson     case TEMP_TB:
4094c0522136SRichard Henderson         new_type = TEMP_VAL_MEM;
4095c0522136SRichard Henderson         break;
4096c7482438SRichard Henderson     case TEMP_EBB:
4097c0522136SRichard Henderson         new_type = free_or_dead < 0 ? TEMP_VAL_MEM : TEMP_VAL_DEAD;
4098c0522136SRichard Henderson         break;
4099c0522136SRichard Henderson     case TEMP_CONST:
4100c0522136SRichard Henderson         new_type = TEMP_VAL_CONST;
4101c0522136SRichard Henderson         break;
4102c0522136SRichard Henderson     default:
4103c0522136SRichard Henderson         g_assert_not_reached();
410459d7c14eSRichard Henderson     }
4105098859f1SRichard Henderson     set_temp_val_nonreg(s, ts, new_type);
410659d7c14eSRichard Henderson }
4107c896fe29Sbellard 
410859d7c14eSRichard Henderson /* Mark a temporary as dead.  */
410959d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts)
411059d7c14eSRichard Henderson {
411159d7c14eSRichard Henderson     temp_free_or_dead(s, ts, 1);
411259d7c14eSRichard Henderson }
411359d7c14eSRichard Henderson 
411459d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary
411559d7c14eSRichard Henderson    registers needs to be allocated to store a constant.  If 'free_or_dead'
411659d7c14eSRichard Henderson    is non-zero, subsequently release the temporary; if it is positive, the
411759d7c14eSRichard Henderson    temp is dead; if it is negative, the temp is free.  */
411898b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs,
411998b4e186SRichard Henderson                       TCGRegSet preferred_regs, int free_or_dead)
412059d7c14eSRichard Henderson {
4121c0522136SRichard Henderson     if (!temp_readonly(ts) && !ts->mem_coherent) {
41227f6ceedfSAurelien Jarno         if (!ts->mem_allocated) {
41232272e4a7SRichard Henderson             temp_allocate_frame(s, ts);
412459d7c14eSRichard Henderson         }
412559d7c14eSRichard Henderson         switch (ts->val_type) {
412659d7c14eSRichard Henderson         case TEMP_VAL_CONST:
412759d7c14eSRichard Henderson             /* If we're going to free the temp immediately, then we won't
412859d7c14eSRichard Henderson                require it later in a register, so attempt to store the
412959d7c14eSRichard Henderson                constant to memory directly.  */
413059d7c14eSRichard Henderson             if (free_or_dead
413159d7c14eSRichard Henderson                 && tcg_out_sti(s, ts->type, ts->val,
413259d7c14eSRichard Henderson                                ts->mem_base->reg, ts->mem_offset)) {
413359d7c14eSRichard Henderson                 break;
413459d7c14eSRichard Henderson             }
413559d7c14eSRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
413698b4e186SRichard Henderson                       allocated_regs, preferred_regs);
413759d7c14eSRichard Henderson             /* fallthrough */
413859d7c14eSRichard Henderson 
413959d7c14eSRichard Henderson         case TEMP_VAL_REG:
414059d7c14eSRichard Henderson             tcg_out_st(s, ts->type, ts->reg,
414159d7c14eSRichard Henderson                        ts->mem_base->reg, ts->mem_offset);
414259d7c14eSRichard Henderson             break;
414359d7c14eSRichard Henderson 
414459d7c14eSRichard Henderson         case TEMP_VAL_MEM:
414559d7c14eSRichard Henderson             break;
414659d7c14eSRichard Henderson 
414759d7c14eSRichard Henderson         case TEMP_VAL_DEAD:
414859d7c14eSRichard Henderson         default:
4149732e89f4SRichard Henderson             g_assert_not_reached();
4150c896fe29Sbellard         }
41517f6ceedfSAurelien Jarno         ts->mem_coherent = 1;
41527f6ceedfSAurelien Jarno     }
415359d7c14eSRichard Henderson     if (free_or_dead) {
415459d7c14eSRichard Henderson         temp_free_or_dead(s, ts, free_or_dead);
415559d7c14eSRichard Henderson     }
415659d7c14eSRichard Henderson }
41577f6ceedfSAurelien Jarno 
41587f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */
4159b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs)
41607f6ceedfSAurelien Jarno {
4161f8b2f202SRichard Henderson     TCGTemp *ts = s->reg_to_temp[reg];
4162f8b2f202SRichard Henderson     if (ts != NULL) {
416398b4e186SRichard Henderson         temp_sync(s, ts, allocated_regs, 0, -1);
4164c896fe29Sbellard     }
4165c896fe29Sbellard }
4166c896fe29Sbellard 
4167b016486eSRichard Henderson /**
4168b016486eSRichard Henderson  * tcg_reg_alloc:
4169b016486eSRichard Henderson  * @required_regs: Set of registers in which we must allocate.
4170b016486eSRichard Henderson  * @allocated_regs: Set of registers which must be avoided.
4171b016486eSRichard Henderson  * @preferred_regs: Set of registers we should prefer.
4172b016486eSRichard Henderson  * @rev: True if we search the registers in "indirect" order.
4173b016486eSRichard Henderson  *
4174b016486eSRichard Henderson  * The allocated register must be in @required_regs & ~@allocated_regs,
4175b016486eSRichard Henderson  * but if we can put it in @preferred_regs we may save a move later.
4176b016486eSRichard Henderson  */
4177b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs,
4178b016486eSRichard Henderson                             TCGRegSet allocated_regs,
4179b016486eSRichard Henderson                             TCGRegSet preferred_regs, bool rev)
4180c896fe29Sbellard {
4181b016486eSRichard Henderson     int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
4182b016486eSRichard Henderson     TCGRegSet reg_ct[2];
418391478cefSRichard Henderson     const int *order;
4184c896fe29Sbellard 
4185b016486eSRichard Henderson     reg_ct[1] = required_regs & ~allocated_regs;
4186b016486eSRichard Henderson     tcg_debug_assert(reg_ct[1] != 0);
4187b016486eSRichard Henderson     reg_ct[0] = reg_ct[1] & preferred_regs;
4188b016486eSRichard Henderson 
4189b016486eSRichard Henderson     /* Skip the preferred_regs option if it cannot be satisfied,
4190b016486eSRichard Henderson        or if the preference made no difference.  */
4191b016486eSRichard Henderson     f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1];
4192b016486eSRichard Henderson 
419391478cefSRichard Henderson     order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
4194c896fe29Sbellard 
4195b016486eSRichard Henderson     /* Try free registers, preferences first.  */
4196b016486eSRichard Henderson     for (j = f; j < 2; j++) {
4197b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
4198b016486eSRichard Henderson 
4199b016486eSRichard Henderson         if (tcg_regset_single(set)) {
4200b016486eSRichard Henderson             /* One register in the set.  */
4201b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
4202b016486eSRichard Henderson             if (s->reg_to_temp[reg] == NULL) {
4203c896fe29Sbellard                 return reg;
4204c896fe29Sbellard             }
4205b016486eSRichard Henderson         } else {
420691478cefSRichard Henderson             for (i = 0; i < n; i++) {
4207b016486eSRichard Henderson                 TCGReg reg = order[i];
4208b016486eSRichard Henderson                 if (s->reg_to_temp[reg] == NULL &&
4209b016486eSRichard Henderson                     tcg_regset_test_reg(set, reg)) {
4210b016486eSRichard Henderson                     return reg;
4211b016486eSRichard Henderson                 }
4212b016486eSRichard Henderson             }
4213b016486eSRichard Henderson         }
4214b016486eSRichard Henderson     }
4215b016486eSRichard Henderson 
4216b016486eSRichard Henderson     /* We must spill something.  */
4217b016486eSRichard Henderson     for (j = f; j < 2; j++) {
4218b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
4219b016486eSRichard Henderson 
4220b016486eSRichard Henderson         if (tcg_regset_single(set)) {
4221b016486eSRichard Henderson             /* One register in the set.  */
4222b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
4223b3915dbbSRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
4224c896fe29Sbellard             return reg;
4225b016486eSRichard Henderson         } else {
4226b016486eSRichard Henderson             for (i = 0; i < n; i++) {
4227b016486eSRichard Henderson                 TCGReg reg = order[i];
4228b016486eSRichard Henderson                 if (tcg_regset_test_reg(set, reg)) {
4229b016486eSRichard Henderson                     tcg_reg_free(s, reg, allocated_regs);
4230b016486eSRichard Henderson                     return reg;
4231b016486eSRichard Henderson                 }
4232b016486eSRichard Henderson             }
4233c896fe29Sbellard         }
4234c896fe29Sbellard     }
4235c896fe29Sbellard 
4236732e89f4SRichard Henderson     g_assert_not_reached();
4237c896fe29Sbellard }
4238c896fe29Sbellard 
423929f5e925SRichard Henderson static TCGReg tcg_reg_alloc_pair(TCGContext *s, TCGRegSet required_regs,
424029f5e925SRichard Henderson                                  TCGRegSet allocated_regs,
424129f5e925SRichard Henderson                                  TCGRegSet preferred_regs, bool rev)
424229f5e925SRichard Henderson {
424329f5e925SRichard Henderson     int i, j, k, fmin, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
424429f5e925SRichard Henderson     TCGRegSet reg_ct[2];
424529f5e925SRichard Henderson     const int *order;
424629f5e925SRichard Henderson 
424729f5e925SRichard Henderson     /* Ensure that if I is not in allocated_regs, I+1 is not either. */
424829f5e925SRichard Henderson     reg_ct[1] = required_regs & ~(allocated_regs | (allocated_regs >> 1));
424929f5e925SRichard Henderson     tcg_debug_assert(reg_ct[1] != 0);
425029f5e925SRichard Henderson     reg_ct[0] = reg_ct[1] & preferred_regs;
425129f5e925SRichard Henderson 
425229f5e925SRichard Henderson     order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
425329f5e925SRichard Henderson 
425429f5e925SRichard Henderson     /*
425529f5e925SRichard Henderson      * Skip the preferred_regs option if it cannot be satisfied,
425629f5e925SRichard Henderson      * or if the preference made no difference.
425729f5e925SRichard Henderson      */
425829f5e925SRichard Henderson     k = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1];
425929f5e925SRichard Henderson 
426029f5e925SRichard Henderson     /*
426129f5e925SRichard Henderson      * Minimize the number of flushes by looking for 2 free registers first,
426229f5e925SRichard Henderson      * then a single flush, then two flushes.
426329f5e925SRichard Henderson      */
426429f5e925SRichard Henderson     for (fmin = 2; fmin >= 0; fmin--) {
426529f5e925SRichard Henderson         for (j = k; j < 2; j++) {
426629f5e925SRichard Henderson             TCGRegSet set = reg_ct[j];
426729f5e925SRichard Henderson 
426829f5e925SRichard Henderson             for (i = 0; i < n; i++) {
426929f5e925SRichard Henderson                 TCGReg reg = order[i];
427029f5e925SRichard Henderson 
427129f5e925SRichard Henderson                 if (tcg_regset_test_reg(set, reg)) {
427229f5e925SRichard Henderson                     int f = !s->reg_to_temp[reg] + !s->reg_to_temp[reg + 1];
427329f5e925SRichard Henderson                     if (f >= fmin) {
427429f5e925SRichard Henderson                         tcg_reg_free(s, reg, allocated_regs);
427529f5e925SRichard Henderson                         tcg_reg_free(s, reg + 1, allocated_regs);
427629f5e925SRichard Henderson                         return reg;
427729f5e925SRichard Henderson                     }
427829f5e925SRichard Henderson                 }
427929f5e925SRichard Henderson             }
428029f5e925SRichard Henderson         }
428129f5e925SRichard Henderson     }
4282732e89f4SRichard Henderson     g_assert_not_reached();
428329f5e925SRichard Henderson }
428429f5e925SRichard Henderson 
428540ae5c62SRichard Henderson /* Make sure the temporary is in a register.  If needed, allocate the register
428640ae5c62SRichard Henderson    from DESIRED while avoiding ALLOCATED.  */
428740ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs,
4288b722452aSRichard Henderson                       TCGRegSet allocated_regs, TCGRegSet preferred_regs)
428940ae5c62SRichard Henderson {
429040ae5c62SRichard Henderson     TCGReg reg;
429140ae5c62SRichard Henderson 
429240ae5c62SRichard Henderson     switch (ts->val_type) {
429340ae5c62SRichard Henderson     case TEMP_VAL_REG:
429440ae5c62SRichard Henderson         return;
429540ae5c62SRichard Henderson     case TEMP_VAL_CONST:
4296b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
4297b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
42980a6a8bc8SRichard Henderson         if (ts->type <= TCG_TYPE_I64) {
429940ae5c62SRichard Henderson             tcg_out_movi(s, ts->type, reg, ts->val);
43000a6a8bc8SRichard Henderson         } else {
43014e186175SRichard Henderson             uint64_t val = ts->val;
43024e186175SRichard Henderson             MemOp vece = MO_64;
43034e186175SRichard Henderson 
43044e186175SRichard Henderson             /*
43054e186175SRichard Henderson              * Find the minimal vector element that matches the constant.
43064e186175SRichard Henderson              * The targets will, in general, have to do this search anyway,
43074e186175SRichard Henderson              * do this generically.
43084e186175SRichard Henderson              */
43094e186175SRichard Henderson             if (val == dup_const(MO_8, val)) {
43104e186175SRichard Henderson                 vece = MO_8;
43114e186175SRichard Henderson             } else if (val == dup_const(MO_16, val)) {
43124e186175SRichard Henderson                 vece = MO_16;
43130b4286ddSRichard Henderson             } else if (val == dup_const(MO_32, val)) {
43144e186175SRichard Henderson                 vece = MO_32;
43154e186175SRichard Henderson             }
43164e186175SRichard Henderson 
43174e186175SRichard Henderson             tcg_out_dupi_vec(s, ts->type, vece, reg, ts->val);
43180a6a8bc8SRichard Henderson         }
431940ae5c62SRichard Henderson         ts->mem_coherent = 0;
432040ae5c62SRichard Henderson         break;
432140ae5c62SRichard Henderson     case TEMP_VAL_MEM:
4322b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
4323b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
432440ae5c62SRichard Henderson         tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset);
432540ae5c62SRichard Henderson         ts->mem_coherent = 1;
432640ae5c62SRichard Henderson         break;
432740ae5c62SRichard Henderson     case TEMP_VAL_DEAD:
432840ae5c62SRichard Henderson     default:
4329732e89f4SRichard Henderson         g_assert_not_reached();
433040ae5c62SRichard Henderson     }
4331098859f1SRichard Henderson     set_temp_val_reg(s, ts, reg);
433240ae5c62SRichard Henderson }
433340ae5c62SRichard Henderson 
433459d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a
4335e8996ee0Sbellard    temporary registers needs to be allocated to store a constant.  */
433659d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs)
43371ad80729SAurelien Jarno {
43382c0366f0SAurelien Jarno     /* The liveness analysis already ensures that globals are back
4339eabb7b91SAurelien Jarno        in memory. Keep an tcg_debug_assert for safety. */
4340e01fa97dSRichard Henderson     tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || temp_readonly(ts));
43411ad80729SAurelien Jarno }
43421ad80729SAurelien Jarno 
43439814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be
4344641d5fbeSbellard    modified be the following code. 'allocated_regs' is used in case a
4345641d5fbeSbellard    temporary registers needs to be allocated to store a constant. */
4346641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
4347641d5fbeSbellard {
4348ac3b8891SRichard Henderson     int i, n;
4349641d5fbeSbellard 
4350ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
4351b13eb728SRichard Henderson         temp_save(s, &s->temps[i], allocated_regs);
4352641d5fbeSbellard     }
4353e5097dc8Sbellard }
4354e5097dc8Sbellard 
43553d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be
43563d5c5f87SAurelien Jarno    read by the following code. 'allocated_regs' is used in case a
43573d5c5f87SAurelien Jarno    temporary registers needs to be allocated to store a constant. */
43583d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs)
43593d5c5f87SAurelien Jarno {
4360ac3b8891SRichard Henderson     int i, n;
43613d5c5f87SAurelien Jarno 
4362ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
436312b9b11aSRichard Henderson         TCGTemp *ts = &s->temps[i];
436412b9b11aSRichard Henderson         tcg_debug_assert(ts->val_type != TEMP_VAL_REG
4365ee17db83SRichard Henderson                          || ts->kind == TEMP_FIXED
436612b9b11aSRichard Henderson                          || ts->mem_coherent);
43673d5c5f87SAurelien Jarno     }
43683d5c5f87SAurelien Jarno }
43693d5c5f87SAurelien Jarno 
4370e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and
4371e8996ee0Sbellard    all globals are stored at their canonical location. */
4372e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
4373e5097dc8Sbellard {
4374e5097dc8Sbellard     int i;
4375e5097dc8Sbellard 
4376c896fe29Sbellard     for (i = s->nb_globals; i < s->nb_temps; i++) {
4377b13eb728SRichard Henderson         TCGTemp *ts = &s->temps[i];
4378c0522136SRichard Henderson 
4379c0522136SRichard Henderson         switch (ts->kind) {
4380f57c6915SRichard Henderson         case TEMP_TB:
4381b13eb728SRichard Henderson             temp_save(s, ts, allocated_regs);
4382c0522136SRichard Henderson             break;
4383c7482438SRichard Henderson         case TEMP_EBB:
43842c0366f0SAurelien Jarno             /* The liveness analysis already ensures that temps are dead.
4385eabb7b91SAurelien Jarno                Keep an tcg_debug_assert for safety. */
4386eabb7b91SAurelien Jarno             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
4387c0522136SRichard Henderson             break;
4388c0522136SRichard Henderson         case TEMP_CONST:
4389c0522136SRichard Henderson             /* Similarly, we should have freed any allocated register. */
4390c0522136SRichard Henderson             tcg_debug_assert(ts->val_type == TEMP_VAL_CONST);
4391c0522136SRichard Henderson             break;
4392c0522136SRichard Henderson         default:
4393c0522136SRichard Henderson             g_assert_not_reached();
4394c896fe29Sbellard         }
4395641d5fbeSbellard     }
4396e8996ee0Sbellard 
4397e8996ee0Sbellard     save_globals(s, allocated_regs);
4398c896fe29Sbellard }
4399c896fe29Sbellard 
4400bab1671fSRichard Henderson /*
4401c7482438SRichard Henderson  * At a conditional branch, we assume all temporaries are dead unless
4402c7482438SRichard Henderson  * explicitly live-across-conditional-branch; all globals and local
4403c7482438SRichard Henderson  * temps are synced to their location.
4404b4cb76e6SRichard Henderson  */
4405b4cb76e6SRichard Henderson static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs)
4406b4cb76e6SRichard Henderson {
4407b4cb76e6SRichard Henderson     sync_globals(s, allocated_regs);
4408b4cb76e6SRichard Henderson 
4409b4cb76e6SRichard Henderson     for (int i = s->nb_globals; i < s->nb_temps; i++) {
4410b4cb76e6SRichard Henderson         TCGTemp *ts = &s->temps[i];
4411b4cb76e6SRichard Henderson         /*
4412b4cb76e6SRichard Henderson          * The liveness analysis already ensures that temps are dead.
4413b4cb76e6SRichard Henderson          * Keep tcg_debug_asserts for safety.
4414b4cb76e6SRichard Henderson          */
4415c0522136SRichard Henderson         switch (ts->kind) {
4416f57c6915SRichard Henderson         case TEMP_TB:
4417b4cb76e6SRichard Henderson             tcg_debug_assert(ts->val_type != TEMP_VAL_REG || ts->mem_coherent);
4418c0522136SRichard Henderson             break;
4419c7482438SRichard Henderson         case TEMP_EBB:
4420c0522136SRichard Henderson         case TEMP_CONST:
4421c0522136SRichard Henderson             break;
4422c0522136SRichard Henderson         default:
4423c0522136SRichard Henderson             g_assert_not_reached();
4424b4cb76e6SRichard Henderson         }
4425b4cb76e6SRichard Henderson     }
4426b4cb76e6SRichard Henderson }
4427b4cb76e6SRichard Henderson 
4428b4cb76e6SRichard Henderson /*
4429c58f4c97SRichard Henderson  * Specialized code generation for INDEX_op_mov_* with a constant.
4430bab1671fSRichard Henderson  */
44310fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots,
4432ba87719cSRichard Henderson                                   tcg_target_ulong val, TCGLifeData arg_life,
4433ba87719cSRichard Henderson                                   TCGRegSet preferred_regs)
4434e8996ee0Sbellard {
4435d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
4436e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
443759d7c14eSRichard Henderson 
443859d7c14eSRichard Henderson     /* The movi is not explicitly generated here.  */
4439098859f1SRichard Henderson     set_temp_val_nonreg(s, ots, TEMP_VAL_CONST);
4440e8996ee0Sbellard     ots->val = val;
444159d7c14eSRichard Henderson     ots->mem_coherent = 0;
4442ec7a869dSAurelien Jarno     if (NEED_SYNC_ARG(0)) {
4443ba87719cSRichard Henderson         temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0));
444459d7c14eSRichard Henderson     } else if (IS_DEAD_ARG(0)) {
4445f8bf00f1SRichard Henderson         temp_dead(s, ots);
44464c4e1ab2SAurelien Jarno     }
4447e8996ee0Sbellard }
4448e8996ee0Sbellard 
4449bab1671fSRichard Henderson /*
4450bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_mov_*.
4451bab1671fSRichard Henderson  */
4452dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op)
4453c896fe29Sbellard {
4454dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
445569e3706dSRichard Henderson     TCGRegSet allocated_regs, preferred_regs;
4456c896fe29Sbellard     TCGTemp *ts, *ots;
4457450445d5SRichard Henderson     TCGType otype, itype;
4458098859f1SRichard Henderson     TCGReg oreg, ireg;
4459c896fe29Sbellard 
4460d21369f5SRichard Henderson     allocated_regs = s->reserved_regs;
446131fd884bSRichard Henderson     preferred_regs = output_pref(op, 0);
446243439139SRichard Henderson     ots = arg_temp(op->args[0]);
446343439139SRichard Henderson     ts = arg_temp(op->args[1]);
4464450445d5SRichard Henderson 
4465d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
4466e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
4467d63e3b6eSRichard Henderson 
4468450445d5SRichard Henderson     /* Note that otype != itype for no-op truncation.  */
4469450445d5SRichard Henderson     otype = ots->type;
4470450445d5SRichard Henderson     itype = ts->type;
4471c896fe29Sbellard 
44720fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_CONST) {
44730fe4fca4SPaolo Bonzini         /* propagate constant or generate sti */
44740fe4fca4SPaolo Bonzini         tcg_target_ulong val = ts->val;
44750fe4fca4SPaolo Bonzini         if (IS_DEAD_ARG(1)) {
44760fe4fca4SPaolo Bonzini             temp_dead(s, ts);
44770fe4fca4SPaolo Bonzini         }
447869e3706dSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs);
44790fe4fca4SPaolo Bonzini         return;
44800fe4fca4SPaolo Bonzini     }
44810fe4fca4SPaolo Bonzini 
44820fe4fca4SPaolo Bonzini     /* If the source value is in memory we're going to be forced
44830fe4fca4SPaolo Bonzini        to have it in a register in order to perform the copy.  Copy
44840fe4fca4SPaolo Bonzini        the SOURCE value into its own register first, that way we
44850fe4fca4SPaolo Bonzini        don't have to reload SOURCE the next time it is used. */
44860fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_MEM) {
448769e3706dSRichard Henderson         temp_load(s, ts, tcg_target_available_regs[itype],
448869e3706dSRichard Henderson                   allocated_regs, preferred_regs);
4489c29c1d7eSAurelien Jarno     }
44900fe4fca4SPaolo Bonzini     tcg_debug_assert(ts->val_type == TEMP_VAL_REG);
4491098859f1SRichard Henderson     ireg = ts->reg;
4492098859f1SRichard Henderson 
4493d63e3b6eSRichard Henderson     if (IS_DEAD_ARG(0)) {
4494c29c1d7eSAurelien Jarno         /* mov to a non-saved dead register makes no sense (even with
4495c29c1d7eSAurelien Jarno            liveness analysis disabled). */
4496eabb7b91SAurelien Jarno         tcg_debug_assert(NEED_SYNC_ARG(0));
4497c29c1d7eSAurelien Jarno         if (!ots->mem_allocated) {
44982272e4a7SRichard Henderson             temp_allocate_frame(s, ots);
4499c29c1d7eSAurelien Jarno         }
4500098859f1SRichard Henderson         tcg_out_st(s, otype, ireg, ots->mem_base->reg, ots->mem_offset);
4501c29c1d7eSAurelien Jarno         if (IS_DEAD_ARG(1)) {
4502f8bf00f1SRichard Henderson             temp_dead(s, ts);
4503c29c1d7eSAurelien Jarno         }
4504f8bf00f1SRichard Henderson         temp_dead(s, ots);
4505098859f1SRichard Henderson         return;
4506098859f1SRichard Henderson     }
4507098859f1SRichard Henderson 
4508ee17db83SRichard Henderson     if (IS_DEAD_ARG(1) && ts->kind != TEMP_FIXED) {
4509098859f1SRichard Henderson         /*
4510098859f1SRichard Henderson          * The mov can be suppressed.  Kill input first, so that it
4511098859f1SRichard Henderson          * is unlinked from reg_to_temp, then set the output to the
4512098859f1SRichard Henderson          * reg that we saved from the input.
4513098859f1SRichard Henderson          */
4514f8bf00f1SRichard Henderson         temp_dead(s, ts);
4515098859f1SRichard Henderson         oreg = ireg;
4516c29c1d7eSAurelien Jarno     } else {
4517098859f1SRichard Henderson         if (ots->val_type == TEMP_VAL_REG) {
4518098859f1SRichard Henderson             oreg = ots->reg;
4519098859f1SRichard Henderson         } else {
4520098859f1SRichard Henderson             /* Make sure to not spill the input register during allocation. */
4521098859f1SRichard Henderson             oreg = tcg_reg_alloc(s, tcg_target_available_regs[otype],
4522098859f1SRichard Henderson                                  allocated_regs | ((TCGRegSet)1 << ireg),
4523098859f1SRichard Henderson                                  preferred_regs, ots->indirect_base);
4524c29c1d7eSAurelien Jarno         }
4525098859f1SRichard Henderson         if (!tcg_out_mov(s, otype, oreg, ireg)) {
4526240c08d0SRichard Henderson             /*
4527240c08d0SRichard Henderson              * Cross register class move not supported.
4528240c08d0SRichard Henderson              * Store the source register into the destination slot
4529240c08d0SRichard Henderson              * and leave the destination temp as TEMP_VAL_MEM.
4530240c08d0SRichard Henderson              */
4531e01fa97dSRichard Henderson             assert(!temp_readonly(ots));
4532240c08d0SRichard Henderson             if (!ts->mem_allocated) {
4533240c08d0SRichard Henderson                 temp_allocate_frame(s, ots);
4534240c08d0SRichard Henderson             }
4535098859f1SRichard Henderson             tcg_out_st(s, ts->type, ireg, ots->mem_base->reg, ots->mem_offset);
4536098859f1SRichard Henderson             set_temp_val_nonreg(s, ts, TEMP_VAL_MEM);
4537240c08d0SRichard Henderson             ots->mem_coherent = 1;
4538240c08d0SRichard Henderson             return;
453978113e83SRichard Henderson         }
4540c29c1d7eSAurelien Jarno     }
4541098859f1SRichard Henderson     set_temp_val_reg(s, ots, oreg);
4542c896fe29Sbellard     ots->mem_coherent = 0;
4543098859f1SRichard Henderson 
4544ec7a869dSAurelien Jarno     if (NEED_SYNC_ARG(0)) {
454598b4e186SRichard Henderson         temp_sync(s, ots, allocated_regs, 0, 0);
4546c29c1d7eSAurelien Jarno     }
4547ec7a869dSAurelien Jarno }
4548c896fe29Sbellard 
4549bab1671fSRichard Henderson /*
4550bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_dup_vec.
4551bab1671fSRichard Henderson  */
4552bab1671fSRichard Henderson static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op)
4553bab1671fSRichard Henderson {
4554bab1671fSRichard Henderson     const TCGLifeData arg_life = op->life;
4555bab1671fSRichard Henderson     TCGRegSet dup_out_regs, dup_in_regs;
4556bab1671fSRichard Henderson     TCGTemp *its, *ots;
4557bab1671fSRichard Henderson     TCGType itype, vtype;
4558bab1671fSRichard Henderson     unsigned vece;
455931c96417SRichard Henderson     int lowpart_ofs;
4560bab1671fSRichard Henderson     bool ok;
4561bab1671fSRichard Henderson 
4562bab1671fSRichard Henderson     ots = arg_temp(op->args[0]);
4563bab1671fSRichard Henderson     its = arg_temp(op->args[1]);
4564bab1671fSRichard Henderson 
4565bab1671fSRichard Henderson     /* ENV should not be modified.  */
4566e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
4567bab1671fSRichard Henderson 
4568bab1671fSRichard Henderson     itype = its->type;
4569bab1671fSRichard Henderson     vece = TCGOP_VECE(op);
4570bab1671fSRichard Henderson     vtype = TCGOP_VECL(op) + TCG_TYPE_V64;
4571bab1671fSRichard Henderson 
4572bab1671fSRichard Henderson     if (its->val_type == TEMP_VAL_CONST) {
4573bab1671fSRichard Henderson         /* Propagate constant via movi -> dupi.  */
4574bab1671fSRichard Henderson         tcg_target_ulong val = its->val;
4575bab1671fSRichard Henderson         if (IS_DEAD_ARG(1)) {
4576bab1671fSRichard Henderson             temp_dead(s, its);
4577bab1671fSRichard Henderson         }
457831fd884bSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, output_pref(op, 0));
4579bab1671fSRichard Henderson         return;
4580bab1671fSRichard Henderson     }
4581bab1671fSRichard Henderson 
45829be0d080SRichard Henderson     dup_out_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs;
45839be0d080SRichard Henderson     dup_in_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[1].regs;
4584bab1671fSRichard Henderson 
4585bab1671fSRichard Henderson     /* Allocate the output register now.  */
4586bab1671fSRichard Henderson     if (ots->val_type != TEMP_VAL_REG) {
4587bab1671fSRichard Henderson         TCGRegSet allocated_regs = s->reserved_regs;
4588098859f1SRichard Henderson         TCGReg oreg;
4589bab1671fSRichard Henderson 
4590bab1671fSRichard Henderson         if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) {
4591bab1671fSRichard Henderson             /* Make sure to not spill the input register. */
4592bab1671fSRichard Henderson             tcg_regset_set_reg(allocated_regs, its->reg);
4593bab1671fSRichard Henderson         }
4594098859f1SRichard Henderson         oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
459531fd884bSRichard Henderson                              output_pref(op, 0), ots->indirect_base);
4596098859f1SRichard Henderson         set_temp_val_reg(s, ots, oreg);
4597bab1671fSRichard Henderson     }
4598bab1671fSRichard Henderson 
4599bab1671fSRichard Henderson     switch (its->val_type) {
4600bab1671fSRichard Henderson     case TEMP_VAL_REG:
4601bab1671fSRichard Henderson         /*
4602bab1671fSRichard Henderson          * The dup constriaints must be broad, covering all possible VECE.
4603bab1671fSRichard Henderson          * However, tcg_op_dup_vec() gets to see the VECE and we allow it
4604bab1671fSRichard Henderson          * to fail, indicating that extra moves are required for that case.
4605bab1671fSRichard Henderson          */
4606bab1671fSRichard Henderson         if (tcg_regset_test_reg(dup_in_regs, its->reg)) {
4607bab1671fSRichard Henderson             if (tcg_out_dup_vec(s, vtype, vece, ots->reg, its->reg)) {
4608bab1671fSRichard Henderson                 goto done;
4609bab1671fSRichard Henderson             }
4610bab1671fSRichard Henderson             /* Try again from memory or a vector input register.  */
4611bab1671fSRichard Henderson         }
4612bab1671fSRichard Henderson         if (!its->mem_coherent) {
4613bab1671fSRichard Henderson             /*
4614bab1671fSRichard Henderson              * The input register is not synced, and so an extra store
4615bab1671fSRichard Henderson              * would be required to use memory.  Attempt an integer-vector
4616bab1671fSRichard Henderson              * register move first.  We do not have a TCGRegSet for this.
4617bab1671fSRichard Henderson              */
4618bab1671fSRichard Henderson             if (tcg_out_mov(s, itype, ots->reg, its->reg)) {
4619bab1671fSRichard Henderson                 break;
4620bab1671fSRichard Henderson             }
4621bab1671fSRichard Henderson             /* Sync the temp back to its slot and load from there.  */
4622bab1671fSRichard Henderson             temp_sync(s, its, s->reserved_regs, 0, 0);
4623bab1671fSRichard Henderson         }
4624bab1671fSRichard Henderson         /* fall through */
4625bab1671fSRichard Henderson 
4626bab1671fSRichard Henderson     case TEMP_VAL_MEM:
462731c96417SRichard Henderson         lowpart_ofs = 0;
462831c96417SRichard Henderson         if (HOST_BIG_ENDIAN) {
462931c96417SRichard Henderson             lowpart_ofs = tcg_type_size(itype) - (1 << vece);
463031c96417SRichard Henderson         }
4631d6ecb4a9SRichard Henderson         if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg,
463231c96417SRichard Henderson                              its->mem_offset + lowpart_ofs)) {
4633d6ecb4a9SRichard Henderson             goto done;
4634d6ecb4a9SRichard Henderson         }
4635098859f1SRichard Henderson         /* Load the input into the destination vector register. */
4636bab1671fSRichard Henderson         tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset);
4637bab1671fSRichard Henderson         break;
4638bab1671fSRichard Henderson 
4639bab1671fSRichard Henderson     default:
4640bab1671fSRichard Henderson         g_assert_not_reached();
4641bab1671fSRichard Henderson     }
4642bab1671fSRichard Henderson 
4643bab1671fSRichard Henderson     /* We now have a vector input register, so dup must succeed. */
4644bab1671fSRichard Henderson     ok = tcg_out_dup_vec(s, vtype, vece, ots->reg, ots->reg);
4645bab1671fSRichard Henderson     tcg_debug_assert(ok);
4646bab1671fSRichard Henderson 
4647bab1671fSRichard Henderson  done:
464836f5539cSRichard Henderson     ots->mem_coherent = 0;
4649bab1671fSRichard Henderson     if (IS_DEAD_ARG(1)) {
4650bab1671fSRichard Henderson         temp_dead(s, its);
4651bab1671fSRichard Henderson     }
4652bab1671fSRichard Henderson     if (NEED_SYNC_ARG(0)) {
4653bab1671fSRichard Henderson         temp_sync(s, ots, s->reserved_regs, 0, 0);
4654bab1671fSRichard Henderson     }
4655bab1671fSRichard Henderson     if (IS_DEAD_ARG(0)) {
4656bab1671fSRichard Henderson         temp_dead(s, ots);
4657bab1671fSRichard Henderson     }
4658bab1671fSRichard Henderson }
4659bab1671fSRichard Henderson 
4660dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op)
4661c896fe29Sbellard {
4662dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
4663dd186292SRichard Henderson     const TCGOpDef * const def = &tcg_op_defs[op->opc];
466482790a87SRichard Henderson     TCGRegSet i_allocated_regs;
466582790a87SRichard Henderson     TCGRegSet o_allocated_regs;
4666b6638662SRichard Henderson     int i, k, nb_iargs, nb_oargs;
4667b6638662SRichard Henderson     TCGReg reg;
4668c896fe29Sbellard     TCGArg arg;
4669c896fe29Sbellard     const TCGArgConstraint *arg_ct;
4670c896fe29Sbellard     TCGTemp *ts;
4671c896fe29Sbellard     TCGArg new_args[TCG_MAX_OP_ARGS];
4672c896fe29Sbellard     int const_args[TCG_MAX_OP_ARGS];
4673c896fe29Sbellard 
4674c896fe29Sbellard     nb_oargs = def->nb_oargs;
4675c896fe29Sbellard     nb_iargs = def->nb_iargs;
4676c896fe29Sbellard 
4677c896fe29Sbellard     /* copy constants */
4678c896fe29Sbellard     memcpy(new_args + nb_oargs + nb_iargs,
4679dd186292SRichard Henderson            op->args + nb_oargs + nb_iargs,
4680c896fe29Sbellard            sizeof(TCGArg) * def->nb_cargs);
4681c896fe29Sbellard 
4682d21369f5SRichard Henderson     i_allocated_regs = s->reserved_regs;
4683d21369f5SRichard Henderson     o_allocated_regs = s->reserved_regs;
468482790a87SRichard Henderson 
4685c896fe29Sbellard     /* satisfy input constraints */
4686c896fe29Sbellard     for (k = 0; k < nb_iargs; k++) {
468729f5e925SRichard Henderson         TCGRegSet i_preferred_regs, i_required_regs;
468829f5e925SRichard Henderson         bool allocate_new_reg, copyto_new_reg;
468929f5e925SRichard Henderson         TCGTemp *ts2;
469029f5e925SRichard Henderson         int i1, i2;
4691d62816f2SRichard Henderson 
469266792f90SRichard Henderson         i = def->args_ct[nb_oargs + k].sort_index;
4693dd186292SRichard Henderson         arg = op->args[i];
4694c896fe29Sbellard         arg_ct = &def->args_ct[i];
469543439139SRichard Henderson         ts = arg_temp(arg);
469640ae5c62SRichard Henderson 
469740ae5c62SRichard Henderson         if (ts->val_type == TEMP_VAL_CONST
4698ebe92db2SJiajie Chen             && tcg_target_const_match(ts->val, ts->type, arg_ct->ct, TCGOP_VECE(op))) {
4699c896fe29Sbellard             /* constant is OK for instruction */
4700c896fe29Sbellard             const_args[i] = 1;
4701c896fe29Sbellard             new_args[i] = ts->val;
4702d62816f2SRichard Henderson             continue;
4703c896fe29Sbellard         }
470440ae5c62SRichard Henderson 
47051c1824dcSRichard Henderson         reg = ts->reg;
47061c1824dcSRichard Henderson         i_preferred_regs = 0;
470729f5e925SRichard Henderson         i_required_regs = arg_ct->regs;
47081c1824dcSRichard Henderson         allocate_new_reg = false;
470929f5e925SRichard Henderson         copyto_new_reg = false;
47101c1824dcSRichard Henderson 
471129f5e925SRichard Henderson         switch (arg_ct->pair) {
471229f5e925SRichard Henderson         case 0: /* not paired */
4713bc2b17e6SRichard Henderson             if (arg_ct->ialias) {
471431fd884bSRichard Henderson                 i_preferred_regs = output_pref(op, arg_ct->alias_index);
4715c0522136SRichard Henderson 
4716c0522136SRichard Henderson                 /*
4717c0522136SRichard Henderson                  * If the input is readonly, then it cannot also be an
4718c0522136SRichard Henderson                  * output and aliased to itself.  If the input is not
4719c0522136SRichard Henderson                  * dead after the instruction, we must allocate a new
4720c0522136SRichard Henderson                  * register and move it.
4721c0522136SRichard Henderson                  */
472222d2e535SIlya Leoshkevich                 if (temp_readonly(ts) || !IS_DEAD_ARG(i)
472322d2e535SIlya Leoshkevich                     || def->args_ct[arg_ct->alias_index].newreg) {
47241c1824dcSRichard Henderson                     allocate_new_reg = true;
47251c1824dcSRichard Henderson                 } else if (ts->val_type == TEMP_VAL_REG) {
4726c0522136SRichard Henderson                     /*
47271c1824dcSRichard Henderson                      * Check if the current register has already been
47281c1824dcSRichard Henderson                      * allocated for another input.
4729c0522136SRichard Henderson                      */
473029f5e925SRichard Henderson                     allocate_new_reg =
473129f5e925SRichard Henderson                         tcg_regset_test_reg(i_allocated_regs, reg);
47327e1df267SAurelien Jarno                 }
47337e1df267SAurelien Jarno             }
47341c1824dcSRichard Henderson             if (!allocate_new_reg) {
473529f5e925SRichard Henderson                 temp_load(s, ts, i_required_regs, i_allocated_regs,
473629f5e925SRichard Henderson                           i_preferred_regs);
4737c896fe29Sbellard                 reg = ts->reg;
473829f5e925SRichard Henderson                 allocate_new_reg = !tcg_regset_test_reg(i_required_regs, reg);
47391c1824dcSRichard Henderson             }
47401c1824dcSRichard Henderson             if (allocate_new_reg) {
4741c0522136SRichard Henderson                 /*
4742c0522136SRichard Henderson                  * Allocate a new register matching the constraint
4743c0522136SRichard Henderson                  * and move the temporary register into it.
4744c0522136SRichard Henderson                  */
4745d62816f2SRichard Henderson                 temp_load(s, ts, tcg_target_available_regs[ts->type],
4746d62816f2SRichard Henderson                           i_allocated_regs, 0);
474729f5e925SRichard Henderson                 reg = tcg_reg_alloc(s, i_required_regs, i_allocated_regs,
47481c1824dcSRichard Henderson                                     i_preferred_regs, ts->indirect_base);
474929f5e925SRichard Henderson                 copyto_new_reg = true;
475029f5e925SRichard Henderson             }
475129f5e925SRichard Henderson             break;
475229f5e925SRichard Henderson 
475329f5e925SRichard Henderson         case 1:
475429f5e925SRichard Henderson             /* First of an input pair; if i1 == i2, the second is an output. */
475529f5e925SRichard Henderson             i1 = i;
475629f5e925SRichard Henderson             i2 = arg_ct->pair_index;
475729f5e925SRichard Henderson             ts2 = i1 != i2 ? arg_temp(op->args[i2]) : NULL;
475829f5e925SRichard Henderson 
475929f5e925SRichard Henderson             /*
476029f5e925SRichard Henderson              * It is easier to default to allocating a new pair
476129f5e925SRichard Henderson              * and to identify a few cases where it's not required.
476229f5e925SRichard Henderson              */
476329f5e925SRichard Henderson             if (arg_ct->ialias) {
476431fd884bSRichard Henderson                 i_preferred_regs = output_pref(op, arg_ct->alias_index);
476529f5e925SRichard Henderson                 if (IS_DEAD_ARG(i1) &&
476629f5e925SRichard Henderson                     IS_DEAD_ARG(i2) &&
476729f5e925SRichard Henderson                     !temp_readonly(ts) &&
476829f5e925SRichard Henderson                     ts->val_type == TEMP_VAL_REG &&
476929f5e925SRichard Henderson                     ts->reg < TCG_TARGET_NB_REGS - 1 &&
477029f5e925SRichard Henderson                     tcg_regset_test_reg(i_required_regs, reg) &&
477129f5e925SRichard Henderson                     !tcg_regset_test_reg(i_allocated_regs, reg) &&
477229f5e925SRichard Henderson                     !tcg_regset_test_reg(i_allocated_regs, reg + 1) &&
477329f5e925SRichard Henderson                     (ts2
477429f5e925SRichard Henderson                      ? ts2->val_type == TEMP_VAL_REG &&
477529f5e925SRichard Henderson                        ts2->reg == reg + 1 &&
477629f5e925SRichard Henderson                        !temp_readonly(ts2)
477729f5e925SRichard Henderson                      : s->reg_to_temp[reg + 1] == NULL)) {
477829f5e925SRichard Henderson                     break;
477929f5e925SRichard Henderson                 }
478029f5e925SRichard Henderson             } else {
478129f5e925SRichard Henderson                 /* Without aliasing, the pair must also be an input. */
478229f5e925SRichard Henderson                 tcg_debug_assert(ts2);
478329f5e925SRichard Henderson                 if (ts->val_type == TEMP_VAL_REG &&
478429f5e925SRichard Henderson                     ts2->val_type == TEMP_VAL_REG &&
478529f5e925SRichard Henderson                     ts2->reg == reg + 1 &&
478629f5e925SRichard Henderson                     tcg_regset_test_reg(i_required_regs, reg)) {
478729f5e925SRichard Henderson                     break;
478829f5e925SRichard Henderson                 }
478929f5e925SRichard Henderson             }
479029f5e925SRichard Henderson             reg = tcg_reg_alloc_pair(s, i_required_regs, i_allocated_regs,
479129f5e925SRichard Henderson                                      0, ts->indirect_base);
479229f5e925SRichard Henderson             goto do_pair;
479329f5e925SRichard Henderson 
479429f5e925SRichard Henderson         case 2: /* pair second */
479529f5e925SRichard Henderson             reg = new_args[arg_ct->pair_index] + 1;
479629f5e925SRichard Henderson             goto do_pair;
479729f5e925SRichard Henderson 
479829f5e925SRichard Henderson         case 3: /* ialias with second output, no first input */
479929f5e925SRichard Henderson             tcg_debug_assert(arg_ct->ialias);
480031fd884bSRichard Henderson             i_preferred_regs = output_pref(op, arg_ct->alias_index);
480129f5e925SRichard Henderson 
480229f5e925SRichard Henderson             if (IS_DEAD_ARG(i) &&
480329f5e925SRichard Henderson                 !temp_readonly(ts) &&
480429f5e925SRichard Henderson                 ts->val_type == TEMP_VAL_REG &&
480529f5e925SRichard Henderson                 reg > 0 &&
480629f5e925SRichard Henderson                 s->reg_to_temp[reg - 1] == NULL &&
480729f5e925SRichard Henderson                 tcg_regset_test_reg(i_required_regs, reg) &&
480829f5e925SRichard Henderson                 !tcg_regset_test_reg(i_allocated_regs, reg) &&
480929f5e925SRichard Henderson                 !tcg_regset_test_reg(i_allocated_regs, reg - 1)) {
481029f5e925SRichard Henderson                 tcg_regset_set_reg(i_allocated_regs, reg - 1);
481129f5e925SRichard Henderson                 break;
481229f5e925SRichard Henderson             }
481329f5e925SRichard Henderson             reg = tcg_reg_alloc_pair(s, i_required_regs >> 1,
481429f5e925SRichard Henderson                                      i_allocated_regs, 0,
481529f5e925SRichard Henderson                                      ts->indirect_base);
481629f5e925SRichard Henderson             tcg_regset_set_reg(i_allocated_regs, reg);
481729f5e925SRichard Henderson             reg += 1;
481829f5e925SRichard Henderson             goto do_pair;
481929f5e925SRichard Henderson 
482029f5e925SRichard Henderson         do_pair:
482129f5e925SRichard Henderson             /*
482229f5e925SRichard Henderson              * If an aliased input is not dead after the instruction,
482329f5e925SRichard Henderson              * we must allocate a new register and move it.
482429f5e925SRichard Henderson              */
482529f5e925SRichard Henderson             if (arg_ct->ialias && (!IS_DEAD_ARG(i) || temp_readonly(ts))) {
482629f5e925SRichard Henderson                 TCGRegSet t_allocated_regs = i_allocated_regs;
482729f5e925SRichard Henderson 
482829f5e925SRichard Henderson                 /*
482929f5e925SRichard Henderson                  * Because of the alias, and the continued life, make sure
483029f5e925SRichard Henderson                  * that the temp is somewhere *other* than the reg pair,
483129f5e925SRichard Henderson                  * and we get a copy in reg.
483229f5e925SRichard Henderson                  */
483329f5e925SRichard Henderson                 tcg_regset_set_reg(t_allocated_regs, reg);
483429f5e925SRichard Henderson                 tcg_regset_set_reg(t_allocated_regs, reg + 1);
483529f5e925SRichard Henderson                 if (ts->val_type == TEMP_VAL_REG && ts->reg == reg) {
483629f5e925SRichard Henderson                     /* If ts was already in reg, copy it somewhere else. */
483729f5e925SRichard Henderson                     TCGReg nr;
483829f5e925SRichard Henderson                     bool ok;
483929f5e925SRichard Henderson 
484029f5e925SRichard Henderson                     tcg_debug_assert(ts->kind != TEMP_FIXED);
484129f5e925SRichard Henderson                     nr = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
484229f5e925SRichard Henderson                                        t_allocated_regs, 0, ts->indirect_base);
484329f5e925SRichard Henderson                     ok = tcg_out_mov(s, ts->type, nr, reg);
484429f5e925SRichard Henderson                     tcg_debug_assert(ok);
484529f5e925SRichard Henderson 
484629f5e925SRichard Henderson                     set_temp_val_reg(s, ts, nr);
484729f5e925SRichard Henderson                 } else {
484829f5e925SRichard Henderson                     temp_load(s, ts, tcg_target_available_regs[ts->type],
484929f5e925SRichard Henderson                               t_allocated_regs, 0);
485029f5e925SRichard Henderson                     copyto_new_reg = true;
485129f5e925SRichard Henderson                 }
485229f5e925SRichard Henderson             } else {
485329f5e925SRichard Henderson                 /* Preferably allocate to reg, otherwise copy. */
485429f5e925SRichard Henderson                 i_required_regs = (TCGRegSet)1 << reg;
485529f5e925SRichard Henderson                 temp_load(s, ts, i_required_regs, i_allocated_regs,
485629f5e925SRichard Henderson                           i_preferred_regs);
485729f5e925SRichard Henderson                 copyto_new_reg = ts->reg != reg;
485829f5e925SRichard Henderson             }
485929f5e925SRichard Henderson             break;
486029f5e925SRichard Henderson 
486129f5e925SRichard Henderson         default:
486229f5e925SRichard Henderson             g_assert_not_reached();
486329f5e925SRichard Henderson         }
486429f5e925SRichard Henderson 
486529f5e925SRichard Henderson         if (copyto_new_reg) {
486678113e83SRichard Henderson             if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
4867240c08d0SRichard Henderson                 /*
4868240c08d0SRichard Henderson                  * Cross register class move not supported.  Sync the
4869240c08d0SRichard Henderson                  * temp back to its slot and load from there.
4870240c08d0SRichard Henderson                  */
4871240c08d0SRichard Henderson                 temp_sync(s, ts, i_allocated_regs, 0, 0);
4872240c08d0SRichard Henderson                 tcg_out_ld(s, ts->type, reg,
4873240c08d0SRichard Henderson                            ts->mem_base->reg, ts->mem_offset);
487478113e83SRichard Henderson             }
4875c896fe29Sbellard         }
4876c896fe29Sbellard         new_args[i] = reg;
4877c896fe29Sbellard         const_args[i] = 0;
487882790a87SRichard Henderson         tcg_regset_set_reg(i_allocated_regs, reg);
4879c896fe29Sbellard     }
4880c896fe29Sbellard 
4881c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
4882866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
4883866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
488443439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
4885c896fe29Sbellard         }
4886c896fe29Sbellard     }
4887c896fe29Sbellard 
4888b4cb76e6SRichard Henderson     if (def->flags & TCG_OPF_COND_BRANCH) {
4889b4cb76e6SRichard Henderson         tcg_reg_alloc_cbranch(s, i_allocated_regs);
4890b4cb76e6SRichard Henderson     } else if (def->flags & TCG_OPF_BB_END) {
489182790a87SRichard Henderson         tcg_reg_alloc_bb_end(s, i_allocated_regs);
4892a52ad07eSAurelien Jarno     } else {
4893c896fe29Sbellard         if (def->flags & TCG_OPF_CALL_CLOBBER) {
4894b03cce8eSbellard             /* XXX: permit generic clobber register list ? */
4895c8074023SRichard Henderson             for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
4896c8074023SRichard Henderson                 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
489782790a87SRichard Henderson                     tcg_reg_free(s, i, i_allocated_regs);
4898c896fe29Sbellard                 }
4899c896fe29Sbellard             }
49003d5c5f87SAurelien Jarno         }
49013d5c5f87SAurelien Jarno         if (def->flags & TCG_OPF_SIDE_EFFECTS) {
49023d5c5f87SAurelien Jarno             /* sync globals if the op has side effects and might trigger
49033d5c5f87SAurelien Jarno                an exception. */
490482790a87SRichard Henderson             sync_globals(s, i_allocated_regs);
4905c896fe29Sbellard         }
4906c896fe29Sbellard 
4907c896fe29Sbellard         /* satisfy the output constraints */
4908c896fe29Sbellard         for(k = 0; k < nb_oargs; k++) {
490966792f90SRichard Henderson             i = def->args_ct[k].sort_index;
4910dd186292SRichard Henderson             arg = op->args[i];
4911c896fe29Sbellard             arg_ct = &def->args_ct[i];
491243439139SRichard Henderson             ts = arg_temp(arg);
4913d63e3b6eSRichard Henderson 
4914d63e3b6eSRichard Henderson             /* ENV should not be modified.  */
4915e01fa97dSRichard Henderson             tcg_debug_assert(!temp_readonly(ts));
4916d63e3b6eSRichard Henderson 
491729f5e925SRichard Henderson             switch (arg_ct->pair) {
491829f5e925SRichard Henderson             case 0: /* not paired */
4919bc2b17e6SRichard Henderson                 if (arg_ct->oalias && !const_args[arg_ct->alias_index]) {
49205ff9d6a4Sbellard                     reg = new_args[arg_ct->alias_index];
4921bc2b17e6SRichard Henderson                 } else if (arg_ct->newreg) {
49229be0d080SRichard Henderson                     reg = tcg_reg_alloc(s, arg_ct->regs,
492382790a87SRichard Henderson                                         i_allocated_regs | o_allocated_regs,
492431fd884bSRichard Henderson                                         output_pref(op, k), ts->indirect_base);
4925c896fe29Sbellard                 } else {
49269be0d080SRichard Henderson                     reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs,
492731fd884bSRichard Henderson                                         output_pref(op, k), ts->indirect_base);
4928c896fe29Sbellard                 }
492929f5e925SRichard Henderson                 break;
493029f5e925SRichard Henderson 
493129f5e925SRichard Henderson             case 1: /* first of pair */
493229f5e925SRichard Henderson                 tcg_debug_assert(!arg_ct->newreg);
493329f5e925SRichard Henderson                 if (arg_ct->oalias) {
493429f5e925SRichard Henderson                     reg = new_args[arg_ct->alias_index];
493529f5e925SRichard Henderson                     break;
493629f5e925SRichard Henderson                 }
493729f5e925SRichard Henderson                 reg = tcg_reg_alloc_pair(s, arg_ct->regs, o_allocated_regs,
493831fd884bSRichard Henderson                                          output_pref(op, k), ts->indirect_base);
493929f5e925SRichard Henderson                 break;
494029f5e925SRichard Henderson 
494129f5e925SRichard Henderson             case 2: /* second of pair */
494229f5e925SRichard Henderson                 tcg_debug_assert(!arg_ct->newreg);
494329f5e925SRichard Henderson                 if (arg_ct->oalias) {
494429f5e925SRichard Henderson                     reg = new_args[arg_ct->alias_index];
494529f5e925SRichard Henderson                 } else {
494629f5e925SRichard Henderson                     reg = new_args[arg_ct->pair_index] + 1;
494729f5e925SRichard Henderson                 }
494829f5e925SRichard Henderson                 break;
494929f5e925SRichard Henderson 
495029f5e925SRichard Henderson             case 3: /* first of pair, aliasing with a second input */
495129f5e925SRichard Henderson                 tcg_debug_assert(!arg_ct->newreg);
495229f5e925SRichard Henderson                 reg = new_args[arg_ct->pair_index] - 1;
495329f5e925SRichard Henderson                 break;
495429f5e925SRichard Henderson 
495529f5e925SRichard Henderson             default:
495629f5e925SRichard Henderson                 g_assert_not_reached();
495729f5e925SRichard Henderson             }
495882790a87SRichard Henderson             tcg_regset_set_reg(o_allocated_regs, reg);
4959098859f1SRichard Henderson             set_temp_val_reg(s, ts, reg);
4960c896fe29Sbellard             ts->mem_coherent = 0;
4961c896fe29Sbellard             new_args[i] = reg;
4962c896fe29Sbellard         }
4963e8996ee0Sbellard     }
4964c896fe29Sbellard 
4965c896fe29Sbellard     /* emit instruction */
4966678155b2SRichard Henderson     switch (op->opc) {
4967678155b2SRichard Henderson     case INDEX_op_ext8s_i32:
4968678155b2SRichard Henderson         tcg_out_ext8s(s, TCG_TYPE_I32, new_args[0], new_args[1]);
4969678155b2SRichard Henderson         break;
4970678155b2SRichard Henderson     case INDEX_op_ext8s_i64:
4971678155b2SRichard Henderson         tcg_out_ext8s(s, TCG_TYPE_I64, new_args[0], new_args[1]);
4972678155b2SRichard Henderson         break;
4973d0e66c89SRichard Henderson     case INDEX_op_ext8u_i32:
4974d0e66c89SRichard Henderson     case INDEX_op_ext8u_i64:
4975d0e66c89SRichard Henderson         tcg_out_ext8u(s, new_args[0], new_args[1]);
4976d0e66c89SRichard Henderson         break;
4977753e42eaSRichard Henderson     case INDEX_op_ext16s_i32:
4978753e42eaSRichard Henderson         tcg_out_ext16s(s, TCG_TYPE_I32, new_args[0], new_args[1]);
4979753e42eaSRichard Henderson         break;
4980753e42eaSRichard Henderson     case INDEX_op_ext16s_i64:
4981753e42eaSRichard Henderson         tcg_out_ext16s(s, TCG_TYPE_I64, new_args[0], new_args[1]);
4982753e42eaSRichard Henderson         break;
4983379afdffSRichard Henderson     case INDEX_op_ext16u_i32:
4984379afdffSRichard Henderson     case INDEX_op_ext16u_i64:
4985379afdffSRichard Henderson         tcg_out_ext16u(s, new_args[0], new_args[1]);
4986379afdffSRichard Henderson         break;
498752bf3398SRichard Henderson     case INDEX_op_ext32s_i64:
498852bf3398SRichard Henderson         tcg_out_ext32s(s, new_args[0], new_args[1]);
498952bf3398SRichard Henderson         break;
49909ecf5f61SRichard Henderson     case INDEX_op_ext32u_i64:
49919ecf5f61SRichard Henderson         tcg_out_ext32u(s, new_args[0], new_args[1]);
49929ecf5f61SRichard Henderson         break;
49939c6aa274SRichard Henderson     case INDEX_op_ext_i32_i64:
49949c6aa274SRichard Henderson         tcg_out_exts_i32_i64(s, new_args[0], new_args[1]);
49959c6aa274SRichard Henderson         break;
4996b9bfe000SRichard Henderson     case INDEX_op_extu_i32_i64:
4997b9bfe000SRichard Henderson         tcg_out_extu_i32_i64(s, new_args[0], new_args[1]);
4998b9bfe000SRichard Henderson         break;
4999b8b94ac6SRichard Henderson     case INDEX_op_extrl_i64_i32:
5000b8b94ac6SRichard Henderson         tcg_out_extrl_i64_i32(s, new_args[0], new_args[1]);
5001b8b94ac6SRichard Henderson         break;
5002678155b2SRichard Henderson     default:
5003d2fd745fSRichard Henderson         if (def->flags & TCG_OPF_VECTOR) {
5004d2fd745fSRichard Henderson             tcg_out_vec_op(s, op->opc, TCGOP_VECL(op), TCGOP_VECE(op),
5005d2fd745fSRichard Henderson                            new_args, const_args);
5006d2fd745fSRichard Henderson         } else {
5007dd186292SRichard Henderson             tcg_out_op(s, op->opc, new_args, const_args);
5008d2fd745fSRichard Henderson         }
5009678155b2SRichard Henderson         break;
5010678155b2SRichard Henderson     }
5011c896fe29Sbellard 
5012c896fe29Sbellard     /* move the outputs in the correct register if needed */
5013c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
501443439139SRichard Henderson         ts = arg_temp(op->args[i]);
5015d63e3b6eSRichard Henderson 
5016d63e3b6eSRichard Henderson         /* ENV should not be modified.  */
5017e01fa97dSRichard Henderson         tcg_debug_assert(!temp_readonly(ts));
5018d63e3b6eSRichard Henderson 
5019ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
502098b4e186SRichard Henderson             temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i));
502159d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
5022f8bf00f1SRichard Henderson             temp_dead(s, ts);
5023ec7a869dSAurelien Jarno         }
5024c896fe29Sbellard     }
5025c896fe29Sbellard }
5026c896fe29Sbellard 
5027efe86b21SRichard Henderson static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op)
5028efe86b21SRichard Henderson {
5029efe86b21SRichard Henderson     const TCGLifeData arg_life = op->life;
5030efe86b21SRichard Henderson     TCGTemp *ots, *itsl, *itsh;
5031efe86b21SRichard Henderson     TCGType vtype = TCGOP_VECL(op) + TCG_TYPE_V64;
5032efe86b21SRichard Henderson 
5033efe86b21SRichard Henderson     /* This opcode is only valid for 32-bit hosts, for 64-bit elements. */
5034efe86b21SRichard Henderson     tcg_debug_assert(TCG_TARGET_REG_BITS == 32);
5035efe86b21SRichard Henderson     tcg_debug_assert(TCGOP_VECE(op) == MO_64);
5036efe86b21SRichard Henderson 
5037efe86b21SRichard Henderson     ots = arg_temp(op->args[0]);
5038efe86b21SRichard Henderson     itsl = arg_temp(op->args[1]);
5039efe86b21SRichard Henderson     itsh = arg_temp(op->args[2]);
5040efe86b21SRichard Henderson 
5041efe86b21SRichard Henderson     /* ENV should not be modified.  */
5042efe86b21SRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
5043efe86b21SRichard Henderson 
5044efe86b21SRichard Henderson     /* Allocate the output register now.  */
5045efe86b21SRichard Henderson     if (ots->val_type != TEMP_VAL_REG) {
5046efe86b21SRichard Henderson         TCGRegSet allocated_regs = s->reserved_regs;
5047efe86b21SRichard Henderson         TCGRegSet dup_out_regs =
5048efe86b21SRichard Henderson             tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs;
5049098859f1SRichard Henderson         TCGReg oreg;
5050efe86b21SRichard Henderson 
5051efe86b21SRichard Henderson         /* Make sure to not spill the input registers. */
5052efe86b21SRichard Henderson         if (!IS_DEAD_ARG(1) && itsl->val_type == TEMP_VAL_REG) {
5053efe86b21SRichard Henderson             tcg_regset_set_reg(allocated_regs, itsl->reg);
5054efe86b21SRichard Henderson         }
5055efe86b21SRichard Henderson         if (!IS_DEAD_ARG(2) && itsh->val_type == TEMP_VAL_REG) {
5056efe86b21SRichard Henderson             tcg_regset_set_reg(allocated_regs, itsh->reg);
5057efe86b21SRichard Henderson         }
5058efe86b21SRichard Henderson 
5059098859f1SRichard Henderson         oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
506031fd884bSRichard Henderson                              output_pref(op, 0), ots->indirect_base);
5061098859f1SRichard Henderson         set_temp_val_reg(s, ots, oreg);
5062efe86b21SRichard Henderson     }
5063efe86b21SRichard Henderson 
5064efe86b21SRichard Henderson     /* Promote dup2 of immediates to dupi_vec. */
5065efe86b21SRichard Henderson     if (itsl->val_type == TEMP_VAL_CONST && itsh->val_type == TEMP_VAL_CONST) {
5066efe86b21SRichard Henderson         uint64_t val = deposit64(itsl->val, 32, 32, itsh->val);
5067efe86b21SRichard Henderson         MemOp vece = MO_64;
5068efe86b21SRichard Henderson 
5069efe86b21SRichard Henderson         if (val == dup_const(MO_8, val)) {
5070efe86b21SRichard Henderson             vece = MO_8;
5071efe86b21SRichard Henderson         } else if (val == dup_const(MO_16, val)) {
5072efe86b21SRichard Henderson             vece = MO_16;
5073efe86b21SRichard Henderson         } else if (val == dup_const(MO_32, val)) {
5074efe86b21SRichard Henderson             vece = MO_32;
5075efe86b21SRichard Henderson         }
5076efe86b21SRichard Henderson 
5077efe86b21SRichard Henderson         tcg_out_dupi_vec(s, vtype, vece, ots->reg, val);
5078efe86b21SRichard Henderson         goto done;
5079efe86b21SRichard Henderson     }
5080efe86b21SRichard Henderson 
5081efe86b21SRichard Henderson     /* If the two inputs form one 64-bit value, try dupm_vec. */
5082aef85402SRichard Henderson     if (itsl->temp_subindex == HOST_BIG_ENDIAN &&
5083aef85402SRichard Henderson         itsh->temp_subindex == !HOST_BIG_ENDIAN &&
5084aef85402SRichard Henderson         itsl == itsh + (HOST_BIG_ENDIAN ? 1 : -1)) {
5085aef85402SRichard Henderson         TCGTemp *its = itsl - HOST_BIG_ENDIAN;
5086aef85402SRichard Henderson 
5087aef85402SRichard Henderson         temp_sync(s, its + 0, s->reserved_regs, 0, 0);
5088aef85402SRichard Henderson         temp_sync(s, its + 1, s->reserved_regs, 0, 0);
5089aef85402SRichard Henderson 
5090efe86b21SRichard Henderson         if (tcg_out_dupm_vec(s, vtype, MO_64, ots->reg,
5091efe86b21SRichard Henderson                              its->mem_base->reg, its->mem_offset)) {
5092efe86b21SRichard Henderson             goto done;
5093efe86b21SRichard Henderson         }
5094efe86b21SRichard Henderson     }
5095efe86b21SRichard Henderson 
5096efe86b21SRichard Henderson     /* Fall back to generic expansion. */
5097efe86b21SRichard Henderson     return false;
5098efe86b21SRichard Henderson 
5099efe86b21SRichard Henderson  done:
510036f5539cSRichard Henderson     ots->mem_coherent = 0;
5101efe86b21SRichard Henderson     if (IS_DEAD_ARG(1)) {
5102efe86b21SRichard Henderson         temp_dead(s, itsl);
5103efe86b21SRichard Henderson     }
5104efe86b21SRichard Henderson     if (IS_DEAD_ARG(2)) {
5105efe86b21SRichard Henderson         temp_dead(s, itsh);
5106efe86b21SRichard Henderson     }
5107efe86b21SRichard Henderson     if (NEED_SYNC_ARG(0)) {
5108efe86b21SRichard Henderson         temp_sync(s, ots, s->reserved_regs, 0, IS_DEAD_ARG(0));
5109efe86b21SRichard Henderson     } else if (IS_DEAD_ARG(0)) {
5110efe86b21SRichard Henderson         temp_dead(s, ots);
5111efe86b21SRichard Henderson     }
5112efe86b21SRichard Henderson     return true;
5113efe86b21SRichard Henderson }
5114efe86b21SRichard Henderson 
511539004a71SRichard Henderson static void load_arg_reg(TCGContext *s, TCGReg reg, TCGTemp *ts,
511639004a71SRichard Henderson                          TCGRegSet allocated_regs)
5117c896fe29Sbellard {
5118c896fe29Sbellard     if (ts->val_type == TEMP_VAL_REG) {
5119c896fe29Sbellard         if (ts->reg != reg) {
51204250da10SRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
512178113e83SRichard Henderson             if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
5122240c08d0SRichard Henderson                 /*
5123240c08d0SRichard Henderson                  * Cross register class move not supported.  Sync the
5124240c08d0SRichard Henderson                  * temp back to its slot and load from there.
5125240c08d0SRichard Henderson                  */
5126240c08d0SRichard Henderson                 temp_sync(s, ts, allocated_regs, 0, 0);
5127240c08d0SRichard Henderson                 tcg_out_ld(s, ts->type, reg,
5128240c08d0SRichard Henderson                            ts->mem_base->reg, ts->mem_offset);
512978113e83SRichard Henderson             }
5130c896fe29Sbellard         }
5131c896fe29Sbellard     } else {
5132ccb1bb66SRichard Henderson         TCGRegSet arg_set = 0;
513340ae5c62SRichard Henderson 
51344250da10SRichard Henderson         tcg_reg_free(s, reg, allocated_regs);
513540ae5c62SRichard Henderson         tcg_regset_set_reg(arg_set, reg);
5136b722452aSRichard Henderson         temp_load(s, ts, arg_set, allocated_regs, 0);
5137c896fe29Sbellard     }
513839004a71SRichard Henderson }
513940ae5c62SRichard Henderson 
5140d78e4a4fSRichard Henderson static void load_arg_stk(TCGContext *s, unsigned arg_slot, TCGTemp *ts,
514139004a71SRichard Henderson                          TCGRegSet allocated_regs)
514239004a71SRichard Henderson {
514339004a71SRichard Henderson     /*
514439004a71SRichard Henderson      * When the destination is on the stack, load up the temp and store.
514539004a71SRichard Henderson      * If there are many call-saved registers, the temp might live to
514639004a71SRichard Henderson      * see another use; otherwise it'll be discarded.
514739004a71SRichard Henderson      */
514839004a71SRichard Henderson     temp_load(s, ts, tcg_target_available_regs[ts->type], allocated_regs, 0);
514939004a71SRichard Henderson     tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK,
5150d78e4a4fSRichard Henderson                arg_slot_stk_ofs(arg_slot));
515139004a71SRichard Henderson }
515239004a71SRichard Henderson 
515339004a71SRichard Henderson static void load_arg_normal(TCGContext *s, const TCGCallArgumentLoc *l,
515439004a71SRichard Henderson                             TCGTemp *ts, TCGRegSet *allocated_regs)
515539004a71SRichard Henderson {
5156338b61e9SRichard Henderson     if (arg_slot_reg_p(l->arg_slot)) {
515739004a71SRichard Henderson         TCGReg reg = tcg_target_call_iarg_regs[l->arg_slot];
515839004a71SRichard Henderson         load_arg_reg(s, reg, ts, *allocated_regs);
515939004a71SRichard Henderson         tcg_regset_set_reg(*allocated_regs, reg);
516039004a71SRichard Henderson     } else {
5161d78e4a4fSRichard Henderson         load_arg_stk(s, l->arg_slot, ts, *allocated_regs);
5162c896fe29Sbellard     }
516339cf05d3Sbellard }
5164c896fe29Sbellard 
5165d78e4a4fSRichard Henderson static void load_arg_ref(TCGContext *s, unsigned arg_slot, TCGReg ref_base,
5166313bdea8SRichard Henderson                          intptr_t ref_off, TCGRegSet *allocated_regs)
5167313bdea8SRichard Henderson {
5168313bdea8SRichard Henderson     TCGReg reg;
5169313bdea8SRichard Henderson 
5170d78e4a4fSRichard Henderson     if (arg_slot_reg_p(arg_slot)) {
5171313bdea8SRichard Henderson         reg = tcg_target_call_iarg_regs[arg_slot];
5172313bdea8SRichard Henderson         tcg_reg_free(s, reg, *allocated_regs);
5173313bdea8SRichard Henderson         tcg_out_addi_ptr(s, reg, ref_base, ref_off);
5174313bdea8SRichard Henderson         tcg_regset_set_reg(*allocated_regs, reg);
5175313bdea8SRichard Henderson     } else {
5176313bdea8SRichard Henderson         reg = tcg_reg_alloc(s, tcg_target_available_regs[TCG_TYPE_PTR],
5177313bdea8SRichard Henderson                             *allocated_regs, 0, false);
5178313bdea8SRichard Henderson         tcg_out_addi_ptr(s, reg, ref_base, ref_off);
5179313bdea8SRichard Henderson         tcg_out_st(s, TCG_TYPE_PTR, reg, TCG_REG_CALL_STACK,
5180d78e4a4fSRichard Henderson                    arg_slot_stk_ofs(arg_slot));
5181313bdea8SRichard Henderson     }
5182313bdea8SRichard Henderson }
5183313bdea8SRichard Henderson 
518439004a71SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op)
518539004a71SRichard Henderson {
518639004a71SRichard Henderson     const int nb_oargs = TCGOP_CALLO(op);
518739004a71SRichard Henderson     const int nb_iargs = TCGOP_CALLI(op);
518839004a71SRichard Henderson     const TCGLifeData arg_life = op->life;
518939004a71SRichard Henderson     const TCGHelperInfo *info = tcg_call_info(op);
519039004a71SRichard Henderson     TCGRegSet allocated_regs = s->reserved_regs;
519139004a71SRichard Henderson     int i;
519239004a71SRichard Henderson 
519339004a71SRichard Henderson     /*
519439004a71SRichard Henderson      * Move inputs into place in reverse order,
519539004a71SRichard Henderson      * so that we place stacked arguments first.
519639004a71SRichard Henderson      */
519739004a71SRichard Henderson     for (i = nb_iargs - 1; i >= 0; --i) {
519839004a71SRichard Henderson         const TCGCallArgumentLoc *loc = &info->in[i];
519939004a71SRichard Henderson         TCGTemp *ts = arg_temp(op->args[nb_oargs + i]);
520039004a71SRichard Henderson 
520139004a71SRichard Henderson         switch (loc->kind) {
520239004a71SRichard Henderson         case TCG_CALL_ARG_NORMAL:
520339004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_U:
520439004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_S:
520539004a71SRichard Henderson             load_arg_normal(s, loc, ts, &allocated_regs);
520639004a71SRichard Henderson             break;
5207313bdea8SRichard Henderson         case TCG_CALL_ARG_BY_REF:
5208313bdea8SRichard Henderson             load_arg_stk(s, loc->ref_slot, ts, allocated_regs);
5209313bdea8SRichard Henderson             load_arg_ref(s, loc->arg_slot, TCG_REG_CALL_STACK,
5210d78e4a4fSRichard Henderson                          arg_slot_stk_ofs(loc->ref_slot),
5211313bdea8SRichard Henderson                          &allocated_regs);
5212313bdea8SRichard Henderson             break;
5213313bdea8SRichard Henderson         case TCG_CALL_ARG_BY_REF_N:
5214313bdea8SRichard Henderson             load_arg_stk(s, loc->ref_slot, ts, allocated_regs);
5215313bdea8SRichard Henderson             break;
521639004a71SRichard Henderson         default:
521739004a71SRichard Henderson             g_assert_not_reached();
521839004a71SRichard Henderson         }
521939004a71SRichard Henderson     }
522039004a71SRichard Henderson 
522139004a71SRichard Henderson     /* Mark dead temporaries and free the associated registers.  */
5222866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
5223866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
522443439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
5225c896fe29Sbellard         }
5226c896fe29Sbellard     }
5227c896fe29Sbellard 
522839004a71SRichard Henderson     /* Clobber call registers.  */
5229c8074023SRichard Henderson     for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
5230c8074023SRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
5231b3915dbbSRichard Henderson             tcg_reg_free(s, i, allocated_regs);
5232c896fe29Sbellard         }
5233c896fe29Sbellard     }
5234c896fe29Sbellard 
523539004a71SRichard Henderson     /*
523639004a71SRichard Henderson      * Save globals if they might be written by the helper,
523739004a71SRichard Henderson      * sync them if they might be read.
523839004a71SRichard Henderson      */
523939004a71SRichard Henderson     if (info->flags & TCG_CALL_NO_READ_GLOBALS) {
524078505279SAurelien Jarno         /* Nothing to do */
524139004a71SRichard Henderson     } else if (info->flags & TCG_CALL_NO_WRITE_GLOBALS) {
524278505279SAurelien Jarno         sync_globals(s, allocated_regs);
524378505279SAurelien Jarno     } else {
5244e8996ee0Sbellard         save_globals(s, allocated_regs);
5245b9c18f56Saurel32     }
5246c896fe29Sbellard 
5247313bdea8SRichard Henderson     /*
5248313bdea8SRichard Henderson      * If the ABI passes a pointer to the returned struct as the first
5249313bdea8SRichard Henderson      * argument, load that now.  Pass a pointer to the output home slot.
5250313bdea8SRichard Henderson      */
5251313bdea8SRichard Henderson     if (info->out_kind == TCG_CALL_RET_BY_REF) {
5252313bdea8SRichard Henderson         TCGTemp *ts = arg_temp(op->args[0]);
5253313bdea8SRichard Henderson 
5254313bdea8SRichard Henderson         if (!ts->mem_allocated) {
5255313bdea8SRichard Henderson             temp_allocate_frame(s, ts);
5256313bdea8SRichard Henderson         }
5257313bdea8SRichard Henderson         load_arg_ref(s, 0, ts->mem_base->reg, ts->mem_offset, &allocated_regs);
5258313bdea8SRichard Henderson     }
5259313bdea8SRichard Henderson 
5260cee44b03SRichard Henderson     tcg_out_call(s, tcg_call_func(op), info);
5261c896fe29Sbellard 
526239004a71SRichard Henderson     /* Assign output registers and emit moves if needed.  */
526339004a71SRichard Henderson     switch (info->out_kind) {
526439004a71SRichard Henderson     case TCG_CALL_RET_NORMAL:
5265c896fe29Sbellard         for (i = 0; i < nb_oargs; i++) {
526639004a71SRichard Henderson             TCGTemp *ts = arg_temp(op->args[i]);
52675e3d0c19SRichard Henderson             TCGReg reg = tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, i);
5268d63e3b6eSRichard Henderson 
5269d63e3b6eSRichard Henderson             /* ENV should not be modified.  */
5270e01fa97dSRichard Henderson             tcg_debug_assert(!temp_readonly(ts));
5271d63e3b6eSRichard Henderson 
5272098859f1SRichard Henderson             set_temp_val_reg(s, ts, reg);
5273c896fe29Sbellard             ts->mem_coherent = 0;
527439004a71SRichard Henderson         }
527539004a71SRichard Henderson         break;
5276313bdea8SRichard Henderson 
5277c6556aa0SRichard Henderson     case TCG_CALL_RET_BY_VEC:
5278c6556aa0SRichard Henderson         {
5279c6556aa0SRichard Henderson             TCGTemp *ts = arg_temp(op->args[0]);
5280c6556aa0SRichard Henderson 
5281c6556aa0SRichard Henderson             tcg_debug_assert(ts->base_type == TCG_TYPE_I128);
5282c6556aa0SRichard Henderson             tcg_debug_assert(ts->temp_subindex == 0);
5283c6556aa0SRichard Henderson             if (!ts->mem_allocated) {
5284c6556aa0SRichard Henderson                 temp_allocate_frame(s, ts);
5285c6556aa0SRichard Henderson             }
5286c6556aa0SRichard Henderson             tcg_out_st(s, TCG_TYPE_V128,
5287c6556aa0SRichard Henderson                        tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0),
5288c6556aa0SRichard Henderson                        ts->mem_base->reg, ts->mem_offset);
5289c6556aa0SRichard Henderson         }
5290c6556aa0SRichard Henderson         /* fall through to mark all parts in memory */
5291c6556aa0SRichard Henderson 
5292313bdea8SRichard Henderson     case TCG_CALL_RET_BY_REF:
5293313bdea8SRichard Henderson         /* The callee has performed a write through the reference. */
5294313bdea8SRichard Henderson         for (i = 0; i < nb_oargs; i++) {
5295313bdea8SRichard Henderson             TCGTemp *ts = arg_temp(op->args[i]);
5296313bdea8SRichard Henderson             ts->val_type = TEMP_VAL_MEM;
5297313bdea8SRichard Henderson         }
5298313bdea8SRichard Henderson         break;
5299313bdea8SRichard Henderson 
530039004a71SRichard Henderson     default:
530139004a71SRichard Henderson         g_assert_not_reached();
530239004a71SRichard Henderson     }
530339004a71SRichard Henderson 
530439004a71SRichard Henderson     /* Flush or discard output registers as needed. */
530539004a71SRichard Henderson     for (i = 0; i < nb_oargs; i++) {
530639004a71SRichard Henderson         TCGTemp *ts = arg_temp(op->args[i]);
5307ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
530839004a71SRichard Henderson             temp_sync(s, ts, s->reserved_regs, 0, IS_DEAD_ARG(i));
530959d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
5310f8bf00f1SRichard Henderson             temp_dead(s, ts);
5311c896fe29Sbellard         }
5312c896fe29Sbellard     }
53138c11ad25SAurelien Jarno }
5314c896fe29Sbellard 
5315e63b8a29SRichard Henderson /**
5316e63b8a29SRichard Henderson  * atom_and_align_for_opc:
5317e63b8a29SRichard Henderson  * @s: tcg context
5318e63b8a29SRichard Henderson  * @opc: memory operation code
5319e63b8a29SRichard Henderson  * @host_atom: MO_ATOM_{IFALIGN,WITHIN16,SUBALIGN} for host operations
5320e63b8a29SRichard Henderson  * @allow_two_ops: true if we are prepared to issue two operations
5321e63b8a29SRichard Henderson  *
5322e63b8a29SRichard Henderson  * Return the alignment and atomicity to use for the inline fast path
5323e63b8a29SRichard Henderson  * for the given memory operation.  The alignment may be larger than
5324e63b8a29SRichard Henderson  * that specified in @opc, and the correct alignment will be diagnosed
5325e63b8a29SRichard Henderson  * by the slow path helper.
5326e63b8a29SRichard Henderson  *
5327e63b8a29SRichard Henderson  * If @allow_two_ops, the host is prepared to test for 2x alignment,
5328e63b8a29SRichard Henderson  * and issue two loads or stores for subalignment.
5329e63b8a29SRichard Henderson  */
5330e63b8a29SRichard Henderson static TCGAtomAlign atom_and_align_for_opc(TCGContext *s, MemOp opc,
5331e63b8a29SRichard Henderson                                            MemOp host_atom, bool allow_two_ops)
5332e63b8a29SRichard Henderson {
5333e63b8a29SRichard Henderson     MemOp align = get_alignment_bits(opc);
5334e63b8a29SRichard Henderson     MemOp size = opc & MO_SIZE;
5335e63b8a29SRichard Henderson     MemOp half = size ? size - 1 : 0;
5336e63b8a29SRichard Henderson     MemOp atmax;
5337e63b8a29SRichard Henderson     MemOp atom;
5338e63b8a29SRichard Henderson 
5339e63b8a29SRichard Henderson     /* When serialized, no further atomicity required.  */
5340e63b8a29SRichard Henderson     if (s->gen_tb->cflags & CF_PARALLEL) {
5341e63b8a29SRichard Henderson         atom = opc & MO_ATOM_MASK;
5342e63b8a29SRichard Henderson     } else {
5343e63b8a29SRichard Henderson         atom = MO_ATOM_NONE;
5344e63b8a29SRichard Henderson     }
5345e63b8a29SRichard Henderson 
5346e63b8a29SRichard Henderson     switch (atom) {
5347e63b8a29SRichard Henderson     case MO_ATOM_NONE:
5348e63b8a29SRichard Henderson         /* The operation requires no specific atomicity. */
5349e63b8a29SRichard Henderson         atmax = MO_8;
5350e63b8a29SRichard Henderson         break;
5351e63b8a29SRichard Henderson 
5352e63b8a29SRichard Henderson     case MO_ATOM_IFALIGN:
5353e63b8a29SRichard Henderson         atmax = size;
5354e63b8a29SRichard Henderson         break;
5355e63b8a29SRichard Henderson 
5356e63b8a29SRichard Henderson     case MO_ATOM_IFALIGN_PAIR:
5357e63b8a29SRichard Henderson         atmax = half;
5358e63b8a29SRichard Henderson         break;
5359e63b8a29SRichard Henderson 
5360e63b8a29SRichard Henderson     case MO_ATOM_WITHIN16:
5361e63b8a29SRichard Henderson         atmax = size;
5362e63b8a29SRichard Henderson         if (size == MO_128) {
5363e63b8a29SRichard Henderson             /* Misalignment implies !within16, and therefore no atomicity. */
5364e63b8a29SRichard Henderson         } else if (host_atom != MO_ATOM_WITHIN16) {
5365e63b8a29SRichard Henderson             /* The host does not implement within16, so require alignment. */
5366e63b8a29SRichard Henderson             align = MAX(align, size);
5367e63b8a29SRichard Henderson         }
5368e63b8a29SRichard Henderson         break;
5369e63b8a29SRichard Henderson 
5370e63b8a29SRichard Henderson     case MO_ATOM_WITHIN16_PAIR:
5371e63b8a29SRichard Henderson         atmax = size;
5372e63b8a29SRichard Henderson         /*
5373e63b8a29SRichard Henderson          * Misalignment implies !within16, and therefore half atomicity.
5374e63b8a29SRichard Henderson          * Any host prepared for two operations can implement this with
5375e63b8a29SRichard Henderson          * half alignment.
5376e63b8a29SRichard Henderson          */
5377e63b8a29SRichard Henderson         if (host_atom != MO_ATOM_WITHIN16 && allow_two_ops) {
5378e63b8a29SRichard Henderson             align = MAX(align, half);
5379e63b8a29SRichard Henderson         }
5380e63b8a29SRichard Henderson         break;
5381e63b8a29SRichard Henderson 
5382e63b8a29SRichard Henderson     case MO_ATOM_SUBALIGN:
5383e63b8a29SRichard Henderson         atmax = size;
5384e63b8a29SRichard Henderson         if (host_atom != MO_ATOM_SUBALIGN) {
5385e63b8a29SRichard Henderson             /* If unaligned but not odd, there are subobjects up to half. */
5386e63b8a29SRichard Henderson             if (allow_two_ops) {
5387e63b8a29SRichard Henderson                 align = MAX(align, half);
5388e63b8a29SRichard Henderson             } else {
5389e63b8a29SRichard Henderson                 align = MAX(align, size);
5390e63b8a29SRichard Henderson             }
5391e63b8a29SRichard Henderson         }
5392e63b8a29SRichard Henderson         break;
5393e63b8a29SRichard Henderson 
5394e63b8a29SRichard Henderson     default:
5395e63b8a29SRichard Henderson         g_assert_not_reached();
5396e63b8a29SRichard Henderson     }
5397e63b8a29SRichard Henderson 
5398e63b8a29SRichard Henderson     return (TCGAtomAlign){ .atom = atmax, .align = align };
5399e63b8a29SRichard Henderson }
5400e63b8a29SRichard Henderson 
54018429a1caSRichard Henderson /*
54028429a1caSRichard Henderson  * Similarly for qemu_ld/st slow path helpers.
54038429a1caSRichard Henderson  * We must re-implement tcg_gen_callN and tcg_reg_alloc_call simultaneously,
54048429a1caSRichard Henderson  * using only the provided backend tcg_out_* functions.
54058429a1caSRichard Henderson  */
54068429a1caSRichard Henderson 
54078429a1caSRichard Henderson static int tcg_out_helper_stk_ofs(TCGType type, unsigned slot)
54088429a1caSRichard Henderson {
54098429a1caSRichard Henderson     int ofs = arg_slot_stk_ofs(slot);
54108429a1caSRichard Henderson 
54118429a1caSRichard Henderson     /*
54128429a1caSRichard Henderson      * Each stack slot is TCG_TARGET_LONG_BITS.  If the host does not
54138429a1caSRichard Henderson      * require extension to uint64_t, adjust the address for uint32_t.
54148429a1caSRichard Henderson      */
54158429a1caSRichard Henderson     if (HOST_BIG_ENDIAN &&
54168429a1caSRichard Henderson         TCG_TARGET_REG_BITS == 64 &&
54178429a1caSRichard Henderson         type == TCG_TYPE_I32) {
54188429a1caSRichard Henderson         ofs += 4;
54198429a1caSRichard Henderson     }
54208429a1caSRichard Henderson     return ofs;
54218429a1caSRichard Henderson }
54228429a1caSRichard Henderson 
54238d314041SRichard Henderson static void tcg_out_helper_load_slots(TCGContext *s,
54248429a1caSRichard Henderson                                       unsigned nmov, TCGMovExtend *mov,
54252462e30eSRichard Henderson                                       const TCGLdstHelperParam *parm)
54268429a1caSRichard Henderson {
54278d314041SRichard Henderson     unsigned i;
54282462e30eSRichard Henderson     TCGReg dst3;
54292462e30eSRichard Henderson 
54308d314041SRichard Henderson     /*
54318d314041SRichard Henderson      * Start from the end, storing to the stack first.
54328d314041SRichard Henderson      * This frees those registers, so we need not consider overlap.
54338d314041SRichard Henderson      */
54348d314041SRichard Henderson     for (i = nmov; i-- > 0; ) {
54358d314041SRichard Henderson         unsigned slot = mov[i].dst;
54368d314041SRichard Henderson 
54378d314041SRichard Henderson         if (arg_slot_reg_p(slot)) {
54388d314041SRichard Henderson             goto found_reg;
54398d314041SRichard Henderson         }
54408d314041SRichard Henderson 
54418d314041SRichard Henderson         TCGReg src = mov[i].src;
54428d314041SRichard Henderson         TCGType dst_type = mov[i].dst_type;
54438d314041SRichard Henderson         MemOp dst_mo = dst_type == TCG_TYPE_I32 ? MO_32 : MO_64;
54448d314041SRichard Henderson 
54458d314041SRichard Henderson         /* The argument is going onto the stack; extend into scratch. */
54468d314041SRichard Henderson         if ((mov[i].src_ext & MO_SIZE) != dst_mo) {
54478d314041SRichard Henderson             tcg_debug_assert(parm->ntmp != 0);
54488d314041SRichard Henderson             mov[i].dst = src = parm->tmp[0];
54498d314041SRichard Henderson             tcg_out_movext1(s, &mov[i]);
54508d314041SRichard Henderson         }
54518d314041SRichard Henderson 
54528d314041SRichard Henderson         tcg_out_st(s, dst_type, src, TCG_REG_CALL_STACK,
54538d314041SRichard Henderson                    tcg_out_helper_stk_ofs(dst_type, slot));
54548d314041SRichard Henderson     }
54558d314041SRichard Henderson     return;
54568d314041SRichard Henderson 
54578d314041SRichard Henderson  found_reg:
54588d314041SRichard Henderson     /*
54598d314041SRichard Henderson      * The remaining arguments are in registers.
54608d314041SRichard Henderson      * Convert slot numbers to argument registers.
54618d314041SRichard Henderson      */
54628d314041SRichard Henderson     nmov = i + 1;
54638d314041SRichard Henderson     for (i = 0; i < nmov; ++i) {
54648d314041SRichard Henderson         mov[i].dst = tcg_target_call_iarg_regs[mov[i].dst];
54658d314041SRichard Henderson     }
54668d314041SRichard Henderson 
54678429a1caSRichard Henderson     switch (nmov) {
54682462e30eSRichard Henderson     case 4:
54698429a1caSRichard Henderson         /* The backend must have provided enough temps for the worst case. */
54702462e30eSRichard Henderson         tcg_debug_assert(parm->ntmp >= 2);
54718429a1caSRichard Henderson 
54722462e30eSRichard Henderson         dst3 = mov[3].dst;
54732462e30eSRichard Henderson         for (unsigned j = 0; j < 3; ++j) {
54742462e30eSRichard Henderson             if (dst3 == mov[j].src) {
54758429a1caSRichard Henderson                 /*
54762462e30eSRichard Henderson                  * Conflict. Copy the source to a temporary, perform the
54772462e30eSRichard Henderson                  * remaining moves, then the extension from our scratch
54782462e30eSRichard Henderson                  * on the way out.
54798429a1caSRichard Henderson                  */
54802462e30eSRichard Henderson                 TCGReg scratch = parm->tmp[1];
54818429a1caSRichard Henderson 
54822462e30eSRichard Henderson                 tcg_out_mov(s, mov[3].src_type, scratch, mov[3].src);
54832462e30eSRichard Henderson                 tcg_out_movext3(s, mov, mov + 1, mov + 2, parm->tmp[0]);
54842462e30eSRichard Henderson                 tcg_out_movext1_new_src(s, &mov[3], scratch);
54852462e30eSRichard Henderson                 break;
54868429a1caSRichard Henderson             }
54878429a1caSRichard Henderson         }
54888429a1caSRichard Henderson 
54898429a1caSRichard Henderson         /* No conflicts: perform this move and continue. */
54902462e30eSRichard Henderson         tcg_out_movext1(s, &mov[3]);
54912462e30eSRichard Henderson         /* fall through */
54928429a1caSRichard Henderson 
54932462e30eSRichard Henderson     case 3:
54942462e30eSRichard Henderson         tcg_out_movext3(s, mov, mov + 1, mov + 2,
54952462e30eSRichard Henderson                         parm->ntmp ? parm->tmp[0] : -1);
54962462e30eSRichard Henderson         break;
54978429a1caSRichard Henderson     case 2:
54982462e30eSRichard Henderson         tcg_out_movext2(s, mov, mov + 1,
54992462e30eSRichard Henderson                         parm->ntmp ? parm->tmp[0] : -1);
55002462e30eSRichard Henderson         break;
55018429a1caSRichard Henderson     case 1:
55028429a1caSRichard Henderson         tcg_out_movext1(s, mov);
55032462e30eSRichard Henderson         break;
55042462e30eSRichard Henderson     default:
55058429a1caSRichard Henderson         g_assert_not_reached();
55068429a1caSRichard Henderson     }
55078429a1caSRichard Henderson }
55088429a1caSRichard Henderson 
55098429a1caSRichard Henderson static void tcg_out_helper_load_imm(TCGContext *s, unsigned slot,
55108429a1caSRichard Henderson                                     TCGType type, tcg_target_long imm,
55118429a1caSRichard Henderson                                     const TCGLdstHelperParam *parm)
55128429a1caSRichard Henderson {
55138429a1caSRichard Henderson     if (arg_slot_reg_p(slot)) {
55148429a1caSRichard Henderson         tcg_out_movi(s, type, tcg_target_call_iarg_regs[slot], imm);
55158429a1caSRichard Henderson     } else {
55168429a1caSRichard Henderson         int ofs = tcg_out_helper_stk_ofs(type, slot);
55178429a1caSRichard Henderson         if (!tcg_out_sti(s, type, imm, TCG_REG_CALL_STACK, ofs)) {
55188429a1caSRichard Henderson             tcg_debug_assert(parm->ntmp != 0);
55198429a1caSRichard Henderson             tcg_out_movi(s, type, parm->tmp[0], imm);
55208429a1caSRichard Henderson             tcg_out_st(s, type, parm->tmp[0], TCG_REG_CALL_STACK, ofs);
55218429a1caSRichard Henderson         }
55228429a1caSRichard Henderson     }
55238429a1caSRichard Henderson }
55248429a1caSRichard Henderson 
55258429a1caSRichard Henderson static void tcg_out_helper_load_common_args(TCGContext *s,
55268429a1caSRichard Henderson                                             const TCGLabelQemuLdst *ldst,
55278429a1caSRichard Henderson                                             const TCGLdstHelperParam *parm,
55288429a1caSRichard Henderson                                             const TCGHelperInfo *info,
55298429a1caSRichard Henderson                                             unsigned next_arg)
55308429a1caSRichard Henderson {
55318429a1caSRichard Henderson     TCGMovExtend ptr_mov = {
55328429a1caSRichard Henderson         .dst_type = TCG_TYPE_PTR,
55338429a1caSRichard Henderson         .src_type = TCG_TYPE_PTR,
55348429a1caSRichard Henderson         .src_ext = sizeof(void *) == 4 ? MO_32 : MO_64
55358429a1caSRichard Henderson     };
55368429a1caSRichard Henderson     const TCGCallArgumentLoc *loc = &info->in[0];
55378429a1caSRichard Henderson     TCGType type;
55388429a1caSRichard Henderson     unsigned slot;
55398429a1caSRichard Henderson     tcg_target_ulong imm;
55408429a1caSRichard Henderson 
55418429a1caSRichard Henderson     /*
55428429a1caSRichard Henderson      * Handle env, which is always first.
55438429a1caSRichard Henderson      */
55448429a1caSRichard Henderson     ptr_mov.dst = loc->arg_slot;
55458429a1caSRichard Henderson     ptr_mov.src = TCG_AREG0;
55468429a1caSRichard Henderson     tcg_out_helper_load_slots(s, 1, &ptr_mov, parm);
55478429a1caSRichard Henderson 
55488429a1caSRichard Henderson     /*
55498429a1caSRichard Henderson      * Handle oi.
55508429a1caSRichard Henderson      */
55518429a1caSRichard Henderson     imm = ldst->oi;
55528429a1caSRichard Henderson     loc = &info->in[next_arg];
55538429a1caSRichard Henderson     type = TCG_TYPE_I32;
55548429a1caSRichard Henderson     switch (loc->kind) {
55558429a1caSRichard Henderson     case TCG_CALL_ARG_NORMAL:
55568429a1caSRichard Henderson         break;
55578429a1caSRichard Henderson     case TCG_CALL_ARG_EXTEND_U:
55588429a1caSRichard Henderson     case TCG_CALL_ARG_EXTEND_S:
55598429a1caSRichard Henderson         /* No extension required for MemOpIdx. */
55608429a1caSRichard Henderson         tcg_debug_assert(imm <= INT32_MAX);
55618429a1caSRichard Henderson         type = TCG_TYPE_REG;
55628429a1caSRichard Henderson         break;
55638429a1caSRichard Henderson     default:
55648429a1caSRichard Henderson         g_assert_not_reached();
55658429a1caSRichard Henderson     }
55668429a1caSRichard Henderson     tcg_out_helper_load_imm(s, loc->arg_slot, type, imm, parm);
55678429a1caSRichard Henderson     next_arg++;
55688429a1caSRichard Henderson 
55698429a1caSRichard Henderson     /*
55708429a1caSRichard Henderson      * Handle ra.
55718429a1caSRichard Henderson      */
55728429a1caSRichard Henderson     loc = &info->in[next_arg];
55738429a1caSRichard Henderson     slot = loc->arg_slot;
55748429a1caSRichard Henderson     if (parm->ra_gen) {
55758429a1caSRichard Henderson         int arg_reg = -1;
55768429a1caSRichard Henderson         TCGReg ra_reg;
55778429a1caSRichard Henderson 
55788429a1caSRichard Henderson         if (arg_slot_reg_p(slot)) {
55798429a1caSRichard Henderson             arg_reg = tcg_target_call_iarg_regs[slot];
55808429a1caSRichard Henderson         }
55818429a1caSRichard Henderson         ra_reg = parm->ra_gen(s, ldst, arg_reg);
55828429a1caSRichard Henderson 
55838429a1caSRichard Henderson         ptr_mov.dst = slot;
55848429a1caSRichard Henderson         ptr_mov.src = ra_reg;
55858429a1caSRichard Henderson         tcg_out_helper_load_slots(s, 1, &ptr_mov, parm);
55868429a1caSRichard Henderson     } else {
55878429a1caSRichard Henderson         imm = (uintptr_t)ldst->raddr;
55888429a1caSRichard Henderson         tcg_out_helper_load_imm(s, slot, TCG_TYPE_PTR, imm, parm);
55898429a1caSRichard Henderson     }
55908429a1caSRichard Henderson }
55918429a1caSRichard Henderson 
55928429a1caSRichard Henderson static unsigned tcg_out_helper_add_mov(TCGMovExtend *mov,
55938429a1caSRichard Henderson                                        const TCGCallArgumentLoc *loc,
55948429a1caSRichard Henderson                                        TCGType dst_type, TCGType src_type,
55958429a1caSRichard Henderson                                        TCGReg lo, TCGReg hi)
55968429a1caSRichard Henderson {
5597ebebea53SRichard Henderson     MemOp reg_mo;
5598ebebea53SRichard Henderson 
55998429a1caSRichard Henderson     if (dst_type <= TCG_TYPE_REG) {
56008429a1caSRichard Henderson         MemOp src_ext;
56018429a1caSRichard Henderson 
56028429a1caSRichard Henderson         switch (loc->kind) {
56038429a1caSRichard Henderson         case TCG_CALL_ARG_NORMAL:
56048429a1caSRichard Henderson             src_ext = src_type == TCG_TYPE_I32 ? MO_32 : MO_64;
56058429a1caSRichard Henderson             break;
56068429a1caSRichard Henderson         case TCG_CALL_ARG_EXTEND_U:
56078429a1caSRichard Henderson             dst_type = TCG_TYPE_REG;
56088429a1caSRichard Henderson             src_ext = MO_UL;
56098429a1caSRichard Henderson             break;
56108429a1caSRichard Henderson         case TCG_CALL_ARG_EXTEND_S:
56118429a1caSRichard Henderson             dst_type = TCG_TYPE_REG;
56128429a1caSRichard Henderson             src_ext = MO_SL;
56138429a1caSRichard Henderson             break;
56148429a1caSRichard Henderson         default:
56158429a1caSRichard Henderson             g_assert_not_reached();
56168429a1caSRichard Henderson         }
56178429a1caSRichard Henderson 
56188429a1caSRichard Henderson         mov[0].dst = loc->arg_slot;
56198429a1caSRichard Henderson         mov[0].dst_type = dst_type;
56208429a1caSRichard Henderson         mov[0].src = lo;
56218429a1caSRichard Henderson         mov[0].src_type = src_type;
56228429a1caSRichard Henderson         mov[0].src_ext = src_ext;
56238429a1caSRichard Henderson         return 1;
56248429a1caSRichard Henderson     }
56258429a1caSRichard Henderson 
5626ebebea53SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
5627ebebea53SRichard Henderson         assert(dst_type == TCG_TYPE_I64);
5628ebebea53SRichard Henderson         reg_mo = MO_32;
5629ebebea53SRichard Henderson     } else {
5630ebebea53SRichard Henderson         assert(dst_type == TCG_TYPE_I128);
5631ebebea53SRichard Henderson         reg_mo = MO_64;
5632ebebea53SRichard Henderson     }
56338429a1caSRichard Henderson 
56348429a1caSRichard Henderson     mov[0].dst = loc[HOST_BIG_ENDIAN].arg_slot;
56358429a1caSRichard Henderson     mov[0].src = lo;
5636ebebea53SRichard Henderson     mov[0].dst_type = TCG_TYPE_REG;
5637ebebea53SRichard Henderson     mov[0].src_type = TCG_TYPE_REG;
5638ebebea53SRichard Henderson     mov[0].src_ext = reg_mo;
56398429a1caSRichard Henderson 
56408429a1caSRichard Henderson     mov[1].dst = loc[!HOST_BIG_ENDIAN].arg_slot;
56418429a1caSRichard Henderson     mov[1].src = hi;
5642ebebea53SRichard Henderson     mov[1].dst_type = TCG_TYPE_REG;
5643ebebea53SRichard Henderson     mov[1].src_type = TCG_TYPE_REG;
5644ebebea53SRichard Henderson     mov[1].src_ext = reg_mo;
56458429a1caSRichard Henderson 
56468429a1caSRichard Henderson     return 2;
56478429a1caSRichard Henderson }
56488429a1caSRichard Henderson 
56498429a1caSRichard Henderson static void tcg_out_ld_helper_args(TCGContext *s, const TCGLabelQemuLdst *ldst,
56508429a1caSRichard Henderson                                    const TCGLdstHelperParam *parm)
56518429a1caSRichard Henderson {
56528429a1caSRichard Henderson     const TCGHelperInfo *info;
56538429a1caSRichard Henderson     const TCGCallArgumentLoc *loc;
56548429a1caSRichard Henderson     TCGMovExtend mov[2];
56558429a1caSRichard Henderson     unsigned next_arg, nmov;
56568429a1caSRichard Henderson     MemOp mop = get_memop(ldst->oi);
56578429a1caSRichard Henderson 
56588429a1caSRichard Henderson     switch (mop & MO_SIZE) {
56598429a1caSRichard Henderson     case MO_8:
56608429a1caSRichard Henderson     case MO_16:
56618429a1caSRichard Henderson     case MO_32:
56628429a1caSRichard Henderson         info = &info_helper_ld32_mmu;
56638429a1caSRichard Henderson         break;
56648429a1caSRichard Henderson     case MO_64:
56658429a1caSRichard Henderson         info = &info_helper_ld64_mmu;
56668429a1caSRichard Henderson         break;
5667ebebea53SRichard Henderson     case MO_128:
5668ebebea53SRichard Henderson         info = &info_helper_ld128_mmu;
5669ebebea53SRichard Henderson         break;
56708429a1caSRichard Henderson     default:
56718429a1caSRichard Henderson         g_assert_not_reached();
56728429a1caSRichard Henderson     }
56738429a1caSRichard Henderson 
56748429a1caSRichard Henderson     /* Defer env argument. */
56758429a1caSRichard Henderson     next_arg = 1;
56768429a1caSRichard Henderson 
56778429a1caSRichard Henderson     loc = &info->in[next_arg];
5678c31e5fa4SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && s->addr_type == TCG_TYPE_I32) {
567924e46e6cSRichard Henderson         /*
568024e46e6cSRichard Henderson          * 32-bit host with 32-bit guest: zero-extend the guest address
568124e46e6cSRichard Henderson          * to 64-bits for the helper by storing the low part, then
568224e46e6cSRichard Henderson          * load a zero for the high part.
568324e46e6cSRichard Henderson          */
568424e46e6cSRichard Henderson         tcg_out_helper_add_mov(mov, loc + HOST_BIG_ENDIAN,
568524e46e6cSRichard Henderson                                TCG_TYPE_I32, TCG_TYPE_I32,
568624e46e6cSRichard Henderson                                ldst->addrlo_reg, -1);
568724e46e6cSRichard Henderson         tcg_out_helper_load_slots(s, 1, mov, parm);
568824e46e6cSRichard Henderson 
568924e46e6cSRichard Henderson         tcg_out_helper_load_imm(s, loc[!HOST_BIG_ENDIAN].arg_slot,
569024e46e6cSRichard Henderson                                 TCG_TYPE_I32, 0, parm);
569124e46e6cSRichard Henderson         next_arg += 2;
5692c31e5fa4SRichard Henderson     } else {
5693c31e5fa4SRichard Henderson         nmov = tcg_out_helper_add_mov(mov, loc, TCG_TYPE_I64, s->addr_type,
5694c31e5fa4SRichard Henderson                                       ldst->addrlo_reg, ldst->addrhi_reg);
5695c31e5fa4SRichard Henderson         tcg_out_helper_load_slots(s, nmov, mov, parm);
5696c31e5fa4SRichard Henderson         next_arg += nmov;
569724e46e6cSRichard Henderson     }
56988429a1caSRichard Henderson 
5699ebebea53SRichard Henderson     switch (info->out_kind) {
5700ebebea53SRichard Henderson     case TCG_CALL_RET_NORMAL:
5701ebebea53SRichard Henderson     case TCG_CALL_RET_BY_VEC:
5702ebebea53SRichard Henderson         break;
5703ebebea53SRichard Henderson     case TCG_CALL_RET_BY_REF:
5704ebebea53SRichard Henderson         /*
5705ebebea53SRichard Henderson          * The return reference is in the first argument slot.
5706ebebea53SRichard Henderson          * We need memory in which to return: re-use the top of stack.
5707ebebea53SRichard Henderson          */
5708ebebea53SRichard Henderson         {
5709ebebea53SRichard Henderson             int ofs_slot0 = TCG_TARGET_CALL_STACK_OFFSET;
5710ebebea53SRichard Henderson 
5711ebebea53SRichard Henderson             if (arg_slot_reg_p(0)) {
5712ebebea53SRichard Henderson                 tcg_out_addi_ptr(s, tcg_target_call_iarg_regs[0],
5713ebebea53SRichard Henderson                                  TCG_REG_CALL_STACK, ofs_slot0);
5714ebebea53SRichard Henderson             } else {
5715ebebea53SRichard Henderson                 tcg_debug_assert(parm->ntmp != 0);
5716ebebea53SRichard Henderson                 tcg_out_addi_ptr(s, parm->tmp[0],
5717ebebea53SRichard Henderson                                  TCG_REG_CALL_STACK, ofs_slot0);
5718ebebea53SRichard Henderson                 tcg_out_st(s, TCG_TYPE_PTR, parm->tmp[0],
5719ebebea53SRichard Henderson                            TCG_REG_CALL_STACK, ofs_slot0);
5720ebebea53SRichard Henderson             }
5721ebebea53SRichard Henderson         }
5722ebebea53SRichard Henderson         break;
5723ebebea53SRichard Henderson     default:
5724ebebea53SRichard Henderson         g_assert_not_reached();
5725ebebea53SRichard Henderson     }
57268429a1caSRichard Henderson 
57278429a1caSRichard Henderson     tcg_out_helper_load_common_args(s, ldst, parm, info, next_arg);
57288429a1caSRichard Henderson }
57298429a1caSRichard Henderson 
57308429a1caSRichard Henderson static void tcg_out_ld_helper_ret(TCGContext *s, const TCGLabelQemuLdst *ldst,
57318429a1caSRichard Henderson                                   bool load_sign,
57328429a1caSRichard Henderson                                   const TCGLdstHelperParam *parm)
57338429a1caSRichard Henderson {
57348429a1caSRichard Henderson     MemOp mop = get_memop(ldst->oi);
5735ebebea53SRichard Henderson     TCGMovExtend mov[2];
5736ebebea53SRichard Henderson     int ofs_slot0;
57378429a1caSRichard Henderson 
5738ebebea53SRichard Henderson     switch (ldst->type) {
5739ebebea53SRichard Henderson     case TCG_TYPE_I64:
5740ebebea53SRichard Henderson         if (TCG_TARGET_REG_BITS == 32) {
5741ebebea53SRichard Henderson             break;
5742ebebea53SRichard Henderson         }
5743ebebea53SRichard Henderson         /* fall through */
5744ebebea53SRichard Henderson 
5745ebebea53SRichard Henderson     case TCG_TYPE_I32:
57468429a1caSRichard Henderson         mov[0].dst = ldst->datalo_reg;
57478429a1caSRichard Henderson         mov[0].src = tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, 0);
57488429a1caSRichard Henderson         mov[0].dst_type = ldst->type;
57498429a1caSRichard Henderson         mov[0].src_type = TCG_TYPE_REG;
57508429a1caSRichard Henderson 
57518429a1caSRichard Henderson         /*
57528429a1caSRichard Henderson          * If load_sign, then we allowed the helper to perform the
57538429a1caSRichard Henderson          * appropriate sign extension to tcg_target_ulong, and all
57548429a1caSRichard Henderson          * we need now is a plain move.
57558429a1caSRichard Henderson          *
57568429a1caSRichard Henderson          * If they do not, then we expect the relevant extension
57578429a1caSRichard Henderson          * instruction to be no more expensive than a move, and
57588429a1caSRichard Henderson          * we thus save the icache etc by only using one of two
57598429a1caSRichard Henderson          * helper functions.
57608429a1caSRichard Henderson          */
57618429a1caSRichard Henderson         if (load_sign || !(mop & MO_SIGN)) {
57628429a1caSRichard Henderson             if (TCG_TARGET_REG_BITS == 32 || ldst->type == TCG_TYPE_I32) {
57638429a1caSRichard Henderson                 mov[0].src_ext = MO_32;
57648429a1caSRichard Henderson             } else {
57658429a1caSRichard Henderson                 mov[0].src_ext = MO_64;
57668429a1caSRichard Henderson             }
57678429a1caSRichard Henderson         } else {
57688429a1caSRichard Henderson             mov[0].src_ext = mop & MO_SSIZE;
57698429a1caSRichard Henderson         }
57708429a1caSRichard Henderson         tcg_out_movext1(s, mov);
5771ebebea53SRichard Henderson         return;
5772ebebea53SRichard Henderson 
5773ebebea53SRichard Henderson     case TCG_TYPE_I128:
5774ebebea53SRichard Henderson         tcg_debug_assert(TCG_TARGET_REG_BITS == 64);
5775ebebea53SRichard Henderson         ofs_slot0 = TCG_TARGET_CALL_STACK_OFFSET;
5776ebebea53SRichard Henderson         switch (TCG_TARGET_CALL_RET_I128) {
5777ebebea53SRichard Henderson         case TCG_CALL_RET_NORMAL:
5778ebebea53SRichard Henderson             break;
5779ebebea53SRichard Henderson         case TCG_CALL_RET_BY_VEC:
5780ebebea53SRichard Henderson             tcg_out_st(s, TCG_TYPE_V128,
5781ebebea53SRichard Henderson                        tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0),
5782ebebea53SRichard Henderson                        TCG_REG_CALL_STACK, ofs_slot0);
5783ebebea53SRichard Henderson             /* fall through */
5784ebebea53SRichard Henderson         case TCG_CALL_RET_BY_REF:
5785ebebea53SRichard Henderson             tcg_out_ld(s, TCG_TYPE_I64, ldst->datalo_reg,
5786ebebea53SRichard Henderson                        TCG_REG_CALL_STACK, ofs_slot0 + 8 * HOST_BIG_ENDIAN);
5787ebebea53SRichard Henderson             tcg_out_ld(s, TCG_TYPE_I64, ldst->datahi_reg,
5788ebebea53SRichard Henderson                        TCG_REG_CALL_STACK, ofs_slot0 + 8 * !HOST_BIG_ENDIAN);
5789ebebea53SRichard Henderson             return;
5790ebebea53SRichard Henderson         default:
5791ebebea53SRichard Henderson             g_assert_not_reached();
5792ebebea53SRichard Henderson         }
5793ebebea53SRichard Henderson         break;
5794ebebea53SRichard Henderson 
5795ebebea53SRichard Henderson     default:
5796ebebea53SRichard Henderson         g_assert_not_reached();
5797ebebea53SRichard Henderson     }
57988429a1caSRichard Henderson 
57998429a1caSRichard Henderson     mov[0].dst = ldst->datalo_reg;
58008429a1caSRichard Henderson     mov[0].src =
58018429a1caSRichard Henderson         tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, HOST_BIG_ENDIAN);
5802723d3a27SRichard Henderson     mov[0].dst_type = TCG_TYPE_REG;
5803723d3a27SRichard Henderson     mov[0].src_type = TCG_TYPE_REG;
5804ebebea53SRichard Henderson     mov[0].src_ext = TCG_TARGET_REG_BITS == 32 ? MO_32 : MO_64;
58058429a1caSRichard Henderson 
58068429a1caSRichard Henderson     mov[1].dst = ldst->datahi_reg;
58078429a1caSRichard Henderson     mov[1].src =
58088429a1caSRichard Henderson         tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, !HOST_BIG_ENDIAN);
58098429a1caSRichard Henderson     mov[1].dst_type = TCG_TYPE_REG;
58108429a1caSRichard Henderson     mov[1].src_type = TCG_TYPE_REG;
5811ebebea53SRichard Henderson     mov[1].src_ext = TCG_TARGET_REG_BITS == 32 ? MO_32 : MO_64;
58128429a1caSRichard Henderson 
58138429a1caSRichard Henderson     tcg_out_movext2(s, mov, mov + 1, parm->ntmp ? parm->tmp[0] : -1);
58148429a1caSRichard Henderson }
58158429a1caSRichard Henderson 
58168429a1caSRichard Henderson static void tcg_out_st_helper_args(TCGContext *s, const TCGLabelQemuLdst *ldst,
58178429a1caSRichard Henderson                                    const TCGLdstHelperParam *parm)
58188429a1caSRichard Henderson {
58198429a1caSRichard Henderson     const TCGHelperInfo *info;
58208429a1caSRichard Henderson     const TCGCallArgumentLoc *loc;
58218429a1caSRichard Henderson     TCGMovExtend mov[4];
58228429a1caSRichard Henderson     TCGType data_type;
58238429a1caSRichard Henderson     unsigned next_arg, nmov, n;
58248429a1caSRichard Henderson     MemOp mop = get_memop(ldst->oi);
58258429a1caSRichard Henderson 
58268429a1caSRichard Henderson     switch (mop & MO_SIZE) {
58278429a1caSRichard Henderson     case MO_8:
58288429a1caSRichard Henderson     case MO_16:
58298429a1caSRichard Henderson     case MO_32:
58308429a1caSRichard Henderson         info = &info_helper_st32_mmu;
58318429a1caSRichard Henderson         data_type = TCG_TYPE_I32;
58328429a1caSRichard Henderson         break;
58338429a1caSRichard Henderson     case MO_64:
58348429a1caSRichard Henderson         info = &info_helper_st64_mmu;
58358429a1caSRichard Henderson         data_type = TCG_TYPE_I64;
58368429a1caSRichard Henderson         break;
5837ebebea53SRichard Henderson     case MO_128:
5838ebebea53SRichard Henderson         info = &info_helper_st128_mmu;
5839ebebea53SRichard Henderson         data_type = TCG_TYPE_I128;
5840ebebea53SRichard Henderson         break;
58418429a1caSRichard Henderson     default:
58428429a1caSRichard Henderson         g_assert_not_reached();
58438429a1caSRichard Henderson     }
58448429a1caSRichard Henderson 
58458429a1caSRichard Henderson     /* Defer env argument. */
58468429a1caSRichard Henderson     next_arg = 1;
58478429a1caSRichard Henderson     nmov = 0;
58488429a1caSRichard Henderson 
58498429a1caSRichard Henderson     /* Handle addr argument. */
58508429a1caSRichard Henderson     loc = &info->in[next_arg];
5851c31e5fa4SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && s->addr_type == TCG_TYPE_I32) {
585224e46e6cSRichard Henderson         /*
585324e46e6cSRichard Henderson          * 32-bit host with 32-bit guest: zero-extend the guest address
585424e46e6cSRichard Henderson          * to 64-bits for the helper by storing the low part.  Later,
585524e46e6cSRichard Henderson          * after we have processed the register inputs, we will load a
585624e46e6cSRichard Henderson          * zero for the high part.
585724e46e6cSRichard Henderson          */
585824e46e6cSRichard Henderson         tcg_out_helper_add_mov(mov, loc + HOST_BIG_ENDIAN,
585924e46e6cSRichard Henderson                                TCG_TYPE_I32, TCG_TYPE_I32,
586024e46e6cSRichard Henderson                                ldst->addrlo_reg, -1);
586124e46e6cSRichard Henderson         next_arg += 2;
586224e46e6cSRichard Henderson         nmov += 1;
5863c31e5fa4SRichard Henderson     } else {
5864c31e5fa4SRichard Henderson         n = tcg_out_helper_add_mov(mov, loc, TCG_TYPE_I64, s->addr_type,
5865c31e5fa4SRichard Henderson                                    ldst->addrlo_reg, ldst->addrhi_reg);
5866c31e5fa4SRichard Henderson         next_arg += n;
5867c31e5fa4SRichard Henderson         nmov += n;
586824e46e6cSRichard Henderson     }
58698429a1caSRichard Henderson 
58708429a1caSRichard Henderson     /* Handle data argument. */
58718429a1caSRichard Henderson     loc = &info->in[next_arg];
5872ebebea53SRichard Henderson     switch (loc->kind) {
5873ebebea53SRichard Henderson     case TCG_CALL_ARG_NORMAL:
5874ebebea53SRichard Henderson     case TCG_CALL_ARG_EXTEND_U:
5875ebebea53SRichard Henderson     case TCG_CALL_ARG_EXTEND_S:
58768429a1caSRichard Henderson         n = tcg_out_helper_add_mov(mov + nmov, loc, data_type, ldst->type,
58778429a1caSRichard Henderson                                    ldst->datalo_reg, ldst->datahi_reg);
58788429a1caSRichard Henderson         next_arg += n;
58798429a1caSRichard Henderson         nmov += n;
5880ebebea53SRichard Henderson         tcg_out_helper_load_slots(s, nmov, mov, parm);
5881ebebea53SRichard Henderson         break;
5882ebebea53SRichard Henderson 
5883ebebea53SRichard Henderson     case TCG_CALL_ARG_BY_REF:
5884ebebea53SRichard Henderson         tcg_debug_assert(TCG_TARGET_REG_BITS == 64);
5885ebebea53SRichard Henderson         tcg_debug_assert(data_type == TCG_TYPE_I128);
5886ebebea53SRichard Henderson         tcg_out_st(s, TCG_TYPE_I64,
5887ebebea53SRichard Henderson                    HOST_BIG_ENDIAN ? ldst->datahi_reg : ldst->datalo_reg,
5888ebebea53SRichard Henderson                    TCG_REG_CALL_STACK, arg_slot_stk_ofs(loc[0].ref_slot));
5889ebebea53SRichard Henderson         tcg_out_st(s, TCG_TYPE_I64,
5890ebebea53SRichard Henderson                    HOST_BIG_ENDIAN ? ldst->datalo_reg : ldst->datahi_reg,
5891ebebea53SRichard Henderson                    TCG_REG_CALL_STACK, arg_slot_stk_ofs(loc[1].ref_slot));
58928429a1caSRichard Henderson 
58938429a1caSRichard Henderson         tcg_out_helper_load_slots(s, nmov, mov, parm);
5894ebebea53SRichard Henderson 
5895ebebea53SRichard Henderson         if (arg_slot_reg_p(loc->arg_slot)) {
5896ebebea53SRichard Henderson             tcg_out_addi_ptr(s, tcg_target_call_iarg_regs[loc->arg_slot],
5897ebebea53SRichard Henderson                              TCG_REG_CALL_STACK,
5898ebebea53SRichard Henderson                              arg_slot_stk_ofs(loc->ref_slot));
5899ebebea53SRichard Henderson         } else {
5900ebebea53SRichard Henderson             tcg_debug_assert(parm->ntmp != 0);
5901ebebea53SRichard Henderson             tcg_out_addi_ptr(s, parm->tmp[0], TCG_REG_CALL_STACK,
5902ebebea53SRichard Henderson                              arg_slot_stk_ofs(loc->ref_slot));
5903ebebea53SRichard Henderson             tcg_out_st(s, TCG_TYPE_PTR, parm->tmp[0],
5904ebebea53SRichard Henderson                        TCG_REG_CALL_STACK, arg_slot_stk_ofs(loc->arg_slot));
5905ebebea53SRichard Henderson         }
5906ebebea53SRichard Henderson         next_arg += 2;
5907ebebea53SRichard Henderson         break;
5908ebebea53SRichard Henderson 
5909ebebea53SRichard Henderson     default:
5910ebebea53SRichard Henderson         g_assert_not_reached();
5911ebebea53SRichard Henderson     }
5912ebebea53SRichard Henderson 
5913c31e5fa4SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && s->addr_type == TCG_TYPE_I32) {
5914c31e5fa4SRichard Henderson         /* Zero extend the address by loading a zero for the high part. */
591524e46e6cSRichard Henderson         loc = &info->in[1 + !HOST_BIG_ENDIAN];
591624e46e6cSRichard Henderson         tcg_out_helper_load_imm(s, loc->arg_slot, TCG_TYPE_I32, 0, parm);
591724e46e6cSRichard Henderson     }
591824e46e6cSRichard Henderson 
59198429a1caSRichard Henderson     tcg_out_helper_load_common_args(s, ldst, parm, info, next_arg);
59208429a1caSRichard Henderson }
59218429a1caSRichard Henderson 
5922b6a7f3e0SDaniel P. Berrangé void tcg_dump_op_count(GString *buf)
5923246ae24dSMax Filippov {
5924b6a7f3e0SDaniel P. Berrangé     g_string_append_printf(buf, "[TCG profiler not compiled]\n");
5925246ae24dSMax Filippov }
592672fd2efbSEmilio G. Cota 
592776cef4b2SRichard Henderson int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start)
5928c896fe29Sbellard {
5929747bd69dSRichard Henderson     int i, start_words, num_insns;
593015fa08f8SRichard Henderson     TCGOp *op;
5931c896fe29Sbellard 
5932d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)
5933fbf59aadSRichard Henderson                  && qemu_log_in_addr_range(pc_start))) {
5934c60f599bSRichard Henderson         FILE *logfile = qemu_log_trylock();
593578b54858SRichard Henderson         if (logfile) {
593678b54858SRichard Henderson             fprintf(logfile, "OP:\n");
5937b7a83ff8SRichard Henderson             tcg_dump_ops(s, logfile, false);
593878b54858SRichard Henderson             fprintf(logfile, "\n");
5939fc59d2d8SRobert Foley             qemu_log_unlock(logfile);
5940c896fe29Sbellard         }
594178b54858SRichard Henderson     }
5942c896fe29Sbellard 
5943bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG
5944bef16ab4SRichard Henderson     /* Ensure all labels referenced have been emitted.  */
5945bef16ab4SRichard Henderson     {
5946bef16ab4SRichard Henderson         TCGLabel *l;
5947bef16ab4SRichard Henderson         bool error = false;
5948bef16ab4SRichard Henderson 
5949bef16ab4SRichard Henderson         QSIMPLEQ_FOREACH(l, &s->labels, next) {
5950f85b1fc4SRichard Henderson             if (unlikely(!l->present) && !QSIMPLEQ_EMPTY(&l->branches)) {
5951bef16ab4SRichard Henderson                 qemu_log_mask(CPU_LOG_TB_OP,
5952bef16ab4SRichard Henderson                               "$L%d referenced but not present.\n", l->id);
5953bef16ab4SRichard Henderson                 error = true;
5954bef16ab4SRichard Henderson             }
5955bef16ab4SRichard Henderson         }
5956bef16ab4SRichard Henderson         assert(!error);
5957bef16ab4SRichard Henderson     }
5958bef16ab4SRichard Henderson #endif
5959bef16ab4SRichard Henderson 
5960c45cb8bbSRichard Henderson     tcg_optimize(s);
59618f2e8c07SKirill Batuzov 
5962b4fc67c7SRichard Henderson     reachable_code_pass(s);
5963874b8574SRichard Henderson     liveness_pass_0(s);
5964b83eabeaSRichard Henderson     liveness_pass_1(s);
59655a18407fSRichard Henderson 
59665a18407fSRichard Henderson     if (s->nb_indirects > 0) {
59675a18407fSRichard Henderson         if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND)
5968fbf59aadSRichard Henderson                      && qemu_log_in_addr_range(pc_start))) {
5969c60f599bSRichard Henderson             FILE *logfile = qemu_log_trylock();
597078b54858SRichard Henderson             if (logfile) {
597178b54858SRichard Henderson                 fprintf(logfile, "OP before indirect lowering:\n");
5972b7a83ff8SRichard Henderson                 tcg_dump_ops(s, logfile, false);
597378b54858SRichard Henderson                 fprintf(logfile, "\n");
5974fc59d2d8SRobert Foley                 qemu_log_unlock(logfile);
59755a18407fSRichard Henderson             }
597678b54858SRichard Henderson         }
5977645e3a81SRichard Henderson 
59785a18407fSRichard Henderson         /* Replace indirect temps with direct temps.  */
5979b83eabeaSRichard Henderson         if (liveness_pass_2(s)) {
59805a18407fSRichard Henderson             /* If changes were made, re-run liveness.  */
5981b83eabeaSRichard Henderson             liveness_pass_1(s);
59825a18407fSRichard Henderson         }
59835a18407fSRichard Henderson     }
5984c5cc28ffSAurelien Jarno 
5985d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT)
5986fbf59aadSRichard Henderson                  && qemu_log_in_addr_range(pc_start))) {
5987c60f599bSRichard Henderson         FILE *logfile = qemu_log_trylock();
598878b54858SRichard Henderson         if (logfile) {
598978b54858SRichard Henderson             fprintf(logfile, "OP after optimization and liveness analysis:\n");
5990b7a83ff8SRichard Henderson             tcg_dump_ops(s, logfile, true);
599178b54858SRichard Henderson             fprintf(logfile, "\n");
5992fc59d2d8SRobert Foley             qemu_log_unlock(logfile);
5993c896fe29Sbellard         }
599478b54858SRichard Henderson     }
5995c896fe29Sbellard 
599635abb009SRichard Henderson     /* Initialize goto_tb jump offsets. */
59973a50f424SRichard Henderson     tb->jmp_reset_offset[0] = TB_JMP_OFFSET_INVALID;
59983a50f424SRichard Henderson     tb->jmp_reset_offset[1] = TB_JMP_OFFSET_INVALID;
59999da6079bSRichard Henderson     tb->jmp_insn_offset[0] = TB_JMP_OFFSET_INVALID;
60009da6079bSRichard Henderson     tb->jmp_insn_offset[1] = TB_JMP_OFFSET_INVALID;
600135abb009SRichard Henderson 
6002c896fe29Sbellard     tcg_reg_alloc_start(s);
6003c896fe29Sbellard 
6004db0c51a3SRichard Henderson     /*
6005db0c51a3SRichard Henderson      * Reset the buffer pointers when restarting after overflow.
6006db0c51a3SRichard Henderson      * TODO: Move this into translate-all.c with the rest of the
6007db0c51a3SRichard Henderson      * buffer management.  Having only this done here is confusing.
6008db0c51a3SRichard Henderson      */
6009db0c51a3SRichard Henderson     s->code_buf = tcg_splitwx_to_rw(tb->tc.ptr);
6010db0c51a3SRichard Henderson     s->code_ptr = s->code_buf;
6011c896fe29Sbellard 
6012659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
60136001f772SLaurent Vivier     QSIMPLEQ_INIT(&s->ldst_labels);
6014659ef5cbSRichard Henderson #endif
601557a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
601657a26946SRichard Henderson     s->pool_labels = NULL;
601757a26946SRichard Henderson #endif
60189ecefc84SRichard Henderson 
6019747bd69dSRichard Henderson     start_words = s->insn_start_words;
6020747bd69dSRichard Henderson     s->gen_insn_data =
6021747bd69dSRichard Henderson         tcg_malloc(sizeof(uint64_t) * s->gen_tb->icount * start_words);
6022747bd69dSRichard Henderson 
60239358fbbfSRichard Henderson     tcg_out_tb_start(s);
60249358fbbfSRichard Henderson 
6025fca8a500SRichard Henderson     num_insns = -1;
602615fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
6027c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
6028b3db8758Sblueswir1 
6029c896fe29Sbellard         switch (opc) {
6030c896fe29Sbellard         case INDEX_op_mov_i32:
6031c896fe29Sbellard         case INDEX_op_mov_i64:
6032d2fd745fSRichard Henderson         case INDEX_op_mov_vec:
6033dd186292SRichard Henderson             tcg_reg_alloc_mov(s, op);
6034c896fe29Sbellard             break;
6035bab1671fSRichard Henderson         case INDEX_op_dup_vec:
6036bab1671fSRichard Henderson             tcg_reg_alloc_dup(s, op);
6037bab1671fSRichard Henderson             break;
6038765b842aSRichard Henderson         case INDEX_op_insn_start:
6039fca8a500SRichard Henderson             if (num_insns >= 0) {
60409f754620SRichard Henderson                 size_t off = tcg_current_code_size(s);
60419f754620SRichard Henderson                 s->gen_insn_end_off[num_insns] = off;
60429f754620SRichard Henderson                 /* Assert that we do not overflow our stored offset.  */
60439f754620SRichard Henderson                 assert(s->gen_insn_end_off[num_insns] == off);
6044fca8a500SRichard Henderson             }
6045fca8a500SRichard Henderson             num_insns++;
6046747bd69dSRichard Henderson             for (i = 0; i < start_words; ++i) {
6047747bd69dSRichard Henderson                 s->gen_insn_data[num_insns * start_words + i] =
6048c9ad8d27SRichard Henderson                     tcg_get_insn_start_param(op, i);
6049bad729e2SRichard Henderson             }
6050c896fe29Sbellard             break;
60515ff9d6a4Sbellard         case INDEX_op_discard:
605243439139SRichard Henderson             temp_dead(s, arg_temp(op->args[0]));
60535ff9d6a4Sbellard             break;
6054c896fe29Sbellard         case INDEX_op_set_label:
6055e8996ee0Sbellard             tcg_reg_alloc_bb_end(s, s->reserved_regs);
605692ab8e7dSRichard Henderson             tcg_out_label(s, arg_label(op->args[0]));
6057c896fe29Sbellard             break;
6058c896fe29Sbellard         case INDEX_op_call:
6059dd186292SRichard Henderson             tcg_reg_alloc_call(s, op);
6060c45cb8bbSRichard Henderson             break;
6061b55a8d9dSRichard Henderson         case INDEX_op_exit_tb:
6062b55a8d9dSRichard Henderson             tcg_out_exit_tb(s, op->args[0]);
6063b55a8d9dSRichard Henderson             break;
6064cf7d6b8eSRichard Henderson         case INDEX_op_goto_tb:
6065cf7d6b8eSRichard Henderson             tcg_out_goto_tb(s, op->args[0]);
6066cf7d6b8eSRichard Henderson             break;
6067efe86b21SRichard Henderson         case INDEX_op_dup2_vec:
6068efe86b21SRichard Henderson             if (tcg_reg_alloc_dup2(s, op)) {
6069efe86b21SRichard Henderson                 break;
6070efe86b21SRichard Henderson             }
6071efe86b21SRichard Henderson             /* fall through */
6072c896fe29Sbellard         default:
607325c4d9ccSRichard Henderson             /* Sanity check that we've not introduced any unhandled opcodes. */
6074be0f34b5SRichard Henderson             tcg_debug_assert(tcg_op_supported(opc));
6075c896fe29Sbellard             /* Note: in order to speed up the code, it would be much
6076c896fe29Sbellard                faster to have specialized register allocator functions for
6077c896fe29Sbellard                some common argument patterns */
6078dd186292SRichard Henderson             tcg_reg_alloc_op(s, op);
6079c896fe29Sbellard             break;
6080c896fe29Sbellard         }
6081b125f9dcSRichard Henderson         /* Test for (pending) buffer overflow.  The assumption is that any
6082b125f9dcSRichard Henderson            one operation beginning below the high water mark cannot overrun
6083b125f9dcSRichard Henderson            the buffer completely.  Thus we can test for overflow after
6084b125f9dcSRichard Henderson            generating code without having to check during generation.  */
6085644da9b3SJohn Clarke         if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) {
6086b125f9dcSRichard Henderson             return -1;
6087b125f9dcSRichard Henderson         }
60886e6c4efeSRichard Henderson         /* Test for TB overflow, as seen by gen_insn_end_off.  */
60896e6c4efeSRichard Henderson         if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) {
60906e6c4efeSRichard Henderson             return -2;
60916e6c4efeSRichard Henderson         }
6092c896fe29Sbellard     }
6093747bd69dSRichard Henderson     tcg_debug_assert(num_insns + 1 == s->gen_tb->icount);
6094fca8a500SRichard Henderson     s->gen_insn_end_off[num_insns] = tcg_current_code_size(s);
6095c45cb8bbSRichard Henderson 
6096b76f0d8cSYeongkyoon Lee     /* Generate TB finalization at the end of block */
6097659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
6098aeee05f5SRichard Henderson     i = tcg_out_ldst_finalize(s);
6099aeee05f5SRichard Henderson     if (i < 0) {
6100aeee05f5SRichard Henderson         return i;
610123dceda6SRichard Henderson     }
6102659ef5cbSRichard Henderson #endif
610357a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
61041768987bSRichard Henderson     i = tcg_out_pool_finalize(s);
61051768987bSRichard Henderson     if (i < 0) {
61061768987bSRichard Henderson         return i;
610757a26946SRichard Henderson     }
610857a26946SRichard Henderson #endif
61097ecd02a0SRichard Henderson     if (!tcg_resolve_relocs(s)) {
61107ecd02a0SRichard Henderson         return -2;
61117ecd02a0SRichard Henderson     }
6112c896fe29Sbellard 
6113df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
6114c896fe29Sbellard     /* flush instruction cache */
6115db0c51a3SRichard Henderson     flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf),
6116db0c51a3SRichard Henderson                         (uintptr_t)s->code_buf,
61171da8de39SRichard Henderson                         tcg_ptr_byte_diff(s->code_ptr, s->code_buf));
6118df5d2b16SRichard Henderson #endif
61192aeabc08SStefan Weil 
61201813e175SRichard Henderson     return tcg_current_code_size(s);
6121c896fe29Sbellard }
6122c896fe29Sbellard 
61233a841ab5SDaniel P. Berrangé void tcg_dump_info(GString *buf)
6124a23a9ec6Sbellard {
61253a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "[TCG profiler not compiled]\n");
6126a23a9ec6Sbellard }
6127813da627SRichard Henderson 
6128813da627SRichard Henderson #ifdef ELF_HOST_MACHINE
61295872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things:
61305872bbf2SRichard Henderson 
61315872bbf2SRichard Henderson    (1) Define ELF_HOST_MACHINE to indicate both what value to
61325872bbf2SRichard Henderson        put into the ELF image and to indicate support for the feature.
61335872bbf2SRichard Henderson 
61345872bbf2SRichard Henderson    (2) Define tcg_register_jit.  This should create a buffer containing
61355872bbf2SRichard Henderson        the contents of a .debug_frame section that describes the post-
61365872bbf2SRichard Henderson        prologue unwind info for the tcg machine.
61375872bbf2SRichard Henderson 
61385872bbf2SRichard Henderson    (3) Call tcg_register_jit_int, with the constructed .debug_frame.
61395872bbf2SRichard Henderson */
6140813da627SRichard Henderson 
6141813da627SRichard Henderson /* Begin GDB interface.  THE FOLLOWING MUST MATCH GDB DOCS.  */
6142813da627SRichard Henderson typedef enum {
6143813da627SRichard Henderson     JIT_NOACTION = 0,
6144813da627SRichard Henderson     JIT_REGISTER_FN,
6145813da627SRichard Henderson     JIT_UNREGISTER_FN
6146813da627SRichard Henderson } jit_actions_t;
6147813da627SRichard Henderson 
6148813da627SRichard Henderson struct jit_code_entry {
6149813da627SRichard Henderson     struct jit_code_entry *next_entry;
6150813da627SRichard Henderson     struct jit_code_entry *prev_entry;
6151813da627SRichard Henderson     const void *symfile_addr;
6152813da627SRichard Henderson     uint64_t symfile_size;
6153813da627SRichard Henderson };
6154813da627SRichard Henderson 
6155813da627SRichard Henderson struct jit_descriptor {
6156813da627SRichard Henderson     uint32_t version;
6157813da627SRichard Henderson     uint32_t action_flag;
6158813da627SRichard Henderson     struct jit_code_entry *relevant_entry;
6159813da627SRichard Henderson     struct jit_code_entry *first_entry;
6160813da627SRichard Henderson };
6161813da627SRichard Henderson 
6162813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline));
6163813da627SRichard Henderson void __jit_debug_register_code(void)
6164813da627SRichard Henderson {
6165813da627SRichard Henderson     asm("");
6166813da627SRichard Henderson }
6167813da627SRichard Henderson 
6168813da627SRichard Henderson /* Must statically initialize the version, because GDB may check
6169813da627SRichard Henderson    the version before we can set it.  */
6170813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
6171813da627SRichard Henderson 
6172813da627SRichard Henderson /* End GDB interface.  */
6173813da627SRichard Henderson 
6174813da627SRichard Henderson static int find_string(const char *strtab, const char *str)
6175813da627SRichard Henderson {
6176813da627SRichard Henderson     const char *p = strtab + 1;
6177813da627SRichard Henderson 
6178813da627SRichard Henderson     while (1) {
6179813da627SRichard Henderson         if (strcmp(p, str) == 0) {
6180813da627SRichard Henderson             return p - strtab;
6181813da627SRichard Henderson         }
6182813da627SRichard Henderson         p += strlen(p) + 1;
6183813da627SRichard Henderson     }
6184813da627SRichard Henderson }
6185813da627SRichard Henderson 
6186755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf_ptr, size_t buf_size,
61872c90784aSRichard Henderson                                  const void *debug_frame,
61882c90784aSRichard Henderson                                  size_t debug_frame_size)
6189813da627SRichard Henderson {
61905872bbf2SRichard Henderson     struct __attribute__((packed)) DebugInfo {
61915872bbf2SRichard Henderson         uint32_t  len;
61925872bbf2SRichard Henderson         uint16_t  version;
61935872bbf2SRichard Henderson         uint32_t  abbrev;
61945872bbf2SRichard Henderson         uint8_t   ptr_size;
61955872bbf2SRichard Henderson         uint8_t   cu_die;
61965872bbf2SRichard Henderson         uint16_t  cu_lang;
61975872bbf2SRichard Henderson         uintptr_t cu_low_pc;
61985872bbf2SRichard Henderson         uintptr_t cu_high_pc;
61995872bbf2SRichard Henderson         uint8_t   fn_die;
62005872bbf2SRichard Henderson         char      fn_name[16];
62015872bbf2SRichard Henderson         uintptr_t fn_low_pc;
62025872bbf2SRichard Henderson         uintptr_t fn_high_pc;
62035872bbf2SRichard Henderson         uint8_t   cu_eoc;
62045872bbf2SRichard Henderson     };
6205813da627SRichard Henderson 
6206813da627SRichard Henderson     struct ElfImage {
6207813da627SRichard Henderson         ElfW(Ehdr) ehdr;
6208813da627SRichard Henderson         ElfW(Phdr) phdr;
62095872bbf2SRichard Henderson         ElfW(Shdr) shdr[7];
62105872bbf2SRichard Henderson         ElfW(Sym)  sym[2];
62115872bbf2SRichard Henderson         struct DebugInfo di;
62125872bbf2SRichard Henderson         uint8_t    da[24];
62135872bbf2SRichard Henderson         char       str[80];
62145872bbf2SRichard Henderson     };
62155872bbf2SRichard Henderson 
62165872bbf2SRichard Henderson     struct ElfImage *img;
62175872bbf2SRichard Henderson 
62185872bbf2SRichard Henderson     static const struct ElfImage img_template = {
62195872bbf2SRichard Henderson         .ehdr = {
62205872bbf2SRichard Henderson             .e_ident[EI_MAG0] = ELFMAG0,
62215872bbf2SRichard Henderson             .e_ident[EI_MAG1] = ELFMAG1,
62225872bbf2SRichard Henderson             .e_ident[EI_MAG2] = ELFMAG2,
62235872bbf2SRichard Henderson             .e_ident[EI_MAG3] = ELFMAG3,
62245872bbf2SRichard Henderson             .e_ident[EI_CLASS] = ELF_CLASS,
62255872bbf2SRichard Henderson             .e_ident[EI_DATA] = ELF_DATA,
62265872bbf2SRichard Henderson             .e_ident[EI_VERSION] = EV_CURRENT,
62275872bbf2SRichard Henderson             .e_type = ET_EXEC,
62285872bbf2SRichard Henderson             .e_machine = ELF_HOST_MACHINE,
62295872bbf2SRichard Henderson             .e_version = EV_CURRENT,
62305872bbf2SRichard Henderson             .e_phoff = offsetof(struct ElfImage, phdr),
62315872bbf2SRichard Henderson             .e_shoff = offsetof(struct ElfImage, shdr),
62325872bbf2SRichard Henderson             .e_ehsize = sizeof(ElfW(Shdr)),
62335872bbf2SRichard Henderson             .e_phentsize = sizeof(ElfW(Phdr)),
62345872bbf2SRichard Henderson             .e_phnum = 1,
62355872bbf2SRichard Henderson             .e_shentsize = sizeof(ElfW(Shdr)),
62365872bbf2SRichard Henderson             .e_shnum = ARRAY_SIZE(img->shdr),
62375872bbf2SRichard Henderson             .e_shstrndx = ARRAY_SIZE(img->shdr) - 1,
6238abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS
6239abbb3eaeSRichard Henderson             .e_flags = ELF_HOST_FLAGS,
6240abbb3eaeSRichard Henderson #endif
6241abbb3eaeSRichard Henderson #ifdef ELF_OSABI
6242abbb3eaeSRichard Henderson             .e_ident[EI_OSABI] = ELF_OSABI,
6243abbb3eaeSRichard Henderson #endif
62445872bbf2SRichard Henderson         },
62455872bbf2SRichard Henderson         .phdr = {
62465872bbf2SRichard Henderson             .p_type = PT_LOAD,
62475872bbf2SRichard Henderson             .p_flags = PF_X,
62485872bbf2SRichard Henderson         },
62495872bbf2SRichard Henderson         .shdr = {
62505872bbf2SRichard Henderson             [0] = { .sh_type = SHT_NULL },
62515872bbf2SRichard Henderson             /* Trick: The contents of code_gen_buffer are not present in
62525872bbf2SRichard Henderson                this fake ELF file; that got allocated elsewhere.  Therefore
62535872bbf2SRichard Henderson                we mark .text as SHT_NOBITS (similar to .bss) so that readers
62545872bbf2SRichard Henderson                will not look for contents.  We can record any address.  */
62555872bbf2SRichard Henderson             [1] = { /* .text */
62565872bbf2SRichard Henderson                 .sh_type = SHT_NOBITS,
62575872bbf2SRichard Henderson                 .sh_flags = SHF_EXECINSTR | SHF_ALLOC,
62585872bbf2SRichard Henderson             },
62595872bbf2SRichard Henderson             [2] = { /* .debug_info */
62605872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
62615872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, di),
62625872bbf2SRichard Henderson                 .sh_size = sizeof(struct DebugInfo),
62635872bbf2SRichard Henderson             },
62645872bbf2SRichard Henderson             [3] = { /* .debug_abbrev */
62655872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
62665872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, da),
62675872bbf2SRichard Henderson                 .sh_size = sizeof(img->da),
62685872bbf2SRichard Henderson             },
62695872bbf2SRichard Henderson             [4] = { /* .debug_frame */
62705872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
62715872bbf2SRichard Henderson                 .sh_offset = sizeof(struct ElfImage),
62725872bbf2SRichard Henderson             },
62735872bbf2SRichard Henderson             [5] = { /* .symtab */
62745872bbf2SRichard Henderson                 .sh_type = SHT_SYMTAB,
62755872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, sym),
62765872bbf2SRichard Henderson                 .sh_size = sizeof(img->sym),
62775872bbf2SRichard Henderson                 .sh_info = 1,
62785872bbf2SRichard Henderson                 .sh_link = ARRAY_SIZE(img->shdr) - 1,
62795872bbf2SRichard Henderson                 .sh_entsize = sizeof(ElfW(Sym)),
62805872bbf2SRichard Henderson             },
62815872bbf2SRichard Henderson             [6] = { /* .strtab */
62825872bbf2SRichard Henderson                 .sh_type = SHT_STRTAB,
62835872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, str),
62845872bbf2SRichard Henderson                 .sh_size = sizeof(img->str),
62855872bbf2SRichard Henderson             }
62865872bbf2SRichard Henderson         },
62875872bbf2SRichard Henderson         .sym = {
62885872bbf2SRichard Henderson             [1] = { /* code_gen_buffer */
62895872bbf2SRichard Henderson                 .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC),
62905872bbf2SRichard Henderson                 .st_shndx = 1,
62915872bbf2SRichard Henderson             }
62925872bbf2SRichard Henderson         },
62935872bbf2SRichard Henderson         .di = {
62945872bbf2SRichard Henderson             .len = sizeof(struct DebugInfo) - 4,
62955872bbf2SRichard Henderson             .version = 2,
62965872bbf2SRichard Henderson             .ptr_size = sizeof(void *),
62975872bbf2SRichard Henderson             .cu_die = 1,
62985872bbf2SRichard Henderson             .cu_lang = 0x8001,  /* DW_LANG_Mips_Assembler */
62995872bbf2SRichard Henderson             .fn_die = 2,
63005872bbf2SRichard Henderson             .fn_name = "code_gen_buffer"
63015872bbf2SRichard Henderson         },
63025872bbf2SRichard Henderson         .da = {
63035872bbf2SRichard Henderson             1,          /* abbrev number (the cu) */
63045872bbf2SRichard Henderson             0x11, 1,    /* DW_TAG_compile_unit, has children */
63055872bbf2SRichard Henderson             0x13, 0x5,  /* DW_AT_language, DW_FORM_data2 */
63065872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
63075872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
63085872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
63095872bbf2SRichard Henderson             2,          /* abbrev number (the fn) */
63105872bbf2SRichard Henderson             0x2e, 0,    /* DW_TAG_subprogram, no children */
63115872bbf2SRichard Henderson             0x3, 0x8,   /* DW_AT_name, DW_FORM_string */
63125872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
63135872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
63145872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
63155872bbf2SRichard Henderson             0           /* no more abbrev */
63165872bbf2SRichard Henderson         },
63175872bbf2SRichard Henderson         .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0"
63185872bbf2SRichard Henderson                ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer",
6319813da627SRichard Henderson     };
6320813da627SRichard Henderson 
6321813da627SRichard Henderson     /* We only need a single jit entry; statically allocate it.  */
6322813da627SRichard Henderson     static struct jit_code_entry one_entry;
6323813da627SRichard Henderson 
63245872bbf2SRichard Henderson     uintptr_t buf = (uintptr_t)buf_ptr;
6325813da627SRichard Henderson     size_t img_size = sizeof(struct ElfImage) + debug_frame_size;
63262c90784aSRichard Henderson     DebugFrameHeader *dfh;
6327813da627SRichard Henderson 
63285872bbf2SRichard Henderson     img = g_malloc(img_size);
63295872bbf2SRichard Henderson     *img = img_template;
6330813da627SRichard Henderson 
63315872bbf2SRichard Henderson     img->phdr.p_vaddr = buf;
63325872bbf2SRichard Henderson     img->phdr.p_paddr = buf;
63335872bbf2SRichard Henderson     img->phdr.p_memsz = buf_size;
6334813da627SRichard Henderson 
63355872bbf2SRichard Henderson     img->shdr[1].sh_name = find_string(img->str, ".text");
63365872bbf2SRichard Henderson     img->shdr[1].sh_addr = buf;
63375872bbf2SRichard Henderson     img->shdr[1].sh_size = buf_size;
6338813da627SRichard Henderson 
63395872bbf2SRichard Henderson     img->shdr[2].sh_name = find_string(img->str, ".debug_info");
63405872bbf2SRichard Henderson     img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev");
63415872bbf2SRichard Henderson 
63425872bbf2SRichard Henderson     img->shdr[4].sh_name = find_string(img->str, ".debug_frame");
63435872bbf2SRichard Henderson     img->shdr[4].sh_size = debug_frame_size;
63445872bbf2SRichard Henderson 
63455872bbf2SRichard Henderson     img->shdr[5].sh_name = find_string(img->str, ".symtab");
63465872bbf2SRichard Henderson     img->shdr[6].sh_name = find_string(img->str, ".strtab");
63475872bbf2SRichard Henderson 
63485872bbf2SRichard Henderson     img->sym[1].st_name = find_string(img->str, "code_gen_buffer");
63495872bbf2SRichard Henderson     img->sym[1].st_value = buf;
63505872bbf2SRichard Henderson     img->sym[1].st_size = buf_size;
63515872bbf2SRichard Henderson 
63525872bbf2SRichard Henderson     img->di.cu_low_pc = buf;
635345aba097SRichard Henderson     img->di.cu_high_pc = buf + buf_size;
63545872bbf2SRichard Henderson     img->di.fn_low_pc = buf;
635545aba097SRichard Henderson     img->di.fn_high_pc = buf + buf_size;
6356813da627SRichard Henderson 
63572c90784aSRichard Henderson     dfh = (DebugFrameHeader *)(img + 1);
63582c90784aSRichard Henderson     memcpy(dfh, debug_frame, debug_frame_size);
63592c90784aSRichard Henderson     dfh->fde.func_start = buf;
63602c90784aSRichard Henderson     dfh->fde.func_len = buf_size;
63612c90784aSRichard Henderson 
6362813da627SRichard Henderson #ifdef DEBUG_JIT
6363813da627SRichard Henderson     /* Enable this block to be able to debug the ELF image file creation.
6364813da627SRichard Henderson        One can use readelf, objdump, or other inspection utilities.  */
6365813da627SRichard Henderson     {
6366eb6b2edfSBin Meng         g_autofree char *jit = g_strdup_printf("%s/qemu.jit", g_get_tmp_dir());
6367eb6b2edfSBin Meng         FILE *f = fopen(jit, "w+b");
6368813da627SRichard Henderson         if (f) {
63695872bbf2SRichard Henderson             if (fwrite(img, img_size, 1, f) != img_size) {
6370813da627SRichard Henderson                 /* Avoid stupid unused return value warning for fwrite.  */
6371813da627SRichard Henderson             }
6372813da627SRichard Henderson             fclose(f);
6373813da627SRichard Henderson         }
6374813da627SRichard Henderson     }
6375813da627SRichard Henderson #endif
6376813da627SRichard Henderson 
6377813da627SRichard Henderson     one_entry.symfile_addr = img;
6378813da627SRichard Henderson     one_entry.symfile_size = img_size;
6379813da627SRichard Henderson 
6380813da627SRichard Henderson     __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
6381813da627SRichard Henderson     __jit_debug_descriptor.relevant_entry = &one_entry;
6382813da627SRichard Henderson     __jit_debug_descriptor.first_entry = &one_entry;
6383813da627SRichard Henderson     __jit_debug_register_code();
6384813da627SRichard Henderson }
6385813da627SRichard Henderson #else
63865872bbf2SRichard Henderson /* No support for the feature.  Provide the entry point expected by exec.c,
63875872bbf2SRichard Henderson    and implement the internal function we declared earlier.  */
6388813da627SRichard Henderson 
6389755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size,
63902c90784aSRichard Henderson                                  const void *debug_frame,
63912c90784aSRichard Henderson                                  size_t debug_frame_size)
6392813da627SRichard Henderson {
6393813da627SRichard Henderson }
6394813da627SRichard Henderson 
6395755bf9e5SRichard Henderson void tcg_register_jit(const void *buf, size_t buf_size)
6396813da627SRichard Henderson {
6397813da627SRichard Henderson }
6398813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */
6399db432672SRichard Henderson 
6400db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec
6401db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...)
6402db432672SRichard Henderson {
6403db432672SRichard Henderson     g_assert_not_reached();
6404db432672SRichard Henderson }
6405db432672SRichard Henderson #endif
6406