xref: /qemu/tcg/tcg.c (revision d78e4a4f7b3c147af2c93b0b7b60b715ec7324d3)
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 
25c896fe29Sbellard /* define it to use liveness analysis (better code) */
268f2e8c07SKirill Batuzov #define USE_TCG_OPTIMIZATIONS
27c896fe29Sbellard 
28757e725bSPeter Maydell #include "qemu/osdep.h"
29cca82982Saurel32 
30813da627SRichard Henderson /* Define to jump the ELF file used to communicate with GDB.  */
31813da627SRichard Henderson #undef DEBUG_JIT
32813da627SRichard Henderson 
3372fd2efbSEmilio G. Cota #include "qemu/error-report.h"
34f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
351de7afc9SPaolo Bonzini #include "qemu/host-utils.h"
36d4c51a0aSMarkus Armbruster #include "qemu/qemu-print.h"
37084cfca1SRichard Henderson #include "qemu/cacheflush.h"
38ad768e6fSPeter Maydell #include "qemu/cacheinfo.h"
39533206f0SRichard W.M. Jones #include "qemu/timer.h"
40c896fe29Sbellard 
41c5d3c498SStefan Weil /* Note: the long term plan is to reduce the dependencies on the QEMU
42c896fe29Sbellard    CPU definitions. Currently they are used for qemu_ld/st
43c896fe29Sbellard    instructions */
44c896fe29Sbellard #define NO_CPU_IO_DEFS
45c896fe29Sbellard 
4663c91552SPaolo Bonzini #include "exec/exec-all.h"
47dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h"
48813da627SRichard Henderson 
49edee2579SRichard Henderson #if UINTPTR_MAX == UINT32_MAX
50813da627SRichard Henderson # define ELF_CLASS  ELFCLASS32
51edee2579SRichard Henderson #else
52edee2579SRichard Henderson # define ELF_CLASS  ELFCLASS64
53813da627SRichard Henderson #endif
54e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN
55813da627SRichard Henderson # define ELF_DATA   ELFDATA2MSB
56813da627SRichard Henderson #else
57813da627SRichard Henderson # define ELF_DATA   ELFDATA2LSB
58813da627SRichard Henderson #endif
59813da627SRichard Henderson 
60c896fe29Sbellard #include "elf.h"
61508127e2SPaolo Bonzini #include "exec/log.h"
62d2ba8026SRichard Henderson #include "tcg/tcg-ldst.h"
6347f7313dSRichard Henderson #include "tcg/tcg-temp-internal.h"
645ff7258cSRichard Henderson #include "tcg-internal.h"
655584e2dbSIlya Leoshkevich #include "accel/tcg/perf.h"
66c896fe29Sbellard 
67139c1837SPaolo Bonzini /* Forward declarations for functions declared in tcg-target.c.inc and
68ce151109SPeter Maydell    used here. */
69e4d58b41SRichard Henderson static void tcg_target_init(TCGContext *s);
70e4d58b41SRichard Henderson static void tcg_target_qemu_prologue(TCGContext *s);
716ac17786SRichard Henderson static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
722ba7fae2SRichard Henderson                         intptr_t value, intptr_t addend);
73c896fe29Sbellard 
74497a22ebSRichard Henderson /* The CIE and FDE header definitions will be common to all hosts.  */
75497a22ebSRichard Henderson typedef struct {
76497a22ebSRichard Henderson     uint32_t len __attribute__((aligned((sizeof(void *)))));
77497a22ebSRichard Henderson     uint32_t id;
78497a22ebSRichard Henderson     uint8_t version;
79497a22ebSRichard Henderson     char augmentation[1];
80497a22ebSRichard Henderson     uint8_t code_align;
81497a22ebSRichard Henderson     uint8_t data_align;
82497a22ebSRichard Henderson     uint8_t return_column;
83497a22ebSRichard Henderson } DebugFrameCIE;
84497a22ebSRichard Henderson 
85497a22ebSRichard Henderson typedef struct QEMU_PACKED {
86497a22ebSRichard Henderson     uint32_t len __attribute__((aligned((sizeof(void *)))));
87497a22ebSRichard Henderson     uint32_t cie_offset;
88edee2579SRichard Henderson     uintptr_t func_start;
89edee2579SRichard Henderson     uintptr_t func_len;
90497a22ebSRichard Henderson } DebugFrameFDEHeader;
91497a22ebSRichard Henderson 
922c90784aSRichard Henderson typedef struct QEMU_PACKED {
932c90784aSRichard Henderson     DebugFrameCIE cie;
942c90784aSRichard Henderson     DebugFrameFDEHeader fde;
952c90784aSRichard Henderson } DebugFrameHeader;
962c90784aSRichard Henderson 
972528f771SRichard Henderson typedef struct TCGLabelQemuLdst {
982528f771SRichard Henderson     bool is_ld;             /* qemu_ld: true, qemu_st: false */
992528f771SRichard Henderson     MemOpIdx oi;
1002528f771SRichard Henderson     TCGType type;           /* result type of a load */
1012528f771SRichard Henderson     TCGReg addrlo_reg;      /* reg index for low word of guest virtual addr */
1022528f771SRichard Henderson     TCGReg addrhi_reg;      /* reg index for high word of guest virtual addr */
1032528f771SRichard Henderson     TCGReg datalo_reg;      /* reg index for low word to be loaded or stored */
1042528f771SRichard Henderson     TCGReg datahi_reg;      /* reg index for high word to be loaded or stored */
1052528f771SRichard Henderson     const tcg_insn_unit *raddr;   /* addr of the next IR of qemu_ld/st IR */
1062528f771SRichard Henderson     tcg_insn_unit *label_ptr[2]; /* label pointers to be updated */
1072528f771SRichard Henderson     QSIMPLEQ_ENTRY(TCGLabelQemuLdst) next;
1082528f771SRichard Henderson } TCGLabelQemuLdst;
1092528f771SRichard Henderson 
110755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size,
1112c90784aSRichard Henderson                                  const void *debug_frame,
1122c90784aSRichard Henderson                                  size_t debug_frame_size)
113813da627SRichard Henderson     __attribute__((unused));
114813da627SRichard Henderson 
115139c1837SPaolo Bonzini /* Forward declarations for functions declared and used in tcg-target.c.inc. */
1162a534affSRichard Henderson static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
117a05b5b9bSRichard Henderson                        intptr_t arg2);
11878113e83SRichard Henderson static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
119c0ad3001SStefan Weil static void tcg_out_movi(TCGContext *s, TCGType type,
1202a534affSRichard Henderson                          TCGReg ret, tcg_target_long arg);
121678155b2SRichard Henderson static void tcg_out_ext8s(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
122753e42eaSRichard Henderson static void tcg_out_ext16s(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
123d0e66c89SRichard Henderson static void tcg_out_ext8u(TCGContext *s, TCGReg ret, TCGReg arg);
124379afdffSRichard Henderson static void tcg_out_ext16u(TCGContext *s, TCGReg ret, TCGReg arg);
12552bf3398SRichard Henderson static void tcg_out_ext32s(TCGContext *s, TCGReg ret, TCGReg arg);
1269ecf5f61SRichard Henderson static void tcg_out_ext32u(TCGContext *s, TCGReg ret, TCGReg arg);
1279c6aa274SRichard Henderson static void tcg_out_exts_i32_i64(TCGContext *s, TCGReg ret, TCGReg arg);
128b9bfe000SRichard Henderson static void tcg_out_extu_i32_i64(TCGContext *s, TCGReg ret, TCGReg arg);
129b8b94ac6SRichard Henderson static void tcg_out_extrl_i64_i32(TCGContext *s, TCGReg ret, TCGReg arg);
130313bdea8SRichard Henderson static void tcg_out_addi_ptr(TCGContext *s, TCGReg, TCGReg, tcg_target_long);
131129f1f9eSRichard Henderson static bool tcg_out_xchg(TCGContext *s, TCGType type, TCGReg r1, TCGReg r2);
132b55a8d9dSRichard Henderson static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg);
133cf7d6b8eSRichard Henderson static void tcg_out_goto_tb(TCGContext *s, int which);
1345e8892dbSMiroslav Rezanina static void tcg_out_op(TCGContext *s, TCGOpcode opc,
1355e8892dbSMiroslav Rezanina                        const TCGArg args[TCG_MAX_OP_ARGS],
1365e8892dbSMiroslav Rezanina                        const int const_args[TCG_MAX_OP_ARGS]);
137d2fd745fSRichard Henderson #if TCG_TARGET_MAYBE_vec
138e7632cfaSRichard Henderson static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
139e7632cfaSRichard Henderson                             TCGReg dst, TCGReg src);
140d6ecb4a9SRichard Henderson static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
141d6ecb4a9SRichard Henderson                              TCGReg dst, TCGReg base, intptr_t offset);
1424e186175SRichard Henderson static void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece,
1434e186175SRichard Henderson                              TCGReg dst, int64_t arg);
1445e8892dbSMiroslav Rezanina static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
1455e8892dbSMiroslav Rezanina                            unsigned vecl, unsigned vece,
1465e8892dbSMiroslav Rezanina                            const TCGArg args[TCG_MAX_OP_ARGS],
1475e8892dbSMiroslav Rezanina                            const int const_args[TCG_MAX_OP_ARGS]);
148d2fd745fSRichard Henderson #else
149e7632cfaSRichard Henderson static inline bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
150e7632cfaSRichard Henderson                                    TCGReg dst, TCGReg src)
151e7632cfaSRichard Henderson {
152e7632cfaSRichard Henderson     g_assert_not_reached();
153e7632cfaSRichard Henderson }
154d6ecb4a9SRichard Henderson static inline bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
155d6ecb4a9SRichard Henderson                                     TCGReg dst, TCGReg base, intptr_t offset)
156d6ecb4a9SRichard Henderson {
157d6ecb4a9SRichard Henderson     g_assert_not_reached();
158d6ecb4a9SRichard Henderson }
1594e186175SRichard Henderson static inline void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece,
1604e186175SRichard Henderson                                     TCGReg dst, int64_t arg)
161e7632cfaSRichard Henderson {
162e7632cfaSRichard Henderson     g_assert_not_reached();
163e7632cfaSRichard Henderson }
1645e8892dbSMiroslav Rezanina static inline void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
1655e8892dbSMiroslav Rezanina                                   unsigned vecl, unsigned vece,
1665e8892dbSMiroslav Rezanina                                   const TCGArg args[TCG_MAX_OP_ARGS],
1675e8892dbSMiroslav Rezanina                                   const int const_args[TCG_MAX_OP_ARGS])
168d2fd745fSRichard Henderson {
169d2fd745fSRichard Henderson     g_assert_not_reached();
170d2fd745fSRichard Henderson }
171d2fd745fSRichard Henderson #endif
1722a534affSRichard Henderson static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
173a05b5b9bSRichard Henderson                        intptr_t arg2);
17459d7c14eSRichard Henderson static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
17559d7c14eSRichard Henderson                         TCGReg base, intptr_t ofs);
1767b7d8b2dSRichard Henderson static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target,
177cee44b03SRichard Henderson                          const TCGHelperInfo *info);
1785e3d0c19SRichard Henderson static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot);
179a4fbbd77SRichard Henderson static bool tcg_target_const_match(int64_t val, TCGType type, int ct);
180659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
181aeee05f5SRichard Henderson static int tcg_out_ldst_finalize(TCGContext *s);
182659ef5cbSRichard Henderson #endif
183c896fe29Sbellard 
18442eb6dfcSRichard Henderson TCGContext tcg_init_ctx;
18542eb6dfcSRichard Henderson __thread TCGContext *tcg_ctx;
18642eb6dfcSRichard Henderson 
1875ff7258cSRichard Henderson TCGContext **tcg_ctxs;
1880e2d61cfSRichard Henderson unsigned int tcg_cur_ctxs;
1890e2d61cfSRichard Henderson unsigned int tcg_max_ctxs;
1901c2adb95SRichard Henderson TCGv_env cpu_env = 0;
191c8bc1168SRichard Henderson const void *tcg_code_gen_epilogue;
192db0c51a3SRichard Henderson uintptr_t tcg_splitwx_diff;
193df2cce29SEmilio G. Cota 
194b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
195b91ccb31SRichard Henderson tcg_prologue_fn *tcg_qemu_tb_exec;
196b91ccb31SRichard Henderson #endif
197b91ccb31SRichard Henderson 
198d2fd745fSRichard Henderson static TCGRegSet tcg_target_available_regs[TCG_TYPE_COUNT];
199b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs;
200c896fe29Sbellard 
2011813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1
2024196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v)
203c896fe29Sbellard {
204c896fe29Sbellard     *s->code_ptr++ = v;
205c896fe29Sbellard }
206c896fe29Sbellard 
2074196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p,
2084196dca6SPeter Maydell                                                       uint8_t v)
2095c53bb81SPeter Maydell {
2101813e175SRichard Henderson     *p = v;
2115c53bb81SPeter Maydell }
2121813e175SRichard Henderson #endif
2135c53bb81SPeter Maydell 
2141813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2
2154196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v)
216c896fe29Sbellard {
2171813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
2181813e175SRichard Henderson         *s->code_ptr++ = v;
2191813e175SRichard Henderson     } else {
2201813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2214387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2221813e175SRichard Henderson         s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE);
2231813e175SRichard Henderson     }
224c896fe29Sbellard }
225c896fe29Sbellard 
2264196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p,
2274196dca6SPeter Maydell                                                        uint16_t v)
2285c53bb81SPeter Maydell {
2291813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
2301813e175SRichard Henderson         *p = v;
2311813e175SRichard Henderson     } else {
2325c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2335c53bb81SPeter Maydell     }
2341813e175SRichard Henderson }
2351813e175SRichard Henderson #endif
2365c53bb81SPeter Maydell 
2371813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4
2384196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v)
239c896fe29Sbellard {
2401813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
2411813e175SRichard Henderson         *s->code_ptr++ = v;
2421813e175SRichard Henderson     } else {
2431813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2444387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2451813e175SRichard Henderson         s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE);
2461813e175SRichard Henderson     }
247c896fe29Sbellard }
248c896fe29Sbellard 
2494196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p,
2504196dca6SPeter Maydell                                                        uint32_t v)
2515c53bb81SPeter Maydell {
2521813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
2531813e175SRichard Henderson         *p = v;
2541813e175SRichard Henderson     } else {
2555c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2565c53bb81SPeter Maydell     }
2571813e175SRichard Henderson }
2581813e175SRichard Henderson #endif
2595c53bb81SPeter Maydell 
2601813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 8
2614196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v)
262ac26eb69SRichard Henderson {
2631813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
2641813e175SRichard Henderson         *s->code_ptr++ = v;
2651813e175SRichard Henderson     } else {
2661813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2674387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2681813e175SRichard Henderson         s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE);
2691813e175SRichard Henderson     }
270ac26eb69SRichard Henderson }
271ac26eb69SRichard Henderson 
2724196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p,
2734196dca6SPeter Maydell                                                        uint64_t v)
2745c53bb81SPeter Maydell {
2751813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
2761813e175SRichard Henderson         *p = v;
2771813e175SRichard Henderson     } else {
2785c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2795c53bb81SPeter Maydell     }
2801813e175SRichard Henderson }
2811813e175SRichard Henderson #endif
2825c53bb81SPeter Maydell 
283c896fe29Sbellard /* label relocation processing */
284c896fe29Sbellard 
2851813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
286bec16311SRichard Henderson                           TCGLabel *l, intptr_t addend)
287c896fe29Sbellard {
2887ecd02a0SRichard Henderson     TCGRelocation *r = tcg_malloc(sizeof(TCGRelocation));
289c896fe29Sbellard 
290c896fe29Sbellard     r->type = type;
291c896fe29Sbellard     r->ptr = code_ptr;
292c896fe29Sbellard     r->addend = addend;
2937ecd02a0SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next);
294c896fe29Sbellard }
295c896fe29Sbellard 
29692ab8e7dSRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l)
297c896fe29Sbellard {
298eabb7b91SAurelien Jarno     tcg_debug_assert(!l->has_value);
299c896fe29Sbellard     l->has_value = 1;
30092ab8e7dSRichard Henderson     l->u.value_ptr = tcg_splitwx_to_rx(s->code_ptr);
301c896fe29Sbellard }
302c896fe29Sbellard 
30342a268c2SRichard Henderson TCGLabel *gen_new_label(void)
304c896fe29Sbellard {
305b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
30651e3972cSRichard Henderson     TCGLabel *l = tcg_malloc(sizeof(TCGLabel));
307c896fe29Sbellard 
3087ecd02a0SRichard Henderson     memset(l, 0, sizeof(TCGLabel));
3097ecd02a0SRichard Henderson     l->id = s->nb_labels++;
310f85b1fc4SRichard Henderson     QSIMPLEQ_INIT(&l->branches);
3117ecd02a0SRichard Henderson     QSIMPLEQ_INIT(&l->relocs);
3127ecd02a0SRichard Henderson 
313bef16ab4SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&s->labels, l, next);
31442a268c2SRichard Henderson 
31542a268c2SRichard Henderson     return l;
316c896fe29Sbellard }
317c896fe29Sbellard 
3187ecd02a0SRichard Henderson static bool tcg_resolve_relocs(TCGContext *s)
3197ecd02a0SRichard Henderson {
3207ecd02a0SRichard Henderson     TCGLabel *l;
3217ecd02a0SRichard Henderson 
3227ecd02a0SRichard Henderson     QSIMPLEQ_FOREACH(l, &s->labels, next) {
3237ecd02a0SRichard Henderson         TCGRelocation *r;
3247ecd02a0SRichard Henderson         uintptr_t value = l->u.value;
3257ecd02a0SRichard Henderson 
3267ecd02a0SRichard Henderson         QSIMPLEQ_FOREACH(r, &l->relocs, next) {
3277ecd02a0SRichard Henderson             if (!patch_reloc(r->ptr, r->type, value, r->addend)) {
3287ecd02a0SRichard Henderson                 return false;
3297ecd02a0SRichard Henderson             }
3307ecd02a0SRichard Henderson         }
3317ecd02a0SRichard Henderson     }
3327ecd02a0SRichard Henderson     return true;
3337ecd02a0SRichard Henderson }
3347ecd02a0SRichard Henderson 
3359f754620SRichard Henderson static void set_jmp_reset_offset(TCGContext *s, int which)
3369f754620SRichard Henderson {
337f14bed3fSRichard Henderson     /*
338f14bed3fSRichard Henderson      * We will check for overflow at the end of the opcode loop in
339f14bed3fSRichard Henderson      * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX.
340f14bed3fSRichard Henderson      */
341b7e4afbdSRichard Henderson     s->gen_tb->jmp_reset_offset[which] = tcg_current_code_size(s);
3429f754620SRichard Henderson }
3439f754620SRichard Henderson 
344b52a2c03SRichard Henderson static void G_GNUC_UNUSED set_jmp_insn_offset(TCGContext *s, int which)
345b52a2c03SRichard Henderson {
346b52a2c03SRichard Henderson     /*
347b52a2c03SRichard Henderson      * We will check for overflow at the end of the opcode loop in
348b52a2c03SRichard Henderson      * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX.
349b52a2c03SRichard Henderson      */
3509da6079bSRichard Henderson     s->gen_tb->jmp_insn_offset[which] = tcg_current_code_size(s);
351b52a2c03SRichard Henderson }
352b52a2c03SRichard Henderson 
353becc452aSRichard Henderson static uintptr_t G_GNUC_UNUSED get_jmp_target_addr(TCGContext *s, int which)
354becc452aSRichard Henderson {
355becc452aSRichard Henderson     /*
356becc452aSRichard Henderson      * Return the read-execute version of the pointer, for the benefit
357becc452aSRichard Henderson      * of any pc-relative addressing mode.
358becc452aSRichard Henderson      */
3599da6079bSRichard Henderson     return (uintptr_t)tcg_splitwx_to_rx(&s->gen_tb->jmp_target_addr[which]);
360becc452aSRichard Henderson }
361becc452aSRichard Henderson 
362db6b7d0cSRichard Henderson /* Signal overflow, starting over with fewer guest insns. */
3638905770bSMarc-André Lureau static G_NORETURN
3648905770bSMarc-André Lureau void tcg_raise_tb_overflow(TCGContext *s)
365db6b7d0cSRichard Henderson {
366db6b7d0cSRichard Henderson     siglongjmp(s->jmp_trans, -2);
367db6b7d0cSRichard Henderson }
368db6b7d0cSRichard Henderson 
369129f1f9eSRichard Henderson typedef struct TCGMovExtend {
370129f1f9eSRichard Henderson     TCGReg dst;
371129f1f9eSRichard Henderson     TCGReg src;
372129f1f9eSRichard Henderson     TCGType dst_type;
373129f1f9eSRichard Henderson     TCGType src_type;
374129f1f9eSRichard Henderson     MemOp src_ext;
375129f1f9eSRichard Henderson } TCGMovExtend;
376129f1f9eSRichard Henderson 
377b3dfd5fcSRichard Henderson /**
378b3dfd5fcSRichard Henderson  * tcg_out_movext -- move and extend
379b3dfd5fcSRichard Henderson  * @s: tcg context
380b3dfd5fcSRichard Henderson  * @dst_type: integral type for destination
381b3dfd5fcSRichard Henderson  * @dst: destination register
382b3dfd5fcSRichard Henderson  * @src_type: integral type for source
383b3dfd5fcSRichard Henderson  * @src_ext: extension to apply to source
384b3dfd5fcSRichard Henderson  * @src: source register
385b3dfd5fcSRichard Henderson  *
386b3dfd5fcSRichard Henderson  * Move or extend @src into @dst, depending on @src_ext and the types.
387b3dfd5fcSRichard Henderson  */
388129f1f9eSRichard Henderson static void tcg_out_movext(TCGContext *s, TCGType dst_type, TCGReg dst,
389b3dfd5fcSRichard Henderson                            TCGType src_type, MemOp src_ext, TCGReg src)
390b3dfd5fcSRichard Henderson {
391b3dfd5fcSRichard Henderson     switch (src_ext) {
392b3dfd5fcSRichard Henderson     case MO_UB:
393b3dfd5fcSRichard Henderson         tcg_out_ext8u(s, dst, src);
394b3dfd5fcSRichard Henderson         break;
395b3dfd5fcSRichard Henderson     case MO_SB:
396b3dfd5fcSRichard Henderson         tcg_out_ext8s(s, dst_type, dst, src);
397b3dfd5fcSRichard Henderson         break;
398b3dfd5fcSRichard Henderson     case MO_UW:
399b3dfd5fcSRichard Henderson         tcg_out_ext16u(s, dst, src);
400b3dfd5fcSRichard Henderson         break;
401b3dfd5fcSRichard Henderson     case MO_SW:
402b3dfd5fcSRichard Henderson         tcg_out_ext16s(s, dst_type, dst, src);
403b3dfd5fcSRichard Henderson         break;
404b3dfd5fcSRichard Henderson     case MO_UL:
405b3dfd5fcSRichard Henderson     case MO_SL:
406b3dfd5fcSRichard Henderson         if (dst_type == TCG_TYPE_I32) {
407b3dfd5fcSRichard Henderson             if (src_type == TCG_TYPE_I32) {
408b3dfd5fcSRichard Henderson                 tcg_out_mov(s, TCG_TYPE_I32, dst, src);
409b3dfd5fcSRichard Henderson             } else {
410b3dfd5fcSRichard Henderson                 tcg_out_extrl_i64_i32(s, dst, src);
411b3dfd5fcSRichard Henderson             }
412b3dfd5fcSRichard Henderson         } else if (src_type == TCG_TYPE_I32) {
413b3dfd5fcSRichard Henderson             if (src_ext & MO_SIGN) {
414b3dfd5fcSRichard Henderson                 tcg_out_exts_i32_i64(s, dst, src);
415b3dfd5fcSRichard Henderson             } else {
416b3dfd5fcSRichard Henderson                 tcg_out_extu_i32_i64(s, dst, src);
417b3dfd5fcSRichard Henderson             }
418b3dfd5fcSRichard Henderson         } else {
419b3dfd5fcSRichard Henderson             if (src_ext & MO_SIGN) {
420b3dfd5fcSRichard Henderson                 tcg_out_ext32s(s, dst, src);
421b3dfd5fcSRichard Henderson             } else {
422b3dfd5fcSRichard Henderson                 tcg_out_ext32u(s, dst, src);
423b3dfd5fcSRichard Henderson             }
424b3dfd5fcSRichard Henderson         }
425b3dfd5fcSRichard Henderson         break;
426b3dfd5fcSRichard Henderson     case MO_UQ:
427b3dfd5fcSRichard Henderson         tcg_debug_assert(TCG_TARGET_REG_BITS == 64);
428b3dfd5fcSRichard Henderson         if (dst_type == TCG_TYPE_I32) {
429b3dfd5fcSRichard Henderson             tcg_out_extrl_i64_i32(s, dst, src);
430b3dfd5fcSRichard Henderson         } else {
431b3dfd5fcSRichard Henderson             tcg_out_mov(s, TCG_TYPE_I64, dst, src);
432b3dfd5fcSRichard Henderson         }
433b3dfd5fcSRichard Henderson         break;
434b3dfd5fcSRichard Henderson     default:
435b3dfd5fcSRichard Henderson         g_assert_not_reached();
436b3dfd5fcSRichard Henderson     }
437b3dfd5fcSRichard Henderson }
438b3dfd5fcSRichard Henderson 
439129f1f9eSRichard Henderson /* Minor variations on a theme, using a structure. */
440129f1f9eSRichard Henderson static void tcg_out_movext1_new_src(TCGContext *s, const TCGMovExtend *i,
441129f1f9eSRichard Henderson                                     TCGReg src)
442129f1f9eSRichard Henderson {
443129f1f9eSRichard Henderson     tcg_out_movext(s, i->dst_type, i->dst, i->src_type, i->src_ext, src);
444129f1f9eSRichard Henderson }
445129f1f9eSRichard Henderson 
446129f1f9eSRichard Henderson static void tcg_out_movext1(TCGContext *s, const TCGMovExtend *i)
447129f1f9eSRichard Henderson {
448129f1f9eSRichard Henderson     tcg_out_movext1_new_src(s, i, i->src);
449129f1f9eSRichard Henderson }
450129f1f9eSRichard Henderson 
451129f1f9eSRichard Henderson /**
452129f1f9eSRichard Henderson  * tcg_out_movext2 -- move and extend two pair
453129f1f9eSRichard Henderson  * @s: tcg context
454129f1f9eSRichard Henderson  * @i1: first move description
455129f1f9eSRichard Henderson  * @i2: second move description
456129f1f9eSRichard Henderson  * @scratch: temporary register, or -1 for none
457129f1f9eSRichard Henderson  *
458129f1f9eSRichard Henderson  * As tcg_out_movext, for both @i1 and @i2, caring for overlap
459129f1f9eSRichard Henderson  * between the sources and destinations.
460129f1f9eSRichard Henderson  */
461129f1f9eSRichard Henderson 
462129f1f9eSRichard Henderson static void __attribute__((unused))
463129f1f9eSRichard Henderson tcg_out_movext2(TCGContext *s, const TCGMovExtend *i1,
464129f1f9eSRichard Henderson                 const TCGMovExtend *i2, int scratch)
465129f1f9eSRichard Henderson {
466129f1f9eSRichard Henderson     TCGReg src1 = i1->src;
467129f1f9eSRichard Henderson     TCGReg src2 = i2->src;
468129f1f9eSRichard Henderson 
469129f1f9eSRichard Henderson     if (i1->dst != src2) {
470129f1f9eSRichard Henderson         tcg_out_movext1(s, i1);
471129f1f9eSRichard Henderson         tcg_out_movext1(s, i2);
472129f1f9eSRichard Henderson         return;
473129f1f9eSRichard Henderson     }
474129f1f9eSRichard Henderson     if (i2->dst == src1) {
475129f1f9eSRichard Henderson         TCGType src1_type = i1->src_type;
476129f1f9eSRichard Henderson         TCGType src2_type = i2->src_type;
477129f1f9eSRichard Henderson 
478129f1f9eSRichard Henderson         if (tcg_out_xchg(s, MAX(src1_type, src2_type), src1, src2)) {
479129f1f9eSRichard Henderson             /* The data is now in the correct registers, now extend. */
480129f1f9eSRichard Henderson             src1 = i2->src;
481129f1f9eSRichard Henderson             src2 = i1->src;
482129f1f9eSRichard Henderson         } else {
483129f1f9eSRichard Henderson             tcg_debug_assert(scratch >= 0);
484129f1f9eSRichard Henderson             tcg_out_mov(s, src1_type, scratch, src1);
485129f1f9eSRichard Henderson             src1 = scratch;
486129f1f9eSRichard Henderson         }
487129f1f9eSRichard Henderson     }
488129f1f9eSRichard Henderson     tcg_out_movext1_new_src(s, i2, src2);
489129f1f9eSRichard Henderson     tcg_out_movext1_new_src(s, i1, src1);
490129f1f9eSRichard Henderson }
491129f1f9eSRichard Henderson 
4924c22e840SRichard Henderson #define C_PFX1(P, A)                    P##A
4934c22e840SRichard Henderson #define C_PFX2(P, A, B)                 P##A##_##B
4944c22e840SRichard Henderson #define C_PFX3(P, A, B, C)              P##A##_##B##_##C
4954c22e840SRichard Henderson #define C_PFX4(P, A, B, C, D)           P##A##_##B##_##C##_##D
4964c22e840SRichard Henderson #define C_PFX5(P, A, B, C, D, E)        P##A##_##B##_##C##_##D##_##E
4974c22e840SRichard Henderson #define C_PFX6(P, A, B, C, D, E, F)     P##A##_##B##_##C##_##D##_##E##_##F
4984c22e840SRichard Henderson 
4994c22e840SRichard Henderson /* Define an enumeration for the various combinations. */
5004c22e840SRichard Henderson 
5014c22e840SRichard Henderson #define C_O0_I1(I1)                     C_PFX1(c_o0_i1_, I1),
5024c22e840SRichard Henderson #define C_O0_I2(I1, I2)                 C_PFX2(c_o0_i2_, I1, I2),
5034c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3)             C_PFX3(c_o0_i3_, I1, I2, I3),
5044c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4)         C_PFX4(c_o0_i4_, I1, I2, I3, I4),
5054c22e840SRichard Henderson 
5064c22e840SRichard Henderson #define C_O1_I1(O1, I1)                 C_PFX2(c_o1_i1_, O1, I1),
5074c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2)             C_PFX3(c_o1_i2_, O1, I1, I2),
5084c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3)         C_PFX4(c_o1_i3_, O1, I1, I2, I3),
5094c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4)     C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4),
5104c22e840SRichard Henderson 
5114c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2)             C_PFX3(c_n1_i2_, O1, I1, I2),
5124c22e840SRichard Henderson 
5134c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1)             C_PFX3(c_o2_i1_, O1, O2, I1),
5144c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2)         C_PFX4(c_o2_i2_, O1, O2, I1, I2),
5154c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3)     C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3),
5164c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4),
5174c22e840SRichard Henderson 
5184c22e840SRichard Henderson typedef enum {
5194c22e840SRichard Henderson #include "tcg-target-con-set.h"
5204c22e840SRichard Henderson } TCGConstraintSetIndex;
5214c22e840SRichard Henderson 
5224c22e840SRichard Henderson static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode);
5234c22e840SRichard Henderson 
5244c22e840SRichard Henderson #undef C_O0_I1
5254c22e840SRichard Henderson #undef C_O0_I2
5264c22e840SRichard Henderson #undef C_O0_I3
5274c22e840SRichard Henderson #undef C_O0_I4
5284c22e840SRichard Henderson #undef C_O1_I1
5294c22e840SRichard Henderson #undef C_O1_I2
5304c22e840SRichard Henderson #undef C_O1_I3
5314c22e840SRichard Henderson #undef C_O1_I4
5324c22e840SRichard Henderson #undef C_N1_I2
5334c22e840SRichard Henderson #undef C_O2_I1
5344c22e840SRichard Henderson #undef C_O2_I2
5354c22e840SRichard Henderson #undef C_O2_I3
5364c22e840SRichard Henderson #undef C_O2_I4
5374c22e840SRichard Henderson 
5384c22e840SRichard Henderson /* Put all of the constraint sets into an array, indexed by the enum. */
5394c22e840SRichard Henderson 
5404c22e840SRichard Henderson #define C_O0_I1(I1)                     { .args_ct_str = { #I1 } },
5414c22e840SRichard Henderson #define C_O0_I2(I1, I2)                 { .args_ct_str = { #I1, #I2 } },
5424c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3)             { .args_ct_str = { #I1, #I2, #I3 } },
5434c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4)         { .args_ct_str = { #I1, #I2, #I3, #I4 } },
5444c22e840SRichard Henderson 
5454c22e840SRichard Henderson #define C_O1_I1(O1, I1)                 { .args_ct_str = { #O1, #I1 } },
5464c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2)             { .args_ct_str = { #O1, #I1, #I2 } },
5474c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3)         { .args_ct_str = { #O1, #I1, #I2, #I3 } },
5484c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4)     { .args_ct_str = { #O1, #I1, #I2, #I3, #I4 } },
5494c22e840SRichard Henderson 
5504c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2)             { .args_ct_str = { "&" #O1, #I1, #I2 } },
5514c22e840SRichard Henderson 
5524c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1)             { .args_ct_str = { #O1, #O2, #I1 } },
5534c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2)         { .args_ct_str = { #O1, #O2, #I1, #I2 } },
5544c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3)     { .args_ct_str = { #O1, #O2, #I1, #I2, #I3 } },
5554c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) { .args_ct_str = { #O1, #O2, #I1, #I2, #I3, #I4 } },
5564c22e840SRichard Henderson 
5574c22e840SRichard Henderson static const TCGTargetOpDef constraint_sets[] = {
5584c22e840SRichard Henderson #include "tcg-target-con-set.h"
5594c22e840SRichard Henderson };
5604c22e840SRichard Henderson 
5614c22e840SRichard Henderson 
5624c22e840SRichard Henderson #undef C_O0_I1
5634c22e840SRichard Henderson #undef C_O0_I2
5644c22e840SRichard Henderson #undef C_O0_I3
5654c22e840SRichard Henderson #undef C_O0_I4
5664c22e840SRichard Henderson #undef C_O1_I1
5674c22e840SRichard Henderson #undef C_O1_I2
5684c22e840SRichard Henderson #undef C_O1_I3
5694c22e840SRichard Henderson #undef C_O1_I4
5704c22e840SRichard Henderson #undef C_N1_I2
5714c22e840SRichard Henderson #undef C_O2_I1
5724c22e840SRichard Henderson #undef C_O2_I2
5734c22e840SRichard Henderson #undef C_O2_I3
5744c22e840SRichard Henderson #undef C_O2_I4
5754c22e840SRichard Henderson 
5764c22e840SRichard Henderson /* Expand the enumerator to be returned from tcg_target_op_def(). */
5774c22e840SRichard Henderson 
5784c22e840SRichard Henderson #define C_O0_I1(I1)                     C_PFX1(c_o0_i1_, I1)
5794c22e840SRichard Henderson #define C_O0_I2(I1, I2)                 C_PFX2(c_o0_i2_, I1, I2)
5804c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3)             C_PFX3(c_o0_i3_, I1, I2, I3)
5814c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4)         C_PFX4(c_o0_i4_, I1, I2, I3, I4)
5824c22e840SRichard Henderson 
5834c22e840SRichard Henderson #define C_O1_I1(O1, I1)                 C_PFX2(c_o1_i1_, O1, I1)
5844c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2)             C_PFX3(c_o1_i2_, O1, I1, I2)
5854c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3)         C_PFX4(c_o1_i3_, O1, I1, I2, I3)
5864c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4)     C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4)
5874c22e840SRichard Henderson 
5884c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2)             C_PFX3(c_n1_i2_, O1, I1, I2)
5894c22e840SRichard Henderson 
5904c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1)             C_PFX3(c_o2_i1_, O1, O2, I1)
5914c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2)         C_PFX4(c_o2_i2_, O1, O2, I1, I2)
5924c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3)     C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3)
5934c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4)
5944c22e840SRichard Henderson 
595139c1837SPaolo Bonzini #include "tcg-target.c.inc"
596c896fe29Sbellard 
59738b47b19SEmilio G. Cota static void alloc_tcg_plugin_context(TCGContext *s)
59838b47b19SEmilio G. Cota {
59938b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN
60038b47b19SEmilio G. Cota     s->plugin_tb = g_new0(struct qemu_plugin_tb, 1);
60138b47b19SEmilio G. Cota     s->plugin_tb->insns =
60238b47b19SEmilio G. Cota         g_ptr_array_new_with_free_func(qemu_plugin_insn_cleanup_fn);
60338b47b19SEmilio G. Cota #endif
60438b47b19SEmilio G. Cota }
60538b47b19SEmilio G. Cota 
606e8feb96fSEmilio G. Cota /*
6073468b59eSEmilio G. Cota  * All TCG threads except the parent (i.e. the one that called tcg_context_init
6083468b59eSEmilio G. Cota  * and registered the target's TCG globals) must register with this function
6093468b59eSEmilio G. Cota  * before initiating translation.
6103468b59eSEmilio G. Cota  *
6113468b59eSEmilio G. Cota  * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation
6123468b59eSEmilio G. Cota  * of tcg_region_init() for the reasoning behind this.
6133468b59eSEmilio G. Cota  *
6143468b59eSEmilio G. Cota  * In softmmu each caller registers its context in tcg_ctxs[]. Note that in
6153468b59eSEmilio G. Cota  * softmmu tcg_ctxs[] does not track tcg_ctx_init, since the initial context
6163468b59eSEmilio G. Cota  * is not used anymore for translation once this function is called.
6173468b59eSEmilio G. Cota  *
6183468b59eSEmilio G. Cota  * Not tracking tcg_init_ctx in tcg_ctxs[] in softmmu keeps code that iterates
6193468b59eSEmilio G. Cota  * over the array (e.g. tcg_code_size() the same for both softmmu and user-mode.
6203468b59eSEmilio G. Cota  */
6213468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
6223468b59eSEmilio G. Cota void tcg_register_thread(void)
6233468b59eSEmilio G. Cota {
6243468b59eSEmilio G. Cota     tcg_ctx = &tcg_init_ctx;
6253468b59eSEmilio G. Cota }
6263468b59eSEmilio G. Cota #else
6273468b59eSEmilio G. Cota void tcg_register_thread(void)
6283468b59eSEmilio G. Cota {
6293468b59eSEmilio G. Cota     TCGContext *s = g_malloc(sizeof(*s));
6303468b59eSEmilio G. Cota     unsigned int i, n;
6313468b59eSEmilio G. Cota 
6323468b59eSEmilio G. Cota     *s = tcg_init_ctx;
6333468b59eSEmilio G. Cota 
6343468b59eSEmilio G. Cota     /* Relink mem_base.  */
6353468b59eSEmilio G. Cota     for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) {
6363468b59eSEmilio G. Cota         if (tcg_init_ctx.temps[i].mem_base) {
6373468b59eSEmilio G. Cota             ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps;
6383468b59eSEmilio G. Cota             tcg_debug_assert(b >= 0 && b < n);
6393468b59eSEmilio G. Cota             s->temps[i].mem_base = &s->temps[b];
6403468b59eSEmilio G. Cota         }
6413468b59eSEmilio G. Cota     }
6423468b59eSEmilio G. Cota 
6433468b59eSEmilio G. Cota     /* Claim an entry in tcg_ctxs */
6440e2d61cfSRichard Henderson     n = qatomic_fetch_inc(&tcg_cur_ctxs);
6450e2d61cfSRichard Henderson     g_assert(n < tcg_max_ctxs);
646d73415a3SStefan Hajnoczi     qatomic_set(&tcg_ctxs[n], s);
6473468b59eSEmilio G. Cota 
64838b47b19SEmilio G. Cota     if (n > 0) {
64938b47b19SEmilio G. Cota         alloc_tcg_plugin_context(s);
650bf042e8eSRichard Henderson         tcg_region_initial_alloc(s);
65138b47b19SEmilio G. Cota     }
65238b47b19SEmilio G. Cota 
6533468b59eSEmilio G. Cota     tcg_ctx = s;
6543468b59eSEmilio G. Cota }
6553468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */
6563468b59eSEmilio G. Cota 
657c896fe29Sbellard /* pool based memory allocation */
658c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size)
659c896fe29Sbellard {
660c896fe29Sbellard     TCGPool *p;
661c896fe29Sbellard     int pool_size;
662c896fe29Sbellard 
663c896fe29Sbellard     if (size > TCG_POOL_CHUNK_SIZE) {
664c896fe29Sbellard         /* big malloc: insert a new pool (XXX: could optimize) */
6657267c094SAnthony Liguori         p = g_malloc(sizeof(TCGPool) + size);
666c896fe29Sbellard         p->size = size;
6674055299eSKirill Batuzov         p->next = s->pool_first_large;
6684055299eSKirill Batuzov         s->pool_first_large = p;
6694055299eSKirill Batuzov         return p->data;
670c896fe29Sbellard     } else {
671c896fe29Sbellard         p = s->pool_current;
672c896fe29Sbellard         if (!p) {
673c896fe29Sbellard             p = s->pool_first;
674c896fe29Sbellard             if (!p)
675c896fe29Sbellard                 goto new_pool;
676c896fe29Sbellard         } else {
677c896fe29Sbellard             if (!p->next) {
678c896fe29Sbellard             new_pool:
679c896fe29Sbellard                 pool_size = TCG_POOL_CHUNK_SIZE;
6807267c094SAnthony Liguori                 p = g_malloc(sizeof(TCGPool) + pool_size);
681c896fe29Sbellard                 p->size = pool_size;
682c896fe29Sbellard                 p->next = NULL;
683a813e36fSRichard Henderson                 if (s->pool_current) {
684c896fe29Sbellard                     s->pool_current->next = p;
685a813e36fSRichard Henderson                 } else {
686c896fe29Sbellard                     s->pool_first = p;
687a813e36fSRichard Henderson                 }
688c896fe29Sbellard             } else {
689c896fe29Sbellard                 p = p->next;
690c896fe29Sbellard             }
691c896fe29Sbellard         }
692c896fe29Sbellard     }
693c896fe29Sbellard     s->pool_current = p;
694c896fe29Sbellard     s->pool_cur = p->data + size;
695c896fe29Sbellard     s->pool_end = p->data + p->size;
696c896fe29Sbellard     return p->data;
697c896fe29Sbellard }
698c896fe29Sbellard 
699c896fe29Sbellard void tcg_pool_reset(TCGContext *s)
700c896fe29Sbellard {
7014055299eSKirill Batuzov     TCGPool *p, *t;
7024055299eSKirill Batuzov     for (p = s->pool_first_large; p; p = t) {
7034055299eSKirill Batuzov         t = p->next;
7044055299eSKirill Batuzov         g_free(p);
7054055299eSKirill Batuzov     }
7064055299eSKirill Batuzov     s->pool_first_large = NULL;
707c896fe29Sbellard     s->pool_cur = s->pool_end = NULL;
708c896fe29Sbellard     s->pool_current = NULL;
709c896fe29Sbellard }
710c896fe29Sbellard 
7112ef6175aSRichard Henderson #include "exec/helper-proto.h"
7122ef6175aSRichard Henderson 
71339004a71SRichard Henderson static TCGHelperInfo all_helpers[] = {
7142ef6175aSRichard Henderson #include "exec/helper-tcg.h"
715100b5e01SRichard Henderson };
716619205fdSEmilio G. Cota static GHashTable *helper_table;
717100b5e01SRichard Henderson 
71822f15579SRichard Henderson #ifdef CONFIG_TCG_INTERPRETER
719c6ef8c7bSPhilippe Mathieu-Daudé static ffi_type *typecode_to_ffi(int argmask)
720c6ef8c7bSPhilippe Mathieu-Daudé {
721e9709e17SRichard Henderson     /*
722e9709e17SRichard Henderson      * libffi does not support __int128_t, so we have forced Int128
723e9709e17SRichard Henderson      * to use the structure definition instead of the builtin type.
724e9709e17SRichard Henderson      */
725e9709e17SRichard Henderson     static ffi_type *ffi_type_i128_elements[3] = {
726e9709e17SRichard Henderson         &ffi_type_uint64,
727e9709e17SRichard Henderson         &ffi_type_uint64,
728e9709e17SRichard Henderson         NULL
729e9709e17SRichard Henderson     };
730e9709e17SRichard Henderson     static ffi_type ffi_type_i128 = {
731e9709e17SRichard Henderson         .size = 16,
732e9709e17SRichard Henderson         .alignment = __alignof__(Int128),
733e9709e17SRichard Henderson         .type = FFI_TYPE_STRUCT,
734e9709e17SRichard Henderson         .elements = ffi_type_i128_elements,
735e9709e17SRichard Henderson     };
736e9709e17SRichard Henderson 
737c6ef8c7bSPhilippe Mathieu-Daudé     switch (argmask) {
738c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_void:
739c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_void;
740c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_i32:
741c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_uint32;
742c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_s32:
743c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_sint32;
744c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_i64:
745c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_uint64;
746c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_s64:
747c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_sint64;
748c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_ptr:
749c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_pointer;
750e9709e17SRichard Henderson     case dh_typecode_i128:
751e9709e17SRichard Henderson         return &ffi_type_i128;
752c6ef8c7bSPhilippe Mathieu-Daudé     }
753c6ef8c7bSPhilippe Mathieu-Daudé     g_assert_not_reached();
754c6ef8c7bSPhilippe Mathieu-Daudé }
7550c22e176SPhilippe Mathieu-Daudé 
7560c22e176SPhilippe Mathieu-Daudé static void init_ffi_layouts(void)
7570c22e176SPhilippe Mathieu-Daudé {
7580c22e176SPhilippe Mathieu-Daudé     /* g_direct_hash/equal for direct comparisons on uint32_t.  */
759f9c4bb80SRichard Henderson     GHashTable *ffi_table = g_hash_table_new(NULL, NULL);
760f9c4bb80SRichard Henderson 
7610c22e176SPhilippe Mathieu-Daudé     for (int i = 0; i < ARRAY_SIZE(all_helpers); ++i) {
762f9c4bb80SRichard Henderson         TCGHelperInfo *info = &all_helpers[i];
763f9c4bb80SRichard Henderson         unsigned typemask = info->typemask;
7640c22e176SPhilippe Mathieu-Daudé         gpointer hash = (gpointer)(uintptr_t)typemask;
7650c22e176SPhilippe Mathieu-Daudé         struct {
7660c22e176SPhilippe Mathieu-Daudé             ffi_cif cif;
7670c22e176SPhilippe Mathieu-Daudé             ffi_type *args[];
7680c22e176SPhilippe Mathieu-Daudé         } *ca;
7690c22e176SPhilippe Mathieu-Daudé         ffi_status status;
7700c22e176SPhilippe Mathieu-Daudé         int nargs;
771f9c4bb80SRichard Henderson         ffi_cif *cif;
7720c22e176SPhilippe Mathieu-Daudé 
773f9c4bb80SRichard Henderson         cif = g_hash_table_lookup(ffi_table, hash);
774f9c4bb80SRichard Henderson         if (cif) {
775f9c4bb80SRichard Henderson             info->cif = cif;
7760c22e176SPhilippe Mathieu-Daudé             continue;
7770c22e176SPhilippe Mathieu-Daudé         }
7780c22e176SPhilippe Mathieu-Daudé 
7790c22e176SPhilippe Mathieu-Daudé         /* Ignoring the return type, find the last non-zero field. */
7800c22e176SPhilippe Mathieu-Daudé         nargs = 32 - clz32(typemask >> 3);
7810c22e176SPhilippe Mathieu-Daudé         nargs = DIV_ROUND_UP(nargs, 3);
782e9709e17SRichard Henderson         assert(nargs <= MAX_CALL_IARGS);
7830c22e176SPhilippe Mathieu-Daudé 
7840c22e176SPhilippe Mathieu-Daudé         ca = g_malloc0(sizeof(*ca) + nargs * sizeof(ffi_type *));
7850c22e176SPhilippe Mathieu-Daudé         ca->cif.rtype = typecode_to_ffi(typemask & 7);
7860c22e176SPhilippe Mathieu-Daudé         ca->cif.nargs = nargs;
7870c22e176SPhilippe Mathieu-Daudé 
7880c22e176SPhilippe Mathieu-Daudé         if (nargs != 0) {
7890c22e176SPhilippe Mathieu-Daudé             ca->cif.arg_types = ca->args;
7900c22e176SPhilippe Mathieu-Daudé             for (int j = 0; j < nargs; ++j) {
7910c22e176SPhilippe Mathieu-Daudé                 int typecode = extract32(typemask, (j + 1) * 3, 3);
7920c22e176SPhilippe Mathieu-Daudé                 ca->args[j] = typecode_to_ffi(typecode);
7930c22e176SPhilippe Mathieu-Daudé             }
7940c22e176SPhilippe Mathieu-Daudé         }
7950c22e176SPhilippe Mathieu-Daudé 
7960c22e176SPhilippe Mathieu-Daudé         status = ffi_prep_cif(&ca->cif, FFI_DEFAULT_ABI, nargs,
7970c22e176SPhilippe Mathieu-Daudé                               ca->cif.rtype, ca->cif.arg_types);
7980c22e176SPhilippe Mathieu-Daudé         assert(status == FFI_OK);
7990c22e176SPhilippe Mathieu-Daudé 
800f9c4bb80SRichard Henderson         cif = &ca->cif;
801f9c4bb80SRichard Henderson         info->cif = cif;
802f9c4bb80SRichard Henderson         g_hash_table_insert(ffi_table, hash, (gpointer)cif);
8030c22e176SPhilippe Mathieu-Daudé     }
804f9c4bb80SRichard Henderson 
805f9c4bb80SRichard Henderson     g_hash_table_destroy(ffi_table);
8060c22e176SPhilippe Mathieu-Daudé }
8070c22e176SPhilippe Mathieu-Daudé #endif /* CONFIG_TCG_INTERPRETER */
80822f15579SRichard Henderson 
809338b61e9SRichard Henderson static inline bool arg_slot_reg_p(unsigned arg_slot)
810338b61e9SRichard Henderson {
811338b61e9SRichard Henderson     /*
812338b61e9SRichard Henderson      * Split the sizeof away from the comparison to avoid Werror from
813338b61e9SRichard Henderson      * "unsigned < 0 is always false", when iarg_regs is empty.
814338b61e9SRichard Henderson      */
815338b61e9SRichard Henderson     unsigned nreg = ARRAY_SIZE(tcg_target_call_iarg_regs);
816338b61e9SRichard Henderson     return arg_slot < nreg;
817338b61e9SRichard Henderson }
818338b61e9SRichard Henderson 
819*d78e4a4fSRichard Henderson static inline int arg_slot_stk_ofs(unsigned arg_slot)
820*d78e4a4fSRichard Henderson {
821*d78e4a4fSRichard Henderson     unsigned max = TCG_STATIC_CALL_ARGS_SIZE / sizeof(tcg_target_long);
822*d78e4a4fSRichard Henderson     unsigned stk_slot = arg_slot - ARRAY_SIZE(tcg_target_call_iarg_regs);
823*d78e4a4fSRichard Henderson 
824*d78e4a4fSRichard Henderson     tcg_debug_assert(stk_slot < max);
825*d78e4a4fSRichard Henderson     return TCG_TARGET_CALL_STACK_OFFSET + stk_slot * sizeof(tcg_target_long);
826*d78e4a4fSRichard Henderson }
827*d78e4a4fSRichard Henderson 
82839004a71SRichard Henderson typedef struct TCGCumulativeArgs {
82939004a71SRichard Henderson     int arg_idx;                /* tcg_gen_callN args[] */
83039004a71SRichard Henderson     int info_in_idx;            /* TCGHelperInfo in[] */
83139004a71SRichard Henderson     int arg_slot;               /* regs+stack slot */
83239004a71SRichard Henderson     int ref_slot;               /* stack slots for references */
83339004a71SRichard Henderson } TCGCumulativeArgs;
83439004a71SRichard Henderson 
83539004a71SRichard Henderson static void layout_arg_even(TCGCumulativeArgs *cum)
83639004a71SRichard Henderson {
83739004a71SRichard Henderson     cum->arg_slot += cum->arg_slot & 1;
83839004a71SRichard Henderson }
83939004a71SRichard Henderson 
84039004a71SRichard Henderson static void layout_arg_1(TCGCumulativeArgs *cum, TCGHelperInfo *info,
84139004a71SRichard Henderson                          TCGCallArgumentKind kind)
84239004a71SRichard Henderson {
84339004a71SRichard Henderson     TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx];
84439004a71SRichard Henderson 
84539004a71SRichard Henderson     *loc = (TCGCallArgumentLoc){
84639004a71SRichard Henderson         .kind = kind,
84739004a71SRichard Henderson         .arg_idx = cum->arg_idx,
84839004a71SRichard Henderson         .arg_slot = cum->arg_slot,
84939004a71SRichard Henderson     };
85039004a71SRichard Henderson     cum->info_in_idx++;
85139004a71SRichard Henderson     cum->arg_slot++;
85239004a71SRichard Henderson }
85339004a71SRichard Henderson 
85439004a71SRichard Henderson static void layout_arg_normal_n(TCGCumulativeArgs *cum,
85539004a71SRichard Henderson                                 TCGHelperInfo *info, int n)
85639004a71SRichard Henderson {
85739004a71SRichard Henderson     TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx];
85839004a71SRichard Henderson 
85939004a71SRichard Henderson     for (int i = 0; i < n; ++i) {
86039004a71SRichard Henderson         /* Layout all using the same arg_idx, adjusting the subindex. */
86139004a71SRichard Henderson         loc[i] = (TCGCallArgumentLoc){
86239004a71SRichard Henderson             .kind = TCG_CALL_ARG_NORMAL,
86339004a71SRichard Henderson             .arg_idx = cum->arg_idx,
86439004a71SRichard Henderson             .tmp_subindex = i,
86539004a71SRichard Henderson             .arg_slot = cum->arg_slot + i,
86639004a71SRichard Henderson         };
86739004a71SRichard Henderson     }
86839004a71SRichard Henderson     cum->info_in_idx += n;
86939004a71SRichard Henderson     cum->arg_slot += n;
87039004a71SRichard Henderson }
87139004a71SRichard Henderson 
872313bdea8SRichard Henderson static void layout_arg_by_ref(TCGCumulativeArgs *cum, TCGHelperInfo *info)
873313bdea8SRichard Henderson {
874313bdea8SRichard Henderson     TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx];
875313bdea8SRichard Henderson     int n = 128 / TCG_TARGET_REG_BITS;
876313bdea8SRichard Henderson 
877313bdea8SRichard Henderson     /* The first subindex carries the pointer. */
878313bdea8SRichard Henderson     layout_arg_1(cum, info, TCG_CALL_ARG_BY_REF);
879313bdea8SRichard Henderson 
880313bdea8SRichard Henderson     /*
881313bdea8SRichard Henderson      * The callee is allowed to clobber memory associated with
882313bdea8SRichard Henderson      * structure pass by-reference.  Therefore we must make copies.
883313bdea8SRichard Henderson      * Allocate space from "ref_slot", which will be adjusted to
884313bdea8SRichard Henderson      * follow the parameters on the stack.
885313bdea8SRichard Henderson      */
886313bdea8SRichard Henderson     loc[0].ref_slot = cum->ref_slot;
887313bdea8SRichard Henderson 
888313bdea8SRichard Henderson     /*
889313bdea8SRichard Henderson      * Subsequent words also go into the reference slot, but
890313bdea8SRichard Henderson      * do not accumulate into the regular arguments.
891313bdea8SRichard Henderson      */
892313bdea8SRichard Henderson     for (int i = 1; i < n; ++i) {
893313bdea8SRichard Henderson         loc[i] = (TCGCallArgumentLoc){
894313bdea8SRichard Henderson             .kind = TCG_CALL_ARG_BY_REF_N,
895313bdea8SRichard Henderson             .arg_idx = cum->arg_idx,
896313bdea8SRichard Henderson             .tmp_subindex = i,
897313bdea8SRichard Henderson             .ref_slot = cum->ref_slot + i,
898313bdea8SRichard Henderson         };
899313bdea8SRichard Henderson     }
900313bdea8SRichard Henderson     cum->info_in_idx += n;
901313bdea8SRichard Henderson     cum->ref_slot += n;
902313bdea8SRichard Henderson }
903313bdea8SRichard Henderson 
90439004a71SRichard Henderson static void init_call_layout(TCGHelperInfo *info)
90539004a71SRichard Henderson {
90639004a71SRichard Henderson     int max_reg_slots = ARRAY_SIZE(tcg_target_call_iarg_regs);
90739004a71SRichard Henderson     int max_stk_slots = TCG_STATIC_CALL_ARGS_SIZE / sizeof(tcg_target_long);
90839004a71SRichard Henderson     unsigned typemask = info->typemask;
90939004a71SRichard Henderson     unsigned typecode;
91039004a71SRichard Henderson     TCGCumulativeArgs cum = { };
91139004a71SRichard Henderson 
91239004a71SRichard Henderson     /*
91339004a71SRichard Henderson      * Parse and place any function return value.
91439004a71SRichard Henderson      */
91539004a71SRichard Henderson     typecode = typemask & 7;
91639004a71SRichard Henderson     switch (typecode) {
91739004a71SRichard Henderson     case dh_typecode_void:
91839004a71SRichard Henderson         info->nr_out = 0;
91939004a71SRichard Henderson         break;
92039004a71SRichard Henderson     case dh_typecode_i32:
92139004a71SRichard Henderson     case dh_typecode_s32:
92239004a71SRichard Henderson     case dh_typecode_ptr:
92339004a71SRichard Henderson         info->nr_out = 1;
92439004a71SRichard Henderson         info->out_kind = TCG_CALL_RET_NORMAL;
92539004a71SRichard Henderson         break;
92639004a71SRichard Henderson     case dh_typecode_i64:
92739004a71SRichard Henderson     case dh_typecode_s64:
92839004a71SRichard Henderson         info->nr_out = 64 / TCG_TARGET_REG_BITS;
92939004a71SRichard Henderson         info->out_kind = TCG_CALL_RET_NORMAL;
9305e3d0c19SRichard Henderson         /* Query the last register now to trigger any assert early. */
9315e3d0c19SRichard Henderson         tcg_target_call_oarg_reg(info->out_kind, info->nr_out - 1);
932466d3759SRichard Henderson         break;
933466d3759SRichard Henderson     case dh_typecode_i128:
934466d3759SRichard Henderson         info->nr_out = 128 / TCG_TARGET_REG_BITS;
9355427a9a7SRichard Henderson         info->out_kind = TCG_TARGET_CALL_RET_I128;
9365427a9a7SRichard Henderson         switch (TCG_TARGET_CALL_RET_I128) {
937466d3759SRichard Henderson         case TCG_CALL_RET_NORMAL:
9385e3d0c19SRichard Henderson             /* Query the last register now to trigger any assert early. */
9395e3d0c19SRichard Henderson             tcg_target_call_oarg_reg(info->out_kind, info->nr_out - 1);
940466d3759SRichard Henderson             break;
941c6556aa0SRichard Henderson         case TCG_CALL_RET_BY_VEC:
942c6556aa0SRichard Henderson             /* Query the single register now to trigger any assert early. */
943c6556aa0SRichard Henderson             tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0);
944c6556aa0SRichard Henderson             break;
945313bdea8SRichard Henderson         case TCG_CALL_RET_BY_REF:
946313bdea8SRichard Henderson             /*
947313bdea8SRichard Henderson              * Allocate the first argument to the output.
948313bdea8SRichard Henderson              * We don't need to store this anywhere, just make it
949313bdea8SRichard Henderson              * unavailable for use in the input loop below.
950313bdea8SRichard Henderson              */
951313bdea8SRichard Henderson             cum.arg_slot = 1;
952313bdea8SRichard Henderson             break;
953466d3759SRichard Henderson         default:
954466d3759SRichard Henderson             qemu_build_not_reached();
955466d3759SRichard Henderson         }
95639004a71SRichard Henderson         break;
95739004a71SRichard Henderson     default:
95839004a71SRichard Henderson         g_assert_not_reached();
95939004a71SRichard Henderson     }
96039004a71SRichard Henderson 
96139004a71SRichard Henderson     /*
96239004a71SRichard Henderson      * Parse and place function arguments.
96339004a71SRichard Henderson      */
96439004a71SRichard Henderson     for (typemask >>= 3; typemask; typemask >>= 3, cum.arg_idx++) {
96539004a71SRichard Henderson         TCGCallArgumentKind kind;
96639004a71SRichard Henderson         TCGType type;
96739004a71SRichard Henderson 
96839004a71SRichard Henderson         typecode = typemask & 7;
96939004a71SRichard Henderson         switch (typecode) {
97039004a71SRichard Henderson         case dh_typecode_i32:
97139004a71SRichard Henderson         case dh_typecode_s32:
97239004a71SRichard Henderson             type = TCG_TYPE_I32;
97339004a71SRichard Henderson             break;
97439004a71SRichard Henderson         case dh_typecode_i64:
97539004a71SRichard Henderson         case dh_typecode_s64:
97639004a71SRichard Henderson             type = TCG_TYPE_I64;
97739004a71SRichard Henderson             break;
97839004a71SRichard Henderson         case dh_typecode_ptr:
97939004a71SRichard Henderson             type = TCG_TYPE_PTR;
98039004a71SRichard Henderson             break;
981466d3759SRichard Henderson         case dh_typecode_i128:
982466d3759SRichard Henderson             type = TCG_TYPE_I128;
983466d3759SRichard Henderson             break;
98439004a71SRichard Henderson         default:
98539004a71SRichard Henderson             g_assert_not_reached();
98639004a71SRichard Henderson         }
98739004a71SRichard Henderson 
98839004a71SRichard Henderson         switch (type) {
98939004a71SRichard Henderson         case TCG_TYPE_I32:
99039004a71SRichard Henderson             switch (TCG_TARGET_CALL_ARG_I32) {
99139004a71SRichard Henderson             case TCG_CALL_ARG_EVEN:
99239004a71SRichard Henderson                 layout_arg_even(&cum);
99339004a71SRichard Henderson                 /* fall through */
99439004a71SRichard Henderson             case TCG_CALL_ARG_NORMAL:
99539004a71SRichard Henderson                 layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL);
99639004a71SRichard Henderson                 break;
99739004a71SRichard Henderson             case TCG_CALL_ARG_EXTEND:
99839004a71SRichard Henderson                 kind = TCG_CALL_ARG_EXTEND_U + (typecode & 1);
99939004a71SRichard Henderson                 layout_arg_1(&cum, info, kind);
100039004a71SRichard Henderson                 break;
100139004a71SRichard Henderson             default:
100239004a71SRichard Henderson                 qemu_build_not_reached();
100339004a71SRichard Henderson             }
100439004a71SRichard Henderson             break;
100539004a71SRichard Henderson 
100639004a71SRichard Henderson         case TCG_TYPE_I64:
100739004a71SRichard Henderson             switch (TCG_TARGET_CALL_ARG_I64) {
100839004a71SRichard Henderson             case TCG_CALL_ARG_EVEN:
100939004a71SRichard Henderson                 layout_arg_even(&cum);
101039004a71SRichard Henderson                 /* fall through */
101139004a71SRichard Henderson             case TCG_CALL_ARG_NORMAL:
101239004a71SRichard Henderson                 if (TCG_TARGET_REG_BITS == 32) {
101339004a71SRichard Henderson                     layout_arg_normal_n(&cum, info, 2);
101439004a71SRichard Henderson                 } else {
101539004a71SRichard Henderson                     layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL);
101639004a71SRichard Henderson                 }
101739004a71SRichard Henderson                 break;
101839004a71SRichard Henderson             default:
101939004a71SRichard Henderson                 qemu_build_not_reached();
102039004a71SRichard Henderson             }
102139004a71SRichard Henderson             break;
102239004a71SRichard Henderson 
1023466d3759SRichard Henderson         case TCG_TYPE_I128:
10245427a9a7SRichard Henderson             switch (TCG_TARGET_CALL_ARG_I128) {
1025466d3759SRichard Henderson             case TCG_CALL_ARG_EVEN:
1026466d3759SRichard Henderson                 layout_arg_even(&cum);
1027466d3759SRichard Henderson                 /* fall through */
1028466d3759SRichard Henderson             case TCG_CALL_ARG_NORMAL:
1029466d3759SRichard Henderson                 layout_arg_normal_n(&cum, info, 128 / TCG_TARGET_REG_BITS);
1030466d3759SRichard Henderson                 break;
1031313bdea8SRichard Henderson             case TCG_CALL_ARG_BY_REF:
1032313bdea8SRichard Henderson                 layout_arg_by_ref(&cum, info);
1033313bdea8SRichard Henderson                 break;
1034466d3759SRichard Henderson             default:
1035466d3759SRichard Henderson                 qemu_build_not_reached();
1036466d3759SRichard Henderson             }
1037466d3759SRichard Henderson             break;
1038466d3759SRichard Henderson 
103939004a71SRichard Henderson         default:
104039004a71SRichard Henderson             g_assert_not_reached();
104139004a71SRichard Henderson         }
104239004a71SRichard Henderson     }
104339004a71SRichard Henderson     info->nr_in = cum.info_in_idx;
104439004a71SRichard Henderson 
104539004a71SRichard Henderson     /* Validate that we didn't overrun the input array. */
104639004a71SRichard Henderson     assert(cum.info_in_idx <= ARRAY_SIZE(info->in));
104739004a71SRichard Henderson     /* Validate the backend has enough argument space. */
104839004a71SRichard Henderson     assert(cum.arg_slot <= max_reg_slots + max_stk_slots);
1049313bdea8SRichard Henderson 
1050313bdea8SRichard Henderson     /*
1051313bdea8SRichard Henderson      * Relocate the "ref_slot" area to the end of the parameters.
1052313bdea8SRichard Henderson      * Minimizing this stack offset helps code size for x86,
1053313bdea8SRichard Henderson      * which has a signed 8-bit offset encoding.
1054313bdea8SRichard Henderson      */
1055313bdea8SRichard Henderson     if (cum.ref_slot != 0) {
1056313bdea8SRichard Henderson         int ref_base = 0;
1057313bdea8SRichard Henderson 
1058313bdea8SRichard Henderson         if (cum.arg_slot > max_reg_slots) {
1059313bdea8SRichard Henderson             int align = __alignof(Int128) / sizeof(tcg_target_long);
1060313bdea8SRichard Henderson 
1061313bdea8SRichard Henderson             ref_base = cum.arg_slot - max_reg_slots;
1062313bdea8SRichard Henderson             if (align > 1) {
1063313bdea8SRichard Henderson                 ref_base = ROUND_UP(ref_base, align);
1064313bdea8SRichard Henderson             }
1065313bdea8SRichard Henderson         }
1066313bdea8SRichard Henderson         assert(ref_base + cum.ref_slot <= max_stk_slots);
1067*d78e4a4fSRichard Henderson         ref_base += max_reg_slots;
1068313bdea8SRichard Henderson 
1069313bdea8SRichard Henderson         if (ref_base != 0) {
1070313bdea8SRichard Henderson             for (int i = cum.info_in_idx - 1; i >= 0; --i) {
1071313bdea8SRichard Henderson                 TCGCallArgumentLoc *loc = &info->in[i];
1072313bdea8SRichard Henderson                 switch (loc->kind) {
1073313bdea8SRichard Henderson                 case TCG_CALL_ARG_BY_REF:
1074313bdea8SRichard Henderson                 case TCG_CALL_ARG_BY_REF_N:
1075313bdea8SRichard Henderson                     loc->ref_slot += ref_base;
1076313bdea8SRichard Henderson                     break;
1077313bdea8SRichard Henderson                 default:
1078313bdea8SRichard Henderson                     break;
1079313bdea8SRichard Henderson                 }
1080313bdea8SRichard Henderson             }
1081313bdea8SRichard Henderson         }
1082313bdea8SRichard Henderson     }
108339004a71SRichard Henderson }
108439004a71SRichard Henderson 
108591478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)];
1086f69d277eSRichard Henderson static void process_op_defs(TCGContext *s);
10871c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
10881c2adb95SRichard Henderson                                             TCGReg reg, const char *name);
108991478cefSRichard Henderson 
109043b972b7SRichard Henderson static void tcg_context_init(unsigned max_cpus)
1091c896fe29Sbellard {
1092a76aabd3SRichard Henderson     TCGContext *s = &tcg_init_ctx;
1093100b5e01SRichard Henderson     int op, total_args, n, i;
1094c896fe29Sbellard     TCGOpDef *def;
1095c896fe29Sbellard     TCGArgConstraint *args_ct;
10961c2adb95SRichard Henderson     TCGTemp *ts;
1097c896fe29Sbellard 
1098c896fe29Sbellard     memset(s, 0, sizeof(*s));
1099c896fe29Sbellard     s->nb_globals = 0;
1100c896fe29Sbellard 
1101c896fe29Sbellard     /* Count total number of arguments and allocate the corresponding
1102c896fe29Sbellard        space */
1103c896fe29Sbellard     total_args = 0;
1104c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
1105c896fe29Sbellard         def = &tcg_op_defs[op];
1106c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
1107c896fe29Sbellard         total_args += n;
1108c896fe29Sbellard     }
1109c896fe29Sbellard 
1110bc2b17e6SRichard Henderson     args_ct = g_new0(TCGArgConstraint, total_args);
1111c896fe29Sbellard 
1112c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
1113c896fe29Sbellard         def = &tcg_op_defs[op];
1114c896fe29Sbellard         def->args_ct = args_ct;
1115c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
1116c896fe29Sbellard         args_ct += n;
1117c896fe29Sbellard     }
1118c896fe29Sbellard 
11195cd8f621SRichard Henderson     /* Register helpers.  */
112084fd9dd3SRichard Henderson     /* Use g_direct_hash/equal for direct pointer comparisons on func.  */
1121619205fdSEmilio G. Cota     helper_table = g_hash_table_new(NULL, NULL);
112284fd9dd3SRichard Henderson 
1123100b5e01SRichard Henderson     for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) {
112439004a71SRichard Henderson         init_call_layout(&all_helpers[i]);
112584fd9dd3SRichard Henderson         g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func,
112672866e82SRichard Henderson                             (gpointer)&all_helpers[i]);
1127100b5e01SRichard Henderson     }
11285cd8f621SRichard Henderson 
112922f15579SRichard Henderson #ifdef CONFIG_TCG_INTERPRETER
11300c22e176SPhilippe Mathieu-Daudé     init_ffi_layouts();
113122f15579SRichard Henderson #endif
113222f15579SRichard Henderson 
1133c896fe29Sbellard     tcg_target_init(s);
1134f69d277eSRichard Henderson     process_op_defs(s);
113591478cefSRichard Henderson 
113691478cefSRichard Henderson     /* Reverse the order of the saved registers, assuming they're all at
113791478cefSRichard Henderson        the start of tcg_target_reg_alloc_order.  */
113891478cefSRichard Henderson     for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) {
113991478cefSRichard Henderson         int r = tcg_target_reg_alloc_order[n];
114091478cefSRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) {
114191478cefSRichard Henderson             break;
114291478cefSRichard Henderson         }
114391478cefSRichard Henderson     }
114491478cefSRichard Henderson     for (i = 0; i < n; ++i) {
114591478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i];
114691478cefSRichard Henderson     }
114791478cefSRichard Henderson     for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) {
114891478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i];
114991478cefSRichard Henderson     }
1150b1311c4aSEmilio G. Cota 
115138b47b19SEmilio G. Cota     alloc_tcg_plugin_context(s);
115238b47b19SEmilio G. Cota 
1153b1311c4aSEmilio G. Cota     tcg_ctx = s;
11543468b59eSEmilio G. Cota     /*
11553468b59eSEmilio G. Cota      * In user-mode we simply share the init context among threads, since we
11563468b59eSEmilio G. Cota      * use a single region. See the documentation tcg_region_init() for the
11573468b59eSEmilio G. Cota      * reasoning behind this.
11583468b59eSEmilio G. Cota      * In softmmu we will have at most max_cpus TCG threads.
11593468b59eSEmilio G. Cota      */
11603468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
1161df2cce29SEmilio G. Cota     tcg_ctxs = &tcg_ctx;
11620e2d61cfSRichard Henderson     tcg_cur_ctxs = 1;
11630e2d61cfSRichard Henderson     tcg_max_ctxs = 1;
11643468b59eSEmilio G. Cota #else
11650e2d61cfSRichard Henderson     tcg_max_ctxs = max_cpus;
11660e2d61cfSRichard Henderson     tcg_ctxs = g_new0(TCGContext *, max_cpus);
11673468b59eSEmilio G. Cota #endif
11681c2adb95SRichard Henderson 
11691c2adb95SRichard Henderson     tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0));
11701c2adb95SRichard Henderson     ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env");
11711c2adb95SRichard Henderson     cpu_env = temp_tcgv_ptr(ts);
11729002ec79SRichard Henderson }
1173b03cce8eSbellard 
117443b972b7SRichard Henderson void tcg_init(size_t tb_size, int splitwx, unsigned max_cpus)
1175a76aabd3SRichard Henderson {
117643b972b7SRichard Henderson     tcg_context_init(max_cpus);
117743b972b7SRichard Henderson     tcg_region_init(tb_size, splitwx, max_cpus);
1178a76aabd3SRichard Henderson }
1179a76aabd3SRichard Henderson 
11806e3b2bfdSEmilio G. Cota /*
11816e3b2bfdSEmilio G. Cota  * Allocate TBs right before their corresponding translated code, making
11826e3b2bfdSEmilio G. Cota  * sure that TBs and code are on different cache lines.
11836e3b2bfdSEmilio G. Cota  */
11846e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s)
11856e3b2bfdSEmilio G. Cota {
11866e3b2bfdSEmilio G. Cota     uintptr_t align = qemu_icache_linesize;
11876e3b2bfdSEmilio G. Cota     TranslationBlock *tb;
11886e3b2bfdSEmilio G. Cota     void *next;
11896e3b2bfdSEmilio G. Cota 
1190e8feb96fSEmilio G. Cota  retry:
11916e3b2bfdSEmilio G. Cota     tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align);
11926e3b2bfdSEmilio G. Cota     next = (void *)ROUND_UP((uintptr_t)(tb + 1), align);
11936e3b2bfdSEmilio G. Cota 
11946e3b2bfdSEmilio G. Cota     if (unlikely(next > s->code_gen_highwater)) {
1195e8feb96fSEmilio G. Cota         if (tcg_region_alloc(s)) {
11966e3b2bfdSEmilio G. Cota             return NULL;
11976e3b2bfdSEmilio G. Cota         }
1198e8feb96fSEmilio G. Cota         goto retry;
1199e8feb96fSEmilio G. Cota     }
1200d73415a3SStefan Hajnoczi     qatomic_set(&s->code_gen_ptr, next);
120157a26946SRichard Henderson     s->data_gen_ptr = NULL;
12026e3b2bfdSEmilio G. Cota     return tb;
12036e3b2bfdSEmilio G. Cota }
12046e3b2bfdSEmilio G. Cota 
12059002ec79SRichard Henderson void tcg_prologue_init(TCGContext *s)
12069002ec79SRichard Henderson {
1207b0a0794aSRichard Henderson     size_t prologue_size;
12088163b749SRichard Henderson 
1209b0a0794aSRichard Henderson     s->code_ptr = s->code_gen_ptr;
1210b0a0794aSRichard Henderson     s->code_buf = s->code_gen_ptr;
12115b38ee31SRichard Henderson     s->data_gen_ptr = NULL;
1212b91ccb31SRichard Henderson 
1213b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
1214b0a0794aSRichard Henderson     tcg_qemu_tb_exec = (tcg_prologue_fn *)tcg_splitwx_to_rx(s->code_ptr);
1215b91ccb31SRichard Henderson #endif
12168163b749SRichard Henderson 
12175b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
12185b38ee31SRichard Henderson     s->pool_labels = NULL;
12195b38ee31SRichard Henderson #endif
12205b38ee31SRichard Henderson 
1221653b87ebSRoman Bolshakov     qemu_thread_jit_write();
12228163b749SRichard Henderson     /* Generate the prologue.  */
1223b03cce8eSbellard     tcg_target_qemu_prologue(s);
12245b38ee31SRichard Henderson 
12255b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
12265b38ee31SRichard Henderson     /* Allow the prologue to put e.g. guest_base into a pool entry.  */
12275b38ee31SRichard Henderson     {
12281768987bSRichard Henderson         int result = tcg_out_pool_finalize(s);
12291768987bSRichard Henderson         tcg_debug_assert(result == 0);
12305b38ee31SRichard Henderson     }
12315b38ee31SRichard Henderson #endif
12325b38ee31SRichard Henderson 
1233b0a0794aSRichard Henderson     prologue_size = tcg_current_code_size(s);
12345584e2dbSIlya Leoshkevich     perf_report_prologue(s->code_gen_ptr, prologue_size);
1235b0a0794aSRichard Henderson 
1236df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
1237b0a0794aSRichard Henderson     flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf),
1238b0a0794aSRichard Henderson                         (uintptr_t)s->code_buf, prologue_size);
1239df5d2b16SRichard Henderson #endif
12408163b749SRichard Henderson 
1241d6b64b2bSRichard Henderson #ifdef DEBUG_DISAS
1242d6b64b2bSRichard Henderson     if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) {
1243c60f599bSRichard Henderson         FILE *logfile = qemu_log_trylock();
124478b54858SRichard Henderson         if (logfile) {
124578b54858SRichard Henderson             fprintf(logfile, "PROLOGUE: [size=%zu]\n", prologue_size);
12465b38ee31SRichard Henderson             if (s->data_gen_ptr) {
1247b0a0794aSRichard Henderson                 size_t code_size = s->data_gen_ptr - s->code_gen_ptr;
12485b38ee31SRichard Henderson                 size_t data_size = prologue_size - code_size;
12495b38ee31SRichard Henderson                 size_t i;
12505b38ee31SRichard Henderson 
125178b54858SRichard Henderson                 disas(logfile, s->code_gen_ptr, code_size);
12525b38ee31SRichard Henderson 
12535b38ee31SRichard Henderson                 for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) {
12545b38ee31SRichard Henderson                     if (sizeof(tcg_target_ulong) == 8) {
125578b54858SRichard Henderson                         fprintf(logfile,
125678b54858SRichard Henderson                                 "0x%08" PRIxPTR ":  .quad  0x%016" PRIx64 "\n",
12575b38ee31SRichard Henderson                                 (uintptr_t)s->data_gen_ptr + i,
12585b38ee31SRichard Henderson                                 *(uint64_t *)(s->data_gen_ptr + i));
12595b38ee31SRichard Henderson                     } else {
126078b54858SRichard Henderson                         fprintf(logfile,
126178b54858SRichard Henderson                                 "0x%08" PRIxPTR ":  .long  0x%08x\n",
12625b38ee31SRichard Henderson                                 (uintptr_t)s->data_gen_ptr + i,
12635b38ee31SRichard Henderson                                 *(uint32_t *)(s->data_gen_ptr + i));
12645b38ee31SRichard Henderson                     }
12655b38ee31SRichard Henderson                 }
12665b38ee31SRichard Henderson             } else {
126778b54858SRichard Henderson                 disas(logfile, s->code_gen_ptr, prologue_size);
12685b38ee31SRichard Henderson             }
126978b54858SRichard Henderson             fprintf(logfile, "\n");
1270fc59d2d8SRobert Foley             qemu_log_unlock(logfile);
1271d6b64b2bSRichard Henderson         }
127278b54858SRichard Henderson     }
1273d6b64b2bSRichard Henderson #endif
1274cedbcb01SEmilio G. Cota 
12756eea0434SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
12766eea0434SRichard Henderson     /*
12776eea0434SRichard Henderson      * Assert that goto_ptr is implemented completely, setting an epilogue.
12786eea0434SRichard Henderson      * For tci, we use NULL as the signal to return from the interpreter,
12796eea0434SRichard Henderson      * so skip this check.
12806eea0434SRichard Henderson      */
12818b5c2b62SRichard Henderson     tcg_debug_assert(tcg_code_gen_epilogue != NULL);
12826eea0434SRichard Henderson #endif
1283d1c74ab3SRichard Henderson 
1284d1c74ab3SRichard Henderson     tcg_region_prologue_set(s);
1285c896fe29Sbellard }
1286c896fe29Sbellard 
1287c896fe29Sbellard void tcg_func_start(TCGContext *s)
1288c896fe29Sbellard {
1289c896fe29Sbellard     tcg_pool_reset(s);
1290c896fe29Sbellard     s->nb_temps = s->nb_globals;
12910ec9eabcSRichard Henderson 
12920ec9eabcSRichard Henderson     /* No temps have been previously allocated for size or locality.  */
12930ec9eabcSRichard Henderson     memset(s->free_temps, 0, sizeof(s->free_temps));
12940ec9eabcSRichard Henderson 
1295c0522136SRichard Henderson     /* No constant temps have been previously allocated. */
1296c0522136SRichard Henderson     for (int i = 0; i < TCG_TYPE_COUNT; ++i) {
1297c0522136SRichard Henderson         if (s->const_table[i]) {
1298c0522136SRichard Henderson             g_hash_table_remove_all(s->const_table[i]);
1299c0522136SRichard Henderson         }
1300c0522136SRichard Henderson     }
1301c0522136SRichard Henderson 
1302abebf925SRichard Henderson     s->nb_ops = 0;
1303c896fe29Sbellard     s->nb_labels = 0;
1304c896fe29Sbellard     s->current_frame_offset = s->frame_start;
1305c896fe29Sbellard 
13060a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG
13070a209d4bSRichard Henderson     s->goto_tb_issue_mask = 0;
13080a209d4bSRichard Henderson #endif
13090a209d4bSRichard Henderson 
131015fa08f8SRichard Henderson     QTAILQ_INIT(&s->ops);
131115fa08f8SRichard Henderson     QTAILQ_INIT(&s->free_ops);
1312bef16ab4SRichard Henderson     QSIMPLEQ_INIT(&s->labels);
1313c896fe29Sbellard }
1314c896fe29Sbellard 
1315ae30e866SRichard Henderson static TCGTemp *tcg_temp_alloc(TCGContext *s)
13167ca4b752SRichard Henderson {
13177ca4b752SRichard Henderson     int n = s->nb_temps++;
1318ae30e866SRichard Henderson 
1319ae30e866SRichard Henderson     if (n >= TCG_MAX_TEMPS) {
1320db6b7d0cSRichard Henderson         tcg_raise_tb_overflow(s);
1321ae30e866SRichard Henderson     }
13227ca4b752SRichard Henderson     return memset(&s->temps[n], 0, sizeof(TCGTemp));
13237ca4b752SRichard Henderson }
13247ca4b752SRichard Henderson 
1325ae30e866SRichard Henderson static TCGTemp *tcg_global_alloc(TCGContext *s)
13267ca4b752SRichard Henderson {
1327fa477d25SRichard Henderson     TCGTemp *ts;
1328fa477d25SRichard Henderson 
13297ca4b752SRichard Henderson     tcg_debug_assert(s->nb_globals == s->nb_temps);
1330ae30e866SRichard Henderson     tcg_debug_assert(s->nb_globals < TCG_MAX_TEMPS);
13317ca4b752SRichard Henderson     s->nb_globals++;
1332fa477d25SRichard Henderson     ts = tcg_temp_alloc(s);
1333ee17db83SRichard Henderson     ts->kind = TEMP_GLOBAL;
1334fa477d25SRichard Henderson 
1335fa477d25SRichard Henderson     return ts;
1336c896fe29Sbellard }
1337c896fe29Sbellard 
1338085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
1339b6638662SRichard Henderson                                             TCGReg reg, const char *name)
1340c896fe29Sbellard {
1341c896fe29Sbellard     TCGTemp *ts;
1342c896fe29Sbellard 
13431a057554SRichard Henderson     tcg_debug_assert(TCG_TARGET_REG_BITS == 64 || type == TCG_TYPE_I32);
13447ca4b752SRichard Henderson 
13457ca4b752SRichard Henderson     ts = tcg_global_alloc(s);
1346c896fe29Sbellard     ts->base_type = type;
1347c896fe29Sbellard     ts->type = type;
1348ee17db83SRichard Henderson     ts->kind = TEMP_FIXED;
1349c896fe29Sbellard     ts->reg = reg;
1350c896fe29Sbellard     ts->name = name;
1351c896fe29Sbellard     tcg_regset_set_reg(s->reserved_regs, reg);
13527ca4b752SRichard Henderson 
1353085272b3SRichard Henderson     return ts;
1354a7812ae4Spbrook }
1355a7812ae4Spbrook 
1356b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size)
1357a7812ae4Spbrook {
1358b3a62939SRichard Henderson     s->frame_start = start;
1359b3a62939SRichard Henderson     s->frame_end = start + size;
1360085272b3SRichard Henderson     s->frame_temp
1361085272b3SRichard Henderson         = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame");
1362b3a62939SRichard Henderson }
1363a7812ae4Spbrook 
1364085272b3SRichard Henderson TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base,
1365e1ccc054SRichard Henderson                                      intptr_t offset, const char *name)
1366c896fe29Sbellard {
1367b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1368dc41aa7dSRichard Henderson     TCGTemp *base_ts = tcgv_ptr_temp(base);
13697ca4b752SRichard Henderson     TCGTemp *ts = tcg_global_alloc(s);
1370aef85402SRichard Henderson     int indirect_reg = 0;
1371c896fe29Sbellard 
1372c0522136SRichard Henderson     switch (base_ts->kind) {
1373c0522136SRichard Henderson     case TEMP_FIXED:
1374c0522136SRichard Henderson         break;
1375c0522136SRichard Henderson     case TEMP_GLOBAL:
13765a18407fSRichard Henderson         /* We do not support double-indirect registers.  */
13775a18407fSRichard Henderson         tcg_debug_assert(!base_ts->indirect_reg);
1378b3915dbbSRichard Henderson         base_ts->indirect_base = 1;
13795a18407fSRichard Henderson         s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64
13805a18407fSRichard Henderson                             ? 2 : 1);
13815a18407fSRichard Henderson         indirect_reg = 1;
1382c0522136SRichard Henderson         break;
1383c0522136SRichard Henderson     default:
1384c0522136SRichard Henderson         g_assert_not_reached();
1385b3915dbbSRichard Henderson     }
1386b3915dbbSRichard Henderson 
13877ca4b752SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
13887ca4b752SRichard Henderson         TCGTemp *ts2 = tcg_global_alloc(s);
1389c896fe29Sbellard         char buf[64];
13907ca4b752SRichard Henderson 
13917ca4b752SRichard Henderson         ts->base_type = TCG_TYPE_I64;
1392c896fe29Sbellard         ts->type = TCG_TYPE_I32;
1393b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1394c896fe29Sbellard         ts->mem_allocated = 1;
1395b3a62939SRichard Henderson         ts->mem_base = base_ts;
1396aef85402SRichard Henderson         ts->mem_offset = offset;
1397c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1398c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_0");
1399c896fe29Sbellard         ts->name = strdup(buf);
1400c896fe29Sbellard 
14017ca4b752SRichard Henderson         tcg_debug_assert(ts2 == ts + 1);
14027ca4b752SRichard Henderson         ts2->base_type = TCG_TYPE_I64;
14037ca4b752SRichard Henderson         ts2->type = TCG_TYPE_I32;
1404b3915dbbSRichard Henderson         ts2->indirect_reg = indirect_reg;
14057ca4b752SRichard Henderson         ts2->mem_allocated = 1;
14067ca4b752SRichard Henderson         ts2->mem_base = base_ts;
1407aef85402SRichard Henderson         ts2->mem_offset = offset + 4;
1408fac87bd2SRichard Henderson         ts2->temp_subindex = 1;
1409c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1410c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_1");
1411120c1084SRichard Henderson         ts2->name = strdup(buf);
14127ca4b752SRichard Henderson     } else {
1413c896fe29Sbellard         ts->base_type = type;
1414c896fe29Sbellard         ts->type = type;
1415b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1416c896fe29Sbellard         ts->mem_allocated = 1;
1417b3a62939SRichard Henderson         ts->mem_base = base_ts;
1418c896fe29Sbellard         ts->mem_offset = offset;
1419c896fe29Sbellard         ts->name = name;
1420c896fe29Sbellard     }
1421085272b3SRichard Henderson     return ts;
1422c896fe29Sbellard }
1423c896fe29Sbellard 
1424bbf989bfSRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, TCGTempKind kind)
1425c896fe29Sbellard {
1426b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1427c896fe29Sbellard     TCGTemp *ts;
1428e1c08b00SRichard Henderson     int n;
1429c896fe29Sbellard 
1430e1c08b00SRichard Henderson     if (kind == TEMP_EBB) {
1431e1c08b00SRichard Henderson         int idx = find_first_bit(s->free_temps[type].l, TCG_MAX_TEMPS);
1432e1c08b00SRichard Henderson 
14330ec9eabcSRichard Henderson         if (idx < TCG_MAX_TEMPS) {
14340ec9eabcSRichard Henderson             /* There is already an available temp with the right type.  */
1435e1c08b00SRichard Henderson             clear_bit(idx, s->free_temps[type].l);
14360ec9eabcSRichard Henderson 
1437e8996ee0Sbellard             ts = &s->temps[idx];
1438e8996ee0Sbellard             ts->temp_allocated = 1;
14397ca4b752SRichard Henderson             tcg_debug_assert(ts->base_type == type);
1440ee17db83SRichard Henderson             tcg_debug_assert(ts->kind == kind);
14412f2e911dSRichard Henderson             return ts;
1442e1c08b00SRichard Henderson         }
1443e8996ee0Sbellard     } else {
1444e1c08b00SRichard Henderson         tcg_debug_assert(kind == TEMP_TB);
1445e1c08b00SRichard Henderson     }
144643eef72fSRichard Henderson 
144743eef72fSRichard Henderson     switch (type) {
144843eef72fSRichard Henderson     case TCG_TYPE_I32:
144943eef72fSRichard Henderson     case TCG_TYPE_V64:
145043eef72fSRichard Henderson     case TCG_TYPE_V128:
145143eef72fSRichard Henderson     case TCG_TYPE_V256:
145243eef72fSRichard Henderson         n = 1;
145343eef72fSRichard Henderson         break;
145443eef72fSRichard Henderson     case TCG_TYPE_I64:
145543eef72fSRichard Henderson         n = 64 / TCG_TARGET_REG_BITS;
145643eef72fSRichard Henderson         break;
145743eef72fSRichard Henderson     case TCG_TYPE_I128:
145843eef72fSRichard Henderson         n = 128 / TCG_TARGET_REG_BITS;
145943eef72fSRichard Henderson         break;
146043eef72fSRichard Henderson     default:
146143eef72fSRichard Henderson         g_assert_not_reached();
146243eef72fSRichard Henderson     }
146343eef72fSRichard Henderson 
14647ca4b752SRichard Henderson     ts = tcg_temp_alloc(s);
146543eef72fSRichard Henderson     ts->base_type = type;
146643eef72fSRichard Henderson     ts->temp_allocated = 1;
146743eef72fSRichard Henderson     ts->kind = kind;
146843eef72fSRichard Henderson 
146943eef72fSRichard Henderson     if (n == 1) {
147043eef72fSRichard Henderson         ts->type = type;
147143eef72fSRichard Henderson     } else {
147243eef72fSRichard Henderson         ts->type = TCG_TYPE_REG;
147343eef72fSRichard Henderson 
1474e1c08b00SRichard Henderson         for (int i = 1; i < n; ++i) {
14757ca4b752SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
14767ca4b752SRichard Henderson 
147743eef72fSRichard Henderson             tcg_debug_assert(ts2 == ts + i);
147843eef72fSRichard Henderson             ts2->base_type = type;
147943eef72fSRichard Henderson             ts2->type = TCG_TYPE_REG;
14807ca4b752SRichard Henderson             ts2->temp_allocated = 1;
148143eef72fSRichard Henderson             ts2->temp_subindex = i;
1482ee17db83SRichard Henderson             ts2->kind = kind;
148343eef72fSRichard Henderson         }
1484c896fe29Sbellard     }
1485085272b3SRichard Henderson     return ts;
1486c896fe29Sbellard }
1487c896fe29Sbellard 
1488d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type)
1489d2fd745fSRichard Henderson {
1490d2fd745fSRichard Henderson     TCGTemp *t;
1491d2fd745fSRichard Henderson 
1492d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG
1493d2fd745fSRichard Henderson     switch (type) {
1494d2fd745fSRichard Henderson     case TCG_TYPE_V64:
1495d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v64);
1496d2fd745fSRichard Henderson         break;
1497d2fd745fSRichard Henderson     case TCG_TYPE_V128:
1498d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v128);
1499d2fd745fSRichard Henderson         break;
1500d2fd745fSRichard Henderson     case TCG_TYPE_V256:
1501d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v256);
1502d2fd745fSRichard Henderson         break;
1503d2fd745fSRichard Henderson     default:
1504d2fd745fSRichard Henderson         g_assert_not_reached();
1505d2fd745fSRichard Henderson     }
1506d2fd745fSRichard Henderson #endif
1507d2fd745fSRichard Henderson 
1508bbf989bfSRichard Henderson     t = tcg_temp_new_internal(type, TEMP_EBB);
1509d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1510d2fd745fSRichard Henderson }
1511d2fd745fSRichard Henderson 
1512d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp.  */
1513d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match)
1514d2fd745fSRichard Henderson {
1515d2fd745fSRichard Henderson     TCGTemp *t = tcgv_vec_temp(match);
1516d2fd745fSRichard Henderson 
1517d2fd745fSRichard Henderson     tcg_debug_assert(t->temp_allocated != 0);
1518d2fd745fSRichard Henderson 
1519bbf989bfSRichard Henderson     t = tcg_temp_new_internal(t->base_type, TEMP_EBB);
1520d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1521d2fd745fSRichard Henderson }
1522d2fd745fSRichard Henderson 
15235bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts)
1524c896fe29Sbellard {
1525b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1526c896fe29Sbellard 
1527c7482438SRichard Henderson     switch (ts->kind) {
1528c7482438SRichard Henderson     case TEMP_CONST:
1529f57c6915SRichard Henderson     case TEMP_TB:
15302f2e911dSRichard Henderson         /* Silently ignore free. */
1531c7482438SRichard Henderson         break;
15322f2e911dSRichard Henderson     case TEMP_EBB:
1533eabb7b91SAurelien Jarno         tcg_debug_assert(ts->temp_allocated != 0);
1534e8996ee0Sbellard         ts->temp_allocated = 0;
15352f2e911dSRichard Henderson         set_bit(temp_idx(ts), s->free_temps[ts->base_type].l);
15362f2e911dSRichard Henderson         break;
15372f2e911dSRichard Henderson     default:
15382f2e911dSRichard Henderson         /* It never made sense to free TEMP_FIXED or TEMP_GLOBAL. */
15392f2e911dSRichard Henderson         g_assert_not_reached();
1540e1c08b00SRichard Henderson     }
1541e8996ee0Sbellard }
1542e8996ee0Sbellard 
1543c0522136SRichard Henderson TCGTemp *tcg_constant_internal(TCGType type, int64_t val)
1544c0522136SRichard Henderson {
1545c0522136SRichard Henderson     TCGContext *s = tcg_ctx;
1546c0522136SRichard Henderson     GHashTable *h = s->const_table[type];
1547c0522136SRichard Henderson     TCGTemp *ts;
1548c0522136SRichard Henderson 
1549c0522136SRichard Henderson     if (h == NULL) {
1550c0522136SRichard Henderson         h = g_hash_table_new(g_int64_hash, g_int64_equal);
1551c0522136SRichard Henderson         s->const_table[type] = h;
1552c0522136SRichard Henderson     }
1553c0522136SRichard Henderson 
1554c0522136SRichard Henderson     ts = g_hash_table_lookup(h, &val);
1555c0522136SRichard Henderson     if (ts == NULL) {
1556aef85402SRichard Henderson         int64_t *val_ptr;
1557aef85402SRichard Henderson 
1558c0522136SRichard Henderson         ts = tcg_temp_alloc(s);
1559c0522136SRichard Henderson 
1560c0522136SRichard Henderson         if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
1561c0522136SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
1562c0522136SRichard Henderson 
1563aef85402SRichard Henderson             tcg_debug_assert(ts2 == ts + 1);
1564aef85402SRichard Henderson 
1565c0522136SRichard Henderson             ts->base_type = TCG_TYPE_I64;
1566c0522136SRichard Henderson             ts->type = TCG_TYPE_I32;
1567c0522136SRichard Henderson             ts->kind = TEMP_CONST;
1568c0522136SRichard Henderson             ts->temp_allocated = 1;
1569c0522136SRichard Henderson 
1570c0522136SRichard Henderson             ts2->base_type = TCG_TYPE_I64;
1571c0522136SRichard Henderson             ts2->type = TCG_TYPE_I32;
1572c0522136SRichard Henderson             ts2->kind = TEMP_CONST;
1573c0522136SRichard Henderson             ts2->temp_allocated = 1;
1574fac87bd2SRichard Henderson             ts2->temp_subindex = 1;
1575aef85402SRichard Henderson 
1576aef85402SRichard Henderson             /*
1577aef85402SRichard Henderson              * Retain the full value of the 64-bit constant in the low
1578aef85402SRichard Henderson              * part, so that the hash table works.  Actual uses will
1579aef85402SRichard Henderson              * truncate the value to the low part.
1580aef85402SRichard Henderson              */
1581aef85402SRichard Henderson             ts[HOST_BIG_ENDIAN].val = val;
1582aef85402SRichard Henderson             ts[!HOST_BIG_ENDIAN].val = val >> 32;
1583aef85402SRichard Henderson             val_ptr = &ts[HOST_BIG_ENDIAN].val;
1584c0522136SRichard Henderson         } else {
1585c0522136SRichard Henderson             ts->base_type = type;
1586c0522136SRichard Henderson             ts->type = type;
1587c0522136SRichard Henderson             ts->kind = TEMP_CONST;
1588c0522136SRichard Henderson             ts->temp_allocated = 1;
1589c0522136SRichard Henderson             ts->val = val;
1590aef85402SRichard Henderson             val_ptr = &ts->val;
1591c0522136SRichard Henderson         }
1592aef85402SRichard Henderson         g_hash_table_insert(h, val_ptr, ts);
1593c0522136SRichard Henderson     }
1594c0522136SRichard Henderson 
1595c0522136SRichard Henderson     return ts;
1596c0522136SRichard Henderson }
1597c0522136SRichard Henderson 
1598c0522136SRichard Henderson TCGv_vec tcg_constant_vec(TCGType type, unsigned vece, int64_t val)
1599c0522136SRichard Henderson {
1600c0522136SRichard Henderson     val = dup_const(vece, val);
1601c0522136SRichard Henderson     return temp_tcgv_vec(tcg_constant_internal(type, val));
1602c0522136SRichard Henderson }
1603c0522136SRichard Henderson 
160488d4005bSRichard Henderson TCGv_vec tcg_constant_vec_matching(TCGv_vec match, unsigned vece, int64_t val)
160588d4005bSRichard Henderson {
160688d4005bSRichard Henderson     TCGTemp *t = tcgv_vec_temp(match);
160788d4005bSRichard Henderson 
160888d4005bSRichard Henderson     tcg_debug_assert(t->temp_allocated != 0);
160988d4005bSRichard Henderson     return tcg_constant_vec(t->base_type, vece, val);
161088d4005bSRichard Henderson }
161188d4005bSRichard Henderson 
1612be0f34b5SRichard Henderson /* Return true if OP may appear in the opcode stream.
1613be0f34b5SRichard Henderson    Test the runtime variable that controls each opcode.  */
1614be0f34b5SRichard Henderson bool tcg_op_supported(TCGOpcode op)
1615be0f34b5SRichard Henderson {
1616d2fd745fSRichard Henderson     const bool have_vec
1617d2fd745fSRichard Henderson         = TCG_TARGET_HAS_v64 | TCG_TARGET_HAS_v128 | TCG_TARGET_HAS_v256;
1618d2fd745fSRichard Henderson 
1619be0f34b5SRichard Henderson     switch (op) {
1620be0f34b5SRichard Henderson     case INDEX_op_discard:
1621be0f34b5SRichard Henderson     case INDEX_op_set_label:
1622be0f34b5SRichard Henderson     case INDEX_op_call:
1623be0f34b5SRichard Henderson     case INDEX_op_br:
1624be0f34b5SRichard Henderson     case INDEX_op_mb:
1625be0f34b5SRichard Henderson     case INDEX_op_insn_start:
1626be0f34b5SRichard Henderson     case INDEX_op_exit_tb:
1627be0f34b5SRichard Henderson     case INDEX_op_goto_tb:
1628f4e01e30SRichard Henderson     case INDEX_op_goto_ptr:
1629be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i32:
1630be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i32:
1631be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i64:
1632be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i64:
1633be0f34b5SRichard Henderson         return true;
1634be0f34b5SRichard Henderson 
163507ce0b05SRichard Henderson     case INDEX_op_qemu_st8_i32:
163607ce0b05SRichard Henderson         return TCG_TARGET_HAS_qemu_st8_i32;
163707ce0b05SRichard Henderson 
1638be0f34b5SRichard Henderson     case INDEX_op_mov_i32:
1639be0f34b5SRichard Henderson     case INDEX_op_setcond_i32:
1640be0f34b5SRichard Henderson     case INDEX_op_brcond_i32:
1641be0f34b5SRichard Henderson     case INDEX_op_ld8u_i32:
1642be0f34b5SRichard Henderson     case INDEX_op_ld8s_i32:
1643be0f34b5SRichard Henderson     case INDEX_op_ld16u_i32:
1644be0f34b5SRichard Henderson     case INDEX_op_ld16s_i32:
1645be0f34b5SRichard Henderson     case INDEX_op_ld_i32:
1646be0f34b5SRichard Henderson     case INDEX_op_st8_i32:
1647be0f34b5SRichard Henderson     case INDEX_op_st16_i32:
1648be0f34b5SRichard Henderson     case INDEX_op_st_i32:
1649be0f34b5SRichard Henderson     case INDEX_op_add_i32:
1650be0f34b5SRichard Henderson     case INDEX_op_sub_i32:
1651be0f34b5SRichard Henderson     case INDEX_op_mul_i32:
1652be0f34b5SRichard Henderson     case INDEX_op_and_i32:
1653be0f34b5SRichard Henderson     case INDEX_op_or_i32:
1654be0f34b5SRichard Henderson     case INDEX_op_xor_i32:
1655be0f34b5SRichard Henderson     case INDEX_op_shl_i32:
1656be0f34b5SRichard Henderson     case INDEX_op_shr_i32:
1657be0f34b5SRichard Henderson     case INDEX_op_sar_i32:
1658be0f34b5SRichard Henderson         return true;
1659be0f34b5SRichard Henderson 
1660be0f34b5SRichard Henderson     case INDEX_op_movcond_i32:
1661be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i32;
1662be0f34b5SRichard Henderson     case INDEX_op_div_i32:
1663be0f34b5SRichard Henderson     case INDEX_op_divu_i32:
1664be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i32;
1665be0f34b5SRichard Henderson     case INDEX_op_rem_i32:
1666be0f34b5SRichard Henderson     case INDEX_op_remu_i32:
1667be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i32;
1668be0f34b5SRichard Henderson     case INDEX_op_div2_i32:
1669be0f34b5SRichard Henderson     case INDEX_op_divu2_i32:
1670be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i32;
1671be0f34b5SRichard Henderson     case INDEX_op_rotl_i32:
1672be0f34b5SRichard Henderson     case INDEX_op_rotr_i32:
1673be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i32;
1674be0f34b5SRichard Henderson     case INDEX_op_deposit_i32:
1675be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i32;
1676be0f34b5SRichard Henderson     case INDEX_op_extract_i32:
1677be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i32;
1678be0f34b5SRichard Henderson     case INDEX_op_sextract_i32:
1679be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i32;
1680fce1296fSRichard Henderson     case INDEX_op_extract2_i32:
1681fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i32;
1682be0f34b5SRichard Henderson     case INDEX_op_add2_i32:
1683be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i32;
1684be0f34b5SRichard Henderson     case INDEX_op_sub2_i32:
1685be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i32;
1686be0f34b5SRichard Henderson     case INDEX_op_mulu2_i32:
1687be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i32;
1688be0f34b5SRichard Henderson     case INDEX_op_muls2_i32:
1689be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i32;
1690be0f34b5SRichard Henderson     case INDEX_op_muluh_i32:
1691be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i32;
1692be0f34b5SRichard Henderson     case INDEX_op_mulsh_i32:
1693be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i32;
1694be0f34b5SRichard Henderson     case INDEX_op_ext8s_i32:
1695be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i32;
1696be0f34b5SRichard Henderson     case INDEX_op_ext16s_i32:
1697be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i32;
1698be0f34b5SRichard Henderson     case INDEX_op_ext8u_i32:
1699be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i32;
1700be0f34b5SRichard Henderson     case INDEX_op_ext16u_i32:
1701be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i32;
1702be0f34b5SRichard Henderson     case INDEX_op_bswap16_i32:
1703be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i32;
1704be0f34b5SRichard Henderson     case INDEX_op_bswap32_i32:
1705be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i32;
1706be0f34b5SRichard Henderson     case INDEX_op_not_i32:
1707be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i32;
1708be0f34b5SRichard Henderson     case INDEX_op_neg_i32:
1709be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i32;
1710be0f34b5SRichard Henderson     case INDEX_op_andc_i32:
1711be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i32;
1712be0f34b5SRichard Henderson     case INDEX_op_orc_i32:
1713be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i32;
1714be0f34b5SRichard Henderson     case INDEX_op_eqv_i32:
1715be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i32;
1716be0f34b5SRichard Henderson     case INDEX_op_nand_i32:
1717be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i32;
1718be0f34b5SRichard Henderson     case INDEX_op_nor_i32:
1719be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i32;
1720be0f34b5SRichard Henderson     case INDEX_op_clz_i32:
1721be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i32;
1722be0f34b5SRichard Henderson     case INDEX_op_ctz_i32:
1723be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i32;
1724be0f34b5SRichard Henderson     case INDEX_op_ctpop_i32:
1725be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i32;
1726be0f34b5SRichard Henderson 
1727be0f34b5SRichard Henderson     case INDEX_op_brcond2_i32:
1728be0f34b5SRichard Henderson     case INDEX_op_setcond2_i32:
1729be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 32;
1730be0f34b5SRichard Henderson 
1731be0f34b5SRichard Henderson     case INDEX_op_mov_i64:
1732be0f34b5SRichard Henderson     case INDEX_op_setcond_i64:
1733be0f34b5SRichard Henderson     case INDEX_op_brcond_i64:
1734be0f34b5SRichard Henderson     case INDEX_op_ld8u_i64:
1735be0f34b5SRichard Henderson     case INDEX_op_ld8s_i64:
1736be0f34b5SRichard Henderson     case INDEX_op_ld16u_i64:
1737be0f34b5SRichard Henderson     case INDEX_op_ld16s_i64:
1738be0f34b5SRichard Henderson     case INDEX_op_ld32u_i64:
1739be0f34b5SRichard Henderson     case INDEX_op_ld32s_i64:
1740be0f34b5SRichard Henderson     case INDEX_op_ld_i64:
1741be0f34b5SRichard Henderson     case INDEX_op_st8_i64:
1742be0f34b5SRichard Henderson     case INDEX_op_st16_i64:
1743be0f34b5SRichard Henderson     case INDEX_op_st32_i64:
1744be0f34b5SRichard Henderson     case INDEX_op_st_i64:
1745be0f34b5SRichard Henderson     case INDEX_op_add_i64:
1746be0f34b5SRichard Henderson     case INDEX_op_sub_i64:
1747be0f34b5SRichard Henderson     case INDEX_op_mul_i64:
1748be0f34b5SRichard Henderson     case INDEX_op_and_i64:
1749be0f34b5SRichard Henderson     case INDEX_op_or_i64:
1750be0f34b5SRichard Henderson     case INDEX_op_xor_i64:
1751be0f34b5SRichard Henderson     case INDEX_op_shl_i64:
1752be0f34b5SRichard Henderson     case INDEX_op_shr_i64:
1753be0f34b5SRichard Henderson     case INDEX_op_sar_i64:
1754be0f34b5SRichard Henderson     case INDEX_op_ext_i32_i64:
1755be0f34b5SRichard Henderson     case INDEX_op_extu_i32_i64:
1756be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 64;
1757be0f34b5SRichard Henderson 
1758be0f34b5SRichard Henderson     case INDEX_op_movcond_i64:
1759be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i64;
1760be0f34b5SRichard Henderson     case INDEX_op_div_i64:
1761be0f34b5SRichard Henderson     case INDEX_op_divu_i64:
1762be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i64;
1763be0f34b5SRichard Henderson     case INDEX_op_rem_i64:
1764be0f34b5SRichard Henderson     case INDEX_op_remu_i64:
1765be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i64;
1766be0f34b5SRichard Henderson     case INDEX_op_div2_i64:
1767be0f34b5SRichard Henderson     case INDEX_op_divu2_i64:
1768be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i64;
1769be0f34b5SRichard Henderson     case INDEX_op_rotl_i64:
1770be0f34b5SRichard Henderson     case INDEX_op_rotr_i64:
1771be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i64;
1772be0f34b5SRichard Henderson     case INDEX_op_deposit_i64:
1773be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i64;
1774be0f34b5SRichard Henderson     case INDEX_op_extract_i64:
1775be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i64;
1776be0f34b5SRichard Henderson     case INDEX_op_sextract_i64:
1777be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i64;
1778fce1296fSRichard Henderson     case INDEX_op_extract2_i64:
1779fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i64;
1780be0f34b5SRichard Henderson     case INDEX_op_extrl_i64_i32:
1781be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrl_i64_i32;
1782be0f34b5SRichard Henderson     case INDEX_op_extrh_i64_i32:
1783be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrh_i64_i32;
1784be0f34b5SRichard Henderson     case INDEX_op_ext8s_i64:
1785be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i64;
1786be0f34b5SRichard Henderson     case INDEX_op_ext16s_i64:
1787be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i64;
1788be0f34b5SRichard Henderson     case INDEX_op_ext32s_i64:
1789be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32s_i64;
1790be0f34b5SRichard Henderson     case INDEX_op_ext8u_i64:
1791be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i64;
1792be0f34b5SRichard Henderson     case INDEX_op_ext16u_i64:
1793be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i64;
1794be0f34b5SRichard Henderson     case INDEX_op_ext32u_i64:
1795be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32u_i64;
1796be0f34b5SRichard Henderson     case INDEX_op_bswap16_i64:
1797be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i64;
1798be0f34b5SRichard Henderson     case INDEX_op_bswap32_i64:
1799be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i64;
1800be0f34b5SRichard Henderson     case INDEX_op_bswap64_i64:
1801be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap64_i64;
1802be0f34b5SRichard Henderson     case INDEX_op_not_i64:
1803be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i64;
1804be0f34b5SRichard Henderson     case INDEX_op_neg_i64:
1805be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i64;
1806be0f34b5SRichard Henderson     case INDEX_op_andc_i64:
1807be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i64;
1808be0f34b5SRichard Henderson     case INDEX_op_orc_i64:
1809be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i64;
1810be0f34b5SRichard Henderson     case INDEX_op_eqv_i64:
1811be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i64;
1812be0f34b5SRichard Henderson     case INDEX_op_nand_i64:
1813be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i64;
1814be0f34b5SRichard Henderson     case INDEX_op_nor_i64:
1815be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i64;
1816be0f34b5SRichard Henderson     case INDEX_op_clz_i64:
1817be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i64;
1818be0f34b5SRichard Henderson     case INDEX_op_ctz_i64:
1819be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i64;
1820be0f34b5SRichard Henderson     case INDEX_op_ctpop_i64:
1821be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i64;
1822be0f34b5SRichard Henderson     case INDEX_op_add2_i64:
1823be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i64;
1824be0f34b5SRichard Henderson     case INDEX_op_sub2_i64:
1825be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i64;
1826be0f34b5SRichard Henderson     case INDEX_op_mulu2_i64:
1827be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i64;
1828be0f34b5SRichard Henderson     case INDEX_op_muls2_i64:
1829be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i64;
1830be0f34b5SRichard Henderson     case INDEX_op_muluh_i64:
1831be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i64;
1832be0f34b5SRichard Henderson     case INDEX_op_mulsh_i64:
1833be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i64;
1834be0f34b5SRichard Henderson 
1835d2fd745fSRichard Henderson     case INDEX_op_mov_vec:
1836d2fd745fSRichard Henderson     case INDEX_op_dup_vec:
183737ee55a0SRichard Henderson     case INDEX_op_dupm_vec:
1838d2fd745fSRichard Henderson     case INDEX_op_ld_vec:
1839d2fd745fSRichard Henderson     case INDEX_op_st_vec:
1840d2fd745fSRichard Henderson     case INDEX_op_add_vec:
1841d2fd745fSRichard Henderson     case INDEX_op_sub_vec:
1842d2fd745fSRichard Henderson     case INDEX_op_and_vec:
1843d2fd745fSRichard Henderson     case INDEX_op_or_vec:
1844d2fd745fSRichard Henderson     case INDEX_op_xor_vec:
1845212be173SRichard Henderson     case INDEX_op_cmp_vec:
1846d2fd745fSRichard Henderson         return have_vec;
1847d2fd745fSRichard Henderson     case INDEX_op_dup2_vec:
1848d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_REG_BITS == 32;
1849d2fd745fSRichard Henderson     case INDEX_op_not_vec:
1850d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_not_vec;
1851d2fd745fSRichard Henderson     case INDEX_op_neg_vec:
1852d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_neg_vec;
1853bcefc902SRichard Henderson     case INDEX_op_abs_vec:
1854bcefc902SRichard Henderson         return have_vec && TCG_TARGET_HAS_abs_vec;
1855d2fd745fSRichard Henderson     case INDEX_op_andc_vec:
1856d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_andc_vec;
1857d2fd745fSRichard Henderson     case INDEX_op_orc_vec:
1858d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_orc_vec;
1859ed523473SRichard Henderson     case INDEX_op_nand_vec:
1860ed523473SRichard Henderson         return have_vec && TCG_TARGET_HAS_nand_vec;
1861ed523473SRichard Henderson     case INDEX_op_nor_vec:
1862ed523473SRichard Henderson         return have_vec && TCG_TARGET_HAS_nor_vec;
1863ed523473SRichard Henderson     case INDEX_op_eqv_vec:
1864ed523473SRichard Henderson         return have_vec && TCG_TARGET_HAS_eqv_vec;
18653774030aSRichard Henderson     case INDEX_op_mul_vec:
18663774030aSRichard Henderson         return have_vec && TCG_TARGET_HAS_mul_vec;
1867d0ec9796SRichard Henderson     case INDEX_op_shli_vec:
1868d0ec9796SRichard Henderson     case INDEX_op_shri_vec:
1869d0ec9796SRichard Henderson     case INDEX_op_sari_vec:
1870d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shi_vec;
1871d0ec9796SRichard Henderson     case INDEX_op_shls_vec:
1872d0ec9796SRichard Henderson     case INDEX_op_shrs_vec:
1873d0ec9796SRichard Henderson     case INDEX_op_sars_vec:
1874d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shs_vec;
1875d0ec9796SRichard Henderson     case INDEX_op_shlv_vec:
1876d0ec9796SRichard Henderson     case INDEX_op_shrv_vec:
1877d0ec9796SRichard Henderson     case INDEX_op_sarv_vec:
1878d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shv_vec;
1879b0f7e744SRichard Henderson     case INDEX_op_rotli_vec:
1880b0f7e744SRichard Henderson         return have_vec && TCG_TARGET_HAS_roti_vec;
188123850a74SRichard Henderson     case INDEX_op_rotls_vec:
188223850a74SRichard Henderson         return have_vec && TCG_TARGET_HAS_rots_vec;
18835d0ceda9SRichard Henderson     case INDEX_op_rotlv_vec:
18845d0ceda9SRichard Henderson     case INDEX_op_rotrv_vec:
18855d0ceda9SRichard Henderson         return have_vec && TCG_TARGET_HAS_rotv_vec;
18868afaf050SRichard Henderson     case INDEX_op_ssadd_vec:
18878afaf050SRichard Henderson     case INDEX_op_usadd_vec:
18888afaf050SRichard Henderson     case INDEX_op_sssub_vec:
18898afaf050SRichard Henderson     case INDEX_op_ussub_vec:
18908afaf050SRichard Henderson         return have_vec && TCG_TARGET_HAS_sat_vec;
1891dd0a0fcdSRichard Henderson     case INDEX_op_smin_vec:
1892dd0a0fcdSRichard Henderson     case INDEX_op_umin_vec:
1893dd0a0fcdSRichard Henderson     case INDEX_op_smax_vec:
1894dd0a0fcdSRichard Henderson     case INDEX_op_umax_vec:
1895dd0a0fcdSRichard Henderson         return have_vec && TCG_TARGET_HAS_minmax_vec;
189638dc1294SRichard Henderson     case INDEX_op_bitsel_vec:
189738dc1294SRichard Henderson         return have_vec && TCG_TARGET_HAS_bitsel_vec;
1898f75da298SRichard Henderson     case INDEX_op_cmpsel_vec:
1899f75da298SRichard Henderson         return have_vec && TCG_TARGET_HAS_cmpsel_vec;
1900d2fd745fSRichard Henderson 
1901db432672SRichard Henderson     default:
1902db432672SRichard Henderson         tcg_debug_assert(op > INDEX_op_last_generic && op < NB_OPS);
1903db432672SRichard Henderson         return true;
1904be0f34b5SRichard Henderson     }
1905be0f34b5SRichard Henderson }
1906be0f34b5SRichard Henderson 
190739004a71SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs);
190839004a71SRichard Henderson 
1909ae8b75dcSRichard Henderson void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args)
1910c896fe29Sbellard {
19113e92aa34SRichard Henderson     const TCGHelperInfo *info;
191239004a71SRichard Henderson     TCGv_i64 extend_free[MAX_CALL_IARGS];
191339004a71SRichard Henderson     int n_extend = 0;
191475e8b9b7SRichard Henderson     TCGOp *op;
191539004a71SRichard Henderson     int i, n, pi = 0, total_args;
1916afb49896SRichard Henderson 
1917619205fdSEmilio G. Cota     info = g_hash_table_lookup(helper_table, (gpointer)func);
191839004a71SRichard Henderson     total_args = info->nr_out + info->nr_in + 2;
191939004a71SRichard Henderson     op = tcg_op_alloc(INDEX_op_call, total_args);
19202bece2c8SRichard Henderson 
192138b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN
192217083f6fSEmilio Cota     /* Flag helpers that may affect guest state */
192317083f6fSEmilio Cota     if (tcg_ctx->plugin_insn &&
192417083f6fSEmilio Cota         !(info->flags & TCG_CALL_PLUGIN) &&
192517083f6fSEmilio Cota         !(info->flags & TCG_CALL_NO_SIDE_EFFECTS)) {
192638b47b19SEmilio G. Cota         tcg_ctx->plugin_insn->calls_helpers = true;
192738b47b19SEmilio G. Cota     }
192838b47b19SEmilio G. Cota #endif
192938b47b19SEmilio G. Cota 
193039004a71SRichard Henderson     TCGOP_CALLO(op) = n = info->nr_out;
193139004a71SRichard Henderson     switch (n) {
193239004a71SRichard Henderson     case 0:
193339004a71SRichard Henderson         tcg_debug_assert(ret == NULL);
193439004a71SRichard Henderson         break;
193539004a71SRichard Henderson     case 1:
193639004a71SRichard Henderson         tcg_debug_assert(ret != NULL);
193739004a71SRichard Henderson         op->args[pi++] = temp_arg(ret);
193839004a71SRichard Henderson         break;
193939004a71SRichard Henderson     case 2:
1940466d3759SRichard Henderson     case 4:
194139004a71SRichard Henderson         tcg_debug_assert(ret != NULL);
1942466d3759SRichard Henderson         tcg_debug_assert(ret->base_type == ret->type + ctz32(n));
194339004a71SRichard Henderson         tcg_debug_assert(ret->temp_subindex == 0);
1944466d3759SRichard Henderson         for (i = 0; i < n; ++i) {
1945466d3759SRichard Henderson             op->args[pi++] = temp_arg(ret + i);
1946466d3759SRichard Henderson         }
194739004a71SRichard Henderson         break;
194839004a71SRichard Henderson     default:
194939004a71SRichard Henderson         g_assert_not_reached();
195039004a71SRichard Henderson     }
19517319d83aSRichard Henderson 
195239004a71SRichard Henderson     TCGOP_CALLI(op) = n = info->nr_in;
195339004a71SRichard Henderson     for (i = 0; i < n; i++) {
195439004a71SRichard Henderson         const TCGCallArgumentLoc *loc = &info->in[i];
195539004a71SRichard Henderson         TCGTemp *ts = args[loc->arg_idx] + loc->tmp_subindex;
195639004a71SRichard Henderson 
195739004a71SRichard Henderson         switch (loc->kind) {
195839004a71SRichard Henderson         case TCG_CALL_ARG_NORMAL:
1959313bdea8SRichard Henderson         case TCG_CALL_ARG_BY_REF:
1960313bdea8SRichard Henderson         case TCG_CALL_ARG_BY_REF_N:
196139004a71SRichard Henderson             op->args[pi++] = temp_arg(ts);
196239004a71SRichard Henderson             break;
196339004a71SRichard Henderson 
196439004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_U:
196539004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_S:
196639004a71SRichard Henderson             {
19675dd48602SRichard Henderson                 TCGv_i64 temp = tcg_temp_ebb_new_i64();
196839004a71SRichard Henderson                 TCGv_i32 orig = temp_tcgv_i32(ts);
196939004a71SRichard Henderson 
197039004a71SRichard Henderson                 if (loc->kind == TCG_CALL_ARG_EXTEND_S) {
197118cf3d07SRichard Henderson                     tcg_gen_ext_i32_i64(temp, orig);
19722bece2c8SRichard Henderson                 } else {
197318cf3d07SRichard Henderson                     tcg_gen_extu_i32_i64(temp, orig);
19742bece2c8SRichard Henderson                 }
197539004a71SRichard Henderson                 op->args[pi++] = tcgv_i64_arg(temp);
197639004a71SRichard Henderson                 extend_free[n_extend++] = temp;
19772bece2c8SRichard Henderson             }
197839004a71SRichard Henderson             break;
19792bece2c8SRichard Henderson 
1980e2a9dd6bSRichard Henderson         default:
1981e2a9dd6bSRichard Henderson             g_assert_not_reached();
1982e2a9dd6bSRichard Henderson         }
1983c896fe29Sbellard     }
198475e8b9b7SRichard Henderson     op->args[pi++] = (uintptr_t)func;
19853e92aa34SRichard Henderson     op->args[pi++] = (uintptr_t)info;
198639004a71SRichard Henderson     tcg_debug_assert(pi == total_args);
1987a7812ae4Spbrook 
198839004a71SRichard Henderson     QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
19892bece2c8SRichard Henderson 
199039004a71SRichard Henderson     tcg_debug_assert(n_extend < ARRAY_SIZE(extend_free));
199139004a71SRichard Henderson     for (i = 0; i < n_extend; ++i) {
199239004a71SRichard Henderson         tcg_temp_free_i64(extend_free[i]);
1993eb8b0224SRichard Henderson     }
1994a7812ae4Spbrook }
1995c896fe29Sbellard 
19968fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s)
1997c896fe29Sbellard {
1998ac3b8891SRichard Henderson     int i, n;
1999ac3b8891SRichard Henderson 
2000ee17db83SRichard Henderson     for (i = 0, n = s->nb_temps; i < n; i++) {
2001ee17db83SRichard Henderson         TCGTemp *ts = &s->temps[i];
2002ee17db83SRichard Henderson         TCGTempVal val = TEMP_VAL_MEM;
2003ee17db83SRichard Henderson 
2004ee17db83SRichard Henderson         switch (ts->kind) {
2005c0522136SRichard Henderson         case TEMP_CONST:
2006c0522136SRichard Henderson             val = TEMP_VAL_CONST;
2007c0522136SRichard Henderson             break;
2008ee17db83SRichard Henderson         case TEMP_FIXED:
2009ee17db83SRichard Henderson             val = TEMP_VAL_REG;
2010ee17db83SRichard Henderson             break;
2011ee17db83SRichard Henderson         case TEMP_GLOBAL:
2012ee17db83SRichard Henderson             break;
2013c7482438SRichard Henderson         case TEMP_EBB:
2014ee17db83SRichard Henderson             val = TEMP_VAL_DEAD;
2015ee17db83SRichard Henderson             /* fall through */
2016f57c6915SRichard Henderson         case TEMP_TB:
2017e8996ee0Sbellard             ts->mem_allocated = 0;
2018ee17db83SRichard Henderson             break;
2019ee17db83SRichard Henderson         default:
2020ee17db83SRichard Henderson             g_assert_not_reached();
2021ee17db83SRichard Henderson         }
2022ee17db83SRichard Henderson         ts->val_type = val;
2023e8996ee0Sbellard     }
2024f8b2f202SRichard Henderson 
2025f8b2f202SRichard Henderson     memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp));
2026c896fe29Sbellard }
2027c896fe29Sbellard 
2028f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size,
2029f8b2f202SRichard Henderson                                  TCGTemp *ts)
2030c896fe29Sbellard {
20311807f4c4SRichard Henderson     int idx = temp_idx(ts);
2032ac56dd48Spbrook 
2033ee17db83SRichard Henderson     switch (ts->kind) {
2034ee17db83SRichard Henderson     case TEMP_FIXED:
2035ee17db83SRichard Henderson     case TEMP_GLOBAL:
2036ac56dd48Spbrook         pstrcpy(buf, buf_size, ts->name);
2037ee17db83SRichard Henderson         break;
2038f57c6915SRichard Henderson     case TEMP_TB:
2039641d5fbeSbellard         snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
2040ee17db83SRichard Henderson         break;
2041c7482438SRichard Henderson     case TEMP_EBB:
2042ac56dd48Spbrook         snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
2043ee17db83SRichard Henderson         break;
2044c0522136SRichard Henderson     case TEMP_CONST:
2045c0522136SRichard Henderson         switch (ts->type) {
2046c0522136SRichard Henderson         case TCG_TYPE_I32:
2047c0522136SRichard Henderson             snprintf(buf, buf_size, "$0x%x", (int32_t)ts->val);
2048c0522136SRichard Henderson             break;
2049c0522136SRichard Henderson #if TCG_TARGET_REG_BITS > 32
2050c0522136SRichard Henderson         case TCG_TYPE_I64:
2051c0522136SRichard Henderson             snprintf(buf, buf_size, "$0x%" PRIx64, ts->val);
2052c0522136SRichard Henderson             break;
2053c0522136SRichard Henderson #endif
2054c0522136SRichard Henderson         case TCG_TYPE_V64:
2055c0522136SRichard Henderson         case TCG_TYPE_V128:
2056c0522136SRichard Henderson         case TCG_TYPE_V256:
2057c0522136SRichard Henderson             snprintf(buf, buf_size, "v%d$0x%" PRIx64,
2058c0522136SRichard Henderson                      64 << (ts->type - TCG_TYPE_V64), ts->val);
2059c0522136SRichard Henderson             break;
2060c0522136SRichard Henderson         default:
2061c0522136SRichard Henderson             g_assert_not_reached();
2062c0522136SRichard Henderson         }
2063c0522136SRichard Henderson         break;
2064c896fe29Sbellard     }
2065c896fe29Sbellard     return buf;
2066c896fe29Sbellard }
2067c896fe29Sbellard 
206843439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf,
206943439139SRichard Henderson                              int buf_size, TCGArg arg)
2070f8b2f202SRichard Henderson {
207143439139SRichard Henderson     return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg));
2072f8b2f202SRichard Henderson }
2073f8b2f202SRichard Henderson 
2074f48f3edeSblueswir1 static const char * const cond_name[] =
2075f48f3edeSblueswir1 {
20760aed257fSRichard Henderson     [TCG_COND_NEVER] = "never",
20770aed257fSRichard Henderson     [TCG_COND_ALWAYS] = "always",
2078f48f3edeSblueswir1     [TCG_COND_EQ] = "eq",
2079f48f3edeSblueswir1     [TCG_COND_NE] = "ne",
2080f48f3edeSblueswir1     [TCG_COND_LT] = "lt",
2081f48f3edeSblueswir1     [TCG_COND_GE] = "ge",
2082f48f3edeSblueswir1     [TCG_COND_LE] = "le",
2083f48f3edeSblueswir1     [TCG_COND_GT] = "gt",
2084f48f3edeSblueswir1     [TCG_COND_LTU] = "ltu",
2085f48f3edeSblueswir1     [TCG_COND_GEU] = "geu",
2086f48f3edeSblueswir1     [TCG_COND_LEU] = "leu",
2087f48f3edeSblueswir1     [TCG_COND_GTU] = "gtu"
2088f48f3edeSblueswir1 };
2089f48f3edeSblueswir1 
2090f713d6adSRichard Henderson static const char * const ldst_name[] =
2091f713d6adSRichard Henderson {
2092f713d6adSRichard Henderson     [MO_UB]   = "ub",
2093f713d6adSRichard Henderson     [MO_SB]   = "sb",
2094f713d6adSRichard Henderson     [MO_LEUW] = "leuw",
2095f713d6adSRichard Henderson     [MO_LESW] = "lesw",
2096f713d6adSRichard Henderson     [MO_LEUL] = "leul",
2097f713d6adSRichard Henderson     [MO_LESL] = "lesl",
2098fc313c64SFrédéric Pétrot     [MO_LEUQ] = "leq",
2099f713d6adSRichard Henderson     [MO_BEUW] = "beuw",
2100f713d6adSRichard Henderson     [MO_BESW] = "besw",
2101f713d6adSRichard Henderson     [MO_BEUL] = "beul",
2102f713d6adSRichard Henderson     [MO_BESL] = "besl",
2103fc313c64SFrédéric Pétrot     [MO_BEUQ] = "beq",
2104f713d6adSRichard Henderson };
2105f713d6adSRichard Henderson 
21061f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = {
210752bf9771Stony.nguyen@bt.com #ifdef TARGET_ALIGNED_ONLY
21081f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "un+",
21091f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "",
21101f00b27fSSergey Sorokin #else
21111f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "",
21121f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "al+",
21131f00b27fSSergey Sorokin #endif
21141f00b27fSSergey Sorokin     [MO_ALIGN_2 >> MO_ASHIFT]  = "al2+",
21151f00b27fSSergey Sorokin     [MO_ALIGN_4 >> MO_ASHIFT]  = "al4+",
21161f00b27fSSergey Sorokin     [MO_ALIGN_8 >> MO_ASHIFT]  = "al8+",
21171f00b27fSSergey Sorokin     [MO_ALIGN_16 >> MO_ASHIFT] = "al16+",
21181f00b27fSSergey Sorokin     [MO_ALIGN_32 >> MO_ASHIFT] = "al32+",
21191f00b27fSSergey Sorokin     [MO_ALIGN_64 >> MO_ASHIFT] = "al64+",
21201f00b27fSSergey Sorokin };
21211f00b27fSSergey Sorokin 
2122587195bdSRichard Henderson static const char bswap_flag_name[][6] = {
2123587195bdSRichard Henderson     [TCG_BSWAP_IZ] = "iz",
2124587195bdSRichard Henderson     [TCG_BSWAP_OZ] = "oz",
2125587195bdSRichard Henderson     [TCG_BSWAP_OS] = "os",
2126587195bdSRichard Henderson     [TCG_BSWAP_IZ | TCG_BSWAP_OZ] = "iz,oz",
2127587195bdSRichard Henderson     [TCG_BSWAP_IZ | TCG_BSWAP_OS] = "iz,os",
2128587195bdSRichard Henderson };
2129587195bdSRichard Henderson 
2130b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d)
2131b016486eSRichard Henderson {
2132b016486eSRichard Henderson     return (d & (d - 1)) == 0;
2133b016486eSRichard Henderson }
2134b016486eSRichard Henderson 
2135b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d)
2136b016486eSRichard Henderson {
2137b016486eSRichard Henderson     if (TCG_TARGET_NB_REGS <= 32) {
2138b016486eSRichard Henderson         return ctz32(d);
2139b016486eSRichard Henderson     } else {
2140b016486eSRichard Henderson         return ctz64(d);
2141b016486eSRichard Henderson     }
2142b016486eSRichard Henderson }
2143b016486eSRichard Henderson 
2144b7a83ff8SRichard Henderson /* Return only the number of characters output -- no error return. */
2145b7a83ff8SRichard Henderson #define ne_fprintf(...) \
2146b7a83ff8SRichard Henderson     ({ int ret_ = fprintf(__VA_ARGS__); ret_ >= 0 ? ret_ : 0; })
2147b7a83ff8SRichard Henderson 
2148b7a83ff8SRichard Henderson static void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs)
2149c896fe29Sbellard {
2150c896fe29Sbellard     char buf[128];
2151c45cb8bbSRichard Henderson     TCGOp *op;
2152c896fe29Sbellard 
215315fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
2154c45cb8bbSRichard Henderson         int i, k, nb_oargs, nb_iargs, nb_cargs;
2155c45cb8bbSRichard Henderson         const TCGOpDef *def;
2156c45cb8bbSRichard Henderson         TCGOpcode c;
2157bdfb460eSRichard Henderson         int col = 0;
2158c45cb8bbSRichard Henderson 
2159c45cb8bbSRichard Henderson         c = op->opc;
2160c896fe29Sbellard         def = &tcg_op_defs[c];
2161c45cb8bbSRichard Henderson 
2162765b842aSRichard Henderson         if (c == INDEX_op_insn_start) {
2163b016486eSRichard Henderson             nb_oargs = 0;
2164b7a83ff8SRichard Henderson             col += ne_fprintf(f, "\n ----");
21659aef40edSRichard Henderson 
21669aef40edSRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
21679aef40edSRichard Henderson                 target_ulong a;
21687e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
2169efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
21707e4597d7Sbellard #else
2171efee3746SRichard Henderson                 a = op->args[i];
21727e4597d7Sbellard #endif
2173b7a83ff8SRichard Henderson                 col += ne_fprintf(f, " " TARGET_FMT_lx, a);
2174eeacee4dSBlue Swirl             }
21757e4597d7Sbellard         } else if (c == INDEX_op_call) {
21763e92aa34SRichard Henderson             const TCGHelperInfo *info = tcg_call_info(op);
2177fa52e660SRichard Henderson             void *func = tcg_call_func(op);
21783e92aa34SRichard Henderson 
2179c896fe29Sbellard             /* variable number of arguments */
2180cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
2181cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
2182c896fe29Sbellard             nb_cargs = def->nb_cargs;
2183b03cce8eSbellard 
2184b7a83ff8SRichard Henderson             col += ne_fprintf(f, " %s ", def->name);
21853e92aa34SRichard Henderson 
21863e92aa34SRichard Henderson             /*
21873e92aa34SRichard Henderson              * Print the function name from TCGHelperInfo, if available.
21883e92aa34SRichard Henderson              * Note that plugins have a template function for the info,
21893e92aa34SRichard Henderson              * but the actual function pointer comes from the plugin.
21903e92aa34SRichard Henderson              */
21913e92aa34SRichard Henderson             if (func == info->func) {
2192b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s", info->name);
21933e92aa34SRichard Henderson             } else {
2194b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "plugin(%p)", func);
21953e92aa34SRichard Henderson             }
21963e92aa34SRichard Henderson 
2197b7a83ff8SRichard Henderson             col += ne_fprintf(f, ",$0x%x,$%d", info->flags, nb_oargs);
2198b03cce8eSbellard             for (i = 0; i < nb_oargs; i++) {
2199b7a83ff8SRichard Henderson                 col += ne_fprintf(f, ",%s", tcg_get_arg_str(s, buf, sizeof(buf),
2200efee3746SRichard Henderson                                                             op->args[i]));
2201b03cce8eSbellard             }
2202cf066674SRichard Henderson             for (i = 0; i < nb_iargs; i++) {
2203efee3746SRichard Henderson                 TCGArg arg = op->args[nb_oargs + i];
220439004a71SRichard Henderson                 const char *t = tcg_get_arg_str(s, buf, sizeof(buf), arg);
2205b7a83ff8SRichard Henderson                 col += ne_fprintf(f, ",%s", t);
2206e8996ee0Sbellard             }
2207b03cce8eSbellard         } else {
2208b7a83ff8SRichard Henderson             col += ne_fprintf(f, " %s ", def->name);
2209c45cb8bbSRichard Henderson 
2210c896fe29Sbellard             nb_oargs = def->nb_oargs;
2211c896fe29Sbellard             nb_iargs = def->nb_iargs;
2212c896fe29Sbellard             nb_cargs = def->nb_cargs;
2213c896fe29Sbellard 
2214d2fd745fSRichard Henderson             if (def->flags & TCG_OPF_VECTOR) {
2215b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "v%d,e%d,", 64 << TCGOP_VECL(op),
2216d2fd745fSRichard Henderson                                   8 << TCGOP_VECE(op));
2217d2fd745fSRichard Henderson             }
2218d2fd745fSRichard Henderson 
2219c896fe29Sbellard             k = 0;
2220c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
2221b7a83ff8SRichard Henderson                 const char *sep =  k ? "," : "";
2222b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s%s", sep,
2223b7a83ff8SRichard Henderson                                   tcg_get_arg_str(s, buf, sizeof(buf),
2224efee3746SRichard Henderson                                                   op->args[k++]));
2225c896fe29Sbellard             }
2226c896fe29Sbellard             for (i = 0; i < nb_iargs; i++) {
2227b7a83ff8SRichard Henderson                 const char *sep =  k ? "," : "";
2228b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s%s", sep,
2229b7a83ff8SRichard Henderson                                   tcg_get_arg_str(s, buf, sizeof(buf),
2230efee3746SRichard Henderson                                                   op->args[k++]));
2231c896fe29Sbellard             }
2232be210acbSRichard Henderson             switch (c) {
2233be210acbSRichard Henderson             case INDEX_op_brcond_i32:
2234ffc5ea09SRichard Henderson             case INDEX_op_setcond_i32:
2235ffc5ea09SRichard Henderson             case INDEX_op_movcond_i32:
2236be210acbSRichard Henderson             case INDEX_op_brcond2_i32:
2237be210acbSRichard Henderson             case INDEX_op_setcond2_i32:
2238ffc5ea09SRichard Henderson             case INDEX_op_brcond_i64:
2239be210acbSRichard Henderson             case INDEX_op_setcond_i64:
2240ffc5ea09SRichard Henderson             case INDEX_op_movcond_i64:
2241212be173SRichard Henderson             case INDEX_op_cmp_vec:
2242f75da298SRichard Henderson             case INDEX_op_cmpsel_vec:
2243efee3746SRichard Henderson                 if (op->args[k] < ARRAY_SIZE(cond_name)
2244efee3746SRichard Henderson                     && cond_name[op->args[k]]) {
2245b7a83ff8SRichard Henderson                     col += ne_fprintf(f, ",%s", cond_name[op->args[k++]]);
2246eeacee4dSBlue Swirl                 } else {
2247b7a83ff8SRichard Henderson                     col += ne_fprintf(f, ",$0x%" TCG_PRIlx, op->args[k++]);
2248eeacee4dSBlue Swirl                 }
2249f48f3edeSblueswir1                 i = 1;
2250be210acbSRichard Henderson                 break;
2251f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i32:
2252f713d6adSRichard Henderson             case INDEX_op_qemu_st_i32:
225307ce0b05SRichard Henderson             case INDEX_op_qemu_st8_i32:
2254f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i64:
2255f713d6adSRichard Henderson             case INDEX_op_qemu_st_i64:
225659227d5dSRichard Henderson                 {
22579002ffcbSRichard Henderson                     MemOpIdx oi = op->args[k++];
225814776ab5STony Nguyen                     MemOp op = get_memop(oi);
225959227d5dSRichard Henderson                     unsigned ix = get_mmuidx(oi);
226059227d5dSRichard Henderson 
226159c4b7e8SRichard Henderson                     if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) {
2262b7a83ff8SRichard Henderson                         col += ne_fprintf(f, ",$0x%x,%u", op, ix);
226359c4b7e8SRichard Henderson                     } else {
22641f00b27fSSergey Sorokin                         const char *s_al, *s_op;
22651f00b27fSSergey Sorokin                         s_al = alignment_name[(op & MO_AMASK) >> MO_ASHIFT];
226659c4b7e8SRichard Henderson                         s_op = ldst_name[op & (MO_BSWAP | MO_SSIZE)];
2267b7a83ff8SRichard Henderson                         col += ne_fprintf(f, ",%s%s,%u", s_al, s_op, ix);
2268f713d6adSRichard Henderson                     }
2269f713d6adSRichard Henderson                     i = 1;
227059227d5dSRichard Henderson                 }
2271f713d6adSRichard Henderson                 break;
2272587195bdSRichard Henderson             case INDEX_op_bswap16_i32:
2273587195bdSRichard Henderson             case INDEX_op_bswap16_i64:
2274587195bdSRichard Henderson             case INDEX_op_bswap32_i32:
2275587195bdSRichard Henderson             case INDEX_op_bswap32_i64:
2276587195bdSRichard Henderson             case INDEX_op_bswap64_i64:
2277587195bdSRichard Henderson                 {
2278587195bdSRichard Henderson                     TCGArg flags = op->args[k];
2279587195bdSRichard Henderson                     const char *name = NULL;
2280587195bdSRichard Henderson 
2281587195bdSRichard Henderson                     if (flags < ARRAY_SIZE(bswap_flag_name)) {
2282587195bdSRichard Henderson                         name = bswap_flag_name[flags];
2283587195bdSRichard Henderson                     }
2284587195bdSRichard Henderson                     if (name) {
2285b7a83ff8SRichard Henderson                         col += ne_fprintf(f, ",%s", name);
2286587195bdSRichard Henderson                     } else {
2287b7a83ff8SRichard Henderson                         col += ne_fprintf(f, ",$0x%" TCG_PRIlx, flags);
2288587195bdSRichard Henderson                     }
2289587195bdSRichard Henderson                     i = k = 1;
2290587195bdSRichard Henderson                 }
2291587195bdSRichard Henderson                 break;
2292be210acbSRichard Henderson             default:
2293f48f3edeSblueswir1                 i = 0;
2294be210acbSRichard Henderson                 break;
2295be210acbSRichard Henderson             }
229651e3972cSRichard Henderson             switch (c) {
229751e3972cSRichard Henderson             case INDEX_op_set_label:
229851e3972cSRichard Henderson             case INDEX_op_br:
229951e3972cSRichard Henderson             case INDEX_op_brcond_i32:
230051e3972cSRichard Henderson             case INDEX_op_brcond_i64:
230151e3972cSRichard Henderson             case INDEX_op_brcond2_i32:
2302b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s$L%d", k ? "," : "",
2303efee3746SRichard Henderson                                   arg_label(op->args[k])->id);
230451e3972cSRichard Henderson                 i++, k++;
230551e3972cSRichard Henderson                 break;
23063470867bSRichard Henderson             case INDEX_op_mb:
23073470867bSRichard Henderson                 {
23083470867bSRichard Henderson                     TCGBar membar = op->args[k];
23093470867bSRichard Henderson                     const char *b_op, *m_op;
23103470867bSRichard Henderson 
23113470867bSRichard Henderson                     switch (membar & TCG_BAR_SC) {
23123470867bSRichard Henderson                     case 0:
23133470867bSRichard Henderson                         b_op = "none";
23143470867bSRichard Henderson                         break;
23153470867bSRichard Henderson                     case TCG_BAR_LDAQ:
23163470867bSRichard Henderson                         b_op = "acq";
23173470867bSRichard Henderson                         break;
23183470867bSRichard Henderson                     case TCG_BAR_STRL:
23193470867bSRichard Henderson                         b_op = "rel";
23203470867bSRichard Henderson                         break;
23213470867bSRichard Henderson                     case TCG_BAR_SC:
23223470867bSRichard Henderson                         b_op = "seq";
23233470867bSRichard Henderson                         break;
23243470867bSRichard Henderson                     default:
23253470867bSRichard Henderson                         g_assert_not_reached();
23263470867bSRichard Henderson                     }
23273470867bSRichard Henderson 
23283470867bSRichard Henderson                     switch (membar & TCG_MO_ALL) {
23293470867bSRichard Henderson                     case 0:
23303470867bSRichard Henderson                         m_op = "none";
23313470867bSRichard Henderson                         break;
23323470867bSRichard Henderson                     case TCG_MO_LD_LD:
23333470867bSRichard Henderson                         m_op = "rr";
23343470867bSRichard Henderson                         break;
23353470867bSRichard Henderson                     case TCG_MO_LD_ST:
23363470867bSRichard Henderson                         m_op = "rw";
23373470867bSRichard Henderson                         break;
23383470867bSRichard Henderson                     case TCG_MO_ST_LD:
23393470867bSRichard Henderson                         m_op = "wr";
23403470867bSRichard Henderson                         break;
23413470867bSRichard Henderson                     case TCG_MO_ST_ST:
23423470867bSRichard Henderson                         m_op = "ww";
23433470867bSRichard Henderson                         break;
23443470867bSRichard Henderson                     case TCG_MO_LD_LD | TCG_MO_LD_ST:
23453470867bSRichard Henderson                         m_op = "rr+rw";
23463470867bSRichard Henderson                         break;
23473470867bSRichard Henderson                     case TCG_MO_LD_LD | TCG_MO_ST_LD:
23483470867bSRichard Henderson                         m_op = "rr+wr";
23493470867bSRichard Henderson                         break;
23503470867bSRichard Henderson                     case TCG_MO_LD_LD | TCG_MO_ST_ST:
23513470867bSRichard Henderson                         m_op = "rr+ww";
23523470867bSRichard Henderson                         break;
23533470867bSRichard Henderson                     case TCG_MO_LD_ST | TCG_MO_ST_LD:
23543470867bSRichard Henderson                         m_op = "rw+wr";
23553470867bSRichard Henderson                         break;
23563470867bSRichard Henderson                     case TCG_MO_LD_ST | TCG_MO_ST_ST:
23573470867bSRichard Henderson                         m_op = "rw+ww";
23583470867bSRichard Henderson                         break;
23593470867bSRichard Henderson                     case TCG_MO_ST_LD | TCG_MO_ST_ST:
23603470867bSRichard Henderson                         m_op = "wr+ww";
23613470867bSRichard Henderson                         break;
23623470867bSRichard Henderson                     case TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_MO_ST_LD:
23633470867bSRichard Henderson                         m_op = "rr+rw+wr";
23643470867bSRichard Henderson                         break;
23653470867bSRichard Henderson                     case TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_MO_ST_ST:
23663470867bSRichard Henderson                         m_op = "rr+rw+ww";
23673470867bSRichard Henderson                         break;
23683470867bSRichard Henderson                     case TCG_MO_LD_LD | TCG_MO_ST_LD | TCG_MO_ST_ST:
23693470867bSRichard Henderson                         m_op = "rr+wr+ww";
23703470867bSRichard Henderson                         break;
23713470867bSRichard Henderson                     case TCG_MO_LD_ST | TCG_MO_ST_LD | TCG_MO_ST_ST:
23723470867bSRichard Henderson                         m_op = "rw+wr+ww";
23733470867bSRichard Henderson                         break;
23743470867bSRichard Henderson                     case TCG_MO_ALL:
23753470867bSRichard Henderson                         m_op = "all";
23763470867bSRichard Henderson                         break;
23773470867bSRichard Henderson                     default:
23783470867bSRichard Henderson                         g_assert_not_reached();
23793470867bSRichard Henderson                     }
23803470867bSRichard Henderson 
23813470867bSRichard Henderson                     col += ne_fprintf(f, "%s%s:%s", (k ? "," : ""), b_op, m_op);
23823470867bSRichard Henderson                     i++, k++;
23833470867bSRichard Henderson                 }
23843470867bSRichard Henderson                 break;
238551e3972cSRichard Henderson             default:
238651e3972cSRichard Henderson                 break;
2387eeacee4dSBlue Swirl             }
238851e3972cSRichard Henderson             for (; i < nb_cargs; i++, k++) {
2389b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s$0x%" TCG_PRIlx, k ? "," : "",
2390b7a83ff8SRichard Henderson                                   op->args[k]);
2391bdfb460eSRichard Henderson             }
2392bdfb460eSRichard Henderson         }
2393bdfb460eSRichard Henderson 
23941894f69aSRichard Henderson         if (have_prefs || op->life) {
23951894f69aSRichard Henderson             for (; col < 40; ++col) {
2396b7a83ff8SRichard Henderson                 putc(' ', f);
2397bdfb460eSRichard Henderson             }
23981894f69aSRichard Henderson         }
23991894f69aSRichard Henderson 
24001894f69aSRichard Henderson         if (op->life) {
24011894f69aSRichard Henderson             unsigned life = op->life;
2402bdfb460eSRichard Henderson 
2403bdfb460eSRichard Henderson             if (life & (SYNC_ARG * 3)) {
2404b7a83ff8SRichard Henderson                 ne_fprintf(f, "  sync:");
2405bdfb460eSRichard Henderson                 for (i = 0; i < 2; ++i) {
2406bdfb460eSRichard Henderson                     if (life & (SYNC_ARG << i)) {
2407b7a83ff8SRichard Henderson                         ne_fprintf(f, " %d", i);
2408bdfb460eSRichard Henderson                     }
2409bdfb460eSRichard Henderson                 }
2410bdfb460eSRichard Henderson             }
2411bdfb460eSRichard Henderson             life /= DEAD_ARG;
2412bdfb460eSRichard Henderson             if (life) {
2413b7a83ff8SRichard Henderson                 ne_fprintf(f, "  dead:");
2414bdfb460eSRichard Henderson                 for (i = 0; life; ++i, life >>= 1) {
2415bdfb460eSRichard Henderson                     if (life & 1) {
2416b7a83ff8SRichard Henderson                         ne_fprintf(f, " %d", i);
2417bdfb460eSRichard Henderson                     }
2418bdfb460eSRichard Henderson                 }
2419c896fe29Sbellard             }
2420b03cce8eSbellard         }
24211894f69aSRichard Henderson 
24221894f69aSRichard Henderson         if (have_prefs) {
24231894f69aSRichard Henderson             for (i = 0; i < nb_oargs; ++i) {
242431fd884bSRichard Henderson                 TCGRegSet set = output_pref(op, i);
24251894f69aSRichard Henderson 
24261894f69aSRichard Henderson                 if (i == 0) {
2427b7a83ff8SRichard Henderson                     ne_fprintf(f, "  pref=");
24281894f69aSRichard Henderson                 } else {
2429b7a83ff8SRichard Henderson                     ne_fprintf(f, ",");
24301894f69aSRichard Henderson                 }
24311894f69aSRichard Henderson                 if (set == 0) {
2432b7a83ff8SRichard Henderson                     ne_fprintf(f, "none");
24331894f69aSRichard Henderson                 } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) {
2434b7a83ff8SRichard Henderson                     ne_fprintf(f, "all");
24351894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG
24361894f69aSRichard Henderson                 } else if (tcg_regset_single(set)) {
24371894f69aSRichard Henderson                     TCGReg reg = tcg_regset_first(set);
2438b7a83ff8SRichard Henderson                     ne_fprintf(f, "%s", tcg_target_reg_names[reg]);
24391894f69aSRichard Henderson #endif
24401894f69aSRichard Henderson                 } else if (TCG_TARGET_NB_REGS <= 32) {
2441b7a83ff8SRichard Henderson                     ne_fprintf(f, "0x%x", (uint32_t)set);
24421894f69aSRichard Henderson                 } else {
2443b7a83ff8SRichard Henderson                     ne_fprintf(f, "0x%" PRIx64, (uint64_t)set);
24441894f69aSRichard Henderson                 }
24451894f69aSRichard Henderson             }
24461894f69aSRichard Henderson         }
24471894f69aSRichard Henderson 
2448b7a83ff8SRichard Henderson         putc('\n', f);
2449c896fe29Sbellard     }
2450c896fe29Sbellard }
2451c896fe29Sbellard 
2452c896fe29Sbellard /* we give more priority to constraints with less registers */
2453c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k)
2454c896fe29Sbellard {
245574a11790SRichard Henderson     const TCGArgConstraint *arg_ct = &def->args_ct[k];
245629f5e925SRichard Henderson     int n = ctpop64(arg_ct->regs);
2457c896fe29Sbellard 
245829f5e925SRichard Henderson     /*
245929f5e925SRichard Henderson      * Sort constraints of a single register first, which includes output
246029f5e925SRichard Henderson      * aliases (which must exactly match the input already allocated).
246129f5e925SRichard Henderson      */
246229f5e925SRichard Henderson     if (n == 1 || arg_ct->oalias) {
246329f5e925SRichard Henderson         return INT_MAX;
2464c896fe29Sbellard     }
246529f5e925SRichard Henderson 
246629f5e925SRichard Henderson     /*
246729f5e925SRichard Henderson      * Sort register pairs next, first then second immediately after.
246829f5e925SRichard Henderson      * Arbitrarily sort multiple pairs by the index of the first reg;
246929f5e925SRichard Henderson      * there shouldn't be many pairs.
247029f5e925SRichard Henderson      */
247129f5e925SRichard Henderson     switch (arg_ct->pair) {
247229f5e925SRichard Henderson     case 1:
247329f5e925SRichard Henderson     case 3:
247429f5e925SRichard Henderson         return (k + 1) * 2;
247529f5e925SRichard Henderson     case 2:
247629f5e925SRichard Henderson         return (arg_ct->pair_index + 1) * 2 - 1;
247729f5e925SRichard Henderson     }
247829f5e925SRichard Henderson 
247929f5e925SRichard Henderson     /* Finally, sort by decreasing register count. */
248029f5e925SRichard Henderson     assert(n > 1);
248129f5e925SRichard Henderson     return -n;
2482c896fe29Sbellard }
2483c896fe29Sbellard 
2484c896fe29Sbellard /* sort from highest priority to lowest */
2485c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n)
2486c896fe29Sbellard {
248766792f90SRichard Henderson     int i, j;
248866792f90SRichard Henderson     TCGArgConstraint *a = def->args_ct;
2489c896fe29Sbellard 
249066792f90SRichard Henderson     for (i = 0; i < n; i++) {
249166792f90SRichard Henderson         a[start + i].sort_index = start + i;
249266792f90SRichard Henderson     }
249366792f90SRichard Henderson     if (n <= 1) {
2494c896fe29Sbellard         return;
249566792f90SRichard Henderson     }
2496c896fe29Sbellard     for (i = 0; i < n - 1; i++) {
2497c896fe29Sbellard         for (j = i + 1; j < n; j++) {
249866792f90SRichard Henderson             int p1 = get_constraint_priority(def, a[start + i].sort_index);
249966792f90SRichard Henderson             int p2 = get_constraint_priority(def, a[start + j].sort_index);
2500c896fe29Sbellard             if (p1 < p2) {
250166792f90SRichard Henderson                 int tmp = a[start + i].sort_index;
250266792f90SRichard Henderson                 a[start + i].sort_index = a[start + j].sort_index;
250366792f90SRichard Henderson                 a[start + j].sort_index = tmp;
2504c896fe29Sbellard             }
2505c896fe29Sbellard         }
2506c896fe29Sbellard     }
2507c896fe29Sbellard }
2508c896fe29Sbellard 
2509f69d277eSRichard Henderson static void process_op_defs(TCGContext *s)
2510c896fe29Sbellard {
2511a9751609SRichard Henderson     TCGOpcode op;
2512c896fe29Sbellard 
2513f69d277eSRichard Henderson     for (op = 0; op < NB_OPS; op++) {
2514f69d277eSRichard Henderson         TCGOpDef *def = &tcg_op_defs[op];
2515f69d277eSRichard Henderson         const TCGTargetOpDef *tdefs;
251629f5e925SRichard Henderson         bool saw_alias_pair = false;
251729f5e925SRichard Henderson         int i, o, i2, o2, nb_args;
2518f69d277eSRichard Henderson 
2519f69d277eSRichard Henderson         if (def->flags & TCG_OPF_NOT_PRESENT) {
2520f69d277eSRichard Henderson             continue;
2521f69d277eSRichard Henderson         }
2522f69d277eSRichard Henderson 
2523c896fe29Sbellard         nb_args = def->nb_iargs + def->nb_oargs;
2524f69d277eSRichard Henderson         if (nb_args == 0) {
2525f69d277eSRichard Henderson             continue;
2526f69d277eSRichard Henderson         }
2527f69d277eSRichard Henderson 
25284c22e840SRichard Henderson         /*
25294c22e840SRichard Henderson          * Macro magic should make it impossible, but double-check that
25304c22e840SRichard Henderson          * the array index is in range.  Since the signness of an enum
25314c22e840SRichard Henderson          * is implementation defined, force the result to unsigned.
25324c22e840SRichard Henderson          */
25334c22e840SRichard Henderson         unsigned con_set = tcg_target_op_def(op);
25344c22e840SRichard Henderson         tcg_debug_assert(con_set < ARRAY_SIZE(constraint_sets));
25354c22e840SRichard Henderson         tdefs = &constraint_sets[con_set];
2536f69d277eSRichard Henderson 
2537c896fe29Sbellard         for (i = 0; i < nb_args; i++) {
2538f69d277eSRichard Henderson             const char *ct_str = tdefs->args_ct_str[i];
25398940ea0dSPhilippe Mathieu-Daudé             bool input_p = i >= def->nb_oargs;
25408940ea0dSPhilippe Mathieu-Daudé 
2541f69d277eSRichard Henderson             /* Incomplete TCGTargetOpDef entry. */
2542eabb7b91SAurelien Jarno             tcg_debug_assert(ct_str != NULL);
2543f69d277eSRichard Henderson 
254417280ff4SRichard Henderson             switch (*ct_str) {
254517280ff4SRichard Henderson             case '0' ... '9':
25468940ea0dSPhilippe Mathieu-Daudé                 o = *ct_str - '0';
25478940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(input_p);
25488940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(o < def->nb_oargs);
25498940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(def->args_ct[o].regs != 0);
25508940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(!def->args_ct[o].oalias);
25518940ea0dSPhilippe Mathieu-Daudé                 def->args_ct[i] = def->args_ct[o];
2552bc2b17e6SRichard Henderson                 /* The output sets oalias.  */
25538940ea0dSPhilippe Mathieu-Daudé                 def->args_ct[o].oalias = 1;
25548940ea0dSPhilippe Mathieu-Daudé                 def->args_ct[o].alias_index = i;
2555bc2b17e6SRichard Henderson                 /* The input sets ialias. */
25568940ea0dSPhilippe Mathieu-Daudé                 def->args_ct[i].ialias = 1;
25578940ea0dSPhilippe Mathieu-Daudé                 def->args_ct[i].alias_index = o;
255829f5e925SRichard Henderson                 if (def->args_ct[i].pair) {
255929f5e925SRichard Henderson                     saw_alias_pair = true;
256029f5e925SRichard Henderson                 }
25618940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(ct_str[1] == '\0');
25628940ea0dSPhilippe Mathieu-Daudé                 continue;
25638940ea0dSPhilippe Mathieu-Daudé 
256482790a87SRichard Henderson             case '&':
25658940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(!input_p);
2566bc2b17e6SRichard Henderson                 def->args_ct[i].newreg = true;
256782790a87SRichard Henderson                 ct_str++;
256882790a87SRichard Henderson                 break;
256929f5e925SRichard Henderson 
257029f5e925SRichard Henderson             case 'p': /* plus */
257129f5e925SRichard Henderson                 /* Allocate to the register after the previous. */
257229f5e925SRichard Henderson                 tcg_debug_assert(i > (input_p ? def->nb_oargs : 0));
257329f5e925SRichard Henderson                 o = i - 1;
257429f5e925SRichard Henderson                 tcg_debug_assert(!def->args_ct[o].pair);
257529f5e925SRichard Henderson                 tcg_debug_assert(!def->args_ct[o].ct);
257629f5e925SRichard Henderson                 def->args_ct[i] = (TCGArgConstraint){
257729f5e925SRichard Henderson                     .pair = 2,
257829f5e925SRichard Henderson                     .pair_index = o,
257929f5e925SRichard Henderson                     .regs = def->args_ct[o].regs << 1,
258029f5e925SRichard Henderson                 };
258129f5e925SRichard Henderson                 def->args_ct[o].pair = 1;
258229f5e925SRichard Henderson                 def->args_ct[o].pair_index = i;
258329f5e925SRichard Henderson                 tcg_debug_assert(ct_str[1] == '\0');
258429f5e925SRichard Henderson                 continue;
258529f5e925SRichard Henderson 
258629f5e925SRichard Henderson             case 'm': /* minus */
258729f5e925SRichard Henderson                 /* Allocate to the register before the previous. */
258829f5e925SRichard Henderson                 tcg_debug_assert(i > (input_p ? def->nb_oargs : 0));
258929f5e925SRichard Henderson                 o = i - 1;
259029f5e925SRichard Henderson                 tcg_debug_assert(!def->args_ct[o].pair);
259129f5e925SRichard Henderson                 tcg_debug_assert(!def->args_ct[o].ct);
259229f5e925SRichard Henderson                 def->args_ct[i] = (TCGArgConstraint){
259329f5e925SRichard Henderson                     .pair = 1,
259429f5e925SRichard Henderson                     .pair_index = o,
259529f5e925SRichard Henderson                     .regs = def->args_ct[o].regs >> 1,
259629f5e925SRichard Henderson                 };
259729f5e925SRichard Henderson                 def->args_ct[o].pair = 2;
259829f5e925SRichard Henderson                 def->args_ct[o].pair_index = i;
259929f5e925SRichard Henderson                 tcg_debug_assert(ct_str[1] == '\0');
260029f5e925SRichard Henderson                 continue;
26018940ea0dSPhilippe Mathieu-Daudé             }
26028940ea0dSPhilippe Mathieu-Daudé 
26038940ea0dSPhilippe Mathieu-Daudé             do {
26048940ea0dSPhilippe Mathieu-Daudé                 switch (*ct_str) {
2605c896fe29Sbellard                 case 'i':
2606c896fe29Sbellard                     def->args_ct[i].ct |= TCG_CT_CONST;
2607c896fe29Sbellard                     break;
2608358b4923SRichard Henderson 
2609358b4923SRichard Henderson                 /* Include all of the target-specific constraints. */
2610358b4923SRichard Henderson 
2611358b4923SRichard Henderson #undef CONST
2612358b4923SRichard Henderson #define CONST(CASE, MASK) \
26138940ea0dSPhilippe Mathieu-Daudé     case CASE: def->args_ct[i].ct |= MASK; break;
2614358b4923SRichard Henderson #define REGS(CASE, MASK) \
26158940ea0dSPhilippe Mathieu-Daudé     case CASE: def->args_ct[i].regs |= MASK; break;
2616358b4923SRichard Henderson 
2617358b4923SRichard Henderson #include "tcg-target-con-str.h"
2618358b4923SRichard Henderson 
2619358b4923SRichard Henderson #undef REGS
2620358b4923SRichard Henderson #undef CONST
2621c896fe29Sbellard                 default:
26228940ea0dSPhilippe Mathieu-Daudé                 case '0' ... '9':
26238940ea0dSPhilippe Mathieu-Daudé                 case '&':
262429f5e925SRichard Henderson                 case 'p':
262529f5e925SRichard Henderson                 case 'm':
2626358b4923SRichard Henderson                     /* Typo in TCGTargetOpDef constraint. */
2627358b4923SRichard Henderson                     g_assert_not_reached();
2628358b4923SRichard Henderson                 }
26298940ea0dSPhilippe Mathieu-Daudé             } while (*++ct_str != '\0');
2630c896fe29Sbellard         }
2631c896fe29Sbellard 
2632c68aaa18SStefan Weil         /* TCGTargetOpDef entry with too much information? */
2633eabb7b91SAurelien Jarno         tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
2634c68aaa18SStefan Weil 
263529f5e925SRichard Henderson         /*
263629f5e925SRichard Henderson          * Fix up output pairs that are aliased with inputs.
263729f5e925SRichard Henderson          * When we created the alias, we copied pair from the output.
263829f5e925SRichard Henderson          * There are three cases:
263929f5e925SRichard Henderson          *    (1a) Pairs of inputs alias pairs of outputs.
264029f5e925SRichard Henderson          *    (1b) One input aliases the first of a pair of outputs.
264129f5e925SRichard Henderson          *    (2)  One input aliases the second of a pair of outputs.
264229f5e925SRichard Henderson          *
264329f5e925SRichard Henderson          * Case 1a is handled by making sure that the pair_index'es are
264429f5e925SRichard Henderson          * properly updated so that they appear the same as a pair of inputs.
264529f5e925SRichard Henderson          *
264629f5e925SRichard Henderson          * Case 1b is handled by setting the pair_index of the input to
264729f5e925SRichard Henderson          * itself, simply so it doesn't point to an unrelated argument.
264829f5e925SRichard Henderson          * Since we don't encounter the "second" during the input allocation
264929f5e925SRichard Henderson          * phase, nothing happens with the second half of the input pair.
265029f5e925SRichard Henderson          *
265129f5e925SRichard Henderson          * Case 2 is handled by setting the second input to pair=3, the
265229f5e925SRichard Henderson          * first output to pair=3, and the pair_index'es to match.
265329f5e925SRichard Henderson          */
265429f5e925SRichard Henderson         if (saw_alias_pair) {
265529f5e925SRichard Henderson             for (i = def->nb_oargs; i < nb_args; i++) {
265629f5e925SRichard Henderson                 /*
265729f5e925SRichard Henderson                  * Since [0-9pm] must be alone in the constraint string,
265829f5e925SRichard Henderson                  * the only way they can both be set is if the pair comes
265929f5e925SRichard Henderson                  * from the output alias.
266029f5e925SRichard Henderson                  */
266129f5e925SRichard Henderson                 if (!def->args_ct[i].ialias) {
266229f5e925SRichard Henderson                     continue;
266329f5e925SRichard Henderson                 }
266429f5e925SRichard Henderson                 switch (def->args_ct[i].pair) {
266529f5e925SRichard Henderson                 case 0:
266629f5e925SRichard Henderson                     break;
266729f5e925SRichard Henderson                 case 1:
266829f5e925SRichard Henderson                     o = def->args_ct[i].alias_index;
266929f5e925SRichard Henderson                     o2 = def->args_ct[o].pair_index;
267029f5e925SRichard Henderson                     tcg_debug_assert(def->args_ct[o].pair == 1);
267129f5e925SRichard Henderson                     tcg_debug_assert(def->args_ct[o2].pair == 2);
267229f5e925SRichard Henderson                     if (def->args_ct[o2].oalias) {
267329f5e925SRichard Henderson                         /* Case 1a */
267429f5e925SRichard Henderson                         i2 = def->args_ct[o2].alias_index;
267529f5e925SRichard Henderson                         tcg_debug_assert(def->args_ct[i2].pair == 2);
267629f5e925SRichard Henderson                         def->args_ct[i2].pair_index = i;
267729f5e925SRichard Henderson                         def->args_ct[i].pair_index = i2;
267829f5e925SRichard Henderson                     } else {
267929f5e925SRichard Henderson                         /* Case 1b */
268029f5e925SRichard Henderson                         def->args_ct[i].pair_index = i;
268129f5e925SRichard Henderson                     }
268229f5e925SRichard Henderson                     break;
268329f5e925SRichard Henderson                 case 2:
268429f5e925SRichard Henderson                     o = def->args_ct[i].alias_index;
268529f5e925SRichard Henderson                     o2 = def->args_ct[o].pair_index;
268629f5e925SRichard Henderson                     tcg_debug_assert(def->args_ct[o].pair == 2);
268729f5e925SRichard Henderson                     tcg_debug_assert(def->args_ct[o2].pair == 1);
268829f5e925SRichard Henderson                     if (def->args_ct[o2].oalias) {
268929f5e925SRichard Henderson                         /* Case 1a */
269029f5e925SRichard Henderson                         i2 = def->args_ct[o2].alias_index;
269129f5e925SRichard Henderson                         tcg_debug_assert(def->args_ct[i2].pair == 1);
269229f5e925SRichard Henderson                         def->args_ct[i2].pair_index = i;
269329f5e925SRichard Henderson                         def->args_ct[i].pair_index = i2;
269429f5e925SRichard Henderson                     } else {
269529f5e925SRichard Henderson                         /* Case 2 */
269629f5e925SRichard Henderson                         def->args_ct[i].pair = 3;
269729f5e925SRichard Henderson                         def->args_ct[o2].pair = 3;
269829f5e925SRichard Henderson                         def->args_ct[i].pair_index = o2;
269929f5e925SRichard Henderson                         def->args_ct[o2].pair_index = i;
270029f5e925SRichard Henderson                     }
270129f5e925SRichard Henderson                     break;
270229f5e925SRichard Henderson                 default:
270329f5e925SRichard Henderson                     g_assert_not_reached();
270429f5e925SRichard Henderson                 }
270529f5e925SRichard Henderson             }
270629f5e925SRichard Henderson         }
270729f5e925SRichard Henderson 
2708c896fe29Sbellard         /* sort the constraints (XXX: this is just an heuristic) */
2709c896fe29Sbellard         sort_constraints(def, 0, def->nb_oargs);
2710c896fe29Sbellard         sort_constraints(def, def->nb_oargs, def->nb_iargs);
2711c896fe29Sbellard     }
2712c896fe29Sbellard }
2713c896fe29Sbellard 
2714f85b1fc4SRichard Henderson static void remove_label_use(TCGOp *op, int idx)
2715f85b1fc4SRichard Henderson {
2716f85b1fc4SRichard Henderson     TCGLabel *label = arg_label(op->args[idx]);
2717f85b1fc4SRichard Henderson     TCGLabelUse *use;
2718f85b1fc4SRichard Henderson 
2719f85b1fc4SRichard Henderson     QSIMPLEQ_FOREACH(use, &label->branches, next) {
2720f85b1fc4SRichard Henderson         if (use->op == op) {
2721f85b1fc4SRichard Henderson             QSIMPLEQ_REMOVE(&label->branches, use, TCGLabelUse, next);
2722f85b1fc4SRichard Henderson             return;
2723f85b1fc4SRichard Henderson         }
2724f85b1fc4SRichard Henderson     }
2725f85b1fc4SRichard Henderson     g_assert_not_reached();
2726f85b1fc4SRichard Henderson }
2727f85b1fc4SRichard Henderson 
27280c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op)
27290c627cdcSRichard Henderson {
2730d88a117eSRichard Henderson     switch (op->opc) {
2731d88a117eSRichard Henderson     case INDEX_op_br:
2732f85b1fc4SRichard Henderson         remove_label_use(op, 0);
2733d88a117eSRichard Henderson         break;
2734d88a117eSRichard Henderson     case INDEX_op_brcond_i32:
2735d88a117eSRichard Henderson     case INDEX_op_brcond_i64:
2736f85b1fc4SRichard Henderson         remove_label_use(op, 3);
2737d88a117eSRichard Henderson         break;
2738d88a117eSRichard Henderson     case INDEX_op_brcond2_i32:
2739f85b1fc4SRichard Henderson         remove_label_use(op, 5);
2740d88a117eSRichard Henderson         break;
2741d88a117eSRichard Henderson     default:
2742d88a117eSRichard Henderson         break;
2743d88a117eSRichard Henderson     }
2744d88a117eSRichard Henderson 
274515fa08f8SRichard Henderson     QTAILQ_REMOVE(&s->ops, op, link);
274615fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&s->free_ops, op, link);
2747abebf925SRichard Henderson     s->nb_ops--;
27480c627cdcSRichard Henderson 
27490c627cdcSRichard Henderson #ifdef CONFIG_PROFILER
2750d73415a3SStefan Hajnoczi     qatomic_set(&s->prof.del_op_count, s->prof.del_op_count + 1);
27510c627cdcSRichard Henderson #endif
27520c627cdcSRichard Henderson }
27530c627cdcSRichard Henderson 
2754a80cdd31SRichard Henderson void tcg_remove_ops_after(TCGOp *op)
2755a80cdd31SRichard Henderson {
2756a80cdd31SRichard Henderson     TCGContext *s = tcg_ctx;
2757a80cdd31SRichard Henderson 
2758a80cdd31SRichard Henderson     while (true) {
2759a80cdd31SRichard Henderson         TCGOp *last = tcg_last_op();
2760a80cdd31SRichard Henderson         if (last == op) {
2761a80cdd31SRichard Henderson             return;
2762a80cdd31SRichard Henderson         }
2763a80cdd31SRichard Henderson         tcg_op_remove(s, last);
2764a80cdd31SRichard Henderson     }
2765a80cdd31SRichard Henderson }
2766a80cdd31SRichard Henderson 
2767d4478943SPhilippe Mathieu-Daudé static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs)
276815fa08f8SRichard Henderson {
276915fa08f8SRichard Henderson     TCGContext *s = tcg_ctx;
2770cb10bc63SRichard Henderson     TCGOp *op = NULL;
277115fa08f8SRichard Henderson 
2772cb10bc63SRichard Henderson     if (unlikely(!QTAILQ_EMPTY(&s->free_ops))) {
2773cb10bc63SRichard Henderson         QTAILQ_FOREACH(op, &s->free_ops, link) {
2774cb10bc63SRichard Henderson             if (nargs <= op->nargs) {
277515fa08f8SRichard Henderson                 QTAILQ_REMOVE(&s->free_ops, op, link);
2776cb10bc63SRichard Henderson                 nargs = op->nargs;
2777cb10bc63SRichard Henderson                 goto found;
277815fa08f8SRichard Henderson             }
2779cb10bc63SRichard Henderson         }
2780cb10bc63SRichard Henderson     }
2781cb10bc63SRichard Henderson 
2782cb10bc63SRichard Henderson     /* Most opcodes have 3 or 4 operands: reduce fragmentation. */
2783cb10bc63SRichard Henderson     nargs = MAX(4, nargs);
2784cb10bc63SRichard Henderson     op = tcg_malloc(sizeof(TCGOp) + sizeof(TCGArg) * nargs);
2785cb10bc63SRichard Henderson 
2786cb10bc63SRichard Henderson  found:
278715fa08f8SRichard Henderson     memset(op, 0, offsetof(TCGOp, link));
278815fa08f8SRichard Henderson     op->opc = opc;
2789cb10bc63SRichard Henderson     op->nargs = nargs;
279015fa08f8SRichard Henderson 
2791cb10bc63SRichard Henderson     /* Check for bitfield overflow. */
2792cb10bc63SRichard Henderson     tcg_debug_assert(op->nargs == nargs);
2793cb10bc63SRichard Henderson 
2794cb10bc63SRichard Henderson     s->nb_ops++;
279515fa08f8SRichard Henderson     return op;
279615fa08f8SRichard Henderson }
279715fa08f8SRichard Henderson 
2798d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_emit_op(TCGOpcode opc, unsigned nargs)
279915fa08f8SRichard Henderson {
2800d4478943SPhilippe Mathieu-Daudé     TCGOp *op = tcg_op_alloc(opc, nargs);
280115fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
280215fa08f8SRichard Henderson     return op;
280315fa08f8SRichard Henderson }
280415fa08f8SRichard Henderson 
2805d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op,
2806d4478943SPhilippe Mathieu-Daudé                             TCGOpcode opc, unsigned nargs)
28075a18407fSRichard Henderson {
2808d4478943SPhilippe Mathieu-Daudé     TCGOp *new_op = tcg_op_alloc(opc, nargs);
280915fa08f8SRichard Henderson     QTAILQ_INSERT_BEFORE(old_op, new_op, link);
28105a18407fSRichard Henderson     return new_op;
28115a18407fSRichard Henderson }
28125a18407fSRichard Henderson 
2813d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op,
2814d4478943SPhilippe Mathieu-Daudé                            TCGOpcode opc, unsigned nargs)
28155a18407fSRichard Henderson {
2816d4478943SPhilippe Mathieu-Daudé     TCGOp *new_op = tcg_op_alloc(opc, nargs);
281715fa08f8SRichard Henderson     QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link);
28185a18407fSRichard Henderson     return new_op;
28195a18407fSRichard Henderson }
28205a18407fSRichard Henderson 
2821968f305eSRichard Henderson static void move_label_uses(TCGLabel *to, TCGLabel *from)
2822968f305eSRichard Henderson {
2823968f305eSRichard Henderson     TCGLabelUse *u;
2824968f305eSRichard Henderson 
2825968f305eSRichard Henderson     QSIMPLEQ_FOREACH(u, &from->branches, next) {
2826968f305eSRichard Henderson         TCGOp *op = u->op;
2827968f305eSRichard Henderson         switch (op->opc) {
2828968f305eSRichard Henderson         case INDEX_op_br:
2829968f305eSRichard Henderson             op->args[0] = label_arg(to);
2830968f305eSRichard Henderson             break;
2831968f305eSRichard Henderson         case INDEX_op_brcond_i32:
2832968f305eSRichard Henderson         case INDEX_op_brcond_i64:
2833968f305eSRichard Henderson             op->args[3] = label_arg(to);
2834968f305eSRichard Henderson             break;
2835968f305eSRichard Henderson         case INDEX_op_brcond2_i32:
2836968f305eSRichard Henderson             op->args[5] = label_arg(to);
2837968f305eSRichard Henderson             break;
2838968f305eSRichard Henderson         default:
2839968f305eSRichard Henderson             g_assert_not_reached();
2840968f305eSRichard Henderson         }
2841968f305eSRichard Henderson     }
2842968f305eSRichard Henderson 
2843968f305eSRichard Henderson     QSIMPLEQ_CONCAT(&to->branches, &from->branches);
2844968f305eSRichard Henderson }
2845968f305eSRichard Henderson 
2846b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code.  */
28479bbee4c0SRichard Henderson static void __attribute__((noinline))
28489bbee4c0SRichard Henderson reachable_code_pass(TCGContext *s)
2849b4fc67c7SRichard Henderson {
28504d89d0bbSRichard Henderson     TCGOp *op, *op_next, *op_prev;
2851b4fc67c7SRichard Henderson     bool dead = false;
2852b4fc67c7SRichard Henderson 
2853b4fc67c7SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
2854b4fc67c7SRichard Henderson         bool remove = dead;
2855b4fc67c7SRichard Henderson         TCGLabel *label;
2856b4fc67c7SRichard Henderson 
2857b4fc67c7SRichard Henderson         switch (op->opc) {
2858b4fc67c7SRichard Henderson         case INDEX_op_set_label:
2859b4fc67c7SRichard Henderson             label = arg_label(op->args[0]);
28604d89d0bbSRichard Henderson 
28614d89d0bbSRichard Henderson             /*
2862968f305eSRichard Henderson              * Note that the first op in the TB is always a load,
2863968f305eSRichard Henderson              * so there is always something before a label.
2864968f305eSRichard Henderson              */
2865968f305eSRichard Henderson             op_prev = QTAILQ_PREV(op, link);
2866968f305eSRichard Henderson 
2867968f305eSRichard Henderson             /*
2868968f305eSRichard Henderson              * If we find two sequential labels, move all branches to
2869968f305eSRichard Henderson              * reference the second label and remove the first label.
2870968f305eSRichard Henderson              * Do this before branch to next optimization, so that the
2871968f305eSRichard Henderson              * middle label is out of the way.
2872968f305eSRichard Henderson              */
2873968f305eSRichard Henderson             if (op_prev->opc == INDEX_op_set_label) {
2874968f305eSRichard Henderson                 move_label_uses(label, arg_label(op_prev->args[0]));
2875968f305eSRichard Henderson                 tcg_op_remove(s, op_prev);
2876968f305eSRichard Henderson                 op_prev = QTAILQ_PREV(op, link);
2877968f305eSRichard Henderson             }
2878968f305eSRichard Henderson 
2879968f305eSRichard Henderson             /*
28804d89d0bbSRichard Henderson              * Optimization can fold conditional branches to unconditional.
28814d89d0bbSRichard Henderson              * If we find a label which is preceded by an unconditional
28824d89d0bbSRichard Henderson              * branch to next, remove the branch.  We couldn't do this when
28834d89d0bbSRichard Henderson              * processing the branch because any dead code between the branch
28844d89d0bbSRichard Henderson              * and label had not yet been removed.
28854d89d0bbSRichard Henderson              */
28864d89d0bbSRichard Henderson             if (op_prev->opc == INDEX_op_br &&
28874d89d0bbSRichard Henderson                 label == arg_label(op_prev->args[0])) {
28884d89d0bbSRichard Henderson                 tcg_op_remove(s, op_prev);
28894d89d0bbSRichard Henderson                 /* Fall through means insns become live again.  */
28904d89d0bbSRichard Henderson                 dead = false;
28914d89d0bbSRichard Henderson             }
28924d89d0bbSRichard Henderson 
2893f85b1fc4SRichard Henderson             if (QSIMPLEQ_EMPTY(&label->branches)) {
2894b4fc67c7SRichard Henderson                 /*
2895b4fc67c7SRichard Henderson                  * While there is an occasional backward branch, virtually
2896b4fc67c7SRichard Henderson                  * all branches generated by the translators are forward.
2897b4fc67c7SRichard Henderson                  * Which means that generally we will have already removed
2898b4fc67c7SRichard Henderson                  * all references to the label that will be, and there is
2899b4fc67c7SRichard Henderson                  * little to be gained by iterating.
2900b4fc67c7SRichard Henderson                  */
2901b4fc67c7SRichard Henderson                 remove = true;
2902b4fc67c7SRichard Henderson             } else {
2903b4fc67c7SRichard Henderson                 /* Once we see a label, insns become live again.  */
2904b4fc67c7SRichard Henderson                 dead = false;
2905b4fc67c7SRichard Henderson                 remove = false;
2906b4fc67c7SRichard Henderson             }
2907b4fc67c7SRichard Henderson             break;
2908b4fc67c7SRichard Henderson 
2909b4fc67c7SRichard Henderson         case INDEX_op_br:
2910b4fc67c7SRichard Henderson         case INDEX_op_exit_tb:
2911b4fc67c7SRichard Henderson         case INDEX_op_goto_ptr:
2912b4fc67c7SRichard Henderson             /* Unconditional branches; everything following is dead.  */
2913b4fc67c7SRichard Henderson             dead = true;
2914b4fc67c7SRichard Henderson             break;
2915b4fc67c7SRichard Henderson 
2916b4fc67c7SRichard Henderson         case INDEX_op_call:
2917b4fc67c7SRichard Henderson             /* Notice noreturn helper calls, raising exceptions.  */
291890163900SRichard Henderson             if (tcg_call_flags(op) & TCG_CALL_NO_RETURN) {
2919b4fc67c7SRichard Henderson                 dead = true;
2920b4fc67c7SRichard Henderson             }
2921b4fc67c7SRichard Henderson             break;
2922b4fc67c7SRichard Henderson 
2923b4fc67c7SRichard Henderson         case INDEX_op_insn_start:
2924b4fc67c7SRichard Henderson             /* Never remove -- we need to keep these for unwind.  */
2925b4fc67c7SRichard Henderson             remove = false;
2926b4fc67c7SRichard Henderson             break;
2927b4fc67c7SRichard Henderson 
2928b4fc67c7SRichard Henderson         default:
2929b4fc67c7SRichard Henderson             break;
2930b4fc67c7SRichard Henderson         }
2931b4fc67c7SRichard Henderson 
2932b4fc67c7SRichard Henderson         if (remove) {
2933b4fc67c7SRichard Henderson             tcg_op_remove(s, op);
2934b4fc67c7SRichard Henderson         }
2935b4fc67c7SRichard Henderson     }
2936b4fc67c7SRichard Henderson }
2937b4fc67c7SRichard Henderson 
2938c70fbf0aSRichard Henderson #define TS_DEAD  1
2939c70fbf0aSRichard Henderson #define TS_MEM   2
2940c70fbf0aSRichard Henderson 
29415a18407fSRichard Henderson #define IS_DEAD_ARG(n)   (arg_life & (DEAD_ARG << (n)))
29425a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n)))
29435a18407fSRichard Henderson 
294425f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp.  */
294525f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts)
294625f49c5fSRichard Henderson {
294725f49c5fSRichard Henderson     return ts->state_ptr;
294825f49c5fSRichard Henderson }
294925f49c5fSRichard Henderson 
295025f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the
295125f49c5fSRichard Henderson  * maximal regset for its type.
295225f49c5fSRichard Henderson  */
295325f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts)
295425f49c5fSRichard Henderson {
295525f49c5fSRichard Henderson     *la_temp_pref(ts)
295625f49c5fSRichard Henderson         = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]);
295725f49c5fSRichard Henderson }
295825f49c5fSRichard Henderson 
29599c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals
29609c43b68dSAurelien Jarno    should be in memory. */
29612616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt)
2962c896fe29Sbellard {
2963b83eabeaSRichard Henderson     int i;
2964b83eabeaSRichard Henderson 
2965b83eabeaSRichard Henderson     for (i = 0; i < ng; ++i) {
2966b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
296725f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2968b83eabeaSRichard Henderson     }
2969b83eabeaSRichard Henderson     for (i = ng; i < nt; ++i) {
2970b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD;
297125f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2972b83eabeaSRichard Henderson     }
2973c896fe29Sbellard }
2974c896fe29Sbellard 
29759c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals
29769c43b68dSAurelien Jarno    and local temps should be in memory. */
29772616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt)
2978641d5fbeSbellard {
2979b83eabeaSRichard Henderson     int i;
2980641d5fbeSbellard 
2981ee17db83SRichard Henderson     for (i = 0; i < nt; ++i) {
2982ee17db83SRichard Henderson         TCGTemp *ts = &s->temps[i];
2983ee17db83SRichard Henderson         int state;
2984ee17db83SRichard Henderson 
2985ee17db83SRichard Henderson         switch (ts->kind) {
2986ee17db83SRichard Henderson         case TEMP_FIXED:
2987ee17db83SRichard Henderson         case TEMP_GLOBAL:
2988f57c6915SRichard Henderson         case TEMP_TB:
2989ee17db83SRichard Henderson             state = TS_DEAD | TS_MEM;
2990ee17db83SRichard Henderson             break;
2991c7482438SRichard Henderson         case TEMP_EBB:
2992c0522136SRichard Henderson         case TEMP_CONST:
2993ee17db83SRichard Henderson             state = TS_DEAD;
2994ee17db83SRichard Henderson             break;
2995ee17db83SRichard Henderson         default:
2996ee17db83SRichard Henderson             g_assert_not_reached();
2997c70fbf0aSRichard Henderson         }
2998ee17db83SRichard Henderson         ts->state = state;
2999ee17db83SRichard Henderson         la_reset_pref(ts);
3000641d5fbeSbellard     }
3001641d5fbeSbellard }
3002641d5fbeSbellard 
3003f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory.  */
3004f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng)
3005f65a061cSRichard Henderson {
3006f65a061cSRichard Henderson     int i;
3007f65a061cSRichard Henderson 
3008f65a061cSRichard Henderson     for (i = 0; i < ng; ++i) {
300925f49c5fSRichard Henderson         int state = s->temps[i].state;
301025f49c5fSRichard Henderson         s->temps[i].state = state | TS_MEM;
301125f49c5fSRichard Henderson         if (state == TS_DEAD) {
301225f49c5fSRichard Henderson             /* If the global was previously dead, reset prefs.  */
301325f49c5fSRichard Henderson             la_reset_pref(&s->temps[i]);
301425f49c5fSRichard Henderson         }
3015f65a061cSRichard Henderson     }
3016f65a061cSRichard Henderson }
3017f65a061cSRichard Henderson 
3018b4cb76e6SRichard Henderson /*
3019c7482438SRichard Henderson  * liveness analysis: conditional branch: all temps are dead unless
3020c7482438SRichard Henderson  * explicitly live-across-conditional-branch, globals and local temps
3021c7482438SRichard Henderson  * should be synced.
3022b4cb76e6SRichard Henderson  */
3023b4cb76e6SRichard Henderson static void la_bb_sync(TCGContext *s, int ng, int nt)
3024b4cb76e6SRichard Henderson {
3025b4cb76e6SRichard Henderson     la_global_sync(s, ng);
3026b4cb76e6SRichard Henderson 
3027b4cb76e6SRichard Henderson     for (int i = ng; i < nt; ++i) {
3028c0522136SRichard Henderson         TCGTemp *ts = &s->temps[i];
3029c0522136SRichard Henderson         int state;
3030c0522136SRichard Henderson 
3031c0522136SRichard Henderson         switch (ts->kind) {
3032f57c6915SRichard Henderson         case TEMP_TB:
3033c0522136SRichard Henderson             state = ts->state;
3034c0522136SRichard Henderson             ts->state = state | TS_MEM;
3035b4cb76e6SRichard Henderson             if (state != TS_DEAD) {
3036b4cb76e6SRichard Henderson                 continue;
3037b4cb76e6SRichard Henderson             }
3038c0522136SRichard Henderson             break;
3039c7482438SRichard Henderson         case TEMP_EBB:
3040c0522136SRichard Henderson         case TEMP_CONST:
3041c0522136SRichard Henderson             continue;
3042c0522136SRichard Henderson         default:
3043c0522136SRichard Henderson             g_assert_not_reached();
3044b4cb76e6SRichard Henderson         }
3045b4cb76e6SRichard Henderson         la_reset_pref(&s->temps[i]);
3046b4cb76e6SRichard Henderson     }
3047b4cb76e6SRichard Henderson }
3048b4cb76e6SRichard Henderson 
3049f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill.  */
3050f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng)
3051f65a061cSRichard Henderson {
3052f65a061cSRichard Henderson     int i;
3053f65a061cSRichard Henderson 
3054f65a061cSRichard Henderson     for (i = 0; i < ng; i++) {
3055f65a061cSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
305625f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
305725f49c5fSRichard Henderson     }
305825f49c5fSRichard Henderson }
305925f49c5fSRichard Henderson 
306025f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls.  */
306125f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt)
306225f49c5fSRichard Henderson {
306325f49c5fSRichard Henderson     TCGRegSet mask = ~tcg_target_call_clobber_regs;
306425f49c5fSRichard Henderson     int i;
306525f49c5fSRichard Henderson 
306625f49c5fSRichard Henderson     for (i = 0; i < nt; i++) {
306725f49c5fSRichard Henderson         TCGTemp *ts = &s->temps[i];
306825f49c5fSRichard Henderson         if (!(ts->state & TS_DEAD)) {
306925f49c5fSRichard Henderson             TCGRegSet *pset = la_temp_pref(ts);
307025f49c5fSRichard Henderson             TCGRegSet set = *pset;
307125f49c5fSRichard Henderson 
307225f49c5fSRichard Henderson             set &= mask;
307325f49c5fSRichard Henderson             /* If the combination is not possible, restart.  */
307425f49c5fSRichard Henderson             if (set == 0) {
307525f49c5fSRichard Henderson                 set = tcg_target_available_regs[ts->type] & mask;
307625f49c5fSRichard Henderson             }
307725f49c5fSRichard Henderson             *pset = set;
307825f49c5fSRichard Henderson         }
3079f65a061cSRichard Henderson     }
3080f65a061cSRichard Henderson }
3081f65a061cSRichard Henderson 
3082874b8574SRichard Henderson /*
3083874b8574SRichard Henderson  * Liveness analysis: Verify the lifetime of TEMP_TB, and reduce
3084874b8574SRichard Henderson  * to TEMP_EBB, if possible.
3085874b8574SRichard Henderson  */
3086874b8574SRichard Henderson static void __attribute__((noinline))
3087874b8574SRichard Henderson liveness_pass_0(TCGContext *s)
3088874b8574SRichard Henderson {
3089874b8574SRichard Henderson     void * const multiple_ebb = (void *)(uintptr_t)-1;
3090874b8574SRichard Henderson     int nb_temps = s->nb_temps;
3091874b8574SRichard Henderson     TCGOp *op, *ebb;
3092874b8574SRichard Henderson 
3093874b8574SRichard Henderson     for (int i = s->nb_globals; i < nb_temps; ++i) {
3094874b8574SRichard Henderson         s->temps[i].state_ptr = NULL;
3095874b8574SRichard Henderson     }
3096874b8574SRichard Henderson 
3097874b8574SRichard Henderson     /*
3098874b8574SRichard Henderson      * Represent each EBB by the op at which it begins.  In the case of
3099874b8574SRichard Henderson      * the first EBB, this is the first op, otherwise it is a label.
3100874b8574SRichard Henderson      * Collect the uses of each TEMP_TB: NULL for unused, EBB for use
3101874b8574SRichard Henderson      * within a single EBB, else MULTIPLE_EBB.
3102874b8574SRichard Henderson      */
3103874b8574SRichard Henderson     ebb = QTAILQ_FIRST(&s->ops);
3104874b8574SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
3105874b8574SRichard Henderson         const TCGOpDef *def;
3106874b8574SRichard Henderson         int nb_oargs, nb_iargs;
3107874b8574SRichard Henderson 
3108874b8574SRichard Henderson         switch (op->opc) {
3109874b8574SRichard Henderson         case INDEX_op_set_label:
3110874b8574SRichard Henderson             ebb = op;
3111874b8574SRichard Henderson             continue;
3112874b8574SRichard Henderson         case INDEX_op_discard:
3113874b8574SRichard Henderson             continue;
3114874b8574SRichard Henderson         case INDEX_op_call:
3115874b8574SRichard Henderson             nb_oargs = TCGOP_CALLO(op);
3116874b8574SRichard Henderson             nb_iargs = TCGOP_CALLI(op);
3117874b8574SRichard Henderson             break;
3118874b8574SRichard Henderson         default:
3119874b8574SRichard Henderson             def = &tcg_op_defs[op->opc];
3120874b8574SRichard Henderson             nb_oargs = def->nb_oargs;
3121874b8574SRichard Henderson             nb_iargs = def->nb_iargs;
3122874b8574SRichard Henderson             break;
3123874b8574SRichard Henderson         }
3124874b8574SRichard Henderson 
3125874b8574SRichard Henderson         for (int i = 0; i < nb_oargs + nb_iargs; ++i) {
3126874b8574SRichard Henderson             TCGTemp *ts = arg_temp(op->args[i]);
3127874b8574SRichard Henderson 
3128874b8574SRichard Henderson             if (ts->kind != TEMP_TB) {
3129874b8574SRichard Henderson                 continue;
3130874b8574SRichard Henderson             }
3131874b8574SRichard Henderson             if (ts->state_ptr == NULL) {
3132874b8574SRichard Henderson                 ts->state_ptr = ebb;
3133874b8574SRichard Henderson             } else if (ts->state_ptr != ebb) {
3134874b8574SRichard Henderson                 ts->state_ptr = multiple_ebb;
3135874b8574SRichard Henderson             }
3136874b8574SRichard Henderson         }
3137874b8574SRichard Henderson     }
3138874b8574SRichard Henderson 
3139874b8574SRichard Henderson     /*
3140874b8574SRichard Henderson      * For TEMP_TB that turned out not to be used beyond one EBB,
3141874b8574SRichard Henderson      * reduce the liveness to TEMP_EBB.
3142874b8574SRichard Henderson      */
3143874b8574SRichard Henderson     for (int i = s->nb_globals; i < nb_temps; ++i) {
3144874b8574SRichard Henderson         TCGTemp *ts = &s->temps[i];
3145874b8574SRichard Henderson         if (ts->kind == TEMP_TB && ts->state_ptr != multiple_ebb) {
3146874b8574SRichard Henderson             ts->kind = TEMP_EBB;
3147874b8574SRichard Henderson         }
3148874b8574SRichard Henderson     }
3149874b8574SRichard Henderson }
3150874b8574SRichard Henderson 
3151a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a
3152c896fe29Sbellard    given input arguments is dead. Instructions updating dead
3153c896fe29Sbellard    temporaries are removed. */
31549bbee4c0SRichard Henderson static void __attribute__((noinline))
31559bbee4c0SRichard Henderson liveness_pass_1(TCGContext *s)
3156c896fe29Sbellard {
3157c70fbf0aSRichard Henderson     int nb_globals = s->nb_globals;
31582616c808SRichard Henderson     int nb_temps = s->nb_temps;
315915fa08f8SRichard Henderson     TCGOp *op, *op_prev;
316025f49c5fSRichard Henderson     TCGRegSet *prefs;
316125f49c5fSRichard Henderson     int i;
316225f49c5fSRichard Henderson 
316325f49c5fSRichard Henderson     prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps);
316425f49c5fSRichard Henderson     for (i = 0; i < nb_temps; ++i) {
316525f49c5fSRichard Henderson         s->temps[i].state_ptr = prefs + i;
316625f49c5fSRichard Henderson     }
3167c896fe29Sbellard 
3168ae36a246SRichard Henderson     /* ??? Should be redundant with the exit_tb that ends the TB.  */
31692616c808SRichard Henderson     la_func_end(s, nb_globals, nb_temps);
3170c896fe29Sbellard 
3171eae3eb3eSPaolo Bonzini     QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) {
317225f49c5fSRichard Henderson         int nb_iargs, nb_oargs;
3173c45cb8bbSRichard Henderson         TCGOpcode opc_new, opc_new2;
3174c45cb8bbSRichard Henderson         bool have_opc_new2;
3175a1b3c48dSRichard Henderson         TCGLifeData arg_life = 0;
317625f49c5fSRichard Henderson         TCGTemp *ts;
3177c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
3178c45cb8bbSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
3179c45cb8bbSRichard Henderson 
3180c45cb8bbSRichard Henderson         switch (opc) {
3181c896fe29Sbellard         case INDEX_op_call:
3182c6e113f5Sbellard             {
318339004a71SRichard Henderson                 const TCGHelperInfo *info = tcg_call_info(op);
318439004a71SRichard Henderson                 int call_flags = tcg_call_flags(op);
3185c6e113f5Sbellard 
3186cd9090aaSRichard Henderson                 nb_oargs = TCGOP_CALLO(op);
3187cd9090aaSRichard Henderson                 nb_iargs = TCGOP_CALLI(op);
3188c6e113f5Sbellard 
3189c45cb8bbSRichard Henderson                 /* pure functions can be removed if their result is unused */
319078505279SAurelien Jarno                 if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) {
3191c6e113f5Sbellard                     for (i = 0; i < nb_oargs; i++) {
319225f49c5fSRichard Henderson                         ts = arg_temp(op->args[i]);
319325f49c5fSRichard Henderson                         if (ts->state != TS_DEAD) {
3194c6e113f5Sbellard                             goto do_not_remove_call;
3195c6e113f5Sbellard                         }
31969c43b68dSAurelien Jarno                     }
3197c45cb8bbSRichard Henderson                     goto do_remove;
3198152c35aaSRichard Henderson                 }
3199c6e113f5Sbellard             do_not_remove_call:
3200c896fe29Sbellard 
320125f49c5fSRichard Henderson                 /* Output args are dead.  */
3202c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
320325f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
320425f49c5fSRichard Henderson                     if (ts->state & TS_DEAD) {
3205a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
32066b64b624SAurelien Jarno                     }
320725f49c5fSRichard Henderson                     if (ts->state & TS_MEM) {
3208a1b3c48dSRichard Henderson                         arg_life |= SYNC_ARG << i;
32099c43b68dSAurelien Jarno                     }
321025f49c5fSRichard Henderson                     ts->state = TS_DEAD;
321125f49c5fSRichard Henderson                     la_reset_pref(ts);
3212c896fe29Sbellard                 }
3213c896fe29Sbellard 
321431fd884bSRichard Henderson                 /* Not used -- it will be tcg_target_call_oarg_reg().  */
321531fd884bSRichard Henderson                 memset(op->output_pref, 0, sizeof(op->output_pref));
321631fd884bSRichard Henderson 
321778505279SAurelien Jarno                 if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS |
321878505279SAurelien Jarno                                     TCG_CALL_NO_READ_GLOBALS))) {
3219f65a061cSRichard Henderson                     la_global_kill(s, nb_globals);
3220c70fbf0aSRichard Henderson                 } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) {
3221f65a061cSRichard Henderson                     la_global_sync(s, nb_globals);
3222b9c18f56Saurel32                 }
3223c896fe29Sbellard 
322425f49c5fSRichard Henderson                 /* Record arguments that die in this helper.  */
3225866cb6cbSAurelien Jarno                 for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
322625f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
322739004a71SRichard Henderson                     if (ts->state & TS_DEAD) {
3228a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
3229c896fe29Sbellard                     }
3230c896fe29Sbellard                 }
323125f49c5fSRichard Henderson 
323225f49c5fSRichard Henderson                 /* For all live registers, remove call-clobbered prefs.  */
323325f49c5fSRichard Henderson                 la_cross_call(s, nb_temps);
323425f49c5fSRichard Henderson 
323539004a71SRichard Henderson                 /*
323639004a71SRichard Henderson                  * Input arguments are live for preceding opcodes.
323739004a71SRichard Henderson                  *
323839004a71SRichard Henderson                  * For those arguments that die, and will be allocated in
323939004a71SRichard Henderson                  * registers, clear the register set for that arg, to be
324039004a71SRichard Henderson                  * filled in below.  For args that will be on the stack,
324139004a71SRichard Henderson                  * reset to any available reg.  Process arguments in reverse
324239004a71SRichard Henderson                  * order so that if a temp is used more than once, the stack
324339004a71SRichard Henderson                  * reset to max happens before the register reset to 0.
324425f49c5fSRichard Henderson                  */
324539004a71SRichard Henderson                 for (i = nb_iargs - 1; i >= 0; i--) {
324639004a71SRichard Henderson                     const TCGCallArgumentLoc *loc = &info->in[i];
324739004a71SRichard Henderson                     ts = arg_temp(op->args[nb_oargs + i]);
324839004a71SRichard Henderson 
324939004a71SRichard Henderson                     if (ts->state & TS_DEAD) {
325039004a71SRichard Henderson                         switch (loc->kind) {
325139004a71SRichard Henderson                         case TCG_CALL_ARG_NORMAL:
325239004a71SRichard Henderson                         case TCG_CALL_ARG_EXTEND_U:
325339004a71SRichard Henderson                         case TCG_CALL_ARG_EXTEND_S:
3254338b61e9SRichard Henderson                             if (arg_slot_reg_p(loc->arg_slot)) {
325539004a71SRichard Henderson                                 *la_temp_pref(ts) = 0;
325639004a71SRichard Henderson                                 break;
325739004a71SRichard Henderson                             }
325839004a71SRichard Henderson                             /* fall through */
325939004a71SRichard Henderson                         default:
326039004a71SRichard Henderson                             *la_temp_pref(ts) =
326139004a71SRichard Henderson                                 tcg_target_available_regs[ts->type];
326239004a71SRichard Henderson                             break;
326339004a71SRichard Henderson                         }
326425f49c5fSRichard Henderson                         ts->state &= ~TS_DEAD;
326525f49c5fSRichard Henderson                     }
326625f49c5fSRichard Henderson                 }
326725f49c5fSRichard Henderson 
326839004a71SRichard Henderson                 /*
326939004a71SRichard Henderson                  * For each input argument, add its input register to prefs.
327039004a71SRichard Henderson                  * If a temp is used once, this produces a single set bit;
327139004a71SRichard Henderson                  * if a temp is used multiple times, this produces a set.
327239004a71SRichard Henderson                  */
327339004a71SRichard Henderson                 for (i = 0; i < nb_iargs; i++) {
327439004a71SRichard Henderson                     const TCGCallArgumentLoc *loc = &info->in[i];
327539004a71SRichard Henderson                     ts = arg_temp(op->args[nb_oargs + i]);
327639004a71SRichard Henderson 
327739004a71SRichard Henderson                     switch (loc->kind) {
327839004a71SRichard Henderson                     case TCG_CALL_ARG_NORMAL:
327939004a71SRichard Henderson                     case TCG_CALL_ARG_EXTEND_U:
328039004a71SRichard Henderson                     case TCG_CALL_ARG_EXTEND_S:
3281338b61e9SRichard Henderson                         if (arg_slot_reg_p(loc->arg_slot)) {
328225f49c5fSRichard Henderson                             tcg_regset_set_reg(*la_temp_pref(ts),
328339004a71SRichard Henderson                                 tcg_target_call_iarg_regs[loc->arg_slot]);
328439004a71SRichard Henderson                         }
328539004a71SRichard Henderson                         break;
328639004a71SRichard Henderson                     default:
328739004a71SRichard Henderson                         break;
3288c70fbf0aSRichard Henderson                     }
3289c19f47bfSAurelien Jarno                 }
3290c6e113f5Sbellard             }
3291c896fe29Sbellard             break;
3292765b842aSRichard Henderson         case INDEX_op_insn_start:
3293c896fe29Sbellard             break;
32945ff9d6a4Sbellard         case INDEX_op_discard:
32955ff9d6a4Sbellard             /* mark the temporary as dead */
329625f49c5fSRichard Henderson             ts = arg_temp(op->args[0]);
329725f49c5fSRichard Henderson             ts->state = TS_DEAD;
329825f49c5fSRichard Henderson             la_reset_pref(ts);
32995ff9d6a4Sbellard             break;
33001305c451SRichard Henderson 
33011305c451SRichard Henderson         case INDEX_op_add2_i32:
3302c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i32;
3303f1fae40cSRichard Henderson             goto do_addsub2;
33041305c451SRichard Henderson         case INDEX_op_sub2_i32:
3305c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i32;
3306f1fae40cSRichard Henderson             goto do_addsub2;
3307f1fae40cSRichard Henderson         case INDEX_op_add2_i64:
3308c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i64;
3309f1fae40cSRichard Henderson             goto do_addsub2;
3310f1fae40cSRichard Henderson         case INDEX_op_sub2_i64:
3311c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i64;
3312f1fae40cSRichard Henderson         do_addsub2:
33131305c451SRichard Henderson             nb_iargs = 4;
33141305c451SRichard Henderson             nb_oargs = 2;
33151305c451SRichard Henderson             /* Test if the high part of the operation is dead, but not
33161305c451SRichard Henderson                the low part.  The result can be optimized to a simple
33171305c451SRichard Henderson                add or sub.  This happens often for x86_64 guest when the
33181305c451SRichard Henderson                cpu mode is set to 32 bit.  */
3319b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
3320b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
33211305c451SRichard Henderson                     goto do_remove;
33221305c451SRichard Henderson                 }
3323c45cb8bbSRichard Henderson                 /* Replace the opcode and adjust the args in place,
3324c45cb8bbSRichard Henderson                    leaving 3 unused args at the end.  */
3325c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
3326efee3746SRichard Henderson                 op->args[1] = op->args[2];
3327efee3746SRichard Henderson                 op->args[2] = op->args[4];
33281305c451SRichard Henderson                 /* Fall through and mark the single-word operation live.  */
33291305c451SRichard Henderson                 nb_iargs = 2;
33301305c451SRichard Henderson                 nb_oargs = 1;
33311305c451SRichard Henderson             }
33321305c451SRichard Henderson             goto do_not_remove;
33331305c451SRichard Henderson 
33341414968aSRichard Henderson         case INDEX_op_mulu2_i32:
3335c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
3336c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i32;
3337c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i32;
333803271524SRichard Henderson             goto do_mul2;
3339f1fae40cSRichard Henderson         case INDEX_op_muls2_i32:
3340c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
3341c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i32;
3342c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i32;
3343f1fae40cSRichard Henderson             goto do_mul2;
3344f1fae40cSRichard Henderson         case INDEX_op_mulu2_i64:
3345c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
3346c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i64;
3347c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i64;
334803271524SRichard Henderson             goto do_mul2;
3349f1fae40cSRichard Henderson         case INDEX_op_muls2_i64:
3350c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
3351c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i64;
3352c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i64;
335303271524SRichard Henderson             goto do_mul2;
3354f1fae40cSRichard Henderson         do_mul2:
33551414968aSRichard Henderson             nb_iargs = 2;
33561414968aSRichard Henderson             nb_oargs = 2;
3357b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
3358b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
335903271524SRichard Henderson                     /* Both parts of the operation are dead.  */
33601414968aSRichard Henderson                     goto do_remove;
33611414968aSRichard Henderson                 }
336203271524SRichard Henderson                 /* The high part of the operation is dead; generate the low. */
3363c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
3364efee3746SRichard Henderson                 op->args[1] = op->args[2];
3365efee3746SRichard Henderson                 op->args[2] = op->args[3];
3366b83eabeaSRichard Henderson             } else if (arg_temp(op->args[0])->state == TS_DEAD && have_opc_new2) {
336703271524SRichard Henderson                 /* The low part of the operation is dead; generate the high. */
3368c45cb8bbSRichard Henderson                 op->opc = opc = opc_new2;
3369efee3746SRichard Henderson                 op->args[0] = op->args[1];
3370efee3746SRichard Henderson                 op->args[1] = op->args[2];
3371efee3746SRichard Henderson                 op->args[2] = op->args[3];
337203271524SRichard Henderson             } else {
337303271524SRichard Henderson                 goto do_not_remove;
337403271524SRichard Henderson             }
337503271524SRichard Henderson             /* Mark the single-word operation live.  */
33761414968aSRichard Henderson             nb_oargs = 1;
33771414968aSRichard Henderson             goto do_not_remove;
33781414968aSRichard Henderson 
3379c896fe29Sbellard         default:
33801305c451SRichard Henderson             /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
3381c896fe29Sbellard             nb_iargs = def->nb_iargs;
3382c896fe29Sbellard             nb_oargs = def->nb_oargs;
3383c896fe29Sbellard 
3384c896fe29Sbellard             /* Test if the operation can be removed because all
33855ff9d6a4Sbellard                its outputs are dead. We assume that nb_oargs == 0
33865ff9d6a4Sbellard                implies side effects */
33875ff9d6a4Sbellard             if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
3388c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
3389b83eabeaSRichard Henderson                     if (arg_temp(op->args[i])->state != TS_DEAD) {
3390c896fe29Sbellard                         goto do_not_remove;
3391c896fe29Sbellard                     }
33929c43b68dSAurelien Jarno                 }
3393152c35aaSRichard Henderson                 goto do_remove;
3394152c35aaSRichard Henderson             }
3395152c35aaSRichard Henderson             goto do_not_remove;
3396152c35aaSRichard Henderson 
33971305c451SRichard Henderson         do_remove:
33980c627cdcSRichard Henderson             tcg_op_remove(s, op);
3399152c35aaSRichard Henderson             break;
3400152c35aaSRichard Henderson 
3401c896fe29Sbellard         do_not_remove:
3402c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
340325f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
340425f49c5fSRichard Henderson 
340525f49c5fSRichard Henderson                 /* Remember the preference of the uses that followed.  */
340631fd884bSRichard Henderson                 if (i < ARRAY_SIZE(op->output_pref)) {
340725f49c5fSRichard Henderson                     op->output_pref[i] = *la_temp_pref(ts);
340831fd884bSRichard Henderson                 }
340925f49c5fSRichard Henderson 
341025f49c5fSRichard Henderson                 /* Output args are dead.  */
341125f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
3412a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
34136b64b624SAurelien Jarno                 }
341425f49c5fSRichard Henderson                 if (ts->state & TS_MEM) {
3415a1b3c48dSRichard Henderson                     arg_life |= SYNC_ARG << i;
34169c43b68dSAurelien Jarno                 }
341725f49c5fSRichard Henderson                 ts->state = TS_DEAD;
341825f49c5fSRichard Henderson                 la_reset_pref(ts);
3419c896fe29Sbellard             }
3420c896fe29Sbellard 
342125f49c5fSRichard Henderson             /* If end of basic block, update.  */
3422ae36a246SRichard Henderson             if (def->flags & TCG_OPF_BB_EXIT) {
3423ae36a246SRichard Henderson                 la_func_end(s, nb_globals, nb_temps);
3424b4cb76e6SRichard Henderson             } else if (def->flags & TCG_OPF_COND_BRANCH) {
3425b4cb76e6SRichard Henderson                 la_bb_sync(s, nb_globals, nb_temps);
3426ae36a246SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
34272616c808SRichard Henderson                 la_bb_end(s, nb_globals, nb_temps);
34283d5c5f87SAurelien Jarno             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
3429f65a061cSRichard Henderson                 la_global_sync(s, nb_globals);
343025f49c5fSRichard Henderson                 if (def->flags & TCG_OPF_CALL_CLOBBER) {
343125f49c5fSRichard Henderson                     la_cross_call(s, nb_temps);
343225f49c5fSRichard Henderson                 }
3433c896fe29Sbellard             }
3434c896fe29Sbellard 
343525f49c5fSRichard Henderson             /* Record arguments that die in this opcode.  */
3436866cb6cbSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
343725f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
343825f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
3439a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
3440c896fe29Sbellard                 }
3441c19f47bfSAurelien Jarno             }
344225f49c5fSRichard Henderson 
344325f49c5fSRichard Henderson             /* Input arguments are live for preceding opcodes.  */
3444c19f47bfSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
344525f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
344625f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
344725f49c5fSRichard Henderson                     /* For operands that were dead, initially allow
344825f49c5fSRichard Henderson                        all regs for the type.  */
344925f49c5fSRichard Henderson                     *la_temp_pref(ts) = tcg_target_available_regs[ts->type];
345025f49c5fSRichard Henderson                     ts->state &= ~TS_DEAD;
345125f49c5fSRichard Henderson                 }
345225f49c5fSRichard Henderson             }
345325f49c5fSRichard Henderson 
345425f49c5fSRichard Henderson             /* Incorporate constraints for this operand.  */
345525f49c5fSRichard Henderson             switch (opc) {
345625f49c5fSRichard Henderson             case INDEX_op_mov_i32:
345725f49c5fSRichard Henderson             case INDEX_op_mov_i64:
345825f49c5fSRichard Henderson                 /* Note that these are TCG_OPF_NOT_PRESENT and do not
345925f49c5fSRichard Henderson                    have proper constraints.  That said, special case
346025f49c5fSRichard Henderson                    moves to propagate preferences backward.  */
346125f49c5fSRichard Henderson                 if (IS_DEAD_ARG(1)) {
346225f49c5fSRichard Henderson                     *la_temp_pref(arg_temp(op->args[0]))
346325f49c5fSRichard Henderson                         = *la_temp_pref(arg_temp(op->args[1]));
346425f49c5fSRichard Henderson                 }
346525f49c5fSRichard Henderson                 break;
346625f49c5fSRichard Henderson 
346725f49c5fSRichard Henderson             default:
346825f49c5fSRichard Henderson                 for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
346925f49c5fSRichard Henderson                     const TCGArgConstraint *ct = &def->args_ct[i];
347025f49c5fSRichard Henderson                     TCGRegSet set, *pset;
347125f49c5fSRichard Henderson 
347225f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
347325f49c5fSRichard Henderson                     pset = la_temp_pref(ts);
347425f49c5fSRichard Henderson                     set = *pset;
347525f49c5fSRichard Henderson 
34769be0d080SRichard Henderson                     set &= ct->regs;
3477bc2b17e6SRichard Henderson                     if (ct->ialias) {
347831fd884bSRichard Henderson                         set &= output_pref(op, ct->alias_index);
347925f49c5fSRichard Henderson                     }
348025f49c5fSRichard Henderson                     /* If the combination is not possible, restart.  */
348125f49c5fSRichard Henderson                     if (set == 0) {
34829be0d080SRichard Henderson                         set = ct->regs;
348325f49c5fSRichard Henderson                     }
348425f49c5fSRichard Henderson                     *pset = set;
348525f49c5fSRichard Henderson                 }
348625f49c5fSRichard Henderson                 break;
3487c896fe29Sbellard             }
3488c896fe29Sbellard             break;
3489c896fe29Sbellard         }
3490bee158cbSRichard Henderson         op->life = arg_life;
3491c896fe29Sbellard     }
34921ff0a2c5SEvgeny Voevodin }
3493c896fe29Sbellard 
34945a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries.  */
34959bbee4c0SRichard Henderson static bool __attribute__((noinline))
34969bbee4c0SRichard Henderson liveness_pass_2(TCGContext *s)
34975a18407fSRichard Henderson {
34985a18407fSRichard Henderson     int nb_globals = s->nb_globals;
349915fa08f8SRichard Henderson     int nb_temps, i;
35005a18407fSRichard Henderson     bool changes = false;
350115fa08f8SRichard Henderson     TCGOp *op, *op_next;
35025a18407fSRichard Henderson 
35035a18407fSRichard Henderson     /* Create a temporary for each indirect global.  */
35045a18407fSRichard Henderson     for (i = 0; i < nb_globals; ++i) {
35055a18407fSRichard Henderson         TCGTemp *its = &s->temps[i];
35065a18407fSRichard Henderson         if (its->indirect_reg) {
35075a18407fSRichard Henderson             TCGTemp *dts = tcg_temp_alloc(s);
35085a18407fSRichard Henderson             dts->type = its->type;
35095a18407fSRichard Henderson             dts->base_type = its->base_type;
3510e1e64652SRichard Henderson             dts->temp_subindex = its->temp_subindex;
3511c7482438SRichard Henderson             dts->kind = TEMP_EBB;
3512b83eabeaSRichard Henderson             its->state_ptr = dts;
3513b83eabeaSRichard Henderson         } else {
3514b83eabeaSRichard Henderson             its->state_ptr = NULL;
35155a18407fSRichard Henderson         }
3516b83eabeaSRichard Henderson         /* All globals begin dead.  */
3517b83eabeaSRichard Henderson         its->state = TS_DEAD;
35185a18407fSRichard Henderson     }
3519b83eabeaSRichard Henderson     for (nb_temps = s->nb_temps; i < nb_temps; ++i) {
3520b83eabeaSRichard Henderson         TCGTemp *its = &s->temps[i];
3521b83eabeaSRichard Henderson         its->state_ptr = NULL;
3522b83eabeaSRichard Henderson         its->state = TS_DEAD;
3523b83eabeaSRichard Henderson     }
35245a18407fSRichard Henderson 
352515fa08f8SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
35265a18407fSRichard Henderson         TCGOpcode opc = op->opc;
35275a18407fSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
35285a18407fSRichard Henderson         TCGLifeData arg_life = op->life;
35295a18407fSRichard Henderson         int nb_iargs, nb_oargs, call_flags;
3530b83eabeaSRichard Henderson         TCGTemp *arg_ts, *dir_ts;
35315a18407fSRichard Henderson 
35325a18407fSRichard Henderson         if (opc == INDEX_op_call) {
3533cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
3534cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
353590163900SRichard Henderson             call_flags = tcg_call_flags(op);
35365a18407fSRichard Henderson         } else {
35375a18407fSRichard Henderson             nb_iargs = def->nb_iargs;
35385a18407fSRichard Henderson             nb_oargs = def->nb_oargs;
35395a18407fSRichard Henderson 
35405a18407fSRichard Henderson             /* Set flags similar to how calls require.  */
3541b4cb76e6SRichard Henderson             if (def->flags & TCG_OPF_COND_BRANCH) {
3542b4cb76e6SRichard Henderson                 /* Like reading globals: sync_globals */
3543b4cb76e6SRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
3544b4cb76e6SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
35455a18407fSRichard Henderson                 /* Like writing globals: save_globals */
35465a18407fSRichard Henderson                 call_flags = 0;
35475a18407fSRichard Henderson             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
35485a18407fSRichard Henderson                 /* Like reading globals: sync_globals */
35495a18407fSRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
35505a18407fSRichard Henderson             } else {
35515a18407fSRichard Henderson                 /* No effect on globals.  */
35525a18407fSRichard Henderson                 call_flags = (TCG_CALL_NO_READ_GLOBALS |
35535a18407fSRichard Henderson                               TCG_CALL_NO_WRITE_GLOBALS);
35545a18407fSRichard Henderson             }
35555a18407fSRichard Henderson         }
35565a18407fSRichard Henderson 
35575a18407fSRichard Henderson         /* Make sure that input arguments are available.  */
35585a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
3559b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
3560b83eabeaSRichard Henderson             dir_ts = arg_ts->state_ptr;
3561b83eabeaSRichard Henderson             if (dir_ts && arg_ts->state == TS_DEAD) {
3562b83eabeaSRichard Henderson                 TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32
35635a18407fSRichard Henderson                                   ? INDEX_op_ld_i32
35645a18407fSRichard Henderson                                   : INDEX_op_ld_i64);
3565d4478943SPhilippe Mathieu-Daudé                 TCGOp *lop = tcg_op_insert_before(s, op, lopc, 3);
35665a18407fSRichard Henderson 
3567b83eabeaSRichard Henderson                 lop->args[0] = temp_arg(dir_ts);
3568b83eabeaSRichard Henderson                 lop->args[1] = temp_arg(arg_ts->mem_base);
3569b83eabeaSRichard Henderson                 lop->args[2] = arg_ts->mem_offset;
35705a18407fSRichard Henderson 
35715a18407fSRichard Henderson                 /* Loaded, but synced with memory.  */
3572b83eabeaSRichard Henderson                 arg_ts->state = TS_MEM;
35735a18407fSRichard Henderson             }
35745a18407fSRichard Henderson         }
35755a18407fSRichard Henderson 
35765a18407fSRichard Henderson         /* Perform input replacement, and mark inputs that became dead.
35775a18407fSRichard Henderson            No action is required except keeping temp_state up to date
35785a18407fSRichard Henderson            so that we reload when needed.  */
35795a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
3580b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
3581b83eabeaSRichard Henderson             dir_ts = arg_ts->state_ptr;
3582b83eabeaSRichard Henderson             if (dir_ts) {
3583b83eabeaSRichard Henderson                 op->args[i] = temp_arg(dir_ts);
35845a18407fSRichard Henderson                 changes = true;
35855a18407fSRichard Henderson                 if (IS_DEAD_ARG(i)) {
3586b83eabeaSRichard Henderson                     arg_ts->state = TS_DEAD;
35875a18407fSRichard Henderson                 }
35885a18407fSRichard Henderson             }
35895a18407fSRichard Henderson         }
35905a18407fSRichard Henderson 
35915a18407fSRichard Henderson         /* Liveness analysis should ensure that the following are
35925a18407fSRichard Henderson            all correct, for call sites and basic block end points.  */
35935a18407fSRichard Henderson         if (call_flags & TCG_CALL_NO_READ_GLOBALS) {
35945a18407fSRichard Henderson             /* Nothing to do */
35955a18407fSRichard Henderson         } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) {
35965a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
35975a18407fSRichard Henderson                 /* Liveness should see that globals are synced back,
35985a18407fSRichard Henderson                    that is, either TS_DEAD or TS_MEM.  */
3599b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
3600b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
3601b83eabeaSRichard Henderson                                  || arg_ts->state != 0);
36025a18407fSRichard Henderson             }
36035a18407fSRichard Henderson         } else {
36045a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
36055a18407fSRichard Henderson                 /* Liveness should see that globals are saved back,
36065a18407fSRichard Henderson                    that is, TS_DEAD, waiting to be reloaded.  */
3607b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
3608b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
3609b83eabeaSRichard Henderson                                  || arg_ts->state == TS_DEAD);
36105a18407fSRichard Henderson             }
36115a18407fSRichard Henderson         }
36125a18407fSRichard Henderson 
36135a18407fSRichard Henderson         /* Outputs become available.  */
361461f15c48SRichard Henderson         if (opc == INDEX_op_mov_i32 || opc == INDEX_op_mov_i64) {
361561f15c48SRichard Henderson             arg_ts = arg_temp(op->args[0]);
361661f15c48SRichard Henderson             dir_ts = arg_ts->state_ptr;
361761f15c48SRichard Henderson             if (dir_ts) {
361861f15c48SRichard Henderson                 op->args[0] = temp_arg(dir_ts);
361961f15c48SRichard Henderson                 changes = true;
362061f15c48SRichard Henderson 
362161f15c48SRichard Henderson                 /* The output is now live and modified.  */
362261f15c48SRichard Henderson                 arg_ts->state = 0;
362361f15c48SRichard Henderson 
362461f15c48SRichard Henderson                 if (NEED_SYNC_ARG(0)) {
362561f15c48SRichard Henderson                     TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
362661f15c48SRichard Henderson                                       ? INDEX_op_st_i32
362761f15c48SRichard Henderson                                       : INDEX_op_st_i64);
3628d4478943SPhilippe Mathieu-Daudé                     TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3);
362961f15c48SRichard Henderson                     TCGTemp *out_ts = dir_ts;
363061f15c48SRichard Henderson 
363161f15c48SRichard Henderson                     if (IS_DEAD_ARG(0)) {
363261f15c48SRichard Henderson                         out_ts = arg_temp(op->args[1]);
363361f15c48SRichard Henderson                         arg_ts->state = TS_DEAD;
363461f15c48SRichard Henderson                         tcg_op_remove(s, op);
363561f15c48SRichard Henderson                     } else {
363661f15c48SRichard Henderson                         arg_ts->state = TS_MEM;
363761f15c48SRichard Henderson                     }
363861f15c48SRichard Henderson 
363961f15c48SRichard Henderson                     sop->args[0] = temp_arg(out_ts);
364061f15c48SRichard Henderson                     sop->args[1] = temp_arg(arg_ts->mem_base);
364161f15c48SRichard Henderson                     sop->args[2] = arg_ts->mem_offset;
364261f15c48SRichard Henderson                 } else {
364361f15c48SRichard Henderson                     tcg_debug_assert(!IS_DEAD_ARG(0));
364461f15c48SRichard Henderson                 }
364561f15c48SRichard Henderson             }
364661f15c48SRichard Henderson         } else {
36475a18407fSRichard Henderson             for (i = 0; i < nb_oargs; i++) {
3648b83eabeaSRichard Henderson                 arg_ts = arg_temp(op->args[i]);
3649b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
3650b83eabeaSRichard Henderson                 if (!dir_ts) {
36515a18407fSRichard Henderson                     continue;
36525a18407fSRichard Henderson                 }
3653b83eabeaSRichard Henderson                 op->args[i] = temp_arg(dir_ts);
36545a18407fSRichard Henderson                 changes = true;
36555a18407fSRichard Henderson 
36565a18407fSRichard Henderson                 /* The output is now live and modified.  */
3657b83eabeaSRichard Henderson                 arg_ts->state = 0;
36585a18407fSRichard Henderson 
36595a18407fSRichard Henderson                 /* Sync outputs upon their last write.  */
36605a18407fSRichard Henderson                 if (NEED_SYNC_ARG(i)) {
3661b83eabeaSRichard Henderson                     TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
36625a18407fSRichard Henderson                                       ? INDEX_op_st_i32
36635a18407fSRichard Henderson                                       : INDEX_op_st_i64);
3664d4478943SPhilippe Mathieu-Daudé                     TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3);
36655a18407fSRichard Henderson 
3666b83eabeaSRichard Henderson                     sop->args[0] = temp_arg(dir_ts);
3667b83eabeaSRichard Henderson                     sop->args[1] = temp_arg(arg_ts->mem_base);
3668b83eabeaSRichard Henderson                     sop->args[2] = arg_ts->mem_offset;
36695a18407fSRichard Henderson 
3670b83eabeaSRichard Henderson                     arg_ts->state = TS_MEM;
36715a18407fSRichard Henderson                 }
36725a18407fSRichard Henderson                 /* Drop outputs that are dead.  */
36735a18407fSRichard Henderson                 if (IS_DEAD_ARG(i)) {
3674b83eabeaSRichard Henderson                     arg_ts->state = TS_DEAD;
36755a18407fSRichard Henderson                 }
36765a18407fSRichard Henderson             }
36775a18407fSRichard Henderson         }
367861f15c48SRichard Henderson     }
36795a18407fSRichard Henderson 
36805a18407fSRichard Henderson     return changes;
36815a18407fSRichard Henderson }
36825a18407fSRichard Henderson 
36832272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts)
3684c896fe29Sbellard {
368531c96417SRichard Henderson     intptr_t off;
3686273eb50cSRichard Henderson     int size, align;
3687c1c09194SRichard Henderson 
3688273eb50cSRichard Henderson     /* When allocating an object, look at the full type. */
3689273eb50cSRichard Henderson     size = tcg_type_size(ts->base_type);
3690273eb50cSRichard Henderson     switch (ts->base_type) {
3691c1c09194SRichard Henderson     case TCG_TYPE_I32:
369231c96417SRichard Henderson         align = 4;
3693c1c09194SRichard Henderson         break;
3694c1c09194SRichard Henderson     case TCG_TYPE_I64:
3695c1c09194SRichard Henderson     case TCG_TYPE_V64:
369631c96417SRichard Henderson         align = 8;
3697c1c09194SRichard Henderson         break;
369843eef72fSRichard Henderson     case TCG_TYPE_I128:
3699c1c09194SRichard Henderson     case TCG_TYPE_V128:
3700c1c09194SRichard Henderson     case TCG_TYPE_V256:
370143eef72fSRichard Henderson         /*
370243eef72fSRichard Henderson          * Note that we do not require aligned storage for V256,
370343eef72fSRichard Henderson          * and that we provide alignment for I128 to match V128,
370443eef72fSRichard Henderson          * even if that's above what the host ABI requires.
370543eef72fSRichard Henderson          */
370631c96417SRichard Henderson         align = 16;
3707c1c09194SRichard Henderson         break;
3708c1c09194SRichard Henderson     default:
3709c1c09194SRichard Henderson         g_assert_not_reached();
3710b591dc59SBlue Swirl     }
3711c1c09194SRichard Henderson 
3712b9537d59SRichard Henderson     /*
3713b9537d59SRichard Henderson      * Assume the stack is sufficiently aligned.
3714b9537d59SRichard Henderson      * This affects e.g. ARM NEON, where we have 8 byte stack alignment
3715b9537d59SRichard Henderson      * and do not require 16 byte vector alignment.  This seems slightly
3716b9537d59SRichard Henderson      * easier than fully parameterizing the above switch statement.
3717b9537d59SRichard Henderson      */
3718b9537d59SRichard Henderson     align = MIN(TCG_TARGET_STACK_ALIGN, align);
3719c1c09194SRichard Henderson     off = ROUND_UP(s->current_frame_offset, align);
3720732d5897SRichard Henderson 
3721732d5897SRichard Henderson     /* If we've exhausted the stack frame, restart with a smaller TB. */
3722732d5897SRichard Henderson     if (off + size > s->frame_end) {
3723732d5897SRichard Henderson         tcg_raise_tb_overflow(s);
3724732d5897SRichard Henderson     }
3725c1c09194SRichard Henderson     s->current_frame_offset = off + size;
37269defd1bdSRichard Henderson #if defined(__sparc__)
3727273eb50cSRichard Henderson     off += TCG_TARGET_STACK_BIAS;
37289defd1bdSRichard Henderson #endif
3729273eb50cSRichard Henderson 
3730273eb50cSRichard Henderson     /* If the object was subdivided, assign memory to all the parts. */
3731273eb50cSRichard Henderson     if (ts->base_type != ts->type) {
3732273eb50cSRichard Henderson         int part_size = tcg_type_size(ts->type);
3733273eb50cSRichard Henderson         int part_count = size / part_size;
3734273eb50cSRichard Henderson 
3735273eb50cSRichard Henderson         /*
3736273eb50cSRichard Henderson          * Each part is allocated sequentially in tcg_temp_new_internal.
3737273eb50cSRichard Henderson          * Jump back to the first part by subtracting the current index.
3738273eb50cSRichard Henderson          */
3739273eb50cSRichard Henderson         ts -= ts->temp_subindex;
3740273eb50cSRichard Henderson         for (int i = 0; i < part_count; ++i) {
3741273eb50cSRichard Henderson             ts[i].mem_offset = off + i * part_size;
3742273eb50cSRichard Henderson             ts[i].mem_base = s->frame_temp;
3743273eb50cSRichard Henderson             ts[i].mem_allocated = 1;
3744273eb50cSRichard Henderson         }
3745273eb50cSRichard Henderson     } else {
3746273eb50cSRichard Henderson         ts->mem_offset = off;
3747b3a62939SRichard Henderson         ts->mem_base = s->frame_temp;
3748c896fe29Sbellard         ts->mem_allocated = 1;
3749c896fe29Sbellard     }
3750273eb50cSRichard Henderson }
3751c896fe29Sbellard 
3752098859f1SRichard Henderson /* Assign @reg to @ts, and update reg_to_temp[]. */
3753098859f1SRichard Henderson static void set_temp_val_reg(TCGContext *s, TCGTemp *ts, TCGReg reg)
3754098859f1SRichard Henderson {
3755098859f1SRichard Henderson     if (ts->val_type == TEMP_VAL_REG) {
3756098859f1SRichard Henderson         TCGReg old = ts->reg;
3757098859f1SRichard Henderson         tcg_debug_assert(s->reg_to_temp[old] == ts);
3758098859f1SRichard Henderson         if (old == reg) {
3759098859f1SRichard Henderson             return;
3760098859f1SRichard Henderson         }
3761098859f1SRichard Henderson         s->reg_to_temp[old] = NULL;
3762098859f1SRichard Henderson     }
3763098859f1SRichard Henderson     tcg_debug_assert(s->reg_to_temp[reg] == NULL);
3764098859f1SRichard Henderson     s->reg_to_temp[reg] = ts;
3765098859f1SRichard Henderson     ts->val_type = TEMP_VAL_REG;
3766098859f1SRichard Henderson     ts->reg = reg;
3767098859f1SRichard Henderson }
3768098859f1SRichard Henderson 
3769098859f1SRichard Henderson /* Assign a non-register value type to @ts, and update reg_to_temp[]. */
3770098859f1SRichard Henderson static void set_temp_val_nonreg(TCGContext *s, TCGTemp *ts, TCGTempVal type)
3771098859f1SRichard Henderson {
3772098859f1SRichard Henderson     tcg_debug_assert(type != TEMP_VAL_REG);
3773098859f1SRichard Henderson     if (ts->val_type == TEMP_VAL_REG) {
3774098859f1SRichard Henderson         TCGReg reg = ts->reg;
3775098859f1SRichard Henderson         tcg_debug_assert(s->reg_to_temp[reg] == ts);
3776098859f1SRichard Henderson         s->reg_to_temp[reg] = NULL;
3777098859f1SRichard Henderson     }
3778098859f1SRichard Henderson     ts->val_type = type;
3779098859f1SRichard Henderson }
3780098859f1SRichard Henderson 
3781b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet);
3782b3915dbbSRichard Henderson 
378359d7c14eSRichard Henderson /* Mark a temporary as free or dead.  If 'free_or_dead' is negative,
378459d7c14eSRichard Henderson    mark it free; otherwise mark it dead.  */
378559d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead)
3786c896fe29Sbellard {
3787c0522136SRichard Henderson     TCGTempVal new_type;
3788c0522136SRichard Henderson 
3789c0522136SRichard Henderson     switch (ts->kind) {
3790c0522136SRichard Henderson     case TEMP_FIXED:
379159d7c14eSRichard Henderson         return;
3792c0522136SRichard Henderson     case TEMP_GLOBAL:
3793f57c6915SRichard Henderson     case TEMP_TB:
3794c0522136SRichard Henderson         new_type = TEMP_VAL_MEM;
3795c0522136SRichard Henderson         break;
3796c7482438SRichard Henderson     case TEMP_EBB:
3797c0522136SRichard Henderson         new_type = free_or_dead < 0 ? TEMP_VAL_MEM : TEMP_VAL_DEAD;
3798c0522136SRichard Henderson         break;
3799c0522136SRichard Henderson     case TEMP_CONST:
3800c0522136SRichard Henderson         new_type = TEMP_VAL_CONST;
3801c0522136SRichard Henderson         break;
3802c0522136SRichard Henderson     default:
3803c0522136SRichard Henderson         g_assert_not_reached();
380459d7c14eSRichard Henderson     }
3805098859f1SRichard Henderson     set_temp_val_nonreg(s, ts, new_type);
380659d7c14eSRichard Henderson }
3807c896fe29Sbellard 
380859d7c14eSRichard Henderson /* Mark a temporary as dead.  */
380959d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts)
381059d7c14eSRichard Henderson {
381159d7c14eSRichard Henderson     temp_free_or_dead(s, ts, 1);
381259d7c14eSRichard Henderson }
381359d7c14eSRichard Henderson 
381459d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary
381559d7c14eSRichard Henderson    registers needs to be allocated to store a constant.  If 'free_or_dead'
381659d7c14eSRichard Henderson    is non-zero, subsequently release the temporary; if it is positive, the
381759d7c14eSRichard Henderson    temp is dead; if it is negative, the temp is free.  */
381898b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs,
381998b4e186SRichard Henderson                       TCGRegSet preferred_regs, int free_or_dead)
382059d7c14eSRichard Henderson {
3821c0522136SRichard Henderson     if (!temp_readonly(ts) && !ts->mem_coherent) {
38227f6ceedfSAurelien Jarno         if (!ts->mem_allocated) {
38232272e4a7SRichard Henderson             temp_allocate_frame(s, ts);
382459d7c14eSRichard Henderson         }
382559d7c14eSRichard Henderson         switch (ts->val_type) {
382659d7c14eSRichard Henderson         case TEMP_VAL_CONST:
382759d7c14eSRichard Henderson             /* If we're going to free the temp immediately, then we won't
382859d7c14eSRichard Henderson                require it later in a register, so attempt to store the
382959d7c14eSRichard Henderson                constant to memory directly.  */
383059d7c14eSRichard Henderson             if (free_or_dead
383159d7c14eSRichard Henderson                 && tcg_out_sti(s, ts->type, ts->val,
383259d7c14eSRichard Henderson                                ts->mem_base->reg, ts->mem_offset)) {
383359d7c14eSRichard Henderson                 break;
383459d7c14eSRichard Henderson             }
383559d7c14eSRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
383698b4e186SRichard Henderson                       allocated_regs, preferred_regs);
383759d7c14eSRichard Henderson             /* fallthrough */
383859d7c14eSRichard Henderson 
383959d7c14eSRichard Henderson         case TEMP_VAL_REG:
384059d7c14eSRichard Henderson             tcg_out_st(s, ts->type, ts->reg,
384159d7c14eSRichard Henderson                        ts->mem_base->reg, ts->mem_offset);
384259d7c14eSRichard Henderson             break;
384359d7c14eSRichard Henderson 
384459d7c14eSRichard Henderson         case TEMP_VAL_MEM:
384559d7c14eSRichard Henderson             break;
384659d7c14eSRichard Henderson 
384759d7c14eSRichard Henderson         case TEMP_VAL_DEAD:
384859d7c14eSRichard Henderson         default:
3849732e89f4SRichard Henderson             g_assert_not_reached();
3850c896fe29Sbellard         }
38517f6ceedfSAurelien Jarno         ts->mem_coherent = 1;
38527f6ceedfSAurelien Jarno     }
385359d7c14eSRichard Henderson     if (free_or_dead) {
385459d7c14eSRichard Henderson         temp_free_or_dead(s, ts, free_or_dead);
385559d7c14eSRichard Henderson     }
385659d7c14eSRichard Henderson }
38577f6ceedfSAurelien Jarno 
38587f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */
3859b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs)
38607f6ceedfSAurelien Jarno {
3861f8b2f202SRichard Henderson     TCGTemp *ts = s->reg_to_temp[reg];
3862f8b2f202SRichard Henderson     if (ts != NULL) {
386398b4e186SRichard Henderson         temp_sync(s, ts, allocated_regs, 0, -1);
3864c896fe29Sbellard     }
3865c896fe29Sbellard }
3866c896fe29Sbellard 
3867b016486eSRichard Henderson /**
3868b016486eSRichard Henderson  * tcg_reg_alloc:
3869b016486eSRichard Henderson  * @required_regs: Set of registers in which we must allocate.
3870b016486eSRichard Henderson  * @allocated_regs: Set of registers which must be avoided.
3871b016486eSRichard Henderson  * @preferred_regs: Set of registers we should prefer.
3872b016486eSRichard Henderson  * @rev: True if we search the registers in "indirect" order.
3873b016486eSRichard Henderson  *
3874b016486eSRichard Henderson  * The allocated register must be in @required_regs & ~@allocated_regs,
3875b016486eSRichard Henderson  * but if we can put it in @preferred_regs we may save a move later.
3876b016486eSRichard Henderson  */
3877b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs,
3878b016486eSRichard Henderson                             TCGRegSet allocated_regs,
3879b016486eSRichard Henderson                             TCGRegSet preferred_regs, bool rev)
3880c896fe29Sbellard {
3881b016486eSRichard Henderson     int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
3882b016486eSRichard Henderson     TCGRegSet reg_ct[2];
388391478cefSRichard Henderson     const int *order;
3884c896fe29Sbellard 
3885b016486eSRichard Henderson     reg_ct[1] = required_regs & ~allocated_regs;
3886b016486eSRichard Henderson     tcg_debug_assert(reg_ct[1] != 0);
3887b016486eSRichard Henderson     reg_ct[0] = reg_ct[1] & preferred_regs;
3888b016486eSRichard Henderson 
3889b016486eSRichard Henderson     /* Skip the preferred_regs option if it cannot be satisfied,
3890b016486eSRichard Henderson        or if the preference made no difference.  */
3891b016486eSRichard Henderson     f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1];
3892b016486eSRichard Henderson 
389391478cefSRichard Henderson     order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
3894c896fe29Sbellard 
3895b016486eSRichard Henderson     /* Try free registers, preferences first.  */
3896b016486eSRichard Henderson     for (j = f; j < 2; j++) {
3897b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
3898b016486eSRichard Henderson 
3899b016486eSRichard Henderson         if (tcg_regset_single(set)) {
3900b016486eSRichard Henderson             /* One register in the set.  */
3901b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
3902b016486eSRichard Henderson             if (s->reg_to_temp[reg] == NULL) {
3903c896fe29Sbellard                 return reg;
3904c896fe29Sbellard             }
3905b016486eSRichard Henderson         } else {
390691478cefSRichard Henderson             for (i = 0; i < n; i++) {
3907b016486eSRichard Henderson                 TCGReg reg = order[i];
3908b016486eSRichard Henderson                 if (s->reg_to_temp[reg] == NULL &&
3909b016486eSRichard Henderson                     tcg_regset_test_reg(set, reg)) {
3910b016486eSRichard Henderson                     return reg;
3911b016486eSRichard Henderson                 }
3912b016486eSRichard Henderson             }
3913b016486eSRichard Henderson         }
3914b016486eSRichard Henderson     }
3915b016486eSRichard Henderson 
3916b016486eSRichard Henderson     /* We must spill something.  */
3917b016486eSRichard Henderson     for (j = f; j < 2; j++) {
3918b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
3919b016486eSRichard Henderson 
3920b016486eSRichard Henderson         if (tcg_regset_single(set)) {
3921b016486eSRichard Henderson             /* One register in the set.  */
3922b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
3923b3915dbbSRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
3924c896fe29Sbellard             return reg;
3925b016486eSRichard Henderson         } else {
3926b016486eSRichard Henderson             for (i = 0; i < n; i++) {
3927b016486eSRichard Henderson                 TCGReg reg = order[i];
3928b016486eSRichard Henderson                 if (tcg_regset_test_reg(set, reg)) {
3929b016486eSRichard Henderson                     tcg_reg_free(s, reg, allocated_regs);
3930b016486eSRichard Henderson                     return reg;
3931b016486eSRichard Henderson                 }
3932b016486eSRichard Henderson             }
3933c896fe29Sbellard         }
3934c896fe29Sbellard     }
3935c896fe29Sbellard 
3936732e89f4SRichard Henderson     g_assert_not_reached();
3937c896fe29Sbellard }
3938c896fe29Sbellard 
393929f5e925SRichard Henderson static TCGReg tcg_reg_alloc_pair(TCGContext *s, TCGRegSet required_regs,
394029f5e925SRichard Henderson                                  TCGRegSet allocated_regs,
394129f5e925SRichard Henderson                                  TCGRegSet preferred_regs, bool rev)
394229f5e925SRichard Henderson {
394329f5e925SRichard Henderson     int i, j, k, fmin, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
394429f5e925SRichard Henderson     TCGRegSet reg_ct[2];
394529f5e925SRichard Henderson     const int *order;
394629f5e925SRichard Henderson 
394729f5e925SRichard Henderson     /* Ensure that if I is not in allocated_regs, I+1 is not either. */
394829f5e925SRichard Henderson     reg_ct[1] = required_regs & ~(allocated_regs | (allocated_regs >> 1));
394929f5e925SRichard Henderson     tcg_debug_assert(reg_ct[1] != 0);
395029f5e925SRichard Henderson     reg_ct[0] = reg_ct[1] & preferred_regs;
395129f5e925SRichard Henderson 
395229f5e925SRichard Henderson     order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
395329f5e925SRichard Henderson 
395429f5e925SRichard Henderson     /*
395529f5e925SRichard Henderson      * Skip the preferred_regs option if it cannot be satisfied,
395629f5e925SRichard Henderson      * or if the preference made no difference.
395729f5e925SRichard Henderson      */
395829f5e925SRichard Henderson     k = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1];
395929f5e925SRichard Henderson 
396029f5e925SRichard Henderson     /*
396129f5e925SRichard Henderson      * Minimize the number of flushes by looking for 2 free registers first,
396229f5e925SRichard Henderson      * then a single flush, then two flushes.
396329f5e925SRichard Henderson      */
396429f5e925SRichard Henderson     for (fmin = 2; fmin >= 0; fmin--) {
396529f5e925SRichard Henderson         for (j = k; j < 2; j++) {
396629f5e925SRichard Henderson             TCGRegSet set = reg_ct[j];
396729f5e925SRichard Henderson 
396829f5e925SRichard Henderson             for (i = 0; i < n; i++) {
396929f5e925SRichard Henderson                 TCGReg reg = order[i];
397029f5e925SRichard Henderson 
397129f5e925SRichard Henderson                 if (tcg_regset_test_reg(set, reg)) {
397229f5e925SRichard Henderson                     int f = !s->reg_to_temp[reg] + !s->reg_to_temp[reg + 1];
397329f5e925SRichard Henderson                     if (f >= fmin) {
397429f5e925SRichard Henderson                         tcg_reg_free(s, reg, allocated_regs);
397529f5e925SRichard Henderson                         tcg_reg_free(s, reg + 1, allocated_regs);
397629f5e925SRichard Henderson                         return reg;
397729f5e925SRichard Henderson                     }
397829f5e925SRichard Henderson                 }
397929f5e925SRichard Henderson             }
398029f5e925SRichard Henderson         }
398129f5e925SRichard Henderson     }
3982732e89f4SRichard Henderson     g_assert_not_reached();
398329f5e925SRichard Henderson }
398429f5e925SRichard Henderson 
398540ae5c62SRichard Henderson /* Make sure the temporary is in a register.  If needed, allocate the register
398640ae5c62SRichard Henderson    from DESIRED while avoiding ALLOCATED.  */
398740ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs,
3988b722452aSRichard Henderson                       TCGRegSet allocated_regs, TCGRegSet preferred_regs)
398940ae5c62SRichard Henderson {
399040ae5c62SRichard Henderson     TCGReg reg;
399140ae5c62SRichard Henderson 
399240ae5c62SRichard Henderson     switch (ts->val_type) {
399340ae5c62SRichard Henderson     case TEMP_VAL_REG:
399440ae5c62SRichard Henderson         return;
399540ae5c62SRichard Henderson     case TEMP_VAL_CONST:
3996b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
3997b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
39980a6a8bc8SRichard Henderson         if (ts->type <= TCG_TYPE_I64) {
399940ae5c62SRichard Henderson             tcg_out_movi(s, ts->type, reg, ts->val);
40000a6a8bc8SRichard Henderson         } else {
40014e186175SRichard Henderson             uint64_t val = ts->val;
40024e186175SRichard Henderson             MemOp vece = MO_64;
40034e186175SRichard Henderson 
40044e186175SRichard Henderson             /*
40054e186175SRichard Henderson              * Find the minimal vector element that matches the constant.
40064e186175SRichard Henderson              * The targets will, in general, have to do this search anyway,
40074e186175SRichard Henderson              * do this generically.
40084e186175SRichard Henderson              */
40094e186175SRichard Henderson             if (val == dup_const(MO_8, val)) {
40104e186175SRichard Henderson                 vece = MO_8;
40114e186175SRichard Henderson             } else if (val == dup_const(MO_16, val)) {
40124e186175SRichard Henderson                 vece = MO_16;
40130b4286ddSRichard Henderson             } else if (val == dup_const(MO_32, val)) {
40144e186175SRichard Henderson                 vece = MO_32;
40154e186175SRichard Henderson             }
40164e186175SRichard Henderson 
40174e186175SRichard Henderson             tcg_out_dupi_vec(s, ts->type, vece, reg, ts->val);
40180a6a8bc8SRichard Henderson         }
401940ae5c62SRichard Henderson         ts->mem_coherent = 0;
402040ae5c62SRichard Henderson         break;
402140ae5c62SRichard Henderson     case TEMP_VAL_MEM:
4022b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
4023b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
402440ae5c62SRichard Henderson         tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset);
402540ae5c62SRichard Henderson         ts->mem_coherent = 1;
402640ae5c62SRichard Henderson         break;
402740ae5c62SRichard Henderson     case TEMP_VAL_DEAD:
402840ae5c62SRichard Henderson     default:
4029732e89f4SRichard Henderson         g_assert_not_reached();
403040ae5c62SRichard Henderson     }
4031098859f1SRichard Henderson     set_temp_val_reg(s, ts, reg);
403240ae5c62SRichard Henderson }
403340ae5c62SRichard Henderson 
403459d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a
4035e8996ee0Sbellard    temporary registers needs to be allocated to store a constant.  */
403659d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs)
40371ad80729SAurelien Jarno {
40382c0366f0SAurelien Jarno     /* The liveness analysis already ensures that globals are back
4039eabb7b91SAurelien Jarno        in memory. Keep an tcg_debug_assert for safety. */
4040e01fa97dSRichard Henderson     tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || temp_readonly(ts));
40411ad80729SAurelien Jarno }
40421ad80729SAurelien Jarno 
40439814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be
4044641d5fbeSbellard    modified be the following code. 'allocated_regs' is used in case a
4045641d5fbeSbellard    temporary registers needs to be allocated to store a constant. */
4046641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
4047641d5fbeSbellard {
4048ac3b8891SRichard Henderson     int i, n;
4049641d5fbeSbellard 
4050ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
4051b13eb728SRichard Henderson         temp_save(s, &s->temps[i], allocated_regs);
4052641d5fbeSbellard     }
4053e5097dc8Sbellard }
4054e5097dc8Sbellard 
40553d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be
40563d5c5f87SAurelien Jarno    read by the following code. 'allocated_regs' is used in case a
40573d5c5f87SAurelien Jarno    temporary registers needs to be allocated to store a constant. */
40583d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs)
40593d5c5f87SAurelien Jarno {
4060ac3b8891SRichard Henderson     int i, n;
40613d5c5f87SAurelien Jarno 
4062ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
406312b9b11aSRichard Henderson         TCGTemp *ts = &s->temps[i];
406412b9b11aSRichard Henderson         tcg_debug_assert(ts->val_type != TEMP_VAL_REG
4065ee17db83SRichard Henderson                          || ts->kind == TEMP_FIXED
406612b9b11aSRichard Henderson                          || ts->mem_coherent);
40673d5c5f87SAurelien Jarno     }
40683d5c5f87SAurelien Jarno }
40693d5c5f87SAurelien Jarno 
4070e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and
4071e8996ee0Sbellard    all globals are stored at their canonical location. */
4072e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
4073e5097dc8Sbellard {
4074e5097dc8Sbellard     int i;
4075e5097dc8Sbellard 
4076c896fe29Sbellard     for (i = s->nb_globals; i < s->nb_temps; i++) {
4077b13eb728SRichard Henderson         TCGTemp *ts = &s->temps[i];
4078c0522136SRichard Henderson 
4079c0522136SRichard Henderson         switch (ts->kind) {
4080f57c6915SRichard Henderson         case TEMP_TB:
4081b13eb728SRichard Henderson             temp_save(s, ts, allocated_regs);
4082c0522136SRichard Henderson             break;
4083c7482438SRichard Henderson         case TEMP_EBB:
40842c0366f0SAurelien Jarno             /* The liveness analysis already ensures that temps are dead.
4085eabb7b91SAurelien Jarno                Keep an tcg_debug_assert for safety. */
4086eabb7b91SAurelien Jarno             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
4087c0522136SRichard Henderson             break;
4088c0522136SRichard Henderson         case TEMP_CONST:
4089c0522136SRichard Henderson             /* Similarly, we should have freed any allocated register. */
4090c0522136SRichard Henderson             tcg_debug_assert(ts->val_type == TEMP_VAL_CONST);
4091c0522136SRichard Henderson             break;
4092c0522136SRichard Henderson         default:
4093c0522136SRichard Henderson             g_assert_not_reached();
4094c896fe29Sbellard         }
4095641d5fbeSbellard     }
4096e8996ee0Sbellard 
4097e8996ee0Sbellard     save_globals(s, allocated_regs);
4098c896fe29Sbellard }
4099c896fe29Sbellard 
4100bab1671fSRichard Henderson /*
4101c7482438SRichard Henderson  * At a conditional branch, we assume all temporaries are dead unless
4102c7482438SRichard Henderson  * explicitly live-across-conditional-branch; all globals and local
4103c7482438SRichard Henderson  * temps are synced to their location.
4104b4cb76e6SRichard Henderson  */
4105b4cb76e6SRichard Henderson static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs)
4106b4cb76e6SRichard Henderson {
4107b4cb76e6SRichard Henderson     sync_globals(s, allocated_regs);
4108b4cb76e6SRichard Henderson 
4109b4cb76e6SRichard Henderson     for (int i = s->nb_globals; i < s->nb_temps; i++) {
4110b4cb76e6SRichard Henderson         TCGTemp *ts = &s->temps[i];
4111b4cb76e6SRichard Henderson         /*
4112b4cb76e6SRichard Henderson          * The liveness analysis already ensures that temps are dead.
4113b4cb76e6SRichard Henderson          * Keep tcg_debug_asserts for safety.
4114b4cb76e6SRichard Henderson          */
4115c0522136SRichard Henderson         switch (ts->kind) {
4116f57c6915SRichard Henderson         case TEMP_TB:
4117b4cb76e6SRichard Henderson             tcg_debug_assert(ts->val_type != TEMP_VAL_REG || ts->mem_coherent);
4118c0522136SRichard Henderson             break;
4119c7482438SRichard Henderson         case TEMP_EBB:
4120c0522136SRichard Henderson         case TEMP_CONST:
4121c0522136SRichard Henderson             break;
4122c0522136SRichard Henderson         default:
4123c0522136SRichard Henderson             g_assert_not_reached();
4124b4cb76e6SRichard Henderson         }
4125b4cb76e6SRichard Henderson     }
4126b4cb76e6SRichard Henderson }
4127b4cb76e6SRichard Henderson 
4128b4cb76e6SRichard Henderson /*
4129c58f4c97SRichard Henderson  * Specialized code generation for INDEX_op_mov_* with a constant.
4130bab1671fSRichard Henderson  */
41310fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots,
4132ba87719cSRichard Henderson                                   tcg_target_ulong val, TCGLifeData arg_life,
4133ba87719cSRichard Henderson                                   TCGRegSet preferred_regs)
4134e8996ee0Sbellard {
4135d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
4136e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
413759d7c14eSRichard Henderson 
413859d7c14eSRichard Henderson     /* The movi is not explicitly generated here.  */
4139098859f1SRichard Henderson     set_temp_val_nonreg(s, ots, TEMP_VAL_CONST);
4140e8996ee0Sbellard     ots->val = val;
414159d7c14eSRichard Henderson     ots->mem_coherent = 0;
4142ec7a869dSAurelien Jarno     if (NEED_SYNC_ARG(0)) {
4143ba87719cSRichard Henderson         temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0));
414459d7c14eSRichard Henderson     } else if (IS_DEAD_ARG(0)) {
4145f8bf00f1SRichard Henderson         temp_dead(s, ots);
41464c4e1ab2SAurelien Jarno     }
4147e8996ee0Sbellard }
4148e8996ee0Sbellard 
4149bab1671fSRichard Henderson /*
4150bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_mov_*.
4151bab1671fSRichard Henderson  */
4152dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op)
4153c896fe29Sbellard {
4154dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
415569e3706dSRichard Henderson     TCGRegSet allocated_regs, preferred_regs;
4156c896fe29Sbellard     TCGTemp *ts, *ots;
4157450445d5SRichard Henderson     TCGType otype, itype;
4158098859f1SRichard Henderson     TCGReg oreg, ireg;
4159c896fe29Sbellard 
4160d21369f5SRichard Henderson     allocated_regs = s->reserved_regs;
416131fd884bSRichard Henderson     preferred_regs = output_pref(op, 0);
416243439139SRichard Henderson     ots = arg_temp(op->args[0]);
416343439139SRichard Henderson     ts = arg_temp(op->args[1]);
4164450445d5SRichard Henderson 
4165d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
4166e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
4167d63e3b6eSRichard Henderson 
4168450445d5SRichard Henderson     /* Note that otype != itype for no-op truncation.  */
4169450445d5SRichard Henderson     otype = ots->type;
4170450445d5SRichard Henderson     itype = ts->type;
4171c896fe29Sbellard 
41720fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_CONST) {
41730fe4fca4SPaolo Bonzini         /* propagate constant or generate sti */
41740fe4fca4SPaolo Bonzini         tcg_target_ulong val = ts->val;
41750fe4fca4SPaolo Bonzini         if (IS_DEAD_ARG(1)) {
41760fe4fca4SPaolo Bonzini             temp_dead(s, ts);
41770fe4fca4SPaolo Bonzini         }
417869e3706dSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs);
41790fe4fca4SPaolo Bonzini         return;
41800fe4fca4SPaolo Bonzini     }
41810fe4fca4SPaolo Bonzini 
41820fe4fca4SPaolo Bonzini     /* If the source value is in memory we're going to be forced
41830fe4fca4SPaolo Bonzini        to have it in a register in order to perform the copy.  Copy
41840fe4fca4SPaolo Bonzini        the SOURCE value into its own register first, that way we
41850fe4fca4SPaolo Bonzini        don't have to reload SOURCE the next time it is used. */
41860fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_MEM) {
418769e3706dSRichard Henderson         temp_load(s, ts, tcg_target_available_regs[itype],
418869e3706dSRichard Henderson                   allocated_regs, preferred_regs);
4189c29c1d7eSAurelien Jarno     }
41900fe4fca4SPaolo Bonzini     tcg_debug_assert(ts->val_type == TEMP_VAL_REG);
4191098859f1SRichard Henderson     ireg = ts->reg;
4192098859f1SRichard Henderson 
4193d63e3b6eSRichard Henderson     if (IS_DEAD_ARG(0)) {
4194c29c1d7eSAurelien Jarno         /* mov to a non-saved dead register makes no sense (even with
4195c29c1d7eSAurelien Jarno            liveness analysis disabled). */
4196eabb7b91SAurelien Jarno         tcg_debug_assert(NEED_SYNC_ARG(0));
4197c29c1d7eSAurelien Jarno         if (!ots->mem_allocated) {
41982272e4a7SRichard Henderson             temp_allocate_frame(s, ots);
4199c29c1d7eSAurelien Jarno         }
4200098859f1SRichard Henderson         tcg_out_st(s, otype, ireg, ots->mem_base->reg, ots->mem_offset);
4201c29c1d7eSAurelien Jarno         if (IS_DEAD_ARG(1)) {
4202f8bf00f1SRichard Henderson             temp_dead(s, ts);
4203c29c1d7eSAurelien Jarno         }
4204f8bf00f1SRichard Henderson         temp_dead(s, ots);
4205098859f1SRichard Henderson         return;
4206098859f1SRichard Henderson     }
4207098859f1SRichard Henderson 
4208ee17db83SRichard Henderson     if (IS_DEAD_ARG(1) && ts->kind != TEMP_FIXED) {
4209098859f1SRichard Henderson         /*
4210098859f1SRichard Henderson          * The mov can be suppressed.  Kill input first, so that it
4211098859f1SRichard Henderson          * is unlinked from reg_to_temp, then set the output to the
4212098859f1SRichard Henderson          * reg that we saved from the input.
4213098859f1SRichard Henderson          */
4214f8bf00f1SRichard Henderson         temp_dead(s, ts);
4215098859f1SRichard Henderson         oreg = ireg;
4216c29c1d7eSAurelien Jarno     } else {
4217098859f1SRichard Henderson         if (ots->val_type == TEMP_VAL_REG) {
4218098859f1SRichard Henderson             oreg = ots->reg;
4219098859f1SRichard Henderson         } else {
4220098859f1SRichard Henderson             /* Make sure to not spill the input register during allocation. */
4221098859f1SRichard Henderson             oreg = tcg_reg_alloc(s, tcg_target_available_regs[otype],
4222098859f1SRichard Henderson                                  allocated_regs | ((TCGRegSet)1 << ireg),
4223098859f1SRichard Henderson                                  preferred_regs, ots->indirect_base);
4224c29c1d7eSAurelien Jarno         }
4225098859f1SRichard Henderson         if (!tcg_out_mov(s, otype, oreg, ireg)) {
4226240c08d0SRichard Henderson             /*
4227240c08d0SRichard Henderson              * Cross register class move not supported.
4228240c08d0SRichard Henderson              * Store the source register into the destination slot
4229240c08d0SRichard Henderson              * and leave the destination temp as TEMP_VAL_MEM.
4230240c08d0SRichard Henderson              */
4231e01fa97dSRichard Henderson             assert(!temp_readonly(ots));
4232240c08d0SRichard Henderson             if (!ts->mem_allocated) {
4233240c08d0SRichard Henderson                 temp_allocate_frame(s, ots);
4234240c08d0SRichard Henderson             }
4235098859f1SRichard Henderson             tcg_out_st(s, ts->type, ireg, ots->mem_base->reg, ots->mem_offset);
4236098859f1SRichard Henderson             set_temp_val_nonreg(s, ts, TEMP_VAL_MEM);
4237240c08d0SRichard Henderson             ots->mem_coherent = 1;
4238240c08d0SRichard Henderson             return;
423978113e83SRichard Henderson         }
4240c29c1d7eSAurelien Jarno     }
4241098859f1SRichard Henderson     set_temp_val_reg(s, ots, oreg);
4242c896fe29Sbellard     ots->mem_coherent = 0;
4243098859f1SRichard Henderson 
4244ec7a869dSAurelien Jarno     if (NEED_SYNC_ARG(0)) {
424598b4e186SRichard Henderson         temp_sync(s, ots, allocated_regs, 0, 0);
4246c29c1d7eSAurelien Jarno     }
4247ec7a869dSAurelien Jarno }
4248c896fe29Sbellard 
4249bab1671fSRichard Henderson /*
4250bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_dup_vec.
4251bab1671fSRichard Henderson  */
4252bab1671fSRichard Henderson static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op)
4253bab1671fSRichard Henderson {
4254bab1671fSRichard Henderson     const TCGLifeData arg_life = op->life;
4255bab1671fSRichard Henderson     TCGRegSet dup_out_regs, dup_in_regs;
4256bab1671fSRichard Henderson     TCGTemp *its, *ots;
4257bab1671fSRichard Henderson     TCGType itype, vtype;
4258bab1671fSRichard Henderson     unsigned vece;
425931c96417SRichard Henderson     int lowpart_ofs;
4260bab1671fSRichard Henderson     bool ok;
4261bab1671fSRichard Henderson 
4262bab1671fSRichard Henderson     ots = arg_temp(op->args[0]);
4263bab1671fSRichard Henderson     its = arg_temp(op->args[1]);
4264bab1671fSRichard Henderson 
4265bab1671fSRichard Henderson     /* ENV should not be modified.  */
4266e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
4267bab1671fSRichard Henderson 
4268bab1671fSRichard Henderson     itype = its->type;
4269bab1671fSRichard Henderson     vece = TCGOP_VECE(op);
4270bab1671fSRichard Henderson     vtype = TCGOP_VECL(op) + TCG_TYPE_V64;
4271bab1671fSRichard Henderson 
4272bab1671fSRichard Henderson     if (its->val_type == TEMP_VAL_CONST) {
4273bab1671fSRichard Henderson         /* Propagate constant via movi -> dupi.  */
4274bab1671fSRichard Henderson         tcg_target_ulong val = its->val;
4275bab1671fSRichard Henderson         if (IS_DEAD_ARG(1)) {
4276bab1671fSRichard Henderson             temp_dead(s, its);
4277bab1671fSRichard Henderson         }
427831fd884bSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, output_pref(op, 0));
4279bab1671fSRichard Henderson         return;
4280bab1671fSRichard Henderson     }
4281bab1671fSRichard Henderson 
42829be0d080SRichard Henderson     dup_out_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs;
42839be0d080SRichard Henderson     dup_in_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[1].regs;
4284bab1671fSRichard Henderson 
4285bab1671fSRichard Henderson     /* Allocate the output register now.  */
4286bab1671fSRichard Henderson     if (ots->val_type != TEMP_VAL_REG) {
4287bab1671fSRichard Henderson         TCGRegSet allocated_regs = s->reserved_regs;
4288098859f1SRichard Henderson         TCGReg oreg;
4289bab1671fSRichard Henderson 
4290bab1671fSRichard Henderson         if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) {
4291bab1671fSRichard Henderson             /* Make sure to not spill the input register. */
4292bab1671fSRichard Henderson             tcg_regset_set_reg(allocated_regs, its->reg);
4293bab1671fSRichard Henderson         }
4294098859f1SRichard Henderson         oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
429531fd884bSRichard Henderson                              output_pref(op, 0), ots->indirect_base);
4296098859f1SRichard Henderson         set_temp_val_reg(s, ots, oreg);
4297bab1671fSRichard Henderson     }
4298bab1671fSRichard Henderson 
4299bab1671fSRichard Henderson     switch (its->val_type) {
4300bab1671fSRichard Henderson     case TEMP_VAL_REG:
4301bab1671fSRichard Henderson         /*
4302bab1671fSRichard Henderson          * The dup constriaints must be broad, covering all possible VECE.
4303bab1671fSRichard Henderson          * However, tcg_op_dup_vec() gets to see the VECE and we allow it
4304bab1671fSRichard Henderson          * to fail, indicating that extra moves are required for that case.
4305bab1671fSRichard Henderson          */
4306bab1671fSRichard Henderson         if (tcg_regset_test_reg(dup_in_regs, its->reg)) {
4307bab1671fSRichard Henderson             if (tcg_out_dup_vec(s, vtype, vece, ots->reg, its->reg)) {
4308bab1671fSRichard Henderson                 goto done;
4309bab1671fSRichard Henderson             }
4310bab1671fSRichard Henderson             /* Try again from memory or a vector input register.  */
4311bab1671fSRichard Henderson         }
4312bab1671fSRichard Henderson         if (!its->mem_coherent) {
4313bab1671fSRichard Henderson             /*
4314bab1671fSRichard Henderson              * The input register is not synced, and so an extra store
4315bab1671fSRichard Henderson              * would be required to use memory.  Attempt an integer-vector
4316bab1671fSRichard Henderson              * register move first.  We do not have a TCGRegSet for this.
4317bab1671fSRichard Henderson              */
4318bab1671fSRichard Henderson             if (tcg_out_mov(s, itype, ots->reg, its->reg)) {
4319bab1671fSRichard Henderson                 break;
4320bab1671fSRichard Henderson             }
4321bab1671fSRichard Henderson             /* Sync the temp back to its slot and load from there.  */
4322bab1671fSRichard Henderson             temp_sync(s, its, s->reserved_regs, 0, 0);
4323bab1671fSRichard Henderson         }
4324bab1671fSRichard Henderson         /* fall through */
4325bab1671fSRichard Henderson 
4326bab1671fSRichard Henderson     case TEMP_VAL_MEM:
432731c96417SRichard Henderson         lowpart_ofs = 0;
432831c96417SRichard Henderson         if (HOST_BIG_ENDIAN) {
432931c96417SRichard Henderson             lowpart_ofs = tcg_type_size(itype) - (1 << vece);
433031c96417SRichard Henderson         }
4331d6ecb4a9SRichard Henderson         if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg,
433231c96417SRichard Henderson                              its->mem_offset + lowpart_ofs)) {
4333d6ecb4a9SRichard Henderson             goto done;
4334d6ecb4a9SRichard Henderson         }
4335098859f1SRichard Henderson         /* Load the input into the destination vector register. */
4336bab1671fSRichard Henderson         tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset);
4337bab1671fSRichard Henderson         break;
4338bab1671fSRichard Henderson 
4339bab1671fSRichard Henderson     default:
4340bab1671fSRichard Henderson         g_assert_not_reached();
4341bab1671fSRichard Henderson     }
4342bab1671fSRichard Henderson 
4343bab1671fSRichard Henderson     /* We now have a vector input register, so dup must succeed. */
4344bab1671fSRichard Henderson     ok = tcg_out_dup_vec(s, vtype, vece, ots->reg, ots->reg);
4345bab1671fSRichard Henderson     tcg_debug_assert(ok);
4346bab1671fSRichard Henderson 
4347bab1671fSRichard Henderson  done:
434836f5539cSRichard Henderson     ots->mem_coherent = 0;
4349bab1671fSRichard Henderson     if (IS_DEAD_ARG(1)) {
4350bab1671fSRichard Henderson         temp_dead(s, its);
4351bab1671fSRichard Henderson     }
4352bab1671fSRichard Henderson     if (NEED_SYNC_ARG(0)) {
4353bab1671fSRichard Henderson         temp_sync(s, ots, s->reserved_regs, 0, 0);
4354bab1671fSRichard Henderson     }
4355bab1671fSRichard Henderson     if (IS_DEAD_ARG(0)) {
4356bab1671fSRichard Henderson         temp_dead(s, ots);
4357bab1671fSRichard Henderson     }
4358bab1671fSRichard Henderson }
4359bab1671fSRichard Henderson 
4360dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op)
4361c896fe29Sbellard {
4362dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
4363dd186292SRichard Henderson     const TCGOpDef * const def = &tcg_op_defs[op->opc];
436482790a87SRichard Henderson     TCGRegSet i_allocated_regs;
436582790a87SRichard Henderson     TCGRegSet o_allocated_regs;
4366b6638662SRichard Henderson     int i, k, nb_iargs, nb_oargs;
4367b6638662SRichard Henderson     TCGReg reg;
4368c896fe29Sbellard     TCGArg arg;
4369c896fe29Sbellard     const TCGArgConstraint *arg_ct;
4370c896fe29Sbellard     TCGTemp *ts;
4371c896fe29Sbellard     TCGArg new_args[TCG_MAX_OP_ARGS];
4372c896fe29Sbellard     int const_args[TCG_MAX_OP_ARGS];
4373c896fe29Sbellard 
4374c896fe29Sbellard     nb_oargs = def->nb_oargs;
4375c896fe29Sbellard     nb_iargs = def->nb_iargs;
4376c896fe29Sbellard 
4377c896fe29Sbellard     /* copy constants */
4378c896fe29Sbellard     memcpy(new_args + nb_oargs + nb_iargs,
4379dd186292SRichard Henderson            op->args + nb_oargs + nb_iargs,
4380c896fe29Sbellard            sizeof(TCGArg) * def->nb_cargs);
4381c896fe29Sbellard 
4382d21369f5SRichard Henderson     i_allocated_regs = s->reserved_regs;
4383d21369f5SRichard Henderson     o_allocated_regs = s->reserved_regs;
438482790a87SRichard Henderson 
4385c896fe29Sbellard     /* satisfy input constraints */
4386c896fe29Sbellard     for (k = 0; k < nb_iargs; k++) {
438729f5e925SRichard Henderson         TCGRegSet i_preferred_regs, i_required_regs;
438829f5e925SRichard Henderson         bool allocate_new_reg, copyto_new_reg;
438929f5e925SRichard Henderson         TCGTemp *ts2;
439029f5e925SRichard Henderson         int i1, i2;
4391d62816f2SRichard Henderson 
439266792f90SRichard Henderson         i = def->args_ct[nb_oargs + k].sort_index;
4393dd186292SRichard Henderson         arg = op->args[i];
4394c896fe29Sbellard         arg_ct = &def->args_ct[i];
439543439139SRichard Henderson         ts = arg_temp(arg);
439640ae5c62SRichard Henderson 
439740ae5c62SRichard Henderson         if (ts->val_type == TEMP_VAL_CONST
4398a4fbbd77SRichard Henderson             && tcg_target_const_match(ts->val, ts->type, arg_ct->ct)) {
4399c896fe29Sbellard             /* constant is OK for instruction */
4400c896fe29Sbellard             const_args[i] = 1;
4401c896fe29Sbellard             new_args[i] = ts->val;
4402d62816f2SRichard Henderson             continue;
4403c896fe29Sbellard         }
440440ae5c62SRichard Henderson 
44051c1824dcSRichard Henderson         reg = ts->reg;
44061c1824dcSRichard Henderson         i_preferred_regs = 0;
440729f5e925SRichard Henderson         i_required_regs = arg_ct->regs;
44081c1824dcSRichard Henderson         allocate_new_reg = false;
440929f5e925SRichard Henderson         copyto_new_reg = false;
44101c1824dcSRichard Henderson 
441129f5e925SRichard Henderson         switch (arg_ct->pair) {
441229f5e925SRichard Henderson         case 0: /* not paired */
4413bc2b17e6SRichard Henderson             if (arg_ct->ialias) {
441431fd884bSRichard Henderson                 i_preferred_regs = output_pref(op, arg_ct->alias_index);
4415c0522136SRichard Henderson 
4416c0522136SRichard Henderson                 /*
4417c0522136SRichard Henderson                  * If the input is readonly, then it cannot also be an
4418c0522136SRichard Henderson                  * output and aliased to itself.  If the input is not
4419c0522136SRichard Henderson                  * dead after the instruction, we must allocate a new
4420c0522136SRichard Henderson                  * register and move it.
4421c0522136SRichard Henderson                  */
4422c0522136SRichard Henderson                 if (temp_readonly(ts) || !IS_DEAD_ARG(i)) {
44231c1824dcSRichard Henderson                     allocate_new_reg = true;
44241c1824dcSRichard Henderson                 } else if (ts->val_type == TEMP_VAL_REG) {
4425c0522136SRichard Henderson                     /*
44261c1824dcSRichard Henderson                      * Check if the current register has already been
44271c1824dcSRichard Henderson                      * allocated for another input.
4428c0522136SRichard Henderson                      */
442929f5e925SRichard Henderson                     allocate_new_reg =
443029f5e925SRichard Henderson                         tcg_regset_test_reg(i_allocated_regs, reg);
44317e1df267SAurelien Jarno                 }
44327e1df267SAurelien Jarno             }
44331c1824dcSRichard Henderson             if (!allocate_new_reg) {
443429f5e925SRichard Henderson                 temp_load(s, ts, i_required_regs, i_allocated_regs,
443529f5e925SRichard Henderson                           i_preferred_regs);
4436c896fe29Sbellard                 reg = ts->reg;
443729f5e925SRichard Henderson                 allocate_new_reg = !tcg_regset_test_reg(i_required_regs, reg);
44381c1824dcSRichard Henderson             }
44391c1824dcSRichard Henderson             if (allocate_new_reg) {
4440c0522136SRichard Henderson                 /*
4441c0522136SRichard Henderson                  * Allocate a new register matching the constraint
4442c0522136SRichard Henderson                  * and move the temporary register into it.
4443c0522136SRichard Henderson                  */
4444d62816f2SRichard Henderson                 temp_load(s, ts, tcg_target_available_regs[ts->type],
4445d62816f2SRichard Henderson                           i_allocated_regs, 0);
444629f5e925SRichard Henderson                 reg = tcg_reg_alloc(s, i_required_regs, i_allocated_regs,
44471c1824dcSRichard Henderson                                     i_preferred_regs, ts->indirect_base);
444829f5e925SRichard Henderson                 copyto_new_reg = true;
444929f5e925SRichard Henderson             }
445029f5e925SRichard Henderson             break;
445129f5e925SRichard Henderson 
445229f5e925SRichard Henderson         case 1:
445329f5e925SRichard Henderson             /* First of an input pair; if i1 == i2, the second is an output. */
445429f5e925SRichard Henderson             i1 = i;
445529f5e925SRichard Henderson             i2 = arg_ct->pair_index;
445629f5e925SRichard Henderson             ts2 = i1 != i2 ? arg_temp(op->args[i2]) : NULL;
445729f5e925SRichard Henderson 
445829f5e925SRichard Henderson             /*
445929f5e925SRichard Henderson              * It is easier to default to allocating a new pair
446029f5e925SRichard Henderson              * and to identify a few cases where it's not required.
446129f5e925SRichard Henderson              */
446229f5e925SRichard Henderson             if (arg_ct->ialias) {
446331fd884bSRichard Henderson                 i_preferred_regs = output_pref(op, arg_ct->alias_index);
446429f5e925SRichard Henderson                 if (IS_DEAD_ARG(i1) &&
446529f5e925SRichard Henderson                     IS_DEAD_ARG(i2) &&
446629f5e925SRichard Henderson                     !temp_readonly(ts) &&
446729f5e925SRichard Henderson                     ts->val_type == TEMP_VAL_REG &&
446829f5e925SRichard Henderson                     ts->reg < TCG_TARGET_NB_REGS - 1 &&
446929f5e925SRichard Henderson                     tcg_regset_test_reg(i_required_regs, reg) &&
447029f5e925SRichard Henderson                     !tcg_regset_test_reg(i_allocated_regs, reg) &&
447129f5e925SRichard Henderson                     !tcg_regset_test_reg(i_allocated_regs, reg + 1) &&
447229f5e925SRichard Henderson                     (ts2
447329f5e925SRichard Henderson                      ? ts2->val_type == TEMP_VAL_REG &&
447429f5e925SRichard Henderson                        ts2->reg == reg + 1 &&
447529f5e925SRichard Henderson                        !temp_readonly(ts2)
447629f5e925SRichard Henderson                      : s->reg_to_temp[reg + 1] == NULL)) {
447729f5e925SRichard Henderson                     break;
447829f5e925SRichard Henderson                 }
447929f5e925SRichard Henderson             } else {
448029f5e925SRichard Henderson                 /* Without aliasing, the pair must also be an input. */
448129f5e925SRichard Henderson                 tcg_debug_assert(ts2);
448229f5e925SRichard Henderson                 if (ts->val_type == TEMP_VAL_REG &&
448329f5e925SRichard Henderson                     ts2->val_type == TEMP_VAL_REG &&
448429f5e925SRichard Henderson                     ts2->reg == reg + 1 &&
448529f5e925SRichard Henderson                     tcg_regset_test_reg(i_required_regs, reg)) {
448629f5e925SRichard Henderson                     break;
448729f5e925SRichard Henderson                 }
448829f5e925SRichard Henderson             }
448929f5e925SRichard Henderson             reg = tcg_reg_alloc_pair(s, i_required_regs, i_allocated_regs,
449029f5e925SRichard Henderson                                      0, ts->indirect_base);
449129f5e925SRichard Henderson             goto do_pair;
449229f5e925SRichard Henderson 
449329f5e925SRichard Henderson         case 2: /* pair second */
449429f5e925SRichard Henderson             reg = new_args[arg_ct->pair_index] + 1;
449529f5e925SRichard Henderson             goto do_pair;
449629f5e925SRichard Henderson 
449729f5e925SRichard Henderson         case 3: /* ialias with second output, no first input */
449829f5e925SRichard Henderson             tcg_debug_assert(arg_ct->ialias);
449931fd884bSRichard Henderson             i_preferred_regs = output_pref(op, arg_ct->alias_index);
450029f5e925SRichard Henderson 
450129f5e925SRichard Henderson             if (IS_DEAD_ARG(i) &&
450229f5e925SRichard Henderson                 !temp_readonly(ts) &&
450329f5e925SRichard Henderson                 ts->val_type == TEMP_VAL_REG &&
450429f5e925SRichard Henderson                 reg > 0 &&
450529f5e925SRichard Henderson                 s->reg_to_temp[reg - 1] == NULL &&
450629f5e925SRichard Henderson                 tcg_regset_test_reg(i_required_regs, reg) &&
450729f5e925SRichard Henderson                 !tcg_regset_test_reg(i_allocated_regs, reg) &&
450829f5e925SRichard Henderson                 !tcg_regset_test_reg(i_allocated_regs, reg - 1)) {
450929f5e925SRichard Henderson                 tcg_regset_set_reg(i_allocated_regs, reg - 1);
451029f5e925SRichard Henderson                 break;
451129f5e925SRichard Henderson             }
451229f5e925SRichard Henderson             reg = tcg_reg_alloc_pair(s, i_required_regs >> 1,
451329f5e925SRichard Henderson                                      i_allocated_regs, 0,
451429f5e925SRichard Henderson                                      ts->indirect_base);
451529f5e925SRichard Henderson             tcg_regset_set_reg(i_allocated_regs, reg);
451629f5e925SRichard Henderson             reg += 1;
451729f5e925SRichard Henderson             goto do_pair;
451829f5e925SRichard Henderson 
451929f5e925SRichard Henderson         do_pair:
452029f5e925SRichard Henderson             /*
452129f5e925SRichard Henderson              * If an aliased input is not dead after the instruction,
452229f5e925SRichard Henderson              * we must allocate a new register and move it.
452329f5e925SRichard Henderson              */
452429f5e925SRichard Henderson             if (arg_ct->ialias && (!IS_DEAD_ARG(i) || temp_readonly(ts))) {
452529f5e925SRichard Henderson                 TCGRegSet t_allocated_regs = i_allocated_regs;
452629f5e925SRichard Henderson 
452729f5e925SRichard Henderson                 /*
452829f5e925SRichard Henderson                  * Because of the alias, and the continued life, make sure
452929f5e925SRichard Henderson                  * that the temp is somewhere *other* than the reg pair,
453029f5e925SRichard Henderson                  * and we get a copy in reg.
453129f5e925SRichard Henderson                  */
453229f5e925SRichard Henderson                 tcg_regset_set_reg(t_allocated_regs, reg);
453329f5e925SRichard Henderson                 tcg_regset_set_reg(t_allocated_regs, reg + 1);
453429f5e925SRichard Henderson                 if (ts->val_type == TEMP_VAL_REG && ts->reg == reg) {
453529f5e925SRichard Henderson                     /* If ts was already in reg, copy it somewhere else. */
453629f5e925SRichard Henderson                     TCGReg nr;
453729f5e925SRichard Henderson                     bool ok;
453829f5e925SRichard Henderson 
453929f5e925SRichard Henderson                     tcg_debug_assert(ts->kind != TEMP_FIXED);
454029f5e925SRichard Henderson                     nr = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
454129f5e925SRichard Henderson                                        t_allocated_regs, 0, ts->indirect_base);
454229f5e925SRichard Henderson                     ok = tcg_out_mov(s, ts->type, nr, reg);
454329f5e925SRichard Henderson                     tcg_debug_assert(ok);
454429f5e925SRichard Henderson 
454529f5e925SRichard Henderson                     set_temp_val_reg(s, ts, nr);
454629f5e925SRichard Henderson                 } else {
454729f5e925SRichard Henderson                     temp_load(s, ts, tcg_target_available_regs[ts->type],
454829f5e925SRichard Henderson                               t_allocated_regs, 0);
454929f5e925SRichard Henderson                     copyto_new_reg = true;
455029f5e925SRichard Henderson                 }
455129f5e925SRichard Henderson             } else {
455229f5e925SRichard Henderson                 /* Preferably allocate to reg, otherwise copy. */
455329f5e925SRichard Henderson                 i_required_regs = (TCGRegSet)1 << reg;
455429f5e925SRichard Henderson                 temp_load(s, ts, i_required_regs, i_allocated_regs,
455529f5e925SRichard Henderson                           i_preferred_regs);
455629f5e925SRichard Henderson                 copyto_new_reg = ts->reg != reg;
455729f5e925SRichard Henderson             }
455829f5e925SRichard Henderson             break;
455929f5e925SRichard Henderson 
456029f5e925SRichard Henderson         default:
456129f5e925SRichard Henderson             g_assert_not_reached();
456229f5e925SRichard Henderson         }
456329f5e925SRichard Henderson 
456429f5e925SRichard Henderson         if (copyto_new_reg) {
456578113e83SRichard Henderson             if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
4566240c08d0SRichard Henderson                 /*
4567240c08d0SRichard Henderson                  * Cross register class move not supported.  Sync the
4568240c08d0SRichard Henderson                  * temp back to its slot and load from there.
4569240c08d0SRichard Henderson                  */
4570240c08d0SRichard Henderson                 temp_sync(s, ts, i_allocated_regs, 0, 0);
4571240c08d0SRichard Henderson                 tcg_out_ld(s, ts->type, reg,
4572240c08d0SRichard Henderson                            ts->mem_base->reg, ts->mem_offset);
457378113e83SRichard Henderson             }
4574c896fe29Sbellard         }
4575c896fe29Sbellard         new_args[i] = reg;
4576c896fe29Sbellard         const_args[i] = 0;
457782790a87SRichard Henderson         tcg_regset_set_reg(i_allocated_regs, reg);
4578c896fe29Sbellard     }
4579c896fe29Sbellard 
4580c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
4581866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
4582866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
458343439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
4584c896fe29Sbellard         }
4585c896fe29Sbellard     }
4586c896fe29Sbellard 
4587b4cb76e6SRichard Henderson     if (def->flags & TCG_OPF_COND_BRANCH) {
4588b4cb76e6SRichard Henderson         tcg_reg_alloc_cbranch(s, i_allocated_regs);
4589b4cb76e6SRichard Henderson     } else if (def->flags & TCG_OPF_BB_END) {
459082790a87SRichard Henderson         tcg_reg_alloc_bb_end(s, i_allocated_regs);
4591a52ad07eSAurelien Jarno     } else {
4592c896fe29Sbellard         if (def->flags & TCG_OPF_CALL_CLOBBER) {
4593b03cce8eSbellard             /* XXX: permit generic clobber register list ? */
4594c8074023SRichard Henderson             for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
4595c8074023SRichard Henderson                 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
459682790a87SRichard Henderson                     tcg_reg_free(s, i, i_allocated_regs);
4597c896fe29Sbellard                 }
4598c896fe29Sbellard             }
45993d5c5f87SAurelien Jarno         }
46003d5c5f87SAurelien Jarno         if (def->flags & TCG_OPF_SIDE_EFFECTS) {
46013d5c5f87SAurelien Jarno             /* sync globals if the op has side effects and might trigger
46023d5c5f87SAurelien Jarno                an exception. */
460382790a87SRichard Henderson             sync_globals(s, i_allocated_regs);
4604c896fe29Sbellard         }
4605c896fe29Sbellard 
4606c896fe29Sbellard         /* satisfy the output constraints */
4607c896fe29Sbellard         for(k = 0; k < nb_oargs; k++) {
460866792f90SRichard Henderson             i = def->args_ct[k].sort_index;
4609dd186292SRichard Henderson             arg = op->args[i];
4610c896fe29Sbellard             arg_ct = &def->args_ct[i];
461143439139SRichard Henderson             ts = arg_temp(arg);
4612d63e3b6eSRichard Henderson 
4613d63e3b6eSRichard Henderson             /* ENV should not be modified.  */
4614e01fa97dSRichard Henderson             tcg_debug_assert(!temp_readonly(ts));
4615d63e3b6eSRichard Henderson 
461629f5e925SRichard Henderson             switch (arg_ct->pair) {
461729f5e925SRichard Henderson             case 0: /* not paired */
4618bc2b17e6SRichard Henderson                 if (arg_ct->oalias && !const_args[arg_ct->alias_index]) {
46195ff9d6a4Sbellard                     reg = new_args[arg_ct->alias_index];
4620bc2b17e6SRichard Henderson                 } else if (arg_ct->newreg) {
46219be0d080SRichard Henderson                     reg = tcg_reg_alloc(s, arg_ct->regs,
462282790a87SRichard Henderson                                         i_allocated_regs | o_allocated_regs,
462331fd884bSRichard Henderson                                         output_pref(op, k), ts->indirect_base);
4624c896fe29Sbellard                 } else {
46259be0d080SRichard Henderson                     reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs,
462631fd884bSRichard Henderson                                         output_pref(op, k), ts->indirect_base);
4627c896fe29Sbellard                 }
462829f5e925SRichard Henderson                 break;
462929f5e925SRichard Henderson 
463029f5e925SRichard Henderson             case 1: /* first of pair */
463129f5e925SRichard Henderson                 tcg_debug_assert(!arg_ct->newreg);
463229f5e925SRichard Henderson                 if (arg_ct->oalias) {
463329f5e925SRichard Henderson                     reg = new_args[arg_ct->alias_index];
463429f5e925SRichard Henderson                     break;
463529f5e925SRichard Henderson                 }
463629f5e925SRichard Henderson                 reg = tcg_reg_alloc_pair(s, arg_ct->regs, o_allocated_regs,
463731fd884bSRichard Henderson                                          output_pref(op, k), ts->indirect_base);
463829f5e925SRichard Henderson                 break;
463929f5e925SRichard Henderson 
464029f5e925SRichard Henderson             case 2: /* second of pair */
464129f5e925SRichard Henderson                 tcg_debug_assert(!arg_ct->newreg);
464229f5e925SRichard Henderson                 if (arg_ct->oalias) {
464329f5e925SRichard Henderson                     reg = new_args[arg_ct->alias_index];
464429f5e925SRichard Henderson                 } else {
464529f5e925SRichard Henderson                     reg = new_args[arg_ct->pair_index] + 1;
464629f5e925SRichard Henderson                 }
464729f5e925SRichard Henderson                 break;
464829f5e925SRichard Henderson 
464929f5e925SRichard Henderson             case 3: /* first of pair, aliasing with a second input */
465029f5e925SRichard Henderson                 tcg_debug_assert(!arg_ct->newreg);
465129f5e925SRichard Henderson                 reg = new_args[arg_ct->pair_index] - 1;
465229f5e925SRichard Henderson                 break;
465329f5e925SRichard Henderson 
465429f5e925SRichard Henderson             default:
465529f5e925SRichard Henderson                 g_assert_not_reached();
465629f5e925SRichard Henderson             }
465782790a87SRichard Henderson             tcg_regset_set_reg(o_allocated_regs, reg);
4658098859f1SRichard Henderson             set_temp_val_reg(s, ts, reg);
4659c896fe29Sbellard             ts->mem_coherent = 0;
4660c896fe29Sbellard             new_args[i] = reg;
4661c896fe29Sbellard         }
4662e8996ee0Sbellard     }
4663c896fe29Sbellard 
4664c896fe29Sbellard     /* emit instruction */
4665678155b2SRichard Henderson     switch (op->opc) {
4666678155b2SRichard Henderson     case INDEX_op_ext8s_i32:
4667678155b2SRichard Henderson         tcg_out_ext8s(s, TCG_TYPE_I32, new_args[0], new_args[1]);
4668678155b2SRichard Henderson         break;
4669678155b2SRichard Henderson     case INDEX_op_ext8s_i64:
4670678155b2SRichard Henderson         tcg_out_ext8s(s, TCG_TYPE_I64, new_args[0], new_args[1]);
4671678155b2SRichard Henderson         break;
4672d0e66c89SRichard Henderson     case INDEX_op_ext8u_i32:
4673d0e66c89SRichard Henderson     case INDEX_op_ext8u_i64:
4674d0e66c89SRichard Henderson         tcg_out_ext8u(s, new_args[0], new_args[1]);
4675d0e66c89SRichard Henderson         break;
4676753e42eaSRichard Henderson     case INDEX_op_ext16s_i32:
4677753e42eaSRichard Henderson         tcg_out_ext16s(s, TCG_TYPE_I32, new_args[0], new_args[1]);
4678753e42eaSRichard Henderson         break;
4679753e42eaSRichard Henderson     case INDEX_op_ext16s_i64:
4680753e42eaSRichard Henderson         tcg_out_ext16s(s, TCG_TYPE_I64, new_args[0], new_args[1]);
4681753e42eaSRichard Henderson         break;
4682379afdffSRichard Henderson     case INDEX_op_ext16u_i32:
4683379afdffSRichard Henderson     case INDEX_op_ext16u_i64:
4684379afdffSRichard Henderson         tcg_out_ext16u(s, new_args[0], new_args[1]);
4685379afdffSRichard Henderson         break;
468652bf3398SRichard Henderson     case INDEX_op_ext32s_i64:
468752bf3398SRichard Henderson         tcg_out_ext32s(s, new_args[0], new_args[1]);
468852bf3398SRichard Henderson         break;
46899ecf5f61SRichard Henderson     case INDEX_op_ext32u_i64:
46909ecf5f61SRichard Henderson         tcg_out_ext32u(s, new_args[0], new_args[1]);
46919ecf5f61SRichard Henderson         break;
46929c6aa274SRichard Henderson     case INDEX_op_ext_i32_i64:
46939c6aa274SRichard Henderson         tcg_out_exts_i32_i64(s, new_args[0], new_args[1]);
46949c6aa274SRichard Henderson         break;
4695b9bfe000SRichard Henderson     case INDEX_op_extu_i32_i64:
4696b9bfe000SRichard Henderson         tcg_out_extu_i32_i64(s, new_args[0], new_args[1]);
4697b9bfe000SRichard Henderson         break;
4698b8b94ac6SRichard Henderson     case INDEX_op_extrl_i64_i32:
4699b8b94ac6SRichard Henderson         tcg_out_extrl_i64_i32(s, new_args[0], new_args[1]);
4700b8b94ac6SRichard Henderson         break;
4701678155b2SRichard Henderson     default:
4702d2fd745fSRichard Henderson         if (def->flags & TCG_OPF_VECTOR) {
4703d2fd745fSRichard Henderson             tcg_out_vec_op(s, op->opc, TCGOP_VECL(op), TCGOP_VECE(op),
4704d2fd745fSRichard Henderson                            new_args, const_args);
4705d2fd745fSRichard Henderson         } else {
4706dd186292SRichard Henderson             tcg_out_op(s, op->opc, new_args, const_args);
4707d2fd745fSRichard Henderson         }
4708678155b2SRichard Henderson         break;
4709678155b2SRichard Henderson     }
4710c896fe29Sbellard 
4711c896fe29Sbellard     /* move the outputs in the correct register if needed */
4712c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
471343439139SRichard Henderson         ts = arg_temp(op->args[i]);
4714d63e3b6eSRichard Henderson 
4715d63e3b6eSRichard Henderson         /* ENV should not be modified.  */
4716e01fa97dSRichard Henderson         tcg_debug_assert(!temp_readonly(ts));
4717d63e3b6eSRichard Henderson 
4718ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
471998b4e186SRichard Henderson             temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i));
472059d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
4721f8bf00f1SRichard Henderson             temp_dead(s, ts);
4722ec7a869dSAurelien Jarno         }
4723c896fe29Sbellard     }
4724c896fe29Sbellard }
4725c896fe29Sbellard 
4726efe86b21SRichard Henderson static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op)
4727efe86b21SRichard Henderson {
4728efe86b21SRichard Henderson     const TCGLifeData arg_life = op->life;
4729efe86b21SRichard Henderson     TCGTemp *ots, *itsl, *itsh;
4730efe86b21SRichard Henderson     TCGType vtype = TCGOP_VECL(op) + TCG_TYPE_V64;
4731efe86b21SRichard Henderson 
4732efe86b21SRichard Henderson     /* This opcode is only valid for 32-bit hosts, for 64-bit elements. */
4733efe86b21SRichard Henderson     tcg_debug_assert(TCG_TARGET_REG_BITS == 32);
4734efe86b21SRichard Henderson     tcg_debug_assert(TCGOP_VECE(op) == MO_64);
4735efe86b21SRichard Henderson 
4736efe86b21SRichard Henderson     ots = arg_temp(op->args[0]);
4737efe86b21SRichard Henderson     itsl = arg_temp(op->args[1]);
4738efe86b21SRichard Henderson     itsh = arg_temp(op->args[2]);
4739efe86b21SRichard Henderson 
4740efe86b21SRichard Henderson     /* ENV should not be modified.  */
4741efe86b21SRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
4742efe86b21SRichard Henderson 
4743efe86b21SRichard Henderson     /* Allocate the output register now.  */
4744efe86b21SRichard Henderson     if (ots->val_type != TEMP_VAL_REG) {
4745efe86b21SRichard Henderson         TCGRegSet allocated_regs = s->reserved_regs;
4746efe86b21SRichard Henderson         TCGRegSet dup_out_regs =
4747efe86b21SRichard Henderson             tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs;
4748098859f1SRichard Henderson         TCGReg oreg;
4749efe86b21SRichard Henderson 
4750efe86b21SRichard Henderson         /* Make sure to not spill the input registers. */
4751efe86b21SRichard Henderson         if (!IS_DEAD_ARG(1) && itsl->val_type == TEMP_VAL_REG) {
4752efe86b21SRichard Henderson             tcg_regset_set_reg(allocated_regs, itsl->reg);
4753efe86b21SRichard Henderson         }
4754efe86b21SRichard Henderson         if (!IS_DEAD_ARG(2) && itsh->val_type == TEMP_VAL_REG) {
4755efe86b21SRichard Henderson             tcg_regset_set_reg(allocated_regs, itsh->reg);
4756efe86b21SRichard Henderson         }
4757efe86b21SRichard Henderson 
4758098859f1SRichard Henderson         oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
475931fd884bSRichard Henderson                              output_pref(op, 0), ots->indirect_base);
4760098859f1SRichard Henderson         set_temp_val_reg(s, ots, oreg);
4761efe86b21SRichard Henderson     }
4762efe86b21SRichard Henderson 
4763efe86b21SRichard Henderson     /* Promote dup2 of immediates to dupi_vec. */
4764efe86b21SRichard Henderson     if (itsl->val_type == TEMP_VAL_CONST && itsh->val_type == TEMP_VAL_CONST) {
4765efe86b21SRichard Henderson         uint64_t val = deposit64(itsl->val, 32, 32, itsh->val);
4766efe86b21SRichard Henderson         MemOp vece = MO_64;
4767efe86b21SRichard Henderson 
4768efe86b21SRichard Henderson         if (val == dup_const(MO_8, val)) {
4769efe86b21SRichard Henderson             vece = MO_8;
4770efe86b21SRichard Henderson         } else if (val == dup_const(MO_16, val)) {
4771efe86b21SRichard Henderson             vece = MO_16;
4772efe86b21SRichard Henderson         } else if (val == dup_const(MO_32, val)) {
4773efe86b21SRichard Henderson             vece = MO_32;
4774efe86b21SRichard Henderson         }
4775efe86b21SRichard Henderson 
4776efe86b21SRichard Henderson         tcg_out_dupi_vec(s, vtype, vece, ots->reg, val);
4777efe86b21SRichard Henderson         goto done;
4778efe86b21SRichard Henderson     }
4779efe86b21SRichard Henderson 
4780efe86b21SRichard Henderson     /* If the two inputs form one 64-bit value, try dupm_vec. */
4781aef85402SRichard Henderson     if (itsl->temp_subindex == HOST_BIG_ENDIAN &&
4782aef85402SRichard Henderson         itsh->temp_subindex == !HOST_BIG_ENDIAN &&
4783aef85402SRichard Henderson         itsl == itsh + (HOST_BIG_ENDIAN ? 1 : -1)) {
4784aef85402SRichard Henderson         TCGTemp *its = itsl - HOST_BIG_ENDIAN;
4785aef85402SRichard Henderson 
4786aef85402SRichard Henderson         temp_sync(s, its + 0, s->reserved_regs, 0, 0);
4787aef85402SRichard Henderson         temp_sync(s, its + 1, s->reserved_regs, 0, 0);
4788aef85402SRichard Henderson 
4789efe86b21SRichard Henderson         if (tcg_out_dupm_vec(s, vtype, MO_64, ots->reg,
4790efe86b21SRichard Henderson                              its->mem_base->reg, its->mem_offset)) {
4791efe86b21SRichard Henderson             goto done;
4792efe86b21SRichard Henderson         }
4793efe86b21SRichard Henderson     }
4794efe86b21SRichard Henderson 
4795efe86b21SRichard Henderson     /* Fall back to generic expansion. */
4796efe86b21SRichard Henderson     return false;
4797efe86b21SRichard Henderson 
4798efe86b21SRichard Henderson  done:
479936f5539cSRichard Henderson     ots->mem_coherent = 0;
4800efe86b21SRichard Henderson     if (IS_DEAD_ARG(1)) {
4801efe86b21SRichard Henderson         temp_dead(s, itsl);
4802efe86b21SRichard Henderson     }
4803efe86b21SRichard Henderson     if (IS_DEAD_ARG(2)) {
4804efe86b21SRichard Henderson         temp_dead(s, itsh);
4805efe86b21SRichard Henderson     }
4806efe86b21SRichard Henderson     if (NEED_SYNC_ARG(0)) {
4807efe86b21SRichard Henderson         temp_sync(s, ots, s->reserved_regs, 0, IS_DEAD_ARG(0));
4808efe86b21SRichard Henderson     } else if (IS_DEAD_ARG(0)) {
4809efe86b21SRichard Henderson         temp_dead(s, ots);
4810efe86b21SRichard Henderson     }
4811efe86b21SRichard Henderson     return true;
4812efe86b21SRichard Henderson }
4813efe86b21SRichard Henderson 
481439004a71SRichard Henderson static void load_arg_reg(TCGContext *s, TCGReg reg, TCGTemp *ts,
481539004a71SRichard Henderson                          TCGRegSet allocated_regs)
4816c896fe29Sbellard {
4817c896fe29Sbellard     if (ts->val_type == TEMP_VAL_REG) {
4818c896fe29Sbellard         if (ts->reg != reg) {
48194250da10SRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
482078113e83SRichard Henderson             if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
4821240c08d0SRichard Henderson                 /*
4822240c08d0SRichard Henderson                  * Cross register class move not supported.  Sync the
4823240c08d0SRichard Henderson                  * temp back to its slot and load from there.
4824240c08d0SRichard Henderson                  */
4825240c08d0SRichard Henderson                 temp_sync(s, ts, allocated_regs, 0, 0);
4826240c08d0SRichard Henderson                 tcg_out_ld(s, ts->type, reg,
4827240c08d0SRichard Henderson                            ts->mem_base->reg, ts->mem_offset);
482878113e83SRichard Henderson             }
4829c896fe29Sbellard         }
4830c896fe29Sbellard     } else {
4831ccb1bb66SRichard Henderson         TCGRegSet arg_set = 0;
483240ae5c62SRichard Henderson 
48334250da10SRichard Henderson         tcg_reg_free(s, reg, allocated_regs);
483440ae5c62SRichard Henderson         tcg_regset_set_reg(arg_set, reg);
4835b722452aSRichard Henderson         temp_load(s, ts, arg_set, allocated_regs, 0);
4836c896fe29Sbellard     }
483739004a71SRichard Henderson }
483840ae5c62SRichard Henderson 
4839*d78e4a4fSRichard Henderson static void load_arg_stk(TCGContext *s, unsigned arg_slot, TCGTemp *ts,
484039004a71SRichard Henderson                          TCGRegSet allocated_regs)
484139004a71SRichard Henderson {
484239004a71SRichard Henderson     /*
484339004a71SRichard Henderson      * When the destination is on the stack, load up the temp and store.
484439004a71SRichard Henderson      * If there are many call-saved registers, the temp might live to
484539004a71SRichard Henderson      * see another use; otherwise it'll be discarded.
484639004a71SRichard Henderson      */
484739004a71SRichard Henderson     temp_load(s, ts, tcg_target_available_regs[ts->type], allocated_regs, 0);
484839004a71SRichard Henderson     tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK,
4849*d78e4a4fSRichard Henderson                arg_slot_stk_ofs(arg_slot));
485039004a71SRichard Henderson }
485139004a71SRichard Henderson 
485239004a71SRichard Henderson static void load_arg_normal(TCGContext *s, const TCGCallArgumentLoc *l,
485339004a71SRichard Henderson                             TCGTemp *ts, TCGRegSet *allocated_regs)
485439004a71SRichard Henderson {
4855338b61e9SRichard Henderson     if (arg_slot_reg_p(l->arg_slot)) {
485639004a71SRichard Henderson         TCGReg reg = tcg_target_call_iarg_regs[l->arg_slot];
485739004a71SRichard Henderson         load_arg_reg(s, reg, ts, *allocated_regs);
485839004a71SRichard Henderson         tcg_regset_set_reg(*allocated_regs, reg);
485939004a71SRichard Henderson     } else {
4860*d78e4a4fSRichard Henderson         load_arg_stk(s, l->arg_slot, ts, *allocated_regs);
4861c896fe29Sbellard     }
486239cf05d3Sbellard }
4863c896fe29Sbellard 
4864*d78e4a4fSRichard Henderson static void load_arg_ref(TCGContext *s, unsigned arg_slot, TCGReg ref_base,
4865313bdea8SRichard Henderson                          intptr_t ref_off, TCGRegSet *allocated_regs)
4866313bdea8SRichard Henderson {
4867313bdea8SRichard Henderson     TCGReg reg;
4868313bdea8SRichard Henderson 
4869*d78e4a4fSRichard Henderson     if (arg_slot_reg_p(arg_slot)) {
4870313bdea8SRichard Henderson         reg = tcg_target_call_iarg_regs[arg_slot];
4871313bdea8SRichard Henderson         tcg_reg_free(s, reg, *allocated_regs);
4872313bdea8SRichard Henderson         tcg_out_addi_ptr(s, reg, ref_base, ref_off);
4873313bdea8SRichard Henderson         tcg_regset_set_reg(*allocated_regs, reg);
4874313bdea8SRichard Henderson     } else {
4875313bdea8SRichard Henderson         reg = tcg_reg_alloc(s, tcg_target_available_regs[TCG_TYPE_PTR],
4876313bdea8SRichard Henderson                             *allocated_regs, 0, false);
4877313bdea8SRichard Henderson         tcg_out_addi_ptr(s, reg, ref_base, ref_off);
4878313bdea8SRichard Henderson         tcg_out_st(s, TCG_TYPE_PTR, reg, TCG_REG_CALL_STACK,
4879*d78e4a4fSRichard Henderson                    arg_slot_stk_ofs(arg_slot));
4880313bdea8SRichard Henderson     }
4881313bdea8SRichard Henderson }
4882313bdea8SRichard Henderson 
488339004a71SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op)
488439004a71SRichard Henderson {
488539004a71SRichard Henderson     const int nb_oargs = TCGOP_CALLO(op);
488639004a71SRichard Henderson     const int nb_iargs = TCGOP_CALLI(op);
488739004a71SRichard Henderson     const TCGLifeData arg_life = op->life;
488839004a71SRichard Henderson     const TCGHelperInfo *info = tcg_call_info(op);
488939004a71SRichard Henderson     TCGRegSet allocated_regs = s->reserved_regs;
489039004a71SRichard Henderson     int i;
489139004a71SRichard Henderson 
489239004a71SRichard Henderson     /*
489339004a71SRichard Henderson      * Move inputs into place in reverse order,
489439004a71SRichard Henderson      * so that we place stacked arguments first.
489539004a71SRichard Henderson      */
489639004a71SRichard Henderson     for (i = nb_iargs - 1; i >= 0; --i) {
489739004a71SRichard Henderson         const TCGCallArgumentLoc *loc = &info->in[i];
489839004a71SRichard Henderson         TCGTemp *ts = arg_temp(op->args[nb_oargs + i]);
489939004a71SRichard Henderson 
490039004a71SRichard Henderson         switch (loc->kind) {
490139004a71SRichard Henderson         case TCG_CALL_ARG_NORMAL:
490239004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_U:
490339004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_S:
490439004a71SRichard Henderson             load_arg_normal(s, loc, ts, &allocated_regs);
490539004a71SRichard Henderson             break;
4906313bdea8SRichard Henderson         case TCG_CALL_ARG_BY_REF:
4907313bdea8SRichard Henderson             load_arg_stk(s, loc->ref_slot, ts, allocated_regs);
4908313bdea8SRichard Henderson             load_arg_ref(s, loc->arg_slot, TCG_REG_CALL_STACK,
4909*d78e4a4fSRichard Henderson                          arg_slot_stk_ofs(loc->ref_slot),
4910313bdea8SRichard Henderson                          &allocated_regs);
4911313bdea8SRichard Henderson             break;
4912313bdea8SRichard Henderson         case TCG_CALL_ARG_BY_REF_N:
4913313bdea8SRichard Henderson             load_arg_stk(s, loc->ref_slot, ts, allocated_regs);
4914313bdea8SRichard Henderson             break;
491539004a71SRichard Henderson         default:
491639004a71SRichard Henderson             g_assert_not_reached();
491739004a71SRichard Henderson         }
491839004a71SRichard Henderson     }
491939004a71SRichard Henderson 
492039004a71SRichard Henderson     /* Mark dead temporaries and free the associated registers.  */
4921866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
4922866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
492343439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
4924c896fe29Sbellard         }
4925c896fe29Sbellard     }
4926c896fe29Sbellard 
492739004a71SRichard Henderson     /* Clobber call registers.  */
4928c8074023SRichard Henderson     for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
4929c8074023SRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
4930b3915dbbSRichard Henderson             tcg_reg_free(s, i, allocated_regs);
4931c896fe29Sbellard         }
4932c896fe29Sbellard     }
4933c896fe29Sbellard 
493439004a71SRichard Henderson     /*
493539004a71SRichard Henderson      * Save globals if they might be written by the helper,
493639004a71SRichard Henderson      * sync them if they might be read.
493739004a71SRichard Henderson      */
493839004a71SRichard Henderson     if (info->flags & TCG_CALL_NO_READ_GLOBALS) {
493978505279SAurelien Jarno         /* Nothing to do */
494039004a71SRichard Henderson     } else if (info->flags & TCG_CALL_NO_WRITE_GLOBALS) {
494178505279SAurelien Jarno         sync_globals(s, allocated_regs);
494278505279SAurelien Jarno     } else {
4943e8996ee0Sbellard         save_globals(s, allocated_regs);
4944b9c18f56Saurel32     }
4945c896fe29Sbellard 
4946313bdea8SRichard Henderson     /*
4947313bdea8SRichard Henderson      * If the ABI passes a pointer to the returned struct as the first
4948313bdea8SRichard Henderson      * argument, load that now.  Pass a pointer to the output home slot.
4949313bdea8SRichard Henderson      */
4950313bdea8SRichard Henderson     if (info->out_kind == TCG_CALL_RET_BY_REF) {
4951313bdea8SRichard Henderson         TCGTemp *ts = arg_temp(op->args[0]);
4952313bdea8SRichard Henderson 
4953313bdea8SRichard Henderson         if (!ts->mem_allocated) {
4954313bdea8SRichard Henderson             temp_allocate_frame(s, ts);
4955313bdea8SRichard Henderson         }
4956313bdea8SRichard Henderson         load_arg_ref(s, 0, ts->mem_base->reg, ts->mem_offset, &allocated_regs);
4957313bdea8SRichard Henderson     }
4958313bdea8SRichard Henderson 
4959cee44b03SRichard Henderson     tcg_out_call(s, tcg_call_func(op), info);
4960c896fe29Sbellard 
496139004a71SRichard Henderson     /* Assign output registers and emit moves if needed.  */
496239004a71SRichard Henderson     switch (info->out_kind) {
496339004a71SRichard Henderson     case TCG_CALL_RET_NORMAL:
4964c896fe29Sbellard         for (i = 0; i < nb_oargs; i++) {
496539004a71SRichard Henderson             TCGTemp *ts = arg_temp(op->args[i]);
49665e3d0c19SRichard Henderson             TCGReg reg = tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, i);
4967d63e3b6eSRichard Henderson 
4968d63e3b6eSRichard Henderson             /* ENV should not be modified.  */
4969e01fa97dSRichard Henderson             tcg_debug_assert(!temp_readonly(ts));
4970d63e3b6eSRichard Henderson 
4971098859f1SRichard Henderson             set_temp_val_reg(s, ts, reg);
4972c896fe29Sbellard             ts->mem_coherent = 0;
497339004a71SRichard Henderson         }
497439004a71SRichard Henderson         break;
4975313bdea8SRichard Henderson 
4976c6556aa0SRichard Henderson     case TCG_CALL_RET_BY_VEC:
4977c6556aa0SRichard Henderson         {
4978c6556aa0SRichard Henderson             TCGTemp *ts = arg_temp(op->args[0]);
4979c6556aa0SRichard Henderson 
4980c6556aa0SRichard Henderson             tcg_debug_assert(ts->base_type == TCG_TYPE_I128);
4981c6556aa0SRichard Henderson             tcg_debug_assert(ts->temp_subindex == 0);
4982c6556aa0SRichard Henderson             if (!ts->mem_allocated) {
4983c6556aa0SRichard Henderson                 temp_allocate_frame(s, ts);
4984c6556aa0SRichard Henderson             }
4985c6556aa0SRichard Henderson             tcg_out_st(s, TCG_TYPE_V128,
4986c6556aa0SRichard Henderson                        tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0),
4987c6556aa0SRichard Henderson                        ts->mem_base->reg, ts->mem_offset);
4988c6556aa0SRichard Henderson         }
4989c6556aa0SRichard Henderson         /* fall through to mark all parts in memory */
4990c6556aa0SRichard Henderson 
4991313bdea8SRichard Henderson     case TCG_CALL_RET_BY_REF:
4992313bdea8SRichard Henderson         /* The callee has performed a write through the reference. */
4993313bdea8SRichard Henderson         for (i = 0; i < nb_oargs; i++) {
4994313bdea8SRichard Henderson             TCGTemp *ts = arg_temp(op->args[i]);
4995313bdea8SRichard Henderson             ts->val_type = TEMP_VAL_MEM;
4996313bdea8SRichard Henderson         }
4997313bdea8SRichard Henderson         break;
4998313bdea8SRichard Henderson 
499939004a71SRichard Henderson     default:
500039004a71SRichard Henderson         g_assert_not_reached();
500139004a71SRichard Henderson     }
500239004a71SRichard Henderson 
500339004a71SRichard Henderson     /* Flush or discard output registers as needed. */
500439004a71SRichard Henderson     for (i = 0; i < nb_oargs; i++) {
500539004a71SRichard Henderson         TCGTemp *ts = arg_temp(op->args[i]);
5006ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
500739004a71SRichard Henderson             temp_sync(s, ts, s->reserved_regs, 0, IS_DEAD_ARG(i));
500859d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
5009f8bf00f1SRichard Henderson             temp_dead(s, ts);
5010c896fe29Sbellard         }
5011c896fe29Sbellard     }
50128c11ad25SAurelien Jarno }
5013c896fe29Sbellard 
5014c896fe29Sbellard #ifdef CONFIG_PROFILER
5015c896fe29Sbellard 
5016c3fac113SEmilio G. Cota /* avoid copy/paste errors */
5017c3fac113SEmilio G. Cota #define PROF_ADD(to, from, field)                       \
5018c3fac113SEmilio G. Cota     do {                                                \
5019d73415a3SStefan Hajnoczi         (to)->field += qatomic_read(&((from)->field));  \
5020c3fac113SEmilio G. Cota     } while (0)
5021c896fe29Sbellard 
5022c3fac113SEmilio G. Cota #define PROF_MAX(to, from, field)                                       \
5023c3fac113SEmilio G. Cota     do {                                                                \
5024d73415a3SStefan Hajnoczi         typeof((from)->field) val__ = qatomic_read(&((from)->field));   \
5025c3fac113SEmilio G. Cota         if (val__ > (to)->field) {                                      \
5026c3fac113SEmilio G. Cota             (to)->field = val__;                                        \
5027c3fac113SEmilio G. Cota         }                                                               \
5028c3fac113SEmilio G. Cota     } while (0)
5029c3fac113SEmilio G. Cota 
5030c3fac113SEmilio G. Cota /* Pass in a zero'ed @prof */
5031c3fac113SEmilio G. Cota static inline
5032c3fac113SEmilio G. Cota void tcg_profile_snapshot(TCGProfile *prof, bool counters, bool table)
5033c896fe29Sbellard {
50340e2d61cfSRichard Henderson     unsigned int n_ctxs = qatomic_read(&tcg_cur_ctxs);
5035c3fac113SEmilio G. Cota     unsigned int i;
5036c3fac113SEmilio G. Cota 
50373468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
5038d73415a3SStefan Hajnoczi         TCGContext *s = qatomic_read(&tcg_ctxs[i]);
50393468b59eSEmilio G. Cota         const TCGProfile *orig = &s->prof;
5040c3fac113SEmilio G. Cota 
5041c3fac113SEmilio G. Cota         if (counters) {
504272fd2efbSEmilio G. Cota             PROF_ADD(prof, orig, cpu_exec_time);
5043c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count1);
5044c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count);
5045c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, op_count);
5046c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, op_count_max);
5047c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, temp_count);
5048c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, temp_count_max);
5049c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, del_op_count);
5050c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_in_len);
5051c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_out_len);
5052c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, search_out_len);
5053c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, interm_time);
5054c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_time);
5055c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, la_time);
5056c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, opt_time);
5057c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_count);
5058c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_time);
5059c3fac113SEmilio G. Cota         }
5060c3fac113SEmilio G. Cota         if (table) {
5061c896fe29Sbellard             int i;
5062d70724ceSzhanghailiang 
506315fc7daaSRichard Henderson             for (i = 0; i < NB_OPS; i++) {
5064c3fac113SEmilio G. Cota                 PROF_ADD(prof, orig, table_op_count[i]);
5065c3fac113SEmilio G. Cota             }
5066c3fac113SEmilio G. Cota         }
5067c3fac113SEmilio G. Cota     }
5068c3fac113SEmilio G. Cota }
5069c3fac113SEmilio G. Cota 
5070c3fac113SEmilio G. Cota #undef PROF_ADD
5071c3fac113SEmilio G. Cota #undef PROF_MAX
5072c3fac113SEmilio G. Cota 
5073c3fac113SEmilio G. Cota static void tcg_profile_snapshot_counters(TCGProfile *prof)
5074c3fac113SEmilio G. Cota {
5075c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, true, false);
5076c3fac113SEmilio G. Cota }
5077c3fac113SEmilio G. Cota 
5078c3fac113SEmilio G. Cota static void tcg_profile_snapshot_table(TCGProfile *prof)
5079c3fac113SEmilio G. Cota {
5080c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, false, true);
5081c3fac113SEmilio G. Cota }
5082c3fac113SEmilio G. Cota 
5083b6a7f3e0SDaniel P. Berrangé void tcg_dump_op_count(GString *buf)
5084c3fac113SEmilio G. Cota {
5085c3fac113SEmilio G. Cota     TCGProfile prof = {};
5086c3fac113SEmilio G. Cota     int i;
5087c3fac113SEmilio G. Cota 
5088c3fac113SEmilio G. Cota     tcg_profile_snapshot_table(&prof);
5089c3fac113SEmilio G. Cota     for (i = 0; i < NB_OPS; i++) {
5090b6a7f3e0SDaniel P. Berrangé         g_string_append_printf(buf, "%s %" PRId64 "\n", tcg_op_defs[i].name,
5091c3fac113SEmilio G. Cota                                prof.table_op_count[i]);
5092c896fe29Sbellard     }
5093c896fe29Sbellard }
509472fd2efbSEmilio G. Cota 
509572fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void)
509672fd2efbSEmilio G. Cota {
50970e2d61cfSRichard Henderson     unsigned int n_ctxs = qatomic_read(&tcg_cur_ctxs);
509872fd2efbSEmilio G. Cota     unsigned int i;
509972fd2efbSEmilio G. Cota     int64_t ret = 0;
510072fd2efbSEmilio G. Cota 
510172fd2efbSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
5102d73415a3SStefan Hajnoczi         const TCGContext *s = qatomic_read(&tcg_ctxs[i]);
510372fd2efbSEmilio G. Cota         const TCGProfile *prof = &s->prof;
510472fd2efbSEmilio G. Cota 
5105d73415a3SStefan Hajnoczi         ret += qatomic_read(&prof->cpu_exec_time);
510672fd2efbSEmilio G. Cota     }
510772fd2efbSEmilio G. Cota     return ret;
510872fd2efbSEmilio G. Cota }
5109246ae24dSMax Filippov #else
5110b6a7f3e0SDaniel P. Berrangé void tcg_dump_op_count(GString *buf)
5111246ae24dSMax Filippov {
5112b6a7f3e0SDaniel P. Berrangé     g_string_append_printf(buf, "[TCG profiler not compiled]\n");
5113246ae24dSMax Filippov }
511472fd2efbSEmilio G. Cota 
511572fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void)
511672fd2efbSEmilio G. Cota {
511772fd2efbSEmilio G. Cota     error_report("%s: TCG profiler not compiled", __func__);
511872fd2efbSEmilio G. Cota     exit(EXIT_FAILURE);
511972fd2efbSEmilio G. Cota }
5120c896fe29Sbellard #endif
5121c896fe29Sbellard 
5122c896fe29Sbellard 
5123fbf59aadSRichard Henderson int tcg_gen_code(TCGContext *s, TranslationBlock *tb, target_ulong pc_start)
5124c896fe29Sbellard {
5125c3fac113SEmilio G. Cota #ifdef CONFIG_PROFILER
5126c3fac113SEmilio G. Cota     TCGProfile *prof = &s->prof;
5127c3fac113SEmilio G. Cota #endif
512815fa08f8SRichard Henderson     int i, num_insns;
512915fa08f8SRichard Henderson     TCGOp *op;
5130c896fe29Sbellard 
513104fe6400SRichard Henderson #ifdef CONFIG_PROFILER
513204fe6400SRichard Henderson     {
5133c1f543b7SEmilio G. Cota         int n = 0;
513404fe6400SRichard Henderson 
513515fa08f8SRichard Henderson         QTAILQ_FOREACH(op, &s->ops, link) {
513615fa08f8SRichard Henderson             n++;
513715fa08f8SRichard Henderson         }
5138d73415a3SStefan Hajnoczi         qatomic_set(&prof->op_count, prof->op_count + n);
5139c3fac113SEmilio G. Cota         if (n > prof->op_count_max) {
5140d73415a3SStefan Hajnoczi             qatomic_set(&prof->op_count_max, n);
514104fe6400SRichard Henderson         }
514204fe6400SRichard Henderson 
514304fe6400SRichard Henderson         n = s->nb_temps;
5144d73415a3SStefan Hajnoczi         qatomic_set(&prof->temp_count, prof->temp_count + n);
5145c3fac113SEmilio G. Cota         if (n > prof->temp_count_max) {
5146d73415a3SStefan Hajnoczi             qatomic_set(&prof->temp_count_max, n);
514704fe6400SRichard Henderson         }
514804fe6400SRichard Henderson     }
514904fe6400SRichard Henderson #endif
515004fe6400SRichard Henderson 
5151c896fe29Sbellard #ifdef DEBUG_DISAS
5152d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)
5153fbf59aadSRichard Henderson                  && qemu_log_in_addr_range(pc_start))) {
5154c60f599bSRichard Henderson         FILE *logfile = qemu_log_trylock();
515578b54858SRichard Henderson         if (logfile) {
515678b54858SRichard Henderson             fprintf(logfile, "OP:\n");
5157b7a83ff8SRichard Henderson             tcg_dump_ops(s, logfile, false);
515878b54858SRichard Henderson             fprintf(logfile, "\n");
5159fc59d2d8SRobert Foley             qemu_log_unlock(logfile);
5160c896fe29Sbellard         }
516178b54858SRichard Henderson     }
5162c896fe29Sbellard #endif
5163c896fe29Sbellard 
5164bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG
5165bef16ab4SRichard Henderson     /* Ensure all labels referenced have been emitted.  */
5166bef16ab4SRichard Henderson     {
5167bef16ab4SRichard Henderson         TCGLabel *l;
5168bef16ab4SRichard Henderson         bool error = false;
5169bef16ab4SRichard Henderson 
5170bef16ab4SRichard Henderson         QSIMPLEQ_FOREACH(l, &s->labels, next) {
5171f85b1fc4SRichard Henderson             if (unlikely(!l->present) && !QSIMPLEQ_EMPTY(&l->branches)) {
5172bef16ab4SRichard Henderson                 qemu_log_mask(CPU_LOG_TB_OP,
5173bef16ab4SRichard Henderson                               "$L%d referenced but not present.\n", l->id);
5174bef16ab4SRichard Henderson                 error = true;
5175bef16ab4SRichard Henderson             }
5176bef16ab4SRichard Henderson         }
5177bef16ab4SRichard Henderson         assert(!error);
5178bef16ab4SRichard Henderson     }
5179bef16ab4SRichard Henderson #endif
5180bef16ab4SRichard Henderson 
5181c5cc28ffSAurelien Jarno #ifdef CONFIG_PROFILER
5182d73415a3SStefan Hajnoczi     qatomic_set(&prof->opt_time, prof->opt_time - profile_getclock());
5183c5cc28ffSAurelien Jarno #endif
5184c5cc28ffSAurelien Jarno 
51858f2e8c07SKirill Batuzov #ifdef USE_TCG_OPTIMIZATIONS
5186c45cb8bbSRichard Henderson     tcg_optimize(s);
51878f2e8c07SKirill Batuzov #endif
51888f2e8c07SKirill Batuzov 
5189a23a9ec6Sbellard #ifdef CONFIG_PROFILER
5190d73415a3SStefan Hajnoczi     qatomic_set(&prof->opt_time, prof->opt_time + profile_getclock());
5191d73415a3SStefan Hajnoczi     qatomic_set(&prof->la_time, prof->la_time - profile_getclock());
5192a23a9ec6Sbellard #endif
5193c5cc28ffSAurelien Jarno 
5194b4fc67c7SRichard Henderson     reachable_code_pass(s);
5195874b8574SRichard Henderson     liveness_pass_0(s);
5196b83eabeaSRichard Henderson     liveness_pass_1(s);
51975a18407fSRichard Henderson 
51985a18407fSRichard Henderson     if (s->nb_indirects > 0) {
51995a18407fSRichard Henderson #ifdef DEBUG_DISAS
52005a18407fSRichard Henderson         if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND)
5201fbf59aadSRichard Henderson                      && qemu_log_in_addr_range(pc_start))) {
5202c60f599bSRichard Henderson             FILE *logfile = qemu_log_trylock();
520378b54858SRichard Henderson             if (logfile) {
520478b54858SRichard Henderson                 fprintf(logfile, "OP before indirect lowering:\n");
5205b7a83ff8SRichard Henderson                 tcg_dump_ops(s, logfile, false);
520678b54858SRichard Henderson                 fprintf(logfile, "\n");
5207fc59d2d8SRobert Foley                 qemu_log_unlock(logfile);
52085a18407fSRichard Henderson             }
520978b54858SRichard Henderson         }
52105a18407fSRichard Henderson #endif
52115a18407fSRichard Henderson         /* Replace indirect temps with direct temps.  */
5212b83eabeaSRichard Henderson         if (liveness_pass_2(s)) {
52135a18407fSRichard Henderson             /* If changes were made, re-run liveness.  */
5214b83eabeaSRichard Henderson             liveness_pass_1(s);
52155a18407fSRichard Henderson         }
52165a18407fSRichard Henderson     }
5217c5cc28ffSAurelien Jarno 
5218a23a9ec6Sbellard #ifdef CONFIG_PROFILER
5219d73415a3SStefan Hajnoczi     qatomic_set(&prof->la_time, prof->la_time + profile_getclock());
5220a23a9ec6Sbellard #endif
5221c896fe29Sbellard 
5222c896fe29Sbellard #ifdef DEBUG_DISAS
5223d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT)
5224fbf59aadSRichard Henderson                  && qemu_log_in_addr_range(pc_start))) {
5225c60f599bSRichard Henderson         FILE *logfile = qemu_log_trylock();
522678b54858SRichard Henderson         if (logfile) {
522778b54858SRichard Henderson             fprintf(logfile, "OP after optimization and liveness analysis:\n");
5228b7a83ff8SRichard Henderson             tcg_dump_ops(s, logfile, true);
522978b54858SRichard Henderson             fprintf(logfile, "\n");
5230fc59d2d8SRobert Foley             qemu_log_unlock(logfile);
5231c896fe29Sbellard         }
523278b54858SRichard Henderson     }
5233c896fe29Sbellard #endif
5234c896fe29Sbellard 
523535abb009SRichard Henderson     /* Initialize goto_tb jump offsets. */
52363a50f424SRichard Henderson     tb->jmp_reset_offset[0] = TB_JMP_OFFSET_INVALID;
52373a50f424SRichard Henderson     tb->jmp_reset_offset[1] = TB_JMP_OFFSET_INVALID;
52389da6079bSRichard Henderson     tb->jmp_insn_offset[0] = TB_JMP_OFFSET_INVALID;
52399da6079bSRichard Henderson     tb->jmp_insn_offset[1] = TB_JMP_OFFSET_INVALID;
524035abb009SRichard Henderson 
5241c896fe29Sbellard     tcg_reg_alloc_start(s);
5242c896fe29Sbellard 
5243db0c51a3SRichard Henderson     /*
5244db0c51a3SRichard Henderson      * Reset the buffer pointers when restarting after overflow.
5245db0c51a3SRichard Henderson      * TODO: Move this into translate-all.c with the rest of the
5246db0c51a3SRichard Henderson      * buffer management.  Having only this done here is confusing.
5247db0c51a3SRichard Henderson      */
5248db0c51a3SRichard Henderson     s->code_buf = tcg_splitwx_to_rw(tb->tc.ptr);
5249db0c51a3SRichard Henderson     s->code_ptr = s->code_buf;
5250c896fe29Sbellard 
5251659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
52526001f772SLaurent Vivier     QSIMPLEQ_INIT(&s->ldst_labels);
5253659ef5cbSRichard Henderson #endif
525457a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
525557a26946SRichard Henderson     s->pool_labels = NULL;
525657a26946SRichard Henderson #endif
52579ecefc84SRichard Henderson 
5258fca8a500SRichard Henderson     num_insns = -1;
525915fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
5260c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
5261b3db8758Sblueswir1 
5262c896fe29Sbellard #ifdef CONFIG_PROFILER
5263d73415a3SStefan Hajnoczi         qatomic_set(&prof->table_op_count[opc], prof->table_op_count[opc] + 1);
5264c896fe29Sbellard #endif
5265c45cb8bbSRichard Henderson 
5266c896fe29Sbellard         switch (opc) {
5267c896fe29Sbellard         case INDEX_op_mov_i32:
5268c896fe29Sbellard         case INDEX_op_mov_i64:
5269d2fd745fSRichard Henderson         case INDEX_op_mov_vec:
5270dd186292SRichard Henderson             tcg_reg_alloc_mov(s, op);
5271c896fe29Sbellard             break;
5272bab1671fSRichard Henderson         case INDEX_op_dup_vec:
5273bab1671fSRichard Henderson             tcg_reg_alloc_dup(s, op);
5274bab1671fSRichard Henderson             break;
5275765b842aSRichard Henderson         case INDEX_op_insn_start:
5276fca8a500SRichard Henderson             if (num_insns >= 0) {
52779f754620SRichard Henderson                 size_t off = tcg_current_code_size(s);
52789f754620SRichard Henderson                 s->gen_insn_end_off[num_insns] = off;
52799f754620SRichard Henderson                 /* Assert that we do not overflow our stored offset.  */
52809f754620SRichard Henderson                 assert(s->gen_insn_end_off[num_insns] == off);
5281fca8a500SRichard Henderson             }
5282fca8a500SRichard Henderson             num_insns++;
5283bad729e2SRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
5284bad729e2SRichard Henderson                 target_ulong a;
5285bad729e2SRichard Henderson #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
5286efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
5287bad729e2SRichard Henderson #else
5288efee3746SRichard Henderson                 a = op->args[i];
5289bad729e2SRichard Henderson #endif
5290fca8a500SRichard Henderson                 s->gen_insn_data[num_insns][i] = a;
5291bad729e2SRichard Henderson             }
5292c896fe29Sbellard             break;
52935ff9d6a4Sbellard         case INDEX_op_discard:
529443439139SRichard Henderson             temp_dead(s, arg_temp(op->args[0]));
52955ff9d6a4Sbellard             break;
5296c896fe29Sbellard         case INDEX_op_set_label:
5297e8996ee0Sbellard             tcg_reg_alloc_bb_end(s, s->reserved_regs);
529892ab8e7dSRichard Henderson             tcg_out_label(s, arg_label(op->args[0]));
5299c896fe29Sbellard             break;
5300c896fe29Sbellard         case INDEX_op_call:
5301dd186292SRichard Henderson             tcg_reg_alloc_call(s, op);
5302c45cb8bbSRichard Henderson             break;
5303b55a8d9dSRichard Henderson         case INDEX_op_exit_tb:
5304b55a8d9dSRichard Henderson             tcg_out_exit_tb(s, op->args[0]);
5305b55a8d9dSRichard Henderson             break;
5306cf7d6b8eSRichard Henderson         case INDEX_op_goto_tb:
5307cf7d6b8eSRichard Henderson             tcg_out_goto_tb(s, op->args[0]);
5308cf7d6b8eSRichard Henderson             break;
5309efe86b21SRichard Henderson         case INDEX_op_dup2_vec:
5310efe86b21SRichard Henderson             if (tcg_reg_alloc_dup2(s, op)) {
5311efe86b21SRichard Henderson                 break;
5312efe86b21SRichard Henderson             }
5313efe86b21SRichard Henderson             /* fall through */
5314c896fe29Sbellard         default:
531525c4d9ccSRichard Henderson             /* Sanity check that we've not introduced any unhandled opcodes. */
5316be0f34b5SRichard Henderson             tcg_debug_assert(tcg_op_supported(opc));
5317c896fe29Sbellard             /* Note: in order to speed up the code, it would be much
5318c896fe29Sbellard                faster to have specialized register allocator functions for
5319c896fe29Sbellard                some common argument patterns */
5320dd186292SRichard Henderson             tcg_reg_alloc_op(s, op);
5321c896fe29Sbellard             break;
5322c896fe29Sbellard         }
5323b125f9dcSRichard Henderson         /* Test for (pending) buffer overflow.  The assumption is that any
5324b125f9dcSRichard Henderson            one operation beginning below the high water mark cannot overrun
5325b125f9dcSRichard Henderson            the buffer completely.  Thus we can test for overflow after
5326b125f9dcSRichard Henderson            generating code without having to check during generation.  */
5327644da9b3SJohn Clarke         if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) {
5328b125f9dcSRichard Henderson             return -1;
5329b125f9dcSRichard Henderson         }
53306e6c4efeSRichard Henderson         /* Test for TB overflow, as seen by gen_insn_end_off.  */
53316e6c4efeSRichard Henderson         if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) {
53326e6c4efeSRichard Henderson             return -2;
53336e6c4efeSRichard Henderson         }
5334c896fe29Sbellard     }
5335fca8a500SRichard Henderson     tcg_debug_assert(num_insns >= 0);
5336fca8a500SRichard Henderson     s->gen_insn_end_off[num_insns] = tcg_current_code_size(s);
5337c45cb8bbSRichard Henderson 
5338b76f0d8cSYeongkyoon Lee     /* Generate TB finalization at the end of block */
5339659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
5340aeee05f5SRichard Henderson     i = tcg_out_ldst_finalize(s);
5341aeee05f5SRichard Henderson     if (i < 0) {
5342aeee05f5SRichard Henderson         return i;
534323dceda6SRichard Henderson     }
5344659ef5cbSRichard Henderson #endif
534557a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
53461768987bSRichard Henderson     i = tcg_out_pool_finalize(s);
53471768987bSRichard Henderson     if (i < 0) {
53481768987bSRichard Henderson         return i;
534957a26946SRichard Henderson     }
535057a26946SRichard Henderson #endif
53517ecd02a0SRichard Henderson     if (!tcg_resolve_relocs(s)) {
53527ecd02a0SRichard Henderson         return -2;
53537ecd02a0SRichard Henderson     }
5354c896fe29Sbellard 
5355df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
5356c896fe29Sbellard     /* flush instruction cache */
5357db0c51a3SRichard Henderson     flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf),
5358db0c51a3SRichard Henderson                         (uintptr_t)s->code_buf,
53591da8de39SRichard Henderson                         tcg_ptr_byte_diff(s->code_ptr, s->code_buf));
5360df5d2b16SRichard Henderson #endif
53612aeabc08SStefan Weil 
53621813e175SRichard Henderson     return tcg_current_code_size(s);
5363c896fe29Sbellard }
5364c896fe29Sbellard 
5365a23a9ec6Sbellard #ifdef CONFIG_PROFILER
53663a841ab5SDaniel P. Berrangé void tcg_dump_info(GString *buf)
5367a23a9ec6Sbellard {
5368c3fac113SEmilio G. Cota     TCGProfile prof = {};
5369c3fac113SEmilio G. Cota     const TCGProfile *s;
5370c3fac113SEmilio G. Cota     int64_t tb_count;
5371c3fac113SEmilio G. Cota     int64_t tb_div_count;
5372c3fac113SEmilio G. Cota     int64_t tot;
5373c3fac113SEmilio G. Cota 
5374c3fac113SEmilio G. Cota     tcg_profile_snapshot_counters(&prof);
5375c3fac113SEmilio G. Cota     s = &prof;
5376c3fac113SEmilio G. Cota     tb_count = s->tb_count;
5377c3fac113SEmilio G. Cota     tb_div_count = tb_count ? tb_count : 1;
5378c3fac113SEmilio G. Cota     tot = s->interm_time + s->code_time;
5379a23a9ec6Sbellard 
53803a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "JIT cycles          %" PRId64
53813a841ab5SDaniel P. Berrangé                            " (%0.3f s at 2.4 GHz)\n",
5382a23a9ec6Sbellard                            tot, tot / 2.4e9);
53833a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "translated TBs      %" PRId64
53843a841ab5SDaniel P. Berrangé                            " (aborted=%" PRId64 " %0.1f%%)\n",
5385fca8a500SRichard Henderson                            tb_count, s->tb_count1 - tb_count,
5386fca8a500SRichard Henderson                            (double)(s->tb_count1 - s->tb_count)
5387fca8a500SRichard Henderson                            / (s->tb_count1 ? s->tb_count1 : 1) * 100.0);
53883a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "avg ops/TB          %0.1f max=%d\n",
5389fca8a500SRichard Henderson                            (double)s->op_count / tb_div_count, s->op_count_max);
53903a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "deleted ops/TB      %0.2f\n",
5391fca8a500SRichard Henderson                            (double)s->del_op_count / tb_div_count);
53923a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "avg temps/TB        %0.2f max=%d\n",
53933a841ab5SDaniel P. Berrangé                            (double)s->temp_count / tb_div_count,
53943a841ab5SDaniel P. Berrangé                            s->temp_count_max);
53953a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "avg host code/TB    %0.1f\n",
5396fca8a500SRichard Henderson                            (double)s->code_out_len / tb_div_count);
53973a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "avg search data/TB  %0.1f\n",
5398fca8a500SRichard Henderson                            (double)s->search_out_len / tb_div_count);
5399a23a9ec6Sbellard 
54003a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "cycles/op           %0.1f\n",
5401a23a9ec6Sbellard                            s->op_count ? (double)tot / s->op_count : 0);
54023a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "cycles/in byte      %0.1f\n",
5403a23a9ec6Sbellard                            s->code_in_len ? (double)tot / s->code_in_len : 0);
54043a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "cycles/out byte     %0.1f\n",
5405a23a9ec6Sbellard                            s->code_out_len ? (double)tot / s->code_out_len : 0);
54063a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "cycles/search byte     %0.1f\n",
54073a841ab5SDaniel P. Berrangé                            s->search_out_len ?
54083a841ab5SDaniel P. Berrangé                            (double)tot / s->search_out_len : 0);
5409fca8a500SRichard Henderson     if (tot == 0) {
5410a23a9ec6Sbellard         tot = 1;
5411fca8a500SRichard Henderson     }
54123a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "  gen_interm time   %0.1f%%\n",
5413a23a9ec6Sbellard                            (double)s->interm_time / tot * 100.0);
54143a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "  gen_code time     %0.1f%%\n",
5415a23a9ec6Sbellard                            (double)s->code_time / tot * 100.0);
54163a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "optim./code time    %0.1f%%\n",
54173a841ab5SDaniel P. Berrangé                            (double)s->opt_time / (s->code_time ?
54183a841ab5SDaniel P. Berrangé                                                   s->code_time : 1)
5419c5cc28ffSAurelien Jarno                            * 100.0);
54203a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "liveness/code time  %0.1f%%\n",
54213a841ab5SDaniel P. Berrangé                            (double)s->la_time / (s->code_time ?
54223a841ab5SDaniel P. Berrangé                                                  s->code_time : 1) * 100.0);
54233a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "cpu_restore count   %" PRId64 "\n",
5424a23a9ec6Sbellard                            s->restore_count);
54253a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "  avg cycles        %0.1f\n",
54263a841ab5SDaniel P. Berrangé                            s->restore_count ?
54273a841ab5SDaniel P. Berrangé                            (double)s->restore_time / s->restore_count : 0);
5428a23a9ec6Sbellard }
5429a23a9ec6Sbellard #else
54303a841ab5SDaniel P. Berrangé void tcg_dump_info(GString *buf)
5431a23a9ec6Sbellard {
54323a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "[TCG profiler not compiled]\n");
5433a23a9ec6Sbellard }
5434a23a9ec6Sbellard #endif
5435813da627SRichard Henderson 
5436813da627SRichard Henderson #ifdef ELF_HOST_MACHINE
54375872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things:
54385872bbf2SRichard Henderson 
54395872bbf2SRichard Henderson    (1) Define ELF_HOST_MACHINE to indicate both what value to
54405872bbf2SRichard Henderson        put into the ELF image and to indicate support for the feature.
54415872bbf2SRichard Henderson 
54425872bbf2SRichard Henderson    (2) Define tcg_register_jit.  This should create a buffer containing
54435872bbf2SRichard Henderson        the contents of a .debug_frame section that describes the post-
54445872bbf2SRichard Henderson        prologue unwind info for the tcg machine.
54455872bbf2SRichard Henderson 
54465872bbf2SRichard Henderson    (3) Call tcg_register_jit_int, with the constructed .debug_frame.
54475872bbf2SRichard Henderson */
5448813da627SRichard Henderson 
5449813da627SRichard Henderson /* Begin GDB interface.  THE FOLLOWING MUST MATCH GDB DOCS.  */
5450813da627SRichard Henderson typedef enum {
5451813da627SRichard Henderson     JIT_NOACTION = 0,
5452813da627SRichard Henderson     JIT_REGISTER_FN,
5453813da627SRichard Henderson     JIT_UNREGISTER_FN
5454813da627SRichard Henderson } jit_actions_t;
5455813da627SRichard Henderson 
5456813da627SRichard Henderson struct jit_code_entry {
5457813da627SRichard Henderson     struct jit_code_entry *next_entry;
5458813da627SRichard Henderson     struct jit_code_entry *prev_entry;
5459813da627SRichard Henderson     const void *symfile_addr;
5460813da627SRichard Henderson     uint64_t symfile_size;
5461813da627SRichard Henderson };
5462813da627SRichard Henderson 
5463813da627SRichard Henderson struct jit_descriptor {
5464813da627SRichard Henderson     uint32_t version;
5465813da627SRichard Henderson     uint32_t action_flag;
5466813da627SRichard Henderson     struct jit_code_entry *relevant_entry;
5467813da627SRichard Henderson     struct jit_code_entry *first_entry;
5468813da627SRichard Henderson };
5469813da627SRichard Henderson 
5470813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline));
5471813da627SRichard Henderson void __jit_debug_register_code(void)
5472813da627SRichard Henderson {
5473813da627SRichard Henderson     asm("");
5474813da627SRichard Henderson }
5475813da627SRichard Henderson 
5476813da627SRichard Henderson /* Must statically initialize the version, because GDB may check
5477813da627SRichard Henderson    the version before we can set it.  */
5478813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
5479813da627SRichard Henderson 
5480813da627SRichard Henderson /* End GDB interface.  */
5481813da627SRichard Henderson 
5482813da627SRichard Henderson static int find_string(const char *strtab, const char *str)
5483813da627SRichard Henderson {
5484813da627SRichard Henderson     const char *p = strtab + 1;
5485813da627SRichard Henderson 
5486813da627SRichard Henderson     while (1) {
5487813da627SRichard Henderson         if (strcmp(p, str) == 0) {
5488813da627SRichard Henderson             return p - strtab;
5489813da627SRichard Henderson         }
5490813da627SRichard Henderson         p += strlen(p) + 1;
5491813da627SRichard Henderson     }
5492813da627SRichard Henderson }
5493813da627SRichard Henderson 
5494755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf_ptr, size_t buf_size,
54952c90784aSRichard Henderson                                  const void *debug_frame,
54962c90784aSRichard Henderson                                  size_t debug_frame_size)
5497813da627SRichard Henderson {
54985872bbf2SRichard Henderson     struct __attribute__((packed)) DebugInfo {
54995872bbf2SRichard Henderson         uint32_t  len;
55005872bbf2SRichard Henderson         uint16_t  version;
55015872bbf2SRichard Henderson         uint32_t  abbrev;
55025872bbf2SRichard Henderson         uint8_t   ptr_size;
55035872bbf2SRichard Henderson         uint8_t   cu_die;
55045872bbf2SRichard Henderson         uint16_t  cu_lang;
55055872bbf2SRichard Henderson         uintptr_t cu_low_pc;
55065872bbf2SRichard Henderson         uintptr_t cu_high_pc;
55075872bbf2SRichard Henderson         uint8_t   fn_die;
55085872bbf2SRichard Henderson         char      fn_name[16];
55095872bbf2SRichard Henderson         uintptr_t fn_low_pc;
55105872bbf2SRichard Henderson         uintptr_t fn_high_pc;
55115872bbf2SRichard Henderson         uint8_t   cu_eoc;
55125872bbf2SRichard Henderson     };
5513813da627SRichard Henderson 
5514813da627SRichard Henderson     struct ElfImage {
5515813da627SRichard Henderson         ElfW(Ehdr) ehdr;
5516813da627SRichard Henderson         ElfW(Phdr) phdr;
55175872bbf2SRichard Henderson         ElfW(Shdr) shdr[7];
55185872bbf2SRichard Henderson         ElfW(Sym)  sym[2];
55195872bbf2SRichard Henderson         struct DebugInfo di;
55205872bbf2SRichard Henderson         uint8_t    da[24];
55215872bbf2SRichard Henderson         char       str[80];
55225872bbf2SRichard Henderson     };
55235872bbf2SRichard Henderson 
55245872bbf2SRichard Henderson     struct ElfImage *img;
55255872bbf2SRichard Henderson 
55265872bbf2SRichard Henderson     static const struct ElfImage img_template = {
55275872bbf2SRichard Henderson         .ehdr = {
55285872bbf2SRichard Henderson             .e_ident[EI_MAG0] = ELFMAG0,
55295872bbf2SRichard Henderson             .e_ident[EI_MAG1] = ELFMAG1,
55305872bbf2SRichard Henderson             .e_ident[EI_MAG2] = ELFMAG2,
55315872bbf2SRichard Henderson             .e_ident[EI_MAG3] = ELFMAG3,
55325872bbf2SRichard Henderson             .e_ident[EI_CLASS] = ELF_CLASS,
55335872bbf2SRichard Henderson             .e_ident[EI_DATA] = ELF_DATA,
55345872bbf2SRichard Henderson             .e_ident[EI_VERSION] = EV_CURRENT,
55355872bbf2SRichard Henderson             .e_type = ET_EXEC,
55365872bbf2SRichard Henderson             .e_machine = ELF_HOST_MACHINE,
55375872bbf2SRichard Henderson             .e_version = EV_CURRENT,
55385872bbf2SRichard Henderson             .e_phoff = offsetof(struct ElfImage, phdr),
55395872bbf2SRichard Henderson             .e_shoff = offsetof(struct ElfImage, shdr),
55405872bbf2SRichard Henderson             .e_ehsize = sizeof(ElfW(Shdr)),
55415872bbf2SRichard Henderson             .e_phentsize = sizeof(ElfW(Phdr)),
55425872bbf2SRichard Henderson             .e_phnum = 1,
55435872bbf2SRichard Henderson             .e_shentsize = sizeof(ElfW(Shdr)),
55445872bbf2SRichard Henderson             .e_shnum = ARRAY_SIZE(img->shdr),
55455872bbf2SRichard Henderson             .e_shstrndx = ARRAY_SIZE(img->shdr) - 1,
5546abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS
5547abbb3eaeSRichard Henderson             .e_flags = ELF_HOST_FLAGS,
5548abbb3eaeSRichard Henderson #endif
5549abbb3eaeSRichard Henderson #ifdef ELF_OSABI
5550abbb3eaeSRichard Henderson             .e_ident[EI_OSABI] = ELF_OSABI,
5551abbb3eaeSRichard Henderson #endif
55525872bbf2SRichard Henderson         },
55535872bbf2SRichard Henderson         .phdr = {
55545872bbf2SRichard Henderson             .p_type = PT_LOAD,
55555872bbf2SRichard Henderson             .p_flags = PF_X,
55565872bbf2SRichard Henderson         },
55575872bbf2SRichard Henderson         .shdr = {
55585872bbf2SRichard Henderson             [0] = { .sh_type = SHT_NULL },
55595872bbf2SRichard Henderson             /* Trick: The contents of code_gen_buffer are not present in
55605872bbf2SRichard Henderson                this fake ELF file; that got allocated elsewhere.  Therefore
55615872bbf2SRichard Henderson                we mark .text as SHT_NOBITS (similar to .bss) so that readers
55625872bbf2SRichard Henderson                will not look for contents.  We can record any address.  */
55635872bbf2SRichard Henderson             [1] = { /* .text */
55645872bbf2SRichard Henderson                 .sh_type = SHT_NOBITS,
55655872bbf2SRichard Henderson                 .sh_flags = SHF_EXECINSTR | SHF_ALLOC,
55665872bbf2SRichard Henderson             },
55675872bbf2SRichard Henderson             [2] = { /* .debug_info */
55685872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
55695872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, di),
55705872bbf2SRichard Henderson                 .sh_size = sizeof(struct DebugInfo),
55715872bbf2SRichard Henderson             },
55725872bbf2SRichard Henderson             [3] = { /* .debug_abbrev */
55735872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
55745872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, da),
55755872bbf2SRichard Henderson                 .sh_size = sizeof(img->da),
55765872bbf2SRichard Henderson             },
55775872bbf2SRichard Henderson             [4] = { /* .debug_frame */
55785872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
55795872bbf2SRichard Henderson                 .sh_offset = sizeof(struct ElfImage),
55805872bbf2SRichard Henderson             },
55815872bbf2SRichard Henderson             [5] = { /* .symtab */
55825872bbf2SRichard Henderson                 .sh_type = SHT_SYMTAB,
55835872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, sym),
55845872bbf2SRichard Henderson                 .sh_size = sizeof(img->sym),
55855872bbf2SRichard Henderson                 .sh_info = 1,
55865872bbf2SRichard Henderson                 .sh_link = ARRAY_SIZE(img->shdr) - 1,
55875872bbf2SRichard Henderson                 .sh_entsize = sizeof(ElfW(Sym)),
55885872bbf2SRichard Henderson             },
55895872bbf2SRichard Henderson             [6] = { /* .strtab */
55905872bbf2SRichard Henderson                 .sh_type = SHT_STRTAB,
55915872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, str),
55925872bbf2SRichard Henderson                 .sh_size = sizeof(img->str),
55935872bbf2SRichard Henderson             }
55945872bbf2SRichard Henderson         },
55955872bbf2SRichard Henderson         .sym = {
55965872bbf2SRichard Henderson             [1] = { /* code_gen_buffer */
55975872bbf2SRichard Henderson                 .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC),
55985872bbf2SRichard Henderson                 .st_shndx = 1,
55995872bbf2SRichard Henderson             }
56005872bbf2SRichard Henderson         },
56015872bbf2SRichard Henderson         .di = {
56025872bbf2SRichard Henderson             .len = sizeof(struct DebugInfo) - 4,
56035872bbf2SRichard Henderson             .version = 2,
56045872bbf2SRichard Henderson             .ptr_size = sizeof(void *),
56055872bbf2SRichard Henderson             .cu_die = 1,
56065872bbf2SRichard Henderson             .cu_lang = 0x8001,  /* DW_LANG_Mips_Assembler */
56075872bbf2SRichard Henderson             .fn_die = 2,
56085872bbf2SRichard Henderson             .fn_name = "code_gen_buffer"
56095872bbf2SRichard Henderson         },
56105872bbf2SRichard Henderson         .da = {
56115872bbf2SRichard Henderson             1,          /* abbrev number (the cu) */
56125872bbf2SRichard Henderson             0x11, 1,    /* DW_TAG_compile_unit, has children */
56135872bbf2SRichard Henderson             0x13, 0x5,  /* DW_AT_language, DW_FORM_data2 */
56145872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
56155872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
56165872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
56175872bbf2SRichard Henderson             2,          /* abbrev number (the fn) */
56185872bbf2SRichard Henderson             0x2e, 0,    /* DW_TAG_subprogram, no children */
56195872bbf2SRichard Henderson             0x3, 0x8,   /* DW_AT_name, DW_FORM_string */
56205872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
56215872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
56225872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
56235872bbf2SRichard Henderson             0           /* no more abbrev */
56245872bbf2SRichard Henderson         },
56255872bbf2SRichard Henderson         .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0"
56265872bbf2SRichard Henderson                ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer",
5627813da627SRichard Henderson     };
5628813da627SRichard Henderson 
5629813da627SRichard Henderson     /* We only need a single jit entry; statically allocate it.  */
5630813da627SRichard Henderson     static struct jit_code_entry one_entry;
5631813da627SRichard Henderson 
56325872bbf2SRichard Henderson     uintptr_t buf = (uintptr_t)buf_ptr;
5633813da627SRichard Henderson     size_t img_size = sizeof(struct ElfImage) + debug_frame_size;
56342c90784aSRichard Henderson     DebugFrameHeader *dfh;
5635813da627SRichard Henderson 
56365872bbf2SRichard Henderson     img = g_malloc(img_size);
56375872bbf2SRichard Henderson     *img = img_template;
5638813da627SRichard Henderson 
56395872bbf2SRichard Henderson     img->phdr.p_vaddr = buf;
56405872bbf2SRichard Henderson     img->phdr.p_paddr = buf;
56415872bbf2SRichard Henderson     img->phdr.p_memsz = buf_size;
5642813da627SRichard Henderson 
56435872bbf2SRichard Henderson     img->shdr[1].sh_name = find_string(img->str, ".text");
56445872bbf2SRichard Henderson     img->shdr[1].sh_addr = buf;
56455872bbf2SRichard Henderson     img->shdr[1].sh_size = buf_size;
5646813da627SRichard Henderson 
56475872bbf2SRichard Henderson     img->shdr[2].sh_name = find_string(img->str, ".debug_info");
56485872bbf2SRichard Henderson     img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev");
56495872bbf2SRichard Henderson 
56505872bbf2SRichard Henderson     img->shdr[4].sh_name = find_string(img->str, ".debug_frame");
56515872bbf2SRichard Henderson     img->shdr[4].sh_size = debug_frame_size;
56525872bbf2SRichard Henderson 
56535872bbf2SRichard Henderson     img->shdr[5].sh_name = find_string(img->str, ".symtab");
56545872bbf2SRichard Henderson     img->shdr[6].sh_name = find_string(img->str, ".strtab");
56555872bbf2SRichard Henderson 
56565872bbf2SRichard Henderson     img->sym[1].st_name = find_string(img->str, "code_gen_buffer");
56575872bbf2SRichard Henderson     img->sym[1].st_value = buf;
56585872bbf2SRichard Henderson     img->sym[1].st_size = buf_size;
56595872bbf2SRichard Henderson 
56605872bbf2SRichard Henderson     img->di.cu_low_pc = buf;
566145aba097SRichard Henderson     img->di.cu_high_pc = buf + buf_size;
56625872bbf2SRichard Henderson     img->di.fn_low_pc = buf;
566345aba097SRichard Henderson     img->di.fn_high_pc = buf + buf_size;
5664813da627SRichard Henderson 
56652c90784aSRichard Henderson     dfh = (DebugFrameHeader *)(img + 1);
56662c90784aSRichard Henderson     memcpy(dfh, debug_frame, debug_frame_size);
56672c90784aSRichard Henderson     dfh->fde.func_start = buf;
56682c90784aSRichard Henderson     dfh->fde.func_len = buf_size;
56692c90784aSRichard Henderson 
5670813da627SRichard Henderson #ifdef DEBUG_JIT
5671813da627SRichard Henderson     /* Enable this block to be able to debug the ELF image file creation.
5672813da627SRichard Henderson        One can use readelf, objdump, or other inspection utilities.  */
5673813da627SRichard Henderson     {
5674eb6b2edfSBin Meng         g_autofree char *jit = g_strdup_printf("%s/qemu.jit", g_get_tmp_dir());
5675eb6b2edfSBin Meng         FILE *f = fopen(jit, "w+b");
5676813da627SRichard Henderson         if (f) {
56775872bbf2SRichard Henderson             if (fwrite(img, img_size, 1, f) != img_size) {
5678813da627SRichard Henderson                 /* Avoid stupid unused return value warning for fwrite.  */
5679813da627SRichard Henderson             }
5680813da627SRichard Henderson             fclose(f);
5681813da627SRichard Henderson         }
5682813da627SRichard Henderson     }
5683813da627SRichard Henderson #endif
5684813da627SRichard Henderson 
5685813da627SRichard Henderson     one_entry.symfile_addr = img;
5686813da627SRichard Henderson     one_entry.symfile_size = img_size;
5687813da627SRichard Henderson 
5688813da627SRichard Henderson     __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
5689813da627SRichard Henderson     __jit_debug_descriptor.relevant_entry = &one_entry;
5690813da627SRichard Henderson     __jit_debug_descriptor.first_entry = &one_entry;
5691813da627SRichard Henderson     __jit_debug_register_code();
5692813da627SRichard Henderson }
5693813da627SRichard Henderson #else
56945872bbf2SRichard Henderson /* No support for the feature.  Provide the entry point expected by exec.c,
56955872bbf2SRichard Henderson    and implement the internal function we declared earlier.  */
5696813da627SRichard Henderson 
5697755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size,
56982c90784aSRichard Henderson                                  const void *debug_frame,
56992c90784aSRichard Henderson                                  size_t debug_frame_size)
5700813da627SRichard Henderson {
5701813da627SRichard Henderson }
5702813da627SRichard Henderson 
5703755bf9e5SRichard Henderson void tcg_register_jit(const void *buf, size_t buf_size)
5704813da627SRichard Henderson {
5705813da627SRichard Henderson }
5706813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */
5707db432672SRichard Henderson 
5708db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec
5709db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...)
5710db432672SRichard Henderson {
5711db432672SRichard Henderson     g_assert_not_reached();
5712db432672SRichard Henderson }
5713db432672SRichard Henderson #endif
5714